Merge pull request #2815 from lambdageek/dev/monoerror-mono_compile_method
[mono.git] / mcs / class / System / System.Net.Sockets / Socket.cs
index c0e1e9548250b909e995d8c912a3f5661eb78e7f..d71b3eecabe26a4a8ded29eff3d04f184f62bec3 100644 (file)
@@ -70,13 +70,13 @@ namespace System.Net.Sockets
 
                int linger_timeout;
 
-               /* the field "safe_handle" is looked up by name by the runtime */
-               SafeSocketHandle safe_handle;
-
                AddressFamily address_family;
                SocketType socket_type;
                ProtocolType protocol_type;
 
+               /* the field "safe_handle" is looked up by name by the runtime */
+               internal SafeSocketHandle safe_handle;
+
                /*
                 * This EndPoint is used when creating new endpoints. Because
                 * there are many types of EndPoints possible,
@@ -86,8 +86,8 @@ namespace System.Net.Sockets
                 */
                internal EndPoint seed_endpoint = null;
 
-               internal Queue readQ = new Queue (2);
-               internal Queue writeQ = new Queue (2);
+               internal Queue<KeyValuePair<IntPtr, IOSelectorJob>> readQ = new Queue<KeyValuePair<IntPtr, IOSelectorJob>> (2);
+               internal Queue<KeyValuePair<IntPtr, IOSelectorJob>> writeQ = new Queue<KeyValuePair<IntPtr, IOSelectorJob>> (2);
 
                internal bool is_blocking = true;
                internal bool is_bound;
@@ -156,10 +156,16 @@ namespace System.Net.Sockets
                        }
                }
 
-               [MonoTODO ("Currently hardcoded to IPv4. Ideally, support v4/v6 dual-stack.")]
+               //
+               // This constructor is used by servers that want to listen for instance on both
+               // ipv4 and ipv6.   Mono has historically done that if you use InterNetworkV6 (at
+               // least on Unix), because that is the default behavior unless the IPV6_V6ONLY
+               // option is explicitly set by using setsockopt (sock, IPPROTO_IPV6, IPV6_ONLY)
+               //
                public Socket (SocketType socketType, ProtocolType protocolType)
-                       : this (AddressFamily.InterNetwork, socketType, protocolType)
+                       : this (AddressFamily.InterNetworkV6, socketType, protocolType)
                {
+                       DualMode = true;
                }
                
                public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
@@ -195,11 +201,9 @@ namespace System.Net.Sockets
                        this.address_family = addressFamily;
                        this.socket_type = socketType;
                        this.protocol_type = protocolType;
-                       
-                       int error;
-                       var handle = Socket_internal (addressFamily, socketType, protocolType, out error);
 
-                       this.safe_handle = new SafeSocketHandle (handle, true);
+                       int error;
+                       this.safe_handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
 
                        if (error != 0)
                                throw new SocketException (error);
@@ -275,6 +279,7 @@ namespace System.Net.Sockets
 
 #region Properties
 
+               [ObsoleteAttribute ("Use OSSupportsIPv4 instead")]
                public static bool SupportsIPv4 {
                        get { return ipv4_supported == 1; }
                }
@@ -288,6 +293,19 @@ namespace System.Net.Sockets
                public static bool OSSupportsIPv4 {
                        get { return ipv4_supported == 1; }
                }
+#else
+               public static bool OSSupportsIPv4 {
+                       get {
+                               NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
+
+                               foreach (NetworkInterface adapter in nics) {
+                                       if (adapter.Supports (NetworkInterfaceComponent.IPv4))
+                                               return true;
+                               }
+
+                               return false;
+                       }
+               }
 #endif
 
 #if NET_2_1
@@ -466,6 +484,27 @@ namespace System.Net.Sockets
                        }
                }
 
+               public bool DualMode {
+                       get {
+                               if (AddressFamily != AddressFamily.InterNetworkV6) 
+                                       throw new NotSupportedException("This protocol version is not supported");
+
+                               return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only) == 0);
+                       }
+                       set {
+                               if (AddressFamily != AddressFamily.InterNetworkV6) 
+                                       throw new NotSupportedException("This protocol version is not supported");
+
+                               SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1);
+                       }
+               }
+
+               private bool IsDualMode {
+                       get {
+                               return AddressFamily == AddressFamily.InterNetworkV6 && DualMode;
+                       }
+               }
+
                [MonoTODO ("This doesn't do anything on Mono yet")]
                public bool UseOnlyOverlappedIO {
                        get { return use_overlapped_io; }
@@ -910,16 +949,32 @@ namespace System.Net.Sockets
                                        throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
                        }
 
-                       e.curSocket = this;
-                       e.Worker.Init (this, e, SocketOperation.Accept);
-
-                       SocketAsyncResult sockares = e.Worker.result;
+                       InitSocketAsyncEventArgs (e, AcceptAsyncCallback, e, SocketOperation.Accept);
 
-                       QueueSocketAsyncResult (readQ, e.Worker, sockares);
+                       QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, e.socket_async_result));
 
                        return true;
                }
 
