pocoproject / poco

The POCO C++ Libraries are powerful cross-platform C++ libraries for building network- and internet-based applications that run on desktop, server, mobile, IoT, and embedded systems.
https://pocoproject.org
Other
8.05k stars 2.11k forks source link

Socket::available Causes Connection Reset by Peer on Windows UDP Sockets #4537

Open andrewauclair opened 2 months ago

andrewauclair commented 2 months ago

Describe the bug Created a DatagramSocket with local address 127.0.0.1:0 and remote address 127.0.0.1:2345. After calling sendBytes on this UDP socket, poll returns true, then available returns -1 and the last error is "connection reset by peer". I suspect this is from the recvfrom call within available. If I change this to use the IP of a remote machine as the remote address, poll properly times out and returns false after sendBytes.

To Reproduce

#include <iostream>
void DatagramSocketTest::testLocalIPIssue()
{
    DatagramSocket socket(SocketAddress("127.0.0.1", 0), true, true);

    socket.connect(SocketAddress("127.0.0.1", 2345));

    unsigned char values[5]{};
    socket.sendBytes(values, 5);

    Poco::Timespan timeout(5000);

    if (socket.poll(timeout, Socket::SELECT_READ))
    {
        std::cout << socket.available(); // -1 and last error is "connection reset by peer"
    }
}

Expected behavior Poll returns false, just like it would when local and remote IPs don't match.

Please add relevant environment information:

andrewauclair commented 2 months ago

Should we be using Poco::Net::UDPServer and Poco::Net::UDPClient instead of a Poco::Net::DatagramSocket directly to avoid issues like this?

Maybe not. Looks like that only supports connecting locally.

andrewauclair commented 2 months ago

I ended up closing and reopening the socket if there was an error after calling available(). It still doesn't seem that great to me that available() could cause an error and return -1.

andrewauclair commented 2 months ago

Some additional testing resulted in receiveBytes throwing a std::bad_array_new_length because available returned -1.