2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / class / System / System.Net.Sockets / Socket.cs
index 233fcf6bcc717b4bc32e74aa6c243e59494fd235..2435e1ba914fc4ff2745b3baf780915fd0c56b5f 100644 (file)
@@ -4,10 +4,12 @@
 //     Phillip Pearson (pp@myelin.co.nz)
 //     Dick Porter <dick@ximian.com>
 //     Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//     Sridhar Kulkarni (sridharkulkarni@gmail.com)
+//     Brian Nickel (brian.nickel@gmail.com)
 //
 // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
 //    http://www.myelin.co.nz
-// (c) 2004 Novell, Inc. (http://www.novell.com)
+// (c) 2004-2006 Novell, Inc. (http://www.novell.com)
 //
 
 //
@@ -40,10 +42,19 @@ using System.Threading;
 using System.Reflection;
 using System.IO;
 using System.Net.Configuration;
+using System.Text;
+
+#if NET_2_0
+using System.Collections.Generic;
+using System.Net.NetworkInformation;
+#if !NET_2_1
+using System.Timers;
+#endif
+#endif
 
 namespace System.Net.Sockets 
 {
-       public class Socket : IDisposable 
+       public partial class Socket : IDisposable
        {
                enum SocketOperation {
                        Accept,
@@ -55,13 +66,30 @@ namespace System.Net.Sockets
                        UsedInManaged1,
                        UsedInManaged2,
                        UsedInProcess,
-                       UsedInConsole2
+                       UsedInConsole2,
+                       Disconnect,
+                       AcceptReceive,
+                       ReceiveGeneric,
+                       SendGeneric
                }
 
                [StructLayout (LayoutKind.Sequential)]
-               private sealed class SocketAsyncResult: IAsyncResult 
+               struct WSABUF 
+               {
+                       public int len;
+                       public IntPtr buf;
+               };
+
+               [StructLayout (LayoutKind.Sequential)]
+               private sealed class SocketAsyncResult: IAsyncResult
                {
                        /* Same structure in the runtime */
+                       /*
+                         Keep this in sync with MonoSocketAsyncResult in
+                         metadata/socket-io.h and ProcessAsyncReader
+                         in System.Diagnostics/Process.cs.
+                       */
+
                        public Socket Sock;
                        public IntPtr handle;
                        object state;
@@ -75,6 +103,15 @@ namespace System.Net.Sockets
                        public int Offset;              // Receive,ReceiveFrom,Send,SendTo
                        public int Size;                // Receive,ReceiveFrom,Send,SendTo
                        public SocketFlags SockFlags;   // Receive,ReceiveFrom,Send,SendTo
+                       public Socket AcceptSocket;     // AcceptReceive
+                       public IPAddress[] Addresses;   // Connect
+                       public int Port;                // Connect
+#if NET_2_0
+                       public IList<ArraySegment<byte>> Buffers;       // Receive, Send
+#else
+                       public object Buffers;          // Reserve this slot in older profiles
+#endif
+                       public bool ReuseSocket;        // Disconnect
 
                        // Return values
                        Socket acc_socket;
@@ -86,6 +123,7 @@ namespace System.Net.Sockets
                        internal int error;
                        SocketOperation operation;
                        public object ares;
+                       public int EndCalled;
 
                        public SocketAsyncResult (Socket sock, object state, AsyncCallback callback, SocketOperation operation)
                        {
@@ -100,10 +138,13 @@ namespace System.Net.Sockets
 
                        public void CheckIfThrowDelayedException ()
                        {
-                               if (delayedException != null)
+                               if (delayedException != null) {
+                                       Sock.connected = false;
                                        throw delayedException;
+                               }
 
                                if (error != 0) {
+                                       Sock.connected = false;
                                        throw new SocketException (error);
                                }
                        }
@@ -119,6 +160,8 @@ namespace System.Net.Sockets
                                        cb = new WaitCallback (ares.CompleteDisposed);
                                        ThreadPool.QueueUserWorkItem (cb, null);
                                }
+                               if (pending.Length == 0)
+                                       Buffer = null;
                        }
 
                        void CompleteDisposed (object unused)
@@ -162,6 +205,7 @@ namespace System.Net.Sockets
 
                                if (callback != null)
                                        callback (this);
+                               Buffer = null;
                        }
 
                        SocketAsyncCall GetDelegate (Worker worker, SocketOperation op)
@@ -211,6 +255,13 @@ namespace System.Net.Sockets
                                Complete ();
                        }
 
+                       public void Complete (Socket s, int total)
+                       {
+                               acc_socket = s;
+                               this.total = total;
+                               Complete ();
+                       }
+
                        public object AsyncState {
                                get {
                                        return state;
@@ -261,6 +312,22 @@ namespace System.Net.Sockets
                                get { return total; }
                                set { total = value; }
                        }
+
+                       public SocketError ErrorCode
+                       {
+                               get {
+#if NET_2_0
+                                       SocketException ex = delayedException as SocketException;
+                                       
+                                       if (ex != null)
+                                               return(ex.SocketErrorCode);
+
+                                       if (error != 0)
+                                               return((SocketError)error);
+#endif
+                                       return(SocketError.Success);
+                               }
+                       }
                }
 
                private sealed class Worker 
@@ -285,28 +352,131 @@ namespace System.Net.Sockets
                                result.Complete (acc_socket);
                        }
 
-                       public void Connect ()
+                       /* only used in 2.0 profile and newer, but
+                        * leave in older profiles to keep interface
+                        * to runtime consistent
+                        */
+                       public void AcceptReceive ()
                        {
+                               Socket acc_socket = null;
+                               
                                try {
-                                       if (!result.Sock.Blocking) {
-                                               int success;
-                                               result.Sock.Poll (-1, SelectMode.SelectWrite, out success);
-                                               if (success == 0) {
-                                                       result.Sock.connected = true;
+                                       if (result.AcceptSocket == null) {
+                                               acc_socket = result.Sock.Accept ();
+                                       } else {
+                                               acc_socket = result.AcceptSocket;
+                                               result.Sock.Accept (acc_socket);
+                                       }
+                               } catch (Exception e) {
+                                       result.Complete (e);
+                                       return;
+                               }
+
+                               /* It seems the MS runtime
+                                * special-cases 0-length requested
+                                * receive data.  See bug 464201.
+                                */
+                               int total = 0;
+                               if (result.Size > 0) {
+                                       try {
+                                               SocketError error;
+                                       
+                                               total = acc_socket.Receive_nochecks (result.Buffer,
+                                                                                    result.Offset,
+                                                                                    result.Size,
+                                                                                    result.SockFlags,
+                                                                                    out error);
+                                       } catch (Exception e) {
+                                               result.Complete (e);
+                                               return;
+                                       }
+                               }
+
+                               result.Complete (acc_socket, total);
+                       }
+
+                       public void Connect ()
+                       {
+                               /* If result.EndPoint is non-null,
+                                * this is the standard one-address
+                                * connect attempt.  Otherwise
+                                * Addresses must be non-null and
+                                * contain a list of addresses to try
+                                * to connect to; the first one to
+                                * succeed causes the rest of the list
+                                * to be ignored.
+                                */
+                               if (result.EndPoint != null) {
+                                       try {
+                                               if (!result.Sock.Blocking) {
+                                                       int success;
+                                                       result.Sock.Poll (-1, SelectMode.SelectWrite, out success);
+                                                       if (success == 0) {
+                                                               result.Sock.connected = true;
+                                                       } else {
+                                                               result.Complete (new SocketException (success));
+                                                               return;
+                                                       }
                                                } else {
-                                                       result.Complete (new SocketException (success));
+                                                       result.Sock.seed_endpoint = result.EndPoint;
+                                                       result.Sock.Connect (result.EndPoint);
+                                                       result.Sock.connected = true;
+                                               }
+                                       } catch (Exception e) {
+                                               result.Complete (e);
+                                               return;
+                                       }
+
+                                       result.Complete ();
+                               } else if (result.Addresses != null) {
+                                       int error = (int) SocketError.InProgress; // why?
+                                       foreach(IPAddress address in result.Addresses) {
+                                               IPEndPoint iep = new IPEndPoint (address, result.Port);
+                                               SocketAddress serial = iep.Serialize ();
+                                               
+                                               Socket.Connect_internal (result.Sock.socket, serial, out error);
+                                               if (error == 0) {
+                                                       result.Sock.connected = true;
+                                                       result.Sock.seed_endpoint = iep;
+                                                       result.Complete ();
                                                        return;
+                                               } else if (error != (int)SocketError.InProgress &&
+                                                          error != (int)SocketError.WouldBlock) {
+                                                       continue;
+                                               }
+
+                                               if (!result.Sock.Blocking) {
+                                                       int success;
+                                                       result.Sock.Poll (-1, SelectMode.SelectWrite, out success);
+                                                       if (success == 0) {
+                                                               result.Sock.connected = true;
+                                                               result.Sock.seed_endpoint = iep;
+                                                               result.Complete ();
+                                                               return;
+                                                       }
                                                }
-                                       } else {
-                                               result.Sock.Connect (result.EndPoint);
-                                               result.Sock.connected = true;
                                        }
+                                       
+                                       result.Complete (new SocketException (error));
+                               } else {
+                                       result.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
+                               }
+                       }
+
+                       /* Also only used in 2.0 profile and newer */
+                       public void Disconnect ()
+                       {
+#if NET_2_0
+                               try {
+                                       result.Sock.Disconnect (result.ReuseSocket);
                                } catch (Exception e) {
                                        result.Complete (e);
                                        return;
                                }
-
                                result.Complete ();
+#else
+                               result.Complete (new SocketException ((int)SocketError.Fault));
+#endif
                        }
 
                        public void Receive ()
@@ -332,6 +502,25 @@ namespace System.Net.Sockets
                                result.Complete (total);
                        }
 
+                       public void ReceiveGeneric ()
+                       {
+#if NET_2_0
+                               int total = 0;
+                               try {
+                                       SocketError error;
+                                       
+                                       total = result.Sock.Receive (result.Buffers, result.SockFlags, out error);
+                               } catch (Exception e) {
+                                       result.Complete (e);
+                                       return;
+                               }
+                               
+                               result.Complete (total);
+#else
+                               result.Complete (new SocketException ((int)SocketError.Fault));
+#endif
+                       }
+
                        int send_so_far;
 
                        void UpdateSendValues (int last_sent)
@@ -387,38 +576,37 @@ namespace System.Net.Sockets
 
                                result.Complete ();
                        }
+
+                       public void SendGeneric ()
+                       {
+#if NET_2_0
+                               int total = 0;
+                               try {
+                                       SocketError error;
+                                       
+                                       total = result.Sock.Send (result.Buffers, result.SockFlags, out error);
+                               } catch (Exception e) {
+                                       result.Complete (e);
+                                       return;
+                               }
+                               
+                               result.Complete (total);
+#else
+                               result.Complete (new SocketException ((int)SocketError.Fault));
+#endif
+                       }
                }
                        