+               static AsyncCallback AcceptAsyncCallback = new AsyncCallback (ares => {
+                       SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
+
+                       if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+                               throw new InvalidOperationException ("No operation in progress");
+
+                       try {
+                               e.AcceptSocket = e.current_socket.EndAccept (ares);
+                       } catch (SocketException ex) {
+                               e.SocketError = ex.SocketErrorCode;
+                       } catch (ObjectDisposedException) {
+                               e.SocketError = SocketError.OperationAborted;
+                       } finally {
+                               if (e.AcceptSocket == null)
+                                       e.AcceptSocket = new Socket (e.current_socket.AddressFamily, e.current_socket.SocketType, e.current_socket.ProtocolType, null);
+                               e.Complete ();
+                       }
+               });
+
                public IAsyncResult BeginAccept(AsyncCallback callback, object state)
                {
                        ThrowIfDisposedAndClosed ();
@@ -927,13 +982,31 @@ namespace System.Net.Sockets
                        if (!is_bound || !is_listening)
                                throw new InvalidOperationException ();
 
-                       SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.Accept);
+                       SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Accept);
 
-                       QueueSocketAsyncResult (readQ, sockares.Worker, sockares);
+                       QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, sockares));
 
                        return sockares;
                }
 
+               static IOAsyncCallback BeginAcceptCallback = new IOAsyncCallback (ares => {
+                       SocketAsyncResult sockares = (SocketAsyncResult) ares;
+                       Socket acc_socket = null;
+                       try {
+                               if (sockares.AcceptSocket == null) {
+                                       acc_socket = sockares.socket.Accept ();
+                               } else {
+                                       acc_socket = sockares.AcceptSocket;
+                                       sockares.socket.Accept (acc_socket);
+                               }
+
+                       } catch (Exception e) {
+                               sockares.Complete (e);
+                               return;
+                       }
+                       sockares.Complete (acc_socket);
+               });
+
                public IAsyncResult BeginAccept (int receiveSize, AsyncCallback callback, object state)
                {
                        ThrowIfDisposedAndClosed ();
@@ -941,14 +1014,14 @@ namespace System.Net.Sockets
                        if (receiveSize < 0)
                                throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
 
-                       SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive) {
+                       SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
                                Buffer = new byte [receiveSize],
                                Offset = 0,
                                Size = receiveSize,
                                SockFlags = SocketFlags.None,
                        };
 
-                       QueueSocketAsyncResult (readQ, sockares.Worker, sockares);
+                       QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
 
                        return sockares;
                }
@@ -974,8 +1047,8 @@ namespace System.Net.Sockets
                                if (acceptSocket.ProtocolType != ProtocolType.Tcp)
                                        throw new SocketException ((int)SocketError.InvalidArgument);
                        }
-                       
-                       SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive) {
+
+                       SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
                                Buffer = new byte [receiveSize],
                                Offset = 0,
                                Size = receiveSize,
@@ -983,11 +1056,46 @@ namespace System.Net.Sockets
                                AcceptSocket = acceptSocket,
                        };
 
-                       QueueSocketAsyncResult (readQ, sockares.Worker, sockares);
+                       QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
 
                        return sockares;
                }
 
+               static IOAsyncCallback BeginAcceptReceiveCallback = new IOAsyncCallback (ares => {
+                       SocketAsyncResult sockares = (SocketAsyncResult) ares;
+                       Socket acc_socket = null;
+
+                       try {
+                               if (sockares.AcceptSocket == null) {
+                                       acc_socket = sockares.socket.Accept ();
+                               } else {
+                                       acc_socket = sockares.AcceptSocket;
+                                       sockares.socket.Accept (acc_socket);
+                               }
+                       } catch (Exception e) {
+                               sockares.Complete (e);
+                               return;
+                       }
+
+                       /* It seems the MS runtime special-cases 0-length requested receive data.  See bug 464201. */
+                       int total = 0;
+                       if (sockares.Size > 0) {
+                               try {
+                                       SocketError error;
+                                       total = acc_socket.Receive_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out error);
+                                       if (error != 0) {
+                                               sockares.Complete (new SocketException ((int) error));
+                                               return;
+                                       }
+                               } catch (Exception e) {
+                                       sockares.Complete (e);
+                                       return;
+                               }
+                       }
+
+                       sockares.Complete (acc_socket, total);
+               });
+
                public Socket EndAccept (IAsyncResult result)
                {
                        int bytes;
@@ -1015,7 +1123,7 @@ namespace System.Net.Sockets
                        buffer = sockares.Buffer;
                        bytesTransferred = sockares.Total;
 
-                       return sockares.Socket;
+                       return sockares.AcceptedSocket;
                }
 
                static SafeSocketHandle Accept_internal (SafeSocketHandle safeHandle, out int error, bool blocking)
@@ -1043,7 +1151,12 @@ namespace System.Net.Sockets
 
                        if (local_end == null)
                                throw new ArgumentNullException("local_end");
-
+                               
+                       var ipEndPoint = local_end as IPEndPoint;
+                       if (ipEndPoint != null) {
+                               local_end = RemapIPEndPoint (ipEndPoint);       
+                       }
+                       
                        int error;
                        Bind_internal (safe_handle, local_end.Serialize(), out error);
 
