wiresock / ndisapi

Windows Packet Filter library for network packet interception and manipulation, suitable for custom firewall, VPN and traffic analysis applications.
https://www.ntkernel.com/windows-packet-filter/
MIT License
289 stars 78 forks source link

Potential Issues with WSAWaitForMultipleEvents and High Concurrent TCP Connections #22

Closed piz-ewing closed 1 year ago

piz-ewing commented 1 year ago

Due to the constraints imposed by WSA_MAXIMUM_WAIT_EVENTS, high concurrent TCP connections can potentially give rise to issues with WSAWaitForMultipleEvents.

https://github.com/wiresock/ndisapi/blob/805fe6976a5fc680387126431fa7e1fb02cc818b/examples/cpp/common/proxy/tcp_proxy_server.h#L525

a possible solution from https://stackoverflow.com/a/11989138:

    DWORD WSAWaitForMultipleEvents(DWORD count, const HANDLE* pHandles,
                                   DWORD millisecs) {
        DWORD retval = WAIT_TIMEOUT;

        // Check if objects need to be split up. In theory, the maximum is
        // MAXIMUM_WAIT_OBJECTS, but I found this code performs slightly faster
        // if the object are broken down in batches smaller than this.
        if (count >= MAXIMUM_WAIT_OBJECTS) {
            // loop continuously if infinite timeout specified
            do {
                // divide the batch of handles in two halves ...
                DWORD split = count / 2;
                DWORD wait = (millisecs == INFINITE ? 2000 : millisecs) / 2;
                int random = rand();

                // ... and recurse down both branches in pseudo random order
                for (short branch = 0; branch < 2 && retval == WAIT_TIMEOUT;
                     branch++) {
                    if (random % 2 == branch) {
                        // recurse the lower half
                        retval =
                            WSAWaitForMultipleEvents(split, pHandles, wait);
                    } else {
                        // recurse the upper half
                        retval = WSAWaitForMultipleEvents(
                            count - split, pHandles + split, wait);
                        if (retval >= WAIT_OBJECT_0 &&
                            retval < WAIT_OBJECT_0 + split)
                            retval += split;
                    }
                }
            } while (millisecs == INFINITE && retval == WAIT_TIMEOUT);
        } else {
            // call the native win32 interface
            retval = ::WSAWaitForMultipleEvents(count, pHandles, FALSE,
                                                millisecs, FALSE);
        }

        // done
        return (retval);
    }
wiresock commented 1 year ago

Thanks for the hint, I have updated the tcp_proxy_server.h.