-               /* the field "socket" is looked up by name by the runtime */
-               private IntPtr socket;
-               private AddressFamily address_family;
-               private SocketType socket_type;
-               private ProtocolType protocol_type;
-               internal bool blocking=true;
+
                private Queue readQ = new Queue (2);
                private Queue writeQ = new Queue (2);
 
                delegate void SocketAsyncCall ();
-               /*
-                *      These two fields are looked up by name by the runtime, don't change
-                *  their name without also updating the runtime code.
-                */
-               private static int ipv4Supported = -1, ipv6Supported = -1;
-
-               /* When true, the socket was connected at the time of
-                * the last IO operation
-                */
-               private bool connected=false;
-               /* true if we called Close_internal */
-               private bool closed;
-               internal bool disposed;
-               
 
-               /* Used in LocalEndPoint and RemoteEndPoint if the
-                * Mono.Posix assembly is available
-                */
-               private static object unixendpoint=null;
-               private static Type unixendpointtype=null;
+#if NET_2_0
+               private bool islistening;
+               private bool useoverlappedIO;
+#endif
                
 
                static void AddSockets (ArrayList sockets, IList list, string name)
@@ -426,7 +614,7 @@ namespace System.Net.Sockets
                        if (list != null) {
                                foreach (Socket sock in list) {
                                        if (sock == null) // MS throws a NullRef
-                                               throw new ArgumentNullException (name, "Contains a null element");
+                                               throw new ArgumentNullException ("name", "Contains a null element");
                                        sockets.Add (sock);
                                }
                        }
@@ -463,69 +651,55 @@ namespace System.Net.Sockets
                        if (error != 0)
                                throw new SocketException (error);
 
-                       if (checkRead != null)
-                               checkRead.Clear ();
-
-                       if (checkWrite != null)
-                               checkWrite.Clear ();
-
-                       if (checkError != null)
-                               checkError.Clear ();
-
-                       if (sockets == null)
+                       if (sockets == null) {
+                               if (checkRead != null)
+                                       checkRead.Clear ();
+                               if (checkWrite != null)
+                                       checkWrite.Clear ();
+                               if (checkError != null)
+                                       checkError.Clear ();
                                return;
+                       }
 
                        int mode = 0;
                        int count = sockets.Length;
                        IList currentList = checkRead;
+                       int currentIdx = 0;
                        for (int i = 0; i < count; i++) {
+                               Socket cur_sock;
                                Socket sock = sockets [i];
                                if (sock == null) { // separator
+                                       if (currentList != null) {
+                                               // Remove non-signaled sockets after the current one
+                                               int to_remove = currentList.Count - currentIdx;
+                                               for (int k = 0; k < to_remove; k++)
+                                                       currentList.RemoveAt (currentIdx);
+                                       }
                                        currentList = (mode == 0) ? checkWrite : checkError;
+                                       currentIdx = 0;
                                        mode++;
                                        continue;
                                }
 
-                               if (currentList != null) {
-                                       if (currentList == checkWrite) {
-                                               if ((int)sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0) {
-                                                       sock.connected = true;
-                                               }
-                                       }
-                                       
-                                       currentList.Add (sock);
+                               if (mode == 1 && currentList == checkWrite && !sock.connected) {
+                                       if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
+                                               sock.connected = true;
                                }
-                       }
-               }
 
-               static Socket() {
-                       Assembly ass;
-                       
-                       try {
-                               ass = Assembly.Load (Consts.AssemblyMono_Posix);
-                       } catch (FileNotFoundException) {
-                               return;
+                               // Remove non-signaled sockets before the current one
+                               int max = currentList.Count;
+                               while ((cur_sock = (Socket) currentList [currentIdx]) != sock) {
+                                       currentList.RemoveAt (currentIdx);
+                               }
+                               currentIdx++;
                        }
-                               
-                       unixendpointtype=ass.GetType("Mono.Posix.UnixEndPoint");
-
-                       /* The endpoint Create() method is an instance
-                        * method :-(
-                        */
-                       Type[] arg_types=new Type[1];
-                       arg_types[0]=typeof(string);
-                       ConstructorInfo cons=unixendpointtype.GetConstructor(arg_types);
-
-                       object[] args=new object[1];
-                       args[0]="nothing";
-
-                       unixendpoint=cons.Invoke(args);
                }
 
                // private constructor used by Accept, which already
                // has a socket handle to use
                private Socket(AddressFamily family, SocketType type,
-                              ProtocolType proto, IntPtr sock) {
+                              ProtocolType proto, IntPtr sock)
+               {
                        address_family=family;
                        socket_type=type;
                        protocol_type=proto;
@@ -533,40 +707,67 @@ namespace System.Net.Sockets
                        socket=sock;
                        connected=true;
                }
-#if !TARGET_JVM
-               // Creates a new system socket, returning the handle
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern IntPtr Socket_internal(AddressFamily family,
-                                                     SocketType type,
-                                                     ProtocolType proto,
-                                                     out int error);
-#endif         
-               public Socket(AddressFamily family, SocketType type,
-                             ProtocolType proto) {
-                       address_family=family;
-                       socket_type=type;
-                       protocol_type=proto;
+
+               private void SocketDefaults ()
+               {
+#if NET_2_0
+                       try {
+                               if (address_family == AddressFamily.InterNetwork /* Need to test IPv6 further ||
+                                                                                  address_family == AddressFamily.InterNetworkV6 */) {
+                                       /* This is the default, but it
+                                        * probably has nasty side
+                                        * effects on Linux, as the
+                                        * socket option is kludged by
+                                        * turning on or off PMTU
+                                        * discovery...
+                                        */
+                                       this.DontFragment = false;
+                               }
+
+                               //
+                               // Microsoft sets these to 8192, but we are going to keep them
+                               // both to the OS defaults as these have a big performance impact.
+                               // on WebClient performance.
+                               //
+                               //this.ReceiveBufferSize = 8192;
+                               //this.SendBufferSize = 8192;
+                       } catch (SocketException) {
+                       }
+#endif
+               }
+
+
+#if NET_2_0
+               [MonoTODO]
+               public Socket (SocketInformation socketInformation)
+               {
+                       throw new NotImplementedException ("SocketInformation not figured out yet");
+
+                       // ifdef to avoid the warnings.
+#if false
+                       //address_family = socketInformation.address_family;
+                       //socket_type = socketInformation.socket_type;
+                       //protocol_type = socketInformation.protocol_type;
+                       address_family = AddressFamily.InterNetwork;
+                       socket_type = SocketType.Stream;
+                       protocol_type = ProtocolType.IP;
                        
                        int error;
-                       
-                       socket=Socket_internal(family, type, proto, out error);
-                       if (error != 0) {
+                       socket = Socket_internal (address_family, socket_type, protocol_type, out error);
+                       if (error != 0)
                                throw new SocketException (error);
-                       }
-               }
 
-               public AddressFamily AddressFamily {
-                       get {
-                               return(address_family);
-                       }
+                       SocketDefaults ();
+#endif
                }
+#endif
+
 #if !TARGET_JVM
                // Returns the amount of data waiting to be read on socket
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static int Available_internal(IntPtr socket,
-                                                            out int error);
+               private extern static int Available_internal(IntPtr socket, out int error);
 #endif
-               
+
                public int Available {
                        get {
                                if (disposed && closed)
@@ -576,151 +777,260 @@ namespace System.Net.Sockets
                                
                                ret = Available_internal(socket, out error);
 
-                               if (error != 0) {
+                               if (error != 0)
                                        throw new SocketException (error);
-                               }
 
                                return(ret);
                        }
                }
-#if !TARGET_JVM
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static void Blocking_internal(IntPtr socket,
-                                                            bool block,
-                                                            out int error);
-#endif
-               public bool Blocking {
+
+
+#if NET_2_0
+               public bool DontFragment {
                        get {
-                               return(blocking);
-                       }
-                       set {
-                               if (disposed && closed)
+                               if (disposed && closed) {
                                        throw new ObjectDisposedException (GetType ().ToString ());
+                               }
 
-                               int error;
+                               bool dontfragment;
                                
-                               Blocking_internal(socket, value, out error);
-
-                               if (error != 0) {
-                                       throw new SocketException (error);
+                               if (address_family == AddressFamily.InterNetwork) {
+                                       dontfragment = (int)(GetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment)) != 0;
+                               } else if (address_family == AddressFamily.InterNetworkV6) {
+                                       dontfragment = (int)(GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment)) != 0;
+                               } else {
+                                       throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
                                }
                                
-                               blocking=value;
+                               return(dontfragment);
                        }
-               }
+                       set {
+                               if (disposed && closed) {
+                                       throw new ObjectDisposedException (GetType ().ToString ());
+                               }
 
-               public bool Connected {
-                       get {
-                               return(connected);
+                               if (address_family == AddressFamily.InterNetwork) {
+                                       SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment, value?1:0);
+                               } else if (address_family == AddressFamily.InterNetworkV6) {
+                                       SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment, value?1:0);
+                               } else {
+                                       throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
+                               }
                        }
                }
 