@@ -1135,6 +1248,8 @@ namespace System.Net.Sockets
                        int error = 0;
                        foreach (IPAddress address in addresses) {
                                IPEndPoint iep = new IPEndPoint (address, port);
+                               
+                               iep = RemapIPEndPoint (iep);
 
                                Connect_internal (safe_handle, iep.Serialize (), out error);
                                if (error == 0) {
@@ -1179,6 +1294,10 @@ namespace System.Net.Sockets
 
                        if (is_listening)
                                throw new InvalidOperationException ();
+                               
+                       if (ep != null) {
+                               remoteEP = RemapIPEndPoint (ep);
+                       }
 
                        SocketAddress serial = remoteEP.Serialize ();
 
@@ -1209,37 +1328,51 @@ namespace System.Net.Sockets
                        if (e.RemoteEndPoint == null)
                                throw new ArgumentNullException ("remoteEP");
 
-                       e.curSocket = this;
-                       e.Worker.Init (this, e, SocketOperation.Connect);
-
-                       SocketAsyncResult result = e.Worker.result;
+                       InitSocketAsyncEventArgs (e, ConnectAsyncCallback, e, SocketOperation.Connect);
 
                        try {
                                IPAddress [] addresses;
-                               IAsyncResult ares;
+                               SocketAsyncResult ares;
 
                                if (!GetCheckedIPs (e, out addresses)) {
-                                       result.EndPoint = e.RemoteEndPoint;
-                                       ares = BeginConnect (e.RemoteEndPoint, SocketAsyncEventArgs.Dispatcher, e);
+                                       e.socket_async_result.EndPoint = e.RemoteEndPoint;
+                                       ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
                                } else {
                                        DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
-                                       result.Addresses = addresses;
-                                       result.Port = dep.Port;
-                                       ares = BeginConnect (addresses, dep.Port, SocketAsyncEventArgs.Dispatcher, e);
+                                       e.socket_async_result.Addresses = addresses;
+                                       e.socket_async_result.Port = dep.Port;
+                                       ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
                                }
 
                                if (ares.IsCompleted && ares.CompletedSynchronously) {
-                                       ((SocketAsyncResult) ares).CheckIfThrowDelayedException ();
+                                       ares.CheckIfThrowDelayedException ();
                                        return false;
                                }
                        } catch (Exception exc) {
-                               result.Complete (exc, true);
+                               e.socket_async_result.Complete (exc, true);
                                return false;
                        }
 
                        return true;
                }
 
+               static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
+                       SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
+
+                       if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+                               throw new InvalidOperationException ("No operation in progress");
+
+                       try {
+                               e.current_socket.EndConnect (ares);
+                       } catch (SocketException se) {
+                               e.SocketError = se.SocketErrorCode;
+                       } catch (ObjectDisposedException) {
+                               e.SocketError = SocketError.OperationAborted;
+                       } finally {
+                               e.Complete ();
+                       }
+               });
+
                public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback callback, object state)
                {
                        ThrowIfDisposedAndClosed ();
@@ -1279,7 +1412,7 @@ namespace System.Net.Sockets
                        if (end_point == null)
                                throw new ArgumentNullException ("end_point");
 
-                       SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.Connect) {
+                       SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
                                EndPoint = end_point,
                        };
 
@@ -1290,6 +1423,8 @@ namespace System.Net.Sockets
                                        sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
                                        return sockares;
                                }
+                               
+                               end_point = RemapIPEndPoint (ep);
                        }
 
                        int error = 0;
@@ -1300,8 +1435,7 @@ namespace System.Net.Sockets
                                // an error. Better to just close the socket and move on.
                                connect_in_progress = false;
                                safe_handle.Dispose ();
-                               var handle = Socket_internal (address_family, socket_type, protocol_type, out error);
-                               safe_handle = new SafeSocketHandle (handle, true);
+                               safe_handle = new SafeSocketHandle (Socket_internal (address_family, socket_type, protocol_type, out error), true);
                                if (error != 0)
                                        throw new SocketException (error);
                        }
@@ -1334,7 +1468,7 @@ namespace System.Net.Sockets
                        is_bound = false;
                        connect_in_progress = true;
 
-                       socket_pool_queue (SocketAsyncWorker.Dispatcher, sockares);
+                       IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
 
                        return sockares;
                }
@@ -1354,7 +1488,7 @@ namespace System.Net.Sockets
                        if (is_listening)
                                throw new InvalidOperationException ();
 
-                       SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.Connect) {
+                       SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
                                Addresses = addresses,
                                Port = port,
                        };
