Stack overflow when using the System.Net.Sockets.Socket.AcceptAsync model

Viewed 14726

With respect to C# and .NET's System.Net.Sockets.Socket.AcceptAsync method, one would be required to handle a return value of "false" in order to handle the immediately available SocketAsyncEventArgs state from the synchronously processed connection. Microsoft provides examples (found on the System.Net.Sockets.SocketAsyncEventArgs class page) which will cause a stack overflow if there are a large amount of pending connections, which can be exploited on any system that implements their handling model.

Other ideas for getting around this issue are to make a loop that calls the handler method, with the condition being that the value Socket.AcceptAsync returns is equal to false, and to break the loop (to allow deferred processing) if the value is indicating that the operation is being completed asynchronously (true). However, this solution also causes a stack overflow vulnerability because of the fact that the callback associated with the SocketAsyncEventArgs passed to Socket.AcceptAsync has at the end of the method, a call to Socket.AcceptAsync, which also has a loop for immediately available, synchronously accepted, connections.

As you can see, this is a pretty solid problem, and I've yet to find a good solution that does not involve System.Threading.ThreadPool and creating tons of other methods and scheduling processing. As far as I can see, the asynchronous socket model relating to Socket.AcceptAsync requires more than what is demonstrated in the examples on MSDN.

Does anyone have a clean and efficient solution to handling immediately pending connections that are accepted synchronously from Socket.AcceptAsync without going into creating separate threads to handle the connections and without utilizing recursion?

5 Answers

The SocketTaskExtensions contains useful method overloads for the Socket class. Rather than using the AsyncCallback pattern, the AcceptAsync extension method can be called with ease. It is also compatible with the task asynchronous programming (TAP) model.

There is two basic operation to consider:

  1. Start the listening: As usual socket needs to Bind to a specific IP address and port. Then place the socket in listening state (Listen method). After that it is ready to handle the incoming communication.

  2. Stop the listening: It stops accepting the incoming requests.

    bool _isListening = false;
    
    public Task<bool> StartListening()
    {
        Socket listeningSocket = new Socket(SocketType.Stream, ProtocolType.Tcp);
        listeningSocket.Bind(new IPEndPoint(IPAddress.Any, 0));
        listeningSocket.Listen(10);
    
        return HandleRequests(listeningSocket);
    }
    
    public void StopListening()
    {
        _isListening = false;
    }
    

In order to handle incoming requests, the listening socket accepts (AcceptAsync) the incoming client connection. Then Send or Receive message from the accepted socket. It accepts incoming connection until StopListening was called.

internal async Task<bool> HandleRequests(Socket listeningSocket)
{
    try
    {
        _isListening = true;
        while (_isListening)
        {
            byte[] message = Encoding.UTF8.GetBytes("Message");
            byte[] receivedMessage = new byte[1024];
            using (Socket acceptedSocket = await listeningSocket.AcceptAsync())
            {
                // Send messages
                acceptedSocket.Send(message);

                // Receive messagges
                acceptedSocket.Receive(receivedMessage);
            }
        }
    }
    catch (SocketException)
    {
        // Handle error during communication.
        return false;
    }

    return true;
}

Note:

  • Messages could be exceed the buffer size. In that case try continuously receive until end of the data. Stephen Clearly message framing blog post is good starting point.
  • Sending and receiving also could be asynchronous. NetworkStream can be created from the accepted socket then we can await to the ReadAsnyc and WriteAsync operations.
Related