Commit 3c87b5c4 authored by jan.koester's avatar jan.koester
Browse files

test

parent a16b070e
Loading
Loading
Loading
Loading
+101 −78
Original line number Diff line number Diff line
@@ -154,12 +154,54 @@ namespace netplus {

    class EventWorker {
    public:
class EventWorker {
public:
    /**
     * @brief Initiates an asynchronous read.
     * Uses the specialized WSA methods to interact with the IOCP.
     */
    static void start_read(client* ctx) {
        con& c = *ctx->CurCon;
        // Temporary buffer for the overlapped operation
        buffer buf(ctx->readCtx.buffer, BLOCKSIZE);

        if (c.csock->_Type == sockettype::TCP) {
            static_cast<tcp*>(c.csock.get())->recvDataWSA(buf, 0);
        } else if (c.csock->_Type == sockettype::UDP) {
            static_cast<udp*>(c.csock.get())->recvDataWSA(buf, 0);
        } else if (c.csock->_Type == sockettype::SSL) {
            // SSL recvDataWSA prepares the internal _rx_netbuf for ciphertext
            static_cast<ssl*>(c.csock.get())->recvDataWSA(buf, 0);
        }
    }

    /**
     * @brief Initiates an asynchronous write.
     * For SSL, this triggers encryption before the WSASend call.
     */
    static void start_write(client* ctx) {
        con& c = *ctx->CurCon;
        if (c.SendData.empty()) return;

        size_t toSend = std::min<size_t>(BLOCKSIZE, c.SendData.size());
        buffer out(c.SendData.data(), toSend);

        if (c.csock->_Type == sockettype::TCP) {
            static_cast<tcp*>(c.csock.get())->sendDataWSA(out, 0);
        } else if (c.csock->_Type == sockettype::UDP) {
            static_cast<udp*>(c.csock.get())->sendDataWSA(out, 0);
        } else if (c.csock->_Type == sockettype::SSL) {
            static_cast<ssl*>(c.csock.get())->sendDataWSA(out, 0);
        }
    }

    EventWorker(int tid, ULONG_PTR args, EventWorkerArgs* eargs) {
        while (event::Running) {
            DWORD dwBytesTransfered = 0;
            ULONG_PTR lpContext = 0;
            OVERLAPPED* pOverlapped = nullptr;

            // Wait for completion from the port
            BOOL bReturn = GetQueuedCompletionStatus(eargs->eviocp, &dwBytesTransfered,
                                                    &lpContext, &pOverlapped, eargs->timeout);

@@ -169,77 +211,58 @@ namespace netplus {
            IO_CONTEXT* pIoCtx = CONTAINING_RECORD(pOverlapped, IO_CONTEXT, overlapped);
            con& c = *pClientContext->CurCon;

                // Handle Disconnection or Errors
            // Handle Disconnection or Reset (Fixes PR_CONNECT_RESET_ERROR logic)
            if (!bReturn || (bReturn && dwBytesTransfered == 0)) {
                    eargs->event->DisconnectEvent(c, tid, args);
                eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args);
                delete pClientContext;
                continue;
            }

            try {
                std::lock_guard<std::mutex> guard(pClientContext->cltmtx);

                if (pIoCtx->operation == OP_READ) {
                    if (c.csock->_Type == sockettype::SSL) {
							// CAST required because recvData in SSL class handles the decryption state
                        ssl* sslSocket = static_cast<ssl*>(c.csock.get());

							// 1. Prepare a buffer for the plaintext
                        // Bridge: Feed ciphertext from network to SSL engine for decryption
                        buffer plain(BLOCKSIZE);

							// 2. This call takes the ciphertext (automatically filled by IOCP into _rx_netbuf)
							// and decrypts it into our 'plain' buffer.
                        size_t decrypted = sslSocket->recvData(plain, 0);

                        if (decrypted > 0) {
                            c.RecvData.append(plain.data.buf, decrypted);
								eargs->event->RequestEvent(c, tid, args);
                            eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args);
                        }

							// 3. Request more ciphertext from the wire
							sslSocket->recvDataWSA(c.RecvData, 0);
                    } else {
							// Standard TCP: Direct append and re-read
                        // Plaintext TCP/UDP
                        c.RecvData.append(pIoCtx->buffer, dwBytesTransfered);
							eargs->event->RequestEvent(c, tid, args);
							static_cast<tcp*>(c.csock.get())->recvDataWSA(c.RecvData, 0);
                        eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args);
                    }

                    // Continue Read/Write cycle
                    if (!c.SendData.empty()) start_write(pClientContext);
                    else start_read(pClientContext);

                } else if (pIoCtx->operation == OP_WRITE) {
						// 1. Remove the bytes that were successfully sent from the SendData buffer
						// For TCP/UDP, dwBytesTransfered represents the raw bytes on the wire.
						// For SSL, sendDataWSA handles the internal plaintext tracking.
                    // Update buffer: for SSL, dwBytesTransfered is the encrypted wire size
                    c.SendData.erase(0, dwBytesTransfered);

						// 2. Trigger ResponseEvent if the buffer is now empty to let the user add more data
                    if (c.SendData.empty()) {
                        eargs->event->ResponseEvent(c, tid, (ULONG_PTR)eargs->args);
                    }
						// 3. Continue the write loop if there is remaining data
						if (!c.SendData.empty()) {
							// Prepare a buffer object for the next chunk
							size_t toSend = std::min<size_t>(BLOCKSIZE, c.SendData.size());
							buffer out(c.SendData.data(), toSend);

							// 4. Use the specialized WSA methods based on socket type
							if (c.csock->_Type == sockettype::TCP) {
								static_cast<tcp*>(c.csock.get())->sendDataWSA(out, 0);
							} else if (c.csock->_Type == sockettype::UDP) {
								static_cast<udp*>(c.csock.get())->sendDataWSA(out, 0);
							} else if (c.csock->_Type == sockettype::SSL) {
								// This method encrypts the plaintext in c.SendData and initiates a WSASend
								static_cast<ssl*>(c.csock.get())->sendDataWSA(out, 0);
							}
						} else {
							// If nothing left to write, switch back to listening for data
							EventWorker::start_read(pClientContext);
						}
                    if (!c.SendData.empty()) start_write(pClientContext);
                    else start_read(pClientContext);
                }
            } catch (NetException& e) {
                    std::cerr << "IOCP Worker Error: " << e.what() << std::endl;
                    eargs->event->DisconnectEvent(c, tid, args);
                // Ignore non-critical notes, disconnect on actual errors
                if (e.getErrorType() != NetException::Note) {
                    eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args);
                    delete pClientContext;
                }
            }
        }
    }
};

    event::event(socket* serversocket, int timeout) : _ServerSocket(serversocket) {