From 7e08b87ff77049ebb99e80ac77db417c72973c41 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 22 Jun 2016 17:57:40 +0200 Subject: [PATCH] IPv6 support, improve URL handling/comparison --- dtool/src/parser-inc/netinet/in.h | 17 + dtool/src/parser-inc/socket.h | 10 - dtool/src/parser-inc/sys/socket.h | 18 + dtool/src/parser-inc/winsock2.h | 3 + dtool/src/parser-inc/ws2tcpip.h | 1 + panda/src/downloader/bioPtr.I | 8 + panda/src/downloader/bioPtr.cxx | 172 +++++++++- panda/src/downloader/bioPtr.h | 16 + panda/src/downloader/config_downloader.cxx | 6 + panda/src/downloader/config_downloader.h | 1 + panda/src/downloader/httpChannel.cxx | 59 +++- panda/src/downloader/urlSpec.I | 50 +-- panda/src/downloader/urlSpec.cxx | 202 +++++++++-- panda/src/downloader/urlSpec.h | 28 +- .../src/nativenet/p3nativenet_composite1.cxx | 1 + panda/src/nativenet/socket_address.I | 271 ++++++++------- panda/src/nativenet/socket_address.cxx | 157 +++++++++ panda/src/nativenet/socket_address.h | 35 +- panda/src/nativenet/socket_ip.h | 24 +- panda/src/nativenet/socket_portable.h | 295 +++++++--------- panda/src/nativenet/socket_tcp.h | 232 ++++++------- panda/src/nativenet/socket_tcp_listen.h | 101 ++++-- panda/src/nativenet/socket_tcp_ssl.h | 324 +++++++++--------- panda/src/nativenet/socket_udp.h | 91 +++-- panda/src/nativenet/socket_udp_incoming.h | 195 +++++++---- panda/src/nativenet/socket_udp_outgoing.h | 108 +++--- panda/src/net/connectionListener.cxx | 2 +- panda/src/net/connectionManager.cxx | 126 +++---- panda/src/net/connectionManager.h | 18 +- panda/src/net/netAddress.cxx | 11 +- panda/src/net/netAddress.h | 1 + 31 files changed, 1607 insertions(+), 976 deletions(-) create mode 100644 dtool/src/parser-inc/netinet/in.h delete mode 100644 dtool/src/parser-inc/socket.h create mode 100644 dtool/src/parser-inc/sys/socket.h create mode 100644 dtool/src/parser-inc/ws2tcpip.h create mode 100755 panda/src/nativenet/socket_address.cxx diff --git a/dtool/src/parser-inc/netinet/in.h b/dtool/src/parser-inc/netinet/in.h new file mode 100644 index 0000000000..b0b3bc605e --- /dev/null +++ b/dtool/src/parser-inc/netinet/in.h @@ -0,0 +1,17 @@ +#include +#include + +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; + diff --git a/dtool/src/parser-inc/socket.h b/dtool/src/parser-inc/socket.h deleted file mode 100644 index 2881dc3780..0000000000 --- a/dtool/src/parser-inc/socket.h +++ /dev/null @@ -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; diff --git a/dtool/src/parser-inc/sys/socket.h b/dtool/src/parser-inc/sys/socket.h new file mode 100644 index 0000000000..6fefc30af9 --- /dev/null +++ b/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; diff --git a/dtool/src/parser-inc/winsock2.h b/dtool/src/parser-inc/winsock2.h index c63bef39b2..492d85ec02 100644 --- a/dtool/src/parser-inc/winsock2.h +++ b/dtool/src/parser-inc/winsock2.h @@ -6,6 +6,9 @@ typedef unsigned long SOCKET; +struct sockaddr; struct sockaddr_in; +struct sockaddr_in6; +struct sockaddr_storage; #endif diff --git a/dtool/src/parser-inc/ws2tcpip.h b/dtool/src/parser-inc/ws2tcpip.h new file mode 100644 index 0000000000..49262434c5 --- /dev/null +++ b/dtool/src/parser-inc/ws2tcpip.h @@ -0,0 +1 @@ +typedef DWORD socklen_t; diff --git a/panda/src/downloader/bioPtr.I b/panda/src/downloader/bioPtr.I index a1e1f13e1d..f09ee7bbc8 100644 --- a/panda/src/downloader/bioPtr.I +++ b/panda/src/downloader/bioPtr.I @@ -18,6 +18,14 @@ INLINE BioPtr:: BioPtr(BIO *bio) : _bio(bio) { } +/** + * + */ +INLINE bool BioPtr:: +should_retry() const { + return (_bio != NULL) && BIO_should_retry(_bio); +} + /** * */ diff --git a/panda/src/downloader/bioPtr.cxx b/panda/src/downloader/bioPtr.cxx index 1aee90d207..15fe997c02 100644 --- a/panda/src/downloader/bioPtr.cxx +++ b/panda/src/downloader/bioPtr.cxx @@ -18,13 +18,46 @@ #include "urlSpec.h" #include "config_downloader.h" +#ifdef _WIN32 +#include +#else +#include +#include +#include +#include +#include +#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 * it the server and port name from the indicated URL. It doesn't call * BIO_do_connect(), though. */ BioPtr:: -BioPtr(const URLSpec &url) { +BioPtr(const URLSpec &url) : _connecting(false) { if (url.get_scheme() == "file") { // We're just reading a disk file. string filename = URLSpec::unquote(url.get_path()); @@ -48,14 +81,143 @@ BioPtr(const URLSpec &url) { _bio = BIO_new_file(filename.c_str(), "rb"); } 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(); _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 (downloader_cat.is_debug() && !_server_name.empty()) { downloader_cat.debug() - << "Dropping connection to " << _server_name << ":" << _port << "\n"; + << "Dropping connection to " << _server_name << " port " << _port << "\n"; } BIO_free_all(_bio); diff --git a/panda/src/downloader/bioPtr.h b/panda/src/downloader/bioPtr.h index 077a37ea84..332a1fc715 100644 --- a/panda/src/downloader/bioPtr.h +++ b/panda/src/downloader/bioPtr.h @@ -27,6 +27,14 @@ #include "openSSLWrapper.h" // must be included before any other openssl. #include "openssl/ssl.h" +#ifdef _WIN32 +#include +#include +#else +#include +#include +#endif + class URLSpec; /** @@ -41,6 +49,11 @@ public: BioPtr(const URLSpec &url); virtual ~BioPtr(); + void set_nbio(bool nbio); + bool connect(); + + INLINE bool should_retry() const; + INLINE BIO &operator *() const; INLINE BIO *operator -> () const; INLINE operator BIO * () const; @@ -55,6 +68,9 @@ private: BIO *_bio; string _server_name; int _port; + struct sockaddr_storage _addr; + socklen_t _addrlen; + bool _connecting; }; #include "bioPtr.I" diff --git a/panda/src/downloader/config_downloader.cxx b/panda/src/downloader/config_downloader.cxx index e1ee26ace5..c1db208d01 100644 --- a/panda/src/downloader/config_downloader.cxx +++ b/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 " "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) { init_libdownloader(); } diff --git a/panda/src/downloader/config_downloader.h b/panda/src/downloader/config_downloader.h index b31a7d2bd8..2ffd9be37a 100644 --- a/panda/src/downloader/config_downloader.h +++ b/panda/src/downloader/config_downloader.h @@ -45,6 +45,7 @@ extern ConfigVariableDouble http_idle_timeout; extern ConfigVariableInt http_max_connect_count; extern EXPCL_PANDAEXPRESS ConfigVariableInt tcp_header_size; +extern EXPCL_PANDAEXPRESS ConfigVariableBool support_ipv6; extern EXPCL_PANDAEXPRESS void init_libdownloader(); diff --git a/panda/src/downloader/httpChannel.cxx b/panda/src/downloader/httpChannel.cxx index 7dbe4d1a32..96980fdfaa 100644 --- a/panda/src/downloader/httpChannel.cxx +++ b/panda/src/downloader/httpChannel.cxx @@ -375,26 +375,28 @@ run() { } // No connection. Attempt to establish one. + URLSpec url; if (_proxy.empty()) { - _bio = new BioPtr(_request.get_url()); + url = _request.get_url(); } else { - _bio = new BioPtr(_proxy); + url = _proxy; } + _bio = new BioPtr(url); _source = new BioStreamPtr(new BioStream(_bio)); if (_nonblocking) { - BIO_set_nbio(*_bio, 1); + _bio->set_nbio(true); } if (downloader_cat.is_debug()) { if (_connect_count > 0) { downloader_cat.debug() << _NOTIFY_HTTP_CHANNEL_ID - << "Reconnecting to " << _bio->get_server_name() << ":" + << "Reconnecting to " << _bio->get_server_name() << " port " << _bio->get_port() << "\n"; } else { downloader_cat.debug() << _NOTIFY_HTTP_CHANNEL_ID - << "Connecting to " << _bio->get_server_name() << ":" + << "Connecting to " << _bio->get_server_name() << " port " << _bio->get_port() << "\n"; } } @@ -941,14 +943,14 @@ bool HTTPChannel:: run_connecting() { _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; return false; } downloader_cat.info() << _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"; OpenSSLWrapper::get_global_ptr()->notify_ssl_errors(); _status_entry._status_code = SC_no_connection; @@ -959,7 +961,7 @@ run_connecting() { if (downloader_cat.is_debug()) { downloader_cat.debug() << _NOTIFY_HTTP_CHANNEL_ID - << "Connected to " << _bio->get_server_name() << ":" + << "Connected to " << _bio->get_server_name() << " port " << _bio->get_port() << "\n"; } @@ -1362,6 +1364,10 @@ run_socks_proxy_connect_reply() { total_bytes += (unsigned int)reply[4]; break; + case 0x04: // IPv6 + total_bytes += 16; + break; + default: downloader_cat.info() << _NOTIFY_HTTP_CHANNEL_ID @@ -1396,6 +1402,18 @@ run_socks_proxy_connect_reply() { case 0x03: // DNS connect_host = string(&reply[5], (unsigned int)reply[4]); 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 = @@ -2742,8 +2760,8 @@ server_getline(string &str) { } 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 << "recv: " << str << "\n"; } @@ -2915,7 +2933,7 @@ server_send(const string &str, bool secret) { } #ifndef NDEBUG - if (!secret && downloader_cat.is_debug()) { + if (!secret && downloader_cat.is_spam()) { show_send(str.substr(0, write_count)); } #endif @@ -3486,14 +3504,19 @@ make_header() { 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 // 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 // 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"; if (!get_persistent_connection()) { @@ -3703,14 +3726,14 @@ show_send(const string &message) { size_t newline = message.find('\n', start); while (newline != string::npos) { // Assume every \n is preceded by a \r. - downloader_cat.debug() + downloader_cat.spam() << "send: " << message.substr(start, newline - start - 1) << "\n"; start = newline + 1; newline = message.find('\n', start); } if (start < message.length()) { - downloader_cat.debug() + downloader_cat.spam() << "send: " << message.substr(start) << " (no newline)\n"; } } diff --git a/panda/src/downloader/urlSpec.I b/panda/src/downloader/urlSpec.I index 5d4654e1f7..7af6f4339b 100644 --- a/panda/src/downloader/urlSpec.I +++ b/panda/src/downloader/urlSpec.I @@ -19,14 +19,6 @@ URLSpec(const string &url, bool server_name_expected) { set_url(url, server_name_expected); } -/** - * - */ -INLINE URLSpec:: -URLSpec(const URLSpec ©) { - (*this) = copy; -} - /** * */ @@ -40,7 +32,7 @@ operator = (const string &url) { */ INLINE bool URLSpec:: 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:: 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:: 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:: 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:: empty() const { 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(); } +/** + * + */ +INLINE size_t URLSpec:: +size() const { + return _url.size(); +} + /** * */ 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]; } diff --git a/panda/src/downloader/urlSpec.cxx b/panda/src/downloader/urlSpec.cxx index e724e9a044..46504f96d1 100644 --- a/panda/src/downloader/urlSpec.cxx +++ b/panda/src/downloader/urlSpec.cxx @@ -12,10 +12,11 @@ */ #include "urlSpec.h" +#include "filename.h" +#include "string_utils.h" #include - /** * */ @@ -35,24 +36,88 @@ URLSpec() { _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 ©) { - _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 * specified. */ -int URLSpec:: +uint16_t URLSpec:: get_port() const { if (has_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, * followed by the port number. If the port number is not explicitly given in * 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:: get_server_and_port() const { - if (has_port()) { - return _url.substr(_server_start, _port_end - _server_start); - } ostringstream strm; - strm << get_server() << ":" << get_port(); + 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()) { + strm << ":" << get_port(); + } return strm.str(); } @@ -285,7 +361,15 @@ set_username(const string &username) { if (!username.empty()) { 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()) { authority += ":"; authority += get_port_str(); @@ -296,6 +380,8 @@ set_username(const string &username) { /** * 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:: set_server(const string &server) { @@ -307,7 +393,14 @@ set_server(const string &server) { if (has_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()) { authority += ":"; authority += get_port_str(); @@ -329,7 +422,14 @@ set_port(const string &port) { if (has_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()) { authority += ":"; @@ -344,16 +444,15 @@ set_port(const string &port) { * number. */ 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. * The input string should be of the form "server:port", or just "server" to * make the port number implicit. + * Any IPv6 address must be enclosed in square brackets. */ void URLSpec:: 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? _flags = 0; _port = 0; @@ -781,18 +892,39 @@ parse_authority() { _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; - _server_end = colon; - _port_start = colon + 1; // Decode the port into an integer. Don't bother to error check if it's // not really an integer. 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. diff --git a/panda/src/downloader/urlSpec.h b/panda/src/downloader/urlSpec.h index 7b7cc4e9b2..592fe22087 100644 --- a/panda/src/downloader/urlSpec.h +++ b/panda/src/downloader/urlSpec.h @@ -17,6 +17,8 @@ #include "pandabase.h" #include "pnotify.h" +class Filename; + /** * A container for a URL, e.g. "http://server:port/path". * @@ -27,14 +29,14 @@ class EXPCL_PANDAEXPRESS URLSpec { PUBLISHED: URLSpec(); INLINE URLSpec(const string &url, bool server_name_expected = false); - INLINE URLSpec(const URLSpec ©); + URLSpec(const URLSpec &url, const Filename &path); INLINE void operator = (const string &url); - void operator = (const URLSpec ©); 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_authority() const; @@ -49,7 +51,7 @@ PUBLISHED: INLINE string get_username() const; INLINE string get_server() const; INLINE string get_port_str() const; - int get_port() const; + uint16_t get_port() const; string get_server_and_port() const; bool is_default_port() const; static int get_default_port_for_scheme(const string &scheme); @@ -65,7 +67,7 @@ PUBLISHED: void set_username(const string &username); void set_server(const string &server); 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_path(const string &path); void set_query(const string &query); @@ -75,8 +77,10 @@ PUBLISHED: INLINE operator const string & () const; INLINE const char *c_str() const; INLINE bool empty() const; + INLINE operator bool() 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); void output(ostream &out) const; @@ -86,6 +90,16 @@ PUBLISHED: static string unquote(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: void parse_authority(); @@ -100,7 +114,7 @@ private: }; string _url; - int _port; + uint16_t _port; int _flags; size_t _scheme_end; diff --git a/panda/src/nativenet/p3nativenet_composite1.cxx b/panda/src/nativenet/p3nativenet_composite1.cxx index 51ddce8a5f..1c842ac105 100644 --- a/panda/src/nativenet/p3nativenet_composite1.cxx +++ b/panda/src/nativenet/p3nativenet_composite1.cxx @@ -1,5 +1,6 @@ #include "config_nativenet.cxx" #include "buffered_datagramconnection.cxx" +#include "socket_address.cxx" #include "socket_ip.cxx" #include "socket_tcp.cxx" #include "socket_tcp_listen.cxx" diff --git a/panda/src/nativenet/socket_address.I b/panda/src/nativenet/socket_address.I index c29b6b646f..cb36122c2a 100644 --- a/panda/src/nativenet/socket_address.I +++ b/panda/src/nativenet/socket_address.I @@ -11,42 +11,69 @@ * @date 2014-10-19 */ -/** - * Return a RAW sockaddr_in - */ -INLINE unsigned long Socket_Address:: -GetIPAddressRaw() const { - return _addr.sin_addr.s_addr; -} - /** * Constructor that lets us set a port value */ 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); + _addr4.sin_family = AF_INET; + _addr4.sin_addr.s_addr = INADDR_ANY; + _addr4.sin_port = htons(port); } /** * */ 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 Socket_Address &inaddr) : + _storage(inaddr._storage) { } /** * */ 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 &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:: +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:: +Socket_Address(const struct sockaddr_storage &inaddr) : + _storage(inaddr) { } /** @@ -61,9 +88,24 @@ INLINE Socket_Address:: */ INLINE bool Socket_Address:: 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:: 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:: 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; } @@ -92,9 +132,21 @@ set_broadcast(unsigned short port) { */ INLINE bool Socket_Address:: 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; } @@ -103,7 +155,7 @@ set_any_IP(unsigned short port) { */ INLINE bool Socket_Address:: set_port(unsigned short port) { - _addr.sin_port = htons(port); + _addr4.sin_port = htons(port); return true; } @@ -112,9 +164,18 @@ set_port(unsigned short port) { */ INLINE void Socket_Address:: 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); +} + +/** + * Returns AF_INET if this is an IPv4 address, or AF_INET6 if this is an IPv6 + * address. + */ +INLINE sa_family_t Socket_Address:: +get_family() const { + return _storage.ss_family; } /** @@ -122,73 +183,7 @@ clear() { */ INLINE unsigned short Socket_Address:: get_port() const { - return ntohs(_addr.sin_port); -} - -/** - * Return the IP address portion in dot notation string - */ -INLINE std::string Socket_Address:: -get_ip() const { - return std::string(inet_ntoa(_addr.sin_addr)); -} - -/** - * 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); -} - -/** - * 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:: -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); - } - - - 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); - } - } else { - memcpy(&_addr.sin_addr, &addr, sizeof(addr)); - } - - _addr.sin_port = htons(port); - _addr.sin_family = AF_INET; - return true; -} - -/** - * - */ -INLINE bool Socket_Address:: -set_host(const std::string &hostname) { - std::string::size_type pos = hostname.find(':'); - if (pos == std::string::npos) - return false; - - std::string host = hostname.substr(0, pos); - 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 ntohs(_addr4.sin_port); } /** @@ -196,9 +191,9 @@ set_host(const std::string &hostname) { */ 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; + memcpy(&_addr4.sin_addr, &in_hostname, sizeof(in_hostname)); + _addr4.sin_port = htons(port); + _addr4.sin_family = AF_INET; return true; } @@ -207,27 +202,61 @@ set_host(uint32_t in_hostname, unsigned short port) { */ INLINE bool Socket_Address:: operator < (const Socket_Address &in) const { - if (_addr.sin_port < in._addr.sin_port) + if (_storage.ss_family != in._storage.ss_family) { + return _storage.ss_family < in._storage.ss_family; + } + + if (_storage.ss_family == AF_INET) { + if (_addr4.sin_port != in._addr4.sin_port) { + return _addr4.sin_port < in._addr4.sin_port; + } + + return _addr4.sin_addr.s_addr < in._addr4.sin_addr.s_addr; + + } else if (_storage.ss_family == AF_INET6) { + if (_addr6.sin6_port != in._addr6.sin6_port) { + return _addr6.sin6_port < in._addr6.sin6_port; + } + + return IN6_ARE_ADDR_EQUAL(&_addr6.sin6_addr, &in._addr6.sin6_addr) != 0; + } + + // Unsupported address family. + nassertr(false, false); + return false; +} + +/** + * True if the address is zero. + */ +INLINE bool Socket_Address:: +is_any() const { + if (_storage.ss_family == AF_INET) { + return (_addr4.sin_addr.s_addr == 0); + + } else if (_storage.ss_family == AF_INET6) { + return IN6_IS_ADDR_UNSPECIFIED(&_addr6.sin6_addr) != 0; + + } else { return true; - - if (_addr.sin_port > in._addr.sin_port) - return false; - - if (_addr.sin_addr.s_addr < in._addr.sin_addr.s_addr) - 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. */ 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; + } } diff --git a/panda/src/nativenet/socket_address.cxx b/panda/src/nativenet/socket_address.cxx new file mode 100755 index 0000000000..cf27b0771c --- /dev/null +++ b/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; +} diff --git a/panda/src/nativenet/socket_address.h b/panda/src/nativenet/socket_address.h index a185238e1d..20046e3d24 100644 --- a/panda/src/nativenet/socket_address.h +++ b/panda/src/nativenet/socket_address.h @@ -11,7 +11,6 @@ * @date 2014-10-19 */ - #ifndef SOCKET_ADDRESS_H #define SOCKET_ADDRESS_H @@ -20,15 +19,17 @@ #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 */ class EXPCL_PANDA_NATIVENET Socket_Address { 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: INLINE Socket_Address(unsigned short port = 0); @@ -37,27 +38,35 @@ PUBLISHED: INLINE virtual ~Socket_Address(); 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_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 sa_family_t get_family() 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 is_any() const; INLINE bool is_mcast_range() const; private: - AddressType _addr; + union { + sockaddr _addr; + sockaddr_in _addr4; + sockaddr_in6 _addr6; + sockaddr_storage _storage; + }; }; #include "socket_address.I" diff --git a/panda/src/nativenet/socket_ip.h b/panda/src/nativenet/socket_ip.h index 9094dac03b..3c03db2b3b 100644 --- a/panda/src/nativenet/socket_ip.h +++ b/panda/src/nativenet/socket_ip.h @@ -5,6 +5,7 @@ #include "socket_portable.h" #include "socket_address.h" #include "typedObject.h" +#include "config_downloader.h" // forward declarations for friends... class Socket_TCP; @@ -35,6 +36,7 @@ PUBLISHED: inline int SetNonBlocking(); inline int SetBlocking(); inline bool SetReuseAddress(bool flag = true); + inline bool SetV6Only(bool flag); inline bool Active(); inline int SetRecvBufferSize(int size); inline void SetSocket(SOCKET ins); @@ -44,7 +46,6 @@ PUBLISHED: inline static int InitNetworkDriver() { return init_network(); }; -public: private: inline bool ErrorClose(); @@ -194,7 +195,7 @@ SetBlocking() { fcntl(_socket, F_SETFL, flags); return ALL_OK; #else - unsigned long val = 0; + unsigned long val = 0; unsigned lanswer = 0; lanswer = SOCKIOCTL(_socket, LOCAL_FL_SET, &val); if (lanswer != 0) { @@ -209,8 +210,21 @@ SetBlocking() { */ inline bool Socket_IP:: 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 true; @@ -237,7 +251,7 @@ GetSocket() const { */ inline Socket_Address Socket_IP:: GetPeerName(void) const { - sockaddr_in name; + sockaddr_storage name; socklen_t name_len = sizeof(name); memset(&name, 0, name_len); diff --git a/panda/src/nativenet/socket_portable.h b/panda/src/nativenet/socket_portable.h index 2a80c735f3..d4bdd1fa98 100644 --- a/panda/src/nativenet/socket_portable.h +++ b/panda/src/nativenet/socket_portable.h @@ -6,10 +6,13 @@ const int ALL_OK = 0; const int BASIC_ERROR = -1; +#define SA_SIZEOF(addr) (((addr)->sa_family == AF_INET6) ? sizeof(sockaddr_in6) : sizeof(sockaddr_in)) + #if defined(CPPPARSER) // Interrogate doesn't need to parse any of this. typedef unsigned long SOCKET; +typedef unsigned short sa_family_t; /************************************************************************ * HP SOCKET LIBRARY STUFF @@ -46,91 +49,77 @@ typedef unsigned long SOCKET; /************************************************************************ * WINSOCK 32 bit STUFF ************************************************************************/ -#elif defined(WIN32) || defined(WIN32_VC) || defined(WIN64_VC) +#elif defined(_WIN32) #include #include +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(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_in * addr) -{ - return sendto(a, buffer, buf_len, 0, reinterpret_cast(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() -{ - 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(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 closesocket(a); +inline int DO_CLOSE(const SOCKET a) { + return closesocket(a); } -inline SOCKET DO_ACCEPT(SOCKET sck, sockaddr_in * adr) -{ - int adrlen = sizeof(sockaddr); - return accept(sck, reinterpret_cast(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(addr), &plen); +inline SOCKET DO_ACCEPT(SOCKET sck, sockaddr *addr) { + socklen_t addrlen = sizeof(sockaddr_storage); + return accept(sck, addr, &addrlen); } -inline int DO_LISTEN(const SOCKET a, const int size) -{ - return listen(a, size); +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 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_FL_SET = FIONBIO ; +const long LOCAL_FL_SET = FIONBIO; const int LOCAL_BLOCKING_ERROR = WSAEWOULDBLOCK; const int LOCAL_CONNECT_BLOCKING = WSAEWOULDBLOCK; const int LOCAL_NOTCONNECTED_ERROR = WSAENOTCONN; @@ -162,84 +151,61 @@ const SOCKET BAD_SOCKET = (SOCKET)-1; typedef int SOCKET; 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(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(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() -{ - 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(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) -{ - 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_LISTEN(const SOCKET a, const int size) -{ - return listen(a, size); +inline int DO_ACCEPT(SOCKET sck, sockaddr *addr) { + socklen_t addrlen = sizeof(sockaddr_storage); + return accept(sck, (sockaddr *)addr, &addrlen); } -inline int GETERROR() -{ - return errno; +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 SOCKIOCTL(const SOCKET s, const long flags, void * val) -{ - return ioctl(s, flags, val); +inline int GETERROR() { + return errno; } -inline int init_network() -{ - return ALL_OK; +inline int SOCKIOCTL(const SOCKET s, const long flags, void *val) { + return ioctl(s, flags, val); +} + +inline int init_network() { + return ALL_OK; } #ifndef INADDR_NONE const INADDR_NONE = -1; #endif 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_CONNECT_BLOCKING = EINPROGRESS; @@ -267,94 +233,75 @@ const int LOCAL_CONNECT_BLOCKING = EINPROGRESS; #include #include -typedef struct sockaddr_in AddressType; - typedef int SOCKET; 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(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(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(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 const long LOCAL_NONBLOCK = 1; // 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_CONNECT_BLOCKING = EINPROGRESS; @@ -366,6 +313,4 @@ No Host Type defined !! #error Fatal #endif - - #endif //__SOCKET_PORTABLE_H__ diff --git a/panda/src/nativenet/socket_tcp.h b/panda/src/nativenet/socket_tcp.h index d1d0051d6a..62b624a0b1 100644 --- a/panda/src/nativenet/socket_tcp.h +++ b/panda/src/nativenet/socket_tcp.h @@ -8,30 +8,27 @@ * 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 * machine - * */ -class EXPCL_PANDA_NATIVENET Socket_TCP : public Socket_IP -{ -public: +class EXPCL_PANDA_NATIVENET Socket_TCP : public Socket_IP { 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); - std::string RecvData(int max_len); + std::string RecvData(int max_len); 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: 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 */ -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 */ -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 * 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 * 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 * 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 * 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; +bool Socket_TCP:: +ActiveOpenNonBlocking(const Socket_Address &theaddress) { + _socket = DO_NEWTCP(theaddress.get_family()); + if (_socket == BAD_SOCKET) { + return false; + } - SetNonBlocking(); - SetReuseAddress(); + SetNonBlocking(); + SetReuseAddress(); - if (DO_CONNECT(_socket, &theaddress.GetAddressInfo()) != 0) { - if (GETERROR() != LOCAL_CONNECT_BLOCKING) - { - printf(" None Blockign Connect Error %d",GETERROR()); - return ErrorClose(); - } + 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 * + 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 * 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 - * 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); +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); + free(buffer); + return str; } -inline bool Socket_TCP::ShutdownSend() -{ - return do_shutdown_send(_socket); -}; + +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::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__ diff --git a/panda/src/nativenet/socket_tcp_listen.h b/panda/src/nativenet/socket_tcp_listen.h index 6091d5114d..7dc9115402 100644 --- a/panda/src/nativenet/socket_tcp_listen.h +++ b/panda/src/nativenet/socket_tcp_listen.h @@ -8,16 +8,17 @@ /** * 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: 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: - inline bool GetIncomingConnection(SOCKET & newsession, Socket_Address &address); + inline bool GetIncomingConnection(SOCKET &newsession, Socket_Address &address); public: static TypeHandle get_class_type() { @@ -40,43 +41,77 @@ private: /** * 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(); - SetReuseAddress(); + 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); + } - if (DO_BIND(_socket, &Inaddess.GetAddressInfo()) != 0) { - return ErrorClose(); - } + SetReuseAddress(); - if (DO_LISTEN(_socket, backlog_size) != 0) { - return ErrorClose(); - } + if (DO_BIND(_socket, &address.GetAddressInfo()) != 0) { + return ErrorClose(); + } - return true; + if (DO_LISTEN(_socket, backlog_size) != 0) { + return ErrorClose(); + } + + return true; } + +/** + * This function will initialize a listening Socket + */ +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 &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__ diff --git a/panda/src/nativenet/socket_tcp_ssl.h b/panda/src/nativenet/socket_tcp_ssl.h index ef89e384c8..83b45b4389 100644 --- a/panda/src/nativenet/socket_tcp_ssl.h +++ b/panda/src/nativenet/socket_tcp_ssl.h @@ -15,76 +15,64 @@ #include #include -/** - * - - * - */ - 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: + 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: - SSL* _ssl; + SSL *_ssl; - void CleanSslUp() - { - if(_ssl != NULL) - { - SSL_shutdown(_ssl); - SSL_free(_ssl); - _ssl = NULL; - } - } + void CleanSslUp() { + if (_ssl != NULL) { + SSL_shutdown(_ssl); + SSL_free(_ssl); + _ssl = NULL; + } + } public: 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 */ -inline int Socket_TCP_SSL::SetNoDelay() -{ - int nodel = 1; - int ret1; - ret1 = setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *) & nodel, sizeof(nodel)); +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; + if (ret1 != 0) { + return BASIC_ERROR; + } + return ALL_OK; } /** * 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 * 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 * 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; +* 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(); + 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 * + 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(); - 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 * 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 */ -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: - answer = true; - break; + answer = true; + break; // 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 // 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 // SSl_CODe=[%d] OS=[%d]",ssl_error_code,GETERROR()); - answer = false; - break; - } + answer = false; + break; + } // ERR_clear_error(); - return answer; + return answer; } -inline void Socket_TCP_SSL::DetailErrorFormat(void) -{ - return; // turn on fir debuging +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; + 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"; - } + 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 diff --git a/panda/src/nativenet/socket_udp.h b/panda/src/nativenet/socket_udp.h index aa271d336d..58c410dd97 100644 --- a/panda/src/nativenet/socket_udp.h +++ b/panda/src/nativenet/socket_udp.h @@ -21,25 +21,22 @@ * duplicates code from Socket_UDP_Outgoing, to avoid the problems of multiple * inheritance. */ -class EXPCL_PANDA_NATIVENET Socket_UDP : public Socket_UDP_Incoming -{ +class EXPCL_PANDA_NATIVENET Socket_UDP : public Socket_UDP_Incoming { public: 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: - inline bool Send(const char * data, int len); + inline bool Send(const char *data, int len); 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: - 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: - 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: static TypeHandle get_class_type() { @@ -58,72 +55,64 @@ public: private: 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; +/** + * 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 + * Connects the socket to a Specified address */ -inline bool Socket_UDP::InitToAddress(const Socket_Address & address) -{ - if (InitNoAddress() != true) - return false; +inline bool Socket_UDP:: +InitToAddress(const Socket_Address &address) { + if (InitNoAddress() != true) { + return false; + } - if (DO_CONNECT(_socket, &address.GetAddressInfo()) != 0) - return ErrorClose(); - - return true; -} -/** - * This will set a udp up for targeted sends.. - */ -inline bool Socket_UDP::InitNoAddress() -{ - Close(); - _socket = DO_NEWUDP(); - if (_socket == BAD_SOCKET) - return false; - - return true; + if (DO_CONNECT(_socket, &address.GetAddressInfo()) != 0) { + return ErrorClose(); + } + return true; } /** * 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); } /** * 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()); } /** * 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 */ -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); } diff --git a/panda/src/nativenet/socket_udp_incoming.h b/panda/src/nativenet/socket_udp_incoming.h index 3fb83785d5..b04cb6b303 100644 --- a/panda/src/nativenet/socket_udp_incoming.h +++ b/panda/src/nativenet/socket_udp_incoming.h @@ -6,21 +6,18 @@ /** * 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: - 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: 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; +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; + if (setsockopt(_socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) != 0) { + return false; + } + return true; } -/** - * Set this socket to work with out a bound external address.. - */ -inline bool Socket_UDP_Incoming::InitNoAddress() -{ - Close(); - _socket = DO_NEWUDP(); - if (_socket == BAD_SOCKET) - return false; - return true; +/** + * Set this socket to work without a bound external address. + */ +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); + } + + return (_socket != BAD_SOCKET); } /** * 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(unsigned short port) { + Close(); - if (DO_BIND(_socket, &address.GetAddressInfo()) != 0) - return ErrorClose(); + 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); + } - return true; + 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 */ -inline bool Socket_UDP_Incoming::OpenForInputMCast(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(); + } - Socket_Address wa1(address.get_port()); - if (DO_BIND(_socket, &wa1.GetAddressInfo()) != 0) - return ErrorClose(); + if (DO_BIND(_socket, &address.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 + return true; +} - int status = setsockopt(GetSocket(), IPPROTO_IP, IP_ADD_MEMBERSHIP, - (const char *)&imreq, sizeof(struct ip_mreq)); +/** + * Starts a UDP socket listening on a port + */ +inline bool Socket_UDP_Incoming:: +OpenForInputMCast(const Socket_Address &address) { + Close(); + _socket = DO_NEWUDP(address.get_family()); + if (_socket == BAD_SOCKET) { + return ErrorClose(); + } - if(status != 0) - return false; - return true; + 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 * */ -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; +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; + 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; + return true; } /** * 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__ diff --git a/panda/src/nativenet/socket_udp_outgoing.h b/panda/src/nativenet/socket_udp_outgoing.h index be7b2b9f8f..3d1c9bb688 100644 --- a/panda/src/nativenet/socket_udp_outgoing.h +++ b/panda/src/nativenet/socket_udp_outgoing.h @@ -5,30 +5,25 @@ #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: - 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: - inline bool Send(const char * data, int len); + inline bool Send(const char *data, int len); 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: - 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: - 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: static TypeHandle get_class_type() { @@ -47,72 +42,79 @@ public: private: static TypeHandle _type_handle; }; -/** - * Ask the OS to let us receive BROADCASt packets on this port.. - */ -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; +/** + * Ask the OS to let us receive broadcast packets on this port. + */ +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; } + /** - * 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.. - */ -inline bool Socket_UDP_Outgoing::InitNoAddress() -{ - Close(); - _socket = DO_NEWUDP(); - if (_socket == BAD_SOCKET) - return false; - return true; +/** + * This will set a udp up for targeted sends. + */ +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 */ -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); } /** * 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()); } /** * 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 */ -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); } diff --git a/panda/src/net/connectionListener.cxx b/panda/src/net/connectionListener.cxx index a6e816683d..c959051653 100644 --- a/panda/src/net/connectionListener.cxx +++ b/panda/src/net/connectionListener.cxx @@ -77,7 +77,7 @@ process_incoming_data(SocketInfo *sinfo) { NetAddress net_addr(addr); 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() << "\n"; diff --git a/panda/src/net/connectionManager.cxx b/panda/src/net/connectionManager.cxx index ce2b97ace0..f7fdbe7e3e 100644 --- a/panda/src/net/connectionManager.cxx +++ b/panda/src/net/connectionManager.cxx @@ -69,7 +69,7 @@ ConnectionManager:: * communication. */ PT(Connection) ConnectionManager:: -open_UDP_connection(int port) { +open_UDP_connection(uint16_t port) { return open_UDP_connection("", port); } @@ -80,7 +80,8 @@ open_UDP_connection(int port) { * sending. * * 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 * and/or receive messages on the broadcast address (255.255.255.255); @@ -90,24 +91,27 @@ open_UDP_connection(int port) { * communication. */ 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; if (port > 0) { + bool okflag; NetAddress address; if (hostname.empty()) { - address.set_any(port); + // The empty string means to listen on both IPv4 and IPv6 interfaces. + okflag = socket->OpenForInput(port); } else { address.set_host(hostname, port); + okflag = socket->OpenForInput(address.get_addr()); } - if (!socket->OpenForInput(address.get_addr())) { + if (!okflag) { if (hostname.empty()) { net_cat.error() << "Unable to bind to port " << port << " for UDP.\n"; } else { net_cat.error() - << "Unable to bind to " << hostname << ":" << port << " for UDP.\n"; + << "Unable to bind to " << address << " for UDP.\n"; } delete socket; 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"; } else { net_cat.info() - << "Creating UDP " << broadcast_note << "connection for " << hostname << ":" << port << "\n"; + << "Creating UDP " << broadcast_note << "connection for " << address << "\n"; } } else { @@ -150,23 +154,32 @@ open_UDP_connection(const string &hostname, int port, bool for_broadcast) { return connection; } - - /** * 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 * to a ConnectionListener (not to a generic ConnectionReader). * * 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. */ 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. */ 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()) { - address.set_any(port); + return open_TCP_server_rendezvous(port, backlog); } else { + NetAddress address; 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:: 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; - bool okflag = socket->OpenForListen(address.get_addr(), backlog); - if (!okflag) { + if (!socket->OpenForListen(address.get_addr(), backlog)) { net_cat.info() - << "Unable to listen to " << strm.str() << " for TCP.\n"; + << "Unable to listen to " << address << " for TCP.\n"; delete socket; return PT(Connection)(); } 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); new_connection(connection); @@ -263,7 +268,7 @@ open_TCP_client_connection(const NetAddress &address, int timeout_ms) { if (okflag) { // 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. okflag = false; } @@ -271,8 +276,7 @@ open_TCP_client_connection(const NetAddress &address, int timeout_ms) { if (!okflag) { 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; return PT(Connection)(); } @@ -286,8 +290,7 @@ open_TCP_client_connection(const NetAddress &address, int timeout_ms) { #endif // SIMPLE_THREADS 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); new_connection(connection); @@ -299,7 +302,7 @@ open_TCP_client_connection(const NetAddress &address, int timeout_ms) { * communications to a named host and port. */ 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) { NetAddress address; if (!address.set_host(hostname, port)) { @@ -474,11 +477,12 @@ scan_interfaces() { #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; + ULONG family = support_ipv6 ? AF_UNSPEC : AF_INET; 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) { 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) { IP_ADAPTER_ADDRESSES *p = addresses; while (p != NULL) { @@ -502,7 +506,7 @@ scan_interfaces() { IP_ADAPTER_PREFIX *m = p->FirstPrefix; int mc = 0; 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; ++mc; } @@ -517,10 +521,13 @@ scan_interfaces() { // Now, we can infer the netmask by the difference between the // network address (the first address) and the broadcast 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; 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; iface.set_name(p->ifa_name); 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) { - 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) { - 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) { - iface.set_p2p(NetAddress(Socket_Address(*(sockaddr_in *)p->ifa_dstaddr))); + iface.set_p2p(NetAddress(Socket_Address(*p->ifa_dstaddr))); } _interfaces.push_back(iface); } @@ -572,10 +580,9 @@ scan_interfaces() { /** * 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() { if (!_interfaces_scanned) { scan_interfaces(); @@ -586,16 +593,15 @@ get_num_interfaces() { /** * 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:: -get_interface(int n) { +get_interface(size_t n) { if (!_interfaces_scanned) { scan_interfaces(); } LightMutexHolder holder(_set_mutex); - nassertr(n >= 0 && n < (int)_interfaces.size(), _interfaces[0]); + nassertr(n < _interfaces.size(), _interfaces[0]); return _interfaces[n]; } @@ -709,9 +715,9 @@ remove_writer(ConnectionWriter *writer) { * Formats a device's MAC address into a string. */ 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; - for (int di = 0; di < data_size; ++di) { + for (size_t di = 0; di < data_size; ++di) { if (di != 0) { strm << "-"; } @@ -728,16 +734,16 @@ void ConnectionManager::Interface:: output(ostream &out) const { out << get_name() << " ["; if (has_ip()) { - out << " " << get_ip(); + out << " " << get_ip().get_ip_string(); } if (has_netmask()) { - out << " netmask " << get_netmask(); + out << " netmask " << get_netmask().get_ip_string(); } if (has_broadcast()) { - out << " broadcast " << get_broadcast(); + out << " broadcast " << get_broadcast().get_ip_string(); } if (has_p2p()) { - out << " p2p " << get_p2p(); + out << " p2p " << get_p2p().get_ip_string(); } out << " ]"; } diff --git a/panda/src/net/connectionManager.h b/panda/src/net/connectionManager.h index c6f04ecbe0..1b00268d6c 100644 --- a/panda/src/net/connectionManager.h +++ b/panda/src/net/connectionManager.h @@ -43,18 +43,18 @@ PUBLISHED: 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, - int port, int backlog); + uint16_t port, int backlog); BLOCKING PT(Connection) open_TCP_server_rendezvous(const NetAddress &address, int backlog); BLOCKING PT(Connection) open_TCP_client_connection(const NetAddress &address, 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); BLOCKING bool wait_for_readers(double timeout); @@ -104,8 +104,8 @@ PUBLISHED: }; 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_PROPERTY(host_name, get_host_name); @@ -122,7 +122,7 @@ protected: void add_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 Readers; diff --git a/panda/src/net/netAddress.cxx b/panda/src/net/netAddress.cxx index ee0ed96ba2..0f0404dc45 100644 --- a/panda/src/net/netAddress.cxx +++ b/panda/src/net/netAddress.cxx @@ -91,6 +91,14 @@ set_port(int 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. */ @@ -102,6 +110,7 @@ get_ip_string() const { /** * Returns the IP address to which this address refers, as a 32-bit integer, * in host byte order. + * @deprecated Does not work with IPv6 addresses. */ uint32_t NetAddress:: get_ip() const { @@ -135,7 +144,7 @@ get_addr() const { */ void NetAddress:: output(ostream &out) const { - out << get_ip_string(); + out << _addr.get_ip_port(); } /** diff --git a/panda/src/net/netAddress.h b/panda/src/net/netAddress.h index f10b02041d..d6b15b307e 100644 --- a/panda/src/net/netAddress.h +++ b/panda/src/net/netAddress.h @@ -37,6 +37,7 @@ PUBLISHED: int get_port() const; void set_port(int port); string get_ip_string() const; + bool is_any() const; uint32_t get_ip() const; uint8_t get_ip_component(int n) const;