Merge pull request #601 from knocte/sock_improvements
[mono.git] / mcs / class / System / System.Net.Sockets / Socket.cs
index 97dfb91e9e84804ffc603273b842c1a847fbd9b3..a453d70e43fa9043f3e0ffd85690e57974f9b99e 100644 (file)
@@ -9,9 +9,8 @@
 //
 // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
 //    http://www.myelin.co.nz
-// (c) 2004-2006 Novell, Inc. (http://www.novell.com)
+// (c) 2004-2011 Novell, Inc. (http://www.novell.com)
 //
-
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -45,9 +44,7 @@ using System.IO;
 using System.Net.Configuration;
 using System.Text;
 using System.Timers;
-#if !MOONLIGHT
 using System.Net.NetworkInformation;
-#endif
 
 namespace System.Net.Sockets 
 {
@@ -55,6 +52,9 @@ namespace System.Net.Sockets
        {
                private bool islistening;
                private bool useoverlappedIO;
+               private const int SOCKET_CLOSED = 10004;
+
+               private static readonly string timeout_exc_msg = "A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond";
 
                static void AddSockets (List<Socket> sockets, IList list, string name)
                {
@@ -498,7 +498,6 @@ namespace System.Net.Sockets
                        }
                }
 
-#if !MOONLIGHT
                public bool AcceptAsync (SocketAsyncEventArgs e)
                {
                        // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
@@ -522,11 +521,16 @@ namespace System.Net.Sockets
 
                        e.curSocket = this;
                        Worker w = e.Worker;
-                       w.Init (this, null, e.AcceptCallback, SocketOperation.Accept);
-                       socket_pool_queue (w.Accept, w.result);
+                       w.Init (this, e, SocketOperation.Accept);
+                       int count;
+                       lock (readQ) {
+                               readQ.Enqueue (e.Worker);
+                               count = readQ.Count;
+                       }
+                       if (count == 1)
+                               socket_pool_queue (Worker.Dispatcher, w.result);
                        return true;
                }
-#endif
                // Creates a new system socket, returning the handle
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern static IntPtr Accept_internal(IntPtr sock, out int error, bool blocking);
@@ -537,21 +541,19 @@ namespace System.Net.Sockets
 
                        int error = 0;
                        IntPtr sock = (IntPtr) (-1);
-                       blocking_thread = Thread.CurrentThread;
                        try {
+                               RegisterForBlockingSyscall ();
                                sock = Accept_internal(socket, out error, blocking);
-                       } catch (ThreadAbortException) {
-                               if (disposed) {
-                                       Thread.ResetAbort ();
-                                       error = (int) SocketError.Interrupted;
-                               }
                        } finally {
-                               blocking_thread = null;
+                               UnRegisterForBlockingSyscall ();
+                       }
+
+                       if (error != 0) {
+                               if (closed)
+                                       error = SOCKET_CLOSED;
+                               throw new SocketException(error);
                        }
 
-                       if (error != 0)
-                               throw new SocketException (error);
-                       
                        Socket accepted = new Socket(this.AddressFamily, this.SocketType,
                                this.ProtocolType, sock);
 
@@ -567,21 +569,19 @@ namespace System.Net.Sockets
                        
                        int error = 0;
                        IntPtr sock = (IntPtr)(-1);
-                       blocking_thread = Thread.CurrentThread;
                        
                        try {
+                               RegisterForBlockingSyscall ();
                                sock = Accept_internal (socket, out error, blocking);
-                       } catch (ThreadAbortException) {
-                               if (disposed) {
-                                       Thread.ResetAbort ();
-                                       error = (int)SocketError.Interrupted;
-                               }
                        } finally {
-                               blocking_thread = null;
+                               UnRegisterForBlockingSyscall ();
                        }
                        
-                       if (error != 0)
+                       if (error != 0) {
+                               if (closed)
+                                       error = SOCKET_CLOSED;
                                throw new SocketException (error);
+                       }
                        
                        acceptSocket.address_family = this.AddressFamily;
                        acceptSocket.socket_type = this.SocketType;
@@ -605,8 +605,13 @@ namespace System.Net.Sockets
                                throw new InvalidOperationException ();
 
                        SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Accept);
