New tests.
[mono.git] / mcs / class / System / System.Net.Sockets / Socket_2_1.cs
index d82fed329e782fc2e7c9418ce17d1151657daa85..af54044c3d50f2039abc56e331ebfc96c0462583 100644 (file)
@@ -39,7 +39,6 @@ using System.Collections;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Threading;
-using System.Reflection;
 using System.IO;
 using System.Security;
 using System.Text;
@@ -52,7 +51,6 @@ using System.Net.Configuration;
 using System.Collections.Generic;
 #if !NET_2_1
 using System.Net.NetworkInformation;
-using System.Timers;
 #endif
 #endif
 
@@ -64,15 +62,8 @@ namespace System.Net.Sockets {
                 *      These two fields are looked up by name by the runtime, don't change
                 *  their name without also updating the runtime code.
                 */
-               private static int ipv4Supported = -1;
-               /* MonoTouch doesn't support System.Configuration, and the ipv6 check raises an uncatchable exception
-                * so we unfortunately need to disable ipv6 here.
-                */
-#if MONOTOUCH
-               private static int ipv6Supported = 0;
-#else
-               private static int ipv6Supported = -1;
-#endif
+               private static int ipv4Supported = -1, ipv6Supported = -1;
+               int linger_timeout;
 
                static Socket ()
                {
@@ -236,6 +227,7 @@ namespace System.Net.Sockets {
                                                             bool block,
                                                             out int error);
 #endif
+
                public bool Blocking {
                        get {
                                return(blocking);
@@ -390,23 +382,59 @@ namespace System.Net.Sockets {
                        }
                }
 
+               void Linger (IntPtr handle)
+               {
+                       if (!connected || linger_timeout <= 0)
+                               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)
                                return;
 
                        disposed = true;
+                       bool was_connected = connected;
                        connected = false;
                        if ((int) socket != -1) {
                                int error;
                                closed = true;
                                IntPtr x = socket;
                                socket = (IntPtr) (-1);
-                               Close_internal (x, out error);
-                               if (blocking_thread != null) {
-                                       blocking_thread.Abort ();
+                               Thread th = blocking_thread;
+                               if (th != null) {
+                                       th.Abort ();
                                        blocking_thread = null;
                                }
+
+                               if (was_connected)
+                                       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 (error != 0)
                                        throw new SocketException (error);
                        }
@@ -428,9 +456,18 @@ namespace System.Net.Sockets {
 
                public void Close ()
                {
+                       linger_timeout = 0;
                        ((IDisposable) this).Dispose ();
                }
 
+#if NET_2_0
+               public void Close (int timeout) 
+               {
+                       linger_timeout = timeout;
+                       ((IDisposable) this).Dispose ();
+               }
+#endif
+
                // Connects to the remote address
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern static void Connect_internal(IntPtr sock,
@@ -452,24 +489,15 @@ namespace System.Net.Sockets {
                                if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
                                        throw new SocketException ((int) SocketError.AddressNotAvailable);
 
-#if NET_2_1 && !MONOTOUCH
+#if MOONLIGHT
                        if (protocol_type != ProtocolType.Tcp)
                                throw new SocketException ((int) SocketError.AccessDenied);
-
-                       DnsEndPoint dep = (remoteEP as DnsEndPoint);
-                       if (dep != null)
-                               serial = dep.AsIPEndPoint ().Serialize ();
-                       else
-                               serial = remoteEP.Serialize ();
 #elif NET_2_0
                        /* TODO: check this for the 1.1 profile too */
                        if (islistening)
                                throw new InvalidOperationException ();
-
-                       serial = remoteEP.Serialize ();
-#else
-                       serial = remoteEP.Serialize ();
 #endif
+                       serial = remoteEP.Serialize ();
 
                        int error = 0;
 
@@ -659,10 +687,12 @@ namespace System.Net.Sockets {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
+                       if (!connected)
+                               throw new SocketException (10057); // Not connected
+
                        int error;
                        
                        Shutdown_internal (socket, how, out error);
-
                        if (error != 0)
                                throw new SocketException (error);
                }
@@ -695,10 +725,8 @@ namespace System.Net.Sockets {
 #endif
                }
 
-#if NET_2_1 && !MONOTOUCH
-               static MethodInfo check_socket_policy;
-
-               static void CheckConnect (SocketAsyncEventArgs e, bool checkPolicy)
+#if MOONLIGHT
+               static void CheckConnect (SocketAsyncEventArgs e)
                {
                        // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
 
@@ -706,28 +734,14 @@ namespace System.Net.Sockets {
                                throw new ArgumentNullException ("remoteEP");
                        if (e.BufferList != null)
                                throw new ArgumentException ("Multiple buffers cannot be used with this method.");
-
-                       if (!checkPolicy)
-                               return;
-
-                       e.SocketError = SocketError.AccessDenied;
-                       if (check_socket_policy == null) {
-                               Type type = Type.GetType ("System.Windows.Browser.Net.CrossDomainPolicyManager, System.Windows.Browser, Version=2.0.5.0, Culture=Neutral, PublicKeyToken=7cec85d7bea7798e");
-                               check_socket_policy = type.GetMethod ("CheckEndPoint");
-                               if (check_socket_policy == null)
-                                       throw new SecurityException ();
-                       }
-                       if ((bool) check_socket_policy.Invoke (null, new object [1] { e.RemoteEndPoint }))
-                               e.SocketError = SocketError.Success;
                }
 
-               // only _directly_ used (with false) to download the socket policy
-               internal bool ConnectAsync (SocketAsyncEventArgs e, bool checkPolicy)
+               public bool ConnectAsync (SocketAsyncEventArgs e)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       CheckConnect (e, checkPolicy);
+                       CheckConnect (e);
 
                        e.DoOperation (SocketAsyncOperation.Connect, this);
 
@@ -735,14 +749,10 @@ namespace System.Net.Sockets {
                        return true;
                }
 
-               public bool ConnectAsync (SocketAsyncEventArgs e)
-               {
-                       return ConnectAsync (e, true);
-               }
-
                public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
                {
-                       CheckConnect (e, true);
+                       // exception ordering requires to check before creating the socket (good thing resource wise too)
+                       CheckConnect (e);
 
                        Socket s = new Socket (AddressFamily.InterNetwork, socketType, protocolType);
                        e.DoOperation (SocketAsyncOperation.Connect, s);