2009-09-27 Gonzalo Paniagua Javier <gonzalo@novell.com>
authorGonzalo Paniagua Javier <gonzalo.mono@gmail.com>
Sun, 27 Sep 2009 19:23:24 +0000 (19:23 -0000)
committerGonzalo Paniagua Javier <gonzalo.mono@gmail.com>
Sun, 27 Sep 2009 19:23:24 +0000 (19:23 -0000)
* Socket_2_1.cs: Close(int timeout) blocks up to timeout ms if there's
pending data to be written to the socket. If there's no pending data,
it closes and returns right away. Instead of using Timer and then
doing a 'hard' close(), we set the linget option for the socket.

svn path=/trunk/mcs/; revision=142726

mcs/class/System/System.Net.Sockets/ChangeLog
mcs/class/System/System.Net.Sockets/Socket_2_1.cs

index 42530f50ccb82b38ec3b7b6ca040cc95602edc21..90a14e3fd0553e1a88607cbbdf783e6ee875b7ea 100644 (file)
@@ -1,3 +1,10 @@
+2009-09-27 Gonzalo Paniagua Javier <gonzalo@novell.com>
+
+       * Socket_2_1.cs: Close(int timeout) blocks up to timeout ms if there's
+       pending data to be written to the socket. If there's no pending data,
+       it closes and returns right away. Instead of using Timer and then
+       doing a 'hard' close(), we set the linget option for the socket.
+
 2009-09-27  Sebastien Pouliot  <sebastien@ximian.com>
 
        * SocketAsyncEventArgs.cs: Don't use Socket.Poll for NET_2_1.
index e54fcc1ad3ce81a314cd5e8c79e495bb9e1b515d..4e53c2d527c4a43bcf0b3064c5e0120aa18cebfb 100644 (file)
@@ -49,7 +49,6 @@ using System.Net.Configuration;
 
 #if NET_2_0
 using System.Collections.Generic;
-using System.Timers;
 #if !NET_2_1
 using System.Net.NetworkInformation;
 #endif
@@ -64,6 +63,7 @@ namespace System.Net.Sockets {
                 *  their name without also updating the runtime code.
                 */
                private static int ipv4Supported = -1, ipv6Supported = -1;
+               int linger_timeout;
 
                static Socket ()
                {
@@ -382,6 +382,35 @@ namespace System.Net.Sockets {
                        }
                }
 
+               void Linger (IntPtr handle)
+               {
+                       if (linger_timeout <= 0 || !connected)
+                               return;
+
+                       // We don't want to receive any more data
+                       int error;
+                       Shutdown_internal (handle, SocketShutdown.Receive, out error);
+                       if (error != 0)
+                               return;
+
+                       int seconds = linger_timeout / 1000;
+                       int ms = linger_timeout % 1000;
+                       if (ms > 0) {
+                               // If the other end closes, this will return 'true' with 'Available' == 0
+                               Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
+                               if (error != 0)
+                                       return;
+
+                       }
+                       if (seconds > 0) {
+                               LingerOption linger = new LingerOption (true, seconds);
+                               SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
+                               /* Not needed, we're closing upon return */
+                               /*if (error != 0)
+                                       return; */
+                       }
+               }
+
                protected virtual void Dispose (bool explicitDisposing)
                {
                        if (disposed)
@@ -394,7 +423,10 @@ namespace System.Net.Sockets {
                                closed = true;
                                IntPtr x = socket;
                                socket = (IntPtr) (-1);
+                               Linger (x);
+                               //DateTime start = DateTime.UtcNow;
                                Close_internal (x, out error);
+                               //Console.WriteLine ("Time spent in Close_internal: {0}ms", (DateTime.UtcNow - start).TotalMilliseconds);
                                if (blocking_thread != null) {
                                        blocking_thread.Abort ();
                                        blocking_thread = null;
@@ -420,22 +452,15 @@ namespace System.Net.Sockets {
 
                public void Close ()
                {
+                       linger_timeout = 0;
                        ((IDisposable) this).Dispose ();
                }
 
 #if NET_2_0
                public void Close (int timeout) 
                {
-                       System.Timers.Timer close_timer = new System.Timers.Timer ();
-                       close_timer.Elapsed += new ElapsedEventHandler (OnTimeoutClose);
-                       close_timer.Interval = timeout * 1000;
-                       close_timer.AutoReset = false;
-                       close_timer.Enabled = true;
-               }
-
-               private void OnTimeoutClose (object source, ElapsedEventArgs e)
-               {
-                       this.Close ();
+                       linger_timeout = timeout;
+                       ((IDisposable) this).Dispose ();
                }
 #endif
 
@@ -532,10 +557,11 @@ namespace System.Net.Sockets {
                        return true;
                }
 #endif
-#if !NET_2_1
+
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
 
+#if !NET_2_1
                /* This overload is needed as the async Connect method
                 * also needs to check the socket error status, but
                 * getsockopt(..., SO_ERROR) clears the error.