-                       Worker worker = new Worker (req);
-                       socket_pool_queue (worker.Accept, req);
+                       int count;
+                       lock (readQ) {
+                               readQ.Enqueue (req.Worker);
+                               count = readQ.Count;
+                       }
+                       if (count == 1)
+                               socket_pool_queue (Worker.Dispatcher, req);
                        return req;
                }
 
@@ -621,12 +626,17 @@ namespace System.Net.Sockets
                                throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
 
                        SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive);
-                       Worker worker = new Worker (req);
                        req.Buffer = new byte[receiveSize];
                        req.Offset = 0;
                        req.Size = receiveSize;
                        req.SockFlags = SocketFlags.None;
-                       socket_pool_queue (worker.AcceptReceive, req);
+                       int count;
+                       lock (readQ) {
+                               readQ.Enqueue (req.Worker);
+                               count = readQ.Count;
+                       }
+                       if (count == 1)
+                               socket_pool_queue (Worker.Dispatcher, req);
                        return req;
                }
 
@@ -658,60 +668,18 @@ namespace System.Net.Sockets
                        }
                        
                        SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive);
-                       Worker worker = new Worker (req);
                        req.Buffer = new byte[receiveSize];
                        req.Offset = 0;
                        req.Size = receiveSize;
                        req.SockFlags = SocketFlags.None;
                        req.AcceptSocket = acceptSocket;
-                       socket_pool_queue (worker.AcceptReceive, req);
-                       return(req);
-               }
-
-               public IAsyncResult BeginConnect(EndPoint end_point,
-                                                AsyncCallback callback,
-                                                object state) {
-
-                       if (disposed && closed)
-                               throw new ObjectDisposedException (GetType ().ToString ());
-
-                       if (end_point == null)
-                               throw new ArgumentNullException ("end_point");
-
-                       SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Connect);
-                       req.EndPoint = end_point;
-
-                       // Bug #75154: Connect() should not succeed for .Any addresses.
-                       if (end_point is IPEndPoint) {
-                               IPEndPoint ep = (IPEndPoint) end_point;
-                               if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
-                                       req.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
-                                       return req;
-                               }
-                       }
-
-                       int error = 0;
-                       if (!blocking) {
-                               SocketAddress serial = end_point.Serialize ();
-                               Connect_internal (socket, serial, out error);
-                               if (error == 0) {
-                                       // succeeded synch
-                                       connected = true;
-                                       req.Complete (true);
-                               } else if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
-                                       // error synch
-                                       connected = false;
-                                       req.Complete (new SocketException (error), true);
-                               }
-                       }
-
-                       if (blocking || error == (int) SocketError.InProgress || error == (int) SocketError.WouldBlock) {
-                               // continue asynch
-                               connected = false;
-                               Worker worker = new Worker (req);
-                               socket_pool_queue (worker.Connect, req);
+                       int count;
+                       lock (readQ) {
+                               readQ.Enqueue (req.Worker);
+                               count = readQ.Count;
                        }
-
+                       if (count == 1)
+                               socket_pool_queue (Worker.Dispatcher, req);
                        return(req);
                }
 
@@ -728,6 +696,9 @@ namespace System.Net.Sockets
                        if (address.ToString ().Length == 0)
                                throw new ArgumentException ("The length of the IP address is zero");
 
+                       if (port <= 0 || port > 65535)
+                               throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
+
                        if (islistening)
                                throw new InvalidOperationException ();
 
@@ -735,35 +706,6 @@ namespace System.Net.Sockets
                        return(BeginConnect (iep, callback, state));
                }
 