-               public IntPtr Handle {
+               public bool EnableBroadcast {
                        get {
-                               return(socket);
-                       }
-               }
-#if !TARGET_JVM
-               // Returns the local endpoint details in addr and port
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static SocketAddress LocalEndPoint_internal(IntPtr socket, out int error);
-#endif
-               // Wish:  support non-IP endpoints.
-               public EndPoint LocalEndPoint {
-                       get {
-                               if (disposed && closed)
+                               if (disposed && closed) {
                                        throw new ObjectDisposedException (GetType ().ToString ());
+                               }
 
-                               SocketAddress sa;
-                               int error;
+                               if (protocol_type != ProtocolType.Udp) {
+                                       throw new SocketException ((int)SocketError.ProtocolOption);
+                               }
                                
-                               sa=LocalEndPoint_internal(socket, out error);
-
-                               if (error != 0) {
-                                       throw new SocketException (error);
+                               return((int)(GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0);
+                       }
+                       set {
+                               if (disposed && closed) {
+                                       throw new ObjectDisposedException (GetType ().ToString ());
                                }
 
-                               if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6) {
-                                       // Stupidly, EndPoint.Create() is an
-                                       // instance method
-                                       return new IPEndPoint(0, 0).Create(sa);
-                               } else if (sa.Family==AddressFamily.Unix &&
-                                          unixendpoint!=null) {
-                                       return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
-                               } else {
-                                       throw new NotImplementedException();
+                               if (protocol_type != ProtocolType.Udp) {
+                                       throw new SocketException ((int)SocketError.ProtocolOption);
                                }
-                       }
-               }
 
-               public ProtocolType ProtocolType {
-                       get {
-                               return(protocol_type);
+                               SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value?1:0);
                        }
                }
-
-               // Returns the remote endpoint details in addr and port
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket, out int error);
-
-               //
-               // Wish: Support non-IP endpoints
-               //
-               public EndPoint RemoteEndPoint {
+               
+               public bool ExclusiveAddressUse {
                        get {
-                               if (disposed && closed)
+                               if (disposed && closed) {
                                        throw new ObjectDisposedException (GetType ().ToString ());
-
-                               SocketAddress sa;
-                               int error;
-                               
-                               sa=RemoteEndPoint_internal(socket, out error);
-
-                               if (error != 0) {
-                                       throw new SocketException (error);
                                }
 
-                               if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6 ) {
-                                       // Stupidly, EndPoint.Create() is an
-                                       // instance method
-                                       return new IPEndPoint(0, 0).Create(sa);
-                               } else if (sa.Family==AddressFamily.Unix &&
-                                          unixendpoint!=null) {
-                                       return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
-                               } else {
-                                       throw new NotImplementedException();
+                               return((int)(GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse)) != 0);
+                       }
+                       set {
+                               if (disposed && closed) {
+                                       throw new ObjectDisposedException (GetType ().ToString ());
+                               }
+                               if (isbound) {
+                                       throw new InvalidOperationException ("Bind has already been called for this socket");
                                }
+                               
+                               SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value?1:0);
                        }
                }
-
-               public SocketType SocketType {
+               
+               public bool IsBound {
                        get {
-                               return(socket_type);
+                               return(isbound);
                        }
                }
-
-               public static bool SupportsIPv4 {
+               
+               public LingerOption LingerState {
                        get {
-                               CheckProtocolSupport();
-                               return ipv4Supported == 1;
-                       }
-               }
+                               if (disposed && closed) {
+                                       throw new ObjectDisposedException (GetType ().ToString ());
+                               }
 
-               public static bool SupportsIPv6 {
-                       get {
-                               CheckProtocolSupport();
-                               return ipv6Supported == 1;
+                               return((LingerOption)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger));
+                       }
+                       set {
+                               if (disposed && closed) {
+                                       throw new ObjectDisposedException (GetType ().ToString ());
+                               }
+                               
+                               SetSocketOption (SocketOptionLevel.Socket,
+                                                SocketOptionName.Linger,
+                                                value);
                        }
                }
-
-#if NET_2_0
-               public int SendTimeout {
+               
+               public bool MulticastLoopback {
+                       get {
+                               if (disposed && closed) {
+                                       throw new ObjectDisposedException (GetType ().ToString ());
+                               }
+
+                               /* Even though this option can be set
+                                * for TCP sockets on Linux, throw
+                                * this exception anyway to be
+                                * compatible (the MSDN docs say
+                                * "Setting this property on a
+                                * Transmission Control Protocol (TCP)
+                                * socket will have no effect." but
+                                * the MS runtime throws the
+                                * exception...)
+                                */
+                               if (protocol_type == ProtocolType.Tcp) {
+                                       throw new SocketException ((int)SocketError.ProtocolOption);
+                               }
+                               
+                               bool multicastloopback;
+                               
+                               if (address_family == AddressFamily.InterNetwork) {
+                                       multicastloopback = (int)(GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
+                               } else if (address_family == AddressFamily.InterNetworkV6) {
+                                       multicastloopback = (int)(GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
+                               } else {
+                                       throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
+                               }
+                               
+                               return(multicastloopback);
+                       }
+                       set {
+                               if (disposed && closed) {
+                                       throw new ObjectDisposedException (GetType ().ToString ());
+                               }
+
+                               /* Even though this option can be set
+                                * for TCP sockets on Linux, throw
+                                * this exception anyway to be
+                                * compatible (the MSDN docs say
+                                * "Setting this property on a
+                                * Transmission Control Protocol (TCP)
+                                * socket will have no effect." but
+                                * the MS runtime throws the
+                                * exception...)
+                                */
+                               if (protocol_type == ProtocolType.Tcp) {
+                                       throw new SocketException ((int)SocketError.ProtocolOption);
+                               }
+                               
+                               if (address_family == AddressFamily.InterNetwork) {
+                                       SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value?1:0);
+                               } else if (address_family == AddressFamily.InterNetworkV6) {
+                                       SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value?1:0);
+                               } else {
+                                       throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
+                               }
+                       }
+               }
+               
+               
+               [MonoTODO ("This doesn't do anything on Mono yet")]
+               public bool UseOnlyOverlappedIO {
+                       get {
+                               return(useoverlappedIO);
+                       }
+                       set {
+                               useoverlappedIO = value;
+                       }
+               }
+#endif
+
+               public IntPtr Handle {
+                       get {
+                               return(socket);
+                       }
+               }
+
+#if !TARGET_JVM
+               // Returns the local endpoint details in addr and port
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               private extern static SocketAddress LocalEndPoint_internal(IntPtr socket, out int error);
+#endif
+
+               // Wish:  support non-IP endpoints.
+               public EndPoint LocalEndPoint {
+                       get {
+                               if (disposed && closed)
+                                       throw new ObjectDisposedException (GetType ().ToString ());
+                               
+                               /*
+                                * If the seed EndPoint is null, Connect, Bind,
+                                * etc has not yet been called. MS returns null
+                                * in this case.
+                                */
+                               if (seed_endpoint == null)
+                                       return null;
+                               
+                               SocketAddress sa;
+                               int error;
+                               
+                               sa=LocalEndPoint_internal(socket, out error);
+
+                               if (error != 0)
+                                       throw new SocketException (error);
+
+                               return seed_endpoint.Create (sa);
+                       }
+               }
+
+               public SocketType SocketType {
+                       get {
+                               return(socket_type);
+                       }
+               }
+
+#if NET_2_0
+               public int SendTimeout {
                        get {
+                               if (disposed && closed)
+                                       throw new ObjectDisposedException (GetType ().ToString ());
+
                                return (int)GetSocketOption(
                                        SocketOptionLevel.Socket,
                                        SocketOptionName.SendTimeout);
                        }
                        set {
+                               if (disposed && closed)
+                                       throw new ObjectDisposedException (GetType ().ToString ());
+
+                               if (value < -1)
+                                       throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
+
+                               /* According to the MSDN docs we
+                                * should adjust values between 1 and
+                                * 499 to 500, but the MS runtime
+                                * doesn't do this.
+                                */
+                               if (value == -1)
+                                       value = 0;
+
                                SetSocketOption(
                                        SocketOptionLevel.Socket,
                                        SocketOptionName.SendTimeout, value);
@@ -729,76 +1039,68 @@ namespace System.Net.Sockets
 
                public int ReceiveTimeout {
                        get {
+                               if (disposed && closed)
+                                       throw new ObjectDisposedException (GetType ().ToString ());
+
                                return (int)GetSocketOption(
                                        SocketOptionLevel.Socket,
                                        SocketOptionName.ReceiveTimeout);
                        }
                        set {
+                               if (disposed && closed)
+                                       throw new ObjectDisposedException (GetType ().ToString ());
+
+                               if (value < -1)
+                                       throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
+
+                               if (value == -1) {
+                                       value = 0;
+                               }
+                               
                                SetSocketOption(
                                        SocketOptionLevel.Socket,
                                        SocketOptionName.ReceiveTimeout, value);
                        }
                }
 
-               public bool NoDelay {
-                       get {
-                               return (int)(GetSocketOption (
-                                       SocketOptionLevel.Tcp,
-                                       SocketOptionName.NoDelay)) != 0;
-                       }
-
-                       set {
-                               SetSocketOption (
-                                       SocketOptionLevel.Tcp,
-                                       SocketOptionName.NoDelay, value ? 1 : 0);
-                       }
-               }
-#endif
-
-               internal static void CheckProtocolSupport()
+               public bool AcceptAsync (SocketAsyncEventArgs e)
                {
-                       if(ipv4Supported == -1) {
-                               try  {
-                                       Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
-                                       tmp.Close();
+                       // 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 (!IsBound)
+                               throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
+                       if (!islistening)
+                               throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
+                       if (e.BufferList != null)
+                               throw new ArgumentException ("Multiple buffers cannot be used with this method.");
+                       if (e.Count < 0)
+                               throw new ArgumentOutOfRangeException ("e.Count");
+                       
+                       Socket acceptSocket = e.AcceptSocket;
+                       if (acceptSocket != null) {
+                               if (acceptSocket.IsBound || acceptSocket.Connected)
+                                       throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
+                       } else
+                               e.AcceptSocket = new Socket (AddressFamily, SocketType, ProtocolType);
 
-                                       ipv4Supported = 1;
-                               }
-                               catch {
-                                       ipv4Supported = 0;
-                               }
+                       try {
+                               e.DoOperation (SocketAsyncOperation.Accept, this);
+                       } catch {
+                               ((IDisposable)e).Dispose ();
+                               throw;
                        }
 
-                       if(ipv6Supported == -1) {
-#if NET_2_0 && CONFIGURATION_DEP
-                               SettingsSection config;
-                               config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
-                               if (config != null)
-                                       ipv6Supported = config.Ipv6.Enabled ? -1 : 0;
-#else
-                               NetConfig config = (NetConfig)System.Configuration.ConfigurationSettings.GetConfig("system.net/settings");
-
-                               if(config != null)
-                                       ipv6Supported = config.ipv6Enabled?-1:0;
-#endif
-                               if(ipv6Supported != 0) {
-                                       try {
-                                               Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
-                                               tmp.Close();
-
-                                               ipv6Supported = 1;
-                                       }
-                                       catch { }
-                               }
-                       }
+                       // We always return true for now
+                       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);
+               private extern static IntPtr Accept_internal(IntPtr sock, out int error, bool blocking);
 
-               Thread blocking_thread;
                public Socket Accept() {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
@@ -807,34 +1109,79 @@ namespace System.Net.Sockets
                        IntPtr sock = (IntPtr) (-1);
                        blocking_thread = Thread.CurrentThread;
                        try {
-                               sock = Accept_internal(socket, out error);
+                               sock = Accept_internal(socket, out error, blocking);
                        } catch (ThreadAbortException) {
                                if (disposed) {
+#if !NET_2_1
                                        Thread.ResetAbort ();
+#endif
                                        error = (int) SocketError.Interrupted;
                                }
                        } finally {
                                blocking_thread = null;
                        }
 
-                       if (error != 0) {
+                       if (error != 0)
                                throw new SocketException (error);
-                       }
                        
-                       Socket accepted = new Socket(this.AddressFamily,
-                                                    this.SocketType,
-                                                    this.ProtocolType, sock);
+                       Socket accepted = new Socket(this.AddressFamily, this.SocketType,
+                               this.ProtocolType, sock);
 
+                       accepted.seed_endpoint = this.seed_endpoint;
                        accepted.Blocking = this.Blocking;
                        return(accepted);
                }
 
-               public IAsyncResult BeginAccept(AsyncCallback callback,
-                                               object state) {
+               internal void Accept (Socket acceptSocket)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+                       
+                       int error = 0;
+                       IntPtr sock = (IntPtr)(-1);
+                       blocking_thread = Thread.CurrentThread;
+                       
+                       try {
+                               sock = Accept_internal (socket, out error, blocking);
+                       } catch (ThreadAbortException) {
+                               if (disposed) {
+#if !NET_2_1
+                                       Thread.ResetAbort ();
+#endif
+                                       error = (int)SocketError.Interrupted;
+                               }
+                       } finally {
+                               blocking_thread = null;
+                       }
+                       
+                       if (error != 0)
+                               throw new SocketException (error);
+                       
+                       acceptSocket.address_family = this.AddressFamily;
+                       acceptSocket.socket_type = this.SocketType;
+                       acceptSocket.protocol_type = this.ProtocolType;
+                       acceptSocket.socket = sock;
+                       acceptSocket.connected = true;
+                       acceptSocket.seed_endpoint = this.seed_endpoint;
+                       acceptSocket.Blocking = this.Blocking;
+
+                       /* FIXME: figure out what if anything else
+                        * needs to be reset
+                        */
+               }
 
+               public IAsyncResult BeginAccept(AsyncCallback callback,
+                                               object state)
+               {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
+#if NET_2_0
+                       /* FIXME: check the 1.1 docs for this too */
+                       if (!isbound || !islistening)
+                               throw new InvalidOperationException ();
+#endif
+
                        SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Accept);
                        Worker worker = new Worker (req);
                        SocketAsyncCall sac = new SocketAsyncCall (worker.Accept);
@@ -842,6 +1189,72 @@ namespace System.Net.Sockets
                        return(req);
                }
 
+#if NET_2_0
+               public IAsyncResult BeginAccept (int receiveSize,
+                                                AsyncCallback callback,
+                                                object state)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (receiveSize < 0)
+                               throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
+
+                       SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive);
+                       Worker worker = new Worker (req);
+                       SocketAsyncCall sac = new SocketAsyncCall (worker.AcceptReceive);
+                       
+                       req.Buffer = new byte[receiveSize];
+                       req.Offset = 0;
+                       req.Size = receiveSize;
+                       req.SockFlags = SocketFlags.None;
+
+                       sac.BeginInvoke (null, req);
+                       return(req);
+               }
+
+               public IAsyncResult BeginAccept (Socket acceptSocket,
+                                                int receiveSize,
+                                                AsyncCallback callback,
+                                                object state)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (receiveSize < 0)
+                               throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
+
+                       if (acceptSocket != null) {
+                               if (acceptSocket.disposed && acceptSocket.closed)
+                                       throw new ObjectDisposedException (acceptSocket.GetType ().ToString ());
+
+                               if (acceptSocket.IsBound)
+                                       throw new InvalidOperationException ();
+
+                               /* For some reason the MS runtime
+                                * barfs if the new socket is not TCP,
+                                * even though it's just about to blow
+                                * away all those parameters
+                                */
+                               if (acceptSocket.ProtocolType != ProtocolType.Tcp)
+                                       throw new SocketException ((int)SocketError.InvalidArgument);
+                       }
+                       
+                       SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive);
+                       Worker worker = new Worker (req);
+                       SocketAsyncCall sac = new SocketAsyncCall (worker.AcceptReceive);
+                       
+                       req.Buffer = new byte[receiveSize];
+                       req.Offset = 0;
+                       req.Size = receiveSize;
+                       req.SockFlags = SocketFlags.None;
+                       req.AcceptSocket = acceptSocket;
+
+                       sac.BeginInvoke (null, req);
+                       return(req);
+               }
+#endif
+
                public IAsyncResult BeginConnect(EndPoint end_point,
                                                 AsyncCallback callback,
                                                 object state) {
@@ -890,6 +1303,96 @@ namespace System.Net.Sockets
                        return(req);
                }
 
+#if NET_2_0
+               public IAsyncResult BeginConnect (IPAddress address, int port,
+                                                 AsyncCallback callback,
+                                                 object state)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (address == null)
+                               throw new ArgumentNullException ("address");
+
+                       if (address.ToString ().Length == 0)
+                               throw new ArgumentException ("The length of the IP address is zero");
+
+                       if (islistening)
+                               throw new InvalidOperationException ();
+
+                       IPEndPoint iep = new IPEndPoint (address, port);
+                       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);
+                       SocketAsyncCall sac = new SocketAsyncCall (worker.Connect);
+                       sac.BeginInvoke (null, req);
+                       
+                       return(req);
+               }
+
+               public IAsyncResult BeginConnect (string host, int port,
+                                                 AsyncCallback callback,
+                                                 object state)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (host == null)
+                               throw new ArgumentNullException ("host");
+
+                       if (address_family != AddressFamily.InterNetwork &&
+                               address_family != AddressFamily.InterNetworkV6)
+                               throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
+
+                       if (islistening)
+                               throw new InvalidOperationException ();
+
+                       IPAddress [] addresses = Dns.GetHostAddresses (host);
+                       return (BeginConnect (addresses, port, callback, state));
+               }
+
+               public IAsyncResult BeginDisconnect (bool reuseSocket,
+                                                    AsyncCallback callback,
+                                                    object state)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Disconnect);
+                       req.ReuseSocket = reuseSocket;
+                       
+                       Worker worker = new Worker (req);
+                       SocketAsyncCall sac = new SocketAsyncCall (worker.Disconnect);
+                       sac.BeginInvoke (null, req);
+                       
+                       return(req);
+               }
+#endif
+               
                public IAsyncResult BeginReceive(byte[] buffer, int offset,
                                                 int size,
                                                 SocketFlags socket_flags,
@@ -925,6 +1428,66 @@ namespace System.Net.Sockets
 
                        return req;
                }