@@ -1366,17 +1500,21 @@ namespace System.Net.Sockets
 
                internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
                {
-                       IAsyncResult ares = null;
+                       SocketAsyncResult ares = null;
                        Exception exc = null;
+                       AsyncCallback callback;
 
                        for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
                                try {
                                        sockares.CurrentAddress++;
 
-                                       ares = BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
+                                       ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
                                        if (ares.IsCompleted && ares.CompletedSynchronously) {
-                                               ((SocketAsyncResult) ares).CheckIfThrowDelayedException ();
-                                               sockares.DoMConnectCallback ();
+                                               ares.CheckIfThrowDelayedException ();
+
+                                               callback = ares.AsyncCallback;
+                                               if (callback != null)
+                                                       ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
                                        }
 
                                        break;
@@ -1392,6 +1530,57 @@ namespace System.Net.Sockets
                        return sockares;
                }
 
+               static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
+                       SocketAsyncResult sockares = (SocketAsyncResult) ares;
+
+                       if (sockares.EndPoint == null) {
+                               sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
+                               return;
+                       }
+
+                       SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
+                       bool is_mconnect = mconnect != null && mconnect.Addresses != null;
+
+                       try {
+                               EndPoint ep = sockares.EndPoint;
+                               int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
+
+                               if (error_code == 0) {
+                                       if (is_mconnect)
+                                               sockares = mconnect;
+
+                                       sockares.socket.seed_endpoint = ep;
+                                       sockares.socket.is_connected = true;
+                                       sockares.socket.is_bound = true;
+                                       sockares.socket.connect_in_progress = false;
+                                       sockares.error = 0;
+                                       sockares.Complete ();
+                                       return;
+                               }
+
+                               if (!is_mconnect) {
+                                       sockares.socket.connect_in_progress = false;
+                                       sockares.Complete (new SocketException (error_code));
+                                       return;
+                               }
+
+                               if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
+                                       mconnect.Complete (new SocketException (error_code));
+                                       return;
+                               }
+
+                               mconnect.socket.BeginMConnect (mconnect);
+                       } catch (Exception e) {
+                               sockares.socket.connect_in_progress = false;
+
+                               if (is_mconnect)
+                                       sockares = mconnect;
+
+                               sockares.Complete (e);
+                               return;
+                       }
+               });
+
                public void EndConnect (IAsyncResult result)
                {
                        ThrowIfDisposedAndClosed ();
@@ -1472,30 +1661,56 @@ namespace System.Net.Sockets
 
                        ThrowIfDisposedAndClosed ();
 
-                       e.curSocket = this;
-                       e.Worker.Init (this, e, SocketOperation.Disconnect);
-
-                       SocketAsyncResult sockares = e.Worker.result;
+                       InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
 
-                       socket_pool_queue (SocketAsyncWorker.Dispatcher, sockares);
+                       IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
 
                        return true;
                }
 
+               static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
+                       SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
+
+                       if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+                               throw new InvalidOperationException ("No operation in progress");
+
+                       try {
+                               e.current_socket.EndDisconnect (ares);
+                       } catch (SocketException ex) {
+                               e.SocketError = ex.SocketErrorCode;
+                       } catch (ObjectDisposedException) {
+                               e.SocketError = SocketError.OperationAborted;
+                       } finally {
+                               e.Complete ();
+                       }
+               });
 
                public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
                {
                        ThrowIfDisposedAndClosed ();
 
-                       SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.Disconnect) {
+                       SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
                                ReuseSocket = reuseSocket,
                        };
 
-                       socket_pool_queue (SocketAsyncWorker.Dispatcher, sockares);
+                       IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
 
                        return sockares;
                }
 
+               static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
+                       SocketAsyncResult sockares = (SocketAsyncResult) ares;
+
+                       try {
+                               sockares.socket.Disconnect (sockares.ReuseSocket);
+                       } catch (Exception e) {
+                               sockares.Complete (e);
+                               return;
+                       }
+
+                       sockares.Complete ();
+               });
+
                public void EndDisconnect (IAsyncResult asyncResult)
                {
                        ThrowIfDisposedAndClosed ();
@@ -1673,40 +1888,56 @@ namespace System.Net.Sockets
                        if (e.Buffer == null && e.BufferList == null)
                                throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
 
-                       e.curSocket = this;
-                       e.Worker.Init (this, e, e.Buffer != null ? SocketOperation.Receive : SocketOperation.ReceiveGeneric);
+                       if (e.Buffer == null) {
+                               InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
 
-                       SocketAsyncResult sockares = e.Worker.result;
-                       sockares.SockFlags = e.SocketFlags;
+                               e.socket_async_result.Buffers = e.BufferList;
 
-                       if (e.Buffer != null) {
-                               sockares.Buffer = e.Buffer;
-                               sockares.Offset = e.Offset;
-                               sockares.Size = e.Count;
+                               QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
                        } else {
-                               sockares.Buffers = e.BufferList;
-                       }
+                               InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
+
+                               e.socket_async_result.Buffer = e.Buffer;
+                               e.socket_async_result.Offset = e.Offset;
+                               e.socket_async_result.Size = e.Count;
 
-                       // Receive takes care of ReceiveGeneric
-                       QueueSocketAsyncResult (readQ, e.Worker, sockares);
+                               QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
+                       }
 
                        return true;
                }
 
+               static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
+                       SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
+
+                       if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+                               throw new InvalidOperationException ("No operation in progress");
+
+                       try {
+                               e.BytesTransferred = e.current_socket.EndReceive (ares);
+                       } catch (SocketException se){
+                               e.SocketError = se.SocketErrorCode;
+                       } catch (ObjectDisposedException) {
+                               e.SocketError = SocketError.OperationAborted;
+                       } finally {
+                               e.Complete ();
+                       }
+               });
+
                public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
                {
                        ThrowIfDisposedAndClosed ();
                        ThrowIfBufferNull (buffer);
                        ThrowIfBufferOutOfRange (buffer, offset, size);
 
-                       SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.Receive) {
+                       SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
                                Buffer = buffer,
                                Offset = offset,
                                Size = size,
                                SockFlags = socket_flags,
                        };
 
