Browse Source

IPv6 support, improve URL handling/comparison

rdb 9 years ago
parent
commit
7e08b87ff7

+ 17 - 0
dtool/src/parser-inc/netinet/in.h

@@ -0,0 +1,17 @@
+#include <stdint.h>
+#include <sys/socket.h>
+
+typedef uint32_t in_addr_t;
+struct in_addr;
+typedef uint16_t in_port_t;
+struct in6_addr;
+struct sockaddr_in;
+struct sockaddr_in6;
+struct ip_mreq;
+struct ip_mreq_source;
+struct ipv6_mreq;
+struct group_req;
+struct group_source_req;
+struct ip_msfilter;
+struct group_filter;
+

+ 0 - 10
dtool/src/parser-inc/socket.h

@@ -1,10 +0,0 @@
-typedef int SOCKET ;
-
-struct sockaddr_in
-{
-};
-
-typedef struct fd_set {
-        unsigned int fd_count;               /* how many are SET? */
-        SOCKET  fd_array[10];   /* an array of SOCKETs */
-} fd_set;

+ 18 - 0
dtool/src/parser-inc/sys/socket.h

@@ -0,0 +1,18 @@
+#pragma once
+
+typedef int socklen_t;
+typedef unsigned short int sa_family_t;
+
+struct sockaddr {
+  sa_family_t sa_family;
+  char sa_data[];
+};
+
+struct sockaddr_storage {
+  sa_family_t ss_family;
+};
+
+typedef struct fd_set {
+  unsigned int fd_count;               /* how many are SET? */
+  int fd_array[10];   /* an array of SOCKETs */
+} fd_set;

+ 3 - 0
dtool/src/parser-inc/winsock2.h

@@ -6,6 +6,9 @@
 
 
 typedef unsigned long SOCKET;
 typedef unsigned long SOCKET;
 
 
+struct sockaddr;
 struct sockaddr_in;
 struct sockaddr_in;
+struct sockaddr_in6;
+struct sockaddr_storage;
 
 
 #endif
 #endif

+ 1 - 0
dtool/src/parser-inc/ws2tcpip.h

@@ -0,0 +1 @@
+typedef DWORD socklen_t;

+ 8 - 0
panda/src/downloader/bioPtr.I

@@ -18,6 +18,14 @@ INLINE BioPtr::
 BioPtr(BIO *bio) : _bio(bio) {
 BioPtr(BIO *bio) : _bio(bio) {
 }
 }
 
 
+/**
+ *
+ */
+INLINE bool BioPtr::
+should_retry() const {
+  return (_bio != NULL) && BIO_should_retry(_bio);
+}
+
 /**
 /**
  *
  *
  */
  */

+ 167 - 5
panda/src/downloader/bioPtr.cxx

@@ -18,13 +18,46 @@
 #include "urlSpec.h"
 #include "urlSpec.h"
 #include "config_downloader.h"
 #include "config_downloader.h"
 
 
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#endif
+
+#ifdef _WIN32
+static string format_error() {
+  PVOID buffer;
+  DWORD len;
+  len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                      NULL, WSAGetLastError(), 0, (LPTSTR)&buffer, 0, NULL);
+  if (len == 0) {
+    return string("Unknown error message");
+  }
+
+  const char *text = (const char *)buffer;
+  while (len > 0 && isspace(text[len - 1])) {
+    --len;
+  }
+
+  string result(text, len);
+  LocalFree(buffer);
+  return result;
+}
+#else
+#define format_error() strerror(errno)
+#endif
+
 /**
 /**
  * This flavor of the constructor automatically creates a socket BIO and feeds
  * This flavor of the constructor automatically creates a socket BIO and feeds
  * it the server and port name from the indicated URL.  It doesn't call
  * it the server and port name from the indicated URL.  It doesn't call
  * BIO_do_connect(), though.
  * BIO_do_connect(), though.
  */
  */
 BioPtr::
 BioPtr::
-BioPtr(const URLSpec &url) {
+BioPtr(const URLSpec &url) : _connecting(false) {
   if (url.get_scheme() == "file") {
   if (url.get_scheme() == "file") {
     // We're just reading a disk file.
     // We're just reading a disk file.
     string filename = URLSpec::unquote(url.get_path());
     string filename = URLSpec::unquote(url.get_path());
@@ -48,12 +81,141 @@ BioPtr(const URLSpec &url) {
     _bio = BIO_new_file(filename.c_str(), "rb");
     _bio = BIO_new_file(filename.c_str(), "rb");
 
 
   } else {
   } else {
-    // A normal network-based URL.
+    // A normal network-based URL.  We don't use BIO_new_connect since it
+    // doesn't handle IPv6 properly.
     _server_name = url.get_server();
     _server_name = url.get_server();
     _port = url.get_port();
     _port = url.get_port();
-    _bio = BIO_new_connect((char *)_server_name.c_str());
-    BIO_set_conn_int_port(_bio, &_port);
+    _bio = NULL;
+
+    // These hints tell getaddrinfo what kind of address to return.
+    struct addrinfo hints, *res = NULL;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
+    hints.ai_family = support_ipv6 ? AF_UNSPEC : AF_INET;
+    hints.ai_socktype = SOCK_STREAM;
+
+    // Resolve the hostname or address string.
+    int result = getaddrinfo(_server_name.c_str(), NULL, &hints, &res);
+    if (result != 0) {
+      const char *errmsg;
+#ifndef _WIN32
+      if (result == EAI_SYSTEM && errno != 0) {
+        errmsg = strerror(errno);
+      } else
+#endif
+      {
+        errmsg = gai_strerror(result);
+      }
+      downloader_cat.error()
+        << "Failed to resolve " << url.get_server() << ": " << errmsg << "\n";
+      return;
+    }
+    nassertv(res != NULL && res->ai_addr != NULL);
+
+    // Store the real resolved address.
+    char buf[48];
+    buf[0] = 0;
+#ifdef _WIN32
+    DWORD bufsize = sizeof(buf);
+    WSAAddressToStringA(res->ai_addr, res->ai_addrlen, NULL, buf, &bufsize);
+#else
+    if (res->ai_addr->sa_family == AF_INET) {
+      inet_ntop(AF_INET, (char *)&((sockaddr_in *)res->ai_addr)->sin_addr, buf, sizeof(buf));
+
+    } else if (res->ai_addr->sa_family == AF_INET6) {
+      inet_ntop(AF_INET6, (char *)&((sockaddr_in6 *)res->ai_addr)->sin6_addr, buf, sizeof(buf));
+    }
+#endif
+
+    if (buf[0]) {
+      _server_name = buf;
+    }
+    if (downloader_cat.is_debug()) {
+      downloader_cat.debug()
+        << "Resolved " << url.get_server() << " to " << buf << "\n";
+    }
+
+    // Create the socket.
+    int fd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP);
+    if (fd < 0) {
+      downloader_cat.error()
+        << "Failed to create socket: " << format_error() << "\n";
+      _bio = NULL;
+      freeaddrinfo(res);
+      return;
+    }
+
+    // Store the address and length for later use in connect().
+    nassertv(res->ai_addrlen <= sizeof(_addr));
+    memcpy(&_addr, res->ai_addr, res->ai_addrlen);
+    _addrlen = res->ai_addrlen;
+    freeaddrinfo(res);
+
+    // Also set the port we'd like to connect to.
+    if (_addr.ss_family == AF_INET) {
+      ((sockaddr_in &)_addr).sin_port = htons(_port);
+    } else if (_addr.ss_family == AF_INET6) {
+      ((sockaddr_in6 &)_addr).sin6_port = htons(_port);
+    }
+
+    _bio = BIO_new_socket(fd, 1);
+  }
+}
+
+/**
+ * Sets the non-blocking flag on the socket.
+ */
+void BioPtr::
+set_nbio(bool nbio) {
+  if (_bio == NULL) {
+    return;
+  }
+
+  int fd = -1;
+  BIO_get_fd(_bio, &fd);
+  nassertv_always(fd >= 0);
+
+  BIO_socket_nbio(fd, nbio);
+}
+
+/**
+ * Connects to the socket.  Returns true on success.
+ */
+bool BioPtr::
+connect() {
+  if (_bio == NULL) {
+    return false;
+  }
+
+  int fd = -1;
+  BIO_get_fd(_bio, &fd);
+  nassertr(fd >= 0, false);
+
+  int result;
+  if (_connecting) {
+    result = BIO_sock_error(fd);
+  } else {
+    result = ::connect(fd, (sockaddr *)&_addr, _addrlen);
+
+    if (result != 0 && BIO_sock_should_retry(-1)) {
+      // It's still in progress; we should retry later.  This causes
+      // should_reply() to return true.
+      BIO_set_flags(_bio, BIO_FLAGS_SHOULD_RETRY);
+      _connecting = true;
+      return false;
+    }
   }
   }
+  BIO_clear_retry_flags(_bio);
+  _connecting = false;
+
+  if (result != 0) {
+    downloader_cat.warning()
+      << "Failed to connect to " << _server_name << " port " << _port
+      << ": " << format_error() << "\n";
+    return false;
+  }
+
+  return true;
 }
 }
 
 
 /**
 /**
@@ -64,7 +226,7 @@ BioPtr::
   if (_bio != (BIO *)NULL) {
   if (_bio != (BIO *)NULL) {
     if (downloader_cat.is_debug() && !_server_name.empty()) {
     if (downloader_cat.is_debug() && !_server_name.empty()) {
       downloader_cat.debug()
       downloader_cat.debug()
-        << "Dropping connection to " << _server_name << ":" << _port << "\n";
+        << "Dropping connection to " << _server_name << " port " << _port << "\n";
     }
     }
 
 
     BIO_free_all(_bio);
     BIO_free_all(_bio);

+ 16 - 0
panda/src/downloader/bioPtr.h

@@ -27,6 +27,14 @@
 #include "openSSLWrapper.h"  // must be included before any other openssl.
 #include "openSSLWrapper.h"  // must be included before any other openssl.
 #include "openssl/ssl.h"
 #include "openssl/ssl.h"
 
 
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
 class URLSpec;
 class URLSpec;
 
 
 /**
 /**
@@ -41,6 +49,11 @@ public:
   BioPtr(const URLSpec &url);
   BioPtr(const URLSpec &url);
   virtual ~BioPtr();
   virtual ~BioPtr();
 
 
+  void set_nbio(bool nbio);
+  bool connect();
+
+  INLINE bool should_retry() const;
+
   INLINE BIO &operator *() const;
   INLINE BIO &operator *() const;
   INLINE BIO *operator -> () const;
   INLINE BIO *operator -> () const;
   INLINE operator BIO * () const;
   INLINE operator BIO * () const;
@@ -55,6 +68,9 @@ private:
   BIO *_bio;
   BIO *_bio;
   string _server_name;
   string _server_name;
   int _port;
   int _port;
+  struct sockaddr_storage _addr;
+  socklen_t _addrlen;
+  bool _connecting;
 };
 };
 
 
 #include "bioPtr.I"
 #include "bioPtr.I"

+ 6 - 0
panda/src/downloader/config_downloader.cxx

@@ -111,6 +111,12 @@ ConfigVariableInt tcp_header_size
           "length when writing a datagram on a TCP stream.  This may be "
           "length when writing a datagram on a TCP stream.  This may be "
           "0, 2, or 4.  The server and client must agree on this value."));
           "0, 2, or 4.  The server and client must agree on this value."));
 
 
+ConfigVariableBool support_ipv6
+("support-ipv6", true,
+ PRC_DESC("Specifies whether IPv6 support should be enabled.  This should "
+          "be true unless you are experiencing issues with Panda's IPv6 "
+          "support or are using a misconfigured system."));
+
 ConfigureFn(config_downloader) {
 ConfigureFn(config_downloader) {
   init_libdownloader();
   init_libdownloader();
 }
 }

+ 1 - 0
panda/src/downloader/config_downloader.h

@@ -45,6 +45,7 @@ extern ConfigVariableDouble http_idle_timeout;
 extern ConfigVariableInt http_max_connect_count;
 extern ConfigVariableInt http_max_connect_count;
 
 
 extern EXPCL_PANDAEXPRESS ConfigVariableInt tcp_header_size;
 extern EXPCL_PANDAEXPRESS ConfigVariableInt tcp_header_size;
+extern EXPCL_PANDAEXPRESS ConfigVariableBool support_ipv6;
 
 
 extern EXPCL_PANDAEXPRESS void init_libdownloader();
 extern EXPCL_PANDAEXPRESS void init_libdownloader();
 
 

+ 41 - 18
panda/src/downloader/httpChannel.cxx

@@ -375,26 +375,28 @@ run() {
       }
       }
 
 
       // No connection.  Attempt to establish one.
       // No connection.  Attempt to establish one.
+      URLSpec url;
       if (_proxy.empty()) {
       if (_proxy.empty()) {
-        _bio = new BioPtr(_request.get_url());
+        url = _request.get_url();
       } else {
       } else {
-        _bio = new BioPtr(_proxy);
+        url = _proxy;
       }
       }
+      _bio = new BioPtr(url);
       _source = new BioStreamPtr(new BioStream(_bio));
       _source = new BioStreamPtr(new BioStream(_bio));
       if (_nonblocking) {
       if (_nonblocking) {
-        BIO_set_nbio(*_bio, 1);
+        _bio->set_nbio(true);
       }
       }
 
 
       if (downloader_cat.is_debug()) {
       if (downloader_cat.is_debug()) {
         if (_connect_count > 0) {
         if (_connect_count > 0) {
           downloader_cat.debug()
           downloader_cat.debug()
             << _NOTIFY_HTTP_CHANNEL_ID
             << _NOTIFY_HTTP_CHANNEL_ID
-            << "Reconnecting to " << _bio->get_server_name() << ":"
+            << "Reconnecting to " << _bio->get_server_name() << " port "
             << _bio->get_port() << "\n";
             << _bio->get_port() << "\n";
         } else {
         } else {
           downloader_cat.debug()
           downloader_cat.debug()
             << _NOTIFY_HTTP_CHANNEL_ID
             << _NOTIFY_HTTP_CHANNEL_ID
-            << "Connecting to " << _bio->get_server_name() << ":"
+            << "Connecting to " << _bio->get_server_name() << " port "
             << _bio->get_port() << "\n";
             << _bio->get_port() << "\n";
         }
         }
       }
       }
@@ -941,14 +943,14 @@ bool HTTPChannel::
 run_connecting() {
 run_connecting() {
   _status_entry = StatusEntry();
   _status_entry = StatusEntry();
 
 
-  if (BIO_do_connect(*_bio) <= 0) {
-    if (BIO_should_retry(*_bio)) {
+  if (!_bio->connect()) {
+    if (_bio->should_retry()) {
       _state = S_connecting_wait;
       _state = S_connecting_wait;
       return false;
       return false;
     }
     }
     downloader_cat.info()
     downloader_cat.info()
       << _NOTIFY_HTTP_CHANNEL_ID
       << _NOTIFY_HTTP_CHANNEL_ID
-      << "Could not connect to " << _bio->get_server_name() << ":"
+      << "Could not connect to " << _bio->get_server_name() << " port "
       << _bio->get_port() << "\n";
       << _bio->get_port() << "\n";
     OpenSSLWrapper::get_global_ptr()->notify_ssl_errors();
     OpenSSLWrapper::get_global_ptr()->notify_ssl_errors();
     _status_entry._status_code = SC_no_connection;
     _status_entry._status_code = SC_no_connection;
@@ -959,7 +961,7 @@ run_connecting() {
   if (downloader_cat.is_debug()) {
   if (downloader_cat.is_debug()) {
     downloader_cat.debug()
     downloader_cat.debug()
       << _NOTIFY_HTTP_CHANNEL_ID
       << _NOTIFY_HTTP_CHANNEL_ID
-      << "Connected to " << _bio->get_server_name() << ":"
+      << "Connected to " << _bio->get_server_name() << " port "
       << _bio->get_port() << "\n";
       << _bio->get_port() << "\n";
   }
   }
 
 
@@ -1362,6 +1364,10 @@ run_socks_proxy_connect_reply() {
     total_bytes += (unsigned int)reply[4];
     total_bytes += (unsigned int)reply[4];
     break;
     break;
 
 
+  case 0x04:  // IPv6
+    total_bytes += 16;
+    break;
+
   default:
   default:
     downloader_cat.info()
     downloader_cat.info()
       << _NOTIFY_HTTP_CHANNEL_ID
       << _NOTIFY_HTTP_CHANNEL_ID
@@ -1396,6 +1402,18 @@ run_socks_proxy_connect_reply() {
     case 0x03:  // DNS
     case 0x03:  // DNS
       connect_host = string(&reply[5], (unsigned int)reply[4]);
       connect_host = string(&reply[5], (unsigned int)reply[4]);
       break;
       break;
+
+    case 0x04:  // IPv6
+      {
+        char buf[48];
+        sprintf(buf, "[%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx"
+                     ":%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx]",
+                reply[4], reply[5], reply[6], reply[7], reply[8], reply[9],
+                reply[10], reply[11], reply[12], reply[13], reply[14],
+                reply[15], reply[16], reply[17], reply[18], reply[19]);
+        total_bytes += 16;
+      }
+      break;
     }
     }
 
 
     int connect_port =
     int connect_port =
@@ -2742,8 +2760,8 @@ server_getline(string &str) {
         }
         }
         str = str.substr(0, p);
         str = str.substr(0, p);
       }
       }
-      if (downloader_cat.is_debug()) {
-        downloader_cat.debug()
+      if (downloader_cat.is_spam()) {
+        downloader_cat.spam()
           << _NOTIFY_HTTP_CHANNEL_ID
           << _NOTIFY_HTTP_CHANNEL_ID
           << "recv: " << str << "\n";
           << "recv: " << str << "\n";
       }
       }
@@ -2915,7 +2933,7 @@ server_send(const string &str, bool secret) {
   }
   }
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-  if (!secret && downloader_cat.is_debug()) {
+  if (!secret && downloader_cat.is_spam()) {
     show_send(str.substr(0, write_count));
     show_send(str.substr(0, write_count));
   }
   }
 #endif
 #endif
@@ -3486,14 +3504,19 @@ make_header() {
 
 
   if (_client->get_http_version() >= HTTPEnum::HV_11) {
   if (_client->get_http_version() >= HTTPEnum::HV_11) {
 
 
-    stream
-      << "Host: " << _request.get_url().get_server();
-    if (!_request.get_url().is_default_port()) {
+    if (_request.get_url().has_port() && _request.get_url().is_default_port()) {
       // It appears that some servers (notably gstatic.com) might return a 404
       // It appears that some servers (notably gstatic.com) might return a 404
       // if you include an explicit port number in with the Host: header, even
       // if you include an explicit port number in with the Host: header, even
       // if it is the default port.  So, don't include the port number unless
       // if it is the default port.  So, don't include the port number unless
       // we need to.
       // we need to.
-      stream << ":" << _request.get_url().get_port();
+      string server = _request.get_url().get_server();
+      if (server.find(':') != string::npos) {
+        stream << "Host: [" << server << "]";
+      } else {
+        stream << "Host: " << server;
+      }
+    } else {
+      stream << "Host: " << _request.get_url().get_server_and_port();
     }
     }
     stream << "\r\n";
     stream << "\r\n";
     if (!get_persistent_connection()) {
     if (!get_persistent_connection()) {
@@ -3703,14 +3726,14 @@ show_send(const string &message) {
   size_t newline = message.find('\n', start);
   size_t newline = message.find('\n', start);
   while (newline != string::npos) {
   while (newline != string::npos) {
     // Assume every \n is preceded by a \r.
     // Assume every \n is preceded by a \r.
-    downloader_cat.debug()
+    downloader_cat.spam()
       << "send: " << message.substr(start, newline - start - 1) << "\n";
       << "send: " << message.substr(start, newline - start - 1) << "\n";
     start = newline + 1;
     start = newline + 1;
     newline = message.find('\n', start);
     newline = message.find('\n', start);
   }
   }
 
 
   if (start < message.length()) {
   if (start < message.length()) {
-    downloader_cat.debug()
+    downloader_cat.spam()
       << "send: " << message.substr(start) << " (no newline)\n";
       << "send: " << message.substr(start) << " (no newline)\n";
   }
   }
 }
 }

+ 26 - 24
panda/src/downloader/urlSpec.I

@@ -19,14 +19,6 @@ URLSpec(const string &url, bool server_name_expected) {
   set_url(url, server_name_expected);
   set_url(url, server_name_expected);
 }
 }
 
 
-/**
- *
- */
-INLINE URLSpec::
-URLSpec(const URLSpec &copy) {
-  (*this) = copy;
-}
-
 /**
 /**
  *
  *
  */
  */
