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)
392 receiver->registerError(error,
this);
403 if (len < 128)
return false;
404 char* newBuffer =
new char[len];
447#ifdef TCPCON_PRINT_DEBUG
467 if (err != WSAENOTSOCK)
504 #ifdef TCPCON_PRINT_DEBUG
507 char* tmp =
new char[count+1];
510 LogPrint(0,
LOG_NETWORK,0,
"<<<<<<< READINTOBUFFER <<<<<<<< TCP RECV BUF %d bytes '%s' (%.3fms) %d / %d\n", count, tmp,
GetTimeAge(start)/1000.0, rounds, resize);
519 #ifdef UDPCON_PRINT_DEBUG
522 char* tmp =
new char[count+1];
525 LogPrint(0,
LOG_NETWORK,0,
"<<<<<<< READINTOBUFFER <<<<<<<< UDP RECV BUF %u bytes '%s'\n", count, tmp);
575 if (!c && dataAvailable) {
583 if ((timespent =
GetTimeAgeMS(start)) >= (int32)timeout)
644 if ((timespent =
GetTimeAgeMS(start)) >= (int32)timeout) {
659 inputSpeed = (uint32)(size*1000000.0/(
double)t);
725 if (!
mutex.enter(1000))
729 int res = recv(
socket, peekBuffer, 1, MSG_PEEK);
747 else if (err == WSAENOTCONN) {}
748 else if (err == WSAENOTSOCK) {}
749 else if (err == WSAEOPNOTSUPP) {}
788 #if GCC_VERSION < 40000
802 ldiv_t d = ldiv(timeout*1000, 1000000);
808 res = select(maxfd, NULL, &wfds, NULL, &tv);
818 if (!
mutex.enter(1000))
821 if (FD_ISSET(
socket, &wfds) != 0) {
822 if (getsockopt(
socket, SOL_SOCKET, SO_ERROR, (
char*)&error, &len) != 0) {
831 else if (wsaError == WSAENETDOWN ) {
834 else if (wsaError == WSAEFAULT ) {
837 else if (wsaError == WSAEINPROGRESS ) {
840 else if (wsaError == WSAEINVAL ) {
843 else if (wsaError == WSAENOPROTOOPT ) {
848 else if (wsaError == WSAENOTSOCK ) {
881 #if GCC_VERSION < 40000
895 ldiv_t d = ldiv(timeout * 1000, 1000000);
901 int res = select(maxfd, NULL, &wfds, NULL, &tv);
911 if (FD_ISSET(s, &wfds) != 0) {
912 if (getsockopt(s, SOL_SOCKET, SO_ERROR, (
char*)&error, &len) != 0) {
920 else if (wsaError == WSAENETDOWN) {
923 else if (wsaError == WSAEFAULT) {
926 else if (wsaError == WSAEINPROGRESS) {
929 else if (wsaError == WSAEINVAL) {
932 else if (wsaError == WSAENOPROTOOPT) {
937 else if (wsaError == WSAENOTSOCK) {
955 if (!
mutex.enter(1000))
975 #if GCC_VERSION < 40000
989 ldiv_t d = ldiv(timeout * 1000, 1000000);
995 int res = select(maxfd, NULL, &wfds, NULL, &tv);
1003 len =
sizeof(error);
1006 if (FD_ISSET(
socket, &wfds) != 0) {
1007 if (getsockopt(
socket, SOL_SOCKET, SO_ERROR, (
char*)&error, &len) != 0) {
1011 if (wsaError == 0) {
1016 else if (wsaError == WSAENETDOWN) {
1019 else if (wsaError == WSAEFAULT) {
1022 else if (wsaError == WSAEINPROGRESS) {
1025 else if (wsaError == WSAEINVAL) {
1028 else if (wsaError == WSAENOPROTOOPT) {
1033 else if (wsaError == WSAENOTSOCK) {
1055 char* myBuffer = (
char*) malloc(buflen);
1056 if (myBuffer == NULL)
1059 LogPrint(0,
LOG_NETWORK, 2,
"Incoming network connection from %u.%u.%u.%u:%u, started run...",
1064 if (
receive((
char*)&size,
sizeof(size), 50,
true)) {
1066 if (buflen < size) {
1068 myBuffer = (
char*) realloc(myBuffer, buflen);
1069 if (myBuffer == NULL) {
1077 if (!
receive(myBuffer, size, 500)) {
1085 receiver->receiveData(myBuffer, size,
this);
1138 setsockopt(
socket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (
char *) &one,
sizeof(one));
1150 setsockopt(
socket,SOL_SOCKET,SO_REUSEADDR,&one,
sizeof(one));
1153 setsockopt(
socket,SOL_SOCKET,SO_BROADCAST,(
char*)&one,
sizeof(one));
1168 memcpy(((
char*)&
localAddress)+
sizeof(uint32), &port,
sizeof(uint16));
1184 setsockopt(
socket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (
char *) &one,
sizeof(one));
1196 setsockopt(
socket,SOL_SOCKET,SO_REUSEADDR,&one,
sizeof(one));
1199 setsockopt(
socket,SOL_SOCKET,SO_BROADCAST,(
char*)&one,
sizeof(one));
1201 struct sockaddr_in addr;
1202 addr.sin_family= AF_INET;
1203 addr.sin_addr.s_addr=INADDR_ANY;
1204 addr.sin_port=htons(port);
1234 sockaddr_in recvAddr;
1235 recvAddr.sin_family = AF_INET;
1245 recvAddr.sin_port = htons(p);
1246 memcpy(&recvAddr.sin_addr.s_addr, &rec, 4);
1256 n = ::sendto(
socket, data + pos, size - pos, 0, (
SOCKADDR*)&recvAddr,
sizeof(sockaddr_in));
1291 #ifdef UDPCON_PRINT_DEBUG
1293 char* tmp =
new char[size+1];
1294 memcpy(tmp, data, size);
1300 #ifdef UDPCON_PRINTBINARY_DEBUG
1301 char* tmp =
new char[size+1];
1302 memcpy(tmp, data, size);
1307 char* tmp =
new char[1024];
1308 memcpy(tmp, data, 1023);
1364 struct linger tmp = {1, 0};
1365 setsockopt(
socket, SOL_SOCKET, SO_LINGER, (
char *)&tmp,
sizeof(tmp));
1367 setsockopt(
socket, IPPROTO_TCP, TCP_NODELAY, (
char*) &delay,
sizeof(delay));
1373 LogPrint(0,
LOG_NETWORK, 2,
"Incoming TCP connection from %u.%u.%u.%u:%u, starting run...",
1438 struct sockaddr_in saServer;
1439 saServer.sin_family = AF_INET;
1440 saServer.sin_port = htons(
GETIPPORT(addr));
1441 memcpy(&saServer.sin_addr.s_addr, &addr, 4);
1445 if ((res =
::connect(tempSocket, (
struct sockaddr*)&saServer,
sizeof(
struct sockaddr))) != 0) {
1462 struct linger tmp = {1, 0};
1463 setsockopt(tempSocket, SOL_SOCKET, SO_LINGER, (
char *)&tmp,
sizeof(tmp));
1465 setsockopt(tempSocket, IPPROTO_TCP, TCP_NODELAY, (
char*) &delay,
sizeof(delay));
1472 if (!
mutex.enter(1000)) {
1508 for (uint16 n=0; n<addressCount; n++) {
1631 #ifdef TCPCON_PRINT_DEBUG
1633 char* tmp =
new char[size+1];
1634 memcpy(tmp, data, size);
1636 LogPrint(0,
LOG_NETWORK,0,
">>>>>>> SEND >>>>>>>> TCP Sent %u bytes (%.3f) '%s'\n", size, t/1000.0, tmp);
1640 #ifdef TCPCON_PRINTBINARY_DEBUG
1641 char* tmp =
new char[size+1];
1642 memcpy(tmp, data, size);
1647 char* tmp =
new char[1024];
1648 memcpy(tmp, data, 1023);
1650 LogPrint(0,
LOG_NETWORK,0,
">>>>>>> SEND >>>>>>>> TCP Sent %u bytes (%.3f) '%s'\n", size, t / 1000.0, tmp);
1674 struct sockaddr_in remoteAddr;
1680 #if GCC_VERSION < 40000
1683 socklen_t remoteAddrLen;
1686 socklen_t remoteAddrLen;
1690 remoteAddrLen =
sizeof(
struct sockaddr_in);
1692 if (getpeername(
socket, (
struct sockaddr*) &remoteAddr, &remoteAddrLen) != 0)
1695 uint32 address = remoteAddr.sin_addr.s_addr;
1737 OpenSSL_add_all_algorithms();
1739 ERR_load_crypto_strings();
1740 SSL_load_error_strings();
1742 certbio = BIO_new(BIO_s_file());
1743 outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
1795 applyClientVerify();
1807 applyClientVerify();
1814bool SSLConnection::applyClientVerify() {
1818 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
1824 if (SSL_CTX_load_verify_locations(ctx,
1837 bool loadedOSRoots =
false;
1838 HCERTSTORE hStore = CertOpenSystemStoreA(0,
"ROOT");
1840 X509_STORE* store = SSL_CTX_get_cert_store(ctx);
1841 PCCERT_CONTEXT pWinCert = NULL;
1842 while ((pWinCert = CertEnumCertificatesInStore(hStore, pWinCert)) != NULL) {
1843 const unsigned char* enc = pWinCert->pbCertEncoded;
1844 X509* x = d2i_X509(NULL, &enc, pWinCert->cbCertEncoded);
1847 if (X509_STORE_add_cert(store, x) == 1)
1848 loadedOSRoots =
true;
1852 CertCloseStore(hStore, 0);
1859 if (SSL_CTX_set_default_verify_paths(ctx) != 1)
1863 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
1868int SSLConnection::getVerifyMode() {
1871 return SSL_CTX_get_verify_mode(ctx);
1880 const SSL_METHOD *method = SSLv23_server_method();
1882 ctx = SSL_CTX_new(method);
1885 BIO_printf(outbio,
"Unable to create a new SSL context structure.\n");
1891 if ( SSL_CTX_use_certificate_chain_file(ctx, certFile) <= 0) {
1893 LogSSLErrors(
"certificate chain file", 0);
1897 if ( SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
1899 LogSSLErrors(
"private key file", 0);
1906 if ( !SSL_CTX_check_private_key(ctx) ) {
1908 fprintf(stderr,
"Private key is invalid.\n");
1925 const SSL_METHOD *method = SSLv23_method();
1927 ctx = SSL_CTX_new(method);
1929 BIO_printf(outbio,
"Unable to create a new SSL context structure.\n");
1938 applyClientVerify();
1969 if (!
mutex.enter(200, __FUNCTION__))
1972 int res = recv(
socket, peekBuffer, 1, MSG_PEEK);
1993 else if (err == WSAENOTCONN) {}
1994 else if (err == WSAEOPNOTSUPP) {}
2037 #if GCC_VERSION < 40000
2051 ldiv_t d = ldiv(timeout*1000, 1000000);
2058 res = select(maxfd, NULL, &wfds, NULL, &tv);
2067 len =
sizeof(error);
2071 if (FD_ISSET(
socket, &wfds) != 0) {
2072 if (getsockopt(
socket, SOL_SOCKET, SO_ERROR, (
char*)&error, &len) != 0) {
2076 if (wsaError == 0) {
2081 else if (wsaError == WSAENETDOWN ) {
2084 else if (wsaError == WSAEFAULT ) {
2087 else if (wsaError == WSAEINPROGRESS ) {
2090 else if (wsaError == WSAEINVAL ) {
2093 else if (wsaError == WSAENOPROTOOPT ) {
2098 else if (wsaError == WSAENOTSOCK ) {
2135 if (!ctx || !(ssl = SSL_new(ctx)))
2149 struct linger tmp = {1, 0};
2150 setsockopt(s, SOL_SOCKET, SO_LINGER, (
char *)&tmp,
sizeof(tmp));
2152 setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (
char*) &delay,
sizeof(delay));
2157 SSL_set_fd(ssl, (
int)
socket);
2158 int ret = SSL_accept(ssl);
2163 err = SSL_get_error(ssl, ret);
2164 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
2166 if ((++errCount) > 10) {
2177 ret = SSL_accept(ssl);
2216 if (!ctx && !
init()) {
2219 if (!ctx || !(ssl = SSL_new(ctx))) {
2220 LogSSLErrors(
"SSL_new", 0);
2258 struct sockaddr_in saServer;
2259 saServer.sin_family = AF_INET;
2260 saServer.sin_port = htons(
GETIPPORT(addr));
2261 memcpy(&saServer.sin_addr.s_addr, &addr, 4);
2266 if ((res =
::connect(
socket, (
struct sockaddr*)&saServer,
sizeof(
struct sockaddr))) != 0) {
2287 struct linger tmp = {1, 0};
2288 setsockopt(
socket, SOL_SOCKET, SO_LINGER, (
char *)&tmp,
sizeof(tmp));
2290 setsockopt(
socket, IPPROTO_TCP, TCP_NODELAY, (
char*) &delay,
sizeof(delay));
2293 if (!SSL_set_fd (ssl, (
int)
socket)) {
2294 LogSSLErrors(
"SSL_set_fd", 0);
2303 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
2310 while ( (ret = SSL_connect(ssl)) != 1) {
2311 switch (SSL_get_error(ssl, ret)) {
2312 case SSL_ERROR_WANT_READ:
2315 case SSL_ERROR_WANT_WRITE:
2323 LogSSLErrors(
"handshake failed", 1);
2342 uint32 certnamemax = 1000;
2346 cert = SSL_get_peer_certificate(ssl);
2348 certname =
new char[certnamemax+1];
2349 certinfo = X509_NAME_oneline(X509_get_subject_name(cert), certname, certnamemax);
2384 if (
verifyHostName.empty() && addr && (inet_addr(addr) == INADDR_NONE))
2395 for (uint16 n=0; n<addressCount; n++) {
2438 if (
verifyHostName.empty() && addr && (inet_addr(addr) == INADDR_NONE))
2461 while ( (ret = SSL_write(ssl, data, size)) <= 0) {
2462 switch (SSL_get_error(ssl, ret)) {
2463 case SSL_ERROR_WANT_READ:
2466 case SSL_ERROR_WANT_WRITE:
2476 if (ret < (
int)size) {
2490 #ifdef TCPCON_PRINT_DEBUG
2492 char* tmp =
new char[size+1];
2493 memcpy(tmp, data, size);
2499 #ifdef TCPCON_PRINTBINARY_DEBUG
2500 char* tmp =
new char[size+1];
2501 memcpy(tmp, data, size);
2531 struct sockaddr_in remoteAddr;
2537 #if GCC_VERSION < 40000
2540 socklen_t remoteAddrLen;
2543 socklen_t remoteAddrLen;
2547 remoteAddrLen =
sizeof(
struct sockaddr_in);
2549 if (getpeername(
socket, (
struct sockaddr*) &remoteAddr, &remoteAddrLen) != 0)
2552 uint32 address = remoteAddr.sin_addr.s_addr;
2570 int count = SSL_pending(ssl);
2588 int pending = SSL_pending(ssl);
2608 else if (count == 0) {
2613 #ifdef TCPCON_PRINT_DEBUG
2614 char* tmp =
new char[count+1];
2617 LogPrint(0,
LOG_NETWORK,0,
"<<<<<<< SSL READINTOBUFFER <<<<<<<< TCP RECV BUF %u bytes '%s'\n", count, tmp);
2651 int count, err, timeleft;
2657 err = SSL_get_error(ssl, count);
2658 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
2666 else if (count > 0) {
2667 #ifdef TCPCON_PRINT_DEBUG
2668 char* tmp =
new char[count+1];
2671 LogPrint(0,
LOG_NETWORK,0,
"<<<<<<< RECEIVE <<<<<<<< TCP RECV AVAIL %u bytes '%s'\n", count, tmp);
2678 if ((timespent = (
GetTimeNow() - start)/1000) >= timeout) {
2685 timeleft = (int)(timeout-timespent);
2734 int count, err, timeleft;
2749 err = SSL_get_error(ssl, count);
2750 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
2758 else if (count > 0) {
2759 #ifdef TCPCON_PRINTBINARY_DEBUG
2760 char* tmp =
new char[count+1];
2770 if ((timespent =
GetTimeAgeMS(start)) >= (int32)timeout) {
2779 timeleft = (int)(timeout-timespent);
2788 inputSpeed = (uint32)(size*1000000.0/(
double)t);
2836 uint32 period = 100000;
2841 printf(
"Could not bind to port %u, exiting... \n\n", port);
2845 char* startdata =
new char[12], *data;
2851 printf(
"\n\nListening to port %u for a new connection... ", port);
2856 if (!con->
receive(startdata, 12, 10000)) {
2857 printf(
"[%u] Could not receive start data, exiting...\n", c);
2860 if ((*(uint32*)startdata) != 123456789) {
2861 printf(
"[%u] Start data wrong, exiting...\n", c);
2864 size = *(((uint32*)startdata)+1);
2865 count = *(((uint32*)startdata)+2);
2867 data =
new char[size];
2869 printf(
"Got it - starting test with size %u and count %u...\n\n", size, count);
2872 if (!con->
receive(data, size, 10000)) {
2873 printf(
"[%u] Could not receive data %u, exiting...\n", port, c);
2876 if (!con->
send(data, size)) {
2877 printf(
"[%u] Could not send data %u, exiting...\n", port, c);
2907 delete [] startdata;
2915 if (!con->
connect(address, port, location, 5000)) {
2917 printf(
"Could not connect to '%s' on port %u, exiting...\n", address, port);
2920 printf(
"Connected to '%s' on port %u, starting test...\n", address, port);
2922 char* startdata =
new char[12];
2923 memset(startdata, 0, 12);
2924 *((uint32*)startdata) = 123456789;
2926 uint32 maxSize = 1024*64, innercount = 20, count = 1000, steps = 64, s, c, step;
2927 char* data =
new char[maxSize];
2928 double* vals =
new double[count];
2929 double* avgvals =
new double[steps];
2930 double* maxvals =
new double[steps];
2931 double* minvals =
new double[steps];
2932 double* stdvals =
new double[steps];
2933 double sum, avg, mx, mn,
std;
2939 for (step=0; step<steps; step++) {
2940 s = (maxSize/steps*(step+1));
2941 *(((uint32*)startdata)+1) = s;
2942 *(((uint32*)startdata)+2) = count * innercount;
2943 if (!con->
send(startdata, 12)) {
2944 printf(
"[%u] Could not send startdata, exiting...\n", port);
2947 printf(
"Step %u size %u...\n", step, s);
2948 for (c=0; c<count; c++) {
2950 for (uint32 i=0; i<innercount; i++) {
2951 if (!con->
send(data, s)) {
2952 printf(
"[%u] Could not send data %u, exiting...\n", port, c);
2955 if (!con->
receive(data, s, 10000)) {
2956 printf(
"[%u] Could not receive data %u, exiting...\n", port, c);
2961 vals[c] = (t2-t1)/(
double)innercount;
2964 sum = avg =
std = 0;
2966 for (c=0; c<count; c++) {
2968 if (vals[c] > mx) mx = vals[c];
2969 if (vals[c] < mn) mn = vals[c];
2974 for (c=0; c<count; c++)
2975 sum += pow((vals[c] - avg), 2);
2976 std = sqrt(sum/count-1);
2978 avgvals[step] = avg;
2981 stdvals[step] =
std;
2984 printf(
"Test results (size, avg, min, max, std in us):\n");
2985 for (step=0; step<steps; step++) {
2986 s = (maxSize/steps*(step+1));
2987 printf(
"%u %u %.3f %.3f %.3f %.3f\n",
2988 step, s, avgvals[step], minvals[step], maxvals[step], stdvals[step]);
2994 delete [] startdata;
3039 uint32 expectC = c*2;
3040 if (!receiveFirst) {
3043 if (!con->
send(data, dataLen)) {
3044 printf(
"[%u] Could not send data, exiting...\n", c);
3050 memset(data, 0, dataLen);
3052 if (!con->
receive(data, dataLen, 10000)) {
3053 printf(
"[%u] Could not receive data, exiting...\n", c);
3058 if (*(uint32*)data != dataLen) {
3059 printf(
"[%u] Did not receive correct length (%u != %u), exiting...\n", c, *(uint32*)data, dataLen);
3064 if (*((uint32*)data+1) != expectC) {
3065 printf(
"[%u] Did not receive correct count (%u != %u), exiting...\n", c, *((uint32*)data+1), expectC);
3070 if (strcmp(data+(2*
sizeof(uint32)),
"Testing") != 0) {
3071 data[dataLen-1] = 0;
3072 printf(
"[%u] Did not receive correct text ('%s' != 'Testing'), exiting...\n", c, data+(2*
sizeof(uint32)));
3076 *((uint32*)data+1) = *((uint32*)data+1) + 1;
3081 if (!con->
send(data, dataLen)) {
3082 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)