-               public IAsyncResult BeginConnect (IPAddress[] addresses,
-                                                 int port,
-                                                 AsyncCallback callback,
-                                                 object state)
-               {
-                       if (disposed && closed)
-                               throw new ObjectDisposedException (GetType ().ToString ());
-
-                       if (addresses == null)
-                               throw new ArgumentNullException ("addresses");
-
-                       if (this.AddressFamily != AddressFamily.InterNetwork &&
-                               this.AddressFamily != AddressFamily.InterNetworkV6)
-                               throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
-
-                       if (islistening)
-                               throw new InvalidOperationException ();
-
-                       SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Connect);
-                       req.Addresses = addresses;
-                       req.Port = port;
-                       
-                       connected = false;
-                       Worker worker = new Worker (req);
-                       socket_pool_queue (worker.Connect, req);
-                       
-                       return(req);
-               }
-
                public IAsyncResult BeginConnect (string host, int port,
                                                  AsyncCallback callback,
                                                  object state)
@@ -778,11 +720,13 @@ namespace System.Net.Sockets
                                address_family != AddressFamily.InterNetworkV6)
                                throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
 
+                       if (port <= 0 || port > 65535)
+                               throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
+
                        if (islistening)
                                throw new InvalidOperationException ();
 
-                       IPAddress [] addresses = Dns.GetHostAddresses (host);
-                       return (BeginConnect (addresses, port, callback, state));
+                       return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
                }
 
                public IAsyncResult BeginDisconnect (bool reuseSocket,
@@ -794,12 +738,24 @@ namespace System.Net.Sockets
 
                        SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Disconnect);
                        req.ReuseSocket = reuseSocket;
-                       
-                       Worker worker = new Worker (req);
-                       socket_pool_queue (worker.Disconnect, req);
-                       
+                       socket_pool_queue (Worker.Dispatcher, req);
                        return(req);
                }
+
+               void CheckRange (byte[] buffer, int offset, int size)
+               {
+                       if (offset < 0)
+                               throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
+                               
+                       if (offset > buffer.Length)
+                               throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
+
+                       if (size < 0)                          
+                               throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
+                               
+                       if (size > buffer.Length - offset)
+                               throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
+               }
                
                public IAsyncResult BeginReceive(byte[] buffer, int offset,
                                                 int size,
@@ -813,25 +769,20 @@ namespace System.Net.Sockets
                        if (buffer == null)
                                throw new ArgumentNullException ("buffer");
 
-                       if (offset < 0 || offset > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset");
-
-                       if (size < 0 || offset + size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("size");
+                       CheckRange (buffer, offset, size);
 
                        SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Receive);
                        req.Buffer = buffer;
                        req.Offset = offset;
                        req.Size = size;
                        req.SockFlags = socket_flags;
-                       Worker worker = new Worker (req);
                        int count;
                        lock (readQ) {
-                               readQ.Enqueue (worker);
+                               readQ.Enqueue (req.Worker);
                                count = readQ.Count;
                        }
                        if (count == 1)
-                               socket_pool_queue (worker.Receive, req);
+                               socket_pool_queue (Worker.Dispatcher, req);
                        return req;
                }
 
@@ -867,14 +818,13 @@ namespace System.Net.Sockets
                        SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveGeneric);
                        req.Buffers = buffers;
                        req.SockFlags = socketFlags;
-                       Worker worker = new Worker (req);
                        int count;
                        lock(readQ) {
-                               readQ.Enqueue (worker);
+                               readQ.Enqueue (req.Worker);
                                count = readQ.Count;
                        }
                        if (count == 1)
-                               socket_pool_queue (worker.ReceiveGeneric, req);
+                               socket_pool_queue (Worker.Dispatcher, req);
                        return req;
                }
                
@@ -907,14 +857,7 @@ namespace System.Net.Sockets
                        if (remote_end == null)
                                throw new ArgumentNullException ("remote_end");
 
-                       if (offset < 0)
-                               throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
-
-                       if (size < 0)
-                               throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
-
-                       if (offset + size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset, size", "offset + size exceeds the buffer length");
+                       CheckRange (buffer, offset, size);
 
                        SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveFrom);
                        req.Buffer = buffer;
