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
478 if (err != WSAENOTSOCK)
515 #ifdef TCPCON_PRINT_DEBUG
518 char* tmp =
new char[count+1];
521 LogPrint(0,
LOG_NETWORK,0,
"<<<<<<< READINTOBUFFER <<<<<<<< TCP RECV BUF %d bytes '%s' (%.3fms) %d / %d\n", count, tmp,
GetTimeAge(start)/1000.0, rounds, resize);
530 #ifdef UDPCON_PRINT_DEBUG
533 char* tmp =
new char[count+1];
536 LogPrint(0,
LOG_NETWORK,0,
"<<<<<<< READINTOBUFFER <<<<<<<< UDP RECV BUF %u bytes '%s'\n", count, tmp);
586 if (!c && dataAvailable) {
594 if ((timespent =
GetTimeAgeMS(start)) >= (int32)timeout)
655 if ((timespent =
GetTimeAgeMS(start)) >= (int32)timeout) {
670 inputSpeed = (uint32)(size*1000000.0/(
double)t);
736 if (!
mutex.enter(1000))
740 int res = recv(
socket, peekBuffer, 1, MSG_PEEK);
758 else if (err == WSAENOTCONN) {}
759 else if (err == WSAENOTSOCK) {}
760 else if (err == WSAEOPNOTSUPP) {}
799 #if GCC_VERSION < 40000
813 ldiv_t d = ldiv(timeout*1000, 1000000);
819 res = select(maxfd, NULL, &wfds, NULL, &tv);
829 if (!
mutex.enter(1000))
832 if (FD_ISSET(
socket, &wfds) != 0) {
833 if (getsockopt(
socket, SOL_SOCKET, SO_ERROR, (
char*)&error, &len) != 0) {
842 else if (wsaError == WSAENETDOWN ) {
845 else if (wsaError == WSAEFAULT ) {
848 else if (wsaError == WSAEINPROGRESS ) {
851 else if (wsaError == WSAEINVAL ) {
854 else if (wsaError == WSAENOPROTOOPT ) {
859 else if (wsaError == WSAENOTSOCK ) {
892 #if GCC_VERSION < 40000
906 ldiv_t d = ldiv(timeout * 1000, 1000000);
912 int res = select(maxfd, NULL, &wfds, NULL, &tv);
922 if (FD_ISSET(s, &wfds) != 0) {
923 if (getsockopt(s, SOL_SOCKET, SO_ERROR, (
char*)&error, &len) != 0) {
931 else if (wsaError == WSAENETDOWN) {
934 else if (wsaError == WSAEFAULT) {
937 else if (wsaError == WSAEINPROGRESS) {
940 else if (wsaError == WSAEINVAL) {
943 else if (wsaError == WSAENOPROTOOPT) {
948 else if (wsaError == WSAENOTSOCK) {
966 if (!
mutex.enter(1000))
986 #if GCC_VERSION < 40000
1000 ldiv_t d = ldiv(timeout * 1000, 1000000);
1006 int res = select(maxfd, NULL, &wfds, NULL, &tv);
1014 len =
sizeof(error);
1017 if (FD_ISSET(
socket, &wfds) != 0) {
1018 if (getsockopt(
socket, SOL_SOCKET, SO_ERROR, (
char*)&error, &len) != 0) {
1022 if (wsaError == 0) {
1027 else if (wsaError == WSAENETDOWN) {
1030 else if (wsaError == WSAEFAULT) {
1033 else if (wsaError == WSAEINPROGRESS) {
1036 else if (wsaError == WSAEINVAL) {
1039 else if (wsaError == WSAENOPROTOOPT) {
1044 else if (wsaError == WSAENOTSOCK) {
1066 char* myBuffer = (
char*) malloc(buflen);
1067 if (myBuffer == NULL)
1070 LogPrint(0,
LOG_NETWORK, 2,
"Incoming network connection from %u.%u.%u.%u:%u, started run...",
1075 if (
receive((
char*)&size,
sizeof(size), 50,
true)) {
1077 if (buflen < size) {
1079 myBuffer = (
char*) realloc(myBuffer, buflen);
1080 if (myBuffer == NULL) {
1088 if (!
receive(myBuffer, size, 500)) {
1096 receiver->receiveData(myBuffer, size,
this);
1149 setsockopt(
socket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (
char *) &one,
sizeof(one));
1161 setsockopt(
socket,SOL_SOCKET,SO_REUSEADDR,&one,
sizeof(one));
1164 setsockopt(
socket,SOL_SOCKET,SO_BROADCAST,(
char*)&one,
sizeof(one));
1179 memcpy(((
char*)&
localAddress)+
sizeof(uint32), &port,
sizeof(uint16));
1195 setsockopt(
socket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (
char *) &one,
sizeof(one));
1207 setsockopt(
socket,SOL_SOCKET,SO_REUSEADDR,&one,
sizeof(one));
1210 setsockopt(
socket,SOL_SOCKET,SO_BROADCAST,(
char*)&one,
sizeof(one));
1212 struct sockaddr_in addr;
1213 addr.sin_family= AF_INET;
1214 addr.sin_addr.s_addr=INADDR_ANY;
1215 addr.sin_port=htons(port);
1245 sockaddr_in recvAddr;
1246 recvAddr.sin_family = AF_INET;
1256 recvAddr.sin_port = htons(p);
1257 memcpy(&recvAddr.sin_addr.s_addr, &rec, 4);
1267 n = ::sendto(
socket, data + pos, size - pos, 0, (
SOCKADDR*)&recvAddr,
sizeof(sockaddr_in));
1302 #ifdef UDPCON_PRINT_DEBUG
1304 char* tmp =
new char[size+1];
1305 memcpy(tmp, data, size);
1311 #ifdef UDPCON_PRINTBINARY_DEBUG
1312 char* tmp =
new char[size+1];
1313 memcpy(tmp, data, size);
1318 char* tmp =
new char[1024];
1319 memcpy(tmp, data, 1023);
1375 struct linger tmp = {1, 0};
1376 setsockopt(
socket, SOL_SOCKET, SO_LINGER, (
char *)&tmp,
sizeof(tmp));
1378 setsockopt(
socket, IPPROTO_TCP, TCP_NODELAY, (
char*) &delay,
sizeof(delay));
1384 LogPrint(0,
LOG_NETWORK, 2,
"Incoming TCP connection from %u.%u.%u.%u:%u, starting run...",
1449 struct sockaddr_in saServer;
1450 saServer.sin_family = AF_INET;
1451 saServer.sin_port = htons(
GETIPPORT(addr));
1452 memcpy(&saServer.sin_addr.s_addr, &addr, 4);
1456 if ((res =
::connect(tempSocket, (
struct sockaddr*)&saServer,
sizeof(
struct sockaddr))) != 0) {
1473 struct linger tmp = {1, 0};
1474 setsockopt(tempSocket, SOL_SOCKET, SO_LINGER, (
char *)&tmp,
sizeof(tmp));
1476 setsockopt(tempSocket, IPPROTO_TCP, TCP_NODELAY, (
char*) &delay,
sizeof(delay));
1483 if (!
mutex.enter(1000)) {
1519 for (uint16 n=0; n<addressCount; n++) {
1642 #ifdef TCPCON_PRINT_DEBUG
1644 char* tmp =
new char[size+1];
1645 memcpy(tmp, data, size);
1647 LogPrint(0,
LOG_NETWORK,0,
">>>>>>> SEND >>>>>>>> TCP Sent %u bytes (%.3f) '%s'\n", size, t/1000.0, tmp);
1651 #ifdef TCPCON_PRINTBINARY_DEBUG
1652 char* tmp =
new char[size+1];
1653 memcpy(tmp, data, size);
1658 char* tmp =
new char[1024];
1659 memcpy(tmp, data, 1023);
1661 LogPrint(0,
LOG_NETWORK,0,
">>>>>>> SEND >>>>>>>> TCP Sent %u bytes (%.3f) '%s'\n", size, t / 1000.0, tmp);
1685 struct sockaddr_in remoteAddr;
1691 #if GCC_VERSION < 40000
1694 socklen_t remoteAddrLen;
1697 socklen_t remoteAddrLen;
1701 remoteAddrLen =
sizeof(
struct sockaddr_in);
1703 if (getpeername(
socket, (
struct sockaddr*) &remoteAddr, &remoteAddrLen) != 0)
1706 uint32 address = remoteAddr.sin_addr.s_addr;
1748 OpenSSL_add_all_algorithms();
1750 ERR_load_crypto_strings();
1751 SSL_load_error_strings();
1753 certbio = BIO_new(BIO_s_file());
1754 outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
1806 applyClientVerify();
1818 applyClientVerify();
1825bool SSLConnection::applyClientVerify() {
1829 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
1835 if (SSL_CTX_load_verify_locations(ctx,
1848 bool loadedOSRoots =
false;
1849 HCERTSTORE hStore = CertOpenSystemStoreA(0,
"ROOT");
1851 X509_STORE* store = SSL_CTX_get_cert_store(ctx);
1852 PCCERT_CONTEXT pWinCert = NULL;
1853 while ((pWinCert = CertEnumCertificatesInStore(hStore, pWinCert)) != NULL) {
1854 const unsigned char* enc = pWinCert->pbCertEncoded;
1855 X509* x = d2i_X509(NULL, &enc, pWinCert->cbCertEncoded);
1858 if (X509_STORE_add_cert(store, x) == 1)
1859 loadedOSRoots =
true;
1863 CertCloseStore(hStore, 0);
1870 if (SSL_CTX_set_default_verify_paths(ctx) != 1)
1874 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
1879int SSLConnection::getVerifyMode() {
1882 return SSL_CTX_get_verify_mode(ctx);
1891 const SSL_METHOD *method = SSLv23_server_method();
1893 ctx = SSL_CTX_new(method);
1896 BIO_printf(outbio,
"Unable to create a new SSL context structure.\n");
1902 if ( SSL_CTX_use_certificate_chain_file(ctx, certFile) <= 0) {
1904 LogSSLErrors(
"certificate chain file", 0);
1908 if ( SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
1910 LogSSLErrors(
"private key file", 0);
1917 if ( !SSL_CTX_check_private_key(ctx) ) {
1919 fprintf(stderr,
"Private key is invalid.\n");
1936 const SSL_METHOD *method = SSLv23_method();
1938 ctx = SSL_CTX_new(method);
1940 BIO_printf(outbio,
"Unable to create a new SSL context structure.\n");
1949 applyClientVerify();
1980 if (!
mutex.enter(200, __FUNCTION__))
1983 int res = recv(
socket, peekBuffer, 1, MSG_PEEK);
2004 else if (err == WSAENOTCONN) {}
2005 else if (err == WSAEOPNOTSUPP) {}
2048 #if GCC_VERSION < 40000
2062 ldiv_t d = ldiv(timeout*1000, 1000000);
2069 res = select(maxfd, NULL, &wfds, NULL, &tv);
2078 len =
sizeof(error);
2082 if (FD_ISSET(
socket, &wfds) != 0) {
2083 if (getsockopt(
socket, SOL_SOCKET, SO_ERROR, (
char*)&error, &len) != 0) {
2087 if (wsaError == 0) {
2092 else if (wsaError == WSAENETDOWN ) {
2095 else if (wsaError == WSAEFAULT ) {
2098 else if (wsaError == WSAEINPROGRESS ) {
2101 else if (wsaError == WSAEINVAL ) {
2104 else if (wsaError == WSAENOPROTOOPT ) {
2109 else if (wsaError == WSAENOTSOCK ) {
2146 if (!ctx || !(ssl = SSL_new(ctx)))
2160 struct linger tmp = {1, 0};
2161 setsockopt(s, SOL_SOCKET, SO_LINGER, (
char *)&tmp,
sizeof(tmp));
2163 setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (
char*) &delay,
sizeof(delay));
2168 SSL_set_fd(ssl, (
int)
socket);
2169 int ret = SSL_accept(ssl);
2174 err = SSL_get_error(ssl, ret);
2175 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
2177 if ((++errCount) > 10) {
2188 ret = SSL_accept(ssl);
2227 if (!ctx && !
init()) {
2230 if (!ctx || !(ssl = SSL_new(ctx))) {
2231 LogSSLErrors(
"SSL_new", 0);
2269 struct sockaddr_in saServer;
2270 saServer.sin_family = AF_INET;
2271 saServer.sin_port = htons(
GETIPPORT(addr));
2272 memcpy(&saServer.sin_addr.s_addr, &addr, 4);
2277 if ((res =
::connect(
socket, (
struct sockaddr*)&saServer,
sizeof(
struct sockaddr))) != 0) {
2298 struct linger tmp = {1, 0};
2299 setsockopt(
socket, SOL_SOCKET, SO_LINGER, (
char *)&tmp,
sizeof(tmp));
2301 setsockopt(
socket, IPPROTO_TCP, TCP_NODELAY, (
char*) &delay,
sizeof(delay));
2304 if (!SSL_set_fd (ssl, (
int)
socket)) {
2305 LogSSLErrors(
"SSL_set_fd", 0);
2314 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
2321 while ( (ret = SSL_connect(ssl)) != 1) {
2322 switch (SSL_get_error(ssl, ret)) {
2323 case SSL_ERROR_WANT_READ:
2326 case SSL_ERROR_WANT_WRITE:
2334 LogSSLErrors(
"handshake failed", 1);
2353 uint32 certnamemax = 1000;
2357 cert = SSL_get_peer_certificate(ssl);
2359 certname =
new char[certnamemax+1];
2360 certinfo = X509_NAME_oneline(X509_get_subject_name(cert), certname, certnamemax);
2395 if (
verifyHostName.empty() && addr && (inet_addr(addr) == INADDR_NONE))
2406 for (uint16 n=0; n<addressCount; n++) {
2449 if (
verifyHostName.empty() && addr && (inet_addr(addr) == INADDR_NONE))
2472 while ( (ret = SSL_write(ssl, data, size)) <= 0) {
2473 switch (SSL_get_error(ssl, ret)) {
2474 case SSL_ERROR_WANT_READ:
2477 case SSL_ERROR_WANT_WRITE:
2487 if (ret < (
int)size) {
2501 #ifdef TCPCON_PRINT_DEBUG
2503 char* tmp =
new char[size+1];
2504 memcpy(tmp, data, size);
2510 #ifdef TCPCON_PRINTBINARY_DEBUG
2511 char* tmp =
new char[size+1];
2512 memcpy(tmp, data, size);
2542 struct sockaddr_in remoteAddr;
2548 #if GCC_VERSION < 40000
2551 socklen_t remoteAddrLen;
2554 socklen_t remoteAddrLen;
2558 remoteAddrLen =
sizeof(
struct sockaddr_in);
2560 if (getpeername(
socket, (
struct sockaddr*) &remoteAddr, &remoteAddrLen) != 0)
2563 uint32 address = remoteAddr.sin_addr.s_addr;
2581 int count = SSL_pending(ssl);
2599 int pending = SSL_pending(ssl);
2619 else if (count == 0) {
2624 #ifdef TCPCON_PRINT_DEBUG
2625 char* tmp =
new char[count+1];
2628 LogPrint(0,
LOG_NETWORK,0,
"<<<<<<< SSL READINTOBUFFER <<<<<<<< TCP RECV BUF %u bytes '%s'\n", count, tmp);
2662 int count, err, timeleft;
2668 err = SSL_get_error(ssl, count);
2669 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
2677 else if (count > 0) {
2678 #ifdef TCPCON_PRINT_DEBUG
2679 char* tmp =
new char[count+1];
2682 LogPrint(0,
LOG_NETWORK,0,
"<<<<<<< RECEIVE <<<<<<<< TCP RECV AVAIL %u bytes '%s'\n", count, tmp);
2689 if ((timespent = (
GetTimeNow() - start)/1000) >= timeout) {
2696 timeleft = (int)(timeout-timespent);
2745 int count, err, timeleft;
2760 err = SSL_get_error(ssl, count);
2761 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
2769 else if (count > 0) {
2770 #ifdef TCPCON_PRINTBINARY_DEBUG
2771 char* tmp =
new char[count+1];
2781 if ((timespent =
GetTimeAgeMS(start)) >= (int32)timeout) {
2790 timeleft = (int)(timeout-timespent);
2799 inputSpeed = (uint32)(size*1000000.0/(
double)t);
2847 uint32 period = 100000;
2852 printf(
"Could not bind to port %u, exiting... \n\n", port);
2856 char* startdata =
new char[12], *data;
2862 printf(
"\n\nListening to port %u for a new connection... ", port);
2867 if (!con->
receive(startdata, 12, 10000)) {
2868 printf(
"[%u] Could not receive start data, exiting...\n", c);
2871 if ((*(uint32*)startdata) != 123456789) {
2872 printf(
"[%u] Start data wrong, exiting...\n", c);
2875 size = *(((uint32*)startdata)+1);
2876 count = *(((uint32*)startdata)+2);
2878 data =
new char[size];
2880 printf(
"Got it - starting test with size %u and count %u...\n\n", size, count);
2883 if (!con->
receive(data, size, 10000)) {
2884 printf(
"[%u] Could not receive data %u, exiting...\n", port, c);
2887 if (!con->
send(data, size)) {
2888 printf(
"[%u] Could not send data %u, exiting...\n", port, c);
2918 delete [] startdata;
2926 if (!con->
connect(address, port, location, 5000)) {
2928 printf(
"Could not connect to '%s' on port %u, exiting...\n", address, port);
2931 printf(
"Connected to '%s' on port %u, starting test...\n", address, port);
2933 char* startdata =
new char[12];
2934 memset(startdata, 0, 12);
2935 *((uint32*)startdata) = 123456789;
2937 uint32 maxSize = 1024*64, innercount = 20, count = 1000, steps = 64, s, c, step;
2938 char* data =
new char[maxSize];
2939 double* vals =
new double[count];
2940 double* avgvals =
new double[steps];
2941 double* maxvals =
new double[steps];
2942 double* minvals =
new double[steps];
2943 double* stdvals =
new double[steps];
2944 double sum, avg, mx, mn,
std;
2950 for (step=0; step<steps; step++) {
2951 s = (maxSize/steps*(step+1));
2952 *(((uint32*)startdata)+1) = s;
2953 *(((uint32*)startdata)+2) = count * innercount;
2954 if (!con->
send(startdata, 12)) {
2955 printf(
"[%u] Could not send startdata, exiting...\n", port);
2958 printf(
"Step %u size %u...\n", step, s);
2959 for (c=0; c<count; c++) {
2961 for (uint32 i=0; i<innercount; i++) {
2962 if (!con->
send(data, s)) {
2963 printf(
"[%u] Could not send data %u, exiting...\n", port, c);
2966 if (!con->
receive(data, s, 10000)) {
2967 printf(
"[%u] Could not receive data %u, exiting...\n", port, c);
2972 vals[c] = (t2-t1)/(
double)innercount;
2975 sum = avg =
std = 0;
2977 for (c=0; c<count; c++) {
2979 if (vals[c] > mx) mx = vals[c];
2980 if (vals[c] < mn) mn = vals[c];
2985 for (c=0; c<count; c++)
2986 sum += pow((vals[c] - avg), 2);
2987 std = sqrt(sum/count-1);
2989 avgvals[step] = avg;
2992 stdvals[step] =
std;
2995 printf(
"Test results (size, avg, min, max, std in us):\n");
2996 for (step=0; step<steps; step++) {
2997 s = (maxSize/steps*(step+1));
2998 printf(
"%u %u %.3f %.3f %.3f %.3f\n",
2999 step, s, avgvals[step], minvals[step], maxvals[step], stdvals[step]);
3005 delete [] startdata;
3050 uint32 expectC = c*2;
3051 if (!receiveFirst) {
3054 if (!con->
send(data, dataLen)) {
3055 printf(
"[%u] Could not send data, exiting...\n", c);
3061 memset(data, 0, dataLen);
3063 if (!con->
receive(data, dataLen, 10000)) {
3064 printf(
"[%u] Could not receive data, exiting...\n", c);
3069 if (*(uint32*)data != dataLen) {
3070 printf(
"[%u] Did not receive correct length (%u != %u), exiting...\n", c, *(uint32*)data, dataLen);
3075 if (*((uint32*)data+1) != expectC) {
3076 printf(
"[%u] Did not receive correct count (%u != %u), exiting...\n", c, *((uint32*)data+1), expectC);
3081 if (strcmp(data+(2*
sizeof(uint32)),
"Testing") != 0) {
3082 data[dataLen-1] = 0;
3083 printf(
"[%u] Did not receive correct text ('%s' != 'Testing'), exiting...\n", c, data+(2*
sizeof(uint32)));
3087 *((uint32*)data+1) = *((uint32*)data+1) + 1;
3092 if (!con->
send(data, dataLen)) {
3093 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)