int CSocket::sendData(CString& data) { int intError = 0; int size = 0; // Make sure the socket is connected! if (properties.state == SOCKET_STATE_DISCONNECTED) return SOCKET_INVALID; do { // See if we can send data. // If we can't, return how many bytes we did send. fd_set set; struct timeval tm; tm.tv_sec = tm.tv_usec = 0; FD_ZERO(&set); FD_SET(properties.handle, &set); select(properties.handle + 1, 0, &set, 0, &tm); if (!FD_ISSET(properties.handle, &set)) return size; // Send our data, yay! int sent = 0; if ((sent = ::send(properties.handle, data.text(), data.length(), 0)) == SOCKET_ERROR) { intError = identifyError(); switch (intError) { case ENETDOWN: case ENETRESET: case ENOTCONN: case EHOSTUNREACH: case ECONNABORTED: case ECONNRESET: case ETIMEDOUT: // Destroy the bad socket and create a new one. disconnect(); return intError; break; } if (intError == EAGAIN || intError == EWOULDBLOCK || intError == EINPROGRESS) return size; disconnect(); return intError; } // Remove what we sent. // Increase size by how much we sent. if (sent >= data.length()) data.clear(); else if (sent > 0) data.removeI(0, sent); size += sent; // Repeat while data is still left. } while (data.length() > 0 && intError == 0); // Return how much data was ultimately sent. return size; }
char* CSocket::getData(unsigned int* dsize) { int size = 0; int intError = 0; // Create the buffer. const int BUFFLEN = 0x8000; // 32KB. static char buff[0x8000]; // 32KB. // Make sure it is connected! if (properties.state == SOCKET_STATE_DISCONNECTED || properties.handle == INVALID_SOCKET) { *dsize = 0; return 0; } // Allocate buff. memset((void*)buff, 0, BUFFLEN); // Get our data if (properties.protocol == SOCKET_PROTOCOL_UDP) size = recvfrom(properties.handle, buff, BUFFLEN, 0, 0, 0); else size = recv(properties.handle, buff, BUFFLEN, 0); // Check for error! if (size == SOCKET_ERROR) { size = 0; intError = identifyError(); switch (intError) { case ENETDOWN: case ENETRESET: case ENOTCONN: case EHOSTUNREACH: case ECONNABORTED: case ECONNRESET: case ETIMEDOUT: case ESHUTDOWN: // Destroy the bad socket and create a new one. SLOG("%s - Connection lost! Reason: %s\n", properties.description, errorMessage(intError)); disconnect(); break; default: break; } } // If size is 0, the socket was disconnected. if (size == 0) disconnect(); // Set dsize to how much data was returned. *dsize = size; // Return the data. return buff; }
CSocket* CSocket::accept() { // Make sure the socket is connected! if (properties.state == SOCKET_STATE_DISCONNECTED) return 0; // Only server type TCP sockets can accept new connections. if (properties.type != SOCKET_TYPE_SERVER || properties.protocol != SOCKET_PROTOCOL_TCP) return 0; sockaddr_storage addr; int addrlen = sizeof(addr); SOCKET handle = 0; // Try to accept a new connection. handle = ::accept(properties.handle, (struct sockaddr*)&addr, (socklen_t*)&addrlen); if (handle == INVALID_SOCKET) { int error = identifyError(); if (error == EWOULDBLOCK || error == EINPROGRESS) return 0; SLOG("[CSocket::accept] accept() returned error: %s\n", errorMessage(error)); return 0; } // Create the new socket to store the new connection. CSocket* sock = new CSocket(); sock_properties props; memset((void*)&props, 0, sizeof(sock_properties)); memset((void*)&properties.address, 0, sizeof(struct sockaddr_storage)); memcpy((void*)&props.address, &addr, sizeof(addr)); props.protocol = properties.protocol; props.type = SOCKET_TYPE_CLIENT; props.state = SOCKET_STATE_CONNECTED; props.handle = handle; sock->setProperties(props); sock->setDescription(sock->getRemoteIp()); // Disable the nagle algorithm. if (props.protocol == SOCKET_PROTOCOL_TCP) { int nagle = 1; setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, (char*)&nagle, sizeof(nagle)); } // Set as non-blocking. #if defined(_WIN32) || defined(_WIN64) u_long flags = 1; ioctlsocket(handle, FIONBIO, &flags); #else int flags = fcntl(properties.handle, F_GETFL, 0); fcntl(handle, F_SETFL, flags | O_NONBLOCK); #endif // Accept the connection by calling getsockopt. int type, typeSize = sizeof(int); getsockopt(handle, SOL_SOCKET, SO_TYPE, (char*)&type, (socklen_t*)&typeSize); return sock; }
char* CSocket::peekData() { //int recvsize = 0x10000; int recvsize = 0x2000; int intError; char *buff = 0; // Make sure it is connected! if (properties.state == SOCKET_STATE_DISCONNECTED) return 0; // Make a buffer to store data! buff = new char[ recvsize ]; memset((char *)buff, 0, recvsize); // Get our data if (properties.protocol == SOCKET_PROTOCOL_UDP) intError = recvfrom(properties.handle, buff, recvsize, MSG_PEEK, 0, 0); else intError = recv(properties.handle, buff, recvsize, MSG_PEEK); // Check for error! if (intError == SOCKET_ERROR) { intError = identifyError(); switch (intError) { case ENETDOWN: case ENETRESET: case ENOTCONN: case EHOSTUNREACH: case ECONNABORTED: case ECONNRESET: case ETIMEDOUT: case ESHUTDOWN: // Destroy the bad socket and create a new one. disconnect(); break; default: break; } if (buff) { delete [] buff; buff = 0; } return 0; } // Return the data. return buff; }
int CSocket::sendData(char* data, unsigned int* dsize) { int intError = 0; // Make sure the socket is connected! if (properties.state == SOCKET_STATE_DISCONNECTED || properties.handle == INVALID_SOCKET) { *dsize = 0; return 0; } // Send our data, yay! int sent = 0; if ((sent = ::send(properties.handle, data, *dsize, MSG_NOSIGNAL)) == SOCKET_ERROR) { sent = 0; intError = identifyError(); switch (intError) { case ENETDOWN: case ENETRESET: case ENOTCONN: case EHOSTUNREACH: case ECONNABORTED: case ECONNRESET: case ETIMEDOUT: // Destroy the bad socket and create a new one. SLOG("%s - Connection lost! Reason: %s\n", properties.description, errorMessage(intError)); disconnect(); return 0; break; case EAGAIN: return 0; break; } disconnect(); return 0; } // Remove what we sent from the total size. *dsize -= sent; // Return how much data was ultimately sent. return sent; }
CSocket* CSocket::accept() { // Make sure the socket is connected! if (properties.state == SOCKET_STATE_DISCONNECTED) return 0; // Only server type TCP sockets can accept new connections. if (properties.type != SOCKET_TYPE_SERVER || properties.protocol != SOCKET_PROTOCOL_TCP) return 0; sockaddr_storage addr; int addrlen = sizeof(addr); SOCKET handle = 0; // Try to accept a new connection. handle = ::accept(properties.handle, (struct sockaddr*)&addr, (socklen_t*)&addrlen); if (handle == INVALID_SOCKET) { int error = identifyError(); if (error == EWOULDBLOCK || error == EINPROGRESS) return 0; return 0; } // Create the new socket to store the new connection. CSocket* sock = new CSocket(); sock_properties props; memset((void*)&props, 0, sizeof(sock_properties)); memset((void*)&properties.address, 0, sizeof(struct sockaddr_storage)); memcpy((void*)&props.address, &addr, sizeof(addr)); props.options = properties.options; props.protocol = properties.protocol; props.type = SOCKET_TYPE_CLIENT; props.state = SOCKET_STATE_CONNECTED; props.handle = handle; sock->setProperties(props); sock->setDescription(sock->tcpIp()); // Accept the connection by calling getsockopt. int type, typeSize = sizeof(int); getsockopt(handle, SOL_SOCKET, SO_TYPE, (char*)&type, (socklen_t*)&typeSize); return sock; }
void CSocket::socketSystemDestroy() { // errorOut("debuglog.txt", ":: Destroying socket system..."); #if defined(_WIN32) || defined(_WIN64) int intTimeCheck = 0; while (intTimeCheck++ < 3) { if (WSACleanup() == SOCKET_ERROR) SLOG("[CSocket::socketSystemDestroy] WSACleanup() returned error: %s\n", errorMessage(identifyError())); sleep(1000); } #endif }
void CSocket::disconnect() { // Shut down the socket. if (shutdown(properties.handle, SHUT_RDWR) == SOCKET_ERROR) { int error = identifyError(); if (error == ENOTSOCK) { properties.handle = INVALID_SOCKET; properties.state = SOCKET_STATE_DISCONNECTED; return; } SLOG("[CSocket::destroy] shutdown returned error: %s\n", errorMessage(error)); } // Mark socket as terminating. properties.state = SOCKET_STATE_TERMINATING; // Gracefully shut it down. /* if (properties.protocol == SOCKET_PROTOCOL_TCP) { int count = 0; char buff[ 0x2000 ]; int size; while (++count < 3) { size = recv(properties.handle, buff, 0x2000, 0); if (size == 0) break; if (size == SOCKET_ERROR) break; } } */ // Destroy the socket of d00m. #if defined(_WIN32) || defined(_WIN64) if (closesocket(properties.handle) == SOCKET_ERROR) { SLOG("[CSocket::destroy] closesocket "); #else if (close(properties.handle) == SOCKET_ERROR) { SLOG("[CSocket::destroy] close "); #endif SLOG("returned error: %s\n", errorMessage(identifyError())); } // Reset the socket state. properties.handle = INVALID_SOCKET; properties.state = SOCKET_STATE_DISCONNECTED; } int CSocket::reconnect(long delay, int tries) { int socket_reconnect_delay = delay; int socket_reconnect_attempts = tries; if (delay == 0) delay = socket_reconnect_delay; if (tries == 0) tries = socket_reconnect_attempts; for (int i = 0; i < tries; i++) { switch (this->connect()) { case SOCKET_OK: case SOCKET_ALREADY_CONNECTED: return SOCKET_OK; break; case SOCKET_INVALID: case SOCKET_BIND_ERROR: case SOCKET_CONNECT_ERROR: default: // Do nothing. break; } if (delay != 0) sleep(delay); } return SOCKET_CONNECT_ERROR; }
int CSocket::connect() { // Make sure the socket is disconnected. if (properties.state != SOCKET_STATE_DISCONNECTED) return SOCKET_ALREADY_CONNECTED; // Flag the socket as connecting. properties.state = SOCKET_STATE_CONNECTING; // Create socket. if (properties.protocol == SOCKET_PROTOCOL_TCP) properties.handle = socket(AF_INET, SOCK_STREAM, 0); else properties.handle = socket(AF_INET, SOCK_DGRAM, 0); // Make sure the socket was created correctly. if (properties.handle == INVALID_SOCKET) { SLOG("[CSocket::connect] socket() returned INVALID_SOCKET.\n"); properties.state = SOCKET_STATE_DISCONNECTED; return SOCKET_INVALID; } // Bind the socket if it is a server-type socket. if (properties.type == SOCKET_TYPE_SERVER) { // Let us reuse the address. Freaking bind. int value = 1; setsockopt(properties.handle, SOL_SOCKET, SO_REUSEADDR, (char*)&value, sizeof(value)); // Bind the socket. if (::bind(properties.handle, (struct sockaddr *)&properties.address, sizeof(properties.address)) == SOCKET_ERROR) { SLOG("[CSocket::connect] bind() returned error: %s\n", errorMessage(identifyError())); disconnect(); return SOCKET_BIND_ERROR; } } // Connect the socket. if (properties.type != SOCKET_TYPE_SERVER) { if (::connect(properties.handle, (struct sockaddr *)&properties.address, sizeof(properties.address)) == SOCKET_ERROR) { SLOG("[CSocket::connect] connect() returned error: %s\n", errorMessage(identifyError())); disconnect(); return SOCKET_CONNECT_ERROR; } } // Disable the nagle algorithm. if (properties.protocol == SOCKET_PROTOCOL_TCP) { int nagle = 1; setsockopt(properties.handle, IPPROTO_TCP, TCP_NODELAY, (char*)&nagle, sizeof(nagle)); } // Set as non-blocking. #if defined(_WIN32) || defined(_WIN64) u_long flags = 1; ioctlsocket(properties.handle, FIONBIO, &flags); #else int flags = fcntl(properties.handle, F_GETFL, 0); fcntl(properties.handle, F_SETFL, flags | O_NONBLOCK); #endif // Socket connected! properties.state = SOCKET_STATE_CONNECTED; // Listening sockets. if (properties.type == SOCKET_TYPE_SERVER) { if (properties.protocol == SOCKET_PROTOCOL_UDP) properties.state = SOCKET_STATE_LISTENING; else if (properties.protocol == SOCKET_PROTOCOL_TCP) { if (::listen(properties.handle, SOMAXCONN) == SOCKET_ERROR) { SLOG("[CSocket::connect] listen() returned error: %s\n", errorMessage(identifyError())); disconnect(); return SOCKET_CONNECT_ERROR; } properties.state = SOCKET_STATE_LISTENING; } } return SOCKET_OK; }
int CSocket::getData() { int size = 0; int intError = 0; //char buff[ 0x10000 ]; // 65536 bytes, 64KB char buff[ 0x2000 ]; // 8192 bytes, 8KB int bufflen = 0x2000; CString temp; // Make sure it is connected! if (properties.state == SOCKET_STATE_DISCONNECTED) return SOCKET_ERROR; do { // Make sure there is data to be read. // If size == bufflen, that means there may be more data. Just in case, // call select so blocking sockets don't block. if (size == 0 || size == bufflen) { fd_set set; struct timeval tm; tm.tv_sec = tm.tv_usec = 0; FD_ZERO(&set); FD_SET(properties.handle, &set); select(properties.handle + 1, &set, 0, 0, &tm); if (!FD_ISSET(properties.handle, &set)) return temp.length(); } // Allocate buff. memset((void*)buff, 0, bufflen); // Get our data if (properties.protocol == SOCKET_PROTOCOL_UDP) size = recvfrom(properties.handle, buff, bufflen, 0, 0, 0); else size = recv(properties.handle, buff, bufflen, 0); // Add to the buffer. if (size > 0) temp.write(buff, size); // Check for error! if (size == SOCKET_ERROR) { intError = identifyError(); switch (intError) { case ENETDOWN: case ENETRESET: case ENOTCONN: case EHOSTUNREACH: case ECONNABORTED: case ECONNRESET: case ETIMEDOUT: case ESHUTDOWN: // Destroy the bad socket and create a new one. disconnect(); break; default: break; } } } while (size > 0 && intError == 0); // If size is 0, the socket was disconnected. if (size == 0) disconnect(); // Add the data we just got to the buffer. if (temp.length() > 0) buffer.write(temp.text(), temp.length()); // Return the amount of data obtained. return temp.length(); }