@@ -922,14 +865,13 @@ namespace System.Net.Sockets
                        req.Size = size;
                        req.SockFlags = socket_flags;
                        req.EndPoint = remote_end;
-                       Worker worker = new Worker (req);
                        int count;
                        lock (readQ) {
-                               readQ.Enqueue (worker);
+                               readQ.Enqueue (req.Worker);
                                count = readQ.Count;
                        }
                        if (count == 1)
-                               socket_pool_queue (worker.ReceiveFrom, req);
+                               socket_pool_queue (Worker.Dispatcher, req);
                        return req;
                }
 
@@ -948,11 +890,7 @@ namespace System.Net.Sockets
                        if (remoteEP == null)
                                throw new ArgumentNullException ("remoteEP");
 
-                       if (offset < 0 || offset > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset");
-
-                       if (size < 0 || offset + size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("size");
+                       CheckRange (buffer, offset, size);
 
                        throw new NotImplementedException ();
                }
@@ -966,14 +904,7 @@ namespace System.Net.Sockets
                        if (buffer == null)
                                throw new ArgumentNullException ("buffer");
 
-                       if (offset < 0)
-                               throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
-
-                       if (size < 0)
-                               throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
-
-                       if (offset + size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset, size", "offset + size exceeds the buffer length");
+                       CheckRange (buffer, offset, size);
 
                        if (!connected)
                                throw new SocketException ((int)SocketError.NotConnected);
@@ -983,14 +914,13 @@ namespace System.Net.Sockets
                        req.Offset = offset;
                        req.Size = size;
                        req.SockFlags = socket_flags;
-                       Worker worker = new Worker (req);
                        int count;
                        lock (writeQ) {
-                               writeQ.Enqueue (worker);
+                               writeQ.Enqueue (req.Worker);
                                count = writeQ.Count;
                        }
                        if (count == 1)
-                               socket_pool_queue (worker.Send, req);
+                               socket_pool_queue (Worker.Dispatcher, req);
                        return req;
                }
 
@@ -1029,14 +959,13 @@ namespace System.Net.Sockets
                        SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.SendGeneric);
                        req.Buffers = buffers;
                        req.SockFlags = socketFlags;
-                       Worker worker = new Worker (req);
                        int count;
                        lock (writeQ) {
-                               writeQ.Enqueue (worker);
+                               writeQ.Enqueue (req.Worker);
                                count = writeQ.Count;
                        }
                        if (count == 1)
-                               socket_pool_queue (worker.SendGeneric, req);
+                               socket_pool_queue (Worker.Dispatcher, req);
                        return req;
                }
 
@@ -1126,7 +1055,10 @@ namespace System.Net.Sockets
                                throw new FileNotFoundException ();
 
                        SendFileHandler d = new SendFileHandler (SendFile);
-                       return new SendFileAsyncResult (d, d.BeginInvoke (fileName, preBuffer, postBuffer, flags, callback, state));
+                       return new SendFileAsyncResult (d, d.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => {
+                               SendFileAsyncResult sfar = new SendFileAsyncResult (d, ar);
+                               callback (sfar);
+                       }, state));
                }
 
                public IAsyncResult BeginSendTo(byte[] buffer, int offset,
@@ -1141,14 +1073,7 @@ namespace System.Net.Sockets
                        if (buffer == null)
                                throw new ArgumentNullException ("buffer");
 
-                       if (offset < 0)
-                               throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
-
-                       if (size < 0)
-                               throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
-
-                       if (offset + size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset, size", "offset + size exceeds the buffer length");
+                       CheckRange (buffer, offset, size);
 
                        SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.SendTo);
                        req.Buffer = buffer;
@@ -1156,14 +1081,13 @@ namespace System.Net.Sockets
                        req.Size = size;
                        req.SockFlags = socket_flags;
                        req.EndPoint = remote_end;
-                       Worker worker = new Worker (req);
                        int count;
                        lock (writeQ) {
-                               writeQ.Enqueue (worker);
+                               writeQ.Enqueue (req.Worker);
                                count = writeQ.Count;
                        }
                        if (count == 1)
-                               socket_pool_queue (worker.SendTo, req);
+                               socket_pool_queue (Worker.Dispatcher, req);
                        return req;
                }
 
