IPv6 support, improve URL handling/comparison

This commit is contained in:
rdb 2016-06-22 17:57:40 +02:00
parent f068a8613b
commit 7e08b87ff7
31 changed files with 1607 additions and 976 deletions

View File

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

View File

@ -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;

View File

@ -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;

View File

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

View File

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

View File

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

View File

@ -18,13 +18,46 @@
#include "urlSpec.h"
#include "config_downloader.h"
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#endif
#ifdef _WIN32
static string format_error() {
PVOID buffer;
DWORD len;
len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, WSAGetLastError(), 0, (LPTSTR)&buffer, 0, NULL);
if (len == 0) {
return string("Unknown error message");
}
const char *text = (const char *)buffer;
while (len > 0 && isspace(text[len - 1])) {
--len;
}
string result(text, len);
LocalFree(buffer);
return result;
}
#else
#define format_error() strerror(errno)
#endif
/**
* This flavor of the constructor automatically creates a socket BIO and feeds
* 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);

View File

@ -27,6 +27,14 @@
#include "openSSLWrapper.h" // must be included before any other openssl.
#include "openssl/ssl.h"
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#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"

View File

@ -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();
}

View File

@ -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();

View File

@ -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";
}
}

View File

@ -19,14 +19,6 @@ URLSpec(const string &url, bool server_name_expected) {
set_url(url, server_name_expected);
}
/**
*
*/
INLINE URLSpec::
URLSpec(const URLSpec &copy) {
(*this) = copy;
}
/**
*
*/
@ -40,7 +32,7 @@ operator = (const string &url) {
*/
INLINE bool URLSpec::
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];
}

View File