@@ -40,7 +32,7 @@ operator = (const string &url) {
  */
  */
 INLINE bool URLSpec::
 INLINE bool URLSpec::
 operator == (const URLSpec &other) const {
 operator == (const URLSpec &other) const {
-  return _url == other._url;
+  return compare_to(other) == 0;
 }
 }
 
 
 /**
 /**
@@ -48,7 +40,7 @@ operator == (const URLSpec &other) const {
  */
  */
 INLINE bool URLSpec::
 INLINE bool URLSpec::
 operator != (const URLSpec &other) const {
 operator != (const URLSpec &other) const {
-  return !operator == (other);
+  return compare_to(other) != 0;
 }
 }
 
 
 /**
 /**
@@ -56,16 +48,7 @@ operator != (const URLSpec &other) const {
  */
  */
 INLINE bool URLSpec::
 INLINE bool URLSpec::
 operator < (const URLSpec &other) const {
 operator < (const URLSpec &other) const {
-  return _url < other._url;
-}
-
-/**
- * Returns a number less than zero if this URLSpec sorts before the other one,
- * greater than zero if it sorts after, or zero if they are equivalent.
- */
-INLINE int URLSpec::
-compare_to(const URLSpec &other) const {
-  return strcmp(_url.c_str(), other._url.c_str());
+  return compare_to(other) < 0;
 }
 }
 
 
 /**
 /**
@@ -148,7 +131,8 @@ get_username() const {
 }
 }
 
 
 /**
 /**
- * Returns the server name specified by the URL, if any.
+ * Returns the server name specified by the URL, if any.  In case of an IPv6
+ * address, does not include the enclosing brackets.
  */
  */
 INLINE string URLSpec::
 INLINE string URLSpec::
 get_server() const {
 get_server() const {
@@ -218,13 +202,23 @@ c_str() const {
 }
 }
 
 
 /**
 /**
- *
+ * Returns false if the URLSpec is valid (not empty), or true if it is an
+ * empty string.
  */
  */
 INLINE bool URLSpec::
 INLINE bool URLSpec::
 empty() const {
 empty() const {
   return _url.empty();
   return _url.empty();
 }
 }
 
 
+/**
+ * Returns true if the URLSpec is valid (not empty), or false if it is an
+ * empty string.
+ */
+INLINE URLSpec::
+operator bool() const {
+  return !_url.empty();
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -233,12 +227,20 @@ length() const {
   return _url.length();
   return _url.length();
 }
 }
 
 
+/**
+ *
+ */
+INLINE size_t URLSpec::
+size() const {
+  return _url.size();
+}
+
 /**
 /**
  *
  *
  */
  */
 INLINE char URLSpec::
 INLINE char URLSpec::
-operator [] (int n) const {
-  nassertr(n >= 0 && n < (int)_url.length(), '\0');
+operator [] (size_t n) const {
+  nassertr(n < _url.length(), '\0');
   return _url[n];
   return _url[n];
 }
 }
 
 

+ 166 - 34
panda/src/downloader/urlSpec.cxx

@@ -12,10 +12,11 @@
  */
  */
 
 
 #include "urlSpec.h"
 #include "urlSpec.h"
+#include "filename.h"
+#include "string_utils.h"
 
 
 #include <ctype.h>
 #include <ctype.h>
 
 
-
 /**
 /**
  *
  *
  */
  */
@@ -35,24 +36,88 @@ URLSpec() {
   _query_start = 0;
   _query_start = 0;
 }
 }
 
 
+/**
+ * Creates a URLSpec by appending a path to the end of the old URLSpec,
+ * inserting an intervening forward slash if necessary.
+ */
+URLSpec::
+URLSpec(const URLSpec &url, const Filename &path) {
+  (*this) = url;
+  if (!path.empty()) {
+    string dirname = get_path();
+
+    // Check if the path already ends in a slash.
+    if (!dirname.empty() && dirname.back() == '/') {
+      if (path[0] == '/') {
+        // And the filename begins with one.  Remove the extra slash.
+        dirname.resize(dirname.size() - 1);
+      }
+    } else {
+      if (path[0] != '/') {
+        // Neither has a slash, so insert one.
+        dirname += '/';
+      }
+    }
+    set_path(dirname + path.get_fullpath());
+  }
+}
+
+/**
+ * Returns a number less than zero if this URLSpec sorts before the other one,
+ * greater than zero if it sorts after, or zero if they are equivalent.
+ */
+int URLSpec::
+compare_to(const URLSpec &other) const {
+  int cmp;
+  if (has_scheme() != other.has_scheme()) {
+    return (has_scheme() < other.has_scheme()) ? -1 : 1;
+  }
+  if (has_scheme()) {
+    cmp = cmp_nocase(get_scheme(), other.get_scheme());
+    if (cmp != 0) {
+      return cmp;
+    }
+  }
+  if (has_username() != other.has_username()) {
+    return (has_username() < other.has_username()) ? -1 : 1;
+  }
+  if (has_username()) {
+    cmp = get_username().compare(other.get_username());
+    if (cmp != 0) {
+      return cmp;
+    }
+  }
+  if (has_server() != other.has_server()) {
+    return (has_server() < other.has_server()) ? -1 : 1;
+  }
+  if (has_server()) {
+    cmp = cmp_nocase(get_server(), other.get_server());
+    if (cmp != 0) {
+      return cmp;
+    }
+  }
+  return get_path_and_query().compare(other.get_path_and_query());
+}
+
 /**
 /**
  *
  *
  */
  */
-void URLSpec::
-operator = (const URLSpec &copy) {
-  _url = copy._url;
-  _port = copy._port;
-  _flags = copy._flags;
-  _scheme_end = copy._scheme_end;
-  _username_start = copy._username_start;
-  _username_end = copy._username_end;
-  _server_start = copy._server_start;
-  _server_end = copy._server_end;
-  _port_start = copy._port_start;
-  _port_end = copy._port_end;
-  _path_start = copy._path_start;
-  _path_end = copy._path_end;
-  _query_start = copy._query_start;
+size_t URLSpec::
+get_hash() const {
+  size_t hash = 0;
+  hash = int_hash::add_hash(hash, _flags & (F_has_scheme | F_has_username | F_has_server));
+  if (has_scheme()) {
+    hash = string_hash::add_hash(hash, downcase(get_scheme()));
+  }
+  if (has_username()) {
+    hash = string_hash::add_hash(hash, get_username());
+  }
+  if (has_server()) {
+    hash = string_hash::add_hash(hash, downcase(get_server()));
+  }
+  hash = int_hash::add_hash(hash, get_port());
+  hash = string_hash::add_hash(hash, get_path_and_query());
+  return hash;
 }
 }
 
 
 /**
 /**
@@ -71,7 +136,7 @@ get_scheme() const {
  * Returns the port number specified by the URL, or the default port if not
  * Returns the port number specified by the URL, or the default port if not
  * specified.
  * specified.
  */
  */
-int URLSpec::
+uint16_t URLSpec::
 get_port() const {
 get_port() const {
   if (has_port()) {
   if (has_port()) {
     return _port;
     return _port;
@@ -115,14 +180,25 @@ get_default_port_for_scheme(const string &scheme) {
  * Returns a string consisting of the server name, followed by a colon,
  * Returns a string consisting of the server name, followed by a colon,
  * followed by the port number.  If the port number is not explicitly given in
  * followed by the port number.  If the port number is not explicitly given in
  * the URL, this string will include the implicit port number.
  * the URL, this string will include the implicit port number.
+ * If the server is an IPv6 address, it will be enclosed in square brackets.
  */
  */
 string URLSpec::
 string URLSpec::
 get_server_and_port() const {
 get_server_and_port() const {
+  ostringstream strm;
+  string server = get_server();
+  if (server.find(':') != string::npos) {
+    // Protect an IPv6 address by enclosing it in square brackets.
+    strm << '[' << server << ']';
+
+  } else {
+    if (!has_port()) {
+      return server;
+    }
+    strm << server;
+  }
   if (has_port()) {
   if (has_port()) {
-    return _url.substr(_server_start, _port_end - _server_start);
+    strm << ":" << get_port();
   }
   }
-  ostringstream strm;
-  strm << get_server() << ":" << get_port();
   return strm.str();
   return strm.str();
 }
 }
 
 
@@ -285,7 +361,15 @@ set_username(const string &username) {
   if (!username.empty()) {
   if (!username.empty()) {
     authority = username + "@";
     authority = username + "@";
   }
   }
-  authority += get_server();
+
+  string server = get_server();
+  if (server.find(':') != string::npos) {
+    // Protect an IPv6 address by enclosing it in square brackets.
+    authority += "[" + server + "]";
+  } else {
+    authority += server;
+  }
+
   if (has_port()) {
   if (has_port()) {
     authority += ":";
     authority += ":";
     authority += get_port_str();
     authority += get_port_str();
@@ -296,6 +380,8 @@ set_username(const string &username) {
 
 
 /**
 /**
  * Replaces the server part of the URL specification.
  * Replaces the server part of the URL specification.
+ * Unlike set_server_and_port, this method does not require IPv6 addresses to
+ * be enclosed in square brackets.
  */
  */
 void URLSpec::
 void URLSpec::
 set_server(const string &server) {
 set_server(const string &server) {
@@ -307,7 +393,14 @@ set_server(const string &server) {
   if (has_username()) {
   if (has_username()) {
     authority = get_username() + "@";
     authority = get_username() + "@";
   }
   }
-  authority += server;
+
+  if (server.find(':') != string::npos) {
+    // Protect an IPv6 address by enclosing it in square brackets.
+    authority += "[" + server + "]";
+  } else {
+    authority += server;
+  }
+
   if (has_port()) {
   if (has_port()) {
     authority += ":";
     authority += ":";
     authority += get_port_str();
     authority += get_port_str();
@@ -329,7 +422,14 @@ set_port(const string &port) {
   if (has_username()) {
   if (has_username()) {
     authority = get_username() + "@";
     authority = get_username() + "@";
   }
   }
-  authority += get_server();
+
+  string server = get_server();
+  if (server.find(':') != string::npos) {
+    // Protect an IPv6 address by enclosing it in square brackets.
+    authority += "[" + server + "]";
+  } else {
+    authority += server;
+  }
 
 
   if (!port.empty()) {
   if (!port.empty()) {
     authority += ":";
     authority += ":";
@@ -344,16 +444,15 @@ set_port(const string &port) {
  * number.
  * number.
  */
  */
 void URLSpec::
 void URLSpec::
-set_port(int port) {
-  ostringstream str;
-  str << port;
-  set_port(str.str());
+set_port(uint16_t port) {
+  set_port(format_string(port));
 }
 }
 
 
 /**
 /**
  * Replaces the server and port parts of the URL specification simultaneously.
  * Replaces the server and port parts of the URL specification simultaneously.
  * The input string should be of the form "server:port", or just "server" to
  * The input string should be of the form "server:port", or just "server" to
  * make the port number implicit.
  * make the port number implicit.
+ * Any IPv6 address must be enclosed in square brackets.
  */
  */
 void URLSpec::
 void URLSpec::
 set_server_and_port(const string &server_and_port) {
 set_server_and_port(const string &server_and_port) {
@@ -476,6 +575,18 @@ set_url(const string &url, bool server_name_expected) {
     }
     }
   }
   }
 
 
+  // Now normalize the percent-encoding sequences by making them uppercase.
+  for (p = 0; p + 2 < _url.length();) {
+    if (_url[p++] == '%') {
+      if (_url[p] != '%') {
+        _url[p] = toupper(_url[p]);
+        ++p;
+        _url[p] = toupper(_url[p]);
+      }
+      ++p;
+    }
+  }
+
   // What have we got?
   // What have we got?
   _flags = 0;
   _flags = 0;
   _port = 0;
   _port = 0;
@@ -781,18 +892,39 @@ parse_authority() {
     _server_start = at_sign + 1;
     _server_start = at_sign + 1;
   }
   }
 
 
-  // Is there a port?
-  size_t colon = _url.find(':', _server_start);
-  if (colon < _port_end) {
-    // Yep.
+  // Is this an IPv6 address in square brackets?
+  size_t bracket = _url.find('[', _server_start);
+  if (bracket < _port_end) {
+    // We won't include the brackets in the server name.
+    ++_server_start;
+
+    bracket = _url.find(']');
+    if (bracket < _server_end) {
+      _server_end = bracket;
+
+      // Is it followed directly by a port colon?
+      size_t colon = _url.find(':', _server_end);
+      if (colon < _port_end) {
+        _port_start = colon + 1;
+      }
+    }
+  } else {
+    // Is there a port?
+    size_t colon = _url.find(':', _server_start);
+    if (colon < _port_end) {
+      // Yep.
+      _server_end = colon;
+      _port_start = colon + 1;
+    }
+  }
+
+  if (_port_start < _port_end) {
     _flags |= F_has_port;
     _flags |= F_has_port;
-    _server_end = colon;
-    _port_start = colon + 1;
 
 
     // Decode the port into an integer.  Don't bother to error check if it's
     // Decode the port into an integer.  Don't bother to error check if it's
     // not really an integer.
     // not really an integer.
     string port_str = _url.substr(_port_start, _port_end - _port_start);
     string port_str = _url.substr(_port_start, _port_end - _port_start);
-    _port = atoi(port_str.c_str());
+    _port = (uint16_t)atoi(port_str.c_str());
   }
   }
 
 
   // Make sure the server name is lowercase only.
   // Make sure the server name is lowercase only.

+ 21 - 7
panda/src/downloader/urlSpec.h

@@ -17,6 +17,8 @@
 #include "pandabase.h"
 #include "pandabase.h"
 #include "pnotify.h"
 #include "pnotify.h"
 
 
+class Filename;
+
 /**
 /**
  * A container for a URL, e.g.  "http://server:port/path".
  * A container for a URL, e.g.  "http://server:port/path".
  *
  *
@@ -27,14 +29,14 @@ class EXPCL_PANDAEXPRESS URLSpec {
 PUBLISHED:
 PUBLISHED:
   URLSpec();
   URLSpec();
   INLINE URLSpec(const string &url, bool server_name_expected = false);
   INLINE URLSpec(const string &url, bool server_name_expected = false);
-  INLINE URLSpec(const URLSpec &copy);
+  URLSpec(const URLSpec &url, const Filename &path);
   INLINE void operator = (const string &url);
   INLINE void operator = (const string &url);
-  void operator = (const URLSpec &copy);
 
 
   INLINE bool operator == (const URLSpec &other) const;
   INLINE bool operator == (const URLSpec &other) const;
   INLINE bool operator != (const URLSpec &other) const;
   INLINE bool operator != (const URLSpec &other) const;
   INLINE bool operator < (const URLSpec &other) const;
   INLINE bool operator < (const URLSpec &other) const;
-  INLINE int compare_to(const URLSpec &other) const;
+  int compare_to(const URLSpec &other) const;
+  size_t get_hash() const;
 
 
   INLINE bool has_scheme() const;
   INLINE bool has_scheme() const;
   INLINE bool has_authority() const;
   INLINE bool has_authority() const;
@@ -49,7 +51,7 @@ PUBLISHED:
   INLINE string get_username() const;
   INLINE string get_username() const;
   INLINE string get_server() const;
   INLINE string get_server() const;
   INLINE string get_port_str() const;
   INLINE string get_port_str() const;
-  int get_port() const;
+  uint16_t get_port() const;
   string get_server_and_port() const;
   string get_server_and_port() const;
   bool is_default_port() const;
   bool is_default_port() const;
   static int get_default_port_for_scheme(const string &scheme);
   static int get_default_port_for_scheme(const string &scheme);
@@ -65,7 +67,7 @@ PUBLISHED:
   void set_username(const string &username);
   void set_username(const string &username);
   void set_server(const string &server);
   void set_server(const string &server);
   void set_port(const string &port);
   void set_port(const string &port);
-  void set_port(int port);
+  void set_port(uint16_t port);
   void set_server_and_port(const string &server_and_port);
   void set_server_and_port(const string &server_and_port);
   void set_path(const string &path);
   void set_path(const string &path);
   void set_query(const string &query);
   void set_query(const string &query);
@@ -75,8 +77,10 @@ PUBLISHED:
   INLINE operator const string & () const;
   INLINE operator const string & () const;
   INLINE const char *c_str() const;
   INLINE const char *c_str() const;
   INLINE bool empty() const;
   INLINE bool empty() const;
+  INLINE operator bool() const;
   INLINE size_t length() const;
   INLINE size_t length() const;
-  INLINE char operator [] (int n) const;
+  INLINE size_t size() const;
+  INLINE char operator [] (size_t n) const;
 
 
   bool input(istream &in);
   bool input(istream &in);
   void output(ostream &out) const;
   void output(ostream &out) const;
@@ -86,6 +90,16 @@ PUBLISHED:
   static string unquote(const string &source);
   static string unquote(const string &source);
   static string unquote_plus(const string &source);
   static string unquote_plus(const string &source);
 
 
+  MAKE_PROPERTY(scheme, get_scheme, set_scheme);
+  MAKE_PROPERTY(authority, get_authority, set_authority);
+  MAKE_PROPERTY(username, get_username, set_username);
+  MAKE_PROPERTY(server, get_server, set_server);
+  MAKE_PROPERTY(port, get_port, set_port);
+  MAKE_PROPERTY(server_and_port, get_server_and_port, set_server_and_port);
+  MAKE_PROPERTY(path, get_path, set_path);
+  MAKE_PROPERTY(query, get_query, set_query);
+  MAKE_PROPERTY(ssl, is_ssl);
+
 private:
 private:
   void parse_authority();
   void parse_authority();
 
 
@@ -100,7 +114,7 @@ private:
   };
   };
 
 
   string _url;
   string _url;
-  int _port;
+  uint16_t _port;
   int _flags;
   int _flags;
 
 
   size_t _scheme_end;
   size_t _scheme_end;

+ 1 - 0
panda/src/nativenet/p3nativenet_composite1.cxx

@@ -1,5 +1,6 @@
 #include "config_nativenet.cxx"
 #include "config_nativenet.cxx"
 #include "buffered_datagramconnection.cxx"
 #include "buffered_datagramconnection.cxx"
+#include "socket_address.cxx"
 #include "socket_ip.cxx"
 #include "socket_ip.cxx"
 #include "socket_tcp.cxx"
 #include "socket_tcp.cxx"
 #include "socket_tcp_listen.cxx"
 #include "socket_tcp_listen.cxx"

+ 139 - 110
panda/src/nativenet/socket_address.I

@@ -12,41 +12,68 @@
  */
  */
 
 
 /**
 /**
- * Return a RAW sockaddr_in
+ * Constructor that lets us set a port value
  */
  */
-INLINE unsigned long Socket_Address::
-GetIPAddressRaw() const {
-  return _addr.sin_addr.s_addr;
+INLINE Socket_Address::
+Socket_Address(unsigned short port) {
+  _addr4.sin_family = AF_INET;
+  _addr4.sin_addr.s_addr = INADDR_ANY;
+  _addr4.sin_port = htons(port);
 }
 }
 
 
 /**
 /**
- * Constructor that lets us set a port value
+ *
  */
  */
 INLINE Socket_Address::
 INLINE Socket_Address::
-Socket_Address(unsigned short port) {
-  _addr.sin_family = AF_INET;
-  _addr.sin_addr.s_addr = INADDR_ANY;
-  _addr.sin_port = htons(port);
+Socket_Address(const Socket_Address &inaddr) :
+  _storage(inaddr._storage) {
+}
+
+/**
+ *
+ */
+INLINE Socket_Address::
+Socket_Address(const struct sockaddr &inaddr) {
+  if (inaddr.sa_family == AF_INET) {
+    _addr4 = (const sockaddr_in &)inaddr;
+
+  } else if (inaddr.sa_family == AF_INET6) {
+    _addr6 = (const sockaddr_in6 &)inaddr;
+
+  } else {
+    nassertv(false);
+    clear();
+  }
+}
+
+/**
+ *
+ */
+INLINE Socket_Address::
+Socket_Address(const struct sockaddr_in &inaddr) :
+  _addr4(inaddr) {
 }
 }
 
 
 /**
 /**
  *
  *
  */
  */
 INLINE Socket_Address::
 INLINE Socket_Address::
-Socket_Address(const Socket_Address &inaddr) {
-  _addr.sin_family = inaddr._addr.sin_family;
-  _addr.sin_addr.s_addr = inaddr._addr.sin_addr.s_addr;
-  _addr.sin_port = inaddr._addr.sin_port;
+Socket_Address(const struct sockaddr_in6 &inaddr) :
+  _addr6(inaddr) {
+
+  if (IN6_IS_ADDR_V4MAPPED(&_addr6.sin6_addr) != 0) {
+    // This is really an IPv4 address disguised as an IPv6 address.
+    _addr4.sin_family = AF_INET;
+    _addr4.sin_addr.s_addr = ((uint32_t *)&_addr6.sin6_addr)[3];
+  }
 }
 }
 
 
 /**
 /**
  *
  *
  */
  */
 INLINE Socket_Address::
 INLINE Socket_Address::
-Socket_Address(const AddressType &inaddr) {
-  _addr.sin_family = inaddr.sin_family;
-  _addr.sin_addr.s_addr = inaddr.sin_addr.s_addr;
-  _addr.sin_port = inaddr.sin_port;
+Socket_Address(const struct sockaddr_storage &inaddr) :
+  _storage(inaddr) {
 }
 }
 
 
 /**
 /**
@@ -61,9 +88,24 @@ INLINE Socket_Address::
  */
  */
 INLINE bool Socket_Address::
 INLINE bool Socket_Address::
 operator == (const Socket_Address &in) const {
 operator == (const Socket_Address &in) const {
-  return ((_addr.sin_family == in._addr.sin_family) &&
-          (_addr.sin_addr.s_addr == in._addr.sin_addr.s_addr) &&
-          (_addr.sin_port == in._addr.sin_port));
+  if (_storage.ss_family != in._storage.ss_family) {
+    return false;
+  }
+
+  if (_storage.ss_family == AF_INET) {
+    return _addr4.sin_port == in._addr4.sin_port &&
+           _addr4.sin_addr.s_addr == in._addr4.sin_addr.s_addr;
+
+  } else if (_storage.ss_family == AF_INET6) {
+    return _addr6.sin6_port != in._addr6.sin6_port &&
+           memcmp((char *) &_addr6.sin6_addr,
+                  (char *) &in._addr6.sin6_addr,
+                  sizeof(_addr6.sin6_addr)) == 0;
+  }
+
+  // Unsupported address family.
+  nassertr(false, false);
+  return false;
 }
 }
 
 
 /**
 /**
@@ -71,9 +113,7 @@ operator == (const Socket_Address &in) const {
  */
  */
 INLINE bool Socket_Address::
 INLINE bool Socket_Address::
 operator != (const Socket_Address &in) const {
 operator != (const Socket_Address &in) const {
-  return ((_addr.sin_family != in._addr.sin_family) ||
-          (_addr.sin_addr.s_addr != in._addr.sin_addr.s_addr) ||
-          (_addr.sin_port != in._addr.sin_port));
+  return !operator ==(in);
 }
 }
 
 
 /**
 /**
@@ -81,9 +121,9 @@ operator != (const Socket_Address &in) const {
  */
  */
 INLINE bool Socket_Address::
 INLINE bool Socket_Address::
 set_broadcast(unsigned short port) {
 set_broadcast(unsigned short port) {
-  _addr.sin_family = AF_INET;
-  _addr.sin_addr.s_addr = 0xffffffff;
-  _addr.sin_port = htons(port);
+  _addr4.sin_family = AF_INET;
+  _addr4.sin_addr.s_addr = 0xffffffff;
+  _addr4.sin_port = htons(port);
   return true;
   return true;
 }
 }
 
 
@@ -92,9 +132,21 @@ set_broadcast(unsigned short port) {
  */
  */
 INLINE bool Socket_Address::
 INLINE bool Socket_Address::
 set_any_IP(unsigned short port) {
 set_any_IP(unsigned short port) {
-  _addr.sin_family = AF_INET;
-  _addr.sin_addr.s_addr = INADDR_ANY;
-  _addr.sin_port = htons(port);
+  _addr4.sin_family = AF_INET;
+  _addr4.sin_addr.s_addr = INADDR_ANY;
+  _addr4.sin_port = htons(port);
+  return true;
+}
+
+/**
+ * Set to any IPv6 address and a specified port.
+ */
+INLINE bool Socket_Address::
+set_any_IPv6(unsigned short port) {
+  _addr6.sin6_family = AF_INET6;
+  _addr6.sin6_addr = in6addr_any;
+  _addr6.sin6_port = htons(port);
+  _addr6.sin6_scope_id = 0;
   return true;
   return true;
 }
 }
 
 
@@ -103,7 +155,7 @@ set_any_IP(unsigned short port) {
  */
  */
 INLINE bool Socket_Address::
 INLINE bool Socket_Address::
 set_port(unsigned short port) {
 set_port(unsigned short port) {
-  _addr.sin_port = htons(port);
+  _addr4.sin_port = htons(port);
   return true;
   return true;
 }
 }
 
 
@@ -112,122 +164,99 @@ set_port(unsigned short port) {
  */
  */
 INLINE void Socket_Address::
 INLINE void Socket_Address::
 clear() {
 clear() {
-  _addr.sin_family = AF_INET;
-  _addr.sin_addr.s_addr = INADDR_ANY;
-  _addr.sin_port = htons(0);
+  _addr4.sin_family = AF_INET;
+  _addr4.sin_addr.s_addr = INADDR_ANY;
+  _addr4.sin_port = htons(0);
 }
 }
 
 
 /**
 /**
- * Get the port portion as an integer
+ * Returns AF_INET if this is an IPv4 address, or AF_INET6 if this is an IPv6
+ * address.
  */
  */
-INLINE unsigned short Socket_Address::
-get_port() const {
-  return ntohs(_addr.sin_port);
+INLINE sa_family_t Socket_Address::
+get_family() const {
+  return _storage.ss_family;
 }
 }
 
 
 /**
 /**
- * Return the IP address portion in dot notation string
+ * Get the port portion as an integer
  */
  */
-INLINE std::string Socket_Address::
-get_ip() const {
-  return std::string(inet_ntoa(_addr.sin_addr));
+INLINE unsigned short Socket_Address::
+get_port() const {
+  return ntohs(_addr4.sin_port);
 }
 }
 
 
 /**
 /**
- * Return the ip address/port in dot notation string
+ *
  */
  */
-INLINE std::string Socket_Address::
-get_ip_port() const {
-  char buf1[100];  // 100 is more than enough for any ip address:port combo..
-  sprintf(buf1, "%s:%d", inet_ntoa(_addr.sin_addr), get_port());
-  return std::string(buf1);
+INLINE bool Socket_Address::
+set_host(uint32_t in_hostname, unsigned short port) {
+  memcpy(&_addr4.sin_addr, &in_hostname, sizeof(in_hostname));
+  _addr4.sin_port = htons(port);
+  _addr4.sin_family = AF_INET;
+  return true;
 }
 }
 
 
 /**
 /**
- * This function will take a port and string-based TCP address and initialize
- * the address with this information.  Returns true on success; on failure, it
- * returns false and the address may be undefined.
+ *
  */
  */
 INLINE bool Socket_Address::
 INLINE bool Socket_Address::
-set_host(const std::string &hostname, unsigned short port) {
-  struct hostent *hp = NULL;
-
-  // hmm inet_addr does not resolve 255.255.255.255 on ME98 ?? * HACK * ??
-  if (hostname  == "255.255.255.255") {
-    return set_broadcast(port);
+operator < (const Socket_Address &in) const {
+  if (_storage.ss_family != in._storage.ss_family) {
+    return _storage.ss_family < in._storage.ss_family;
   }
   }
 
 
-
-  uint32_t addr = (uint32_t)inet_addr(hostname.c_str());
-  if (addr == INADDR_NONE) {
-    hp = gethostbyname(hostname.c_str());
-    if (hp == NULL) {
-      return false;
-    } else {
-      memcpy(&_addr.sin_addr, hp->h_addr_list[0], (unsigned int) hp->h_length);
+  if (_storage.ss_family == AF_INET) {
+    if (_addr4.sin_port != in._addr4.sin_port) {
+      return _addr4.sin_port < in._addr4.sin_port;
     }
     }
-  } else {
-    memcpy(&_addr.sin_addr, &addr, sizeof(addr));
-  }
 
 
-  _addr.sin_port = htons(port);
-  _addr.sin_family = AF_INET;
-  return true;
-}
+    return _addr4.sin_addr.s_addr < in._addr4.sin_addr.s_addr;
 
 
-/**
- *
- */
-INLINE bool Socket_Address::
-set_host(const std::string &hostname) {
-  std::string::size_type pos = hostname.find(':');
-  if (pos == std::string::npos)
-    return false;
+  } else if (_storage.ss_family == AF_INET6) {
+    if (_addr6.sin6_port != in._addr6.sin6_port) {
+      return _addr6.sin6_port < in._addr6.sin6_port;
+    }
 
 
-  std::string host = hostname.substr(0, pos);
-  std::string port = hostname.substr(pos + 1, 100);;
+    return IN6_ARE_ADDR_EQUAL(&_addr6.sin6_addr, &in._addr6.sin6_addr) != 0;
+  }
 
 
-  unsigned short port_dig = (unsigned short)atoi(port.c_str());
-  return set_host(host, port_dig);
+  // Unsupported address family.
+  nassertr(false, false);
+  return false;
 }
 }
 
 
 /**
 /**
- *
+ * True if the address is zero.
  */
  */
 INLINE bool Socket_Address::
 INLINE bool Socket_Address::
-set_host(uint32_t in_hostname, unsigned short port) {
-  memcpy(&_addr.sin_addr, &in_hostname, sizeof(in_hostname));
-  _addr.sin_port = htons(port);
-  _addr.sin_family = AF_INET;
-  return true;
-}
-
-/**
- *
- */
-INLINE bool Socket_Address::
-operator < (const Socket_Address &in) const {
-  if (_addr.sin_port < in._addr.sin_port)
-    return true;
+is_any() const {
+  if (_storage.ss_family == AF_INET) {
+    return (_addr4.sin_addr.s_addr == 0);
 
 
-  if (_addr.sin_port > in._addr.sin_port)
-    return false;
+  } else if (_storage.ss_family == AF_INET6) {
+    return IN6_IS_ADDR_UNSPECIFIED(&_addr6.sin6_addr) != 0;
 
 
-  if (_addr.sin_addr.s_addr < in._addr.sin_addr.s_addr)
+  } else {
     return true;
     return true;
-
-  if (_addr.sin_addr.s_addr > in._addr.sin_addr.s_addr)
-    return false;
-
-  return (_addr.sin_family < in._addr.sin_family);
+  }
 }
 }
 
 
 /**
 /**
  * True if the address is in the multicast range.
  * True if the address is in the multicast range.
  */
  */
 INLINE bool Socket_Address::
 INLINE bool Socket_Address::
-is_mcast_range(void) const {
-  uint32_t address = ntohl(_addr.sin_addr.s_addr);
-  // 224.0.0.0-239.255.255.255 .. e0,ef
-  return (address >= 0xe0000000 && address < 0xefffffff);
+is_mcast_range() const {
+  if (_storage.ss_family == AF_INET) {
+    uint32_t address = ntohl(_addr4.sin_addr.s_addr);
+    // 224.0.0.0-239.255.255.255 .. e0,ef
+    return (address >= 0xe0000000 && address < 0xefffffff);
+
+  } else if (_storage.ss_family == AF_INET6) {
+    // ff00::/8
+    return IN6_IS_ADDR_MULTICAST(&_addr6.sin6_addr) != 0;
+
+  } else {
+    return false;
+  }
 }
 }

+ 157 - 0
panda/src/nativenet/socket_address.cxx

@@ -0,0 +1,157 @@
+/**
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * @file socket_address.h
+ * @author rdb
+ * @date 2016-06-17
+ */
+
+#include "socket_address.h"
+#include "config_downloader.h"
+
+/**
+ * This function will take a port and string-based TCP address and initialize
+ * the address with this information.  Returns true on success; on failure, it
+ * returns false and the address may be undefined.
+ */
+bool Socket_Address::
+set_host(const std::string &hostname, unsigned short port) {
+  // hmm inet_addr4 does not resolve 255.255.255.255 on ME98 ?? * HACK * ??
+  if (hostname == "255.255.255.255") {
+    return set_broadcast(port);
+  }
+
+  struct addrinfo hints, *res = NULL;
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_flags = AI_ADDRCONFIG;
+  hints.ai_family = support_ipv6 ? AF_UNSPEC : AF_INET;
+
+  if (getaddrinfo(hostname.c_str(), NULL, &hints, &res)) {
+    return false;
+  }
+
+  nassertr(res->ai_addrlen <= sizeof(_storage), false);
+  memcpy(&_storage, res->ai_addr, res->ai_addrlen);
+  freeaddrinfo(res);
+
+  _addr4.sin_port = htons(port);
+  return true;
+}
+
+/**
+ * Initializes the address from a string specifying both the address and port,
+ * separated by a colon.  An IPv6 address must be enclosed in brackets.
+ */
+bool Socket_Address::
+set_host(const std::string &hostname) {
+  std::string::size_type pos = hostname.rfind(':');
+  if (pos == std::string::npos) {
+    return false;
+  }
+
+  std::string::size_type host_begin = 0;
+  std::string::size_type host_end = pos;
+
+  // Strip spaces.
+  while (host_begin < host_end && isspace(hostname[host_begin])) {
+    ++host_begin;
+  }
+
+  while (host_begin < host_end && isspace(hostname[host_end - 1])) {
+    --host_end;
+  }
+
+  if (host_begin < host_end && hostname[host_begin] == '[') {
+    // Looks like an IPv6 address; extract from the brackets.
+    host_begin += 1;
+    if (hostname[host_end - 1] == ']') {
+      host_end -= 1;
+    } else {
+      return false;
+    }
+  }
+
+  std::string host = hostname.substr(host_begin, host_end - host_begin);
+  std::string port = hostname.substr(pos + 1, 100);
+
+  unsigned short port_dig = (unsigned short)atoi(port.c_str());
+  return set_host(host, port_dig);
+}
+
+/**
+ * Return the IP address portion in dot notation string.
+ */
+std::string Socket_Address::
+get_ip() const {
+  char buf[48];
+  buf[0] = 0;
+
+  if (_storage.ss_family == AF_INET) {
+    getnameinfo(&_addr, sizeof(sockaddr_in), buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
+
+  } else if (_storage.ss_family == AF_INET6) {
+    getnameinfo(&_addr, sizeof(sockaddr_in6), buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
+
+  } else {
+    nassertr(false, std::string());
+  }
+
+  return std::string(buf);
+}
+
+/**
+ * Return the ip address/port in dot notation string.  If this is an IPv6
+ * address, it will be enclosed in square brackets.
+ */
+std::string Socket_Address::
+get_ip_port() const {
+  char buf[100];  // 100 is more than enough for any ip address:port combo..
+  buf[0] = 0;
+
+  if (_storage.ss_family == AF_INET) {
+    getnameinfo(&_addr, sizeof(sockaddr_in), buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
+    sprintf(buf + strlen(buf), ":%hu", get_port());
+
+  } else if (_storage.ss_family == AF_INET6) {
+    // Protect the IPv6 address within square brackets.
+    buf[0] = '[';
+    getnameinfo(&_addr, sizeof(sockaddr_in6), buf + 1, sizeof(buf) - 1, NULL, 0, NI_NUMERICHOST);
+    sprintf(buf + strlen(buf), "]:%hu", get_port());
+
+  } else {
+    nassertr(false, std::string());
+  }
+
+  return std::string(buf);
+}
+
+/**
+ * Returns a raw 32-bit unsigned integer representing the IPv4 address.
+ * @deprecated  Does not work with IPv6 addresses.
+ */
+unsigned long Socket_Address::
+GetIPAddressRaw() const {
+  if (_addr.sa_family == AF_INET) {
+    return _addr4.sin_addr.s_addr;
+  }
+  if (_addr.sa_family == AF_INET6) {
+    // Okay, if we got here, something probably went wrong, but let's see if
+    // we can offer a meaningful translation for mapped addresses.
+    uint32_t *parts = (uint32_t *)&_addr6.sin6_addr;
+    if (parts[0] == 0 && parts[1] == 0 && (parts[2] == 0 || parts[2] == htonl(0xffff))) {
+      if (parts[2] == 0 && parts[3] == htonl(1)) {
+        // Special exception for localhost.
+        return 0x1000007f;
+      } else {
+        return parts[3];
+      }
+    }
+  }
+  nassert_raise("GetIPAddressRaw() can only be called on an IPv4 address");
+  return 0;
+}

+ 22 - 13
panda/src/nativenet/socket_address.h

@@ -11,7 +11,6 @@
  * @date 2014-10-19
  * @date 2014-10-19
  */
  */
 
 
-
 #ifndef SOCKET_ADDRESS_H
 #ifndef SOCKET_ADDRESS_H
 #define SOCKET_ADDRESS_H
 #define SOCKET_ADDRESS_H
 
 
@@ -20,15 +19,17 @@
 #include "socket_portable.h"
 #include "socket_portable.h"
 
 
 /**
 /**
- * A simple place to store and munipulate tcp and port address for
+ * A simple place to store and manipulate tcp and port address for
  * communication layer
  * communication layer
  */
  */
 class EXPCL_PANDA_NATIVENET Socket_Address {
 class EXPCL_PANDA_NATIVENET Socket_Address {
 public:
 public:
-  typedef struct sockaddr_in AddressType;
-  Socket_Address(const AddressType &inaddr);
-  AddressType &GetAddressInfo() { return _addr; }
-  const AddressType &GetAddressInfo() const { return _addr; }
+  INLINE Socket_Address(const struct sockaddr &inaddr);
+  INLINE Socket_Address(const struct sockaddr_in &inaddr);
+  INLINE Socket_Address(const struct sockaddr_in6 &inaddr);
+  INLINE Socket_Address(const struct sockaddr_storage &inaddr);
+  INLINE struct sockaddr &GetAddressInfo() { return _addr; }
+  INLINE const struct sockaddr &GetAddressInfo() const { return _addr; }
 
 
 PUBLISHED:
 PUBLISHED:
   INLINE Socket_Address(unsigned short port = 0);
   INLINE Socket_Address(unsigned short port = 0);
@@ -37,27 +38,35 @@ PUBLISHED:
   INLINE virtual ~Socket_Address();
   INLINE virtual ~Socket_Address();
 
 
   INLINE bool set_any_IP(unsigned short port);
   INLINE bool set_any_IP(unsigned short port);
+  INLINE bool set_any_IPv6(unsigned short port);
   INLINE bool set_port(unsigned short port);
   INLINE bool set_port(unsigned short port);
   INLINE bool set_broadcast(unsigned short port);
   INLINE bool set_broadcast(unsigned short port);
 
 
-  INLINE bool set_host(const std::string &hostname, unsigned short port) ;
-  INLINE bool set_host(const std::string &hostname) ;
-  INLINE bool set_host(unsigned int ip4adr, unsigned short port);
+  bool set_host(const std::string &hostname, unsigned short port);
+  bool set_host(const std::string &hostname);
+  INLINE bool set_host(uint32_t ip4addr, unsigned short port);
   INLINE void clear();
   INLINE void clear();
 
 
+  INLINE sa_family_t get_family() const;
   INLINE unsigned short get_port() const;
   INLINE unsigned short get_port() const;
-  INLINE std::string get_ip() const ;
-  INLINE std::string get_ip_port() const;
-  INLINE unsigned long GetIPAddressRaw() const;
+  std::string get_ip() const ;
+  std::string get_ip_port() const;
+  unsigned long GetIPAddressRaw() const;
 
 
   INLINE bool operator ==(const Socket_Address &in) const;
   INLINE bool operator ==(const Socket_Address &in) const;
   INLINE bool operator !=(const Socket_Address &in) const;
   INLINE bool operator !=(const Socket_Address &in) const;
   INLINE bool operator < (const Socket_Address &in) const;
   INLINE bool operator < (const Socket_Address &in) const;
 
 
+  INLINE bool is_any() const;
   INLINE bool is_mcast_range() const;
   INLINE bool is_mcast_range() const;
 
 
 private:
 private:
-  AddressType _addr;
+  union {
+    sockaddr _addr;
+    sockaddr_in _addr4;
+    sockaddr_in6 _addr6;
+    sockaddr_storage _storage;
+  };
 };
 };
 
 
 #include "socket_address.I"
 #include "socket_address.I"

+ 19 - 5
panda/src/nativenet/socket_ip.h

@@ -5,6 +5,7 @@
 #include "socket_portable.h"
 #include "socket_portable.h"
 #include "socket_address.h"
 #include "socket_address.h"
 #include "typedObject.h"
 #include "typedObject.h"
+#include "config_downloader.h"
 
 
 // forward declarations for friends...
 // forward declarations for friends...
 class Socket_TCP;
 class Socket_TCP;
@@ -35,6 +36,7 @@ PUBLISHED:
   inline int SetNonBlocking();
   inline int SetNonBlocking();
   inline int SetBlocking();
   inline int SetBlocking();
   inline bool SetReuseAddress(bool flag = true);
   inline bool SetReuseAddress(bool flag = true);
+  inline bool SetV6Only(bool flag);
   inline bool Active();
   inline bool Active();
   inline int SetRecvBufferSize(int size);
   inline int SetRecvBufferSize(int size);
   inline void SetSocket(SOCKET ins);
   inline void SetSocket(SOCKET ins);
@@ -44,7 +46,6 @@ PUBLISHED:
 
 
   inline static int InitNetworkDriver() { return init_network(); };
   inline static int InitNetworkDriver() { return init_network(); };
 
 
-public:
 private:
 private:
   inline bool ErrorClose();
   inline bool ErrorClose();
 
 
@@ -194,7 +195,7 @@ SetBlocking() {
   fcntl(_socket, F_SETFL, flags);
   fcntl(_socket, F_SETFL, flags);
   return ALL_OK;
   return ALL_OK;
 #else
 #else
-  unsigned long  val = 0;
+  unsigned long val = 0;
   unsigned lanswer = 0;
   unsigned lanswer = 0;
   lanswer = SOCKIOCTL(_socket, LOCAL_FL_SET, &val);
   lanswer = SOCKIOCTL(_socket, LOCAL_FL_SET, &val);
   if (lanswer != 0) {
   if (lanswer != 0) {
@@ -209,8 +210,21 @@ SetBlocking() {
  */
  */
 inline bool Socket_IP::
 inline bool Socket_IP::
 SetReuseAddress(bool flag) {
 SetReuseAddress(bool flag) {
-  int bOption = flag;
-  if (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&bOption, sizeof(bOption)) != 0) {
+  int value = flag;
+  if (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&value, sizeof(value)) != 0) {
+    return false;
+  }
+  return true;
+}
+
+/**
+ * Sets a flag indicating whether this IPv6 socket should operate in
+ * dual-stack mode or not.
+ */
+inline bool Socket_IP::
+SetV6Only(bool flag) {
+  int value = flag ? 1 : 0;
+  if (setsockopt(_socket, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&value, sizeof(value))) {
     return false;
     return false;
   }
   }
   return true;
   return true;
@@ -237,7 +251,7 @@ GetSocket() const {
  */
  */
 inline Socket_Address Socket_IP::
 inline Socket_Address Socket_IP::
 GetPeerName(void) const {
 GetPeerName(void) const {
-  sockaddr_in name;
+  sockaddr_storage name;
   socklen_t name_len = sizeof(name);
   socklen_t name_len = sizeof(name);
   memset(&name, 0, name_len);
   memset(&name, 0, name_len);
 
 

+ 118 - 173
panda/src/nativenet/socket_portable.h

@@ -6,10 +6,13 @@
 const int ALL_OK = 0;
 const int ALL_OK = 0;
 const int BASIC_ERROR = -1;
 const int BASIC_ERROR = -1;
 
 
+#define SA_SIZEOF(addr) (((addr)->sa_family == AF_INET6) ? sizeof(sockaddr_in6) : sizeof(sockaddr_in))
+
 #if defined(CPPPARSER)
 #if defined(CPPPARSER)
 // Interrogate doesn't need to parse any of this.
 // Interrogate doesn't need to parse any of this.
 
 
 typedef unsigned long SOCKET;
 typedef unsigned long SOCKET;
+typedef unsigned short sa_family_t;
 
 
 /************************************************************************
 /************************************************************************
 * HP SOCKET LIBRARY STUFF
 * HP SOCKET LIBRARY STUFF
@@ -46,91 +49,77 @@ typedef unsigned long SOCKET;
 /************************************************************************
 /************************************************************************
 * WINSOCK 32 bit STUFF
 * WINSOCK 32 bit STUFF
 ************************************************************************/
 ************************************************************************/
-#elif defined(WIN32) || defined(WIN32_VC) || defined(WIN64_VC)
+#elif defined(_WIN32)
 #include <winsock2.h>
 #include <winsock2.h>
 #include <Ws2tcpip.h>
 #include <Ws2tcpip.h>
 
 
+typedef u_short sa_family_t;
 
 
-inline int DO_SELECT(SOCKET n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,struct timeval *timeout)
-{
-    return select((int) n, readfds, writefds, exceptfds,timeout);
+inline int DO_SELECT(SOCKET n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) {
+  return select((int)n, readfds, writefds, exceptfds, timeout);
 }
 }
 
 
-inline int DO_CONNECT( const SOCKET a, const struct sockaddr_in *b)
-{
-    return connect(a, reinterpret_cast<const struct ::sockaddr *>(b), sizeof(sockaddr));
+inline int DO_CONNECT(const SOCKET a, const struct sockaddr *b) {
+  return connect(a, b, SA_SIZEOF(b));
+}
+inline int DO_SOCKET_READ(const SOCKET a, char *buf, const int size) {
+  return recv(a, buf, size, 0);
 }
 }
-inline int DO_SOCKET_READ(const SOCKET a, char * buf, const int size)
-{
-    return recv(a, buf, size, 0);
+inline int DO_SOCKET_WRITE(const SOCKET a, const char *buff, const int len) {
+  return send(a, buff, len, 0);
 }
 }
-inline int DO_SOCKET_WRITE(const SOCKET a, const char * buff, const int len)
-{
-    return send(a, buff, len, 0);
+inline int DO_SOCKET_WRITE_TO(const SOCKET a, const char *buffer, const int buf_len, const sockaddr *addr) {
+  return sendto(a, buffer, buf_len, 0, addr, SA_SIZEOF(addr));
 }
 }
-inline int DO_SOCKET_WRITE_TO(const SOCKET a, const char * buffer, const int buf_len, const sockaddr_in * addr)
-{
-    return sendto(a, buffer, buf_len, 0, reinterpret_cast<const struct ::sockaddr *>(addr), sizeof(sockaddr));
+inline SOCKET DO_NEWUDP(sa_family_t family) {
+  return socket(family, SOCK_DGRAM, 0);
 }
 }
-inline SOCKET DO_NEWUDP()
-{
-    return socket(AF_INET, SOCK_DGRAM, 0);
+inline SOCKET DO_NEWTCP(sa_family_t family) {
+  return socket(family, SOCK_STREAM, 0);
 }
 }
-inline SOCKET DO_NEWTCP()
-{
-    return socket(AF_INET, SOCK_STREAM, 0);
+inline int DO_BIND(const SOCKET a, const sockaddr *b) {
+  return ::bind(a, b, SA_SIZEOF(b));
 }
 }
-inline int DO_BIND(const SOCKET a, const sockaddr_in *b)
-{
-    return ::bind(a, reinterpret_cast<const struct ::sockaddr *>(b), sizeof(sockaddr));
+inline int DO_CLOSE(const SOCKET a) {
+  return closesocket(a);
 }
 }
-inline int DO_CLOSE(const SOCKET a)
-{
-    return closesocket(a);
+inline SOCKET DO_ACCEPT(SOCKET sck, sockaddr *addr) {
+  socklen_t addrlen = sizeof(sockaddr_storage);
+  return accept(sck, addr, &addrlen);
 }
 }
-inline SOCKET DO_ACCEPT(SOCKET sck, sockaddr_in * adr)
-{
-    int adrlen = sizeof(sockaddr);
-    return accept(sck, reinterpret_cast<sockaddr *>(adr), &adrlen);
-};
-inline int DO_RECV_FROM(SOCKET sck, char * data, int len, sockaddr_in * addr)
-{
-    int plen = sizeof(sockaddr);
-    return recvfrom(sck, data, len, 0, reinterpret_cast<sockaddr *>(addr), &plen);
+inline int DO_RECV_FROM(SOCKET sck, char *data, int len, sockaddr *addr) {
+  socklen_t plen = sizeof(sockaddr_storage);
+  return recvfrom(sck, data, len, 0, addr, &plen);
 }
 }
-inline int DO_LISTEN(const SOCKET a, const int size)
-{
-    return listen(a, size);
+inline int DO_LISTEN(const SOCKET a, const int size) {
+  return listen(a, size);
 }
 }
 
 
-inline int GETERROR()
-{
-    return WSAGetLastError();
+inline int GETERROR() {
+  return WSAGetLastError();
 }
 }
 
 
-inline int SOCKIOCTL(const SOCKET s, const long flags, unsigned long * val)
-{
-    return ioctlsocket(s, flags, val);
+inline int SOCKIOCTL(const SOCKET s, const long flags, unsigned long *val) {
+  return ioctlsocket(s, flags, val);
 }
 }
 
 
-inline int init_network()
-{
-    static struct WSAData mydata;
-    int answer = WSAStartup(0x0101, &mydata);
-    if (answer != 0)
-        return BASIC_ERROR;
+inline int init_network() {
+  static struct WSAData mydata;
+  int answer = WSAStartup(0x0101, &mydata);
+  if (answer != 0) {
+    return BASIC_ERROR;
+  }
 
 
-    return ALL_OK;
+  return ALL_OK;
 }
 }
 
 
-inline bool do_shutdown_send(SOCKET s)
-{
-    return (shutdown(s,SD_SEND) == 0);
-};
+inline bool do_shutdown_send(SOCKET s) {
+  return (shutdown(s, SD_SEND) == 0);
+}
 
 
-typedef  int socklen_t  ;
+typedef int socklen_t;
 const long LOCAL_NONBLOCK = 1;
 const long LOCAL_NONBLOCK = 1;
-const long LOCAL_FL_SET = FIONBIO ;
+const long LOCAL_FL_SET = FIONBIO;
 const int LOCAL_BLOCKING_ERROR = WSAEWOULDBLOCK;
 const int LOCAL_BLOCKING_ERROR = WSAEWOULDBLOCK;
 const int LOCAL_CONNECT_BLOCKING = WSAEWOULDBLOCK;
 const int LOCAL_CONNECT_BLOCKING = WSAEWOULDBLOCK;
 const int LOCAL_NOTCONNECTED_ERROR = WSAENOTCONN;
 const int LOCAL_NOTCONNECTED_ERROR = WSAENOTCONN;
@@ -162,84 +151,61 @@ const SOCKET BAD_SOCKET = (SOCKET)-1;
 typedef int SOCKET;
 typedef int SOCKET;
 const SOCKET BAD_SOCKET = 0xffffffff;
 const SOCKET BAD_SOCKET = 0xffffffff;
 
 
-// #define DO_CONNECT(a,b)               connect(a,(sockaddr
-// *)b,sizeof(sockaddr)) #define DO_SOCKET_READ(a,b,c)         recv(a,b,c,0)
-// #define DO_SOCKET_WRITE(a,b,c)        send(a,b,c,0)
-
-inline int DO_CONNECT(const SOCKET a, const sockaddr_in *b)
-{
-    return connect(a, reinterpret_cast<const struct ::sockaddr *>(b), sizeof(sockaddr));
+inline int DO_CONNECT(const SOCKET a, const sockaddr *b) {
+  return connect(a, b, SA_SIZEOF(b));
 }
 }
-inline int DO_SOCKET_READ(const SOCKET a, char * buf, const int size)
-{
-    return recv(a, buf, size, 0);
+inline int DO_SOCKET_READ(const SOCKET a, char *buf, const int size) {
+  return recv(a, buf, size, 0);
 }
 }
-inline int DO_SOCKET_WRITE(const SOCKET a, const char * buff, const int len)
-{
-    return send(a, buff, len, 0);
+inline int DO_SOCKET_WRITE(const SOCKET a, const char *buff, const int len) {
+  return send(a, buff, len, 0);
 }
 }
 
 
-// #define DO_SOCKET_WRITE_TO(a,b,c,d)   sendto(a,b,c,0,(sockaddr
-// *)d,sizeof(sockaddr)) #define DO_NEWUDP()          socket(AF_INET,
-// SOCK_DGRAM, 0) #define DO_NEWTCP()       socket(AF_INET, SOCK_STREAM, 0)
-// #define DO_BIND(a,b)      ::bind(a,(sockaddr *)b,sizeof(sockaddr)) #define
-// DO_CLOSE(a)       close(a)
-inline int DO_SOCKET_WRITE_TO(const SOCKET a, const char * buffer, const int buf_len, const sockaddr_in * addr)
-{
-    return sendto(a, buffer, buf_len, 0, reinterpret_cast<const struct ::sockaddr *>(addr), sizeof(sockaddr));
+inline int DO_SOCKET_WRITE_TO(const SOCKET a, const char *buffer, const int buf_len, const sockaddr *addr) {
+  return sendto(a, buffer, buf_len, 0, addr, SA_SIZEOF(addr));
+}
+inline SOCKET DO_NEWUDP(sa_family_t family) {
+  return socket(family, SOCK_DGRAM, 0);
 }
 }
-inline SOCKET DO_NEWUDP()
-{
-    return socket(AF_INET, SOCK_DGRAM, 0);
+inline SOCKET DO_NEWTCP(sa_family_t family) {
+  return socket(family, SOCK_STREAM, 0);
 }
 }
-inline SOCKET DO_NEWTCP()
-{
-    return socket(AF_INET, SOCK_STREAM, 0);
+inline int DO_BIND(const SOCKET a, const sockaddr *b) {
+  return ::bind(a, b, SA_SIZEOF(b));
 }
 }
-inline int DO_BIND(const SOCKET a, const sockaddr_in *b)
-{
-    return ::bind(a, reinterpret_cast<const struct ::sockaddr *>(b), sizeof(sockaddr));
+inline int DO_CLOSE(const SOCKET a) {
+  return close(a);
 }
 }
-inline int DO_CLOSE(const SOCKET a)
-{
-    return close(a);
+inline int DO_ACCEPT(SOCKET sck, sockaddr *addr) {
+  socklen_t addrlen = sizeof(sockaddr_storage);
+  return accept(sck, (sockaddr *)addr, &addrlen);
 }
 }
-inline int DO_ACCEPT(SOCKET sck, sockaddr_in * adr)
-{
-    int adrlen = sizeof(sockaddr);
-    return accept(sck, ( sockaddr *)adr, &adrlen);
-};
 
 
-inline int DO_RECV_FROM(SOCKET sck, char * data, int len, sockaddr_in * addr)
-{
-    int plen = sizeof(sockaddr);
-    return recvfrom(sck, data, len, 0, (sockaddr *)addr, &plen);
+inline int DO_RECV_FROM(SOCKET sck, char *data, int len, sockaddr *addr) {
+  socklen_t plen = sizeof(sockaddr_storage);
+  return recvfrom(sck, data, len, 0, (sockaddr *)addr, &plen);
 }
 }
-inline int DO_LISTEN(const SOCKET a, const int size)
-{
-    return listen(a, size);
+inline int DO_LISTEN(const SOCKET a, const int size) {
+  return listen(a, size);
 }
 }
 
 
-inline int GETERROR()
-{
-    return errno;
+inline int GETERROR() {
+  return errno;
 }
 }
 
 
-inline int SOCKIOCTL(const SOCKET s, const long flags, void * val)
-{
-    return ioctl(s, flags, val);
+inline int SOCKIOCTL(const SOCKET s, const long flags, void *val) {
+  return ioctl(s, flags, val);
 }
 }
 
 
-inline int init_network()
-{
-    return ALL_OK;
+inline int init_network() {
+  return ALL_OK;
 }
 }
 #ifndef INADDR_NONE
 #ifndef INADDR_NONE
 const INADDR_NONE = -1;
 const INADDR_NONE = -1;
 #endif
 #endif
 
 
 const long LOCAL_NONBLOCK = 1;
 const long LOCAL_NONBLOCK = 1;
-const long LOCAL_FL_SET = FIONBIO ;
+const long LOCAL_FL_SET = FIONBIO;
 const int LOCAL_BLOCKING_ERROR = EAGAIN;
 const int LOCAL_BLOCKING_ERROR = EAGAIN;
 const int LOCAL_CONNECT_BLOCKING = EINPROGRESS;
 const int LOCAL_CONNECT_BLOCKING = EINPROGRESS;
 
 
@@ -267,94 +233,75 @@ const int LOCAL_CONNECT_BLOCKING = EINPROGRESS;
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 #include <unistd.h>
 #include <unistd.h>
 
 
-typedef struct sockaddr_in AddressType;
-
 typedef int SOCKET;
 typedef int SOCKET;
 const SOCKET BAD_SOCKET = -1;
 const SOCKET BAD_SOCKET = -1;
-inline int DO_SELECT(SOCKET n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,struct timeval *timeout)
-{
-    return select((int) n, readfds, writefds, exceptfds,timeout);
+inline int DO_SELECT(SOCKET n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) {
+  return select((int)n, readfds, writefds, exceptfds, timeout);
 }
 }
 
 
-inline int DO_CONNECT(const SOCKET a, const sockaddr_in *b)
-{
-    return connect(a, reinterpret_cast<const struct ::sockaddr *>(b), sizeof(sockaddr));
+inline int DO_CONNECT(const SOCKET a, const sockaddr *b) {
+  return connect(a, b, SA_SIZEOF(b));
 }
 }
-inline int DO_SOCKET_READ(const SOCKET a, char * buf, const int size)
-{
-    return (int)recv(a, buf, (size_t)size, 0);
+inline int DO_SOCKET_READ(const SOCKET a, char *buf, const int size) {
+  return (int)recv(a, buf, (size_t)size, 0);
 }
 }
-inline int DO_SOCKET_WRITE(const SOCKET a, const char * buff, const int len)
-{
-    return (int)send(a, buff, (size_t)len, 0);
+inline int DO_SOCKET_WRITE(const SOCKET a, const char *buff, const int len) {
+  return (int)send(a, buff, (size_t)len, 0);
 }
 }
-inline int DO_SOCKET_WRITE_TO(const SOCKET a, const char * buffer, const int buf_len, const sockaddr_in * addr)
-{
-    return (int)sendto(a, buffer, (size_t)buf_len, 0, reinterpret_cast<const struct ::sockaddr *>(addr), sizeof(sockaddr));
+inline int DO_SOCKET_WRITE_TO(const SOCKET a, const char *buffer, const int buf_len, const sockaddr *addr) {
+  return (int)sendto(a, buffer, (size_t)buf_len, 0, addr, SA_SIZEOF(addr));
 }
 }
-inline SOCKET DO_NEWUDP()
-{
-    return socket(AF_INET, SOCK_DGRAM, 0);
+inline SOCKET DO_NEWUDP(sa_family_t family) {
+  return socket(family, SOCK_DGRAM, 0);
 }
 }
-inline SOCKET DO_NEWTCP()
-{
-    return socket(AF_INET, SOCK_STREAM, 0);
+inline SOCKET DO_NEWTCP(sa_family_t family) {
+  return socket(family, SOCK_STREAM, 0);
 }
 }
-inline int DO_BIND(const SOCKET a, const sockaddr_in *b)
-{
-    return ::bind(a, reinterpret_cast<const struct ::sockaddr *>(b), sizeof(sockaddr));
+inline int DO_BIND(const SOCKET a, const sockaddr *b) {
+  return ::bind(a, b, SA_SIZEOF(b));
 }
 }
-inline int DO_CLOSE(const SOCKET a)
-{
-    return close(a);
+inline int DO_CLOSE(const SOCKET a) {
+  return close(a);
 }
 }
 
 
-inline int DO_ACCEPT(SOCKET sck, sockaddr_in * adr)
-{
-    socklen_t adrlen = sizeof(sockaddr);
-    return accept(sck, ( sockaddr *)adr, &adrlen);
-};
+inline int DO_ACCEPT(SOCKET sck, sockaddr *addr) {
+  socklen_t addrlen = sizeof(sockaddr_storage);
+  return accept(sck, (sockaddr *)addr, &addrlen);
+}
 
 
-inline int DO_RECV_FROM(SOCKET sck, char * data, int len, sockaddr_in * addr)
-{
-    socklen_t plen = sizeof(sockaddr);
-    return (int)recvfrom(sck, data, (size_t)len, 0, (sockaddr *)addr, &plen);
+inline int DO_RECV_FROM(SOCKET sck, char *data, int len, sockaddr *addr) {
+  socklen_t plen = sizeof(sockaddr_storage);
+  return (int)recvfrom(sck, data, (size_t)len, 0, (sockaddr *)addr, &plen);
 }
 }
 
 
 
 
-inline int init_network()
-{
-    signal(SIGPIPE, SIG_IGN); // hmm do i still need this ...
-    return ALL_OK;
+inline int init_network() {
+  signal(SIGPIPE, SIG_IGN); // hmm do i still need this ...
+  return ALL_OK;
 }
 }
 
 
-inline int DO_LISTEN(const SOCKET a, const int size)
-{
-    return listen(a, size);
+inline int DO_LISTEN(const SOCKET a, const int size) {
+  return listen(a, size);
 }
 }
 
 
-inline int GETERROR()
-{
-    return errno;
+inline int GETERROR() {
+  return errno;
 }
 }
 
 
-inline int SOCKIOCTL(const SOCKET s, const long flags, void * val)
-{
-    return ioctl(s, (unsigned long)flags, val);
+inline int SOCKIOCTL(const SOCKET s, const long flags, void *val) {
+  return ioctl(s, (unsigned long)flags, val);
 }
 }
 
 
-inline bool do_shutdown_send(SOCKET s)
-{
-    return (shutdown(s,SHUT_WR) == 0);
-};
-
+inline bool do_shutdown_send(SOCKET s) {
+  return (shutdown(s, SHUT_WR) == 0);
+}
 
 
 #define  BSDBLOCK
 #define  BSDBLOCK
 
 
 
 
 const long LOCAL_NONBLOCK = 1;
 const long LOCAL_NONBLOCK = 1;
 // With BSDBLOCK defined, we don't need FIONBIO.  Solaris doesn't provide it.
 // With BSDBLOCK defined, we don't need FIONBIO.  Solaris doesn't provide it.
-// const long LOCAL_FL_SET = FIONBIO ;
+// const long LOCAL_FL_SET = FIONBIO;
 const int LOCAL_BLOCKING_ERROR = EAGAIN;
 const int LOCAL_BLOCKING_ERROR = EAGAIN;
 const int LOCAL_CONNECT_BLOCKING = EINPROGRESS;
 const int LOCAL_CONNECT_BLOCKING = EINPROGRESS;
 
 
@@ -366,6 +313,4 @@ No Host Type defined !!
 #error  Fatal
 #error  Fatal
 #endif
 #endif
 
 
-
-
 #endif //__SOCKET_PORTABLE_H__
 #endif //__SOCKET_PORTABLE_H__

+ 118 - 116
panda/src/nativenet/socket_tcp.h

@@ -8,30 +8,27 @@
  * Base functionality for a TCP connected socket This class is pretty useless
  * Base functionality for a TCP connected socket This class is pretty useless
  * by itself but it does hide some of the platform differences from machine to
  * by itself but it does hide some of the platform differences from machine to
  * machine
  * machine
- *
  */
  */
-class EXPCL_PANDA_NATIVENET Socket_TCP : public Socket_IP
-{
-public:
+class EXPCL_PANDA_NATIVENET Socket_TCP : public Socket_IP {
 PUBLISHED:
 PUBLISHED:
-    inline Socket_TCP(SOCKET);
-    inline Socket_TCP()    {   };
-    inline int  SetNoDelay(bool flag = true);
-    inline int  SetLinger(int interval_seconds = 0);
-    inline int  DontLinger();
-    inline int  SetSendBufferSize(int insize);
-    // inline bool ActiveOpen(const Socket_Address & theaddress);
-    inline bool ActiveOpen(const Socket_Address & theaddress, bool setdelay);
-    inline bool ActiveOpenNonBlocking(const Socket_Address & theaddress);
-    inline bool ErrorIs_WouldBlocking(int err);
-    inline bool ShutdownSend();
-    inline int  SendData(const std::string &str);
+  inline Socket_TCP(SOCKET);
+  inline Socket_TCP() {};
+  inline int SetNoDelay(bool flag = true);
+  inline int SetLinger(int interval_seconds = 0);
+  inline int DontLinger();
+  inline int SetSendBufferSize(int insize);
+  // inline bool ActiveOpen(const Socket_Address &theaddress);
+  inline bool ActiveOpen(const Socket_Address &theaddress, bool setdelay);
+  inline bool ActiveOpenNonBlocking(const Socket_Address &theaddress);
+  inline bool ErrorIs_WouldBlocking(int err);
+  inline bool ShutdownSend();
+  inline int SendData(const std::string &str);
 // inline int RecvData( std::string &str, int max_len);
 // inline int RecvData( std::string &str, int max_len);
 
 
-    std::string RecvData(int max_len);
+  std::string RecvData(int max_len);
 public:
 public:
-    inline int  SendData(const char * data, int size);
-    inline int  RecvData(char * data, int size);
+  inline int SendData(const char *data, int size);
+  inline int RecvData(char *data, int size);
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
@@ -54,37 +51,35 @@ private:
 /**
 /**
  *
  *
  */
  */
-inline Socket_TCP::Socket_TCP(SOCKET sck) : ::Socket_IP(sck)
-{
+inline Socket_TCP::
+Socket_TCP(SOCKET sck) : ::Socket_IP(sck) {
 }
 }
 
 
 /**
 /**
  * Disable Nagle algorithm.  Don't delay send to coalesce packets
  * Disable Nagle algorithm.  Don't delay send to coalesce packets
  */
  */
-inline int Socket_TCP::SetNoDelay(bool flag)
-{
-    int nodel = flag;
-    int ret1;
-    ret1 = setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *) & nodel, sizeof(nodel));
-
-    if (ret1 != 0)
-        return BASIC_ERROR;
-
-    return ALL_OK;
+inline int Socket_TCP::
+SetNoDelay(bool flag) {
+  int value = flag ? 1 : 0;
+  if (setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (const char *)&value, sizeof(value))) {
+    return BASIC_ERROR;
+  }
+  return ALL_OK;
 }
 }
 
 
 /**
 /**
  * will control the behavior of SO_LINGER for a TCP socket
  * will control the behavior of SO_LINGER for a TCP socket
  */
  */
-int Socket_TCP::SetLinger(int interval_seconds)
-{
-    linger ll;
-    ll.l_linger = interval_seconds;
-    ll.l_onoff = 1;
-    int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *) & ll, sizeof(linger));
-    if (ret1 != 0)
-        return BASIC_ERROR;
-    return ALL_OK;
+int Socket_TCP::
+SetLinger(int interval_seconds) {
+  linger ll;
+  ll.l_linger = interval_seconds;
+  ll.l_onoff = 1;
+  int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *)&ll, sizeof(linger));
+  if (ret1 != 0) {
+    return BASIC_ERROR;
+  }
+  return ALL_OK;
 }
 }
 
 
 /**
 /**
@@ -92,45 +87,50 @@ int Socket_TCP::SetLinger(int interval_seconds)
  * and free up OS resources.  You may lose a stream if you use this flag and
  * and free up OS resources.  You may lose a stream if you use this flag and
  * do not negotiate the close at the application layer.
  * do not negotiate the close at the application layer.
  */
  */
-int Socket_TCP::DontLinger()
-{
-    linger ll;
-    ll.l_linger = 0;
-    ll.l_onoff = 0;
-    int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *) & ll, sizeof(linger));
-    if (ret1 != 0)
-        return BASIC_ERROR;
-    return ALL_OK;
+int Socket_TCP::
+DontLinger() {
+  linger ll;
+  ll.l_linger = 0;
+  ll.l_onoff = 0;
+  int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *)&ll, sizeof(linger));
+  if (ret1 != 0) {
+    return BASIC_ERROR;
+  }
+  return ALL_OK;
 }
 }
 
 
 /**
 /**
  * Just like it sounds.  Sets a buffered socket recv buffer size.  This
  * Just like it sounds.  Sets a buffered socket recv buffer size.  This
  * function does not refuse ranges outside hard-coded OS limits
  * function does not refuse ranges outside hard-coded OS limits
  */
  */
-int Socket_TCP::SetSendBufferSize(int insize)
-{
-    if (setsockopt(_socket, (int) SOL_SOCKET, (int) SO_SNDBUF, (char *) &insize, sizeof(int)))
-        return BASIC_ERROR;
-    return ALL_OK;
+int Socket_TCP::
+SetSendBufferSize(int insize) {
+  if (setsockopt(_socket, SOL_SOCKET, SO_SNDBUF, (char *)&insize, sizeof(int))) {
+    return BASIC_ERROR;
+  }
+  return ALL_OK;
 }
 }
 
 
 /**
 /**
  * This function will try and set the socket up for active open to a specified
  * This function will try and set the socket up for active open to a specified
  * address and port provided by the input parameter
  * address and port provided by the input parameter
  */
  */
-bool Socket_TCP::ActiveOpen(const Socket_Address & theaddress, bool setdelay)
-{
-    _socket = DO_NEWTCP();
-    if (_socket == BAD_SOCKET)
-        return false;
+bool Socket_TCP::
+ActiveOpen(const Socket_Address &theaddress, bool setdelay) {
+  _socket = DO_NEWTCP(theaddress.get_family());
+  if (_socket == BAD_SOCKET) {
+    return false;
+  }
 
 
-    if(setdelay)
-        SetNoDelay();
+  if (setdelay) {
+    SetNoDelay();
+  }
 
 
-    if (DO_CONNECT(_socket, &theaddress.GetAddressInfo()) != 0)
-        return ErrorClose();
+  if (DO_CONNECT(_socket, &theaddress.GetAddressInfo()) != 0) {
+    return ErrorClose();
+  }
 
 
-    return true;
+  return true;
 }
 }
 
 
 
 
@@ -138,85 +138,87 @@ bool Socket_TCP::ActiveOpen(const Socket_Address & theaddress, bool setdelay)
  * This function will try and set the socket up for active open to a specified
  * This function will try and set the socket up for active open to a specified
  * address and port provided by the input parameter (non-blocking version)
  * address and port provided by the input parameter (non-blocking version)
  */
  */
-bool Socket_TCP::ActiveOpenNonBlocking(const Socket_Address & theaddress)
-{
-    _socket = DO_NEWTCP();
-    if (_socket == BAD_SOCKET)
-        return false;
-
-    SetNonBlocking();
-    SetReuseAddress();
-
-    if (DO_CONNECT(_socket, &theaddress.GetAddressInfo()) != 0) {
-        if (GETERROR() != LOCAL_CONNECT_BLOCKING)
-        {
-            printf(" None Blockign Connect Error %d",GETERROR());
-            return ErrorClose();
-        }
+bool Socket_TCP::
+ActiveOpenNonBlocking(const Socket_Address &theaddress) {
+  _socket = DO_NEWTCP(theaddress.get_family());
+  if (_socket == BAD_SOCKET) {
+    return false;
+  }
+
+  SetNonBlocking();
+  SetReuseAddress();
+
+  if (DO_CONNECT(_socket, &theaddress.GetAddressInfo()) != 0) {
+    if (GETERROR() != LOCAL_CONNECT_BLOCKING) {
+      printf("Non Blocking Connect Error %d", GETERROR());
+      return ErrorClose();
     }
     }
+  }
 
 
-    return true;
+  return true;
 }
 }
 
 
 /**
 /**
  * Ok Lets Send the Data - if error 0 if socket closed for write or lengh is 0
  * Ok Lets Send the Data - if error 0 if socket closed for write or lengh is 0
  * + bytes writen ( May be smaller than requested)
  * + bytes writen ( May be smaller than requested)
  */
  */
-inline int Socket_TCP::SendData(const char * data, int size)
-{
-    return DO_SOCKET_WRITE(_socket, data, size);
+inline int Socket_TCP::
+SendData(const char *data, int size) {
+  return DO_SOCKET_WRITE(_socket, data, size);
 }
 }
 
 
 /**
 /**
  * Read the data from the connection - if error 0 if socket closed for read or
  * Read the data from the connection - if error 0 if socket closed for read or
  * length is 0 + bytes read ( May be smaller than requested)
  * length is 0 + bytes read ( May be smaller than requested)
  */
  */
-inline int Socket_TCP::RecvData(char * data, int len)
-{
-    int ecode = DO_SOCKET_READ(_socket, data, len);
-    return ecode;
+inline int Socket_TCP::
+RecvData(char *data, int len) {
+  int ecode = DO_SOCKET_READ(_socket, data, len);
+  return ecode;
 }
 }
 
 
 /**
 /**
  * Read the data from the connection - if error 0 if socket closed for read or
  * Read the data from the connection - if error 0 if socket closed for read or
- * length is 0 + bytes read ( May be smaller than requested)
+ * length is 0 + bytes read (May be smaller than requested)
  */
  */
-inline std::string  Socket_TCP::RecvData(int max_len)
-{
-    std::string str;
-    char    *buffer = (char *) malloc(max_len+1);
-    int ecode  = RecvData(buffer,max_len);
-    if(ecode > 0)
-        str.assign(buffer,ecode);
-
-    free(buffer);
-    return str;
-};
+inline std::string Socket_TCP::
+RecvData(int max_len) {
+  std::string str;
+  char *buffer = (char *)malloc(max_len + 1);
+  int ecode  = RecvData(buffer, max_len);
+  if (ecode > 0) {
+    str.assign(buffer, ecode);
+  }
+
+  free(buffer);
+  return str;
+}
 
 
 
 
-inline bool Socket_TCP::ErrorIs_WouldBlocking(int err)
-{
-    return (GETERROR() == LOCAL_BLOCKING_ERROR);
+inline bool Socket_TCP::
+ErrorIs_WouldBlocking(int err) {
+  return (GETERROR() == LOCAL_BLOCKING_ERROR);
 }
 }
 
 
-inline bool Socket_TCP::ShutdownSend()
-{
-    return do_shutdown_send(_socket);
-};
+inline bool Socket_TCP::
+ShutdownSend() {
+  return do_shutdown_send(_socket);
+}
 
 
 /*
 /*
-inline bool Socket_TCP::DoNotLinger()
-{
-    int bOption = 1;
-    if (setsockopt(_socket, SOL_SOCKET, SO_DONTLINGER, (const char *)&bOption, sizeof(bOption)) != 0)
-        return false;
-    return true;
+inline bool Socket_TCP::
+DoNotLinger() {
+  int bOption = 1;
+  if (setsockopt(_socket, SOL_SOCKET, SO_DONTLINGER, (const char *)&bOption, sizeof(bOption)) != 0) {
+    return false;
+  }
+  return true;
 }
 }
 */
 */
 
 
-inline int Socket_TCP::SendData(const std::string &str)
-{
-    return SendData(str.data(), str.size());
-};
+inline int Socket_TCP::
+SendData(const std::string &str) {
+  return SendData(str.data(), str.size());
+}
 
 
 #endif //__SOCKET_TCP_H__
 #endif //__SOCKET_TCP_H__

+ 68 - 33
panda/src/nativenet/socket_tcp_listen.h

@@ -8,16 +8,17 @@
 /**
 /**
  * Base functionality for a TCP rendezvous socket
  * Base functionality for a TCP rendezvous socket
  */
  */
-class EXPCL_PANDA_NATIVENET Socket_TCP_Listen : public Socket_IP
-{
+class EXPCL_PANDA_NATIVENET Socket_TCP_Listen : public Socket_IP {
 public:
 public:
 PUBLISHED:
 PUBLISHED:
-    Socket_TCP_Listen() {};
-    ~Socket_TCP_Listen() {};
-    inline bool OpenForListen(const Socket_Address & Inaddess, int backlog_size = 1024);
-    inline bool GetIncomingConnection(Socket_TCP & newsession, Socket_Address &address);
+  Socket_TCP_Listen() {};
+  ~Socket_TCP_Listen() {};
+  inline bool OpenForListen(unsigned short port, int backlog_size = 1024);
+  inline bool OpenForListen(const Socket_Address &address, int backlog_size = 1024);
+  inline bool GetIncomingConnection(Socket_TCP &newsession, Socket_Address &address);
+
 public:
 public:
-    inline bool GetIncomingConnection(SOCKET & newsession, Socket_Address &address);
+  inline bool GetIncomingConnection(SOCKET &newsession, Socket_Address &address);
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
@@ -40,43 +41,77 @@ private:
 /**
 /**
  * This function will initialize a listening Socket
  * This function will initialize a listening Socket
  */
  */
-inline bool Socket_TCP_Listen::OpenForListen(const Socket_Address & Inaddess, int backlog_size )
-{
-    ErrorClose();
-    _socket = DO_NEWTCP();
+inline bool Socket_TCP_Listen::
+OpenForListen(unsigned short port, int backlog_size) {
+  ErrorClose();
+
+  Socket_Address address;
+  if (support_ipv6) {
+    // Create a socket supporting both IPv4 and IPv6.
+    address.set_any_IPv6(port);
+    _socket = DO_NEWTCP(AF_INET6);
+    SetV6Only(false);
+  } else {
+    address.set_any_IP(port);
+    _socket = DO_NEWTCP(AF_INET);
+  }
 
 
-    SetReuseAddress();
+  SetReuseAddress();
 
 
-    if (DO_BIND(_socket, &Inaddess.GetAddressInfo()) != 0) {
-      return ErrorClose();
-    }
+  if (DO_BIND(_socket, &address.GetAddressInfo()) != 0) {
+    return ErrorClose();
+  }
 
 
-    if (DO_LISTEN(_socket, backlog_size) != 0) {
-      return ErrorClose();
-    }
+  if (DO_LISTEN(_socket, backlog_size) != 0) {
+    return ErrorClose();
+  }
 
 
-    return true;
+  return true;
 }
 }
+
 /**
 /**
- * This function is used to accept new connections
+ * This function will initialize a listening Socket
  */
  */
-inline bool Socket_TCP_Listen::GetIncomingConnection(SOCKET & newsession, Socket_Address &address)
-{
-    newsession = DO_ACCEPT(_socket, &address.GetAddressInfo());
-    if (newsession == BAD_SOCKET)
-        return false;
-    return true;
+inline bool Socket_TCP_Listen::
+OpenForListen(const Socket_Address &address, int backlog_size) {
+  ErrorClose();
+
+  _socket = DO_NEWTCP(address.get_family());
+
+  SetReuseAddress();
+
+  if (DO_BIND(_socket, &address.GetAddressInfo()) != 0) {
+    return ErrorClose();
+  }
+
+  if (DO_LISTEN(_socket, backlog_size) != 0) {
+    return ErrorClose();
+  }
+
+  return true;
 }
 }
 
 
+/**
+ * This function is used to accept new connections
+ */
+inline bool Socket_TCP_Listen::
+GetIncomingConnection(SOCKET &newsession, Socket_Address &address) {
+  newsession = DO_ACCEPT(_socket, &address.GetAddressInfo());
+  if (newsession == BAD_SOCKET) {
+    return false;
+  }
+  return true;
+}
 
 
-inline bool Socket_TCP_Listen::GetIncomingConnection(Socket_TCP & newsession, Socket_Address &address)
-{
-    SOCKET sck;
-    if(!GetIncomingConnection(sck,address))
-        return false;
+inline bool Socket_TCP_Listen::
+GetIncomingConnection(Socket_TCP &newsession, Socket_Address &address) {
+  SOCKET sck;
+  if (!GetIncomingConnection(sck, address)) {
+    return false;
+  }
 
 
-    newsession.SetSocket(sck);
-    return true;
+  newsession.SetSocket(sck);
+  return true;
 }
 }
 
 
 #endif //__SOCKET_TCP_LISTEN_H__
 #endif //__SOCKET_TCP_LISTEN_H__

+ 162 - 170
panda/src/nativenet/socket_tcp_ssl.h

@@ -15,76 +15,64 @@
 #include <openssl/ssl.h>
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #include <openssl/err.h>
 
 
-/**
- *
-
- *
- */
-
 extern EXPCL_PANDA_NATIVENET SSL_CTX *global_ssl_ctx;
 extern EXPCL_PANDA_NATIVENET SSL_CTX *global_ssl_ctx;
 
 
+struct SSlStartup {
+  SSlStartup() {
+    const SSL_METHOD *meth;
+    SSLeay_add_ssl_algorithms();
+    // meth = SSLv23_server_method();
+    meth = SSLv23_method();
+    SSL_load_error_strings();
+    // I hate this cast, but older versions of OpenSSL need it.
+    global_ssl_ctx = SSL_CTX_new((SSL_METHOD *) meth);
+  }
 
 
-struct SSlStartup
-{
-   SSlStartup()
-   {
-        const SSL_METHOD *meth;
-        SSLeay_add_ssl_algorithms();
-        // meth = SSLv23_server_method();
-        meth = SSLv23_method();
-        SSL_load_error_strings();
-        // I hate this cast, but older versions of OpenSSL need it.
-        global_ssl_ctx = SSL_CTX_new ((SSL_METHOD *) meth);
-   }
-
-   ~SSlStartup()
-   {
-        SSL_CTX_free (global_ssl_ctx);
-        global_ssl_ctx = NULL;
-   }
-
+  ~SSlStartup() {
+    SSL_CTX_free (global_ssl_ctx);
+    global_ssl_ctx = NULL;
+  }
 
 
-   bool isactive() { return global_ssl_ctx != NULL; };
+  bool isactive() { return global_ssl_ctx != NULL; };
 };
 };
 
 
-
-class EXPCL_PANDA_NATIVENET Socket_TCP_SSL : public Socket_IP
-{
+/**
+ *
+ */
+class EXPCL_PANDA_NATIVENET Socket_TCP_SSL : public Socket_IP {
 public:
 public:
+  inline Socket_TCP_SSL(SOCKET);
+  inline Socket_TCP_SSL() : _ssl(NULL) {}
 
 
-    inline Socket_TCP_SSL(SOCKET);
-    inline Socket_TCP_SSL() : _ssl(NULL) {}
+  virtual inline ~Socket_TCP_SSL()
+  {
+      CleanSslUp();
+  }
 
 
-    virtual inline ~Socket_TCP_SSL()
-    {
-        CleanSslUp();
-    }
+  inline int SetNoDelay();
+  inline int SetLinger(int interval_seconds = 0);
+  inline int DontLinger();
 
 
-    inline int SetNoDelay();
-    inline int SetLinger(int interval_seconds = 0);
-    inline int DontLinger();
+  inline int SetSendBufferSize(int insize);
+  inline bool ActiveOpen(const Socket_Address &theaddress);
+  inline int SendData(const char *data, int size);
+  inline int RecvData(char *data, int size);
+  inline bool ErrorIs_WouldBlocking(int err);
 
 
-    inline int SetSendBufferSize(int insize);
-    inline bool ActiveOpen(const Socket_Address & theaddress);
-    inline int SendData(const char * data, int size);
-    inline int RecvData(char * data, int size);
-    inline bool ErrorIs_WouldBlocking(int err);
+  inline SSL *get_ssl() { return _ssl; };
 
 
-    inline SSL * get_ssl() { return _ssl; };
+  inline void DetailErrorFormat(void);
 
 
-    inline void DetailErrorFormat(void);
 private:
 private:
-      SSL*     _ssl;
-
-        void CleanSslUp()
-        {
-            if(_ssl != NULL)
-            {
-                SSL_shutdown(_ssl);
-                SSL_free(_ssl);
-                _ssl = NULL;
-            }
-        }
+  SSL *_ssl;
+
+  void CleanSslUp() {
+    if (_ssl != NULL) {
+      SSL_shutdown(_ssl);
+      SSL_free(_ssl);
+      _ssl = NULL;
+    }
+  }
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
@@ -128,30 +116,31 @@ Socket_TCP_SSL(SOCKET sck) : ::Socket_IP(sck) {
 /**
 /**
  * Disable Nagle algorithm.  Don't delay send to coalesce packets
  * Disable Nagle algorithm.  Don't delay send to coalesce packets
  */
  */
-inline int Socket_TCP_SSL::SetNoDelay()
-{
-    int nodel = 1;
-    int ret1;
-    ret1 = setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *) & nodel, sizeof(nodel));
-
-    if (ret1 != 0)
-        return BASIC_ERROR;
-
-    return ALL_OK;
+inline int Socket_TCP_SSL::
+SetNoDelay() {
+  int nodel = 1;
+  int ret1;
+  ret1 = setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&nodel, sizeof(nodel));
+
+  if (ret1 != 0) {
+    return BASIC_ERROR;
+  }
+  return ALL_OK;
 }
 }
 
 
 /**
 /**
  * will control the behavior of SO_LINGER for a TCP socket
  * will control the behavior of SO_LINGER for a TCP socket
  */
  */
-int Socket_TCP_SSL::SetLinger(int interval_seconds)
-{
-    linger ll;
-    ll.l_linger = interval_seconds;
-    ll.l_onoff = 1;
-    int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *) & ll, sizeof(linger));
-    if (ret1 != 0)
-        return BASIC_ERROR;
-    return ALL_OK;
+int Socket_TCP_SSL::
+SetLinger(int interval_seconds) {
+  linger ll;
+  ll.l_linger = interval_seconds;
+  ll.l_onoff = 1;
+  int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *)&ll, sizeof(linger));
+  if (ret1 != 0) {
+    return BASIC_ERROR;
+  }
+  return ALL_OK;
 }
 }
 
 
 /**
 /**
@@ -159,147 +148,150 @@ int Socket_TCP_SSL::SetLinger(int interval_seconds)
  * and free up OS resources.  You may lose a stream if you use this flag and
  * and free up OS resources.  You may lose a stream if you use this flag and
  * do not negotiate the close at the application layer.
  * do not negotiate the close at the application layer.
  */
  */
-int Socket_TCP_SSL::DontLinger()
-{
-    linger ll;
-    ll.l_linger = 0;
-    ll.l_onoff = 0;
-    int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *) & ll, sizeof(linger));
-    if (ret1 != 0)
-        return BASIC_ERROR;
-    return ALL_OK;
+int Socket_TCP_SSL::
+DontLinger() {
+  linger ll;
+  ll.l_linger = 0;
+  ll.l_onoff = 0;
+  int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *)&ll, sizeof(linger));
+  if (ret1 != 0) {
+    return BASIC_ERROR;
+  }
+  return ALL_OK;
 }
 }
 
 
 /**
 /**
  * Just like it sounds.  Sets a buffered socket recv buffer size.  This
  * Just like it sounds.  Sets a buffered socket recv buffer size.  This
  * function does not refuse ranges outside hard-coded OS limits
  * function does not refuse ranges outside hard-coded OS limits
  */
  */
-int Socket_TCP_SSL::SetSendBufferSize(int insize)
-{
-    if (setsockopt(_socket, (int) SOL_SOCKET, (int) SO_SNDBUF, (char *) &insize, sizeof(int)))
-        return BASIC_ERROR;
-    return ALL_OK;
+int Socket_TCP_SSL::
+SetSendBufferSize(int insize) {
+  if (setsockopt(_socket, (int) SOL_SOCKET, (int) SO_SNDBUF, (char *) &insize, sizeof(int))) {
+    return BASIC_ERROR;
+  }
+  return ALL_OK;
 }
 }
 
 
 /**
 /**
- * This function will try and set the socket up for active open to a specified
- * address and port provided by the input parameter
- */
-bool Socket_TCP_SSL::ActiveOpen(const Socket_Address & theaddress)
-{
-    _socket = DO_NEWTCP();
-    if (_socket == BAD_SOCKET)
-        return false;
-
-    if (DO_CONNECT(_socket, &theaddress.GetAddressInfo()) != 0)
-        return ErrorClose();
+* This function will try and set the socket up for active open to a specified
+* address and port provided by the input parameter
+*/
+bool Socket_TCP_SSL::
+ActiveOpen(const Socket_Address &theaddress) {
+  _socket = DO_NEWTCP(theaddress.get_family());
+  if (_socket == BAD_SOCKET) {
+    return false;
+  }
 
 
+  if (DO_CONNECT(_socket, &theaddress.GetAddressInfo()) != 0) {
+    return ErrorClose();
+  }
 
 
-    _ssl = SSL_new (global_ssl_ctx);
-    if(_ssl == NULL)
-        return false;
-    SSL_set_fd (_ssl,(int)GetSocket() );
-    if(SSL_connect(_ssl) == -1)
-        return false;
-    return true;
+  _ssl = SSL_new(global_ssl_ctx);
+  if (_ssl == NULL) {
+    return false;
+  }
+  SSL_set_fd(_ssl, (int)GetSocket());
+  if (SSL_connect(_ssl) == -1) {
+    return false;
+  }
+  return true;
 
 
-    // return SetSslUp();
+  // return SetSslUp();
 }
 }
 
 
 /**
 /**
  * Ok Lets Send the Data - if error 0 if socket closed for write or lengh is 0
  * Ok Lets Send the Data - if error 0 if socket closed for write or lengh is 0
  * + bytes writen ( May be smaller than requested)
  * + bytes writen ( May be smaller than requested)
  */
  */
-inline int Socket_TCP_SSL::SendData(const char * data, int size)
-{
-    if(_ssl == NULL)
-        return -1;
+inline int Socket_TCP_SSL::
+SendData(const char *data, int size) {
+  if (_ssl == NULL) {
+    return -1;
+  }
 
 
 // ERR_clear_error();
 // ERR_clear_error();
 
 
-    return SSL_write(_ssl, data, size);
+  return SSL_write(_ssl, data, size);
 }
 }
 
 
 /**
 /**
  * Read the data from the connection - if error 0 if socket closed for read or
  * Read the data from the connection - if error 0 if socket closed for read or
  * length is 0 + bytes read ( May be smaller than requested)
  * length is 0 + bytes read ( May be smaller than requested)
  */
  */
-inline int Socket_TCP_SSL::RecvData(char * data, int len)
-{
-    if(_ssl == NULL)
-        return -1;
+inline int Socket_TCP_SSL::
+RecvData(char *data, int len) {
+  if (_ssl == NULL) {
+    return -1;
+  }
 
 
-    ERR_clear_error();
+  ERR_clear_error();
 
 
-    return SSL_read(_ssl, data, len);
+  return SSL_read(_ssl, data, len);
 }
 }
 
 
 /**
 /**
  * Is last error a blocking error ?? True is last error was a blocking error
  * Is last error a blocking error ?? True is last error was a blocking error
  */
  */
-inline bool Socket_TCP_SSL::ErrorIs_WouldBlocking(int err)
-{
-    if(_ssl == NULL || err >= 0)
-    {
-      nativenet_cat.warning()
-        << "Socket_TCP_SSL::ErrorIs_WouldBlocking->Called With Error number "
-        << err << " or _ssl is NULL\n";
-        return false;
-    }
+inline bool Socket_TCP_SSL::
+ErrorIs_WouldBlocking(int err) {
+  if (_ssl == NULL || err >= 0) {
+    nativenet_cat.warning()
+      << "Socket_TCP_SSL::ErrorIs_WouldBlocking->Called With Error number "
+      << err << " or _ssl is NULL\n";
+      return false;
+  }
 
 
-    int ssl_error_code = SSL_get_error(_ssl,err);
-    bool answer = false;
+  int ssl_error_code = SSL_get_error(_ssl,err);
+  bool answer = false;
 
 
-    switch(ssl_error_code)
-    {
-        case SSL_ERROR_WANT_READ:
-        case SSL_ERROR_WANT_WRITE:
-        case SSL_ERROR_WANT_CONNECT:
+  switch(ssl_error_code) {
+  case SSL_ERROR_WANT_READ:
+  case SSL_ERROR_WANT_WRITE:
+  case SSL_ERROR_WANT_CONNECT:
 // case SSL_ERROR_WANT_ACCEPT:
 // case SSL_ERROR_WANT_ACCEPT:
-            answer = true;
-            break;
+    answer = true;
+    break;
 // hmm not sure we need this .. hmmmm
 // hmm not sure we need this .. hmmmm
-        case SSL_ERROR_SYSCALL:
-            if(GETERROR() == LOCAL_BLOCKING_ERROR)
-                answer = true;
-            else
-            {
-                DetailErrorFormat();
+  case SSL_ERROR_SYSCALL:
+    if(GETERROR() == LOCAL_BLOCKING_ERROR) {
+      answer = true;
+    } else {
+        DetailErrorFormat();
 // LOGWARNING("Socket_TCP_SSL::ErrorIs_WouldBlocking-> Not A blocking Error1
 // LOGWARNING("Socket_TCP_SSL::ErrorIs_WouldBlocking-> Not A blocking Error1
 // SSl_CODe=[%d] OS=[%d]",ssl_error_code,GETERROR());
 // SSl_CODe=[%d] OS=[%d]",ssl_error_code,GETERROR());
-            }
-            break;
-        default:
-            DetailErrorFormat();
+    }
+    break;
+  default:
+    DetailErrorFormat();
 // LOGWARNING("Socket_TCP_SSL::ErrorIs_WouldBlocking-> Not A blocking Error2
 // LOGWARNING("Socket_TCP_SSL::ErrorIs_WouldBlocking-> Not A blocking Error2
 // SSl_CODe=[%d] OS=[%d]",ssl_error_code,GETERROR());
 // SSl_CODe=[%d] OS=[%d]",ssl_error_code,GETERROR());
-            answer = false;
-            break;
-    }
+    answer = false;
+    break;
+  }
 
 
 // ERR_clear_error();
 // ERR_clear_error();
-    return answer;
+  return answer;
 }
 }
 
 
-inline void Socket_TCP_SSL::DetailErrorFormat(void)
-{
-    return; // turn on fir debuging
-
-    uint32_t l;
-    char buf[256];
-    char buf2[4096];
-    const char *file,*data;
-    int line,flags;
-    uint32_t es;
-
-    es=CRYPTO_thread_id();
-    while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
-    {
-        ERR_error_string_n(l, buf, sizeof( buf) );
-        BIO_snprintf(buf2, sizeof(buf2), "***%lu:%s:%s:%d:%s\n", (unsigned long) es, buf,file, line, (flags & ERR_TXT_STRING) ? data : "NoText");
-        nativenet_cat.warning()
-          << "Socket_TCP_SSL::DetailErrorFormat->[" << buf2 << "]\n";
-    }
+inline void Socket_TCP_SSL::
+DetailErrorFormat(void) {
+  return; // turn on for debuging
+
+  uint32_t l;
+  char buf[256];
+  char buf2[4096];
+  const char *file,*data;
+  int line,flags;
+  uint32_t es;
+
+  es = CRYPTO_thread_id();
+  while ((l = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) {
+    ERR_error_string_n(l, buf, sizeof(buf));
+    BIO_snprintf(buf2, sizeof(buf2), "***%lu:%s:%s:%d:%s\n", (unsigned long) es, buf, file, line, (flags & ERR_TXT_STRING) ? data : "NoText");
+    nativenet_cat.warning()
+      << "Socket_TCP_SSL::DetailErrorFormat->[" << buf2 << "]\n";
+  }
 }
 }
 
 
 #endif  // HAVE_OPENSSL
 #endif  // HAVE_OPENSSL

+ 37 - 48
panda/src/nativenet/socket_udp.h

@@ -21,25 +21,22 @@
  * duplicates code from Socket_UDP_Outgoing, to avoid the problems of multiple
  * duplicates code from Socket_UDP_Outgoing, to avoid the problems of multiple
  * inheritance.
  * inheritance.
  */
  */
-class EXPCL_PANDA_NATIVENET Socket_UDP : public Socket_UDP_Incoming
-{
+class EXPCL_PANDA_NATIVENET Socket_UDP : public Socket_UDP_Incoming {
 public:
 public:
 PUBLISHED:
 PUBLISHED:
-    inline Socket_UDP() { }
+  inline Socket_UDP() {}
 
 
-    // use this interface for a tagreted UDP connection
-    inline bool InitToAddress(const Socket_Address & address);
+  // use this interface for a tagreted UDP connection
+  inline bool InitToAddress(const Socket_Address &address);
 public:
 public:
-    inline bool Send(const char * data, int len);
+  inline bool Send(const char *data, int len);
 PUBLISHED:
 PUBLISHED:
-    inline bool Send(const string &data);
-    // use this interface for a none tagreted UDP connection
-    inline bool InitNoAddress();
+  inline bool Send(const string &data);
 public:
 public:
-    inline bool SendTo(const char * data, int len, const Socket_Address & address);
+  inline bool SendTo(const char *data, int len, const Socket_Address &address);
 PUBLISHED:
 PUBLISHED:
-    inline bool SendTo(const string &data, const Socket_Address & address);
-    inline bool SetToBroadCast();
+  inline bool SendTo(const string &data, const Socket_Address &address);
+  inline bool SetToBroadCast();
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
@@ -58,72 +55,64 @@ public:
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
 };
 };
-/**
- * Ask the OS to let us receive BROADCASt packets on  this port..
- */
-inline bool Socket_UDP::SetToBroadCast()
-{
-    int optval = 1;
 
 
-    if (setsockopt(_socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) != 0)
-        return false;
-    return true;
-}
 /**
 /**
- * Connects the Socket to a Specified address
+ * Ask the OS to let us receive broadcast packets on this port.
  */
  */
-inline bool Socket_UDP::InitToAddress(const Socket_Address & address)
-{
-    if (InitNoAddress() != true)
-        return false;
-
-    if (DO_CONNECT(_socket, &address.GetAddressInfo()) != 0)
-        return ErrorClose();
+inline bool Socket_UDP::
+SetToBroadCast() {
+  int optval = 1;
 
 
-    return true;
+  if (setsockopt(_socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) != 0) {
+    return false;
+  }
+  return true;
 }
 }
+
 /**
 /**
- * This will set a udp up for targeted sends..
+ * Connects the socket to a Specified address
  */
  */
-inline bool Socket_UDP::InitNoAddress()
-{
-    Close();
-    _socket = DO_NEWUDP();
-    if (_socket == BAD_SOCKET)
-        return false;
+inline bool Socket_UDP::
+InitToAddress(const Socket_Address &address) {
+  if (InitNoAddress() != true) {
+    return false;
+  }
 
 
-    return true;
+  if (DO_CONNECT(_socket, &address.GetAddressInfo()) != 0) {
+    return ErrorClose();
+  }
+  return true;
 }
 }
 
 
 /**
 /**
  * Send data to connected address
  * Send data to connected address
  */
  */
-inline bool Socket_UDP::Send(const char * data, int len)
-{
+inline bool Socket_UDP::
+Send(const char *data, int len) {
   return (DO_SOCKET_WRITE(_socket, data, len) == len);
   return (DO_SOCKET_WRITE(_socket, data, len) == len);
 }
 }
 
 
 /**
 /**
  * Send data to connected address
  * Send data to connected address
  */
  */
-inline bool Socket_UDP::Send(const string &data)
-{
+inline bool Socket_UDP::
+Send(const string &data) {
   return Send(data.data(), data.size());
   return Send(data.data(), data.size());
 }
 }
 
 
 /**
 /**
  * Send data to specified address
  * Send data to specified address
  */
  */
-inline bool Socket_UDP::SendTo(const char * data, int len, const Socket_Address & address)
-{
-    return (DO_SOCKET_WRITE_TO(_socket, data, len, &address.GetAddressInfo()) == len);
+inline bool Socket_UDP::
+SendTo(const char *data, int len, const Socket_Address &address) {
+  return (DO_SOCKET_WRITE_TO(_socket, data, len, &address.GetAddressInfo()) == len);
 }
 }
 
 
 /**
 /**
  * Send data to specified address
  * Send data to specified address
  */
  */
-inline bool Socket_UDP::SendTo(const string &data, const Socket_Address & address)
-{
+inline bool Socket_UDP::
+SendTo(const string &data, const Socket_Address &address) {
   return SendTo(data.data(), data.size(), address);
   return SendTo(data.data(), data.size(), address);
 }
 }
 
 

+ 126 - 79
panda/src/nativenet/socket_udp_incoming.h

@@ -6,21 +6,18 @@
 
 
 /**
 /**
  * Base functionality for a UDP Reader
  * Base functionality for a UDP Reader
- *
-
- *
  */
  */
-class EXPCL_PANDA_NATIVENET Socket_UDP_Incoming : public Socket_IP
-{
+class EXPCL_PANDA_NATIVENET Socket_UDP_Incoming : public Socket_IP {
 PUBLISHED:
 PUBLISHED:
-    inline Socket_UDP_Incoming() { }
+  inline Socket_UDP_Incoming() {}
 
 
-    inline bool OpenForInput(const Socket_Address & address);
-    inline bool OpenForInputMCast(const Socket_Address & address );
-    inline bool GetPacket(char * data, int *max_len, Socket_Address & address);
-    inline bool SendTo(const char * data, int len, const Socket_Address & address);
-    inline bool InitNoAddress();
-    inline bool SetToBroadCast();
+  inline bool OpenForInput(unsigned short port);
+  inline bool OpenForInput(const Socket_Address &address);
+  inline bool OpenForInputMCast(const Socket_Address &address);
+  inline bool GetPacket(char *data, int *max_len, Socket_Address &address);
+  inline bool SendTo(const char *data, int len, const Socket_Address &address);
+  inline bool InitNoAddress();
+  inline bool SetToBroadCast();
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
@@ -41,71 +38,123 @@ private:
 };
 };
 
 
 /**
 /**
- * Flips the OS bits that allow for brodcast packets to com in on this port
- *
+ * Flips the OS bits that allow for brodcast packets to come in on this port.
+ */
+inline bool Socket_UDP_Incoming::
+SetToBroadCast() {
+  int optval = 1;
+
+  if (setsockopt(_socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) != 0) {
+    return false;
+  }
+  return true;
+}
+
+/**
+ * Set this socket to work without a bound external address.
  */
  */
-inline bool Socket_UDP_Incoming::SetToBroadCast()
-{
-    int optval = 1;
+inline bool Socket_UDP_Incoming::
+InitNoAddress() {
+  Close();
+
+  if (support_ipv6) {
+    // Create a socket supporting both IPv4 and IPv6.
+    _socket = DO_NEWUDP(AF_INET6);
+    SetV6Only(false);
+  } else {
+    _socket = DO_NEWUDP(AF_INET);
+  }
 
 
-    if (setsockopt(_socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) != 0)
-        return false;
-    return true;
+  return (_socket != BAD_SOCKET);
 }
 }
+
 /**
 /**
- * Set this socket to work with out a bound external address..
+ * Starts a UDP socket listening on a port
  */
  */
-inline bool Socket_UDP_Incoming::InitNoAddress()
-{
-    Close();
-    _socket = DO_NEWUDP();
-    if (_socket == BAD_SOCKET)
-        return false;
-
-    return true;
+inline bool Socket_UDP_Incoming::
+OpenForInput(unsigned short port) {
+  Close();
+
+  Socket_Address address;
+  if (support_ipv6) {
+    // Create a socket supporting both IPv4 and IPv6.
+    address.set_any_IPv6(port);
+    _socket = DO_NEWUDP(AF_INET6);
+    SetV6Only(false);
+  } else {
+    address.set_any_IP(port);
+    _socket = DO_NEWUDP(AF_INET);
+  }
+
+  if (_socket == BAD_SOCKET) {
+    return ErrorClose();
+  }
+
+  if (DO_BIND(_socket, &address.GetAddressInfo()) != 0) {
+    return ErrorClose();
+  }
+
+  return true;
 }
 }
 
 
 /**
 /**
  * Starts a UDP socket listening on a port
  * Starts a UDP socket listening on a port
  */
  */
-inline bool Socket_UDP_Incoming::OpenForInput(const Socket_Address & address)
-{
-    Close();
-    _socket = DO_NEWUDP();
-    if (_socket == BAD_SOCKET)
-        return ErrorClose();
+inline bool Socket_UDP_Incoming::
+OpenForInput(const Socket_Address &address) {
+  Close();
+  _socket = DO_NEWUDP(address.get_family());
+  if (_socket == BAD_SOCKET) {
+    return ErrorClose();
+  }
 
 
-    if (DO_BIND(_socket, &address.GetAddressInfo()) != 0)
-        return ErrorClose();
+  if (DO_BIND(_socket, &address.GetAddressInfo()) != 0) {
+    return ErrorClose();
+  }
 
 
-    return true;
+  return true;
 }
 }
 
 
 /**
 /**
  * Starts a UDP socket listening on a port
  * Starts a UDP socket listening on a port
  */
  */
-inline bool Socket_UDP_Incoming::OpenForInputMCast(const Socket_Address & address)
-{
-    Close();
-    _socket = DO_NEWUDP();
-    if (_socket == BAD_SOCKET)
-        return ErrorClose();
-
-    Socket_Address  wa1(address.get_port());
-    if (DO_BIND(_socket, &wa1.GetAddressInfo()) != 0)
-        return ErrorClose();
-
-     struct ip_mreq imreq;
-     memset(&imreq,0,sizeof(imreq));
-     imreq.imr_multiaddr.s_addr = address.GetAddressInfo().sin_addr.s_addr;
-     imreq.imr_interface.s_addr = INADDR_ANY; // use DEFAULT interface
-
-    int status = setsockopt(GetSocket(), IPPROTO_IP, IP_ADD_MEMBERSHIP,
-              (const char *)&imreq, sizeof(struct ip_mreq));
-
-    if(status != 0)
-        return false;
-    return true;
+inline bool Socket_UDP_Incoming::
+OpenForInputMCast(const Socket_Address &address) {
+  Close();
+  _socket = DO_NEWUDP(address.get_family());
+  if (_socket == BAD_SOCKET) {
+    return ErrorClose();
+  }
+
+  Socket_Address wa1(address.get_port());
+  if (DO_BIND(_socket, &wa1.GetAddressInfo()) != 0) {
+    return ErrorClose();
+  }
+
+  int status = -1;
+
+  const sockaddr *addr = &address.GetAddressInfo();
+  if (addr->sa_family == AF_INET) {
+    struct ip_mreq imreq;
+    memset(&imreq, 0, sizeof(imreq));
+    imreq.imr_multiaddr.s_addr = ((sockaddr_in*)addr)->sin_addr.s_addr;
+    imreq.imr_interface.s_addr = INADDR_ANY; // use DEFAULT interface
+
+    status = setsockopt(GetSocket(), IPPROTO_IP, IP_ADD_MEMBERSHIP,
+                        (const char *)&imreq, sizeof(imreq));
+
+  } else if (addr->sa_family == AF_INET6) {
+    struct ipv6_mreq imreq;
+    memcpy(&imreq.ipv6mr_multiaddr,
+           &(((struct sockaddr_in6 *)addr)->sin6_addr),
+           sizeof(struct in6_addr));
+    imreq.ipv6mr_interface = 0; // use DEFAULT interface
+
+    status = setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
+                        (const char *)&imreq, sizeof(imreq));
+  }
+
+  return (status == 0);
 }
 }
 
 
 /**
 /**
@@ -113,30 +162,28 @@ inline bool Socket_UDP_Incoming::OpenForInputMCast(const Socket_Address & addres
  * address information
  * address information
  *
  *
  */
  */
-inline bool Socket_UDP_Incoming::GetPacket(char * data, int *max_len, Socket_Address & address)
-{
-    int val = DO_RECV_FROM(_socket, data, *max_len, &address.GetAddressInfo());
-    *max_len = 0;
-
-    if (val <= 0)
-    {
-        if (GetLastError() != LOCAL_BLOCKING_ERROR) // im treating a blocking error as a 0 lenght read
-            return false;
-    } else
-        *max_len = val;
-
-    return true;
+inline bool Socket_UDP_Incoming::
+GetPacket(char *data, int *max_len, Socket_Address &address) {
+  int val = DO_RECV_FROM(_socket, data, *max_len, &address.GetAddressInfo());
+  *max_len = 0;
+
+  if (val <= 0) {
+    if (GetLastError() != LOCAL_BLOCKING_ERROR) { // im treating a blocking error as a 0 lenght read
+      return false;
+    }
+  } else {
+    *max_len = val;
+  }
+
+  return true;
 }
 }
 
 
 /**
 /**
  * Send data to specified address
  * Send data to specified address
  */
  */
-inline bool Socket_UDP_Incoming::SendTo(const char * data, int len, const Socket_Address & address)
-{
-    return (DO_SOCKET_WRITE_TO(_socket, data, len, &address.GetAddressInfo()) == len);
+inline bool Socket_UDP_Incoming::
+SendTo(const char *data, int len, const Socket_Address &address) {
+  return (DO_SOCKET_WRITE_TO(_socket, data, len, &address.GetAddressInfo()) == len);
 }
 }
 
 
-
-
-
 #endif //__SOCKET_UDP_INCOMING_H__
 #endif //__SOCKET_UDP_INCOMING_H__

+ 52 - 50
panda/src/nativenet/socket_udp_outgoing.h

@@ -5,30 +5,25 @@
 #include "socket_ip.h"
 #include "socket_ip.h"
 
 
 /**
 /**
- * Base functionality for a UDP Sending Socket
- *
-
- *
+ * Base functionality for a UDP sending socket
  */
  */
-class EXPCL_PANDA_NATIVENET Socket_UDP_Outgoing : public Socket_IP
-{
-public:
+class EXPCL_PANDA_NATIVENET Socket_UDP_Outgoing : public Socket_IP {
 PUBLISHED:
 PUBLISHED:
-    inline Socket_UDP_Outgoing() { }
+  inline Socket_UDP_Outgoing() {}
 
 
-    // use this interface for a tagreted UDP connection
-    inline bool InitToAddress(const Socket_Address & address);
+  // use this interface for a tagreted UDP connection
+  inline bool InitToAddress(const Socket_Address &address);
 public:
 public:
-    inline bool Send(const char * data, int len);
+  inline bool Send(const char *data, int len);
 PUBLISHED:
 PUBLISHED:
-    inline bool Send(const string &data);
-    // use this interface for a none tagreted UDP connection
-    inline bool InitNoAddress();
+  inline bool Send(const string &data);
+  // use this interface for a none tagreted UDP connection
+  inline bool InitNoAddress();
 public:
 public:
-    inline bool SendTo(const char * data, int len, const Socket_Address & address);
+  inline bool SendTo(const char *data, int len, const Socket_Address &address);
 PUBLISHED:
 PUBLISHED:
-    inline bool SendTo(const string &data, const Socket_Address & address);
-    inline bool SetToBroadCast();
+  inline bool SendTo(const string &data, const Socket_Address &address);
+  inline bool SetToBroadCast();
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
@@ -47,72 +42,79 @@ public:
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
 };
 };
+
 /**
 /**
- * Ask the OS to let us receive BROADCASt packets on  this port..
+ * Ask the OS to let us receive broadcast packets on this port.
  */
  */
-inline bool Socket_UDP_Outgoing::SetToBroadCast()
-{
-    int optval = 1;
+inline bool Socket_UDP_Outgoing::
+SetToBroadCast() {
+  int optval = 1;
 
 
-    if (setsockopt(_socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) != 0)
-        return false;
-    return true;
+  if (setsockopt(_socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) != 0) {
+    return false;
+  }
+  return true;
 }
 }
+
 /**
 /**
- * Connects the Socket to a Specified address
+ * Connects the Socket to a specified address
  */
  */
-inline bool Socket_UDP_Outgoing::InitToAddress(const Socket_Address & address)
-{
-    if (InitNoAddress() != true)
-        return false;
+inline bool Socket_UDP_Outgoing::
+InitToAddress(const Socket_Address &address) {
+  if (InitNoAddress() != true) {
+    return false;
+  }
 
 
-    if (DO_CONNECT(_socket, &address.GetAddressInfo()) != 0)
-        return ErrorClose();
+  if (DO_CONNECT(_socket, &address.GetAddressInfo()) != 0) {
+    return ErrorClose();
+  }
 
 
-    return true;
+  return true;
 }
 }
+
 /**
 /**
- * This will set a udp up for targeted sends..
+ * This will set a udp up for targeted sends.
  */
  */
-inline bool Socket_UDP_Outgoing::InitNoAddress()
-{
-    Close();
-    _socket = DO_NEWUDP();
-    if (_socket == BAD_SOCKET)
-        return false;
-
-    return true;
+inline bool Socket_UDP_Outgoing::
+InitNoAddress() {
+  Close();
+  _socket = DO_NEWUDP(AF_INET);
+  if (_socket == BAD_SOCKET) {
+    return false;
+  }
+
+  return true;
 }
 }
 
 
 /**
 /**
  * Send data to connected address
  * Send data to connected address
  */
  */
-inline bool Socket_UDP_Outgoing::Send(const char * data, int len)
-{
+inline bool Socket_UDP_Outgoing::
+Send(const char *data, int len) {
   return (DO_SOCKET_WRITE(_socket, data, len) == len);
   return (DO_SOCKET_WRITE(_socket, data, len) == len);
 }
 }
 
 
 /**
 /**
  * Send data to connected address
  * Send data to connected address
  */
  */
-inline bool Socket_UDP_Outgoing::Send(const string &data)
-{
+inline bool Socket_UDP_Outgoing::
+Send(const string &data) {
   return Send(data.data(), data.size());
   return Send(data.data(), data.size());
 }
 }
 
 
 /**
 /**
  * Send data to specified address
  * Send data to specified address
  */
  */
-inline bool Socket_UDP_Outgoing::SendTo(const char * data, int len, const Socket_Address & address)
-{
-    return (DO_SOCKET_WRITE_TO(_socket, data, len, &address.GetAddressInfo()) == len);
+inline bool Socket_UDP_Outgoing::
+SendTo(const char *data, int len, const Socket_Address &address) {
+  return (DO_SOCKET_WRITE_TO(_socket, data, len, &address.GetAddressInfo()) == len);
 }
 }
 
 
 /**
 /**
  * Send data to specified address
  * Send data to specified address
  */
  */
-inline bool Socket_UDP_Outgoing::SendTo(const string &data, const Socket_Address & address)
-{
+inline bool Socket_UDP_Outgoing::
+SendTo(const string &data, const Socket_Address &address) {
   return SendTo(data.data(), data.size(), address);
   return SendTo(data.data(), data.size(), address);
 }
 }
 
 

+ 1 - 1
panda/src/net/connectionListener.cxx

@@ -77,7 +77,7 @@ process_incoming_data(SocketInfo *sinfo) {
 
 
   NetAddress net_addr(addr);
   NetAddress net_addr(addr);
   net_cat.info()
   net_cat.info()
-    << "Received TCP connection from client " << net_addr.get_ip_string()
+    << "Received TCP connection from client " << net_addr
     << " on port " << sinfo->_connection->get_address().get_port()
     << " on port " << sinfo->_connection->get_address().get_port()
     << "\n";
     << "\n";
 
 

+ 66 - 60
panda/src/net/connectionManager.cxx

@@ -69,7 +69,7 @@ ConnectionManager::
  * communication.
  * communication.
  */
  */
 PT(Connection) ConnectionManager::
 PT(Connection) ConnectionManager::
-open_UDP_connection(int port) {
+open_UDP_connection(uint16_t port) {
   return open_UDP_connection("", port);
   return open_UDP_connection("", port);
 }
 }
 
 
@@ -80,7 +80,8 @@ open_UDP_connection(int port) {
  * sending.
  * sending.
  *
  *
  * This variant accepts both a hostname and port to listen on a particular
  * This variant accepts both a hostname and port to listen on a particular
- * interface; if the hostname is empty, all interfaces will be available.
+ * interface; if the hostname is empty, all interfaces will be available,
+ * both IPv4 and IPv6.
  *
  *
  * If for_broadcast is true, this UDP connection will be configured to send
  * If for_broadcast is true, this UDP connection will be configured to send
  * and/or receive messages on the broadcast address (255.255.255.255);
  * and/or receive messages on the broadcast address (255.255.255.255);
@@ -90,24 +91,27 @@ open_UDP_connection(int port) {
  * communication.
  * communication.
  */
  */
 PT(Connection) ConnectionManager::
 PT(Connection) ConnectionManager::
-open_UDP_connection(const string &hostname, int port, bool for_broadcast) {
+open_UDP_connection(const string &hostname, uint16_t port, bool for_broadcast) {
   Socket_UDP *socket = new Socket_UDP;
   Socket_UDP *socket = new Socket_UDP;
 
 
   if (port > 0) {
   if (port > 0) {
+    bool okflag;
     NetAddress address;
     NetAddress address;
     if (hostname.empty()) {
     if (hostname.empty()) {
-      address.set_any(port);
+      // The empty string means to listen on both IPv4 and IPv6 interfaces.
+      okflag = socket->OpenForInput(port);
     } else {
     } else {
       address.set_host(hostname, port);
       address.set_host(hostname, port);
+      okflag = socket->OpenForInput(address.get_addr());
     }
     }
 
 
-    if (!socket->OpenForInput(address.get_addr())) {
+    if (!okflag) {
       if (hostname.empty()) {
       if (hostname.empty()) {
         net_cat.error()
         net_cat.error()
           << "Unable to bind to port " << port << " for UDP.\n";
           << "Unable to bind to port " << port << " for UDP.\n";
       } else {
       } else {
         net_cat.error()
         net_cat.error()
-          << "Unable to bind to " << hostname << ":" << port << " for UDP.\n";
+          << "Unable to bind to " << address << " for UDP.\n";
       }
       }
       delete socket;
       delete socket;
       return PT(Connection)();
       return PT(Connection)();
@@ -124,7 +128,7 @@ open_UDP_connection(const string &hostname, int port, bool for_broadcast) {
         << "Creating UDP " << broadcast_note << "connection for port " << port << "\n";
         << "Creating UDP " << broadcast_note << "connection for port " << port << "\n";
     } else {
     } else {
       net_cat.info()
       net_cat.info()
-        << "Creating UDP " << broadcast_note << "connection for " << hostname << ":" << port << "\n";
+        << "Creating UDP " << broadcast_note << "connection for " << address << "\n";
     }
     }
 
 
   } else {
   } else {
@@ -150,23 +154,32 @@ open_UDP_connection(const string &hostname, int port, bool for_broadcast) {
   return connection;
   return connection;
 }
 }
 
 
-
-
 /**
 /**
  * Creates a socket to be used as a rendezvous socket for a server to listen
  * Creates a socket to be used as a rendezvous socket for a server to listen
  * for TCP connections.  The socket returned by this call should only be added
  * for TCP connections.  The socket returned by this call should only be added
  * to a ConnectionListener (not to a generic ConnectionReader).
  * to a ConnectionListener (not to a generic ConnectionReader).
  *
  *
  * This variant of this method accepts a single port, and will listen to that
  * This variant of this method accepts a single port, and will listen to that
- * port on all available interfaces.
+ * port on all available interfaces, both IPv4 and IPv6.
  *
  *
  * backlog is the maximum length of the queue of pending connections.
  * backlog is the maximum length of the queue of pending connections.
  */
  */
 PT(Connection) ConnectionManager::
 PT(Connection) ConnectionManager::
-open_TCP_server_rendezvous(int port, int backlog) {
-  NetAddress address;
-  address.set_any(port);
-  return open_TCP_server_rendezvous(address, backlog);
+open_TCP_server_rendezvous(uint16_t port, int backlog) {
+  Socket_TCP_Listen *socket = new Socket_TCP_Listen;
+  if (!socket->OpenForListen(port, backlog)) {
+    net_cat.info()
+      << "Unable to listen to port " << port << " for TCP.\n";
+    delete socket;
+    return PT(Connection)();
+  }
+
+  net_cat.info()
+    << "Listening for TCP connections on port " << port << "\n";
+
+  PT(Connection) connection = new Connection(this, socket);
+  new_connection(connection);
+  return connection;
 }
 }
 
 
 /**
 /**
@@ -182,14 +195,14 @@ open_TCP_server_rendezvous(int port, int backlog) {
  * backlog is the maximum length of the queue of pending connections.
  * backlog is the maximum length of the queue of pending connections.
  */
  */
 PT(Connection) ConnectionManager::
 PT(Connection) ConnectionManager::
-open_TCP_server_rendezvous(const string &hostname, int port, int backlog) {
-  NetAddress address;
+open_TCP_server_rendezvous(const string &hostname, uint16_t port, int backlog) {
   if (hostname.empty()) {
   if (hostname.empty()) {
-    address.set_any(port);
+    return open_TCP_server_rendezvous(port, backlog);
   } else {
   } else {
+    NetAddress address;
     address.set_host(hostname, port);
     address.set_host(hostname, port);
+    return open_TCP_server_rendezvous(address, backlog);
   }
   }
-  return open_TCP_server_rendezvous(address, backlog);
 }
 }
 
 
 /**
 /**
@@ -204,24 +217,16 @@ open_TCP_server_rendezvous(const string &hostname, int port, int backlog) {
  */
  */
 PT(Connection) ConnectionManager::
 PT(Connection) ConnectionManager::
 open_TCP_server_rendezvous(const NetAddress &address, int backlog) {
 open_TCP_server_rendezvous(const NetAddress &address, int backlog) {
-  ostringstream strm;
-  if (address.get_ip() == 0) {
-    strm << "port " << address.get_port();
-  } else {
-    strm << address.get_ip_string() << ":" << address.get_port();
-  }
-
   Socket_TCP_Listen *socket = new Socket_TCP_Listen;
   Socket_TCP_Listen *socket = new Socket_TCP_Listen;
-  bool okflag = socket->OpenForListen(address.get_addr(), backlog);
-  if (!okflag) {
+  if (!socket->OpenForListen(address.get_addr(), backlog)) {
     net_cat.info()
     net_cat.info()
-      << "Unable to listen to " << strm.str() << " for TCP.\n";
+      << "Unable to listen to " << address << " for TCP.\n";
     delete socket;
     delete socket;
     return PT(Connection)();
     return PT(Connection)();
   }
   }
 
 
   net_cat.info()
   net_cat.info()
-    << "Listening for TCP connections on " << strm.str() << "\n";
+    << "Listening for TCP connections on " << address << "\n";
 
 
   PT(Connection) connection = new Connection(this, socket);
   PT(Connection) connection = new Connection(this, socket);
   new_connection(connection);
   new_connection(connection);
@@ -263,7 +268,7 @@ open_TCP_client_connection(const NetAddress &address, int timeout_ms) {
 
 
   if (okflag) {
   if (okflag) {
     // So, the connect() operation finished, but did it succeed or fail?
     // So, the connect() operation finished, but did it succeed or fail?
-    if (socket->GetPeerName().GetIPAddressRaw() == 0) {
+    if (socket->GetPeerName().is_any()) {
       // No peer means it failed.
       // No peer means it failed.
       okflag = false;
       okflag = false;
     }
     }
@@ -271,8 +276,7 @@ open_TCP_client_connection(const NetAddress &address, int timeout_ms) {
 
 
   if (!okflag) {
   if (!okflag) {
     net_cat.error()
     net_cat.error()
-      << "Unable to open TCP connection to server "
-      << address.get_ip_string() << " on port " << address.get_port() << "\n";
+      << "Unable to open TCP connection to server " << address << "\n";
     delete socket;
     delete socket;
     return PT(Connection)();
     return PT(Connection)();
   }
   }
@@ -286,8 +290,7 @@ open_TCP_client_connection(const NetAddress &address, int timeout_ms) {
 #endif  // SIMPLE_THREADS
 #endif  // SIMPLE_THREADS
 
 
   net_cat.info()
   net_cat.info()
-    << "Opened TCP connection to server " << address.get_ip_string()
-    << " on port " << address.get_port() << "\n";
+    << "Opened TCP connection to server " << address << "\n";
 
 
   PT(Connection) connection = new Connection(this, socket);
   PT(Connection) connection = new Connection(this, socket);
   new_connection(connection);
   new_connection(connection);
@@ -299,7 +302,7 @@ open_TCP_client_connection(const NetAddress &address, int timeout_ms) {
  * communications to a named host and port.
  * communications to a named host and port.
  */
  */
 PT(Connection) ConnectionManager::
 PT(Connection) ConnectionManager::
-open_TCP_client_connection(const string &hostname, int port,
+open_TCP_client_connection(const string &hostname, uint16_t port,
                            int timeout_ms) {
                            int timeout_ms) {
   NetAddress address;
   NetAddress address;
   if (!address.set_host(hostname, port)) {
   if (!address.set_host(hostname, port)) {
@@ -474,11 +477,12 @@ scan_interfaces() {
 
 
 #ifdef WIN32_VC
 #ifdef WIN32_VC
   int flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
   int flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
+  ULONG family = support_ipv6 ? AF_UNSPEC : AF_INET;
   ULONG buffer_size = 0;
   ULONG buffer_size = 0;
-  ULONG result = GetAdaptersAddresses(AF_INET, flags, NULL, NULL, &buffer_size);
+  ULONG result = GetAdaptersAddresses(family, flags, NULL, NULL, &buffer_size);
   if (result == ERROR_BUFFER_OVERFLOW) {
   if (result == ERROR_BUFFER_OVERFLOW) {
     IP_ADAPTER_ADDRESSES *addresses = (IP_ADAPTER_ADDRESSES *)PANDA_MALLOC_ARRAY(buffer_size);
     IP_ADAPTER_ADDRESSES *addresses = (IP_ADAPTER_ADDRESSES *)PANDA_MALLOC_ARRAY(buffer_size);
-    result = GetAdaptersAddresses(AF_INET, flags, NULL, addresses, &buffer_size);
+    result = GetAdaptersAddresses(family, flags, NULL, addresses, &buffer_size);
     if (result == ERROR_SUCCESS) {
     if (result == ERROR_SUCCESS) {
       IP_ADAPTER_ADDRESSES *p = addresses;
       IP_ADAPTER_ADDRESSES *p = addresses;
       while (p != NULL) {
       while (p != NULL) {
@@ -502,7 +506,7 @@ scan_interfaces() {
           IP_ADAPTER_PREFIX *m = p->FirstPrefix;
           IP_ADAPTER_PREFIX *m = p->FirstPrefix;
           int mc = 0;
           int mc = 0;
           while (m != NULL && mc < 3) {
           while (m != NULL && mc < 3) {
-            addresses[mc] = NetAddress(Socket_Address(*(sockaddr_in *)m->Address.lpSockaddr));
+            addresses[mc] = NetAddress(Socket_Address(*m->Address.lpSockaddr));
             m = m->Next;
             m = m->Next;
             ++mc;
             ++mc;
           }
           }
@@ -517,10 +521,13 @@ scan_interfaces() {
             // Now, we can infer the netmask by the difference between the
             // Now, we can infer the netmask by the difference between the
             // network address (the first address) and the broadcast address
             // network address (the first address) and the broadcast address
             // (the last address).
             // (the last address).
-            uint32_t netmask = addresses[0].get_ip() - addresses[2].get_ip() - 1;
-            Socket_Address sa;
-            sa.set_host(netmask, 0);
-            iface.set_netmask(NetAddress(sa));
+            if (addresses[0].get_addr().get_family() == AF_INET &&
+                addresses[2].get_addr().get_family() == AF_INET) {
+              uint32_t netmask = addresses[0].get_ip() - addresses[2].get_ip() - 1;
+              Socket_Address sa;
+              sa.set_host(netmask, 0);
+              iface.set_netmask(NetAddress(sa));
+            }
           }
           }
         }
         }
 
 
@@ -545,19 +552,20 @@ scan_interfaces() {
 
 
   struct ifaddrs *p = ifa;
   struct ifaddrs *p = ifa;
   while (p != NULL) {
   while (p != NULL) {
-    if (p->ifa_addr->sa_family == AF_INET) {
+    if (p->ifa_addr->sa_family == AF_INET ||
+        (support_ipv6 && p->ifa_addr->sa_family == AF_INET6)) {
       Interface iface;
       Interface iface;
       iface.set_name(p->ifa_name);
       iface.set_name(p->ifa_name);
       if (p->ifa_addr != NULL) {
       if (p->ifa_addr != NULL) {
-        iface.set_ip(NetAddress(Socket_Address(*(sockaddr_in *)p->ifa_addr)));
+        iface.set_ip(NetAddress(Socket_Address(*p->ifa_addr)));
       }
       }
       if (p->ifa_netmask != NULL) {
       if (p->ifa_netmask != NULL) {
-        iface.set_netmask(NetAddress(Socket_Address(*(sockaddr_in *)p->ifa_netmask)));
+        iface.set_netmask(NetAddress(Socket_Address(*p->ifa_netmask)));
       }
       }
       if ((p->ifa_flags & IFF_BROADCAST) && p->ifa_broadaddr != NULL) {
       if ((p->ifa_flags & IFF_BROADCAST) && p->ifa_broadaddr != NULL) {
-        iface.set_broadcast(NetAddress(Socket_Address(*(sockaddr_in *)p->ifa_broadaddr)));
+        iface.set_broadcast(NetAddress(Socket_Address(*p->ifa_broadaddr)));
       } else if ((p->ifa_flags & IFF_POINTOPOINT) && p->ifa_dstaddr != NULL) {
       } else if ((p->ifa_flags & IFF_POINTOPOINT) && p->ifa_dstaddr != NULL) {
-        iface.set_p2p(NetAddress(Socket_Address(*(sockaddr_in *)p->ifa_dstaddr)));
+        iface.set_p2p(NetAddress(Socket_Address(*p->ifa_dstaddr)));
       }
       }
       _interfaces.push_back(iface);
       _interfaces.push_back(iface);
     }
     }
@@ -572,10 +580,9 @@ scan_interfaces() {
 
 
 /**
 /**
  * This returns the number of usable network interfaces detected on this
  * This returns the number of usable network interfaces detected on this
- * machine.  (Currently, only IPv4 interfaces are reported.)  See
- * scan_interfaces() to repopulate this list.
+ * machine.  See scan_interfaces() to repopulate this list.
  */
  */
-int ConnectionManager::
+size_t ConnectionManager::
 get_num_interfaces() {
 get_num_interfaces() {
   if (!_interfaces_scanned) {
   if (!_interfaces_scanned) {
     scan_interfaces();
     scan_interfaces();
@@ -586,16 +593,15 @@ get_num_interfaces() {
 
 
 /**
 /**
  * Returns the nth usable network interface detected on this machine.
  * Returns the nth usable network interface detected on this machine.
- * (Currently, only IPv4 interfaces are reported.)  See scan_interfaces() to
- * repopulate this list.
+ * See scan_interfaces() to repopulate this list.
  */
  */
 const ConnectionManager::Interface &ConnectionManager::
 const ConnectionManager::Interface &ConnectionManager::
-get_interface(int n) {
+get_interface(size_t n) {
   if (!_interfaces_scanned) {
   if (!_interfaces_scanned) {
     scan_interfaces();
     scan_interfaces();
   }
   }
   LightMutexHolder holder(_set_mutex);
   LightMutexHolder holder(_set_mutex);
-  nassertr(n >= 0 && n < (int)_interfaces.size(), _interfaces[0]);
+  nassertr(n < _interfaces.size(), _interfaces[0]);
   return _interfaces[n];
   return _interfaces[n];
 }
 }
 
 
@@ -709,9 +715,9 @@ remove_writer(ConnectionWriter *writer) {
  * Formats a device's MAC address into a string.
  * Formats a device's MAC address into a string.
  */
  */
 string ConnectionManager::
 string ConnectionManager::
-format_mac_address(const unsigned char *data, int data_size) {
+format_mac_address(const unsigned char *data, size_t data_size) {
   stringstream strm;
   stringstream strm;
-  for (int di = 0; di < data_size; ++di) {
+  for (size_t di = 0; di < data_size; ++di) {
     if (di != 0) {
     if (di != 0) {
       strm << "-";
       strm << "-";
     }
     }
@@ -728,16 +734,16 @@ void ConnectionManager::Interface::
 output(ostream &out) const {
 output(ostream &out) const {
   out << get_name() << " [";
   out << get_name() << " [";
   if (has_ip()) {
   if (has_ip()) {
-    out << " " << get_ip();
+    out << " " << get_ip().get_ip_string();
   }
   }
   if (has_netmask()) {
   if (has_netmask()) {
-    out << " netmask " << get_netmask();
+    out << " netmask " << get_netmask().get_ip_string();
   }
   }
   if (has_broadcast()) {
   if (has_broadcast()) {
-    out << " broadcast " << get_broadcast();
+    out << " broadcast " << get_broadcast().get_ip_string();
   }
   }
   if (has_p2p()) {
   if (has_p2p()) {
-    out << " p2p " << get_p2p();
+    out << " p2p " << get_p2p().get_ip_string();
   }
   }
   out << " ]";
   out << " ]";
 }
 }

+ 9 - 9
panda/src/net/connectionManager.h

@@ -43,18 +43,18 @@ PUBLISHED:
   ConnectionManager();
   ConnectionManager();
   virtual ~ConnectionManager();
   virtual ~ConnectionManager();
 
 
-  PT(Connection) open_UDP_connection(int port = 0);
-  PT(Connection) open_UDP_connection(const string &hostname, int port, bool for_broadcast = false);
+  PT(Connection) open_UDP_connection(uint16_t port = 0);
+  PT(Connection) open_UDP_connection(const string &hostname, uint16_t port, bool for_broadcast = false);
 
 
-  BLOCKING PT(Connection) open_TCP_server_rendezvous(int port, int backlog);
+  BLOCKING PT(Connection) open_TCP_server_rendezvous(uint16_t port, int backlog);
   BLOCKING PT(Connection) open_TCP_server_rendezvous(const string &hostname,
   BLOCKING PT(Connection) open_TCP_server_rendezvous(const string &hostname,
-                                                     int port, int backlog);
+                                                     uint16_t port, int backlog);
   BLOCKING PT(Connection) open_TCP_server_rendezvous(const NetAddress &address,
   BLOCKING PT(Connection) open_TCP_server_rendezvous(const NetAddress &address,
                                                      int backlog);
                                                      int backlog);
   BLOCKING PT(Connection) open_TCP_client_connection(const NetAddress &address,
   BLOCKING PT(Connection) open_TCP_client_connection(const NetAddress &address,
                                                      int timeout_ms);
                                                      int timeout_ms);
-  BLOCKING PT(Connection) open_TCP_client_connection(const string &hostname, int port,
-                                                     int timeout_ms);
+  BLOCKING PT(Connection) open_TCP_client_connection(const string &hostname,
+                                                     uint16_t port, int timeout_ms);
 
 
   bool close_connection(const PT(Connection) &connection);
   bool close_connection(const PT(Connection) &connection);
   BLOCKING bool wait_for_readers(double timeout);
   BLOCKING bool wait_for_readers(double timeout);
@@ -104,8 +104,8 @@ PUBLISHED:
   };
   };
 
 
   void scan_interfaces();
   void scan_interfaces();
-  int get_num_interfaces();
-  const Interface &get_interface(int n);
+  size_t get_num_interfaces();
+  const Interface &get_interface(size_t n);
   MAKE_SEQ(get_interfaces, get_num_interfaces, get_interface);
   MAKE_SEQ(get_interfaces, get_num_interfaces, get_interface);
 
 
   MAKE_PROPERTY(host_name, get_host_name);
   MAKE_PROPERTY(host_name, get_host_name);
@@ -122,7 +122,7 @@ protected:
   void add_writer(ConnectionWriter *writer);
   void add_writer(ConnectionWriter *writer);
   void remove_writer(ConnectionWriter *writer);
   void remove_writer(ConnectionWriter *writer);
 
 
-  string format_mac_address(const unsigned char *data, int data_size);
+  string format_mac_address(const unsigned char *data, size_t data_size);
 
 
   typedef phash_set< PT(Connection) > Connections;
   typedef phash_set< PT(Connection) > Connections;
   typedef phash_set<ConnectionReader *, pointer_hash> Readers;
   typedef phash_set<ConnectionReader *, pointer_hash> Readers;

+ 10 - 1
panda/src/net/netAddress.cxx

@@ -91,6 +91,14 @@ set_port(int port) {
   _addr.set_port(port);
   _addr.set_port(port);
 }
 }
 
 
+/**
+ * Returns true if the IP address has only zeroes.
+ */
+bool NetAddress::
+is_any() const {
+  return _addr.is_any();
+}
+
 /**
 /**
  * Returns the IP address to which this address refers, formatted as a string.
  * Returns the IP address to which this address refers, formatted as a string.
  */
  */
@@ -102,6 +110,7 @@ get_ip_string() const {
 /**
 /**
  * Returns the IP address to which this address refers, as a 32-bit integer,
  * Returns the IP address to which this address refers, as a 32-bit integer,
  * in host byte order.
  * in host byte order.
+ * @deprecated  Does not work with IPv6 addresses.
  */
  */
 uint32_t NetAddress::
 uint32_t NetAddress::
 get_ip() const {
 get_ip() const {
@@ -135,7 +144,7 @@ get_addr() const {
  */
  */
 void NetAddress::
 void NetAddress::
 output(ostream &out) const {
 output(ostream &out) const {
-  out << get_ip_string();
+  out << _addr.get_ip_port();
 }
 }
 
 
 /**
 /**

+ 1 - 0
panda/src/net/netAddress.h

@@ -37,6 +37,7 @@ PUBLISHED:
   int get_port() const;
   int get_port() const;
   void set_port(int port);
   void set_port(int port);
   string get_ip_string() const;
   string get_ip_string() const;
+  bool is_any() const;
   uint32_t get_ip() const;
   uint32_t get_ip() const;
   uint8_t get_ip_component(int n) const;
   uint8_t get_ip_component(int n) const;