@@ -1191,27 +1115,6 @@ namespace System.Net.Sockets
                        seed_endpoint = local_end;
                }
 
-#if !MOONLIGHT
-               public bool ConnectAsync (SocketAsyncEventArgs e)
-               {
-                       // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
-                       
-                       if (disposed && closed)
-                               throw new ObjectDisposedException (GetType ().ToString ());
-                       if (islistening)
-                               throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
-                       if (e.RemoteEndPoint == null)
-                               throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
-                       if (e.BufferList != null)
-                               throw new ArgumentException ("Multiple buffers cannot be used with this method.");
-
-                       e.DoOperation (SocketAsyncOperation.Connect, this);
-
-                       // We always return true for now
-                       return true;
-               }
-#endif
-               
                public void Connect (IPAddress address, int port)
                {
                        Connect (new IPEndPoint (address, port));
@@ -1270,7 +1173,6 @@ namespace System.Net.Sockets
                        Connect (addresses, port);
                }
 
-#if !MOONLIGHT
                public bool DisconnectAsync (SocketAsyncEventArgs e)
                {
                        // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
@@ -1278,11 +1180,10 @@ namespace System.Net.Sockets
                                throw new ObjectDisposedException (GetType ().ToString ());
 
                        e.curSocket = this;
-                       e.Worker.Init (this, null, e.DisconnectCallback, SocketOperation.Disconnect);
-                       socket_pool_queue (e.Worker.Disconnect, e.Worker.result);
+                       e.Worker.Init (this, e, SocketOperation.Disconnect);
+                       socket_pool_queue (Worker.Dispatcher, e.Worker.result);
                        return true;
                }
-#endif
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                extern static void Disconnect_internal(IntPtr sock, bool reuse, out int error);
@@ -1393,7 +1294,6 @@ namespace System.Net.Sockets
                        req.CheckIfThrowDelayedException();
                }
 
-#if !MOONLIGHT
                public void EndDisconnect (IAsyncResult asyncResult)
                {
                        if (disposed && closed)
@@ -1413,7 +1313,6 @@ namespace System.Net.Sockets
 
                        req.CheckIfThrowDelayedException ();
                }
-#endif
 
                [MonoTODO]
                public int EndReceiveMessageFrom (IAsyncResult asyncResult,
@@ -1454,7 +1353,6 @@ namespace System.Net.Sockets
                        ares.Delegate.EndInvoke (ares.Original);
                }
 
-#if !MOONLIGHT
                public int EndSendTo (IAsyncResult result)
                {
                        if (disposed && closed)
@@ -1475,7 +1373,6 @@ namespace System.Net.Sockets
                        req.CheckIfThrowDelayedException();
                        return req.Total;
                }
