[HttpListener] Close idle connections on Stop()
authorGonzalo Paniagua Javier <gonzalo.mono@gmail.com>
Tue, 15 Feb 2011 06:48:42 +0000 (01:48 -0500)
committerGonzalo Paniagua Javier <gonzalo.mono@gmail.com>
Tue, 15 Feb 2011 06:52:50 +0000 (01:52 -0500)
Idle connections that never received any data or had ever been
associated to a listener are properly closed now when the endpoint is
closed or the last listener they used is closed.
Fixes a bunch of tests in System.ServiceModel.

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

index 92ed05713e7eb5ff7c1a3808ce43725dee973a7a..c3111b22346fa4511aa86197f2dc220a4e14216d 100644 (file)
@@ -48,6 +48,7 @@ namespace System.Net {
                X509Certificate2 cert;
                AsymmetricAlgorithm key;
                bool secure;
+               Hashtable unregistered;
 
                public EndPointListener (IPAddress addr, int port, bool secure)
                {
@@ -66,6 +67,7 @@ namespace System.Net {
                        sock.AcceptAsync (args);
                        prefixes = new Hashtable ();
                        plock = new ReaderWriterLock ();
+                       unregistered = Hashtable.Synchronized (new Hashtable ());
                }
 
                void LoadCertificateAndKey (IPAddress addr, int port)
@@ -114,9 +116,15 @@ namespace System.Net {
                                return;
                        }
                        HttpConnection conn = new HttpConnection (accepted, epl, epl.secure, epl.cert, epl.key);
+                       epl.unregistered [conn] = conn;
                        conn.BeginReadRequest ();
                }
 
+               internal void RemoveConnection (HttpConnection conn)
+               {
+                       unregistered.Remove (conn);
+               }
+
                public bool BindContext (HttpListenerContext context)
                {
                        HttpListenerRequest req = context.Request;
@@ -279,6 +287,11 @@ namespace System.Net {
                public void Close ()
                {
                        sock.Close ();
+                       lock (unregistered) {
+                               foreach (HttpConnection c in unregistered.Keys)
+                                       c.Close (true);
+                               unregistered.Clear ();
+                       }
                }
 
                public void AddPrefix (ListenerPrefix prefix, HttpListener listener)
index 9ba2fd7656553a41739bf3ad0299a9ac5af5022a..16ac15297f70f78e76701b35c190c68438a82e85 100644 (file)
@@ -59,6 +59,7 @@ namespace System.Net {
                int s_timeout = 90000; // 90k ms for first request, 15k ms from then on
                Timer timer;
                IPEndPoint local_ep;
+               HttpListener last_listener;
 
                public HttpConnection (Socket sock, EndPointListener epl, bool secure, X509Certificate2 cert, AsymmetricAlgorithm key)
                {
@@ -96,6 +97,10 @@ namespace System.Net {
                        context = new HttpListenerContext (this);
                }
 
+               public bool IsClosed {
+                       get { return (sock == null); }
+               }
+
                public int Reuses {
                        get { return reuses; }
                }
@@ -125,11 +130,8 @@ namespace System.Net {
 
                void OnTimeout (object unused)
                {
+                       CloseSocket ();
                        Unbind ();
-                       try {
-                               sock.Close (); // stream disposed
-                       } catch {
-                       }
                }
 
                public void BeginReadRequest ()
@@ -142,6 +144,7 @@ namespace System.Net {
                                timer.Change (s_timeout, Timeout.Infinite);
                                stream.BeginRead (buffer, 0, BufferSize, OnRead, this);
                        } catch {
+                               timer.Change (Timeout.Infinite, Timeout.Infinite);
                                CloseSocket ();
                        }
                }
@@ -216,7 +219,16 @@ namespace System.Net {
                                        SendError ("Invalid host", 400);
                                        Close (true);
                                }
-                               context_bound = true;
+                               if (last_listener == null)
+                                       epl.RemoveConnection (this);
+                               else
+                                       last_listener.RemoveConnection (this);
+
+                               if (context.Listener != null) {
+                                       context.Listener.AddConnection (this);
+                                       context_bound = true;
+                               }
+                               last_listener = context.Listener;
                                return;
                        }
                        stream.BeginRead (buffer, 0, BufferSize, OnRead, cnc);
@@ -378,6 +390,8 @@ namespace System.Net {
                        } finally {
                                sock = null;
                        }
+                       if (last_listener == null)
+                               epl.RemoveConnection (this);
                }
 
                internal void Close (bool force_close)
@@ -430,6 +444,8 @@ namespace System.Net {
                                                s.Close ();
                                }
                                Unbind ();
+                               if (last_listener == null)
+                                       epl.RemoveConnection (this);
                                return;
                        }
                }
index 79d4aac860816c4d7a417a9d20fe85320dca090d..5551ec810252fa85883f8d9e194466c76bfd24e3 100644 (file)
@@ -45,11 +45,13 @@ namespace System.Net {
                Hashtable registry;   // Dictionary<HttpListenerContext,HttpListenerContext> 
                ArrayList ctx_queue;  // List<HttpListenerContext> ctx_queue;
                ArrayList wait_queue; // List<ListenerAsyncResult> wait_queue;
+               Hashtable connections;
 
                public HttpListener ()
                {
                        prefixes = new HttpListenerPrefixCollection (this);
                        registry = new Hashtable ();
+                       connections = Hashtable.Synchronized (new Hashtable ());
                        ctx_queue = new ArrayList ();
                        wait_queue = new ArrayList ();
                        auth_schemes = AuthenticationSchemes.Anonymous;
@@ -135,7 +137,7 @@ namespace System.Net {
                                return;
                        }
 
-                       Close (false);
+                       Close (true);
                        disposed = true;
                }
 
@@ -153,12 +155,18 @@ namespace System.Net {
                                        foreach (HttpListenerContext context in registry.Keys) {
                                                context.Connection.Close ();
                                        }
-                                       registry.Clear (); // Just in case.
+                                       registry.Clear ();
                                }
 
+                               lock (connections) {
+                                       foreach (HttpConnection cnc in connections.Keys) {
+                                               cnc.Close (true);
+                                       }
+                                       connections.Clear ();
+                               }
                                lock (ctx_queue) {
                                        foreach (HttpListenerContext context in ctx_queue)
-                                               context.Connection.Close ();
+                                               context.Connection.Close (true);
 
                                        ctx_queue.Clear ();
                                }
@@ -310,6 +318,16 @@ namespace System.Net {
                                        ctx_queue.RemoveAt (idx);
                        }
                }
+
+               internal void AddConnection (HttpConnection cnc)
+               {
+                       connections [cnc] = cnc;
+               }
+
+               internal void RemoveConnection (HttpConnection cnc)
+               {
+                       connections.Remove (cnc);
+               }
        }
 }
 #endif