+#if NET_2_0
+               public IAsyncResult BeginReceive (byte[] buffer, int offset,
+                                                 int size, SocketFlags flags,
+                                                 out SocketError error,
+                                                 AsyncCallback callback,
+                                                 object state)
+               {
+                       /* As far as I can tell from the docs and from
+                        * experimentation, a pointer to the
+                        * SocketError parameter is not supposed to be
+                        * saved for the async parts.  And as we don't
+                        * set any socket errors in the setup code, we
+                        * just have to set it to Success.
+                        */
+                       error = SocketError.Success;
+                       return (BeginReceive (buffer, offset, size, flags, callback, state));
+               }
+
+               [CLSCompliant (false)]
+               public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers,
+                                                 SocketFlags socketFlags,
+                                                 AsyncCallback callback,
+                                                 object state)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (buffers == null)
+                               throw new ArgumentNullException ("buffers");
+
+                       SocketAsyncResult req;
+                       lock(readQ) {
+                               req = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveGeneric);
+                               req.Buffers = buffers;
+                               req.SockFlags = socketFlags;
+                               readQ.Enqueue (req);
+                               if (readQ.Count == 1) {
+                                       Worker worker = new Worker (req);
+                                       SocketAsyncCall sac = new SocketAsyncCall (worker.ReceiveGeneric);
+                                       sac.BeginInvoke (null, req);
+                               }
+                       }
+                       
+                       return(req);
+               }
+               
+               [CLSCompliant (false)]
+               public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers,
+                                                 SocketFlags socketFlags,
+                                                 out SocketError errorCode,
+                                                 AsyncCallback callback,
+                                                 object state)
+               {
+                       /* I assume the same SocketError semantics as
+                        * above
+                        */
+                       errorCode = SocketError.Success;
+                       return (BeginReceive (buffers, socketFlags, callback, state));
+               }
+#endif
 
                public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
                                                     int size,
@@ -939,13 +1502,13 @@ namespace System.Net.Sockets
                                throw new ArgumentNullException ("buffer");
 
                        if (offset < 0)
-                               throw new ArgumentOutOfRangeException ("offset must be >= 0");
+                               throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
 
                        if (size < 0)