-#endif
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern static void GetSocketOption_arr_internal(IntPtr socket,
@@ -1598,20 +1495,7 @@ namespace System.Net.Sockets
 
                public int Receive (byte [] buffer)
                {
-                       if (disposed && closed)
-                               throw new ObjectDisposedException (GetType ().ToString ());
-
-                       if (buffer == null)
-                               throw new ArgumentNullException ("buffer");
-
-                       SocketError error;
-
-                       int ret = Receive_nochecks (buffer, 0, buffer.Length, SocketFlags.None, out error);
-                       
-                       if (error != SocketError.Success)
-                               throw new SocketException ((int) error);
-
-                       return ret;
+                       return Receive (buffer, SocketFlags.None);
                }
 
                public int Receive (byte [] buffer, SocketFlags flags)
@@ -1628,7 +1512,7 @@ namespace System.Net.Sockets
                        
                        if (error != SocketError.Success) {
                                if (error == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set
-                                       throw new SocketException ((int) error, "Operation timed out.");
+                                       throw new SocketException ((int) error, timeout_exc_msg);
                                throw new SocketException ((int) error);
                        }
 
@@ -1643,8 +1527,7 @@ namespace System.Net.Sockets
                        if (buffer == null)
                                throw new ArgumentNullException ("buffer");
 
-                       if (size < 0 || size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("size");
+                       CheckRange (buffer, 0, size);
 
                        SocketError error;
 
@@ -1652,7 +1535,7 @@ namespace System.Net.Sockets
                        
                        if (error != SocketError.Success) {
                                if (error == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set
-                                       throw new SocketException ((int) error, "Operation timed out.");
+                                       throw new SocketException ((int) error, timeout_exc_msg);
                                throw new SocketException ((int) error);
                        }
 
@@ -1667,11 +1550,7 @@ namespace System.Net.Sockets
                        if (buffer == null)
                                throw new ArgumentNullException ("buffer");
 
-                       if (offset < 0 || offset > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset");
-
-                       if (size < 0 || offset + size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("size");
+                       CheckRange (buffer, offset, size);
                        
                        SocketError error;
 
@@ -1679,7 +1558,7 @@ namespace System.Net.Sockets
                        
                        if (error != SocketError.Success) {
                                if (error == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set
-                                       throw new SocketException ((int) error, "Operation timed out.");
+                                       throw new SocketException ((int) error, timeout_exc_msg);
                                throw new SocketException ((int) error);
                        }
 
@@ -1694,16 +1573,11 @@ namespace System.Net.Sockets
                        if (buffer == null)
                                throw new ArgumentNullException ("buffer");
 
-                       if (offset < 0 || offset > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset");
-
-                       if (size < 0 || offset + size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("size");
+                       CheckRange (buffer, offset, size);
                        
                        return Receive_nochecks (buffer, offset, size, flags, out error);
                }
 
-#if !MOONLIGHT
                public bool ReceiveFromAsync (SocketAsyncEventArgs e)
                {
                        if (disposed && closed)
@@ -1716,24 +1590,22 @@ namespace System.Net.Sockets
                                throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
 
                        e.curSocket = this;
-                       e.Worker.Init (this, null, e.ReceiveFromCallback, SocketOperation.ReceiveFrom);
+                       e.Worker.Init (this, e, SocketOperation.ReceiveFrom);
                        SocketAsyncResult res = e.Worker.result;
                        res.Buffer = e.Buffer;
                        res.Offset = e.Offset;
                        res.Size = e.Count;
                        res.EndPoint = e.RemoteEndPoint;
                        res.SockFlags = e.SocketFlags;
-                       Worker worker = new Worker (e);
                        int count;
                        lock (readQ) {
-                               readQ.Enqueue (worker);
+                               readQ.Enqueue (e.Worker);
                                count = readQ.Count;
                        }
                        if (count == 1)
-                               socket_pool_queue (e.Worker.ReceiveFrom, res);
+                               socket_pool_queue (Worker.Dispatcher, res);
                        return true;
                }
-#endif
 
                public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
                {
@@ -1802,11 +1674,7 @@ namespace System.Net.Sockets
                        if (remoteEP == null)
                                throw new ArgumentNullException ("remoteEP");
 
-                       if (offset < 0 || offset > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset");
-
-                       if (size < 0 || offset + size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("size");
+                       CheckRange (buffer, offset, size);
 
                        return ReceiveFrom_nochecks (buffer, offset, size, flags, ref remoteEP);
                }
@@ -1829,7 +1697,7 @@ namespace System.Net.Sockets
                                        connected = false;
                                else if (err == SocketError.WouldBlock && blocking) { // This might happen when ReceiveTimeout is set
                                        if (throwOnError)       
-                                               throw new SocketException ((int) SocketError.TimedOut, "Operation timed out");
+                                               throw new SocketException ((int) SocketError.TimedOut, timeout_exc_msg);
                                        error = (int) SocketError.TimedOut;
                                        return 0;
                                }
@@ -1884,11 +1752,7 @@ namespace System.Net.Sockets
                        if (remoteEP == null)
                                throw new ArgumentNullException ("remoteEP");
 
-                       if (offset < 0 || offset > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset");
-
-                       if (size < 0 || offset + size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("size");
+                       CheckRange (buffer, offset, size);
 
                        /* FIXME: figure out how we get hold of the
                         * IPPacketInformation
@@ -1951,8 +1815,7 @@ namespace System.Net.Sockets
                        if (buf == null)
                                throw new ArgumentNullException ("buf");
 
-                       if (size < 0 || size > buf.Length)
-                               throw new ArgumentOutOfRangeException ("size");
+                       CheckRange (buf, 0, size);
 
                        SocketError error;
 
@@ -1972,11 +1835,7 @@ namespace System.Net.Sockets
                        if (buf == null)
                                throw new ArgumentNullException ("buffer");
 
-                       if (offset < 0 || offset > buf.Length)
-                               throw new ArgumentOutOfRangeException ("offset");
-
-                       if (size < 0 || offset + size > buf.Length)
-                               throw new ArgumentOutOfRangeException ("size");
+                       CheckRange (buf, offset, size);
 
                        SocketError error;
 
@@ -1996,11 +1855,7 @@ namespace System.Net.Sockets
                        if (buf == null)
                                throw new ArgumentNullException ("buffer");
 
-                       if (offset < 0 || offset > buf.Length)
-                               throw new ArgumentOutOfRangeException ("offset");
-
-                       if (size < 0 || offset + size > buf.Length)
-                               throw new ArgumentOutOfRangeException ("size");
+                       CheckRange (buf, offset, size);
 
                        return Send_nochecks (buf, offset, size, flags, out error);
                }
@@ -2041,7 +1896,6 @@ namespace System.Net.Sockets
                        }
                }
 
-#if !MOONLIGHT
                public bool SendToAsync (SocketAsyncEventArgs e)
                {
                        // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
@@ -2054,24 +1908,22 @@ namespace System.Net.Sockets
                                throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
 
                        e.curSocket = this;
-                       e.Worker.Init (this, null, e.SendToCallback, SocketOperation.SendTo);
+                       e.Worker.Init (this, e, SocketOperation.SendTo);
                        SocketAsyncResult res = e.Worker.result;
                        res.Buffer = e.Buffer;
                        res.Offset = e.Offset;
                        res.Size = e.Count;
                        res.SockFlags = e.SocketFlags;
                        res.EndPoint = e.RemoteEndPoint;
-                       Worker worker = new Worker (e);
                        int count;
                        lock (writeQ) {
-                               writeQ.Enqueue (worker);
+                               writeQ.Enqueue (e.Worker);
                                count = writeQ.Count;
                        }
                        if (count == 1)
-                               socket_pool_queue (e.Worker.SendTo, res);
+                               socket_pool_queue (Worker.Dispatcher, res);
                        return true;
                }
-#endif
                
                public int SendTo (byte [] buffer, EndPoint remote_end)
                {
@@ -2112,8 +1964,7 @@ namespace System.Net.Sockets
                        if (remote_end == null)
                                throw new ArgumentNullException ("remote_end");
 
-                       if (size < 0 || size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("size");
+                       CheckRange (buffer, 0, size);
 
                        return SendTo_nochecks (buffer, 0, size, flags, remote_end);
                }
@@ -2139,11 +1990,7 @@ namespace System.Net.Sockets
                        if (remote_end == null)
                                throw new ArgumentNullException("remote_end");
 
-                       if (offset < 0 || offset > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset");
-
-                       if (size < 0 || offset + size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("size");
+                       CheckRange (buffer, offset, size);
 
                        return SendTo_nochecks (buffer, offset, size, flags, remote_end);
                }