@ -12,10 +12,11 @@
*/
#include "urlSpec.h"
#include "filename.h"
#include "string_utils.h"
#include <ctype.h>
/**
*
*/
@ -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 &copy) {
_url = copy._url;
_port = copy._port;
_flags = copy._flags;
_scheme_end = copy._scheme_end;
_username_start = copy._username_start;
_username_end = copy._username_end;
_server_start = copy._server_start;
_server_end = copy._server_end;
_port_start = copy._port_start;
_port_end = copy._port_end;
_path_start = copy._path_start;
_path_end = copy._path_end;
_query_start = copy._query_start;
size_t URLSpec::
get_hash() const {
size_t hash = 0;
hash = int_hash::add_hash(hash, _flags & (F_has_scheme | F_has_username | F_has_server));
if (has_scheme()) {
hash = string_hash::add_hash(hash, downcase(get_scheme()));
}
if (has_username()) {
hash = string_hash::add_hash(hash, get_username());
}
if (has_server()) {
hash = string_hash::add_hash(hash, downcase(get_server()));
}
hash = int_hash::add_hash(hash, get_port());
hash = string_hash::add_hash(hash, get_path_and_query());
return hash;
}
/**
@ -71,7 +136,7 @@ get_scheme() const {
* Returns the port number specified by the URL, or the default port if not
* 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.

View File

@ -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 &copy);
URLSpec(const URLSpec &url, const Filename &path);
INLINE void operator = (const string &url);
void operator = (const URLSpec &copy);
INLINE bool operator == (const URLSpec &other) const;
INLINE bool operator != (const URLSpec &other) const;
INLINE bool operator < (const URLSpec &other) const;
INLINE 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;

View File

@ -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"

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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"

View File

@ -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);

View File

@ -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 <winsock2.h>
#include <Ws2tcpip.h>
typedef u_short sa_family_t;
inline int DO_SELECT(SOCKET n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,struct timeval *timeout)
{
return select((int) n, readfds, writefds, exceptfds,timeout);
inline int DO_SELECT(SOCKET n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) {
return select((int)n, readfds, writefds, exceptfds, timeout);
}
inline int DO_CONNECT( const SOCKET a, const struct sockaddr_in *b)
{
return connect(a, reinterpret_cast<const struct ::sockaddr *>(b), sizeof(sockaddr));
inline int DO_CONNECT(const SOCKET a, const struct sockaddr *b) {
return connect(a, b, SA_SIZEOF(b));
}
inline int DO_SOCKET_READ(const SOCKET a, char * buf, const int size)
{
return recv(a, buf, size, 0);
inline int DO_SOCKET_READ(const SOCKET a, char *buf, const int size) {
return recv(a, buf, size, 0);
}
inline int DO_SOCKET_WRITE(const SOCKET a, const char * buff, const int len)
{
return send(a, buff, len, 0);
inline int DO_SOCKET_WRITE(const SOCKET a, const char *buff, const int len) {
return send(a, buff, len, 0);
}
inline int DO_SOCKET_WRITE_TO(const SOCKET a, const char * buffer, const int buf_len, const sockaddr_in * addr)
{
return sendto(a, buffer, buf_len, 0, reinterpret_cast<const struct ::sockaddr *>(addr), sizeof(sockaddr));
inline int DO_SOCKET_WRITE_TO(const SOCKET a, const char *buffer, const int buf_len, const sockaddr *addr) {
return sendto(a, buffer, buf_len, 0, addr, SA_SIZEOF(addr));
}
inline SOCKET DO_NEWUDP()
{
return socket(AF_INET, SOCK_DGRAM, 0);
inline SOCKET DO_NEWUDP(sa_family_t family) {
return socket(family, SOCK_DGRAM, 0);
}
inline SOCKET DO_NEWTCP()
{
return socket(AF_INET, SOCK_STREAM, 0);
inline SOCKET DO_NEWTCP(sa_family_t family) {
return socket(family, SOCK_STREAM, 0);
}
inline int DO_BIND(const SOCKET a, const sockaddr_in *b)
{
return ::bind(a, reinterpret_cast<const struct ::sockaddr *>(b), sizeof(sockaddr));
inline int DO_BIND(const SOCKET a, const sockaddr *b) {
return ::bind(a, b, SA_SIZEOF(b));
}
inline int DO_CLOSE(const SOCKET a)
{
return 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<sockaddr *>(adr), &adrlen);
};
inline int DO_RECV_FROM(SOCKET sck, char * data, int len, sockaddr_in * addr)
{
int plen = sizeof(sockaddr);
return recvfrom(sck, data, len, 0, reinterpret_cast<sockaddr *>(addr), &plen);
inline 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<const struct ::sockaddr *>(b), sizeof(sockaddr));
inline int DO_CONNECT(const SOCKET a, const sockaddr *b) {
return connect(a, b, SA_SIZEOF(b));
}
inline int DO_SOCKET_READ(const SOCKET a, char * buf, const int size)
{
return recv(a, buf, size, 0);
inline int DO_SOCKET_READ(const SOCKET a, char *buf, const int size) {
return recv(a, buf, size, 0);
}
inline int DO_SOCKET_WRITE(const SOCKET a, const char * buff, const int len)
{
return send(a, buff, len, 0);
inline int DO_SOCKET_WRITE(const SOCKET a, const char *buff, const int len) {
return send(a, buff, len, 0);
}
// #define DO_SOCKET_WRITE_TO(a,b,c,d) sendto(a,b,c,0,(sockaddr
// *)d,sizeof(sockaddr)) #define DO_NEWUDP() socket(AF_INET,
// SOCK_DGRAM, 0) #define DO_NEWTCP() socket(AF_INET, SOCK_STREAM, 0)
// #define DO_BIND(a,b) ::bind(a,(sockaddr *)b,sizeof(sockaddr)) #define
// DO_CLOSE(a) close(a)
inline int DO_SOCKET_WRITE_TO(const SOCKET a, const char * buffer, const int buf_len, const sockaddr_in * addr)
{
return sendto(a, buffer, buf_len, 0, reinterpret_cast<const struct ::sockaddr *>(addr), sizeof(sockaddr));
inline int DO_SOCKET_WRITE_TO(const SOCKET a, const char *buffer, const int buf_len, const sockaddr *addr) {
return sendto(a, buffer, buf_len, 0, addr, SA_SIZEOF(addr));
}
inline SOCKET DO_NEWUDP()
{
return socket(AF_INET, SOCK_DGRAM, 0);
inline SOCKET DO_NEWUDP(sa_family_t family) {
return socket(family, SOCK_DGRAM, 0);
}
inline SOCKET DO_NEWTCP()
{
return socket(AF_INET, SOCK_STREAM, 0);
inline SOCKET DO_NEWTCP(sa_family_t family) {
return socket(family, SOCK_STREAM, 0);
}
inline int DO_BIND(const SOCKET a, const sockaddr_in *b)
{
return ::bind(a, reinterpret_cast<const struct ::sockaddr *>(b), sizeof(sockaddr));
inline int DO_BIND(const SOCKET a, const sockaddr *b) {
return ::bind(a, b, SA_SIZEOF(b));
}
inline int DO_CLOSE(const SOCKET a)
{
return close(a);
inline int DO_CLOSE(const SOCKET a) {
return close(a);
}
inline int DO_ACCEPT(SOCKET sck, sockaddr_in * adr)
{
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 <arpa/inet.h>
#include <unistd.h>
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<const struct ::sockaddr *>(b), sizeof(sockaddr));
inline int DO_CONNECT(const SOCKET a, const sockaddr *b) {
return connect(a, b, SA_SIZEOF(b));
}
inline int DO_SOCKET_READ(const SOCKET a, char * buf, const int size)
{
return (int)recv(a, buf, (size_t)size, 0);
inline int DO_SOCKET_READ(const SOCKET a, char *buf, const int size) {
return (int)recv(a, buf, (size_t)size, 0);
}
inline int DO_SOCKET_WRITE(const SOCKET a, const char * buff, const int len)
{
return (int)send(a, buff, (size_t)len, 0);
inline int DO_SOCKET_WRITE(const SOCKET a, const char *buff, const int len) {
return (int)send(a, buff, (size_t)len, 0);
}
inline int DO_SOCKET_WRITE_TO(const SOCKET a, const char * buffer, const int buf_len, const sockaddr_in * addr)
{
return (int)sendto(a, buffer, (size_t)buf_len, 0, reinterpret_cast<const struct ::sockaddr *>(addr), sizeof(sockaddr));
inline int DO_SOCKET_WRITE_TO(const SOCKET a, const char *buffer, const int buf_len, const sockaddr *addr) {
return (int)sendto(a, buffer, (size_t)buf_len, 0, addr, SA_SIZEOF(addr));
}
inline SOCKET DO_NEWUDP()
{
return socket(AF_INET, SOCK_DGRAM, 0);
inline SOCKET DO_NEWUDP(sa_family_t family) {
return socket(family, SOCK_DGRAM, 0);
}
inline SOCKET DO_NEWTCP()
{
return socket(AF_INET, SOCK_STREAM, 0);
inline SOCKET DO_NEWTCP(sa_family_t family) {
return socket(family, SOCK_STREAM, 0);
}
inline int DO_BIND(const SOCKET a, const sockaddr_in *b)
{
return ::bind(a, reinterpret_cast<const struct ::sockaddr *>(b), sizeof(sockaddr));
inline int DO_BIND(const SOCKET a, const sockaddr *b) {
return ::bind(a, b, SA_SIZEOF(b));
}
inline int DO_CLOSE(const SOCKET a)
{
return close(a);
inline int DO_CLOSE(const SOCKET a) {
return close(a);
}
inline int DO_ACCEPT(SOCKET sck, sockaddr_in * adr)
{
socklen_t adrlen = sizeof(sockaddr);
return accept(sck, ( sockaddr *)adr, &adrlen);
};
inline int DO_ACCEPT(SOCKET sck, sockaddr *addr) {
socklen_t addrlen = sizeof(sockaddr_storage);
return accept(sck, (sockaddr *)addr, &addrlen);
}
inline int DO_RECV_FROM(SOCKET sck, char * data, int len, sockaddr_in * addr)
{
socklen_t plen = sizeof(sockaddr);
return (int)recvfrom(sck, data, (size_t)len, 0, (sockaddr *)addr, &plen);
inline int DO_RECV_FROM(SOCKET sck, char *data, int len, sockaddr *addr) {
socklen_t plen = sizeof(sockaddr_storage);
return (int)recvfrom(sck, data, (size_t)len, 0, (sockaddr *)addr, &plen);
}
inline int init_network()
{
signal(SIGPIPE, SIG_IGN); // hmm do i still need this ...
return ALL_OK;
inline int init_network() {
signal(SIGPIPE, SIG_IGN); // hmm do i still need this ...
return ALL_OK;
}
inline int DO_LISTEN(const SOCKET a, const int size)
{
return listen(a, size);
inline int DO_LISTEN(const SOCKET a, const int size) {
return listen(a, size);
}
inline int GETERROR()
{
return errno;
inline int GETERROR() {
return errno;
}
inline int SOCKIOCTL(const SOCKET s, const long flags, void * val)
{
return ioctl(s, (unsigned long)flags, val);
inline int SOCKIOCTL(const SOCKET s, const long flags, void *val) {
return ioctl(s, (unsigned long)flags, val);
}
inline bool do_shutdown_send(SOCKET s)
{
return (shutdown(s,SHUT_WR) == 0);
};
inline bool do_shutdown_send(SOCKET s) {
return (shutdown(s, SHUT_WR) == 0);
}
#define BSDBLOCK
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__

View File

@ -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__

View File

@ -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__

View File

@ -15,76 +15,64 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
/**
*
*
*/
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

View File

@ -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);
}

View File

@ -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__

View File

@ -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);
}

View File

@ -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";

View File

@ -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 << " ]";
}

View File

@ -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<ConnectionReader *, pointer_hash> Readers;

View File

@ -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();
}
/**

View File

@ -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;