From ede65cd8aa65f004d8bc17884907ea31fc96808c Mon Sep 17 00:00:00 2001 From: Gonzalo Paniagua Javier Date: Sun, 27 Sep 2009 19:23:24 +0000 Subject: [PATCH] 2009-09-27 Gonzalo Paniagua Javier * 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 | 7 +++ .../System/System.Net.Sockets/Socket_2_1.cs | 50 ++++++++++++++----- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/mcs/class/System/System.Net.Sockets/ChangeLog b/mcs/class/System/System.Net.Sockets/ChangeLog index 42530f50ccb..90a14e3fd05 100644 --- a/mcs/class/System/System.Net.Sockets/ChangeLog +++ b/mcs/class/System/System.Net.Sockets/ChangeLog @@ -1,3 +1,10 @@ +2009-09-27 Gonzalo Paniagua Javier + + * 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 * SocketAsyncEventArgs.cs: Don't use Socket.Poll for NET_2_1. diff --git a/mcs/class/System/System.Net.Sockets/Socket_2_1.cs b/mcs/class/System/System.Net.Sockets/Socket_2_1.cs index e54fcc1ad3c..4e53c2d527c 100644 --- a/mcs/class/System/System.Net.Sockets/Socket_2_1.cs +++ b/mcs/class/System/System.Net.Sockets/Socket_2_1.cs @@ -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. -- 2.25.1