10 #include <arpa/inet.h>
12#if defined(_USE_SSL_) && defined(WINDOWS)
19 #undef X509_EXTENSIONS
21 #undef PKCS7_SIGNER_INFO
36static void LogSSLErrors(
const char* context,
int level) {
40 while ((e = ERR_get_error()) != 0) {
41 ERR_error_string_n(e, buf,
sizeof(buf));
46 LogPrint(0,
LOG_NETWORK, level,
"SSL: %s (no OpenSSL error detail)", context ? context :
"error");
90void TCPListener::disconnectInternal(uint16 error) {
97 if (receiver && error)
103 disconnectInternal(error);
119 this->encryption = encryption;
120 memcpy(((
char*)&localAddress)+
sizeof(uint32), &port,
sizeof(uint16));
124 if((socket=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==
INVALID_SOCKET){
134 setsockopt(socket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (
char *) &one,
sizeof(one));
146 setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&one,
sizeof(one));
149 struct sockaddr_in addr;
150 addr.sin_family= AF_INET;
151 addr.sin_addr.s_addr=INADDR_ANY;
152 addr.sin_port=htons(port);
156 disconnectInternal(0);
165 disconnectInternal(0);
170 if (receiver != NULL) {
171 this->receiver = receiver;
175 disconnectInternal(0);
180 this->dataReceiver = dataReceiver;
192 this->sslCertPath = sslCertPath;
193 this->sslKeyPath = sslKeyPath;
205 while ( (timespent = (
GetTimeNow() - start)/1000) < timeout) {
208 new_sock = accept(socket, NULL, NULL);
210 if ((
int) new_sock < 0) {
219 LogPrint(0,
LOG_NETWORK, 2,
"Shutting down network listener with error code: %d", new_sock);
222 if (err != WSAENOTSOCK)
233 if (encryption ==
SSLENC) {
236 if (!sslCon->
init(sslCertPath.c_str(), sslKeyPath.c_str())) {
245 if (!sslCon->
connect(new_sock, localAddress, dataReceiver)) {
254 else if (encryption ==
AESENC) {
261 if (!newCon->
connect(new_sock, localAddress, dataReceiver)) {
280bool TCPListener::run() {
283 if (receiver == NULL)
289 if (receiver != NULL)
333 mutex.setCancelSafe(
true);
403 receiver->registerError(error,
this);
414 if (len < 128)
return false;
415 char* newBuffer =
new char[len];
458#ifdef TCPCON_PRINT_DEBUG
485 memset(&from, 0,
sizeof(from));
487 int fromLen =
sizeof(from);
489 socklen_t fromLen =
sizeof(from);
496 memcpy(&src, &from.sin_addr.s_addr, 4);
497 uint16 srcPort = ntohs(from.sin_port);
498 memcpy(((
char*)&src) +
sizeof(uint32), &srcPort,
sizeof(uint16));
512 if (err != WSAENOTSOCK)
547 if (datagram && c > 0)
551 #ifdef TCPCON_PRINT_DEBUG
554 char* tmp =
new char[count+1];
557 LogPrint(0,
LOG_NETWORK,0,
"<<<<<<< READINTOBUFFER <<<<<<<< TCP RECV BUF %d bytes '%s' (%.3fms) %d / %d\n", count, tmp,
GetTimeAge(start)/1000.0, rounds, resize);
566 #ifdef UDPCON_PRINT_DEBUG
569 char* tmp =
new char[count+1];
572 LogPrint(0,
LOG_NETWORK,0,
"<<<<<<< READINTOBUFFER <<<<<<<< UDP RECV BUF %u bytes '%s'\n", count, tmp);
622 if (!c && dataAvailable) {
630 if ((timespent =
GetTimeAgeMS(start)) >= (int32)timeout)
691 if ((timespent =
GetTimeAgeMS(start)) >= (int32)timeout) {
706 inputSpeed = (uint32)(size*1000000.0/(
double)t);
772 if (!
mutex.enter(1000))
776 int res = recv(
socket, peekBuffer, 1, MSG_PEEK);
794 else if (err == WSAENOTCONN) {}
795 else if (err == WSAENOTSOCK) {}
796 else if (err == WSAEOPNOTSUPP) {}
835 #if GCC_VERSION < 40000
849 ldiv_t d = ldiv(timeout*1000, 1000000);
855 res = select(maxfd, NULL, &wfds, NULL, &tv);
865 if (!
mutex.enter(1000))
868 if (FD_ISSET(
socket, &wfds) != 0) {
869 if (getsockopt(
socket, SOL_SOCKET, SO_ERROR, (
char*)&error, &len) != 0) {
878 else if (wsaError == WSAENETDOWN ) {
881 else if (wsaError == WSAEFAULT ) {
884 else if (wsaError == WSAEINPROGRESS ) {
887 else if (wsaError == WSAEINVAL ) {
890 else if (wsaError == WSAENOPROTOOPT ) {
895 else if (wsaError == WSAENOTSOCK ) {
928 #if GCC_VERSION < 40000
942 ldiv_t d = ldiv(timeout * 1000, 1000000);
948 int res = select(maxfd, NULL, &wfds, NULL, &tv);
958 if (FD_ISSET(s, &wfds) != 0) {
959 if (getsockopt(s, SOL_SOCKET, SO_ERROR, (
char*)&error, &len) != 0) {
967 else if (wsaError == WSAENETDOWN) {
970 else if (wsaError == WSAEFAULT) {
973 else if (wsaError == WSAEINPROGRESS) {
976 else if (wsaError == WSAEINVAL) {
979 else if (wsaError == WSAENOPROTOOPT) {
984 else if (wsaError == WSAENOTSOCK) {
1002 if (!
mutex.enter(1000))
1022 #if GCC_VERSION < 40000
1036 ldiv_t d = ldiv(timeout * 1000, 1000000);
1042 int res = select(maxfd, NULL, &wfds, NULL, &tv);
1050 len =
sizeof(error);
1053 if (FD_ISSET(
socket, &wfds) != 0) {
1054 if (getsockopt(
socket, SOL_SOCKET, SO_ERROR, (
char*)&error, &len) != 0) {
1058 if (wsaError == 0) {
1063 else if (wsaError == WSAENETDOWN) {
1066 else if (wsaError == WSAEFAULT) {
1069 else if (wsaError == WSAEINPROGRESS) {
1072 else if (wsaError == WSAEINVAL) {
1075 else if (wsaError == WSAENOPROTOOPT) {
1080 else if (wsaError == WSAENOTSOCK) {
1102 char* myBuffer = (
char*) malloc(buflen);
1103 if (myBuffer == NULL)
1106 LogPrint(0,
LOG_NETWORK, 2,
"Incoming network connection from %u.%u.%u.%u:%u, started run...",
1111 if (
receive((
char*)&size,
sizeof(size), 50,
true)) {
1113 if (buflen < size) {
1115 myBuffer = (
char*) realloc(myBuffer, buflen);
1116 if (myBuffer == NULL) {
1124 if (!
receive(myBuffer, size, 500)) {
1132 receiver->receiveData(myBuffer, size,
this);
1185 setsockopt(
socket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (
char *) &one,
sizeof(one));
1197 setsockopt(
socket,SOL_SOCKET,SO_REUSEADDR,&one,
sizeof(one));
1200 setsockopt(
socket,SOL_SOCKET,SO_BROADCAST,(
char*)&one,
sizeof(one));
1215 memcpy(((
char*)&
localAddress)+
sizeof(uint32), &port,
sizeof(uint16));
1231 setsockopt(
socket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (
char *) &one,
sizeof(one));
1243 setsockopt(
socket,SOL_SOCKET,SO_REUSEADDR,&one,
sizeof(one));
1246 setsockopt(
socket,SOL_SOCKET,SO_BROADCAST,(
char*)&one,
sizeof(one));
1250 int rcvbuf = 4 * 1024 * 1024;
1251 setsockopt(
socket, SOL_SOCKET, SO_RCVBUF, (
char*)&rcvbuf,
sizeof(rcvbuf));
1254 struct sockaddr_in addr;
1255 addr.sin_family= AF_INET;
1256 addr.sin_addr.s_addr=INADDR_ANY;
1257 addr.sin_port=htons(port);
1287 sockaddr_in recvAddr;
1288 recvAddr.sin_family = AF_INET;
1298 recvAddr.sin_port = htons(p);
1299 memcpy(&recvAddr.sin_addr.s_addr, &rec, 4);
1309 n = ::sendto(
socket, data + pos, size - pos, 0, (
SOCKADDR*)&recvAddr,
sizeof(sockaddr_in));
1344 #ifdef UDPCON_PRINT_DEBUG
1346 char* tmp =
new char[size+1];
1347 memcpy(tmp, data, size);
1353 #ifdef UDPCON_PRINTBINARY_DEBUG
1354 char* tmp =
new char[size+1];
1355 memcpy(tmp, data, size);
1360 char* tmp =
new char[1024];
1361 memcpy(tmp, data, 1023);
1417 struct linger tmp = {1, 0};
1418 setsockopt(
socket, SOL_SOCKET, SO_LINGER, (
char *)&tmp,
sizeof(tmp));
1420 setsockopt(
socket, IPPROTO_TCP, TCP_NODELAY, (
char*) &delay,
sizeof(delay));
1426 LogPrint(0,
LOG_NETWORK, 2,
"Incoming TCP connection from %u.%u.%u.%u:%u, starting run...",
1491 struct sockaddr_in saServer;
1492 saServer.sin_family = AF_INET;
1493 saServer.sin_port = htons(
GETIPPORT(addr));
1494 memcpy(&saServer.sin_addr.s_addr, &addr, 4);
1498 if ((res =
::connect(tempSocket, (
struct sockaddr*)&saServer,
sizeof(
struct sockaddr))) != 0) {
1515 struct linger tmp = {1, 0};
1516 setsockopt(tempSocket, SOL_SOCKET, SO_LINGER, (
char *)&tmp,
sizeof(tmp));
1518 setsockopt(tempSocket, IPPROTO_TCP, TCP_NODELAY, (
char*) &delay,
sizeof(delay));
1525 if (!
mutex.enter(1000)) {
1561 for (uint16 n=0; n<addressCount; n++) {
1684 #ifdef TCPCON_PRINT_DEBUG
1686 char* tmp =
new char[size+1];
1687 memcpy(tmp, data, size);
1689 LogPrint(0,
LOG_NETWORK,0,
">>>>>>> SEND >>>>>>>> TCP Sent %u bytes (%.3f) '%s'\n", size, t/1000.0, tmp);
1693 #ifdef TCPCON_PRINTBINARY_DEBUG
1694 char* tmp =
new char[size+1];
1695 memcpy(tmp, data, size);
1700 char* tmp =
new char[1024];
1701 memcpy(tmp, data, 1023);
1703 LogPrint(0,
LOG_NETWORK,0,
">>>>>>> SEND >>>>>>>> TCP Sent %u bytes (%.3f) '%s'\n", size, t / 1000.0, tmp);
1727 struct sockaddr_in remoteAddr;
1733 #if GCC_VERSION < 40000
1736 socklen_t remoteAddrLen;
1739 socklen_t remoteAddrLen;
1743 remoteAddrLen =
sizeof(
struct sockaddr_in);
1745 if (getpeername(
socket, (
struct sockaddr*) &remoteAddr, &remoteAddrLen) != 0)
1748 uint32 address = remoteAddr.sin_addr.s_addr;
1790 OpenSSL_add_all_algorithms();
1792 ERR_load_crypto_strings();
1793 SSL_load_error_strings();
1795 certbio = BIO_new(BIO_s_file());
1796 outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
1848 applyClientVerify();
1860 applyClientVerify();
1867bool SSLConnection::applyClientVerify() {
1871 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
1877 if (SSL_CTX_load_verify_locations(ctx,
1890 bool loadedOSRoots =
false;
1891 HCERTSTORE hStore = CertOpenSystemStoreA(0,
"ROOT");
1893 X509_STORE* store = SSL_CTX_get_cert_store(ctx);
1894 PCCERT_CONTEXT pWinCert = NULL;
1895 while ((pWinCert = CertEnumCertificatesInStore(hStore, pWinCert)) != NULL) {
1896 const unsigned char* enc = pWinCert->pbCertEncoded;
1897 X509* x = d2i_X509(NULL, &enc, pWinCert->cbCertEncoded);
1900 if (X509_STORE_add_cert(store, x) == 1)
1901 loadedOSRoots =
true;
1905 CertCloseStore(hStore, 0);
1912 if (SSL_CTX_set_default_verify_paths(ctx) != 1)
1916 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
1921int SSLConnection::getVerifyMode() {
1924 return SSL_CTX_get_verify_mode(ctx);
1933 const SSL_METHOD *method = SSLv23_server_method();
1935 ctx = SSL_CTX_new(method);
1938 BIO_printf(outbio,
"Unable to create a new SSL context structure.\n");
1944 if ( SSL_CTX_use_certificate_chain_file(ctx, certFile) <= 0) {
1946 LogSSLErrors(
"certificate chain file", 0);
1950 if ( SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
1952 LogSSLErrors(
"private key file", 0);
1959 if ( !SSL_CTX_check_private_key(ctx) ) {
1961 fprintf(stderr,
"Private key is invalid.\n");
1978 const SSL_METHOD *method = SSLv23_method();
1980 ctx = SSL_CTX_new(method);
1982 BIO_printf(outbio,
"Unable to create a new SSL context structure.\n");
1991 applyClientVerify();
2022 if (!
mutex.enter(200, __FUNCTION__))
2025 int res = recv(
socket, peekBuffer, 1, MSG_PEEK);
2046 else if (err == WSAENOTCONN) {}
2047 else if (err == WSAEOPNOTSUPP) {}
2090 #if GCC_VERSION < 40000
2104 ldiv_t d = ldiv(timeout*1000, 1000000);
2111 res = select(maxfd, NULL, &wfds, NULL, &tv);
2120 len =
sizeof(error);
2124 if (FD_ISSET(
socket, &wfds) != 0) {
2125 if (getsockopt(
socket, SOL_SOCKET, SO_ERROR, (
char*)&error, &len) != 0) {
2129 if (wsaError == 0) {
2134 else if (wsaError == WSAENETDOWN ) {
2137 else if (wsaError == WSAEFAULT ) {
2140 else if (wsaError == WSAEINPROGRESS ) {
2143 else if (wsaError == WSAEINVAL ) {
2146 else if (wsaError == WSAENOPROTOOPT ) {
2151 else if (wsaError == WSAENOTSOCK ) {
2188 if (!ctx || !(ssl = SSL_new(ctx)))
2202 struct linger tmp = {1, 0};
2203 setsockopt(s, SOL_SOCKET, SO_LINGER, (
char *)&tmp,
sizeof(tmp));
2205 setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (
char*) &delay,
sizeof(delay));
2210 SSL_set_fd(ssl, (
int)
socket);
2211 int ret = SSL_accept(ssl);
2216 err = SSL_get_error(ssl, ret);
2217 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
2219 if ((++errCount) > 10) {
2230 ret = SSL_accept(ssl);
2269 if (!ctx && !
init()) {
2272 if (!ctx || !(ssl = SSL_new(ctx))) {
2273 LogSSLErrors(
"SSL_new", 0);
2311 struct sockaddr_in saServer;
2312 saServer.sin_family = AF_INET;
2313 saServer.sin_port = htons(
GETIPPORT(addr));
2314 memcpy(&saServer.sin_addr.s_addr, &addr, 4);
2319 if ((res =
::connect(
socket, (
struct sockaddr*)&saServer,
sizeof(
struct sockaddr))) != 0) {
2340 struct linger tmp = {1, 0};
2341 setsockopt(
socket, SOL_SOCKET, SO_LINGER, (
char *)&tmp,
sizeof(tmp));
2343 setsockopt(
socket, IPPROTO_TCP, TCP_NODELAY, (
char*) &delay,
sizeof(delay));
2346 if (!SSL_set_fd (ssl, (
int)
socket)) {
2347 LogSSLErrors(
"SSL_set_fd", 0);
2356 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
2363 while ( (ret = SSL_connect(ssl)) != 1) {
2364 switch (SSL_get_error(ssl, ret)) {
2365 case SSL_ERROR_WANT_READ:
2368 case SSL_ERROR_WANT_WRITE:
2376 LogSSLErrors(
"handshake failed", 1);
2395 uint32 certnamemax = 1000;
2399 cert = SSL_get_peer_certificate(ssl);
2401 certname =
new char[certnamemax+1];
2402 certinfo = X509_NAME_oneline(X509_get_subject_name(cert), certname, certnamemax);
2437 if (
verifyHostName.empty() && addr && (inet_addr(addr) == INADDR_NONE))
2448 for (uint16 n=0; n<addressCount; n++) {
2491 if (
verifyHostName.empty() && addr && (inet_addr(addr) == INADDR_NONE))
2514 while ( (ret = SSL_write(ssl, data, size)) <= 0) {
2515 switch (SSL_get_error(ssl, ret)) {
2516 case SSL_ERROR_WANT_READ:
2519 case SSL_ERROR_WANT_WRITE:
2529 if (ret < (
int)size) {
2543 #ifdef TCPCON_PRINT_DEBUG
2545 char* tmp =
new char[size+1];
2546 memcpy(tmp, data, size);
2552 #ifdef TCPCON_PRINTBINARY_DEBUG
2553 char* tmp =
new char[size+1];
2554 memcpy(tmp, data, size);
2584 struct sockaddr_in remoteAddr;
2590 #if GCC_VERSION < 40000
2593 socklen_t remoteAddrLen;
2596 socklen_t remoteAddrLen;
2600 remoteAddrLen =
sizeof(
struct sockaddr_in);
2602 if (getpeername(
socket, (
struct sockaddr*) &remoteAddr, &remoteAddrLen) != 0)
2605 uint32 address = remoteAddr.sin_addr.s_addr;
2623 int count = SSL_pending(ssl);
2641 int pending = SSL_pending(ssl);
2661 else if (count == 0) {
2666 #ifdef TCPCON_PRINT_DEBUG
2667 char* tmp =
new char[count+1];
2670 LogPrint(0,
LOG_NETWORK,0,
"<<<<<<< SSL READINTOBUFFER <<<<<<<< TCP RECV BUF %u bytes '%s'\n", count, tmp);
2704 int count, err, timeleft;
2710 err = SSL_get_error(ssl, count);
2711 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
2719 else if (count > 0) {
2720 #ifdef TCPCON_PRINT_DEBUG
2721 char* tmp =
new char[count+1];
2724 LogPrint(0,
LOG_NETWORK,0,
"<<<<<<< RECEIVE <<<<<<<< TCP RECV AVAIL %u bytes '%s'\n", count, tmp);
2731 if ((timespent = (
GetTimeNow() - start)/1000) >= timeout) {
2738 timeleft = (int)(timeout-timespent);
2787 int count, err, timeleft;
2802 err = SSL_get_error(ssl, count);
2803 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
2811 else if (count > 0) {
2812 #ifdef TCPCON_PRINTBINARY_DEBUG
2813 char* tmp =
new char[count+1];
2823 if ((timespent =
GetTimeAgeMS(start)) >= (int32)timeout) {
2832 timeleft = (int)(timeout-timespent);
2841 inputSpeed = (uint32)(size*1000000.0/(
double)t);
2889 uint32 period = 100000;
2894 printf(
"Could not bind to port %u, exiting... \n\n", port);
2898 char* startdata =
new char[12], *data;
2904 printf(
"\n\nListening to port %u for a new connection... ", port);
2909 if (!con->
receive(startdata, 12, 10000)) {
2910 printf(
"[%u] Could not receive start data, exiting...\n", c);
2913 if ((*(uint32*)startdata) != 123456789) {
2914 printf(
"[%u] Start data wrong, exiting...\n", c);
2917 size = *(((uint32*)startdata)+1);
2918 count = *(((uint32*)startdata)+2);
2920 data =
new char[size];
2922 printf(
"Got it - starting test with size %u and count %u...\n\n", size, count);
2925 if (!con->
receive(data, size, 10000)) {
2926 printf(
"[%u] Could not receive data %u, exiting...\n", port, c);
2929 if (!con->
send(data, size)) {
2930 printf(
"[%u] Could not send data %u, exiting...\n", port, c);
2960 delete [] startdata;
2968 if (!con->
connect(address, port, location, 5000)) {
2970 printf(
"Could not connect to '%s' on port %u, exiting...\n", address, port);
2973 printf(
"Connected to '%s' on port %u, starting test...\n", address, port);
2975 char* startdata =
new char[12];
2976 memset(startdata, 0, 12);
2977 *((uint32*)startdata) = 123456789;
2979 uint32 maxSize = 1024*64, innercount = 20, count = 1000, steps = 64, s, c, step;
2980 char* data =
new char[maxSize];
2981 double* vals =
new double[count];
2982 double* avgvals =
new double[steps];
2983 double* maxvals =
new double[steps];
2984 double* minvals =
new double[steps];
2985 double* stdvals =
new double[steps];
2986 double sum, avg, mx, mn,
std;
2992 for (step=0; step<steps; step++) {
2993 s = (maxSize/steps*(step+1));
2994 *(((uint32*)startdata)+1) = s;
2995 *(((uint32*)startdata)+2) = count * innercount;
2996 if (!con->
send(startdata, 12)) {
2997 printf(
"[%u] Could not send startdata, exiting...\n", port);
3000 printf(
"Step %u size %u...\n", step, s);
3001 for (c=0; c<count; c++) {
3003 for (uint32 i=0; i<innercount; i++) {
3004 if (!con->
send(data, s)) {
3005 printf(
"[%u] Could not send data %u, exiting...\n", port, c);
3008 if (!con->
receive(data, s, 10000)) {
3009 printf(
"[%u] Could not receive data %u, exiting...\n", port, c);
3014 vals[c] = (t2-t1)/(
double)innercount;
3017 sum = avg =
std = 0;
3019 for (c=0; c<count; c++) {
3021 if (vals[c] > mx) mx = vals[c];
3022 if (vals[c] < mn) mn = vals[c];
3027 for (c=0; c<count; c++)
3028 sum += pow((vals[c] - avg), 2);
3029 std = sqrt(sum/count-1);
3031 avgvals[step] = avg;
3034 stdvals[step] =
std;
3037 printf(
"Test results (size, avg, min, max, std in us):\n");
3038 for (step=0; step<steps; step++) {
3039 s = (maxSize/steps*(step+1));
3040 printf(
"%u %u %.3f %.3f %.3f %.3f\n",
3041 step, s, avgvals[step], minvals[step], maxvals[step], stdvals[step]);
3047 delete [] startdata;
3092 uint32 expectC = c*2;
3093 if (!receiveFirst) {
3096 if (!con->
send(data, dataLen)) {
3097 printf(
"[%u] Could not send data, exiting...\n", c);
3103 memset(data, 0, dataLen);
3105 if (!con->
receive(data, dataLen, 10000)) {
3106 printf(
"[%u] Could not receive data, exiting...\n", c);
3111 if (*(uint32*)data != dataLen) {
3112 printf(
"[%u] Did not receive correct length (%u != %u), exiting...\n", c, *(uint32*)data, dataLen);
3117 if (*((uint32*)data+1) != expectC) {
3118 printf(
"[%u] Did not receive correct count (%u != %u), exiting...\n", c, *((uint32*)data+1), expectC);
3123 if (strcmp(data+(2*
sizeof(uint32)),
"Testing") != 0) {
3124 data[dataLen-1] = 0;
3125 printf(
"[%u] Did not receive correct text ('%s' != 'Testing'), exiting...\n", c, data+(2*
sizeof(uint32)));
3129 *((uint32*)data+1) = *((uint32*)data+1) + 1;
3134 if (!con->
send(data, dataLen)) {
3135 printf(
"[%u] Could not send data, exiting...\n", c);
Raw socket transport layer: TCP/UDP/SSL connections and TCP listeners with buffered,...
#define SSLCON
SSL/TLS-encrypted TCP connection.
#define AESENC
AES encryption (reserved; not currently implemented).
#define NETWORKERROR_SEND_TIMEOUT
A write could not complete within the timeout.
#define NETWORKERROR_RECEIVE
A read from the socket failed (peer closed or socket error).
#define TCPCON
Plain TCP stream connection.
#define UDPCON
UDP datagram connection.
#define NETWORKERROR_ACCEPT
accept() failed on a listener socket.
#define NOENC
Plain, unencrypted transport.
#define SSLENC
SSL/TLS encryption (requires build with _USE_SSL_).
#define NETWORKERROR_SEND_ERROR
A write to the socket failed.
#define INITIALBUFFERSIZE
Initial size in bytes of a connection's internal receive buffer; it grows on demand via NetworkConnec...
#define NETWORKERROR_MEMORYFULL
The receive buffer could not grow to hold incoming data.
#define GETIPADDRESSQUAD(a)
#define thread_ret_val(ret)
#define THREAD_FUNCTION_CALL
#define GETIPADDRESSPORT(a, p)
Abstract base class for all point-to-point network connections.
virtual bool send(const char *data, uint32 size, uint64 receiver=0)=0
Send raw bytes on the connection.
virtual uint32 getOutputSpeed()
virtual uint32 clearBuffer()
Discard all currently buffered input.
NetworkDataReceiver * receiver
virtual bool waitForDataToBeWritten(uint32 timeout)
Block until the socket is writable.
virtual uint64 getRemoteAddress()
bool setConnectTimeout(uint32 timeoutMS)
Set the timeout used by subsequent connect()/reconnect() attempts.
virtual bool receiveAvailable(char *data, uint32 &size, uint32 maxSize, uint32 timeout, bool peek=false)
Receive whatever bytes are available (up to maxSize).
virtual bool receive(char *data, uint32 size, uint32 timeout, bool peek=false)
Receive exactly size bytes into data, waiting up to timeout ms.
virtual bool disconnect(uint16 error=0)
Close the connection and release the socket.
virtual bool waitForDataToRead(uint32 timeout)
Block until data is readable (buffered or on the socket).
virtual uint8 getConnectionType()
virtual uint32 getInputSpeed()
char * greetingData
Owned copy of the greeting bytes (NULL if unset).
void disconnectInternal(uint16 error)
virtual bool resizeBuffer(uint32 len)
virtual bool discard(uint32 size)
Drop size bytes from the front of the receive buffer (after a peek).
virtual bool didConnect(int timeout=0)
Check/complete an in-progress (delayed) connect on the existing socket.
virtual bool isConnected(int timeout=0)
Test whether the connection is currently alive.
bool setGreetingData(const char *data, uint32 size)
Set greeting bytes sent automatically right after a connection is established (used e....
uint32 greetingSize
Size of greetingData in bytes.
virtual int32 readIntoBuffer()
Callback interface for asynchronous delivery of newly accepted connections.
virtual bool registerError(uint16 error, TCPListener *con)=0
Called when the listener encounters an error.
virtual bool receiveNetworkConnection(NetworkConnection *con)=0
Called when the listener has accepted a new connection.
Callback interface for asynchronous (push) delivery of received bytes.
bool isRunning
Set by the worker while its loop is active.
virtual bool stop(uint32 timeout=200)
Ask the worker loop to finish and wait for it to do so.
uint32 threadID
ThreadManager slot ID of the worker thread (0 until known).
bool shouldContinue
Loop-continuation flag; cleared by stop().
SSL/TLS-encrypted TCP connection (OpenSSL) with configurable peer verification.
static std::string DefaultCAFile
bool isConnected(int timeout=0)
Test whether the connection is currently alive.
bool receiveAvailable(char *data, uint32 &size, uint32 maxSize, uint32 timeout, bool peek=false)
Receive whatever bytes are available (up to maxSize).
bool init()
Initialise the OpenSSL context for a client-side connection.
bool findRemoteAddress(uint64 &addr)
bool didConnect(int timeout=0)
Check/complete an in-progress (delayed) connect on the existing socket.
std::string certinfo
Human-readable summary of the peer certificate (subject/issuer), filled after handshake.
void setCALocation(const char *caFile, const char *caPath)
static std::string DefaultCAPath
void setVerifyHostName(const char *host)
static bool DefaultAllowSelfSigned
friend THREAD_RET THREAD_FUNCTION_CALL SSLConnectionRun(THREAD_ARG arg)
bool disconnect(uint16 error=0)
Shut down the TLS session and close the socket.
bool receive(char *data, uint32 size, uint32 timeout, bool peek=false)
Receive exactly size bytes into data, waiting up to timeout ms.
bool send(const char *data, uint32 size, uint64 receiver=0)
Send bytes over the encrypted stream.
bool connect(SOCKET s, uint64 localAddr, NetworkDataReceiver *receiver=NULL)
Adopt an already-accepted socket and perform the server-side TLS handshake.
static bool GetDefaultAllowSelfSigned()
void setAllowSelfSigned(bool allow)
int32 peekStream()
Peek how many decrypted bytes are pending inside the SSL layer.
bool reconnect(uint32 timeoutMS)
Reconnect and re-handshake to the previous endpoint.
std::string verifyHostName
static void SetDefaultCALocation(const char *caFile, const char *caPath)
static void SetDefaultAllowSelfSigned(bool allow)
bool delayedConnect(uint64 addr, uint32 timeoutMS, NetworkDataReceiver *receiver)
Begin a non-blocking connect (TLS handshake completes in didConnect()).
int32 readIntoBuffer()
Read decrypted bytes from the SSL layer into the internal buffer.
Plain TCP stream connection (client-initiated or accepted from a listener).
friend THREAD_RET THREAD_FUNCTION_CALL TCPConnectionRun(THREAD_ARG arg)
Thread entry point for a TCPConnection's push-mode reader loop.
bool findRemoteAddress(uint64 &addr)
Query the OS for the peer address of the connected socket.
bool send(const char *data, uint32 size, uint64 receiver=0)
Send bytes on the stream (see NetworkConnection::send()).
bool connect(SOCKET s, uint64 localAddr, NetworkDataReceiver *receiver=NULL)
Adopt an already-connected socket (server side, from a TCPListener).
bool delayedConnect(uint64 addr, uint32 timeoutMS, NetworkDataReceiver *receiver)
Begin a non-blocking connect; completion is checked with didConnect().
bool reconnect(uint32 timeoutMS)
Reconnect to the previously resolved remote endpoint.
TCP server socket: binds a port and accepts inbound connections (plain or SSL).
friend THREAD_RET THREAD_FUNCTION_CALL TCPListenerRun(THREAD_ARG arg)
Thread entry point for a TCPListener's internal accept loop.
NetworkConnection * acceptConnection(uint32 timeout)
Synchronously wait for and accept one inbound connection.
bool setSSLCertificate(const char *sslCertPath, const char *sslKeyPath)
Set the SSL certificate and private key used for inbound SSL connections.
bool disconnect(uint16 error=0)
Stop listening and close the socket.
bool init(uint16 port, uint8 encryption, NetworkConnectionReceiver *receiver=NULL, NetworkDataReceiver *dataReceiver=NULL)
Bind and start listening on a port.
static bool CreateThread(THREAD_FUNCTION func, void *args, uint32 &newID, uint32 reqID=0)
Create a new native thread and start it immediately.
bool initForOutputOnly()
Create an unbound socket usable only for sending datagrams.
bool reconnect(uint32 timeoutMS)
Rebind the local port (UDP has no session to re-establish).
bool send(const char *data, uint32 size, uint64 receiver=0)
Send one datagram.
bool connect(uint16 port, NetworkDataReceiver *receiver=NULL)
Bind a local UDP port for receiving datagrams.
uint64 defaultReceiver
Default destination endpoint for send() when none is given.
friend THREAD_RET THREAD_FUNCTION_CALL UDPConnectionRun(THREAD_ARG arg)
Thread entry point for a UDPConnection's push-mode reader loop.
bool setDefaultReceiver(uint64 receiver)
Set the default destination used by send() when receiver == 0.
THREAD_RET THREAD_FUNCTION_CALL TCPListenerRun(THREAD_ARG arg)
Thread entry point for a TCPListener's internal accept loop.
bool NetworkTest_TCPClient(const char *address, uint16 port, uint32 count=0)
Loopback test client matching NetworkTest_TCPServer().
THREAD_RET THREAD_FUNCTION_CALL UDPConnectionRun(THREAD_ARG arg)
Thread entry point for a UDPConnection's push-mode reader loop.
bool NetworkTest_TCPServer(uint16 port, uint32 count=0)
Loopback test server: listens on port and echoes test payloads.
THREAD_RET THREAD_FUNCTION_CALL TCPConnectionRun(THREAD_ARG arg)
Thread entry point for a TCPConnection's push-mode reader loop.
bool NetworkTest_SendReceiveData(TCPConnection *con, char *data, uint32 dataLen, uint32 c, bool receiveFirst=false)
Send-and-verify helper used by the TCP tests.
uint64 GetTimeNow()
Return the current absolute time (µs since year 0) according to the TMC.
int32 GetTimeAgeMS(uint64 t)
Age of a timestamp relative to now, in milliseconds.
int64 GetTimeAge(uint64 t)
Age of a timestamp relative to now.
bool Sleep(uint32 ms)
Suspend the calling thread.
const char * stristr(const char *str, const char *substr, uint32 len=0)
Case-insensitive strstr.
int GetLastOSErrorNumber()
Get the last OS error number (errno / GetLastError()).
bool WaitForSocketReadability(SOCKET s, int32 timeout)
Wait until a socket has data to read.
bool WaitForSocketWriteability(SOCKET s, int32 timeout)
Wait until a socket can be written without blocking.
bool GetLocalIPAddress(uint32 &address)
Get the primary local IPv4 address.
bool LookupIPAddress(const char *name, uint32 &address)
Resolve a hostname to an IPv4 address.
bool SetSocketNonBlockingMode(SOCKET s)
Put a socket into non-blocking mode.
THREAD_RET THREAD_FUNCTION_CALL SSLConnectionRun(THREAD_ARG arg)
bool AESCheckBufferForCompatibility(const char *buffer, uint32 length)
bool SSLCheckBufferForCompatibility(const char *buffer, uint32 length)