Loading src/event/iocp.cpp +180 −23 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #include <iostream> #include <iomanip> #include <algorithm> #include <chrono> #include <mutex> Loading Loading @@ -212,70 +213,226 @@ namespace netplus { if (!ov) continue; // -------------------------------------------------------------------- // 1) AcceptEx completions arrive on the IOCP with key == listenerKey // DO NOT cast key to client* in that case. // -------------------------------------------------------------------- if (key == eargs->listenerKey) { std::unique_ptr<socket> accepted; { std::lock_guard<std::mutex> lk(ACCEPT_MTX); auto it = ACCEPT_PENDING.find(ov); if (it != ACCEPT_PENDING.end()) { accepted = std::move(it->second); ACCEPT_PENDING.erase(it); } } if (!accepted) { std::cerr << "[IOCP] AcceptEx completion: no pending entry for ov=" << ov << "\n"; continue; } SOCKET accSock = (SOCKET)accepted->fd(); std::cerr << "[IOCP] AcceptEx completion: accepted fd=" << accSock << " ov=" << ov << " bytes=" << bytes << "\n"; setsockopt(accSock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char*)&eargs->listenSock, sizeof(eargs->listenSock)); // Build client connection client* pClient = new client(eargs->event); pClient->CurCon->csock = std::move(accepted); // Associate accepted socket with IOCP using key = pClient HANDLE h = CreateIoCompletionPort( (HANDLE)(uintptr_t)pClient->CurCon->csock->fd(), eargs->eviocp, (ULONG_PTR)pClient, 0); if (!h) { std::cerr << "[IOCP] CreateIoCompletionPort(accepted) failed fd=" << pClient->CurCon->csock->fd() << " err=" << GetLastError() << "\n"; eargs->event->DisconnectEvent(*pClient->CurCon, tid, (ULONG_PTR)eargs->args); delete pClient; } else { std::cerr << "[IOCP] calling ConnectEvent for fd=" << pClient->CurCon->csock->fd() << "\n"; eargs->event->ConnectEvent(*pClient->CurCon, tid, (ULONG_PTR)eargs->args); // Start reading raw bytes immediately (TLS handshake will be stepped from OP_READ) start_read(pClient); } // Re-post AcceptEx try { std::unique_ptr<socket> nextSock; static_cast<ssl*>(eargs->ssocket)->accept(eargs->lpfnAcceptEx, nextSock); { std::lock_guard<std::mutex> lk(ACCEPT_MTX); ACCEPT_PENDING.emplace(&nextSock->_Overlapped, std::move(nextSock)); std::cerr << "[IOCP] Re-posted AcceptEx; pending_count=" << ACCEPT_PENDING.size() << "\n"; } } catch (NetException& e) { std::cerr << "AcceptEx repost error: " << e.what() << "\n"; } continue; } // -------------------------------------------------------------------- // 2) Normal client completions: key is client* // -------------------------------------------------------------------- client* ctx = reinterpret_cast<client*>(key); if (!ctx || !ctx->CurCon || !ctx->CurCon->csock) { std::cerr << "[IOCP] ERROR: invalid client key=" << (void*)key << " ov=" << ov << "\n"; continue; } IO_CONTEXT* io = CONTAINING_RECORD(ov, IO_CONTEXT, overlapped); con& c = *ctx->CurCon; if (!ok || bytes == 0) { eargs->event->DisconnectEvent(c, tid, args); std::cerr << "[IOCP] closed/error fd=" << c.csock->fd() << " ok=" << ok << " bytes=" << bytes << " err=" << GetLastError() << "\n"; eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args); delete ctx; continue; } try { std::lock_guard<std::mutex> lock(ctx->cltmtx); std::lock_guard<std::mutex> guard(ctx->cltmtx); if (io->operation == OP_READ) { if (c.csock->_Type == sockettype::SSL) { ssl* s = static_cast<ssl*>(c.csock.get()); // 🔴 FIX: append bytes FIRST s->_rx_netbuf.insert( s->_rx_netbuf.end(), io->buffer, io->buffer + bytes ); // Debug header for "bad TLS version" if (bytes >= 5) { const unsigned char* p = (const unsigned char*)io->buffer; std::cerr << "[IOCP][SSL] RX bytes=" << bytes << " hdr: " << std::hex << (int)p[0] << " " << (int)p[1] << " " << (int)p[2] << " " << (int)p[3] << " " << (int)p[4] << std::dec << "\n"; } else { std::cerr << "[IOCP][SSL] RX bytes=" << bytes << " (<5)\n"; } // 🔴 THEN handshake if (!s->_handshakeDone) { while (s->handshakeStepIOCP()) {} // Append ciphertext into SSL net buffer first (handshakeStepIOCP expects it there) s->_rx_netbuf.insert(s->_rx_netbuf.end(), (unsigned char*)io->buffer, (unsigned char*)io->buffer + bytes); if (!s->_hs_tx.empty()) start_write(ctx); // --- Handshake phase (IOCP stepped) --- if (!s->_handshakeDone) { bool progressed = false; for (;;) { bool step = s->handshakeStepIOCP(); // consumes at most one record per call if (!step) break; progressed = true; } // If handshake produced outbound bytes, send them using overlapped write if (!s->_hs_tx.empty() && s->_hs_tx_off < s->_hs_tx.size()) { // Kick a WSASend of handshake bytes. // Use ctx->writeCtx.overlapped, not some undefined "ctx". buffer out( (const char*)s->_hs_tx.data() + s->_hs_tx_off, (int)(s->_hs_tx.size() - s->_hs_tx_off) ); s->tcp::sendDataWSA(out, &ctx->writeCtx.overlapped, 0); } // Always post next read while handshaking start_read(ctx); continue; } // decrypt application data // --- Application phase --- buffer plain(BLOCKSIZE); size_t n = 0; while ((n = s->recvDataWSA(plain, nullptr, 0)) > 0) { c.RecvData.append(plain.data.buf, n); eargs->event->RequestEvent(c, tid, args); size_t decrypted = 0; while ((decrypted = s->recvDataWSA(plain, nullptr, 0)) > 0) { c.RecvData.append(plain.data.buf, decrypted); std::cerr << "[IOCP] RequestEvent (SSL) fd=" << c.csock->fd() << " +" << decrypted << " total=" << c.RecvData.size() << "\n"; eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args); } } else { // TCP c.RecvData.append(io->buffer, bytes); eargs->event->RequestEvent(c, tid, args); std::cerr << "[IOCP] RequestEvent (TCP) fd=" << c.csock->fd() << " +" << bytes << " total=" << c.RecvData.size() << "\n"; eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args); } // Continue I/O if (!c.SendData.empty()) start_write(ctx); else start_read(ctx); } else if (io->operation == OP_WRITE) { if (c.csock->_Type == sockettype::SSL) { ssl* s = static_cast<ssl*>(c.csock.get()); // Handshake TX in progress? if (!s->_handshakeDone && !s->_hs_tx.empty()) { s->_hs_tx_off += bytes; if (s->_hs_tx_off < s->_hs_tx.size()) { buffer out( (const char*)s->_hs_tx.data() + s->_hs_tx_off, (int)(s->_hs_tx.size() - s->_hs_tx_off) ); s->tcp::sendDataWSA(out, &ctx->writeCtx.overlapped, 0); continue; } // handshake flight fully sent s->_hs_tx.clear(); s->_hs_tx_off = 0; // keep reading to continue handshake start_read(ctx); continue; } // Normal encrypted record send bookkeeping s->_send_off += bytes; if (s->_send_off >= s->_send_record.size()) { s->_send_record.clear(); s->_send_off = 0; } } if (c.SendData.empty()) { std::cerr << "[IOCP] ResponseEvent fd=" << c.csock->fd() << " send_queue_empty\n"; eargs->event->ResponseEvent(c, tid, (ULONG_PTR)eargs->args); } if (!c.SendData.empty()) start_write(ctx); else start_read(ctx); } } catch (NetException& e) { eargs->event->DisconnectEvent(c, tid, args); std::cerr << "[IOCP] NetException fd=" << c.csock->fd() << ": " << e.what() << "\n"; if (e.getErrorType() != NetException::Note) { eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args); delete ctx; } } } } }; void eventapi::CreateConnection(std::shared_ptr<con>& res) { Loading src/ssl.cpp +26 −0 Original line number Diff line number Diff line Loading @@ -2196,6 +2196,17 @@ bool netplus::ssl::handshakeStepIOCP() } }; auto hexDump =[](const uint8_t* p, size_t n) { std::ostringstream oss; oss << std::hex << std::setfill('0'); for (size_t i = 0; i < n; ++i) { oss << std::setw(2) << (unsigned)p[i]; if (i + 1 != n) oss << ' '; } return oss.str(); }; // ---- consume one TLS record per call (keeps IOCP stepping simple) -------- std::vector<uint8_t> rec; if (!tryPopTlsRecord(rec)) return false; // need more ciphertext Loading @@ -2207,8 +2218,23 @@ bool netplus::ssl::handshakeStepIOCP() const uint16_t len = (uint16_t(rec[3]) << 8) | uint16_t(rec[4]); if (ver != 0x0303) { // rec includes the popped TLS record (5+len bytes) const size_t showRec = (std::min<size_t>)(rec.size(), 32); std::cerr << "[TLS-HS] bad ver=" << std::hex << ver << std::dec << " ct=" << (int)ct << " len=" << len << " rec[0..]=" << hexDump(rec.data(), showRec) << "\n"; // also show current remaining buffered ciphertext after popping this record const size_t showBuf = (std::min<size_t>)(_rx_netbuf.size(), (size_t)32); std::cerr << "[TLS-HS] rx_netbuf(rem)=" << _rx_netbuf.size() << " bytes: " << (showBuf ? hexDump(_rx_netbuf.data(), showBuf) : std::string("(empty)")) << "\n"; throwSSL(netplus::NetException::Error, "bad TLS version during handshake"); } if (rec.size() != size_t(5 + len)) { throwSSL(netplus::NetException::Error, "TLS record length mismatch"); } Loading src/windows/ssl.cpp +19 −7 Original line number Diff line number Diff line Loading @@ -282,31 +282,43 @@ namespace netplus { // ---- TLS record reader --------------------------------------------------- std::vector<uint8_t> readTlsRecord(netplus::ssl* s) { uint8_t hdr[5] = { 0xAA,0xAA,0xAA,0xAA,0xAA }; uint8_t hdr[5] = { 0 }; readExactRaw(*s, hdr, 5); if (hdr[1] != 0x0303) { const uint8_t type = hdr[0]; const uint16_t ver = (uint16_t(hdr[1]) << 8) | uint16_t(hdr[2]); const uint16_t len = (uint16_t(hdr[3]) << 8) | uint16_t(hdr[4]); // TLS/SSLv3 record major must be 0x03 if (hdr[1] != 0x03) { netplus::NetException e; e[netplus::NetException::Error] << "ssl::accept: bad TLS major version"; e[netplus::NetException::Error] << "ssl::accept: bad TLS major byte: 0x" << std::hex << int(hdr[1]); throw e; } size_t len = (size_t(hdr[3]) << 8) | size_t(hdr[4]); // Accept legacy record-layer versions (very common: 0x0301 even for TLS1.2 ClientHello) // Allow: TLS1.0..TLS1.2 record versions if (ver < 0x0301 || ver > 0x0303) { netplus::NetException e; e[netplus::NetException::Error] << "ssl::accept: unsupported TLS record version: 0x" << std::hex << ver; throw e; } // sanity on len (keep your existing limits) static constexpr size_t TLS_MAX_PLAINTEXT = 16384; static constexpr size_t TLS_MAX_CBC_OVERHEAD = 2048; static constexpr size_t TLS_MAX_RECORD = TLS_MAX_PLAINTEXT + TLS_MAX_CBC_OVERHEAD; if (len == 0 || len > TLS_MAX_RECORD) { netplus::NetException e; e[netplus::NetException::Error] << "ssl::accept: invalid TLS record length " << len; e[netplus::NetException::Error] << "ssl::accept: invalid TLS record length " << std::dec << len; throw e; } std::vector<uint8_t> rec(5 + len); std::memcpy(rec.data(), hdr, 5); readExactRaw(*s, rec.data() + 5, len); return rec; } Loading Loading
src/event/iocp.cpp +180 −23 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #include <iostream> #include <iomanip> #include <algorithm> #include <chrono> #include <mutex> Loading Loading @@ -212,70 +213,226 @@ namespace netplus { if (!ov) continue; // -------------------------------------------------------------------- // 1) AcceptEx completions arrive on the IOCP with key == listenerKey // DO NOT cast key to client* in that case. // -------------------------------------------------------------------- if (key == eargs->listenerKey) { std::unique_ptr<socket> accepted; { std::lock_guard<std::mutex> lk(ACCEPT_MTX); auto it = ACCEPT_PENDING.find(ov); if (it != ACCEPT_PENDING.end()) { accepted = std::move(it->second); ACCEPT_PENDING.erase(it); } } if (!accepted) { std::cerr << "[IOCP] AcceptEx completion: no pending entry for ov=" << ov << "\n"; continue; } SOCKET accSock = (SOCKET)accepted->fd(); std::cerr << "[IOCP] AcceptEx completion: accepted fd=" << accSock << " ov=" << ov << " bytes=" << bytes << "\n"; setsockopt(accSock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char*)&eargs->listenSock, sizeof(eargs->listenSock)); // Build client connection client* pClient = new client(eargs->event); pClient->CurCon->csock = std::move(accepted); // Associate accepted socket with IOCP using key = pClient HANDLE h = CreateIoCompletionPort( (HANDLE)(uintptr_t)pClient->CurCon->csock->fd(), eargs->eviocp, (ULONG_PTR)pClient, 0); if (!h) { std::cerr << "[IOCP] CreateIoCompletionPort(accepted) failed fd=" << pClient->CurCon->csock->fd() << " err=" << GetLastError() << "\n"; eargs->event->DisconnectEvent(*pClient->CurCon, tid, (ULONG_PTR)eargs->args); delete pClient; } else { std::cerr << "[IOCP] calling ConnectEvent for fd=" << pClient->CurCon->csock->fd() << "\n"; eargs->event->ConnectEvent(*pClient->CurCon, tid, (ULONG_PTR)eargs->args); // Start reading raw bytes immediately (TLS handshake will be stepped from OP_READ) start_read(pClient); } // Re-post AcceptEx try { std::unique_ptr<socket> nextSock; static_cast<ssl*>(eargs->ssocket)->accept(eargs->lpfnAcceptEx, nextSock); { std::lock_guard<std::mutex> lk(ACCEPT_MTX); ACCEPT_PENDING.emplace(&nextSock->_Overlapped, std::move(nextSock)); std::cerr << "[IOCP] Re-posted AcceptEx; pending_count=" << ACCEPT_PENDING.size() << "\n"; } } catch (NetException& e) { std::cerr << "AcceptEx repost error: " << e.what() << "\n"; } continue; } // -------------------------------------------------------------------- // 2) Normal client completions: key is client* // -------------------------------------------------------------------- client* ctx = reinterpret_cast<client*>(key); if (!ctx || !ctx->CurCon || !ctx->CurCon->csock) { std::cerr << "[IOCP] ERROR: invalid client key=" << (void*)key << " ov=" << ov << "\n"; continue; } IO_CONTEXT* io = CONTAINING_RECORD(ov, IO_CONTEXT, overlapped); con& c = *ctx->CurCon; if (!ok || bytes == 0) { eargs->event->DisconnectEvent(c, tid, args); std::cerr << "[IOCP] closed/error fd=" << c.csock->fd() << " ok=" << ok << " bytes=" << bytes << " err=" << GetLastError() << "\n"; eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args); delete ctx; continue; } try { std::lock_guard<std::mutex> lock(ctx->cltmtx); std::lock_guard<std::mutex> guard(ctx->cltmtx); if (io->operation == OP_READ) { if (c.csock->_Type == sockettype::SSL) { ssl* s = static_cast<ssl*>(c.csock.get()); // 🔴 FIX: append bytes FIRST s->_rx_netbuf.insert( s->_rx_netbuf.end(), io->buffer, io->buffer + bytes ); // Debug header for "bad TLS version" if (bytes >= 5) { const unsigned char* p = (const unsigned char*)io->buffer; std::cerr << "[IOCP][SSL] RX bytes=" << bytes << " hdr: " << std::hex << (int)p[0] << " " << (int)p[1] << " " << (int)p[2] << " " << (int)p[3] << " " << (int)p[4] << std::dec << "\n"; } else { std::cerr << "[IOCP][SSL] RX bytes=" << bytes << " (<5)\n"; } // 🔴 THEN handshake if (!s->_handshakeDone) { while (s->handshakeStepIOCP()) {} // Append ciphertext into SSL net buffer first (handshakeStepIOCP expects it there) s->_rx_netbuf.insert(s->_rx_netbuf.end(), (unsigned char*)io->buffer, (unsigned char*)io->buffer + bytes); if (!s->_hs_tx.empty()) start_write(ctx); // --- Handshake phase (IOCP stepped) --- if (!s->_handshakeDone) { bool progressed = false; for (;;) { bool step = s->handshakeStepIOCP(); // consumes at most one record per call if (!step) break; progressed = true; } // If handshake produced outbound bytes, send them using overlapped write if (!s->_hs_tx.empty() && s->_hs_tx_off < s->_hs_tx.size()) { // Kick a WSASend of handshake bytes. // Use ctx->writeCtx.overlapped, not some undefined "ctx". buffer out( (const char*)s->_hs_tx.data() + s->_hs_tx_off, (int)(s->_hs_tx.size() - s->_hs_tx_off) ); s->tcp::sendDataWSA(out, &ctx->writeCtx.overlapped, 0); } // Always post next read while handshaking start_read(ctx); continue; } // decrypt application data // --- Application phase --- buffer plain(BLOCKSIZE); size_t n = 0; while ((n = s->recvDataWSA(plain, nullptr, 0)) > 0) { c.RecvData.append(plain.data.buf, n); eargs->event->RequestEvent(c, tid, args); size_t decrypted = 0; while ((decrypted = s->recvDataWSA(plain, nullptr, 0)) > 0) { c.RecvData.append(plain.data.buf, decrypted); std::cerr << "[IOCP] RequestEvent (SSL) fd=" << c.csock->fd() << " +" << decrypted << " total=" << c.RecvData.size() << "\n"; eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args); } } else { // TCP c.RecvData.append(io->buffer, bytes); eargs->event->RequestEvent(c, tid, args); std::cerr << "[IOCP] RequestEvent (TCP) fd=" << c.csock->fd() << " +" << bytes << " total=" << c.RecvData.size() << "\n"; eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args); } // Continue I/O if (!c.SendData.empty()) start_write(ctx); else start_read(ctx); } else if (io->operation == OP_WRITE) { if (c.csock->_Type == sockettype::SSL) { ssl* s = static_cast<ssl*>(c.csock.get()); // Handshake TX in progress? if (!s->_handshakeDone && !s->_hs_tx.empty()) { s->_hs_tx_off += bytes; if (s->_hs_tx_off < s->_hs_tx.size()) { buffer out( (const char*)s->_hs_tx.data() + s->_hs_tx_off, (int)(s->_hs_tx.size() - s->_hs_tx_off) ); s->tcp::sendDataWSA(out, &ctx->writeCtx.overlapped, 0); continue; } // handshake flight fully sent s->_hs_tx.clear(); s->_hs_tx_off = 0; // keep reading to continue handshake start_read(ctx); continue; } // Normal encrypted record send bookkeeping s->_send_off += bytes; if (s->_send_off >= s->_send_record.size()) { s->_send_record.clear(); s->_send_off = 0; } } if (c.SendData.empty()) { std::cerr << "[IOCP] ResponseEvent fd=" << c.csock->fd() << " send_queue_empty\n"; eargs->event->ResponseEvent(c, tid, (ULONG_PTR)eargs->args); } if (!c.SendData.empty()) start_write(ctx); else start_read(ctx); } } catch (NetException& e) { eargs->event->DisconnectEvent(c, tid, args); std::cerr << "[IOCP] NetException fd=" << c.csock->fd() << ": " << e.what() << "\n"; if (e.getErrorType() != NetException::Note) { eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args); delete ctx; } } } } }; void eventapi::CreateConnection(std::shared_ptr<con>& res) { Loading
src/ssl.cpp +26 −0 Original line number Diff line number Diff line Loading @@ -2196,6 +2196,17 @@ bool netplus::ssl::handshakeStepIOCP() } }; auto hexDump =[](const uint8_t* p, size_t n) { std::ostringstream oss; oss << std::hex << std::setfill('0'); for (size_t i = 0; i < n; ++i) { oss << std::setw(2) << (unsigned)p[i]; if (i + 1 != n) oss << ' '; } return oss.str(); }; // ---- consume one TLS record per call (keeps IOCP stepping simple) -------- std::vector<uint8_t> rec; if (!tryPopTlsRecord(rec)) return false; // need more ciphertext Loading @@ -2207,8 +2218,23 @@ bool netplus::ssl::handshakeStepIOCP() const uint16_t len = (uint16_t(rec[3]) << 8) | uint16_t(rec[4]); if (ver != 0x0303) { // rec includes the popped TLS record (5+len bytes) const size_t showRec = (std::min<size_t>)(rec.size(), 32); std::cerr << "[TLS-HS] bad ver=" << std::hex << ver << std::dec << " ct=" << (int)ct << " len=" << len << " rec[0..]=" << hexDump(rec.data(), showRec) << "\n"; // also show current remaining buffered ciphertext after popping this record const size_t showBuf = (std::min<size_t>)(_rx_netbuf.size(), (size_t)32); std::cerr << "[TLS-HS] rx_netbuf(rem)=" << _rx_netbuf.size() << " bytes: " << (showBuf ? hexDump(_rx_netbuf.data(), showBuf) : std::string("(empty)")) << "\n"; throwSSL(netplus::NetException::Error, "bad TLS version during handshake"); } if (rec.size() != size_t(5 + len)) { throwSSL(netplus::NetException::Error, "TLS record length mismatch"); } Loading
src/windows/ssl.cpp +19 −7 Original line number Diff line number Diff line Loading @@ -282,31 +282,43 @@ namespace netplus { // ---- TLS record reader --------------------------------------------------- std::vector<uint8_t> readTlsRecord(netplus::ssl* s) { uint8_t hdr[5] = { 0xAA,0xAA,0xAA,0xAA,0xAA }; uint8_t hdr[5] = { 0 }; readExactRaw(*s, hdr, 5); if (hdr[1] != 0x0303) { const uint8_t type = hdr[0]; const uint16_t ver = (uint16_t(hdr[1]) << 8) | uint16_t(hdr[2]); const uint16_t len = (uint16_t(hdr[3]) << 8) | uint16_t(hdr[4]); // TLS/SSLv3 record major must be 0x03 if (hdr[1] != 0x03) { netplus::NetException e; e[netplus::NetException::Error] << "ssl::accept: bad TLS major version"; e[netplus::NetException::Error] << "ssl::accept: bad TLS major byte: 0x" << std::hex << int(hdr[1]); throw e; } size_t len = (size_t(hdr[3]) << 8) | size_t(hdr[4]); // Accept legacy record-layer versions (very common: 0x0301 even for TLS1.2 ClientHello) // Allow: TLS1.0..TLS1.2 record versions if (ver < 0x0301 || ver > 0x0303) { netplus::NetException e; e[netplus::NetException::Error] << "ssl::accept: unsupported TLS record version: 0x" << std::hex << ver; throw e; } // sanity on len (keep your existing limits) static constexpr size_t TLS_MAX_PLAINTEXT = 16384; static constexpr size_t TLS_MAX_CBC_OVERHEAD = 2048; static constexpr size_t TLS_MAX_RECORD = TLS_MAX_PLAINTEXT + TLS_MAX_CBC_OVERHEAD; if (len == 0 || len > TLS_MAX_RECORD) { netplus::NetException e; e[netplus::NetException::Error] << "ssl::accept: invalid TLS record length " << len; e[netplus::NetException::Error] << "ssl::accept: invalid TLS record length " << std::dec << len; throw e; } std::vector<uint8_t> rec(5 + len); std::memcpy(rec.data(), hdr, 5); readExactRaw(*s, rec.data() + 5, len); return rec; } Loading