void ChanSwitchUnixCreate(unsigned short const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Create a POSIX-socket-based channel switch. Use an IP socket. Set the socket's local address so that a subsequent "listen" will listen on all IP addresses, port number 'portNumber'. -----------------------------------------------------------------------------*/ int rc; rc = socket(AF_INET, SOCK_STREAM, 0); if (rc < 0) xmlrpc_asprintf(errorP, "socket() failed with errno %d (%s)", errno, strerror(errno)); else { int const socketFd = rc; setSocketOptions(socketFd, errorP); if (!*errorP) { bindSocketToPort(socketFd, NULL, portNumber, errorP); if (!*errorP) { bool const userSupplied = false; createChanSwitch(socketFd, userSupplied, chanSwitchPP, errorP); } } if (*errorP) close(socketFd); } }
/* Establish a listening socket for incomming connections */ static SOCKET socketListen(short port, int32 *err) { struct sockaddr_in addr; SOCKET fd; if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { _psTrace("Error creating listen socket\n"); *err = SOCKET_ERRNO; return INVALID_SOCKET; } setSocketOptions(fd); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { _psTrace("Can't bind socket. Port in use or insufficient privilege\n"); *err = SOCKET_ERRNO; return INVALID_SOCKET; } if (listen(fd, SOMAXCONN) < 0) { _psTrace("Error listening on socket\n"); *err = SOCKET_ERRNO; return INVALID_SOCKET; } _psTraceInt("Listening on port %d\n", port); return fd; }
static SOCKET newUdpSocket(char *ip, short port, int *err) { struct sockaddr_in addr; SOCKET fd; if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { _psTraceInt("Error creating socket %d\n", SOCKET_ERRNO); *err = SOCKET_ERRNO; return INVALID_SOCKET; } setSocketOptions(fd); addr.sin_family = AF_INET; addr.sin_port = htons(port); if (ip == NULL) { addr.sin_addr.s_addr = INADDR_ANY; if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { _psTrace("Can't bind socket. Port in use or permission problem\n"); *err = SOCKET_ERRNO; return INVALID_SOCKET; } } return fd; }
void ChanSwitchUnixCreate2(int const protocolFamily, const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { int rc; rc = socket(protocolFamily, SOCK_STREAM, 0); if (rc < 0) xmlrpc_asprintf(errorP, "socket() failed with errno %d (%s)", errno, strerror(errno)); else { int const socketFd = rc; if (SwitchTraceIsActive) fprintf(stderr, "Created socket for protocol family %d\n", protocolFamily); setSocketOptions(socketFd, errorP); if (!*errorP) { bindSocketToPort(socketFd, sockAddrP, sockAddrLen, errorP); if (!*errorP) { bool const userSupplied = false; createChanSwitch(socketFd, userSupplied, chanSwitchPP, errorP); } } if (*errorP) close(socketFd); } }
static void switchCreateIpV6Port(unsigned short const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Same as switchCreateIpV4Port(), except for IPv6. -----------------------------------------------------------------------------*/ int rc; rc = socket(PF_INET6, SOCK_STREAM, 0); if (rc < 0) xmlrpc_asprintf(errorP, "socket() failed with errno %d (%s)", errno, strerror(errno)); else { int const socketFd = rc; setSocketOptions(socketFd, errorP); if (!*errorP) { bindSocketToPortInet6(socketFd, portNumber, errorP); if (!*errorP) { bool const userSupplied = false; createChanSwitch(socketFd, userSupplied, chanSwitchPP, errorP); } } if (*errorP) close(socketFd); } }
bool TCP_Transporter::connect_common(NDB_SOCKET_TYPE sockfd) { theSocket = sockfd; setSocketOptions(); setSocketNonBlocking(theSocket); DBUG_PRINT("info", ("Successfully set-up TCP transporter to node %d", remoteNodeId)); return true; }
int MulticastProvider::callServer() { if (createSocket()) { if (tryToBind()) { if (setSocketOptions()) { if (addToGroup()) { return socketDescriptor; } } } } return -1; }
bool TCP_Transporter::connect_common(NDB_SOCKET_TYPE sockfd) { setSocketOptions(sockfd); setSocketNonBlocking(sockfd); get_callback_obj()->lock_transporter(remoteNodeId); theSocket = sockfd; get_callback_obj()->unlock_transporter(remoteNodeId); DBUG_PRINT("info", ("Successfully set-up TCP transporter to node %d", remoteNodeId)); return true; }
hbm::communication::SocketNonblocking::SocketNonblocking(int fd, sys::EventLoop &eventLoop) : m_fd(fd) , m_bufferedReader() , m_eventLoop(eventLoop) , m_dataHandler() { if (fcntl(m_fd, F_SETFL, O_NONBLOCK)==-1) { throw std::runtime_error("error setting socket to non-blocking"); } if (setSocketOptions()<0) { throw std::runtime_error("error setting socket options"); } }
hbm::communication::SocketNonblocking::SocketNonblocking(int fd, sys::EventLoop &eventLoop) : m_fd(fd) , m_bufferedReader() , m_eventLoop(eventLoop) , m_dataHandler() { WSADATA wsaData; WSAStartup(2, &wsaData); m_event = WSACreateEvent(); if (setSocketOptions()<0) { throw std::runtime_error("error setting socket options"); } }
void ChanSwitchWinCreate(uint16_t const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Create a Winsock-based channel switch. Set the socket's local address so that a subsequent "listen" will listen on all IP addresses, port number 'portNumber'. -----------------------------------------------------------------------------*/ struct socketWin * socketWinP; MALLOCVAR(socketWinP); if (!socketWinP) xmlrpc_asprintf(errorP, "Unable to allocate memory for Windows socket " "descriptor structure."); else { SOCKET winsock; winsock = socket(AF_INET, SOCK_STREAM, 0); if (winsock == 0 || winsock == INVALID_SOCKET) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "socket() failed with WSAERROR %d (%s)", lastError, getWSAError(lastError)); } else { socketWinP->winsock = winsock; socketWinP->userSuppliedWinsock = FALSE; socketWinP->interruptEvent = CreateEvent(NULL, FALSE, FALSE, NULL); setSocketOptions(socketWinP->winsock, errorP); if (!*errorP) { bindSocketToPort(socketWinP->winsock, NULL, portNumber, errorP); if (!*errorP) ChanSwitchCreate(&chanSwitchVtbl, socketWinP, chanSwitchPP); } if (*errorP) { CloseHandle(socketWinP->interruptEvent); closesocket(winsock); } } if (*errorP) free(socketWinP); } }
void ChanSwitchWinCreate2(int const protocolFamily, const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { struct socketWin * socketWinP; MALLOCVAR(socketWinP); if (!socketWinP) xmlrpc_asprintf(errorP, "Unable to allocate memory for Windows socket " "descriptor structure."); else { SOCKET winsock; winsock = socket(protocolFamily, SOCK_STREAM, 0); if (winsock == 0 || winsock == INVALID_SOCKET) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "socket() failed with WSAERROR %d (%s)", lastError, getWSAError(lastError)); } else { socketWinP->winsock = winsock; socketWinP->userSuppliedWinsock = FALSE; socketWinP->interruptEvent = CreateEvent(NULL, FALSE, FALSE, NULL); setSocketOptions(socketWinP->winsock, errorP); if (!*errorP) { bindSocketToAddr(socketWinP->winsock, sockAddrP, sockAddrLen, errorP); if (!*errorP) ChanSwitchCreate(&chanSwitchVtbl, socketWinP, chanSwitchPP); } if (*errorP) { CloseHandle(socketWinP->interruptEvent); closesocket(winsock); } } if (*errorP) free(socketWinP); } }
int hbm::communication::SocketNonblocking::connect(int domain, const struct sockaddr* pSockAddr, socklen_t len) { m_fd = static_cast <int> (::socket(domain, SOCK_STREAM, 0)); if (m_fd == -1) { return -1; } int err = setSocketOptions(); if (err < 0) { return err; } err = ::connect(m_fd,pSockAddr, len); // success if WSAGetLastError returns WSAEWOULDBLOCK if((err == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK)) { fd_set fdWrite; struct timeval timeout; timeout.tv_sec = TIMEOUT_CONNECT_S; timeout.tv_usec = 0; FD_ZERO(&fdWrite); FD_SET(m_fd,&fdWrite); err = select(m_fd + 1, NULL, &fdWrite, NULL, &timeout); if(err==1) { int value; socklen_t len = sizeof(value); getsockopt(m_fd, SOL_SOCKET, SO_ERROR, reinterpret_cast < char* > (&value), &len); if(value!=0) { err = -1; } } else { err = -1; } } else { err = -1; } return err; }
int hbm::communication::SocketNonblocking::connect(int domain, const struct sockaddr* pSockAddr, socklen_t len) { m_fd = ::socket(domain, SOCK_STREAM | SOCK_NONBLOCK, 0); if (m_fd==-1) { return -1; } if (setSocketOptions()<0) { return -1; } int err = ::connect(m_fd, pSockAddr, len); if (err==-1) { // success if errno equals EINPROGRESS if(errno != EINPROGRESS) { syslog(LOG_ERR, "failed to connect errno=%d '%s'", errno, strerror(errno)); return -1; } struct pollfd pfd; pfd.fd = m_fd; pfd.events = POLLOUT; do { err = poll(&pfd, 1, TIMEOUT_CONNECT_S*1000); } while((err==-1) && (errno==EINTR) ); if(err!=1) { return -1; } int value; len = sizeof(value); getsockopt(m_fd, SOL_SOCKET, SO_ERROR, &value, &len); if(value!=0) { return -1; } } return 0; }
/* Non-blocking socket event handler Wait one time in select for events on any socket This will accept new connections, read and write to sockets that are connected, and close sockets as required. */ static int32 selectLoop(sslKeys_t *keys, SOCKET lfd) { httpConn_t *cp; psTime_t now; DLListEntry connsTmp; DLListEntry *pList; fd_set readfd, writefd; struct timeval timeout; SOCKET fd, maxfd; unsigned char *buf; int32 rc, len, transferred, val; unsigned char rSanity, wSanity, acceptSanity; sslSessOpts_t options; DLListInit(&connsTmp); rc = PS_SUCCESS; maxfd = INVALID_SOCKET; timeout.tv_sec = SELECT_TIME / 1000; timeout.tv_usec = (SELECT_TIME % 1000) * 1000; FD_ZERO(&readfd); FD_ZERO(&writefd); /* Always set readfd for listening socket */ FD_SET(lfd, &readfd); if (lfd > maxfd) { maxfd = lfd; } /* Check timeouts and set readfd and writefd for connections as required. We use connsTemp so that removal on error from the active iteration list doesn't interfere with list traversal */ psGetTime(&now, NULL); while (!DLListIsEmpty(&g_conns)) { pList = DLListGetHead(&g_conns); cp = DLListGetContainer(pList, httpConn_t, List); DLListInsertTail(&connsTmp, &cp->List); /* If timeout != 0 msec ith no new data, close */ if (cp->timeout && (psDiffMsecs(cp->time, now, NULL) > (int32)cp->timeout)) { closeConn(cp, PS_TIMEOUT_FAIL); continue; /* Next connection */ } /* Always select for read */ FD_SET(cp->fd, &readfd); /* Select for write if there's pending write data or connection */ if (matrixSslGetOutdata(cp->ssl, NULL) > 0) { FD_SET(cp->fd, &writefd); } /* Housekeeping for maxsock in select call */ if (cp->fd > maxfd) { maxfd = cp->fd; } } /* Use select to check for events on the sockets */ if ((val = select(maxfd + 1, &readfd, &writefd, NULL, &timeout)) <= 0) { /* On error, restore global connections list */ while (!DLListIsEmpty(&connsTmp)) { pList = DLListGetHead(&connsTmp); cp = DLListGetContainer(pList, httpConn_t, List); DLListInsertTail(&g_conns, &cp->List); } /* Select timeout */ if (val == 0) { return PS_TIMEOUT_FAIL; } /* Woke due to interrupt */ if (SOCKET_ERRNO == EINTR) { return PS_TIMEOUT_FAIL; } /* Should attempt to handle more errnos, such as EBADF */ return PS_PLATFORM_FAIL; } /* Check listener for new incoming socket connections */ if (FD_ISSET(lfd, &readfd)) { for (acceptSanity = 0; acceptSanity < ACCEPT_QUEUE; acceptSanity++) { fd = accept(lfd, NULL, NULL); if (fd == INVALID_SOCKET) { break; /* Nothing more to accept; next listener */ } setSocketOptions(fd); cp = malloc(sizeof(httpConn_t)); memset(cp, 0x0, sizeof(httpConn_t)); memset(&options, 0x0, sizeof(sslSessOpts_t)); options.versionFlag = g_proto; options.userPtr = keys; /* Just a test */ //options.truncHmac = -1; //options.maxFragLen = -1; //options.ecFlags |= SSL_OPT_SECP521R1; //options.ecFlags |= SSL_OPT_SECP224R1; //options.ecFlags |= SSL_OPT_SECP384R1; if ((rc = matrixSslNewServerSession(&cp->ssl, keys, certCb, &options)) < 0) { close(fd); fd = INVALID_SOCKET; continue; } #ifdef USE_SERVER_NAME_INDICATION /* Register extension callbacks to manage client connection opts */ matrixSslRegisterSNICallback(cp->ssl, SNI_callback); #endif #ifdef USE_ALPN matrixSslRegisterALPNCallback(cp->ssl, ALPN_callback); #endif cp->fd = fd; fd = INVALID_SOCKET; cp->timeout = SSL_TIMEOUT; psGetTime(&cp->time, NULL); cp->parsebuf = NULL; cp->parsebuflen = 0; DLListInsertTail(&connsTmp, &cp->List); /* Fake that there is read data available, no harm if there isn't */ FD_SET(cp->fd, &readfd); /* _psTraceInt("=== New Client %d ===\n", cp->fd); */ } } /* Check each connection for read/write activity */ while (!DLListIsEmpty(&connsTmp)) { pList = DLListGetHead(&connsTmp); cp = DLListGetContainer(pList, httpConn_t, List); DLListInsertTail(&g_conns, &cp->List); rSanity = wSanity = 0; /* See if there's pending data to send on this connection We could use FD_ISSET, but this is more reliable for the current state of data to send. */ WRITE_MORE: if ((len = matrixSslGetOutdata(cp->ssl, &buf)) > 0) { /* Could get a EWOULDBLOCK since we don't check FD_ISSET */ transferred = send(cp->fd, buf, len, MSG_DONTWAIT); if (transferred <= 0) { #ifdef WIN32 if (SOCKET_ERRNO != EWOULDBLOCK && SOCKET_ERRNO != WSAEWOULDBLOCK) { #else if (SOCKET_ERRNO != EWOULDBLOCK) { #endif closeConn(cp, PS_PLATFORM_FAIL); continue; /* Next connection */ } } else { /* Indicate that we've written > 0 bytes of data */ if ((rc = matrixSslSentData(cp->ssl, transferred)) < 0) { closeConn(cp, PS_ARG_FAIL); continue; /* Next connection */ } if (rc == MATRIXSSL_REQUEST_CLOSE) { closeConn(cp, MATRIXSSL_REQUEST_CLOSE); continue; /* Next connection */ } else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) { /* If the protocol is server initiated, send data here */ #ifdef ENABLE_FALSE_START /* OR this could be a Chrome browser using FALSE_START and the application data is already waiting in our inbuf for processing */ if ((rc = matrixSslReceivedData(cp->ssl, 0, &buf, (uint32*)&len)) < 0) { closeConn(cp, 0); continue; /* Next connection */ } if (rc > 0) { /* There was leftover data */ goto PROCESS_MORE; } #endif /* ENABLE_FALSE_START */ } /* Update activity time */ psGetTime(&cp->time, NULL); /* Try to send again if more data to send */ if (rc == MATRIXSSL_REQUEST_SEND || transferred < len) { if (wSanity++ < GOTO_SANITY) goto WRITE_MORE; } } } else if (len < 0) { closeConn(cp, PS_ARG_FAIL); continue; /* Next connection */ } /* Check the file descriptor returned from select to see if the connection has data to be read */ if (FD_ISSET(cp->fd, &readfd)) { READ_MORE: /* Get the ssl buffer and how much data it can accept */ /* Note 0 is a return failure, unlike with matrixSslGetOutdata */ if ((len = matrixSslGetReadbuf(cp->ssl, &buf)) <= 0) { closeConn(cp, PS_ARG_FAIL); continue; /* Next connection */ } if ((transferred = recv(cp->fd, buf, len, MSG_DONTWAIT)) < 0) { /* We could get EWOULDBLOCK despite the FD_ISSET on goto */ #ifdef WIN32 if (SOCKET_ERRNO != EWOULDBLOCK && SOCKET_ERRNO != WSAEWOULDBLOCK) { #else if (SOCKET_ERRNO != EWOULDBLOCK) { #endif closeConn(cp, PS_PLATFORM_FAIL); } continue; /* Next connection */ } /* If EOF, remote socket closed. This is semi-normal closure. Officially, we should close on closure alert. */ if (transferred == 0) { /* psTraceIntInfo("Closing connection %d on EOF\n", cp->fd); */ closeConn(cp, 0); continue; /* Next connection */ } /* Notify SSL state machine that we've received more data into the ssl buffer retreived with matrixSslGetReadbuf. */ if ((rc = matrixSslReceivedData(cp->ssl, (int32)transferred, &buf, (uint32*)&len)) < 0) { closeConn(cp, 0); continue; /* Next connection */ } /* Update activity time */ psGetTime(&cp->time, NULL); PROCESS_MORE: /* Process any incoming plaintext application data */ switch (rc) { case MATRIXSSL_HANDSHAKE_COMPLETE: /* If the protocol is server initiated, send data here */ goto READ_MORE; case MATRIXSSL_APP_DATA: case MATRIXSSL_APP_DATA_COMPRESSED: //psTraceBytes("DATA", buf, len); /* Remember, must handle if len == 0! */ if ((rc = httpBasicParse(cp, buf, len, 0)) < 0) { _psTrace("Couldn't parse HTTP data. Closing conn.\n"); closeConn(cp, PS_PROTOCOL_FAIL); continue; /* Next connection */ } if (cp->parsebuf != NULL) { /* Test for one of our custom testing messages */ if (strncmp((const char*)cp->parsebuf, "MATRIX_SHUTDOWN", 15) == 0) { g_exitFlag = 1; matrixSslEncodeClosureAlert(cp->ssl); _psTrace("Got MATRIX_SHUTDOWN. Exiting\n"); goto WRITE_MORE; } } /* reply to /bytes?<byte count> syntax */ if (len > 11 && strncmp((char *)buf, "GET /bytes?", 11) == 0) { cp->bytes_requested = atoi((char *)buf + 11); if (cp->bytes_requested < strlen((char *)g_httpResponseHdr) || cp->bytes_requested > 1073741824) { cp->bytes_requested = strlen((char *)g_httpResponseHdr); } cp->bytes_sent = 0; } if (rc == HTTPS_COMPLETE) { if (httpWriteResponse(cp) < 0) { closeConn(cp, PS_PROTOCOL_FAIL); continue; /* Next connection */ } /* For HTTP, we assume no pipelined requests, so we close after parsing a single HTTP request */ /* Ignore return of closure alert, it's optional */ matrixSslEncodeClosureAlert(cp->ssl); rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len); if (rc > 0) { /* Additional data is available, but we ignore it */ _psTrace("HTTP data parsing not supported, ignoring.\n"); closeConn(cp, PS_SUCCESS); continue; /* Next connection */ } else if (rc < 0) { closeConn(cp, PS_PROTOCOL_FAIL); continue; /* Next connection */ } /* rc == 0, write out our response and closure alert */ goto WRITE_MORE; } /* We processed a partial HTTP message */ if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) { goto READ_MORE; } goto PROCESS_MORE; case MATRIXSSL_REQUEST_SEND: /* Prevent us from reading again after the write, although that wouldn't be the end of the world */ FD_CLR(cp->fd, &readfd); if (wSanity++ < GOTO_SANITY) goto WRITE_MORE; break; case MATRIXSSL_REQUEST_RECV: if (rSanity++ < GOTO_SANITY) goto READ_MORE; break; case MATRIXSSL_RECEIVED_ALERT: /* The first byte of the buffer is the level */ /* The second byte is the description */ if (*buf == SSL_ALERT_LEVEL_FATAL) { psTraceIntInfo("Fatal alert: %d, closing connection.\n", *(buf + 1)); closeConn(cp, PS_PROTOCOL_FAIL); continue; /* Next connection */ } /* Closure alert is normal (and best) way to close */ if (*(buf + 1) == SSL_ALERT_CLOSE_NOTIFY) { closeConn(cp, PS_SUCCESS); continue; /* Next connection */ } psTraceIntInfo("Warning alert: %d\n", *(buf + 1)); if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) { /* No more data in buffer. Might as well read for more. */ goto READ_MORE; } goto PROCESS_MORE; default: /* If rc <= 0 we fall here */ closeConn(cp, PS_PROTOCOL_FAIL); continue; /* Next connection */ } /* Always try to read more if we processed some data */ if (rSanity++ < GOTO_SANITY) goto READ_MORE; } /* readfd handling */ } /* connection loop */ return PS_SUCCESS; } /******************************************************************************/ /* Create an HTTP response and encode it to the SSL buffer */ #define TEST_SIZE 16000 static int32 httpWriteResponse(httpConn_t *conn) { unsigned char *buf; ssl_t *cp; int32 available, len, rc; cp = conn->ssl; if (conn->bytes_requested) { /* The /bytes? syntax */ while (conn->bytes_sent < conn->bytes_requested) { len = conn->bytes_requested - conn->bytes_sent; if (len > RESPONSE_REC_LEN) { len = RESPONSE_REC_LEN; } psAssert(len > 0); rc = matrixSslGetWritebuf(cp, &buf, len); if (rc < len) { len = rc; /* could have been shortened due to max_frag */ } memset(buf, 'J', len); if (conn->bytes_sent == 0) { /* Overwrite first N bytes with HTTP header the first time */ strncpy((char *)buf, (char *)g_httpResponseHdr, strlen((char*)g_httpResponseHdr)); } if ((rc = matrixSslEncodeWritebuf(cp, len)) < 0) { printf("couldn't encode data %d\n", rc); } conn->bytes_sent += len; } return MATRIXSSL_REQUEST_SEND; } /* Usual reply */ if ((available = matrixSslGetWritebuf(cp, &buf, (uint32)strlen((char *)g_httpResponseHdr) + 1)) < 0) { return PS_MEM_FAIL; } strncpy((char *)buf, (char *)g_httpResponseHdr, available); //psTraceBytes("Replying", buf, (uint32)strlen((char *)buf)); if (matrixSslEncodeWritebuf(cp, (uint32)strlen((char *)buf)) < 0) { return PS_MEM_FAIL; } return MATRIXSSL_REQUEST_SEND; } /******************************************************************************/ /* Main non-blocking SSL server Initialize MatrixSSL and sockets layer, and loop on select */ int32 main(int32 argc, char **argv) { sslKeys_t *keys; SOCKET lfd; unsigned char *CAstream; int32 err, rc, CAstreamLen; #ifdef USE_STATELESS_SESSION_TICKETS unsigned char randKey[16]; #endif #ifdef WIN32 WSADATA wsaData; WSAStartup(MAKEWORD(1, 1), &wsaData); #endif keys = NULL; DLListInit(&g_conns); g_exitFlag = 0; lfd = INVALID_SOCKET; #ifdef POSIX if (sighandlers() < 0) { return PS_PLATFORM_FAIL; } #endif /* POSIX */ if ((rc = matrixSslOpen()) < 0) { _psTrace("MatrixSSL library init failure. Exiting\n"); return rc; } if (matrixSslNewKeys(&keys, NULL) < 0) { _psTrace("MatrixSSL library key init failure. Exiting\n"); return -1; } #ifdef USE_STATELESS_SESSION_TICKETS matrixSslSetSessionTicketCallback(keys, sessTicketCb); psGetEntropy(randKey, 16, NULL); if (matrixSslLoadSessionTicketKeys(keys, randKey, sessTicketSymKey, 32, sessTicketMacKey, 32) < 0) { _psTrace("Error loading session ticket encryption key\n"); } #endif #ifdef USE_HEADER_KEYS /* In-memory based keys Build the CA list first for potential client auth usage */ CAstreamLen = 0; #ifdef USE_RSA CAstreamLen += sizeof(RSACAS); #ifdef USE_ECC CAstreamLen += sizeof(ECDHRSACAS); #endif #endif #ifdef USE_ECC CAstreamLen += sizeof(ECCAS); #endif CAstream = psMalloc(NULL, CAstreamLen); CAstreamLen = 0; #ifdef USE_RSA memcpy(CAstream, RSACAS, sizeof(RSACAS)); CAstreamLen += sizeof(RSACAS); #ifdef USE_ECC memcpy(CAstream + CAstreamLen, ECDHRSACAS, sizeof(ECDHRSACAS)); CAstreamLen += sizeof(ECDHRSACAS); #endif #endif #ifdef USE_ECC memcpy(CAstream + CAstreamLen, ECCAS, sizeof(ECCAS)); CAstreamLen += sizeof(ECCAS); #endif #ifdef EXAMPLE_RSA_KEYS if ((rc = matrixSslLoadRsaKeysMem(keys, RSA1024, sizeof(RSA1024), RSA1024KEY, sizeof(RSA1024KEY), CAstream, CAstreamLen)) < 0) { _psTrace("No certificate material loaded. Exiting\n"); psFree(CAstream, NULL); matrixSslDeleteKeys(keys); matrixSslClose(); return rc; } #endif #ifdef EXAMPLE_ECDH_RSA_KEYS if ((rc = matrixSslLoadEcKeysMem(keys, ECDHRSA256, sizeof(ECDHRSA256), ECDHRSA256KEY, sizeof(ECDHRSA256KEY), CAstream, CAstreamLen)) < 0) { _psTrace("No certificate material loaded. Exiting\n"); psFree(CAstream, NULL); matrixSslDeleteKeys(keys); matrixSslClose(); return rc; } #endif #ifdef EXAMPLE_EC_KEYS if ((rc = matrixSslLoadEcKeysMem(keys, EC521, sizeof(EC521), EC521KEY, sizeof(EC521KEY), CAstream, CAstreamLen)) < 0) { // if ((rc = matrixSslLoadEcKeysMem(keys, EC256, sizeof(EC256), // EC256KEY, sizeof(EC256KEY), CAstream, CAstreamLen)) < 0) { // if ((rc = matrixSslLoadEcKeysMem(keys, EC192, sizeof(EC192), // EC192KEY, sizeof(EC192KEY), CAstream, CAstreamLen)) < 0) { _psTrace("No certificate material loaded. Exiting\n"); psFree(CAstream, NULL); matrixSslDeleteKeys(keys); matrixSslClose(); return rc; } #endif #ifdef REQUIRE_DH_PARAMS if (matrixSslLoadDhParamsMem(keys, dhParamBuf1024, sizeof(dhParamBuf1024)) < 0){ _psTrace("Unable to load DH parameters\n"); } #endif /* DH_PARAMS */ psFree(CAstream, NULL); #else /* USE_HEADER_KEYS */ /* File based keys Build the CA list first for potential client auth usage */ CAstreamLen = 0; #ifdef USE_RSA CAstreamLen += (int32)strlen(rsaCAFile) + 1; #ifdef USE_ECC CAstreamLen += (int32)strlen(ecdhRsaCAFile) + 1; #endif #endif #ifdef USE_ECC CAstreamLen += (int32)strlen(ecCAFile) + 1; #endif CAstream = psMalloc(NULL, CAstreamLen); memset(CAstream, 0x0, CAstreamLen); CAstreamLen = 0; #ifdef USE_RSA memcpy(CAstream, rsaCAFile, strlen(rsaCAFile)); CAstreamLen += strlen(rsaCAFile); #ifdef USE_ECC memcpy(CAstream + CAstreamLen, ";", 1); CAstreamLen++; memcpy(CAstream + CAstreamLen, ecdhRsaCAFile, strlen(ecdhRsaCAFile)); CAstreamLen += strlen(ecdhRsaCAFile); #endif #endif #ifdef USE_ECC if (CAstreamLen > 0) { memcpy(CAstream + CAstreamLen, ";", 1); CAstreamLen++; } memcpy(CAstream + CAstreamLen, ecCAFile, strlen(ecCAFile)); #endif /* Load Identiy */ #ifdef EXAMPLE_RSA_KEYS if ((rc = matrixSslLoadRsaKeys(keys, rsaCertFile, rsaPrivkeyFile, NULL, (char*)CAstream)) < 0) { _psTrace("No certificate material loaded. Exiting\n"); psFree(CAstream, NULL); matrixSslDeleteKeys(keys); matrixSslClose(); return rc; } #endif #ifdef EXAMPLE_ECDH_RSA_KEYS if ((rc = matrixSslLoadEcKeys(keys, ecdhRsaCertFile, ecdhRsaPrivkeyFile, NULL, (char*)CAstream)) < 0) { _psTrace("No certificate material loaded. Exiting\n"); psFree(CAstream, NULL); matrixSslDeleteKeys(keys); matrixSslClose(); return rc; } #endif #ifdef EXAMPLE_EC_KEYS if ((rc = matrixSslLoadEcKeys(keys, ecCertFile, ecPrivkeyFile, NULL, (char*)CAstream)) < 0) { _psTrace("No certificate material loaded. Exiting\n"); psFree(CAstream, NULL); matrixSslDeleteKeys(keys); matrixSslClose(); return rc; } #endif #ifdef REQUIRE_DH_PARAMS if (matrixSslLoadDhParams(keys, dhParamFile) < 0){ _psTrace("Unable to load DH parameters\n"); } #endif psFree(CAstream, NULL); #endif /* USE_HEADER_KEYS */ #ifdef USE_PSK_CIPHER_SUITE /* The first one supports the 15-byte openssl PSK ID */ matrixSslLoadPsk(keys, pskTable[0].key, sizeof(pskTable[0].key), pskTable[rc].id, 15); for (rc = 0; rc < 8; rc++) { matrixSslLoadPsk(keys, pskTable[rc].key, sizeof(pskTable[rc].key), pskTable[rc].id, sizeof(pskTable[rc].id)); } #endif /* PSK */ if (argc == 2) { switch (atoi(argv[1])) { case 0: g_proto = SSL_FLAGS_SSLV3; break; case 1: g_proto = SSL_FLAGS_TLS_1_0; break; case 2: g_proto = SSL_FLAGS_TLS_1_1; break; case 3: g_proto = SSL_FLAGS_TLS_1_2; break; default: g_proto = SSL_FLAGS_TLS_1_0; break; } } else { g_proto = 0; } /* Create the listening socket that will accept incoming connections */ if ((lfd = socketListen(HTTPS_PORT, &err)) == INVALID_SOCKET) { _psTraceInt("Can't listen on port %d\n", HTTPS_PORT); goto L_EXIT; } /* Main select loop to handle sockets events */ while (!g_exitFlag) { selectLoop(keys, lfd); } L_EXIT: if (lfd != INVALID_SOCKET) close(lfd); if (keys) matrixSslDeleteKeys(keys); matrixSslClose(); return 0; }
/* Non-blocking socket event handler Wait one time in select for events on any socket This will accept new connections, read and write to sockets that are connected, and close sockets as required. */ static int32 selectLoop(sslKeys_t *keys, SOCKET lfd) { httpConn_t *cp; psTime_t now; DLListEntry connsTmp; DLListEntry *pList; fd_set readfd, writefd; struct timeval timeout; SOCKET fd, maxfd; unsigned char *buf; int32 rc, len, transferred, val; unsigned char rSanity, wSanity, acceptSanity; DLListInit(&connsTmp); rc = PS_SUCCESS; maxfd = INVALID_SOCKET; timeout.tv_sec = SELECT_TIME / 1000; timeout.tv_usec = (SELECT_TIME % 1000) * 1000; FD_ZERO(&readfd); FD_ZERO(&writefd); /* Always set readfd for listening socket */ FD_SET(lfd, &readfd); if (lfd > maxfd) { maxfd = lfd; } /* Check timeouts and set readfd and writefd for connections as required. We use connsTemp so that removal on error from the active iteration list doesn't interfere with list traversal */ psGetTime(&now); while (!DLListIsEmpty(&g_conns)) { pList = DLListGetHead(&g_conns); cp = DLListGetContainer(pList, httpConn_t, List); DLListInsertTail(&connsTmp, &cp->List); /* If timeout != 0 msec ith no new data, close */ if (cp->timeout && (psDiffMsecs(cp->time, now) > (int32)cp->timeout)) { closeConn(cp, PS_TIMEOUT_FAIL); continue; /* Next connection */ } /* Always select for read */ FD_SET(cp->fd, &readfd); /* Select for write if there's pending write data or connection */ if (matrixSslGetOutdata(cp->ssl, NULL) > 0) { FD_SET(cp->fd, &writefd); } /* Housekeeping for maxsock in select call */ if (cp->fd > maxfd) { maxfd = cp->fd; } } /* Use select to check for events on the sockets */ if ((val = select(maxfd + 1, &readfd, &writefd, NULL, &timeout)) <= 0) { /* On error, restore global connections list */ while (!DLListIsEmpty(&connsTmp)) { pList = DLListGetHead(&connsTmp); cp = DLListGetContainer(pList, httpConn_t, List); DLListInsertTail(&g_conns, &cp->List); } /* Select timeout */ if (val == 0) { return PS_TIMEOUT_FAIL; } /* Woke due to interrupt */ if (SOCKET_ERRNO == EINTR) { return PS_TIMEOUT_FAIL; } /* Should attempt to handle more errnos, such as EBADF */ return PS_PLATFORM_FAIL; } /* Check listener for new incoming socket connections */ if (FD_ISSET(lfd, &readfd)) { for (acceptSanity = 0; acceptSanity < ACCEPT_QUEUE; acceptSanity++) { fd = accept(lfd, NULL, NULL); if (fd == INVALID_SOCKET) { break; /* Nothing more to accept; next listener */ } setSocketOptions(fd); cp = malloc(sizeof(httpConn_t)); if ((rc = matrixSslNewServerSession(&cp->ssl, keys, certCb)) < 0) { close(fd); fd = INVALID_SOCKET; continue; } cp->fd = fd; fd = INVALID_SOCKET; cp->timeout = SSL_TIMEOUT; psGetTime(&cp->time); cp->parsebuf = NULL; cp->parsebuflen = 0; DLListInsertTail(&connsTmp, &cp->List); /* Fake that there is read data available, no harm if there isn't */ FD_SET(cp->fd, &readfd); /* _psTraceInt("=== New Client %d ===\n", cp->fd); */ } } /* Check each connection for read/write activity */ while (!DLListIsEmpty(&connsTmp)) { pList = DLListGetHead(&connsTmp); cp = DLListGetContainer(pList, httpConn_t, List); DLListInsertTail(&g_conns, &cp->List); rSanity = wSanity = 0; /* See if there's pending data to send on this connection We could use FD_ISSET, but this is more reliable for the current state of data to send. */ WRITE_MORE: if ((len = matrixSslGetOutdata(cp->ssl, &buf)) > 0) { /* Could get a EWOULDBLOCK since we don't check FD_ISSET */ transferred = send(cp->fd, buf, len, MSG_DONTWAIT); if (transferred <= 0) { #ifdef WIN32 if (SOCKET_ERRNO != EWOULDBLOCK && SOCKET_ERRNO != WSAEWOULDBLOCK) { #else if (SOCKET_ERRNO != EWOULDBLOCK) { #endif closeConn(cp, PS_PLATFORM_FAIL); continue; /* Next connection */ } } else { /* Indicate that we've written > 0 bytes of data */ if ((rc = matrixSslSentData(cp->ssl, transferred)) < 0) { closeConn(cp, PS_ARG_FAIL); continue; /* Next connection */ } if (rc == MATRIXSSL_REQUEST_CLOSE) { closeConn(cp, MATRIXSSL_REQUEST_CLOSE); continue; /* Next connection */ } else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) { /* If the protocol is server initiated, send data here */ #ifdef ENABLE_FALSE_START /* OR this could be a Chrome browser using FALSE_START and the application data is already waiting in our inbuf for processing */ if ((rc = matrixSslReceivedData(cp->ssl, 0, &buf, (uint32*)&len)) < 0) { closeConn(cp, 0); continue; /* Next connection */ } if (rc > 0) { /* There was leftover data */ goto PROCESS_MORE; } #endif /* ENABLE_FALSE_START */ } /* Update activity time */ psGetTime(&cp->time); /* Try to send again if more data to send */ if (rc == MATRIXSSL_REQUEST_SEND || transferred < len) { if (wSanity++ < GOTO_SANITY) goto WRITE_MORE; } } } else if (len < 0) { closeConn(cp, PS_ARG_FAIL); continue; /* Next connection */ } /* Check the file descriptor returned from select to see if the connection has data to be read */ if (FD_ISSET(cp->fd, &readfd)) { READ_MORE: /* Get the ssl buffer and how much data it can accept */ /* Note 0 is a return failure, unlike with matrixSslGetOutdata */ if ((len = matrixSslGetReadbuf(cp->ssl, &buf)) <= 0) { closeConn(cp, PS_ARG_FAIL); continue; /* Next connection */ } if ((transferred = recv(cp->fd, buf, len, MSG_DONTWAIT)) < 0) { /* We could get EWOULDBLOCK despite the FD_ISSET on goto */ #ifdef WIN32 if (SOCKET_ERRNO != EWOULDBLOCK && SOCKET_ERRNO != WSAEWOULDBLOCK) { #else if (SOCKET_ERRNO != EWOULDBLOCK) { #endif closeConn(cp, PS_PLATFORM_FAIL); } continue; /* Next connection */ } /* If EOF, remote socket closed. This is semi-normal closure. Officially, we should close on closure alert. */ if (transferred == 0) { /* psTraceIntInfo("Closing connection %d on EOF\n", cp->fd); */ closeConn(cp, 0); continue; /* Next connection */ } /* Notify SSL state machine that we've received more data into the ssl buffer retreived with matrixSslGetReadbuf. */ if ((rc = matrixSslReceivedData(cp->ssl, (int32)transferred, &buf, (uint32*)&len)) < 0) { closeConn(cp, 0); continue; /* Next connection */ } /* Update activity time */ psGetTime(&cp->time); PROCESS_MORE: /* Process any incoming plaintext application data */ switch (rc) { case MATRIXSSL_HANDSHAKE_COMPLETE: /* If the protocol is server initiated, send data here */ goto READ_MORE; case MATRIXSSL_APP_DATA: /* Remember, must handle if len == 0! */ if ((rc = httpBasicParse(cp, buf, len)) < 0) { _psTrace("Couldn't parse HTTP data. Closing conn.\n"); closeConn(cp, PS_PROTOCOL_FAIL); continue; /* Next connection */ } if (rc == HTTPS_COMPLETE) { if (httpWriteResponse(cp->ssl) < 0) { closeConn(cp, PS_PROTOCOL_FAIL); continue; /* Next connection */ } /* For HTTP, we assume no pipelined requests, so we close after parsing a single HTTP request */ /* Ignore return of closure alert, it's optional */ matrixSslEncodeClosureAlert(cp->ssl); rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len); if (rc > 0) { /* Additional data is available, but we ignore it */ _psTrace("HTTP data parsing not supported, ignoring.\n"); closeConn(cp, PS_SUCCESS); continue; /* Next connection */ } else if (rc < 0) { closeConn(cp, PS_PROTOCOL_FAIL); continue; /* Next connection */ } /* rc == 0, write out our response and closure alert */ goto WRITE_MORE; } /* We processed a partial HTTP message */ if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) { goto READ_MORE; } goto PROCESS_MORE; case MATRIXSSL_REQUEST_SEND: /* Prevent us from reading again after the write, although that wouldn't be the end of the world */ FD_CLR(cp->fd, &readfd); if (wSanity++ < GOTO_SANITY) goto WRITE_MORE; break; case MATRIXSSL_REQUEST_RECV: if (rSanity++ < GOTO_SANITY) goto READ_MORE; break; case MATRIXSSL_RECEIVED_ALERT: /* The first byte of the buffer is the level */ /* The second byte is the description */ if (*buf == SSL_ALERT_LEVEL_FATAL) { psTraceIntInfo("Fatal alert: %d, closing connection.\n", *(buf + 1)); closeConn(cp, PS_PROTOCOL_FAIL); continue; /* Next connection */ } /* Closure alert is normal (and best) way to close */ if (*(buf + 1) == SSL_ALERT_CLOSE_NOTIFY) { closeConn(cp, PS_SUCCESS); continue; /* Next connection */ } psTraceIntInfo("Warning alert: %d\n", *(buf + 1)); if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) { /* No more data in buffer. Might as well read for more. */ goto READ_MORE; } goto PROCESS_MORE; default: /* If rc <= 0 we fall here */ closeConn(cp, PS_PROTOCOL_FAIL); continue; /* Next connection */ } /* Always try to read more if we processed some data */ if (rSanity++ < GOTO_SANITY) goto READ_MORE; } /* readfd handling */ } /* connection loop */ return PS_SUCCESS; } /******************************************************************************/ /* Create an HTTP response and encode it to the SSL buffer */ #define TEST_SIZE 16000 static int32 httpWriteResponse(ssl_t *cp) { unsigned char *buf; int32 available; if ((available = matrixSslGetWritebuf(cp, &buf, strlen((char *)g_httpResponseHdr) + 1)) < 0) { return PS_MEM_FAIL; } strncpy((char *)buf, (char *)g_httpResponseHdr, available); if (matrixSslEncodeWritebuf(cp, strlen((char *)buf)) < 0) { return PS_MEM_FAIL; } return MATRIXSSL_REQUEST_SEND; } /******************************************************************************/ /* Main non-blocking SSL server Initialize MatrixSSL and sockets layer, and loop on select */ int32 main(int32 argc, char **argv) { sslKeys_t *keys; SOCKET lfd; int32 err, rc; #ifdef WIN32 WSADATA wsaData; WSAStartup(MAKEWORD(1, 1), &wsaData); #endif keys = NULL; DLListInit(&g_conns); g_exitFlag = 0; lfd = INVALID_SOCKET; #ifdef POSIX if (sighandlers() < 0) { return PS_PLATFORM_FAIL; } #endif /* POSIX */ if ((rc = matrixSslOpen()) < 0) { _psTrace("MatrixSSL library init failure. Exiting\n"); return rc; } if (matrixSslNewKeys(&keys) < 0) { _psTrace("MatrixSSL library key init failure. Exiting\n"); return -1; } #ifdef USE_HEADER_KEYS /* In-memory based keys */ if ((rc = matrixSslLoadRsaKeysMem(keys, certSrvBuf, sizeof(certSrvBuf), privkeySrvBuf, sizeof(privkeySrvBuf), NULL, 0)) < 0) { _psTrace("No certificate material loaded. Exiting\n"); matrixSslDeleteKeys(keys); matrixSslClose(); return rc; } #else /* USE_HEADER_KEYS */ /* File based keys */ if ((rc = matrixSslLoadRsaKeys(keys, certSrvFile, privkeySrvFile, NULL, NULL)) < 0) { _psTrace("No certificate material loaded. Exiting\n"); matrixSslDeleteKeys(keys); matrixSslClose(); return rc; } #endif /* USE_HEADER_KEYS */ /* Create the listening socket that will accept incoming connections */ if ((lfd = socketListen(HTTPS_PORT, &err)) == INVALID_SOCKET) { _psTraceInt("Can't listen on port %d\n", HTTPS_PORT); goto L_EXIT; } /* Main select loop to handle sockets events */ while (!g_exitFlag) { selectLoop(keys, lfd); } L_EXIT: if (lfd != INVALID_SOCKET) close(lfd); if (keys) matrixSslDeleteKeys(keys); matrixSslClose(); return 0; }
void SocketIPv4::enableNaggleAlgorithm(bool enabled) { BOOL disabled = enabled ? 0 : 1; setSocketOptions(IPPROTO_TCP, TCP_NODELAY, &disabled, sizeof(disabled)); }
int32 PTsshSocket::connectToServer() { int result = PTSSH_SUCCESS; bool bSS_init = false, bSR_init = false; CryptoStuff::Cipher *pEncrypt = NULL, *pDecrypt = NULL; //Set socket options setSocketOptions(m_sock); //Let's try and connect to the host with our socket if ( ::connect(m_sock, (struct sockaddr*)m_pSockAddr, sizeof(struct sockaddr_in)) != 0) { close(m_sock); #ifdef WIN32 int error = WSAGetLastError(); PTLOG((LL_error, "Winsock error number %d\n", error)); #endif result = PTSSH_ERR_CouldNotConnectToHost; goto error; } /************************** * Object init and member var setup ***************************/ pthread_mutex_lock( &m_isAliveMutex); m_bIsSocketAlive = true; pthread_mutex_unlock( &m_isAliveMutex); //Now set the socket blocking if (! setSocketBlocking(m_sock, true)) //Blocking { result = PTSSH_ERR_CouldNotSetSocketBlocking; goto error; } //Finally, create and startup our socket send and socket recieve threads m_pSS = new SocketSend(m_pChannelMgr, m_pActivityMutex, m_pActivity_cv, this, m_sock); m_pSR = new SocketRecieve(m_pChannelMgr, m_pActivityMutex, m_pActivity_cv, this, m_sock); if ( ! m_pSR || ! m_pSS) { result = PTSSH_ERR_CouldNotAllocateMemory; goto error; } if ( m_pSS->init() != PTSSH_SUCCESS) { result = PTSSH_ERR_CouldNotInit_SS; goto error; } bSS_init = true; if ( m_pSR->init() != PTSSH_SUCCESS) { result = PTSSH_ERR_CouldNotInit_SR; goto error; } bSR_init = true; /* Now let the SocketRecieve class know about the SocketSend class so that it can tell * it when to go into key exchange mode. */ m_pSR->setSocketSendPtr( m_pSS); /* ...and let the SocketSend class know about the SocketRecieve class so that it can * tell it when keyX mode is finished & when it can use its new cipher object */ m_pSS->setSocketRecievePtr( m_pSR); /* Create our initial Cipher objects. Starting out, they won't have a cipher algorithm, so we'll just use them to get things like blocksize and mac size */ pEncrypt = new CryptoStuff::Cipher(); if ( ! pEncrypt) { result = PTSSH_ERR_CouldNotAllocateMemory; goto error; } //Give the new cipher to the socketSend class m_pSS->setInitialCipher( pEncrypt); pEncrypt = NULL; // m_pSS now ownes this pDecrypt = new CryptoStuff::Cipher(); if ( ! pDecrypt) { result = PTSSH_ERR_CouldNotAllocateMemory; goto error; } //Set the new decryption cipher m_pSR->setInitialCipher( pDecrypt); pDecrypt = NULL; //m_pSR now ownes this /*************************** * Send/Recieve Banners ***************************/ //setV_C, our banner message in our DH object m_pCrypto->setV_C( PTSSH_BANNER, (uint32) strlen(PTSSH_BANNER) -2); //Send our banner if ( rawSocketWrite( PTSSH_BANNER, (uint32) strlen(PTSSH_BANNER)) == PTSSH_SUCCESS) { char banner[256]; memset(banner, 0x0, 256); //recieve remote banner int32 len = readBanner( &m_pRemoteBanner); if (len > 0 && m_pRemoteBanner) { memcpy(banner, m_pRemoteBanner, len); // <-- dangerous! PTLOG((LL_debug1, "Remote banner: %s\n", banner)); } else { result = PTSSH_ERR_CouldNotGetRemoteBanner; goto error; } } /*************************** * Start the threads! ***************************/ if ( ! m_pSS->startThread()) { result = PTSSH_ERR_CouldNotStartSocketSendThread; goto error; } if ( ! m_pSR->startThread()) { result = PTSSH_ERR_CouldNotStartSocketRecieveThread; goto error; } return result; error: close (m_sock); if ( m_pSS) { if ( bSS_init && m_pSS->isRunning()) m_pSS->stopThread(); delete m_pSS; m_pSS = NULL; } if ( m_pSR) { if ( bSR_init && m_pSR->isRunning() ) m_pSR->stopThread(); delete m_pSR; m_pSR = NULL; } if ( pEncrypt ) { m_pSS->setCipher( NULL); delete pEncrypt; pEncrypt = NULL; } if ( pDecrypt ) { m_pSR->setCipher( NULL); delete pDecrypt; pDecrypt = NULL; } pthread_mutex_lock( &m_isAliveMutex); m_bIsSocketAlive = false; pthread_mutex_unlock( &m_isAliveMutex); return result; }
void SocketIPv4::setExclusiveAddrUse() { int val = 1; setSocketOptions(SOL_SOCKET, SO_EXCLUSIVEADDRUSE, &val, sizeof(val)); }