-                       QueueSocketAsyncResult (readQ, sockares.Worker, sockares);
+                       QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
 
                        return sockares;
                }
@@ -1720,6 +1951,20 @@ namespace System.Net.Sockets
                        return BeginReceive (buffer, offset, size, flags, callback, state);
                }
 
+               static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
+                       SocketAsyncResult sockares = (SocketAsyncResult) ares;
+                       int total = 0;
+
+                       try {
+                               total = Receive_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
+                       } catch (Exception e) {
+                               sockares.Complete (e);
+                               return;
+                       }
+
+                       sockares.Complete (total);
+               });
+
                [CLSCompliant (false)]
                public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
                {
@@ -1728,12 +1973,12 @@ namespace System.Net.Sockets
                        if (buffers == null)
                                throw new ArgumentNullException ("buffers");
 
-                       SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveGeneric) {
+                       SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
                                Buffers = buffers,
                                SockFlags = socketFlags,
                        };
 
-                       QueueSocketAsyncResult (readQ, sockares.Worker, sockares);
+                       QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
 
                        return sockares;
                }
@@ -1746,6 +1991,20 @@ namespace System.Net.Sockets
                        return BeginReceive (buffers, socketFlags, callback, state);
                }
 
+               static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
+                       SocketAsyncResult sockares = (SocketAsyncResult) ares;
+                       int total = 0;
+
+                       try {
+                               total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
+                       } catch (Exception e) {
+                               sockares.Complete (e);
+                               return;
+                       }
+
+                       sockares.Complete (total);
+               });
+
                public int EndReceive (IAsyncResult result)
                {
                        SocketError error;
@@ -1777,7 +2036,7 @@ namespace System.Net.Sockets
                        return sockares.Total;
                }
 
-               internal int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
+               int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
                {
                        int nativeError;
                        int ret = Receive_internal (safe_handle, buf, offset, size, flags, out nativeError);
@@ -1827,24 +2086,16 @@ namespace System.Net.Sockets
                {
                        ThrowIfDisposedAndClosed ();
                        ThrowIfBufferNull (buffer);
-                       ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
-
-                       if (remoteEP == null)
-                               throw new ArgumentNullException ("remoteEP");
 
-                       return ReceiveFrom_nochecks (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
+                       return ReceiveFrom (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
                }
 
                public int ReceiveFrom (byte [] buffer, SocketFlags flags, ref EndPoint remoteEP)
                {
                        ThrowIfDisposedAndClosed ();
                        ThrowIfBufferNull (buffer);
-                       ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
-
-                       if (remoteEP == null)
-                               throw new ArgumentNullException ("remoteEP");
 
-                       return ReceiveFrom_nochecks (buffer, 0, buffer.Length, flags, ref remoteEP);
+                       return ReceiveFrom (buffer, 0, buffer.Length, flags, ref remoteEP);
                }
 
                public int ReceiveFrom (byte [] buffer, int size, SocketFlags flags, ref EndPoint remoteEP)
@@ -1853,10 +2104,7 @@ namespace System.Net.Sockets
                        ThrowIfBufferNull (buffer);
                        ThrowIfBufferOutOfRange (buffer, 0, size);
 
-                       if (remoteEP == null)
-                               throw new ArgumentNullException ("remoteEP");
-
-                       return ReceiveFrom_nochecks (buffer, 0, size, flags, ref remoteEP);
+                       return ReceiveFrom (buffer, 0, size, flags, ref remoteEP);
                }
 
                public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags flags, ref EndPoint remoteEP)
@@ -1868,7 +2116,8 @@ namespace System.Net.Sockets
                        if (remoteEP == null)
                                throw new ArgumentNullException ("remoteEP");
 
-                       return ReceiveFrom_nochecks (buffer, offset, size, flags, ref remoteEP);
+                       int error;
+                       return ReceiveFrom_nochecks_exc (buffer, offset, size, flags, ref remoteEP, true, out error);
                }
 
                public bool ReceiveFromAsync (SocketAsyncEventArgs e)
@@ -1881,21 +2130,36 @@ namespace System.Net.Sockets
                        if (e.RemoteEndPoint == null)
                                throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
 
-                       e.curSocket = this;
-                       e.Worker.Init (this, e, SocketOperation.ReceiveFrom);
+                       InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
 
-                       SocketAsyncResult sockares = e.Worker.result;
-                       sockares.Buffer = e.Buffer;
-                       sockares.Offset = e.Offset;
-                       sockares.Size = e.Count;
-                       sockares.EndPoint = e.RemoteEndPoint;
-                       sockares.SockFlags = e.SocketFlags;
+                       e.socket_async_result.Buffer = e.Buffer;
+                       e.socket_async_result.Offset = e.Offset;
+                       e.socket_async_result.Size = e.Count;
+                       e.socket_async_result.EndPoint = e.RemoteEndPoint;
+                       e.socket_async_result.SockFlags = e.SocketFlags;
 
-                       QueueSocketAsyncResult (readQ, e.Worker, sockares);
+                       QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
 
                        return true;
                }
 
