#define INCLUDE_SSL #include "Client.h" #ifndef WIN32 # include # include # include #endif #include #include #include using namespace Network; // Content of the Client class from Client.h // Constructor Client::Client() : ReferenceCounter(), errorOccured(0) { memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; downStreamBytes = 0; upStreamBytes = 0; sock = 0; sendKey = 0; receiveKey = 0; } // Destructor Client::~Client() { if (sock) disconnect(); if (sendKey) sendKey->release(); if (receiveKey) receiveKey->release(); } // non-constant void Client::setSendKeyZ(Encryption::Key* key) // Sets the key for sending { if (sendKey) sendKey->release(); sendKey = key; } void Client::setReceiveKeyZ( Encryption::Key* key) // Sets the key for receiving { if (receiveKey) receiveKey->release(); receiveKey = key; } void Client::setSendKey(const char* key, int len) // Sets the key for sending { if (!sendKey) sendKey = new Encryption::Key(); sendKey->setKey(key, len); } void Client::setReceiveKey( const char* key, int len) // Sets the key for receiving { if (!receiveKey) receiveKey = new Encryption::Key(); receiveKey->setKey(key, len); } bool Client::connect( unsigned short port, const char* ip) // connects to server { if (sendKey) sendKey->setPos(0); if (receiveKey) receiveKey->setPos(0); if (sock) closesocket(sock); sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); long sIp = inet_addr(ip); // ip address if (sIp == INADDR_NONE) { struct hostent* pHostInfo = gethostbyname(ip); if (pHostInfo == 0) return 0; sIp = *(long*)pHostInfo->h_addr_list[0]; } memcpy((char*)&server.sin_addr, &sIp, sizeof(sIp)); server.sin_port = htons(port); // port if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) // connect { errorOccured = 1; return 0; // Error } errorOccured = 0; return 1; } bool Client::send(const char* message, int len) // sends to server { int ll = 0; while (len > 0) { #ifdef WIN32 int l = send(sock, message + ll, len, 0); #else int l = (int)send(sock, message + ll, len, MSG_NOSIGNAL); #endif if (l <= 0) { #ifdef WIN32 # ifdef _DEBUG Framework::Logging::warning() << "send: " << l << " Error: " << WSAGetLastError(); # endif #endif errorOccured = 1; return 0; // Error } len -= l; ll += l; } upStreamBytes += ll; return 1; } bool Client::getMessage(char* message, int len) // receives message { int ll = 0; while (len > 0) { int l = (int)recv(sock, message + ll, len, MSG_WAITALL); if (l <= 0) { #ifdef WIN32 # ifdef _DEBUG Framework::Logging::warning() << "recv: " << l << " Error: " << WSAGetLastError(); # endif #endif errorOccured = 1; return 0; // Error } len -= l; ll += l; } downStreamBytes += ll; return 1; } bool Client::sendEncrypted(const char* message, int len) // sends to server { if (!sendKey) return send(message, len); Encryption::Bytes* n = new Encryption::Bytes(message, len); sendKey->codieren( dynamic_cast(n->getThis())); int ll = 0; while (len > 0) { #ifdef WIN32 int l = send(sock, n->getBytes() + ll, len, 0); #else int l = (int)send(sock, n->getBytes() + ll, len, MSG_NOSIGNAL); #endif if (l <= 0) { #ifdef WIN32 # ifdef _DEBUG Framework::Logging::warning() << "send: " << l << " Error: " << WSAGetLastError(); # endif #endif n->release(); errorOccured = 1; return 0; // Error } len -= l; ll += l; } upStreamBytes += ll; n->release(); return 1; } bool Client::getMessageEncrypted( char* message, int len) // receives message { if (!receiveKey) return getMessage(message, len); int ll = 0; while (len > 0) { int l = (int)recv(sock, message + ll, len, MSG_WAITALL); if (l <= 0) { #ifdef WIN32 # ifdef _DEBUG Framework::Logging::warning() << "recv: " << l << " Error: " << WSAGetLastError(); # endif #endif errorOccured = 1; return 0; // Error } len -= l; ll += l; } Encryption::Bytes* n = new Encryption::Bytes(); n->setBytesZ(message, ll); receiveKey->decodieren(n); downStreamBytes += ll; return 1; } int Client::getDownloadBytes( bool reset) // returns the number of received bytes { int ret = downStreamBytes; if (reset) downStreamBytes = 0; return ret; } int Client::getUploadBytes( bool reset) // returns the number of sent bytes { int ret = upStreamBytes; if (reset) upStreamBytes = 0; return ret; } bool Client::disconnect() // Disconnects from server { if (!sock) return 1; if (sendKey) sendKey->setPos(0); if (receiveKey) receiveKey->setPos(0); if (closesocket(sock) < 0) // disconnect { errorOccured = 1; return 0; // Error } sock = 0; return 1; } // constant bool Client::hasMessage(int time) // Waits for a message for a given time { fd_set set; FD_ZERO(&set); FD_SET(sock, &set); timeval time = {time / 1000, time}; int result = select(0, &set, 0, 0, &time); if (result < 0) { #ifdef WIN32 # ifdef _DEBUG Framework::Logging::warning() << "select: " << result << " Error: " << WSAGetLastError(); # endif #endif } return result > 0; } unsigned short Client::getServerPort() const // returns the port { return htons(server.sin_port); } const char* Client::getServerIp() const // returns the IP { return inet_ntoa(server.sin_addr); } bool Client::waitForNextMessage() const // waits until there is something to receive { fd_set set; int rv = 0; struct timeval timeout; while (rv == 0 && sock) { FD_ZERO(&set); /* clear the set */ FD_SET(sock, &set); /* add our file descriptor to the set */ timeout.tv_sec = 10; timeout.tv_usec = 0; rv = select((int)sock + 1, &set, NULL, NULL, &timeout); if (rv == -1) { #ifdef WIN32 # ifdef _DEBUG Framework::Logging::warning() << "select: " << rv << " Error: " << WSAGetLastError(); # endif #endif return 0; } } if (!sock) return 0; char c; #ifdef WIN32 int l = (int)recv(sock, &c, 1, MSG_PEEK); #else int l = (int)recv(sock, &c, 1, MSG_WAITALL | MSG_PEEK); #endif if (l <= 0) { #ifdef WIN32 # ifdef _DEBUG Framework::Logging::warning() << "recv: " << l << " Error: " << WSAGetLastError(); # endif #endif return 0; // Error } return 1; } bool Client::isConnected() const // returns true if a connection exists { return sock != 0 && !errorOccured; } // Content of the SSLClient class from Client.h // Constructor SSLClient::SSLClient() : ReferenceCounter() { ctx = SSL_CTX_new(TLS_client_method()); SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION); ip = 0; port = 0; bio = BIO_new_ssl_connect(ctx); BIO_get_ssl(bio, &ssl); downStreamBytes = 0; upStreamBytes = 0; connected = 0; } // Destructor SSLClient::~SSLClient() { if (this->ip) this->ip->release(); if (connected) disconnect(); BIO_free_all(bio); SSL_CTX_free(ctx); #ifdef WIN32 OPENSSL_thread_stop(); #endif } bool SSLClient::connect( unsigned short port, const char* ip) // connects to server { this->port = port; if (this->ip) this->ip->release(); this->ip = new Text(ip); Text adr = ip; adr += ":"; adr += port; BIO_set_conn_hostname(bio, (const char*)adr); connected = BIO_do_connect(bio) > 0; if (connected && BIO_do_handshake(bio) <= 0) disconnect(); return connected; } bool SSLClient::send(const char* message, int len) // sends to server { int ll = 0; while (len > 0) { int l = SSL_write(ssl, message + ll, len); if (l <= 0) { #ifdef _DEBUG Framework::Logging::warning() << "SSL_write: " << l << " Error: " << SSL_get_error(ssl, l); #endif return 0; // Error } len -= l; ll += l; } upStreamBytes += ll; return 1; } bool SSLClient::getMessage(char* message, int len) // receives message { if (!connected) return 0; int ll = 0; while (len > 0) { int l = SSL_read(ssl, message + ll, len); if (l <= 0) { #ifdef _DEBUG Framework::Logging::warning() << "SSL_read: " << l << " Error: " << SSL_get_error(ssl, l); #endif return 0; // Error } len -= l; ll += l; } downStreamBytes += ll; return 1; } int SSLClient::getDownloadBytes( bool reset) // returns the number of received bytes { int ret = downStreamBytes; if (reset) downStreamBytes = 0; return ret; } int SSLClient::getUploadBytes( bool reset) // returns the number of sent bytes { int ret = upStreamBytes; if (reset) upStreamBytes = 0; return ret; } bool SSLClient::disconnect() // Disconnects from server { BIO_ssl_shutdown(bio); connected = 0; return 1; } // constant bool SSLClient::hasMessage( int time) // Waits for a message for a given time { fd_set set; FD_ZERO(&set); FD_SET(SSL_get_rfd(ssl), &set); timeval time = {time / 1000, time}; return SSL_pending(ssl) > 0 || select(0, &set, 0, 0, &time) == 1; } unsigned short SSLClient::getServerPort() const // returns the server port { return port; } const char* SSLClient::getServerIp() const // returns the server IP { return ip->getText(); }