-                               throw new ArgumentOutOfRangeException ("size must be >= 0");
+                               throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
 
                        if (offset + size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length");
+                               throw new ArgumentOutOfRangeException ("offset, size", "offset + size exceeds the buffer length");
 
                        SocketAsyncResult req;
                        lock (readQ) {
@@ -965,6 +1528,32 @@ namespace System.Net.Sockets
                        return req;
                }
 
+#if NET_2_0
+               [MonoTODO]
+               public IAsyncResult BeginReceiveMessageFrom (
+                       byte[] buffer, int offset, int size,
+                       SocketFlags socketFlags, ref EndPoint remoteEP,
+                       AsyncCallback callback, object state)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
+
+                       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");
+
+                       throw new NotImplementedException ();
+               }
+#endif
+
                public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags,
                                               AsyncCallback callback, object state)
                {
@@ -975,13 +1564,19 @@ namespace System.Net.Sockets
                                throw new ArgumentNullException ("buffer");
 
                        if (offset < 0)
-                               throw new ArgumentOutOfRangeException ("offset must be >= 0");
+                               throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
 
                        if (size < 0)
-                               throw new ArgumentOutOfRangeException ("size must be >= 0");
+                               throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
 
                        if (offset + size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length");
+                               throw new ArgumentOutOfRangeException ("offset, size", "offset + size exceeds the buffer length");
+
+#if NET_2_0
+                       /* TODO: Check this exception in the 1.1 profile */
+                       if (!connected)
+                               throw new SocketException ((int)SocketError.NotConnected);
+#endif
 
                        SocketAsyncResult req;
                        lock (writeQ) {
@@ -1000,6 +1595,109 @@ namespace System.Net.Sockets
                        return req;
                }
 
+#if NET_2_0
+               public IAsyncResult BeginSend (byte[] buffer, int offset,
+                                              int size,
+                                              SocketFlags socketFlags,
+                                              out SocketError errorCode,
+                                              AsyncCallback callback,
+                                              object state)
+               {
+                       if (!connected) {
+                               errorCode = SocketError.NotConnected;
+                               throw new SocketException ((int)errorCode);
+                       }
+                       
+                       errorCode = SocketError.Success;
+                       
+                       return (BeginSend (buffer, offset, size, socketFlags, callback,
+                               state));
+               }
+
+               public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers,
+                                              SocketFlags socketFlags,
+                                              AsyncCallback callback,
+                                              object state)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (buffers == null)
+                               throw new ArgumentNullException ("buffers");
+
+                       if (!connected)
+                               throw new SocketException ((int)SocketError.NotConnected);
+
+                       SocketAsyncResult req;
+                       lock (writeQ) {
+                               req = new SocketAsyncResult (this, state, callback, SocketOperation.SendGeneric);
+                               req.Buffers = buffers;
+                               req.SockFlags = socketFlags;
+                               writeQ.Enqueue (req);
+                               if (writeQ.Count == 1) {
+                                       Worker worker = new Worker (req);
+                                       SocketAsyncCall sac = new SocketAsyncCall (worker.SendGeneric);
+                                       sac.BeginInvoke (null, req);
+                               }
+                       }
+                       
+                       return(req);
+               }
+
+               [CLSCompliant (false)]
+               public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers,
+                                              SocketFlags socketFlags,
+                                              out SocketError errorCode,
+                                              AsyncCallback callback,
+                                              object state)
+               {
+                       if (!connected) {
+                               errorCode = SocketError.NotConnected;
+                               throw new SocketException ((int)errorCode);
+                       }
+                       
+                       errorCode = SocketError.Success;
+                       return (BeginSend (buffers, socketFlags, callback, state));
+               }
+
+               [MonoTODO ("Not implemented")]
+               public IAsyncResult BeginSendFile (string fileName,
+                                                  AsyncCallback callback,
+                                                  object state)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (!connected)
+                               throw new NotSupportedException ();
+
+                       if (!File.Exists (fileName))
+                               throw new FileNotFoundException ();
+
+                       throw new NotImplementedException ();
+               }
+
+               [MonoTODO ("Not implemented")]
+               public IAsyncResult BeginSendFile (string fileName,
+                                                  byte[] preBuffer,
+                                                  byte[] postBuffer,
+                                                  TransmitFileOptions flags,
+                                                  AsyncCallback callback,
+                                                  object state)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (!connected)
+                               throw new NotSupportedException ();
+
+                       if (!File.Exists (fileName))
+                               throw new FileNotFoundException ();
+
+                       throw new NotImplementedException ();
+               }
+#endif
+
                public IAsyncResult BeginSendTo(byte[] buffer, int offset,
                                                int size,
                                                SocketFlags socket_flags,
@@ -1013,13 +1711,13 @@ namespace System.Net.Sockets
                                throw new ArgumentNullException ("buffer");
 
                        if (offset < 0)
-                               throw new ArgumentOutOfRangeException ("offset must be >= 0");
+                               throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
 
                        if (size < 0)
-                               throw new ArgumentOutOfRangeException ("size must be >= 0");
+                               throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
 
                        if (offset + size > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length");
+                               throw new ArgumentOutOfRangeException ("offset, size", "offset + size exceeds the buffer length");
 
                        SocketAsyncResult req;
                        lock (writeQ) {
@@ -1049,72 +1747,222 @@ namespace System.Net.Sockets
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if(local_end==null) {
+                       if (local_end == null)
                                throw new ArgumentNullException("local_end");
-                       }
                        
                        int error;
                        
-                       Bind_internal(socket, local_end.Serialize(),
-                                     out error);
+                       Bind_internal(socket, local_end.Serialize(), out error);
+                       if (error != 0)
+                               throw new SocketException (error);
+#if NET_2_0
+                       if (error == 0)
+                               isbound = true;
+#endif
+                       
+                       seed_endpoint = local_end;
+               }
+
+#if NET_2_0 && !NET_2_1
+               public void Close (int timeout) 
+               {
+                       System.Timers.Timer close_timer = new System.Timers.Timer ();
+                       close_timer.Elapsed += new ElapsedEventHandler (OnTimeoutClose);
+                       close_timer.Interval = timeout * 1000;
+                       close_timer.AutoReset = false;
+                       close_timer.Enabled = true;
+               }
+
+               private void OnTimeoutClose (object source, ElapsedEventArgs e)
+               {
+                       this.Close ();
+               }
+
+               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
+               
+#if NET_2_0
+               public void Connect (IPAddress address, int port)
+               {
+                       Connect (new IPEndPoint (address, port));
+               }
+               
+               public void Connect (IPAddress[] addresses, int port)
+               {
+                       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 ();
+
+                       /* FIXME: do non-blocking sockets Poll here? */
+                       foreach (IPAddress address in addresses) {
+                               IPEndPoint iep = new IPEndPoint (address,
+                                                                port);
+                               SocketAddress serial = iep.Serialize ();
+                               int error = 0;
+                               
+                               Connect_internal (socket, serial, out error);
+                               if (error == 0) {
+                                       connected = true;
+                                       seed_endpoint = iep;
+                                       return;
+                               } else if (error != (int)SocketError.InProgress &&
+                                          error != (int)SocketError.WouldBlock) {
+                                       continue;
+                               }
+                               
+                               if (!blocking) {
+                                       Poll (-1, SelectMode.SelectWrite);
+                                       int success = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
+                                       if (success == 0) {
+                                               connected = true;
+                                               seed_endpoint = iep;
+                                               return;
+                                       }
+                               }
+                       }
+               }
+
+               public void Connect (string host, int port)
+               {
+                       IPAddress [] addresses = Dns.GetHostAddresses (host);
+                       Connect (addresses, port);
+               }
+
+#if NET_2_0
+               public bool DisconnectAsync (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 ());
+
+                       e.DoOperation (SocketAsyncOperation.Disconnect, this);
+
+                       return true;
+               }
+#endif
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               private extern static void Disconnect_internal(IntPtr sock,
+                                                              bool reuse,
+                                                              out int error);
+
+               /* According to the docs, the MS runtime will throw
+                * PlatformNotSupportedException if the platform is
+                * newer than w2k.  We should be able to cope...
+                */
+               public void Disconnect (bool reuseSocket)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       int error = 0;
+                       
+                       Disconnect_internal (socket, reuseSocket, out error);
+
+                       if (error != 0) {
+                               if (error == 50) {
+                                       /* ERROR_NOT_SUPPORTED */
+                                       throw new PlatformNotSupportedException ();
+                               } else {
+                                       throw new SocketException (error);
+                               }
+                       }
 
-                       if (error != 0) {
-                               throw new SocketException (error);
+                       connected = false;
+                       
+                       if (reuseSocket) {
+                               /* Do managed housekeeping here... */
                        }
                }
 
-               // Closes the socket
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static void Close_internal(IntPtr socket,
-                                                         out int error);
+               [MonoTODO ("Not implemented")]
+               public SocketInformation DuplicateAndClose (int targetProcessId)
+               {
+                       /* Need to serialize this socket into a
+                        * SocketInformation struct, but must study
+                        * the MS implementation harder to figure out
+                        * behaviour as documentation is lacking
+                        */
+                       throw new NotImplementedException ();
+               }
+#endif
                
-               public void Close() {
-                       ((IDisposable) this).Dispose ();
+               public Socket EndAccept (IAsyncResult result)
+               {
+                       int bytes;
+                       byte[] buffer;
+                       
+                       return(EndAccept (out buffer, out bytes, result));
                }
 
-               // Connects to the remote address
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static void Connect_internal(IntPtr sock,
-                                                           SocketAddress sa,
-                                                           out int error);
+#if NET_2_0
+               public Socket EndAccept (out byte[] buffer,
+                                        IAsyncResult asyncResult)
+               {
+                       int bytes;
+                       
+                       return(EndAccept (out buffer, out bytes, asyncResult));
+               }
+#endif
 
-               public void Connect(EndPoint remote_end) {
+#if NET_2_0
+               public
+#else
+               private
+#endif
+               Socket EndAccept (out byte[] buffer, out int bytesTransferred,
+                                 IAsyncResult asyncResult)
+               {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if(remote_end==null) {
-                               throw new ArgumentNullException("remote_end");
-                       }
-
-                       if (remote_end is IPEndPoint) {
-                               IPEndPoint ep = (IPEndPoint) remote_end;
-                               if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
-                                       throw new SocketException ((int) SocketError.AddressNotAvailable);
-                       }
-
-                       SocketAddress serial = remote_end.Serialize ();
-                       int error = 0;
+                       if (asyncResult == null)
+                               throw new ArgumentNullException ("asyncResult");
+                       
+                       SocketAsyncResult req = asyncResult as SocketAsyncResult;
+                       if (req == null)
+                               throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
 
-                       blocking_thread = Thread.CurrentThread;
-                       try {
-                               Connect_internal (socket, serial, out error);
-                       } catch (ThreadAbortException) {
-                               if (disposed) {
-                                       Thread.ResetAbort ();
-                                       error = (int) SocketError.Interrupted;
-                               }
-                       } finally {
-                               blocking_thread = null;
-                       }
+                       if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+                               throw InvalidAsyncOp ("EndAccept");
+                       if (!asyncResult.IsCompleted)
+                               asyncResult.AsyncWaitHandle.WaitOne ();
 
-                       if (error != 0) {
-                               throw new SocketException (error);
-                       }
+                       req.CheckIfThrowDelayedException ();
                        
-                       connected=true;
+                       buffer = req.Buffer;
+                       bytesTransferred = req.Total;
+                       
+                       return(req.Socket);
                }
-               
-               public Socket EndAccept(IAsyncResult result) {
+
+               public void EndConnect (IAsyncResult result)
+               {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
@@ -1125,50 +1973,73 @@ namespace System.Net.Sockets
                        if (req == null)
                                throw new ArgumentException ("Invalid IAsyncResult", "result");
 
+                       if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+                               throw InvalidAsyncOp ("EndConnect");
                        if (!result.IsCompleted)
                                result.AsyncWaitHandle.WaitOne();
 
                        req.CheckIfThrowDelayedException();
-                       return req.Socket;
                }
 
-               public void EndConnect(IAsyncResult result) {
+#if NET_2_0
+               public void EndDisconnect (IAsyncResult asyncResult)
+               {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if (result == null)
-                               throw new ArgumentNullException ("result");
+                       if (asyncResult == null)
+                               throw new ArgumentNullException ("asyncResult");
 
-                       SocketAsyncResult req = result as SocketAsyncResult;
+                       SocketAsyncResult req = asyncResult as SocketAsyncResult;
                        if (req == null)
-                               throw new ArgumentException ("Invalid IAsyncResult", "result");
+                               throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
 
-                       if (!result.IsCompleted)
-                               result.AsyncWaitHandle.WaitOne();
+                       if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+                               throw InvalidAsyncOp ("EndDisconnect");
+                       if (!asyncResult.IsCompleted)
+                               asyncResult.AsyncWaitHandle.WaitOne ();
 
-                       req.CheckIfThrowDelayedException();
+                       req.CheckIfThrowDelayedException ();
+               }
+#endif
+
+               public int EndReceive (IAsyncResult result)
+               {
+                       SocketError error;
+                       
+                       return (EndReceive (result, out error));
                }
 
-               public int EndReceive(IAsyncResult result) {
+#if NET_2_0
+               public
+#else
+               private
+#endif
+               int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
+               {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if (result == null)
-                               throw new ArgumentNullException ("result");
+                       if (asyncResult == null)
+                               throw new ArgumentNullException ("asyncResult");
 
-                       SocketAsyncResult req = result as SocketAsyncResult;
+                       SocketAsyncResult req = asyncResult as SocketAsyncResult;
                        if (req == null)
-                               throw new ArgumentException ("Invalid IAsyncResult", "result");
+                               throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
 
-                       if (!result.IsCompleted)
-                               result.AsyncWaitHandle.WaitOne();
+                       if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+                               throw InvalidAsyncOp ("EndReceive");
+                       if (!asyncResult.IsCompleted)
+                               asyncResult.AsyncWaitHandle.WaitOne ();
 
-                       req.CheckIfThrowDelayedException();
-                       return req.Total;
+                       errorCode = req.ErrorCode;
+                       req.CheckIfThrowDelayedException ();
+                       
+                       return(req.Total);
                }
 
-               public int EndReceiveFrom(IAsyncResult result,
-                                         ref EndPoint end_point) {
+               public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
+               {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
@@ -1179,6 +2050,8 @@ namespace System.Net.Sockets
                        if (req == null)
                                throw new ArgumentException ("Invalid IAsyncResult", "result");
 
+                       if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+                               throw InvalidAsyncOp ("EndReceiveFrom");
                        if (!result.IsCompleted)
                                result.AsyncWaitHandle.WaitOne();
 
@@ -1187,25 +2060,94 @@ namespace System.Net.Sockets
                        return req.Total;
                }
 
-               public int EndSend(IAsyncResult result) {
+#if NET_2_0
+               [MonoTODO]
+               public int EndReceiveMessageFrom (IAsyncResult asyncResult,
+                                                 ref SocketFlags socketFlags,
+                                                 ref EndPoint endPoint,
+                                                 out IPPacketInformation ipPacketInformation)
+               {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if (result == null)
-                               throw new ArgumentNullException ("result");
+                       if (asyncResult == null)
+                               throw new ArgumentNullException ("asyncResult");
 
-                       SocketAsyncResult req = result as SocketAsyncResult;
+                       if (endPoint == null)
+                               throw new ArgumentNullException ("endPoint");
+
+                       SocketAsyncResult req = asyncResult as SocketAsyncResult;
+                       if (req == null)
+                               throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
+
+                       if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+                               throw InvalidAsyncOp ("EndReceiveMessageFrom");
+                       throw new NotImplementedException ();
+               }
+#endif
+
+               public int EndSend (IAsyncResult result)
+               {
+                       SocketError error;
+                       
+                       return(EndSend (result, out error));
+               }
+
+#if NET_2_0
+               public
+#else
+               private
+#endif
+               int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (asyncResult == null)
+                               throw new ArgumentNullException ("asyncResult");
+                       
+                       SocketAsyncResult req = asyncResult as SocketAsyncResult;
                        if (req == null)
                                throw new ArgumentException ("Invalid IAsyncResult", "result");
 
-                       if (!result.IsCompleted)
-                               result.AsyncWaitHandle.WaitOne();
+                       if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+                               throw InvalidAsyncOp ("EndSend");
+                       if (!asyncResult.IsCompleted)
+                               asyncResult.AsyncWaitHandle.WaitOne ();
 
-                       req.CheckIfThrowDelayedException();
-                       return req.Total;
+                       errorCode = req.ErrorCode;
+                       req.CheckIfThrowDelayedException ();
+                       
+                       return(req.Total);
+               }
+
+#if NET_2_0
+               [MonoTODO]
+               public void EndSendFile (IAsyncResult asyncResult)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (asyncResult == null)
+                               throw new ArgumentNullException ("asyncResult");
+
+                       SocketAsyncResult req = asyncResult as SocketAsyncResult;
+                       if (req == null)
+                               throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
+
+                       if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+                               throw InvalidAsyncOp ("EndSendFile");
+                       throw new NotImplementedException ();
+               }
+#endif
+
+               Exception InvalidAsyncOp (string method)
+               {
+                       return new InvalidOperationException (method + " can only be called once per asynchronous operation");
                }
 
-               public int EndSendTo(IAsyncResult result) {
+               public int EndSendTo (IAsyncResult result)
+               {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
@@ -1216,6 +2158,8 @@ namespace System.Net.Sockets
                        if (req == null)
                                throw new ArgumentException ("Invalid IAsyncResult", "result");
 
+                       if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
+                               throw InvalidAsyncOp ("EndSendTo");
                        if (!result.IsCompleted)
                                result.AsyncWaitHandle.WaitOne();
 
@@ -1224,66 +2168,39 @@ namespace System.Net.Sockets
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
+               private extern static void GetSocketOption_arr_internal(IntPtr socket,
+                       SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val,
+                       out int error);
 
-               public object GetSocketOption (SocketOptionLevel level, SocketOptionName name)
+               public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       object obj_val;
-                       int error;
-                       
-                       GetSocketOption_obj_internal(socket, level, name,
-                                                    out obj_val, out error);
-
-                       if (error != 0) {
-                               throw new SocketException (error);
-                       }
-                       
-                       if(name==SocketOptionName.Linger) {
-                               return((LingerOption)obj_val);
-                       } else if (name==SocketOptionName.AddMembership ||
-                                  name==SocketOptionName.DropMembership) {
-                               return((MulticastOption)obj_val);
-                       } else if (obj_val is int) {
-                               return((int)obj_val);
-                       } else {
-                               return(obj_val);
-                       }
-               }
-
-               public void GetSocketOption (SocketOptionLevel level, SocketOptionName name, byte [] opt_value)
-               {
-                       if (disposed && closed)
-                               throw new ObjectDisposedException (GetType ().ToString ());
+                       if (optionValue == null)
+                               throw new SocketException ((int) SocketError.Fault,
+                                       "Error trying to dereference an invalid pointer");
 
                        int error;
-                       
-                       GetSocketOption_arr_internal(socket, level, name,
-                                                    ref opt_value, out error);
 
-                       if (error != 0) {
+                       GetSocketOption_arr_internal (socket, optionLevel, optionName, ref optionValue,
+                               out error);
+                       if (error != 0)
                                throw new SocketException (error);
-                       }
                }
 
-               public byte [] GetSocketOption (SocketOptionLevel level, SocketOptionName name, int length)
+               public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int length)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
                        byte[] byte_val=new byte[length];
                        int error;
-                       
-                       GetSocketOption_arr_internal(socket, level, name,
-                                                    ref byte_val, out error);
 
-                       if (error != 0) {
+                       GetSocketOption_arr_internal (socket, optionLevel, optionName, ref byte_val,
+                               out error);
+                       if (error != 0)
                                throw new SocketException (error);
-                       }
 
                        return(byte_val);
                }
@@ -1293,9 +2210,8 @@ namespace System.Net.Sockets
                // FIONBIO and SIOCATMARK. Anything else will depend on the
                // system.
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               extern static int WSAIoctl (IntPtr sock, int ioctl_code,
-                                           byte [] input, byte [] output,
-                                           out int error);
+               extern static int WSAIoctl (IntPtr sock, int ioctl_code, byte [] input,
+                       byte [] output, out int error);
 
                public int IOControl (int ioctl_code, byte [] in_value, byte [] out_value)
                {
@@ -1303,12 +2219,11 @@ namespace System.Net.Sockets
                                throw new ObjectDisposedException (GetType ().ToString ());
 
                        int error;
-                       int result = WSAIoctl (socket, ioctl_code, in_value,
-                                              out_value, out error);
+                       int result = WSAIoctl (socket, ioctl_code, in_value, out_value,
+                               out error);
 
-                       if (error != 0) {
+                       if (error != 0)
                                throw new SocketException (error);
-                       }
                        
                        if (result == -1)
                                throw new InvalidOperationException ("Must use Blocking property instead.");
@@ -1316,27 +2231,47 @@ namespace System.Net.Sockets
                        return result;
                }
 
+#if NET_2_0
+               [MonoTODO]
+               public int IOControl (IOControlCode ioControlCode,
+                                     byte[] optionInValue,
+                                     byte[] optionOutValue)
+               {
+                       /* Probably just needs to mirror the int
+                        * overload, but more investigation needed.
+                        */
+                       throw new NotImplementedException ();
+               }
+#endif
+
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static void Listen_internal(IntPtr sock,
-                                                          int backlog,
-                                                          out int error);
+               private extern static void Listen_internal(IntPtr sock, int backlog,
+                       out int error);
 
                public void Listen (int backlog)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
+#if NET_2_0
+                       /* TODO: check if this should be thrown in the
+                        * 1.1 profile too
+                        */
+                       if (!isbound)
+                               throw new SocketException ((int)SocketError.InvalidArgument);
+#endif
+
                        int error;
                        
                        Listen_internal(socket, backlog, out error);
 
-                       if (error != 0) {
+                       if (error != 0)
                                throw new SocketException (error);
-                       }
-               }
 
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
+#if NET_2_0
+                       islistening = true;
+#endif
+               }
 
                public bool Poll (int time_us, SelectMode mode)
                {
@@ -1353,7 +2288,7 @@ namespace System.Net.Sockets
                        if (error != 0)
                                throw new SocketException (error);
 
-                       if (mode == SelectMode.SelectWrite && result == true) {
+                       if (mode == SelectMode.SelectWrite && result && !connected) {
                                /* Update the connected state; for
                                 * non-blocking Connect()s this is
                                 * when we can find out that the
@@ -1367,71 +2302,59 @@ namespace System.Net.Sockets
                        return result;
                }
 
-               /* This overload is needed as the async Connect method
-                * also needs to check the socket error status, but
-                * getsockopt(..., SO_ERROR) clears the error.
-                */
-               private bool Poll (int time_us, SelectMode mode,
-                                  out int socket_error)
+               public int Receive (byte [] buffer)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if (mode != SelectMode.SelectRead &&
-                           mode != SelectMode.SelectWrite &&
-                           mode != SelectMode.SelectError)
-                               throw new NotSupportedException ("'mode' parameter is not valid.");
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
 
-                       int error;
-                       bool result = Poll_internal (socket, mode, time_us, out error);
-                       if (error != 0)
-                               throw new SocketException (error);
+                       SocketError error;
 
-                       socket_error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
-                       
-                       if (mode == SelectMode.SelectWrite && result == true) {
-                               /* Update the connected state; for
-                                * non-blocking Connect()s this is
-                                * when we can find out that the
-                                * connect succeeded.
-                                */
-                               if (socket_error == 0) {
-                                       connected = true;
-                               }
-                       }
+                       int ret = Receive_nochecks (buffer, 0, buffer.Length, SocketFlags.None, out error);
                        
-                       return result;
+                       if (error != SocketError.Success)
+                               throw new SocketException ((int) error);
+
+                       return ret;
                }
-               
-               public int Receive (byte [] buf)
+
+               public int Receive (byte [] buffer, SocketFlags flags)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if (buf == null)
-                               throw new ArgumentNullException ("buf");
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
 
                        SocketError error;
 
-                       int ret = Receive_nochecks (buf, 0, buf.Length, SocketFlags.None, out error);
+                       int ret = Receive_nochecks (buffer, 0, buffer.Length, flags, out error);
                        
-                       if (error != SocketError.Success)
+                       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);
+                       }
 
                        return ret;
                }
 
-               public int Receive (byte [] buf, SocketFlags flags)
+               public int Receive (byte [] buffer, int size, SocketFlags flags)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if (buf == null)
-                               throw new ArgumentNullException ("buf");
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
+
+                       if (size < 0 || size > buffer.Length)
+                               throw new ArgumentOutOfRangeException ("size");
 
                        SocketError error;
 
-                       int ret = Receive_nochecks (buf, 0, buf.Length, flags, out error);
+                       int ret = Receive_nochecks (buffer, 0, size, flags, out error);
                        
                        if (error != SocketError.Success) {
                                if (error == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set
@@ -1442,145 +2365,200 @@ namespace System.Net.Sockets
                        return ret;
                }
 
-               public int Receive (byte [] buf, int size, SocketFlags flags)
+               public int Receive (byte [] buffer, int offset, int size, SocketFlags flags)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if (buf == null)
-                               throw new ArgumentNullException ("buf");
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
 
-                       if (size < 0 || size > buf.Length)
-                               throw new ArgumentOutOfRangeException ("size");
+                       if (offset < 0 || offset > buffer.Length)
+                               throw new ArgumentOutOfRangeException ("offset");
 
+                       if (size < 0 || offset + size > buffer.Length)
+                               throw new ArgumentOutOfRangeException ("size");
+                       
                        SocketError error;
 
-                       int ret = Receive_nochecks (buf, 0, size, flags, out error);
+                       int ret = Receive_nochecks (buffer, offset, size, flags, out error);
                        
                        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);
                        }
-
-                       return ret;
+
+                       return ret;
+               }
+
+#if NET_2_0
+               public int Receive (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       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");
+                       
+                       return Receive_nochecks (buffer, offset, size, flags, out error);
+               }
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static int Receive_internal (IntPtr sock,
+                                                           WSABUF[] bufarray,
+                                                           SocketFlags flags,
+                                                           out int error);
+               
+               public int Receive (IList<ArraySegment<byte>> buffers)
+               {
+                       int ret;
+                       SocketError error;
+                       
+                       ret = Receive (buffers, SocketFlags.None, out error);
+                       if (error != SocketError.Success) {
+                               throw new SocketException ((int)error);
+                       }
+                       
+                       return(ret);
+               }
+               
+               [CLSCompliant (false)]
+               public int Receive (IList<ArraySegment<byte>> buffers,
+                                   SocketFlags socketFlags)
+               {
+                       int ret;
+                       SocketError error;
+                       
+                       ret = Receive (buffers, socketFlags, out error);
+                       if (error != SocketError.Success) {
+                               throw new SocketException ((int)error);
+                       }
+                       
+                       return(ret);
                }
 