+               static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
+                       SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
+
+                       if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+                               throw new InvalidOperationException ("No operation in progress");
+
+                       try {
+                               e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
+                       } catch (SocketException ex) {
+                               e.SocketError = ex.SocketErrorCode;
+                       } catch (ObjectDisposedException) {
+                               e.SocketError = SocketError.OperationAborted;
+                       } finally {
+                               e.Complete ();
+                       }
+               });
+
                public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
                {
                        ThrowIfDisposedAndClosed ();
@@ -1905,7 +2169,7 @@ namespace System.Net.Sockets
                        if (remote_end == null)
                                throw new ArgumentNullException ("remote_end");
 
-                       SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveFrom) {
+                       SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
                                Buffer = buffer,
                                Offset = offset,
                                Size = size,
@@ -1913,11 +2177,26 @@ namespace System.Net.Sockets
                                EndPoint = remote_end,
                        };
 
-                       QueueSocketAsyncResult (readQ, sockares.Worker, sockares);
+                       QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
 
                        return sockares;
                }
 
+               static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
+                       SocketAsyncResult sockares = (SocketAsyncResult) ares;
+                       int total = 0;
+
+                       try {
+                               int error;
+                               total = sockares.socket.ReceiveFrom_nochecks_exc (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, true, out error);
+                       } catch (Exception e) {
+                               sockares.Complete (e);
+                               return;
+                       }
+
+                       sockares.Complete (total);
+               });
+
                public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
                {
                        ThrowIfDisposedAndClosed ();
@@ -1937,12 +2216,6 @@ namespace System.Net.Sockets
                        return sockares.Total;
                }
 
-               internal int ReceiveFrom_nochecks (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end)
-               {
-                       int error;
-                       return ReceiveFrom_nochecks_exc (buf, offset, size, flags, ref remote_end, true, out error);
-               }
-
                internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end, bool throwOnError, out int error)
                {
                        SocketAddress sockaddr = remote_end.Serialize();
@@ -2188,7 +2461,7 @@ namespace System.Net.Sockets
                        return ret;
                }
 
-               internal int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
+               int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
                {
                        if (size == 0) {
                                error = SocketError.Success;
@@ -2219,26 +2492,42 @@ namespace System.Net.Sockets
                        if (e.Buffer == null && e.BufferList == null)
                                throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
 
-                       e.curSocket = this;
-                       e.Worker.Init (this, e, e.Buffer != null ? SocketOperation.Send : SocketOperation.SendGeneric);
+                       if (e.Buffer == null) {
+                               InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
 
-                       SocketAsyncResult sockares = e.Worker.result;
-                       sockares.SockFlags = e.SocketFlags;
+                               e.socket_async_result.Buffers = e.BufferList;
 
-                       if (e.Buffer != null) {
-                               sockares.Buffer = e.Buffer;
-                               sockares.Offset = e.Offset;
-                               sockares.Size = e.Count;
+                               QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
                        } else {
-                               sockares.Buffers = e.BufferList;
-                       }
+                               InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
 
-                       // Send takes care of SendGeneric
-                       QueueSocketAsyncResult (writeQ, e.Worker, sockares);
+                               e.socket_async_result.Buffer = e.Buffer;
+                               e.socket_async_result.Offset = e.Offset;
+                               e.socket_async_result.Size = e.Count;
+
+                               QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
+                       }
 
                        return true;
                }
 
+               static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
+                       SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
+
+                       if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+                               throw new InvalidOperationException ("No operation in progress");
+
+                       try {
+                               e.BytesTransferred = e.current_socket.EndSend (ares);
+                       } catch (SocketException se){
+                               e.SocketError = se.SocketErrorCode;
+                       } catch (ObjectDisposedException) {
+                               e.SocketError = SocketError.OperationAborted;
+                       } finally {
+                               e.Complete ();
+                       }
+               });
+
                public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
                {
                        if (!is_connected) {
@@ -2259,18 +2548,50 @@ namespace System.Net.Sockets
                        if (!is_connected)
                                throw new SocketException ((int)SocketError.NotConnected);
 
-                       SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.Send) {
+                       SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
                                Buffer = buffer,
                                Offset = offset,
                                Size = size,
                                SockFlags = socket_flags,
                        };
 
-                       QueueSocketAsyncResult (writeQ, sockares.Worker, sockares);
+                       QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
 
                        return sockares;
                }
 
+               static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
+               {
+                       int total = 0;
+
+                       try {
+                               total = Socket.Send_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
+                       } catch (Exception e) {
+                               sockares.Complete (e);
+                               return;
+                       }
+
+                       if (sockares.error == 0) {
+                               sent_so_far += total;
+                               sockares.Offset += total;
+                               sockares.Size -= total;
+
+                               if (sockares.socket.is_disposed) {
+                                       sockares.Complete (total);
+                                       return;
+                               }
+
+                               if (sockares.Size > 0) {
+                                       IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
+                                       return; // Have to finish writing everything. See bug #74475.
+                               }
+
+                               sockares.Total = sent_so_far;
+                       }
+
+                       sockares.Complete (total);
+               }
+
                public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
                {
                        ThrowIfDisposedAndClosed ();
@@ -2280,12 +2601,12 @@ namespace System.Net.Sockets
                        if (!is_connected)
                                throw new SocketException ((int)SocketError.NotConnected);
 
-                       SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.SendGeneric) {
+                       SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
                                Buffers = buffers,
                                SockFlags = socketFlags,
                        };
 
