Commit 4fecc044 authored by jan.koester's avatar jan.koester
Browse files

test

parent 7568d11d
Loading
Loading
Loading
Loading
+224 −1646

File changed.

Preview size limit exceeded, changes collapsed.

+23 −2
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

#include <array>
#include <atomic>
#include <string>
#include <memory>
@@ -48,7 +49,19 @@ typedef unsigned long ULONG_PTR;

namespace netplus {       
        enum sockettype {TCP=0,UDP=1,SSL=2};
#ifdef Windows
    struct AcceptContext {
        WSAOVERLAPPED ov{};
        SOCKET acceptSock = INVALID_SOCKET;

        // Must persist until AcceptEx completion!
        // Size recommendation: 2*(sizeof(sockaddr_storage)+16)
        static constexpr size_t ADDR_BUF_SZ =
            2 * (sizeof(SOCKADDR_STORAGE) + 16);

        alignas(void*) char addrBuf[ADDR_BUF_SZ]{};
    };
#endif
        class buffer {
        public:
            buffer(size_t bsize){
@@ -217,11 +230,13 @@ namespace netplus {
        ssl(const std::string &addr,int port,int maxconnections,int sockopts,const netplus::x509cert &cert);

        void accept(std::unique_ptr<socket> &csock) override;
        void handshake_after_accept();
        void connect(std::unique_ptr<socket> &csock) override;

        size_t sendData(buffer &data, int flags = 0) override;
        size_t recvData(buffer &data, int flags = 0) override;
#ifdef Windows
        void accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket>& csock) override;
        size_t sendDataWSA(buffer &data, int flags = 0);
        size_t recvDataWSA(buffer &data, int flags = 0);
#endif
@@ -230,9 +245,9 @@ namespace netplus {
        bool hasPendingWrite() const override {
            return !_send_record.empty(); // your TLS ciphertext buffer
        }
        netplus::x509cert _cert;
    private:
        // --- Cryptographic Components ---
        netplus::x509cert _cert;
        netplus::x509cert _peer_cert;
        netplus::rsa _rsa;

@@ -257,6 +272,9 @@ namespace netplus {

        std::vector<uint8_t> _recv_record;
        std::vector<uint8_t> _rx_netbuf;
#ifdef Windows
        std::array<char, 2 * (sizeof(SOCKADDR_STORAGE) + 16)> _acceptBuf{};
#endif
        size_t _recv_off = 0;

        std::vector<uint8_t> _handshake_transcript;
@@ -315,8 +333,11 @@ namespace netplus {
            const std::vector<uint8_t>& content
        );

        AcceptContext _acpt; 

        friend class poll;
        friend class event;
        friend class EventWorker;
        friend class EventWorkerArgs;
    };
};
+100 −46
Original line number Diff line number Diff line
@@ -3,7 +3,6 @@
#include <algorithm>
#include <iomanip>
#include <cstring>
#include <memory>
#include <vector>
#include <random>
#include <chrono>
@@ -732,18 +731,26 @@ std::vector<uint8_t> netplus::ssl::_calculateHMAC(


void netplus::ssl::accept(std::unique_ptr<socket> &csock) {
    // Legacy synchronous accept + handshake path (used when not using AcceptEx)
    tcp::accept(csock);
    if (!csock || csock->fd() == -1) return;
    if (!csock || csock->fd() == INVALID_SOCKET) return;

    ssl* cssock = static_cast<ssl*>(csock.get());

    // Fresh session state
    // Copy server credentials/state from listening socket
    cssock->_cert = this->_cert;
    cssock->_rsa  = this->_rsa;
    cssock->_send_seq = 0;
    cssock->_recv_seq = 0;
    cssock->_handshakeDone = false;
    cssock->_handshake_transcript.clear();

    // Run TLS handshake on the already-accepted socket
    cssock->handshake_after_accept();
}


void netplus::ssl::handshake_after_accept() {
// Fresh session state    cssock->_send_seq = 0;
    _recv_seq = 0;
    _handshakeDone = false;
    _handshake_transcript.clear();

    // ---- BigInt from BE bytes (RSA ciphertext) ------------------------------
    auto bigIntFromBytesBE = [&](const uint8_t* bytes, size_t len) -> rsa::bigInt {
@@ -787,7 +794,7 @@ void netplus::ssl::accept(std::unique_ptr<socket> &csock) {
    // ---- Transcript helper: for received handshake records, append rec[5..] --
    auto addToTranscript = [&](const std::vector<uint8_t>& rec) {
        if (rec.size() > 5) {
            cssock->_handshake_transcript.insert(cssock->_handshake_transcript.end(),
            _handshake_transcript.insert(_handshake_transcript.end(),
                                                 rec.begin() + 5, rec.end());
        }
    };
@@ -843,7 +850,7 @@ void netplus::ssl::accept(std::unique_ptr<socket> &csock) {
    // ---- Handshake -----------------------------------------------------------
    try {
        // 1) Read ClientHello (Handshake record)
        std::vector<uint8_t> chRec = readTlsRecord(cssock);
        std::vector<uint8_t> chRec = readTlsRecord(this);

        if (chRec.size() < 5 + 4 + 2 + 32 || chRec[0] != 0x16 || chRec[5] != 0x01) {
            throwSSL(netplus::NetException::Error, "Expected ClientHello");
@@ -851,12 +858,12 @@ void netplus::ssl::accept(std::unique_ptr<socket> &csock) {
        addToTranscript(chRec);

        // ClientRandom is at: record(5) + hsHdr(4) + version(2) = 11
        cssock->_clientRandom.assign(chRec.begin() + 11, chRec.begin() + 43);
        _clientRandom.assign(chRec.begin() + 11, chRec.begin() + 43);

        bool secureReneg = clientOfferedSecureReneg(chRec);

        // 2) Send ServerHello / Certificate / ServerHelloDone
        _sendServerHello(cssock, secureReneg);
        _sendServerHello(this, secureReneg);

        std::vector<uint8_t> certMsg;
        std::vector<uint8_t> rawCert = _cert.derData;
@@ -871,18 +878,18 @@ void netplus::ssl::accept(std::unique_ptr<socket> &csock) {
        certMsg.push_back(cLen & 0xFF);
        certMsg.insert(certMsg.end(), rawCert.begin(), rawCert.end());

        _sendHandshake(0x0b, certMsg, cssock); // Certificate
        _sendHandshake(0x0e, {}, cssock);      // ServerHelloDone
        _sendHandshake(0x0b, certMsg, this); // Certificate
        _sendHandshake(0x0e, {}, this);      // ServerHelloDone

        // 3) Read ClientKeyExchange
        std::vector<uint8_t> ckeRec = readTlsRecord(cssock);
        std::vector<uint8_t> ckeRec = readTlsRecord(this);
        if (ckeRec.size() < 11 || ckeRec[0] != 0x16 || ckeRec[5] != 0x10) {
            throwSSL(netplus::NetException::Error, "Expected ClientKeyExchange");
        }
        addToTranscript(ckeRec);

        uint16_t encLen = ((uint16_t)ckeRec[9] << 8) | (uint16_t)ckeRec[10];
        const size_t kBytes = (cssock->_rsa.n.bitLength() + 7) / 8;
        const size_t kBytes = (_rsa.n.bitLength() + 7) / 8;
        if (encLen != kBytes) {
            throwSSL(netplus::NetException::Error,
                     "RSA ciphertext length mismatch encLen=" + std::to_string(encLen) +
@@ -893,38 +900,38 @@ void netplus::ssl::accept(std::unique_ptr<socket> &csock) {
        }

        rsa::bigInt cipher = bigIntFromBytesBE(ckeRec.data() + 11, encLen);
        rsa::bigInt plainBI = cssock->_rsa.decrypt(cipher);
        rsa::bigInt plainBI = _rsa.decrypt(cipher);

        // PKCS#1 block must be exactly kBytes
        std::vector<uint8_t> pkcs1 = netplus::bigIntToBytesBE(plainBI, kBytes);
        std::vector<uint8_t> preMasterSecret = extractPreMasterFromPkcs1(pkcs1);

        // 4) Key derivation (TLS 1.2 PRF uses SHA256; MAC is HMAC-SHA1 for AES128-SHA)
        std::vector<uint8_t> msSeed = cssock->_clientRandom;
        msSeed.insert(msSeed.end(), cssock->_serverRandom.begin(), cssock->_serverRandom.end());
        std::vector<uint8_t> msSeed = _clientRandom;
        msSeed.insert(msSeed.end(), _serverRandom.begin(), _serverRandom.end());
        std::vector<uint8_t> masterSecret = _prf(preMasterSecret, "master secret", msSeed, 48);

        std::vector<uint8_t> kbSeed = cssock->_serverRandom;
        kbSeed.insert(kbSeed.end(), cssock->_clientRandom.begin(), cssock->_clientRandom.end());
        std::vector<uint8_t> kbSeed = _serverRandom;
        kbSeed.insert(kbSeed.end(), _clientRandom.begin(), _clientRandom.end());
        std::vector<uint8_t> keyBlock = _prf(masterSecret, "key expansion", kbSeed, 72);

        size_t off = 0;
        cssock->_client_mac_key.assign(keyBlock.begin() + off, keyBlock.begin() + off + 20); off += 20; // client_write_MAC
        cssock->_mac_key.assign(keyBlock.begin() + off, keyBlock.begin() + off + 20);        off += 20; // server_write_MAC
        _client_mac_key.assign(keyBlock.begin() + off, keyBlock.begin() + off + 20); off += 20; // client_write_MAC
        _mac_key.assign(keyBlock.begin() + off, keyBlock.begin() + off + 20);        off += 20; // server_write_MAC
        std::vector<uint8_t> clientKey(keyBlock.begin() + off, keyBlock.begin() + off + 16); off += 16; // client_write_key
        std::vector<uint8_t> serverKey(keyBlock.begin() + off, keyBlock.begin() + off + 16);            // server_write_key

        cssock->_aes_recv = std::make_unique<aes>(clientKey);
        cssock->_aes      = std::make_unique<aes>(serverKey);
        _aes_recv = std::make_unique<aes>(clientKey);
        _aes      = std::make_unique<aes>(serverKey);

        // 5) Read Client ChangeCipherSpec (unencrypted)
        std::vector<uint8_t> ccsRec = readTlsRecord(cssock);
        std::vector<uint8_t> ccsRec = readTlsRecord(this);
        if (ccsRec.size() != 6 || ccsRec[0] != 0x14 || ccsRec[5] != 0x01) {
            throwSSL(netplus::NetException::Error, "Expected ChangeCipherSpec");
        }

        // 6) Read Client Finished (encrypted handshake record)
        std::vector<uint8_t> finRec = readTlsRecord(cssock);
        std::vector<uint8_t> finRec = readTlsRecord(this);
        if (finRec.size() < 5 + 32 || finRec[0] != 0x16) {
            throwSSL(netplus::NetException::Error, "Expected Finished record");
        }
@@ -932,7 +939,7 @@ void netplus::ssl::accept(std::unique_ptr<socket> &csock) {
        std::vector<uint8_t> finFrag(finRec.begin() + 5, finRec.end());

        // Decrypt + verify record MAC + increment _recv_seq
        std::vector<uint8_t> finPT = _decryptRecordCBC(cssock,finRec[0], finVer, finFrag);
        std::vector<uint8_t> finPT = _decryptRecordCBC(this,finRec[0], finVer, finFrag);

        // finPT should be the Finished handshake message bytes:
        // 0x14 00 00 0C + 12 bytes
@@ -941,22 +948,22 @@ void netplus::ssl::accept(std::unique_ptr<socket> &csock) {
        }

        // Verify client Finished verify_data using transcript hash BEFORE adding Finished
        std::vector<uint8_t> th = _sha256_hash(cssock->_handshake_transcript);
        std::vector<uint8_t> th = _sha256_hash(_handshake_transcript);
        std::vector<uint8_t> expectedClient = _prf(masterSecret, "client finished", th, 12);
        if (!std::equal(expectedClient.begin(), expectedClient.end(), finPT.begin() + 4)) {
            throwSSL(netplus::NetException::Error, "client Finished verify_data mismatch");
        }

        // Now add client's Finished handshake message to transcript
        cssock->_handshake_transcript.insert(cssock->_handshake_transcript.end(), finPT.begin(), finPT.end());
        _handshake_transcript.insert(_handshake_transcript.end(), finPT.begin(), finPT.end());

        // 7) Send Server ChangeCipherSpec (unencrypted)
        std::vector<uint8_t> sccs = { 0x14, 0x03, 0x03, 0x00, 0x01, 0x01 };
        buffer sccsBuf((const char*)sccs.data(), sccs.size());
        cssock->tcp::sendData(sccsBuf);
        tcp::sendData(sccsBuf);

        // 8) Send Server Finished (encrypted handshake record)
        std::vector<uint8_t> th2 = _sha256_hash(cssock->_handshake_transcript);
        std::vector<uint8_t> th2 = _sha256_hash(_handshake_transcript);
        std::vector<uint8_t> verifyServer = _prf(masterSecret, "server finished", th2, 12);

        std::vector<uint8_t> sFin; // handshake message bytes
@@ -966,22 +973,76 @@ void netplus::ssl::accept(std::unique_ptr<socket> &csock) {
        sFin.insert(sFin.end(), verifyServer.begin(), verifyServer.end());

        // Add server Finished to transcript (because we send it)
        cssock->_handshake_transcript.insert(cssock->_handshake_transcript.end(), sFin.begin(), sFin.end());
        _handshake_transcript.insert(_handshake_transcript.end(), sFin.begin(), sFin.end());

        // Encrypt+MAC as TLS record type Handshake (0x16)
        _sendEncryptedRecord(cssock,0x16, sFin);
        _sendEncryptedRecord(this,0x16, sFin);

        cssock->_handshakeDone = true;
        _handshakeDone = true;
        std::cerr << "SSL Handshake Accepted and Secure" << std::endl;

    } catch (const netplus::NetException& e) {
        std::cerr << "SSL Accept Error: " << e.what() << std::endl;
        csock->close();
        close();
    } catch (const std::exception& e) {
        throwSSL(netplus::NetException::Error, e.what());
    }

}



#ifdef Windows
void netplus::ssl::accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket>& csock) {
    NetException exception;

    // Ensure accepted socket object exists (per-connection ssl instance)
    if (!csock) {
        csock = std::make_unique<netplus::ssl>(this->_cert);
    }
    ssl* cssock = static_cast<ssl*>(csock.get());

    // Create accept socket (overlapped)
    const addrinfo* ai = reinterpret_cast<const addrinfo*>(this->_SocketInfo);
    cssock->_Socket = WSASocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, nullptr, 0, WSA_FLAG_OVERLAPPED);
    if (cssock->_Socket == INVALID_SOCKET) {
        int err = WSAGetLastError();
        exception[NetException::Error] << "AcceptEx: WSASocket failed: " << err;
        throw exception;
    }

    // Copy server credentials/state from listener; handshake will be run after AcceptEx completion
    cssock->_cert = this->_cert;
    cssock->_rsa  = this->_rsa;

    // Post AcceptEx (addr buffer must live until completion -> stored in cssock->_acceptBuf)
    DWORD dwbytes = 0;
    std::memset(&cssock->_Overlapped, 0, sizeof(cssock->_Overlapped));
    const BOOL ok = lpfnAcceptEx(
        (SOCKET)this->_Socket,              // listen socket
        (SOCKET)cssock->_Socket,            // accept socket
        cssock->_acceptBuf.data(),          // persistent buffer
        0,
        sizeof(SOCKADDR_STORAGE) + 16,
        sizeof(SOCKADDR_STORAGE) + 16,
        &dwbytes,
        &cssock->_Overlapped
    );

    if (!ok) {
        int err = WSAGetLastError();
        if (err == WSA_IO_PENDING) return; // async path

        closesocket((SOCKET)cssock->_Socket);
        cssock->_Socket = INVALID_SOCKET;

        exception[NetException::Error] << "AcceptEx failed: " << err;
        throw exception;
    }

    // Synchronous completion is possible; completion handler will still run.
}
#endif
void netplus::ssl::connect(std::unique_ptr<socket> &csock) {
    // 0) Establish underlying TCP connection
    tcp::connect(csock);
@@ -1777,16 +1838,9 @@ bool loadServerPrivateKeyDer(const std::string& keyDerPath);

#ifdef Windows
size_t netplus::ssl::sendDataWSA(buffer& data, int flags) {
    // 1) During handshake we may still need to write bytes, but under IOCP we
    // must NOT call tcp::sendDataWSA here (it would post its own OVERLAPPED).
    // Instead, queue raw bytes into _send_record and let the IOCP layer WSASend it.
    // 1) During handshake, we send raw TCP (usually for ServerHello/Certificates)
    if (!_handshakeDone) {
        if (!_send_record.empty() && _send_off < _send_record.size()) return 0;
        if (data.size == 0) return 0;
        const size_t take = (std::min)((size_t)data.size, (size_t)16384);
        _send_record.assign((const uint8_t*)data.data.buf, (const uint8_t*)data.data.buf + take);
        _send_off = 0;
        return take;
        return tcp::sendDataWSA(data, flags);
    }

    auto throwSSL = [&](int etype, const std::string& msg) -> void {
@@ -1862,7 +1916,7 @@ size_t netplus::ssl::sendDataWSA(buffer& data, int flags) {
    buffer out((const char*)_send_record.data(), _send_record.size());
    
    // This call triggers WSASend with the Overlapped structure.
    // NOTE: Do not send here. IOCP EventWorker will WSASend _send_record.
    tcp::sendDataWSA(out, flags);

    // Return 'take' to inform the application how many plaintext bytes were consumed
    return take;
+17 −39
Original line number Diff line number Diff line
@@ -85,7 +85,7 @@ netplus::udp::udp(const std::string &addr, int port, int maxconnections, int soc

    if (_Socket == INVALID_SOCKET) {
        ::freeaddrinfo(result);
        exception[NetException::Critical] << "Create Socket " << (int)_Socket << " failed : " << GetLastError();
        exception[NetException::Critical] << "Create Socket " << (int)_Socket << " failed : " << WSAGetLastError();
        throw exception;
    }

@@ -152,43 +152,21 @@ void netplus::udp::accept(std::unique_ptr<socket> &csock) {
        (LPINT)&((struct addrinfo*)csock->_SocketInfo)->ai_addrlen, nullptr, 0);
    if (csock->_Socket == SOCKET_ERROR) {
        int etype = NetException::Error;
        if (GetLastError() == WSA_IO_PENDING)
        if (WSAGetLastError() == WSA_IO_PENDING)
            etype = NetException::Note;

        exception[etype] << "Can't accept on Socket: " << GetLastError();
        exception[etype] << "Can't accept on Socket: " << WSAGetLastError();
        throw exception;
    }
}

void netplus::udp::accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket> &csock) {
    (void)lpfnAcceptEx;
    (void)csock;
    NetException exception;
    DWORD dwbytes = 0;
    CHAR AcceptBuffer[2 * (sizeof(SOCKADDR_IN6) + 16)];

    copyAddrInfo(&csock->_SocketInfo, _SocketInfo, _SocketInfoLen);

    memset(((struct addrinfo*)csock->_SocketInfo)->ai_addr, 0, ((struct addrinfo*)csock->_SocketInfo)->ai_addrlen);

    ((struct sockaddr_in*)((struct addrinfo*)csock->_SocketInfo)->ai_addr)->sin_port =
        ((struct sockaddr_in*)((struct addrinfo*)_SocketInfo)->ai_addr)->sin_port;

    if ((csock->_Socket = WSASocket(((struct addrinfo*)_SocketInfo)->ai_family,
        ((struct addrinfo*)_SocketInfo)->ai_socktype, 0, nullptr, 0, WSA_FLAG_OVERLAPPED)) < 0) {
        exception[NetException::Error] << "Accept create Socket faied: failed on " << (int)csock->_Socket << " error code : " << GetLastError();
        throw exception;
    }

    if (!lpfnAcceptEx(_Socket, csock->_Socket, &AcceptBuffer, 0,
        sizeof(SOCKADDR_IN6) + 16, sizeof(SOCKADDR_IN6) + 16, &dwbytes, &csock->_Overlapped)) {

        int etype = NetException::Error;
        if (GetLastError() == WSA_IO_PENDING)
            return;

        exception[etype] << "AcceptEX: failed on " << (int)csock->_Socket << " error code : " << GetLastError();
    exception[NetException::Error] << "udp::accept(AcceptEx) not supported (AcceptEx is TCP-only)";
    throw exception;
}
}

void netplus::udp::bind() {
    NetException exception;
@@ -227,13 +205,13 @@ size_t netplus::udp::sendData(buffer &data, int flags) {
            if (_Wait) {
                // Wait for the overlapped I/O operation to complete.
                if (WSAWaitForMultipleEvents(1, &_Overlapped.hEvent, FALSE, _Timeout, FALSE) == WSA_WAIT_FAILED) {
                    exception[NetException::Error] << "WSAWaitForMultipleEvents failed: " << GetLastError();
                    exception[NetException::Error] << "WSAWaitForMultipleEvents failed: " << WSAGetLastError();
                    throw exception;
                }

                // Get the final result of the overlapped operation.
                if (!WSAGetOverlappedResult(_Socket, &_Overlapped, &dwBytes, FALSE, (LPDWORD)&flags)) {
                    exception[NetException::Error] << "WSAGetOverlappedResult failed: " << GetLastError();
                    exception[NetException::Error] << "WSAGetOverlappedResult failed: " << WSAGetLastError();
                    throw exception;
                }
            }
@@ -282,13 +260,13 @@ size_t netplus::udp::recvData(buffer &data, int flags) {
            case WSA_IO_PENDING:
                if(_Wait){
                    if (WSAWaitForMultipleEvents(1, &_Overlapped.hEvent, FALSE, _Timeout, FALSE) == WSA_WAIT_FAILED) {
                        exception[NetException::Error] << "WSAWaitForMultipleEvents failed: " << GetLastError();
                        exception[NetException::Error] << "WSAWaitForMultipleEvents failed: " << WSAGetLastError();
                        throw exception;
                    }
                    // Once the wait completes, get the final result.
                    if (!WSAGetOverlappedResult(_Socket, &_Overlapped, &dwBytes, FALSE, (LPDWORD)&flags)) {
                        // An error occurred during the overlapped operation.
                        exception[NetException::Error] << "WSAGetOverlappedResult failed: " << GetLastError();
                        exception[NetException::Error] << "WSAGetOverlappedResult failed: " << WSAGetLastError();
                        throw exception;
                    }
                }
@@ -298,10 +276,10 @@ size_t netplus::udp::recvData(buffer &data, int flags) {
            case WSAECONNRESET:
                // It's not a connected socket, so these errors are less relevant for UDP.
                // But we'll keep the logic.
                exception[NetException::Error] << "Socket recvData failed: " << GetLastError();
                exception[NetException::Error] << "Socket recvData failed: " << WSAGetLastError();
                throw exception;
            default:
                exception[NetException::Error] << "Socket recvData failed some Error on Socket: " << GetLastError();
                exception[NetException::Error] << "Socket recvData failed some Error on Socket: " << WSAGetLastError();
                throw exception;
        }
    }
@@ -317,19 +295,19 @@ void netplus::udp::connect(std::unique_ptr<socket> &csock) {
    if ((_Socket = ::WSASocket(((struct addrinfo*)_SocketInfo)->ai_family, ((struct addrinfo*)_SocketInfo)->ai_socktype,
        ((struct addrinfo*)_SocketInfo)->ai_protocol, nullptr, 0, WSA_FLAG_OVERLAPPED)) < 0) {
        NetException exception;
        exception[NetException::Error] << "Create Socket " << (int)_Socket << " failed : " << GetLastError();
        exception[NetException::Error] << "Create Socket " << (int)_Socket << " failed : " << WSAGetLastError();
        throw exception;
    }

    if (::WSAConnect(_Socket, ((struct addrinfo*)csock->_SocketInfo)->ai_addr,
        (int)((struct addrinfo*)csock->_SocketInfo)->ai_addrlen, nullptr, nullptr, nullptr, nullptr) < 0) {
        exception[NetException::Error] << "Socket connect: can't connect to server aborting " << " ErrorMsg:" << GetLastError();
        exception[NetException::Error] << "Socket connect: can't connect to server aborting " << " ErrorMsg:" << WSAGetLastError();
        throw exception;
    }

    if (::getpeername(_Socket, ((struct addrinfo*)_SocketInfo)->ai_addr, (int*)&((struct addrinfo*)_SocketInfo)->ai_addrlen) < 0) {
        NetException exception;
        exception[NetException::Error] << "Connect: getpeername failed on " << (int)_Socket << " error code : " << GetLastError();
        exception[NetException::Error] << "Connect: getpeername failed on " << (int)_Socket << " error code : " << WSAGetLastError();
        throw exception;
    }