-               public int Receive (byte [] buf, int offset, int size, SocketFlags flags)
+               [CLSCompliant (false)]
+               public int Receive (IList<ArraySegment<byte>> buffers,
+                                   SocketFlags socketFlags,
+                                   out SocketError errorCode)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if (buf == null)
-                               throw new ArgumentNullException ("buf");
+                       if (buffers == null ||
+                           buffers.Count == 0) {
+                               throw new ArgumentNullException ("buffers");
+                       }
 
-                       if (offset < 0 || offset > buf.Length)
-                               throw new ArgumentOutOfRangeException ("offset");
+                       int numsegments = buffers.Count;
+                       int nativeError;
+                       int ret;
 
-                       if (size < 0 || offset + size > buf.Length)
-                               throw new ArgumentOutOfRangeException ("size");
-                       
-                       SocketError error;
+                       /* Only example I can find of sending a byte
+                        * array reference directly into an internal
+                        * call is in
+                        * System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
+                        * so taking a lead from that...
+                        */
+                       WSABUF[] bufarray = new WSABUF[numsegments];
+                       GCHandle[] gch = new GCHandle[numsegments];
 
-                       int ret = Receive_nochecks (buf, offset, size, flags, out error);
+                       for(int i = 0; i < numsegments; i++) {
+                               ArraySegment<byte> segment = buffers[i];
+                               gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
+                               bufarray[i].len = segment.Count;
+                               bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
+                       }
                        
