handles AwaitAsync finishing synchronously
authorGreg Young <gregoryyoung1@gmail.com>
Wed, 2 Mar 2016 21:28:49 +0000 (23:28 +0200)
committerGreg Young <gregoryyoung1@gmail.com>
Mon, 7 Mar 2016 13:24:01 +0000 (15:24 +0200)
A connect flood will break the async loop and take down the entire HttpListener instance (will stop accepting connections).

To reproduce. Take a HttpListener run say 2 wrk test instances against it (1000 connections each works here). After the run the HttpListener has broken its async loop and will no longer accept any connections after. The reason for this is that it was not previously handling the case that AcceptAsync can return synchronously. In this case event will not be called with args.

Patch handles this case and the above issue is not reproducible with.

mcs/class/System/System.Net/EndPointListener.cs

index 9726b91358b2ffeb1030370681e901b519a6ee8d..5400d73b87e7e6fee4d7d365260f00d7797f81d9 100644 (file)
@@ -73,7 +73,7 @@ namespace System.Net {
                        SocketAsyncEventArgs args = new SocketAsyncEventArgs ();
                        args.UserToken = this;
                        args.Completed += OnAccept;
-                       sock.AcceptAsync (args);
+                       Accept (sock, args);
                        prefixes = new Hashtable ();
                        unregistered = new Dictionary<HttpConnection, HttpConnection> ();
                }
@@ -82,28 +82,25 @@ namespace System.Net {
                        get { return listener; }
                }
 
-               static void OnAccept (object sender, EventArgs e)
+               static void Accept (Socket socket, SocketAsyncEventArgs e) {
+                       e.AcceptSocket = null;
+                       var asyn = socket.AcceptAsync(e);
+                       if (!asyn) {
+                               ProcessAccept(e);
+                       }
+               }
+
+
+               static void ProcessAccept (SocketAsyncEventArgs args) 
                {
-                       SocketAsyncEventArgs args = (SocketAsyncEventArgs) e;
-                       EndPointListener epl = (EndPointListener) args.UserToken;
                        Socket accepted = null;
-                       if (args.SocketError == SocketError.Success) {
+                       if (args.SocketError == SocketError.Success)
                                accepted = args.AcceptSocket;
-                               args.AcceptSocket = null;
-                       }
 
-                       try {
-                               if (epl.sock != null)
-                                       epl.sock.AcceptAsync (args);
-                       } catch {
-                               if (accepted != null) {
-                                       try {
-                                               accepted.Close ();
-                                       } catch {}
-                                       accepted = null;
-                               }
-                       } 
+                       EndPointListener epl = (EndPointListener) args.UserToken;
+
 
+                       Accept (epl.sock, args);
                        if (accepted == null)
                                return;
 
@@ -118,7 +115,12 @@ namespace System.Net {
                        conn.BeginReadRequest ();
                }
 
-               internal void RemoveConnection (HttpConnection conn)
+               static void OnAccept (object sender, SocketAsyncEventArgs e) 
+               {
+                       ProcessAccept (e);
+               }
+
+               internal void RemoveConnection (HttpConnection conn) 
                {
                        lock (unregistered) {
                                unregistered.Remove (conn);