-                       QueueSocketAsyncResult (writeQ, sockares.Worker, sockares);
+                       QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
 
                        return sockares;
                }
@@ -2302,6 +2623,20 @@ namespace System.Net.Sockets
                        return BeginSend (buffers, socketFlags, callback, state);
                }
 
+               static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
+                       SocketAsyncResult sockares = (SocketAsyncResult) ares;
+                       int total = 0;
+
+                       try {
+                               total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
+                       } catch (Exception e) {
+                               sockares.Complete (e);
+                               return;
+                       }
+
+                       sockares.Complete (total);
+               });
+
                public int EndSend (IAsyncResult result)
                {
                        SocketError error;
@@ -2369,36 +2704,21 @@ namespace System.Net.Sockets
                {
                        ThrowIfDisposedAndClosed ();
                        ThrowIfBufferNull (buffer);
-                       ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
-
-                       if (remote_end == null)
-                               throw new ArgumentNullException ("remote_end");
 
-                       return SendTo_nochecks (buffer, 0, buffer.Length, SocketFlags.None, remote_end);
+                       return SendTo (buffer, 0, buffer.Length, SocketFlags.None, remote_end);
                }
 
                public int SendTo (byte [] buffer, SocketFlags flags, EndPoint remote_end)
                {
                        ThrowIfDisposedAndClosed ();
                        ThrowIfBufferNull (buffer);
-                       ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
-
-                       if (remote_end == null)
-                               throw new ArgumentNullException ("remote_end");
 
-                       return SendTo_nochecks (buffer, 0, buffer.Length, flags, remote_end);
+                       return SendTo (buffer, 0, buffer.Length, flags, remote_end);
                }
 
                public int SendTo (byte [] buffer, int size, SocketFlags flags, EndPoint remote_end)
                {
-                       ThrowIfDisposedAndClosed ();
-                       ThrowIfBufferNull (buffer);
-                       ThrowIfBufferOutOfRange (buffer, 0, size);
-
-                       if (remote_end == null)
-                               throw new ArgumentNullException ("remote_end");
-
-                       return SendTo_nochecks (buffer, 0, size, flags, remote_end);
+                       return SendTo (buffer, 0, size, flags, remote_end);
                }
 
                public int SendTo (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
@@ -2413,25 +2733,6 @@ namespace System.Net.Sockets
                        return SendTo_nochecks (buffer, offset, size, flags, remote_end);
                }
 
-               internal int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
-               {
-                       int error;
-                       int ret = SendTo_internal (safe_handle, buffer, offset, size, flags, remote_end.Serialize (), out error);
-
-                       SocketError err = (SocketError) error;
-                       if (err != 0) {
-                               if (err != SocketError.WouldBlock && err != SocketError.InProgress)
-                                       is_connected = false;
-                               throw new SocketException (error);
-                       }
-
-                       is_connected = true;
-                       is_bound = true;
-                       seed_endpoint = remote_end;
-
-                       return ret;
-               }
-
                public bool SendToAsync (SocketAsyncEventArgs e)
                {
                        // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
@@ -2443,21 +2744,35 @@ namespace System.Net.Sockets
                        if (e.RemoteEndPoint == null)
                                throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
 
-                       e.curSocket = this;
-                       e.Worker.Init (this, e, SocketOperation.SendTo);
+                       InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
 
-                       SocketAsyncResult sockares = e.Worker.result;
-                       sockares.Buffer = e.Buffer;
-                       sockares.Offset = e.Offset;
-                       sockares.Size = e.Count;
-                       sockares.SockFlags = e.SocketFlags;
-                       sockares.EndPoint = e.RemoteEndPoint;
+                       e.socket_async_result.Buffer = e.Buffer;
+                       e.socket_async_result.Offset = e.Offset;
+                       e.socket_async_result.Size = e.Count;
+                       e.socket_async_result.SockFlags = e.SocketFlags;
+                       e.socket_async_result.EndPoint = e.RemoteEndPoint;
 
-                       QueueSocketAsyncResult (writeQ, e.Worker, sockares);
+                       QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
 
                        return true;
                }
 
+               static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
+                       SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
+
+                       if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
+                               throw new InvalidOperationException ("No operation in progress");
+
+                       try {
+                               e.BytesTransferred = e.current_socket.EndSendTo (ares);
+                       } catch (SocketException ex) {
+                               e.SocketError = ex.SocketErrorCode;
+                       } catch (ObjectDisposedException) {
+                               e.SocketError = SocketError.OperationAborted;
+                       } finally {
+                               e.Complete ();
+                       }
+               });
 
                public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
                {
@@ -2465,7 +2780,7 @@ namespace System.Net.Sockets
                        ThrowIfBufferNull (buffer);
                        ThrowIfBufferOutOfRange (buffer, offset, size);
 
-                       SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.SendTo) {
+                       SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
                                Buffer = buffer,
                                Offset = offset,
                                Size = size,
@@ -2473,11 +2788,37 @@ namespace System.Net.Sockets
                                EndPoint = remote_end,
                        };
 
-                       QueueSocketAsyncResult (writeQ, sockares.Worker, sockares);
+                       QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
 
                        return sockares;
                }
 