-                       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);
+                       try {
+                               ret = Receive_internal (socket, bufarray,
+                                                       socketFlags,
+                                                       out nativeError);
+                       } finally {
+                               for(int i = 0; i < numsegments; i++) {
+                                       if (gch[i].IsAllocated) {
+                                               gch[i].Free ();
+                                       }
+                               }
                        }
 
-                       return ret;
+                       errorCode = (SocketError)nativeError;
+                       return(ret);
                }
+#endif
 
 #if NET_2_0
-               public int Receive (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
+               public bool ReceiveFromAsync (SocketAsyncEventArgs e)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if (buf == null)
-                               throw new ArgumentNullException ("buf");
+                       // We do not support recv into multiple buffers yet
+                       if (e.BufferList != null)
+                               throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
+                       if (e.RemoteEndPoint == null)
+                               throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
 
-                       if (offset < 0 || offset > buf.Length)
-                               throw new ArgumentOutOfRangeException ("offset");
+                       e.DoOperation (SocketAsyncOperation.ReceiveFrom, this);
 
-                       if (size < 0 || offset + size > buf.Length)
-                               throw new ArgumentOutOfRangeException ("size");
-                       
-                       return Receive_nochecks (buf, offset, size, flags, out error);
+                       // We always return true for now
+                       return true;
                }
 #endif
 
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static int Receive_internal(IntPtr sock,
-                                                          byte[] buffer,
-                                                          int offset,
-                                                          int count,
-                                                          SocketFlags flags,
-                                                          out int error);
-
-               int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
-               {
-                       int nativeError;
-                       int ret = Receive_internal (socket, buf, offset, size, flags, out nativeError);
-                       error = (SocketError) nativeError;
-                       if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
-                               connected = false;
-                       else
-                               connected = true;
-                       
-                       return ret;
-               }
-               
-               public int ReceiveFrom (byte [] buf, ref EndPoint remote_end)
+               public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if (buf == null)
-                               throw new ArgumentNullException ("buf");
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
 
-                       if (remote_end == null)
-                               throw new ArgumentNullException ("remote_end");
+                       if (remoteEP == null)
+                               throw new ArgumentNullException ("remoteEP");
 
-                       return ReceiveFrom_nochecks (buf, 0, buf.Length, SocketFlags.None, ref remote_end);
+                       return ReceiveFrom_nochecks (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
                }
 
-               public int ReceiveFrom (byte [] buf, SocketFlags flags, ref EndPoint remote_end)
+               public int ReceiveFrom (byte [] buffer, SocketFlags flags, ref EndPoint remoteEP)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if (buf == null)
-                               throw new ArgumentNullException ("buf");
-
-                       if (remote_end == null)
-                               throw new ArgumentNullException ("remote_end");
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
 
+                       if (remoteEP == null)
+                               throw new ArgumentNullException ("remoteEP");
 
-                       return ReceiveFrom_nochecks (buf, 0, buf.Length, flags, ref remote_end);
+                       return ReceiveFrom_nochecks (buffer, 0, buffer.Length, flags, ref remoteEP);
                }
 
-               public int ReceiveFrom (byte [] buf, int size, SocketFlags flags,
-                                       ref EndPoint remote_end)
+               public int ReceiveFrom (byte [] buffer, int size, SocketFlags flags,
+                                       ref EndPoint remoteEP)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if (buf == null)
-                               throw new ArgumentNullException ("buf");
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
 
-                       if (remote_end == null)
-                               throw new ArgumentNullException ("remote_end");
+                       if (remoteEP == null)
+                               throw new ArgumentNullException ("remoteEP");
 
-                       if (size < 0 || size > buf.Length)
+                       if (size < 0 || size > buffer.Length)
                                throw new ArgumentOutOfRangeException ("size");
 
-                       return ReceiveFrom_nochecks (buf, 0, size, flags, ref remote_end);
+                       return ReceiveFrom_nochecks (buffer, 0, size, flags, ref remoteEP);
                }
 
-
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern static int RecvFrom_internal(IntPtr sock,
                                                            byte[] buffer,
@@ -1590,47 +2568,61 @@ namespace System.Net.Sockets
                                                            ref SocketAddress sockaddr,
                                                            out int error);
 
-               public int ReceiveFrom (byte [] buf, int offset, int size, SocketFlags flags,
-                                       ref EndPoint remote_end)
+               public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags flags,
+                                       ref EndPoint remoteEP)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if (buf == null)
-                               throw new ArgumentNullException ("buf");
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
 
-                       if (remote_end == null)
-                               throw new ArgumentNullException ("remote_end");
+                       if (remoteEP == null)
+                               throw new ArgumentNullException ("remoteEP");
 
-                       if (offset < 0 || offset > buf.Length)
+                       if (offset < 0 || offset > buffer.Length)
                                throw new ArgumentOutOfRangeException ("offset");
 
-                       if (size < 0 || offset + size > buf.Length)
+                       if (size < 0 || offset + size > buffer.Length)
                                throw new ArgumentOutOfRangeException ("size");
 
-                       return ReceiveFrom_nochecks (buf, offset, size, flags, ref remote_end);
+                       return ReceiveFrom_nochecks (buffer, offset, size, flags, ref remoteEP);
                }
 
-               int ReceiveFrom_nochecks (byte [] buf, int offset, int size, SocketFlags flags,
-                                         ref EndPoint remote_end)
+               internal int ReceiveFrom_nochecks (byte [] buf, int offset, int size, SocketFlags flags,
+                                                  ref EndPoint remote_end)
                {
-                       SocketAddress sockaddr = remote_end.Serialize();
-                       int cnt, error;
-
-                       cnt = RecvFrom_internal (socket, buf, offset, size, flags, ref sockaddr, out error);
+                       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();
+                       int cnt = RecvFrom_internal (socket, buf, offset, size, flags, ref sockaddr, out error);
                        SocketError err = (SocketError) error;
                        if (err != 0) {
                                if (err != SocketError.WouldBlock && err != SocketError.InProgress)
                                        connected = false;
-                               else if (err == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set
-                                       throw new SocketException (error, "Operation timed out.");
+                               else if (err == SocketError.WouldBlock && blocking) { // This might happen when ReceiveTimeout is set
+                                       if (throwOnError)       
+                                               throw new SocketException ((int) SocketError.TimedOut, "Operation timed out");
+                                       error = (int) SocketError.TimedOut;
+                                       return 0;
+                               }
 
-                               throw new SocketException (error);
+                               if (throwOnError)
+                                       throw new SocketException (error);
+                               return 0;
                        }
 
                        connected = true;
 
+#if NET_2_0
+                       isbound = true;
+#endif
+
                        // If sockaddr is null then we're a connection
                        // oriented protocol and should ignore the
                        // remote_end parameter (see MSDN
@@ -1641,10 +2633,64 @@ namespace System.Net.Sockets
                                // instance method
                                remote_end = remote_end.Create (sockaddr);
                        }
-
+                       
+                       seed_endpoint = remote_end;
+                       
                        return cnt;
                }
 
+#if NET_2_0
+               [MonoTODO ("Not implemented")]
+               public bool ReceiveMessageFromAsync (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 ());
+                       
+                       throw new NotImplementedException ();
+               }
+               
+               [MonoTODO ("Not implemented")]
+               public int ReceiveMessageFrom (byte[] buffer, int offset,
+                                              int size,
+                                              ref SocketFlags socketFlags,
+                                              ref EndPoint remoteEP,
+                                              out IPPacketInformation ipPacketInformation)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
+
+                       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");
+
+                       /* FIXME: figure out how we get hold of the
+                        * IPPacketInformation
+                        */
+                       throw new NotImplementedException ();
+               }
+
+               [MonoTODO ("Not implemented")]
+               public bool SendPacketsAsync (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 ());
+                       
+                       throw new NotImplementedException ();
+               }
+
+#endif
+
                public int Send (byte [] buf)
                {
                        if (disposed && closed)
@@ -1743,36 +2789,141 @@ namespace System.Net.Sockets
 
                        return Send_nochecks (buf, offset, size, flags, out error);
                }