+               static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
+               {
+                       int total = 0;
+                       try {
+                               total = sockares.socket.SendTo_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
+
+                               if (sockares.error == 0) {
+                                       sent_so_far += total;
+                                       sockares.Offset += total;
+                                       sockares.Size -= total;
+                               }
+
+                               if (sockares.Size > 0) {
+                                       IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
+                                       return; // Have to finish writing everything. See bug #74475.
+                               }
+
+                               sockares.Total = sent_so_far;
+                       } catch (Exception e) {
+                               sockares.Complete (e);
+                               return;
+                       }
+
+                       sockares.Complete ();
+               }
+
                public int EndSendTo (IAsyncResult result)
                {
                        ThrowIfDisposedAndClosed ();
@@ -2492,6 +2833,25 @@ namespace System.Net.Sockets
                        return sockares.Total;
                }
 
+               int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
+               {
+                       int error;
+                       int ret = SendTo_internal (safe_handle, buffer, offset, size, flags, remote_end.Serialize (), out error);
+
+                       SocketError err = (SocketError) error;
+                       if (err != 0) {
+                               if (err != SocketError.WouldBlock && err != SocketError.InProgress)
+                                       is_connected = false;
+                               throw new SocketException (error);
+                       }
+
+                       is_connected = true;
+                       is_bound = true;
+                       seed_endpoint = remote_end;
+
+                       return ret;
+               }
+
                static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
                {
                        try {
@@ -2807,23 +3167,18 @@ namespace System.Net.Sockets
 
                public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
                {
-                       ThrowIfDisposedAndClosed ();
-
-                       int error;
                        int int_val = optionValue ? 1 : 0;
-                       SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, int_val, out error);
 
-                       if (error != 0) {
-                               if (error == (int) SocketError.InvalidArgument)
-                                       throw new ArgumentException ();
-                               throw new SocketException (error);
-                       }
+                       SetSocketOption (optionLevel, optionName, int_val);
                }
 
                public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
                {
                        ThrowIfDisposedAndClosed ();
 
+                       if (optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse ())
+                               throw new SocketException ((int) SocketError.OperationNotSupported, "Operating system sockets do not support ReuseAddress.\nIf your socket is not intended to bind to the same address and port multiple times remove this option, otherwise you should ignore this exception inside a try catch and check that ReuseAddress is true before binding to the same address and port multiple times.");
+
                        int error;
                        SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, optionValue, out error);
 
@@ -2942,7 +3297,7 @@ namespace System.Net.Sockets
                }
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
+               internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
 
 #endregion
 
@@ -3058,18 +3413,62 @@ namespace System.Net.Sockets
                        return sockares;
                }
 
-               void QueueSocketAsyncResult (Queue queue, SocketAsyncWorker worker, SocketAsyncResult sockares)
+               void QueueIOSelectorJob (Queue<KeyValuePair<IntPtr, IOSelectorJob>> queue, IntPtr handle, IOSelectorJob job)
                {
                        int count;
                        lock (queue) {
-                               queue.Enqueue (worker);
+                               queue.Enqueue (new KeyValuePair<IntPtr, IOSelectorJob> (handle, job));
                                count = queue.Count;
                        }
 
                        if (count == 1)
-                               socket_pool_queue (SocketAsyncWorker.Dispatcher, sockares);
+                               IOSelector.Add (handle, job);
+               }
+
+               void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
+               {
+                       e.socket_async_result.Init (this, callback, state, operation);
+                       if (e.AcceptSocket != null) {
+                               e.socket_async_result.AcceptSocket = e.AcceptSocket;
+                       }
+                       e.current_socket = this;
+                       e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
+                       e.SocketError = SocketError.Success;
+                       e.BytesTransferred = 0;
+               }
+
+               SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
+               {
+                       switch (op) {
+                       case SocketOperation.Connect:
+                               return SocketAsyncOperation.Connect;
+                       case SocketOperation.Accept:
+                               return SocketAsyncOperation.Accept;
+                       case SocketOperation.Disconnect:
+                               return SocketAsyncOperation.Disconnect;
+                       case SocketOperation.Receive:
+                       case SocketOperation.ReceiveGeneric:
+                               return SocketAsyncOperation.Receive;
+                       case SocketOperation.ReceiveFrom:
+                               return SocketAsyncOperation.ReceiveFrom;
+                       case SocketOperation.Send:
+                       case SocketOperation.SendGeneric:
+                               return SocketAsyncOperation.Send;
+                       case SocketOperation.SendTo:
+                               return SocketAsyncOperation.SendTo;
+                       default:
+                               throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
+                       }
                }
-
+               
+               IPEndPoint RemapIPEndPoint (IPEndPoint input) {
+                       // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
+                       if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
+                               return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
+                       
+                       return input;
+               }
+               
                [StructLayout (LayoutKind.Sequential)]
                struct WSABUF {
                        public int len;
@@ -3080,7 +3479,7 @@ namespace System.Net.Sockets
                internal static extern void cancel_blocking_socket_operation (Thread thread);
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               internal static extern void socket_pool_queue (SocketAsyncCallback d, SocketAsyncResult r);
+               internal static extern bool SupportsPortReuse ();
        }
 }