-#endif
 
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static int Send_internal(IntPtr sock,
-                                                       byte[] buf, int offset,
-                                                       int count,
-                                                       SocketFlags flags,
-                                                       out int error);
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static int Send_internal (IntPtr sock,
+                                                        WSABUF[] bufarray,
+                                                        SocketFlags flags,
+                                                        out int error);
 
-               int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
+               public int Send (IList<ArraySegment<byte>> buffers)
                {
-                       if (size == 0) {
-                               error = SocketError.Success;
-                               return 0;
+                       int ret;
+                       SocketError error;
+                       
+                       ret = Send (buffers, SocketFlags.None, out error);
+                       if (error != SocketError.Success) {
+                               throw new SocketException ((int)error);
+                       }
+                       
+                       return(ret);
+               }
+
+               public int Send (IList<ArraySegment<byte>> buffers,
+                                SocketFlags socketFlags)
+               {
+                       int ret;
+                       SocketError error;
+                       
+                       ret = Send (buffers, socketFlags, out error);
+                       if (error != SocketError.Success) {
+                               throw new SocketException ((int)error);
                        }
+                       
+                       return(ret);
+               }
 
+               [CLSCompliant (false)]
+               public int Send (IList<ArraySegment<byte>> buffers,
+                                SocketFlags socketFlags,
+                                out SocketError errorCode)
+               {
+                       if (disposed && closed) {
+                               throw new ObjectDisposedException (GetType ().ToString ());
+                       }
+                       
+                       if (buffers == null) {
+                               throw new ArgumentNullException ("buffers");
+                       }
+                       
+                       if (buffers.Count == 0) {
+                               throw new ArgumentException ("Buffer is empty", "buffers");
+                       }
+                       
+                       int numsegments = buffers.Count;
                        int nativeError;
+                       int ret;
+                       
+                       WSABUF[] bufarray = new WSABUF[numsegments];
+                       GCHandle[] gch = new GCHandle[numsegments];
+                       
+                       for(int i = 0; i < numsegments; i++) {
+                               ArraySegment<byte> segment = buffers[i];
+                               gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
+                               bufarray[i].len = segment.Count;
+                               bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
+                       }
+                       
+                       try {
+                               ret = Send_internal (socket, bufarray,
+                                                    socketFlags,
+                                                    out nativeError);
+                       } finally {
+                               for(int i = 0; i < numsegments; i++) {
+                                       if (gch[i].IsAllocated) {
+                                               gch[i].Free ();
+                                       }
+                               }
+                       }
+                       
+                       errorCode = (SocketError)nativeError;
+                       return(ret);
+               }
+
+               [MonoTODO ("Not implemented")]
+               public void SendFile (string fileName)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
 
-                       int ret = Send_internal (socket, buf, offset, size, flags, out nativeError);
+                       if (!connected)
+                               throw new NotSupportedException ();
 
-                       error = (SocketError)nativeError;
+                       if (!blocking)
+                               throw new InvalidOperationException ();
 
-                       if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
-                               connected = false;
-                       else
-                               connected = true;
+                       if (!File.Exists (fileName))
+                               throw new FileNotFoundException ();
 
-                       return ret;
+                       /* FIXME: Implement TransmitFile */
+                       throw new NotImplementedException ();
+               }
+
+               [MonoTODO ("Not implemented")]
+               public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
+               {
+                       if (disposed && closed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+
+                       if (!connected)
+                               throw new NotSupportedException ();
+
+                       if (!blocking)
+                               throw new InvalidOperationException ();
+
+                       if (!File.Exists (fileName))
+                               throw new FileNotFoundException ();
+
+                       /* FIXME: Implement TransmitFile */
+                       throw new NotImplementedException ();
                }
 
+               public bool SendToAsync (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 (e.RemoteEndPoint == null)
+                               throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
+                       
+                       e.DoOperation (SocketAsyncOperation.SendTo, this);
+
+                       // We always return true for now
+                       return true;
+               }
+#endif
+               
                public int SendTo (byte [] buffer, EndPoint remote_end)
                {
                        if (disposed && closed)
@@ -1848,8 +2999,8 @@ namespace System.Net.Sockets
                        return SendTo_nochecks (buffer, offset, size, flags, remote_end);
                }
 
-               int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags,
-                                  EndPoint remote_end)
+               internal int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags,
+                                             EndPoint remote_end)
                {
                        SocketAddress sockaddr = remote_end.Serialize ();
 
@@ -1867,147 +3018,116 @@ namespace System.Net.Sockets
 
                        connected = true;
 
+#if NET_2_0
+                       isbound = true;
+#endif
+                       
+                       seed_endpoint = remote_end;
+                       
                        return ret;
                }
 
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level,
-                                                                    SocketOptionName name, object obj_val,
-                                                                    byte [] byte_val, int int_val,
-                                                                    out int error);
-
-               public void SetSocketOption (SocketOptionLevel level, SocketOptionName name, byte[] opt_value)
+               public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       int error;
+                       // I'd throw an ArgumentNullException, but this is what MS does.
+                       if (optionValue == null)
+                               throw new SocketException ((int) SocketError.Fault,
+                                       "Error trying to dereference an invalid pointer");
                        
-                       SetSocketOption_internal(socket, level, name, null,
-                                                opt_value, 0, out error);
-
-                       if (error != 0) {
-                               throw new SocketException (error);
-                       }
-               }
-
-               public void SetSocketOption (SocketOptionLevel level, SocketOptionName name, int opt_value)
-               {
-                       if (disposed && closed)
-                               throw new ObjectDisposedException (GetType ().ToString ());
-
                        int error;
-                       
-                       SetSocketOption_internal(socket, level, name, null,
-                                                null, opt_value, out error);
+
+                       SetSocketOption_internal (socket, optionLevel, optionName, null,
+                                                optionValue, 0, out error);
 
                        if (error != 0) {
+                               if (error == (int) SocketError.InvalidArgument)
+                                       throw new ArgumentException ();
                                throw new SocketException (error);
                        }
                }
 
-               public void SetSocketOption (SocketOptionLevel level, SocketOptionName name, object opt_value)
+               public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
                {
-
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
-                       if(opt_value==null) {
-                               throw new ArgumentNullException();
-                       }
+                       // NOTE: if a null is passed, the byte[] overload is used instead...
+                       if (optionValue == null)
+                               throw new ArgumentNullException("optionValue");
                        
                        int error;
-                       /* From MS documentation on SetSocketOption: "For an
-                        * option with a Boolean data type, specify a nonzero
-                        * value to enable the option, and a zero value to
-                        * disable the option."
-                        * Booleans are only handled in 2.0
-                        */
 
-                       if (opt_value is System.Boolean) {
+                       if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
+                               LingerOption linger = optionValue as LingerOption;
+                               if (linger == null)
 #if NET_2_0
-                               bool bool_val = (bool) opt_value;
-                               int int_val = (bool_val) ? 1 : 0;
-
-                               SetSocketOption_internal (socket, level, name, null, null, int_val, out error);
+                                       throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
+#else
+                                       throw new ArgumentException ("optionValue");
+#endif
+                               SetSocketOption_internal (socket, optionLevel, optionName, linger, null, 0, out error);
+                       } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
+                               MulticastOption multicast = optionValue as MulticastOption;
+                               if (multicast == null)
+#if NET_2_0
+                                       throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
 #else
-                               throw new ArgumentException ("Use an integer 1 (true) or 0 (false) instead of a boolean.", "opt_value");
+                                       throw new ArgumentException ("optionValue");
 #endif
+                               SetSocketOption_internal (socket, optionLevel, optionName, multicast, null, 0, out error);
+                       } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
+                               IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
+                               if (multicast == null)
+#if NET_2_0
+                                       throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
+#else
+                                       throw new ArgumentException ("optionValue");
+#endif
+                               SetSocketOption_internal (socket, optionLevel, optionName, multicast, null, 0, out error);
                        } else {
-                               SetSocketOption_internal (socket, level, name, opt_value, null, 0, out error);
+#if NET_2_0
+                               throw new ArgumentException ("Invalid value specified.", "optionValue");
+#else
+                               throw new ArgumentException ("optionValue");
+#endif
                        }
 
-                       if (error != 0)
+                       if (error != 0) {
+                               if (error == (int) SocketError.InvalidArgument)
+                                       throw new ArgumentException ();
                                throw new SocketException (error);
+                       }
                }
 
 #if NET_2_0
-               public void SetSocketOption (SocketOptionLevel level, SocketOptionName name, bool optionValue)
+               public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
                {
                        if (disposed && closed)
                                throw new ObjectDisposedException (GetType ().ToString ());
 
                        int error;
                        int int_val = (optionValue) ? 1 : 0;
-                       SetSocketOption_internal (socket, level, name, null, null, int_val, out error);
-                       if (error != 0)
-                               throw new SocketException (error);
-               }
-#endif
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how, out int error);
-               
-               public void Shutdown (SocketShutdown how)
-               {
-                       if (disposed && closed)
-                               throw new ObjectDisposedException (GetType ().ToString ());
-
-                       int error;
-                       
-                       Shutdown_internal(socket, how, out error);
-
+                       SetSocketOption_internal (socket, optionLevel, optionName, null, null, int_val, out error);
                        if (error != 0) {
+                               if (error == (int) SocketError.InvalidArgument)
+                                       throw new ArgumentException ();
                                throw new SocketException (error);
                        }
                }
+#endif
 
+#if ONLY_1_1
                public override int GetHashCode ()
-               { 
-                       return (int) socket; 
-               }
-
-               protected virtual void Dispose (bool explicitDisposing)
-               {
-                       if (disposed)
-                               return;
-
-                       disposed = true;
-                       connected = false;
-                       if ((int) socket != -1) {
-                               int error;
-                               closed = true;
-                               IntPtr x = socket;
-                               socket = (IntPtr) (-1);
-                               Close_internal (x, out error);
-                               if (blocking_thread != null) {
-                                       blocking_thread.Abort ();
-                                       blocking_thread = null;
-                               }
-
-                               if (error != 0)
-                                       throw new SocketException (error);
-                       }
-               }
-
-               void IDisposable.Dispose ()
                {
-                       Dispose (true);
-                       GC.SuppressFinalize (this);
-               }
-               
-               ~Socket () {
-                       Dispose(false);
+                       // LAMESPEC:
+                       // The socket is not suitable to serve as a hash code,
+                       // because it will change during its lifetime, but
+                       // this is how MS.NET 1.1 implemented this method.
+                       return (int) socket; 
                }
+#endif
        }
 }
-