X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem%2FSystem.Net.Sockets%2FSocket.cs;h=763bc3462f422e907943bb3439a3aa1fb0478b2c;hb=e2b2d181084848f3c5dde2788370db1b79893c69;hp=76f32a0f37c9bc498ca5a9807491ed13e0bf9eee;hpb=e5fe6c826dda8b351c309ba62d0032cc0bcd926e;p=mono.git diff --git a/mcs/class/System/System.Net.Sockets/Socket.cs b/mcs/class/System/System.Net.Sockets/Socket.cs index 76f32a0f37c..763bc3462f4 100644 --- a/mcs/class/System/System.Net.Sockets/Socket.cs +++ b/mcs/class/System/System.Net.Sockets/Socket.cs @@ -9,7 +9,7 @@ // // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc. // http://www.myelin.co.nz -// (c) 2004-2006 Novell, Inc. (http://www.novell.com) +// (c) 2004-2011 Novell, Inc. (http://www.novell.com) // // @@ -36,6 +36,7 @@ using System; using System.Net; using System.Collections; +using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; @@ -43,606 +44,20 @@ 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 +#if !MOONLIGHT +using System.Net.NetworkInformation; #endif namespace System.Net.Sockets { - public class Socket : IDisposable + public partial class Socket : IDisposable { - enum SocketOperation { - Accept, - Connect, - Receive, - ReceiveFrom, - Send, - SendTo, - UsedInManaged1, - UsedInManaged2, - UsedInProcess, - UsedInConsole2, - Disconnect, - AcceptReceive, - ReceiveGeneric, - SendGeneric - } - - [StructLayout (LayoutKind.Sequential)] - 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; - AsyncCallback callback; - WaitHandle waithandle; - - Exception delayedException; - - public EndPoint EndPoint; // Connect,ReceiveFrom,SendTo - public byte [] Buffer; // Receive,ReceiveFrom,Send,SendTo - 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> Buffers; // Receive, Send -#else - public object Buffers; // Reserve this slot in older profiles -#endif - public bool ReuseSocket; // Disconnect - - // Return values - Socket acc_socket; - int total; - - bool completed_sync; - bool completed; - public bool blocking; - internal int error; - SocketOperation operation; - public object ares; - - public SocketAsyncResult (Socket sock, object state, AsyncCallback callback, SocketOperation operation) - { - this.Sock = sock; - this.blocking = sock.blocking; - this.handle = sock.socket; - this.state = state; - this.callback = callback; - this.operation = operation; - SockFlags = SocketFlags.None; - } - - public void CheckIfThrowDelayedException () - { - if (delayedException != null) { - Sock.connected = false; - throw delayedException; - } - - if (error != 0) { - Sock.connected = false; - throw new SocketException (error); - } - } - - void CompleteAllOnDispose (Queue queue) - { - object [] pending = queue.ToArray (); - queue.Clear (); - - WaitCallback cb; - for (int i = 0; i < pending.Length; i++) { - SocketAsyncResult ares = (SocketAsyncResult) pending [i]; - cb = new WaitCallback (ares.CompleteDisposed); - ThreadPool.QueueUserWorkItem (cb, null); - } - if (pending.Length == 0) - Buffer = null; - } - - void CompleteDisposed (object unused) - { - Complete (); - } - - public void Complete () - { - if (operation != SocketOperation.Receive && Sock.disposed) - delayedException = new ObjectDisposedException (Sock.GetType ().ToString ()); - - IsCompleted = true; - - Queue queue = null; - if (operation == SocketOperation.Receive || operation == SocketOperation.ReceiveFrom) { - queue = Sock.readQ; - } else if (operation == SocketOperation.Send || operation == SocketOperation.SendTo) { - queue = Sock.writeQ; - } - - if (queue != null) { - SocketAsyncCall sac = null; - SocketAsyncResult req = null; - lock (queue) { - queue.Dequeue (); // remove ourselves - if (queue.Count > 0) { - req = (SocketAsyncResult) queue.Peek (); - if (!Sock.disposed) { - Worker worker = new Worker (req); - sac = GetDelegate (worker, req.operation); - } else { - CompleteAllOnDispose (queue); - } - } - } - - if (sac != null) - sac.BeginInvoke (null, req); - } - - if (callback != null) - callback (this); - Buffer = null; - } - - SocketAsyncCall GetDelegate (Worker worker, SocketOperation op) - { - switch (op) { - case SocketOperation.Receive: - return new SocketAsyncCall (worker.Receive); - case SocketOperation.ReceiveFrom: - return new SocketAsyncCall (worker.ReceiveFrom); - case SocketOperation.Send: - return new SocketAsyncCall (worker.Send); - case SocketOperation.SendTo: - return new SocketAsyncCall (worker.SendTo); - default: - return null; // never happens - } - } - - public void Complete (bool synch) - { - completed_sync = synch; - Complete (); - } - - public void Complete (int total) - { - this.total = total; - Complete (); - } - - public void Complete (Exception e, bool synch) - { - completed_sync = synch; - delayedException = e; - Complete (); - } - - public void Complete (Exception e) - { - delayedException = e; - Complete (); - } - - public void Complete (Socket s) - { - acc_socket = s; - Complete (); - } - - public void Complete (Socket s, int total) - { - acc_socket = s; - this.total = total; - Complete (); - } - - public object AsyncState { - get { - return state; - } - } - - public WaitHandle AsyncWaitHandle { - get { - lock (this) { - if (waithandle == null) - waithandle = new ManualResetEvent (completed); - } - - return waithandle; - } - set { - waithandle=value; - } - } - - public bool CompletedSynchronously { - get { - return(completed_sync); - } - } - - public bool IsCompleted { - get { - return(completed); - } - set { - completed=value; - lock (this) { - if (waithandle != null && value) { - ((ManualResetEvent) waithandle).Set (); - } - } - } - } - - public Socket Socket { - get { - return acc_socket; - } - } - - public int Total { - 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 - { - SocketAsyncResult result; - - public Worker (SocketAsyncResult ares) - { - this.result = ares; - } - - public void Accept () - { - Socket acc_socket = null; - try { - acc_socket = result.Sock.Accept (); - } catch (Exception e) { - result.Complete (e); - return; - } - - result.Complete (acc_socket); - } - - /* 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.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.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) { - foreach(IPAddress address in result.Addresses) { - IPEndPoint iep = new IPEndPoint (address, result.Port); - SocketAddress serial = iep.Serialize (); - int error = 0; - - 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; - } - } - } - - result.Complete (new SocketException ((int)SocketError.InProgress)); - } 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 () - { - // Actual recv() done in the runtime - result.Complete (); - } - - public void ReceiveFrom () - { - int total = 0; - try { - total = result.Sock.ReceiveFrom_nochecks (result.Buffer, - result.Offset, - result.Size, - result.SockFlags, - ref result.EndPoint); - } catch (Exception e) { - result.Complete (e); - return; - } - - 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) - { - if (result.error == 0) { - send_so_far += last_sent; - result.Offset += last_sent; - result.Size -= last_sent; - } - } - - public void Send () - { - // Actual send() done in the runtime - if (result.error == 0) { - UpdateSendValues (result.Total); - if (result.Sock.disposed) { - result.Complete (); - return; - } - - if (result.Size > 0) { - SocketAsyncCall sac = new SocketAsyncCall (this.Send); - sac.BeginInvoke (null, result); - return; // Have to finish writing everything. See bug #74475. - } - result.Total = send_so_far; - } - result.Complete (); - } - - public void SendTo () - { - int total = 0; - try { - total = result.Sock.SendTo_nochecks (result.Buffer, - result.Offset, - result.Size, - result.SockFlags, - result.EndPoint); - - UpdateSendValues (total); - if (result.Size > 0) { - SocketAsyncCall sac = new SocketAsyncCall (this.SendTo); - sac.BeginInvoke (null, result); - return; // Have to finish writing everything. See bug #74475. - } - result.Total = send_so_far; - } catch (Exception e) { - result.Complete (e); - return; - } - - 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 - } - } - - static Socket () { - // initialize ipv4Supported and ipv6Supported - CheckProtocolSupport (); - } - - /* 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; - /* true if we called Close_internal */ - private bool closed; - internal bool disposed; - - - /* - * This EndPoint is used when creating new endpoints. Because - * there are many types of EndPoints possible, - * seed_endpoint.Create(addr) is used for creating new ones. - * As such, this value is set on Bind, SentTo, ReceiveFrom, - * Connect, etc. - */ - internal EndPoint seed_endpoint = null; - -#if NET_2_0 - private bool isbound; private bool islistening; private bool useoverlappedIO; -#endif - + private const int SOCKET_CLOSED = 10004; - static void AddSockets (ArrayList sockets, IList list, string name) + static void AddSockets (List sockets, IList list, string name) { if (list != null) { foreach (Socket sock in list) { @@ -662,7 +77,7 @@ namespace System.Net.Sockets #endif public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds) { - ArrayList list = new ArrayList (); + var list = new List (); AddSockets (list, checkRead, "checkRead"); AddSockets (list, checkWrite, "checkWrite"); AddSockets (list, checkError, "checkError"); @@ -678,7 +93,7 @@ namespace System.Net.Sockets * WRITE socket 0-n, null, * ERROR socket 0-n, null */ - Socket [] sockets = (Socket []) list.ToArray (typeof (Socket)); + Socket [] sockets = list.ToArray (); Select_internal (ref sockets, microSeconds, out error); if (error != 0) @@ -699,7 +114,6 @@ namespace System.Net.Sockets 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) { @@ -720,8 +134,8 @@ namespace System.Net.Sockets } // Remove non-signaled sockets before the current one - int max = currentList.Count; - while ((cur_sock = (Socket) currentList [currentIdx]) != sock) { + //int max = currentList.Count; + while (((Socket) currentList [currentIdx]) != sock) { currentList.RemoveAt (currentIdx); } currentIdx++; @@ -730,7 +144,7 @@ namespace System.Net.Sockets // private constructor used by Accept, which already // has a socket handle to use - private Socket(AddressFamily family, SocketType type, + internal Socket(AddressFamily family, SocketType type, ProtocolType proto, IntPtr sock) { address_family=family; @@ -740,17 +154,9 @@ 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 + private void SocketDefaults () { -#if NET_2_0 try { if (address_family == AddressFamily.InterNetwork /* Need to test IPv6 further || address_family == AddressFamily.InterNetworkV6 */) { @@ -773,55 +179,28 @@ namespace System.Net.Sockets //this.SendBufferSize = 8192; } catch (SocketException) { } -#endif } - - public Socket(AddressFamily family, SocketType type, ProtocolType proto) - { - address_family=family; - socket_type=type; - protocol_type=proto; - - int error; - - socket = Socket_internal (family, type, proto, out error); - if (error != 0) - throw new SocketException (error); - SocketDefaults (); - } - -#if NET_2_0 - [MonoTODO] +#if !MOBILE public Socket (SocketInformation socketInformation) { - throw new NotImplementedException ("SocketInformation not figured out yet"); + var options = socketInformation.Options; + islistening = (options & SocketInformationOptions.Listening) != 0; + connected = (options & SocketInformationOptions.Connected) != 0; + blocking = (options & SocketInformationOptions.NonBlocking) == 0; + useoverlappedIO = (options & SocketInformationOptions.UseOnlyOverlappedIO) != 0; - // 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; + var result = Mono.DataConverter.Unpack ("iiiil", socketInformation.ProtocolInformation, 0); - int error; - socket = Socket_internal (address_family, socket_type, protocol_type, out error); - if (error != 0) - throw new SocketException (error); - + address_family = (AddressFamily) (int) result [0]; + socket_type = (SocketType) (int) result [1]; + protocol_type = (ProtocolType) (int) result [2]; + isbound = (ProtocolType) (int) result [3] != 0; + socket = (IntPtr) (long) result [4]; SocketDefaults (); -#endif } #endif - - public AddressFamily AddressFamily { - get { - return(address_family); - } - } - + #if !TARGET_JVM // Returns the amount of data waiting to be read on socket [MethodImplAttribute(MethodImplOptions.InternalCall)] @@ -844,41 +223,7 @@ namespace System.Net.Sockets } } -#if !TARGET_JVM - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern static void Blocking_internal(IntPtr socket, - bool block, - out int error); -#endif - - public bool Blocking { - get { - return(blocking); - } - set { - if (disposed && closed) - throw new ObjectDisposedException (GetType ().ToString ()); - - int error; - - Blocking_internal (socket, value, out error); - - if (error != 0) - throw new SocketException (error); - - blocking=value; - } - } - - public bool Connected { - get { - return(connected); - } - - internal set { connected = value; } - } -#if NET_2_0 public bool DontFragment { get { if (disposed && closed) { @@ -982,155 +327,68 @@ namespace System.Net.Sockets } } - 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"); - } - } - } - - public static bool OSSupportsIPv6 { - get { - NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces (); - - foreach(NetworkInterface adapter in nics) { - if (adapter.Supports (NetworkInterfaceComponent.IPv6) == true) { - return(true); - } else { - continue; - } - } - return(false); - } - } - - public int ReceiveBufferSize { - get { - if (disposed && closed) { - throw new ObjectDisposedException (GetType ().ToString ()); - } - return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer)); - } - set { - if (disposed && closed) { - throw new ObjectDisposedException (GetType ().ToString ()); - } - if (value < 0) { - throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero"); - } - - SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value); - } - } - - public int SendBufferSize { - get { - if (disposed && closed) { - throw new ObjectDisposedException (GetType ().ToString ()); - } - return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer)); - } - set { - if (disposed && closed) { - throw new ObjectDisposedException (GetType ().ToString ()); - } - if (value < 0) { - throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero"); - } - - SetSocketOption (SocketOptionLevel.Socket, - SocketOptionName.SendBuffer, - value); - } - } - - public short Ttl { + 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); + } - short ttl_val; + bool multicastloopback; if (address_family == AddressFamily.InterNetwork) { - ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive)); + multicastloopback = (int)(GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0; } else if (address_family == AddressFamily.InterNetworkV6) { - ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit)); + multicastloopback = (int)(GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0; } else { throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets"); } - return(ttl_val); + 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.IpTimeToLive, value); + SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value?1:0); } else if (address_family == AddressFamily.InterNetworkV6) { - SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value); + 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 { @@ -1140,7 +398,6 @@ namespace System.Net.Sockets useoverlappedIO = value; } } -#endif public IntPtr Handle { get { @@ -1151,7 +408,7 @@ namespace System.Net.Sockets #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); + private extern static SocketAddress LocalEndPoint_internal(IntPtr socket, int family, out int error); #endif // Wish: support non-IP endpoints. @@ -1171,42 +428,7 @@ namespace System.Net.Sockets SocketAddress sa; int error; - sa=LocalEndPoint_internal(socket, out error); - - if (error != 0) - throw new SocketException (error); - - return seed_endpoint.Create (sa); - } - } - - public ProtocolType ProtocolType { - get { - return(protocol_type); - } - } - - // Returns the remote endpoint details in addr and port - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket, out int error); - - public EndPoint RemoteEndPoint { - 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=RemoteEndPoint_internal(socket, out error); + sa=LocalEndPoint_internal(socket, (int) address_family, out error); if (error != 0) throw new SocketException (error); @@ -1221,24 +443,6 @@ namespace System.Net.Sockets } } - public static bool SupportsIPv4 { - get { - CheckProtocolSupport(); - return ipv4Supported == 1; - } - } - -#if NET_2_0 - [ObsoleteAttribute ("Use OSSupportsIPv6 instead")] -#endif - public static bool SupportsIPv6 { - get { - CheckProtocolSupport(); - return ipv6Supported == 1; - } - } - -#if NET_2_0 public int SendTimeout { get { if (disposed && closed) @@ -1295,73 +499,7 @@ namespace System.Net.Sockets } } - public bool NoDelay { - get { - if (disposed && closed) - throw new ObjectDisposedException (GetType ().ToString ()); - - if (protocol_type == ProtocolType.Udp) - throw new SocketException ((int)SocketError.ProtocolOption); - - return (int)(GetSocketOption ( - SocketOptionLevel.Tcp, - SocketOptionName.NoDelay)) != 0; - } - - set { - if (disposed && closed) - throw new ObjectDisposedException (GetType ().ToString ()); - - if (protocol_type == ProtocolType.Udp) - throw new SocketException ((int)SocketError.ProtocolOption); - - SetSocketOption ( - SocketOptionLevel.Tcp, - SocketOptionName.NoDelay, value ? 1 : 0); - } - } -#endif - - internal static void CheckProtocolSupport () - { - if(ipv4Supported == -1) { - try { - Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - tmp.Close(); - - ipv4Supported = 1; - } catch { - ipv4Supported = 0; - } - } - - if (ipv6Supported == -1) { -#if !NET_2_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 = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig; - if (config != null) - ipv6Supported = config.ipv6Enabled ? -1 : 0; -#endif -#endif - if (ipv6Supported != 0) { - try { - Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); - tmp.Close(); - - ipv6Supported = 1; - } catch { - ipv6Supported = 0; - } - } - } - } - -#if NET_2_0 +#if !MOONLIGHT public bool AcceptAsync (SocketAsyncEventArgs e) { // NO check is made whether e != null in MS.NET (NRE is thrown in such case) @@ -1376,54 +514,49 @@ namespace System.Net.Sockets 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); - - try { - e.DoOperation (SocketAsyncOperation.Accept, this); - } catch { - ((IDisposable)e).Dispose (); - throw; } - // We always return true for now + e.curSocket = this; + Worker w = e.Worker; + w.Init (this, e, SocketOperation.Accept); + int count; + lock (readQ) { + readQ.Enqueue (e.Worker); + count = readQ.Count; + } + if (count == 1) + socket_pool_queue (Worker.Dispatcher, w.result); return true; } #endif - // Creates a new system socket, returning the handle [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern static IntPtr Accept_internal(IntPtr sock, out int error, bool blocking); - Thread blocking_thread; public Socket Accept() { if (disposed && closed) throw new ObjectDisposedException (GetType ().ToString ()); int error = 0; IntPtr sock = (IntPtr) (-1); - blocking_thread = Thread.CurrentThread; try { + RegisterForBlockingSyscall (); 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; + UnRegisterForBlockingSyscall (); + } + + if (error != 0) { + if (closed) + error = SOCKET_CLOSED; + throw new SocketException(error); } - if (error != 0) - throw new SocketException (error); - Socket accepted = new Socket(this.AddressFamily, this.SocketType, this.ProtocolType, sock); @@ -1439,23 +572,19 @@ namespace System.Net.Sockets int error = 0; IntPtr sock = (IntPtr)(-1); - blocking_thread = Thread.CurrentThread; try { + RegisterForBlockingSyscall (); sock = Accept_internal (socket, out error, blocking); - } catch (ThreadAbortException) { - if (disposed) { -#if !NET_2_1 - Thread.ResetAbort (); -#endif - error = (int)SocketError.Interrupted; - } } finally { - blocking_thread = null; + UnRegisterForBlockingSyscall (); } - if (error != 0) + if (error != 0) { + if (closed) + error = SOCKET_CLOSED; throw new SocketException (error); + } acceptSocket.address_family = this.AddressFamily; acceptSocket.socket_type = this.SocketType; @@ -1470,26 +599,25 @@ namespace System.Net.Sockets */ } - public IAsyncResult BeginAccept(AsyncCallback callback, - object state) + 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); - sac.BeginInvoke (null, req); - return(req); + int count; + lock (readQ) { + readQ.Enqueue (req.Worker); + count = readQ.Count; + } + if (count == 1) + socket_pool_queue (Worker.Dispatcher, req); + return req; } -#if NET_2_0 public IAsyncResult BeginAccept (int receiveSize, AsyncCallback callback, object state) @@ -1501,16 +629,18 @@ namespace System.Net.Sockets throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero"); SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive); - Worker worker = new Worker (req); - 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); + int count; + lock (readQ) { + readQ.Enqueue (req.Worker); + count = readQ.Count; + } + if (count == 1) + socket_pool_queue (Worker.Dispatcher, req); + return req; } public IAsyncResult BeginAccept (Socket acceptSocket, @@ -1541,69 +671,21 @@ namespace System.Net.Sockets } 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) { - - if (disposed && closed) - throw new ObjectDisposedException (GetType ().ToString ()); - - if (end_point == null) - throw new ArgumentNullException ("end_point"); - - SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Connect); - req.EndPoint = end_point; - - // Bug #75154: Connect() should not succeed for .Any addresses. - if (end_point is IPEndPoint) { - IPEndPoint ep = (IPEndPoint) end_point; - if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) { - req.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true); - return req; - } - } - - int error = 0; - if (!blocking) { - SocketAddress serial = end_point.Serialize (); - Connect_internal (socket, serial, out error); - if (error == 0) { - // succeeded synch - connected = true; - req.Complete (true); - } else if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) { - // error synch - connected = false; - req.Complete (new SocketException (error), true); - } - } - - if (blocking || error == (int) SocketError.InProgress || error == (int) SocketError.WouldBlock) { - // continue asynch - connected = false; - Worker worker = new Worker (req); - SocketAsyncCall sac = new SocketAsyncCall (worker.Connect); - sac.BeginInvoke (null, req); + int count; + lock (readQ) { + readQ.Enqueue (req.Worker); + count = readQ.Count; } - + if (count == 1) + socket_pool_queue (Worker.Dispatcher, req); return(req); } -#if NET_2_0 public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback callback, object state) @@ -1617,6 +699,9 @@ namespace System.Net.Sockets if (address.ToString ().Length == 0) throw new ArgumentException ("The length of the IP address is zero"); + if (port <= 0 || port > 65535) + throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536"); + if (islistening) throw new InvalidOperationException (); @@ -1624,36 +709,6 @@ namespace System.Net.Sockets return(BeginConnect (iep, callback, state)); } - public IAsyncResult BeginConnect (IPAddress[] addresses, - int port, - AsyncCallback callback, - object state) - { - if (disposed && closed) - throw new ObjectDisposedException (GetType ().ToString ()); - - if (addresses == null) - throw new ArgumentNullException ("addresses"); - - if (this.AddressFamily != AddressFamily.InterNetwork && - this.AddressFamily != AddressFamily.InterNetworkV6) - throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families"); - - if (islistening) - throw new InvalidOperationException (); - - SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Connect); - req.Addresses = addresses; - req.Port = port; - - connected = false; - Worker worker = new Worker (req); - SocketAsyncCall sac = new SocketAsyncCall (worker.Connect); - sac.BeginInvoke (null, req); - - return(req); - } - public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state) @@ -1668,11 +723,13 @@ namespace System.Net.Sockets address_family != AddressFamily.InterNetworkV6) throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families"); + if (port <= 0 || port > 65535) + throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536"); + if (islistening) throw new InvalidOperationException (); - IPHostEntry hostent = Dns.GetHostEntry (host); - return (BeginConnect (hostent.AddressList, port, callback, state)); + return BeginConnect (Dns.GetHostAddresses (host), port, callback, state); } public IAsyncResult BeginDisconnect (bool reuseSocket, @@ -1684,14 +741,24 @@ namespace System.Net.Sockets 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); - + socket_pool_queue (Worker.Dispatcher, req); return(req); } -#endif + + void CheckRange (byte[] buffer, int offset, int size) + { + if (offset < 0) + throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0"); + + if (offset > buffer.Length) + throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length"); + + if (size < 0) + throw new ArgumentOutOfRangeException ("size", "size must be >= 0"); + + if (size > buffer.Length - offset) + throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset"); + } public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, @@ -1705,30 +772,23 @@ namespace System.Net.Sockets if (buffer == null) throw new ArgumentNullException ("buffer"); - if (offset < 0 || offset > buffer.Length) - throw new ArgumentOutOfRangeException ("offset"); - - if (size < 0 || offset + size > buffer.Length) - throw new ArgumentOutOfRangeException ("size"); + CheckRange (buffer, offset, size); - SocketAsyncResult req; + SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Receive); + req.Buffer = buffer; + req.Offset = offset; + req.Size = size; + req.SockFlags = socket_flags; + int count; lock (readQ) { - req = new SocketAsyncResult (this, state, callback, SocketOperation.Receive); - req.Buffer = buffer; - req.Offset = offset; - req.Size = size; - req.SockFlags = socket_flags; - readQ.Enqueue (req); - if (readQ.Count == 1) { - Worker worker = new Worker (req); - SocketAsyncCall sac = new SocketAsyncCall (worker.Receive); - sac.BeginInvoke (null, req); - } + readQ.Enqueue (req.Worker); + count = readQ.Count; } - + if (count == 1) + socket_pool_queue (Worker.Dispatcher, req); return req; } -#if NET_2_0 + public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags flags, out SocketError error, @@ -1758,20 +818,17 @@ namespace System.Net.Sockets if (buffers == null) throw new ArgumentNullException ("buffers"); - SocketAsyncResult req; + SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveGeneric); + req.Buffers = buffers; + req.SockFlags = socketFlags; + int count; 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); - } + readQ.Enqueue (req.Worker); + count = readQ.Count; } - - return(req); + if (count == 1) + socket_pool_queue (Worker.Dispatcher, req); + return req; } [CLSCompliant (false)] @@ -1787,7 +844,6 @@ namespace System.Net.Sockets errorCode = SocketError.Success; return (BeginReceive (buffers, socketFlags, callback, state)); } -#endif public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset, int size, @@ -1801,34 +857,27 @@ namespace System.Net.Sockets if (buffer == null) throw new ArgumentNullException ("buffer"); - if (offset < 0) - throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0"); - - if (size < 0) - throw new ArgumentOutOfRangeException ("size", "size must be >= 0"); + if (remote_end == null) + throw new ArgumentNullException ("remote_end"); - if (offset + size > buffer.Length) - throw new ArgumentOutOfRangeException ("offset, size", "offset + size exceeds the buffer length"); + CheckRange (buffer, offset, size); - SocketAsyncResult req; + SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveFrom); + req.Buffer = buffer; + req.Offset = offset; + req.Size = size; + req.SockFlags = socket_flags; + req.EndPoint = remote_end; + int count; lock (readQ) { - req = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveFrom); - req.Buffer = buffer; - req.Offset = offset; - req.Size = size; - req.SockFlags = socket_flags; - req.EndPoint = remote_end; - readQ.Enqueue (req); - if (readQ.Count == 1) { - Worker worker = new Worker (req); - SocketAsyncCall sac = new SocketAsyncCall (worker.ReceiveFrom); - sac.BeginInvoke (null, req); - } + readQ.Enqueue (req.Worker); + count = readQ.Count; } + if (count == 1) + socket_pool_queue (Worker.Dispatcher, req); return req; } -#if NET_2_0 [MonoTODO] public IAsyncResult BeginReceiveMessageFrom ( byte[] buffer, int offset, int size, @@ -1844,15 +893,10 @@ namespace System.Net.Sockets if (remoteEP == null) throw new ArgumentNullException ("remoteEP"); - if (offset < 0 || offset > buffer.Length) - throw new ArgumentOutOfRangeException ("offset"); - - if (size < 0 || offset + size > buffer.Length) - throw new ArgumentOutOfRangeException ("size"); + CheckRange (buffer, offset, size); throw new NotImplementedException (); } -#endif public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state) @@ -1863,39 +907,26 @@ namespace System.Net.Sockets if (buffer == null) throw new ArgumentNullException ("buffer"); - if (offset < 0) - throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0"); - - if (size < 0) - throw new ArgumentOutOfRangeException ("size", "size must be >= 0"); - - if (offset + size > buffer.Length) - throw new ArgumentOutOfRangeException ("offset, size", "offset + size exceeds the buffer length"); + CheckRange (buffer, offset, size); -#if NET_2_0 - /* TODO: Check this exception in the 1.1 profile */ if (!connected) throw new SocketException ((int)SocketError.NotConnected); -#endif - SocketAsyncResult req; + SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Send); + req.Buffer = buffer; + req.Offset = offset; + req.Size = size; + req.SockFlags = socket_flags; + int count; lock (writeQ) { - req = new SocketAsyncResult (this, state, callback, SocketOperation.Send); - req.Buffer = buffer; - req.Offset = offset; - req.Size = size; - req.SockFlags = socket_flags; - writeQ.Enqueue (req); - if (writeQ.Count == 1) { - Worker worker = new Worker (req); - SocketAsyncCall sac = new SocketAsyncCall (worker.Send); - sac.BeginInvoke (null, req); - } + writeQ.Enqueue (req.Worker); + count = writeQ.Count; } + if (count == 1) + socket_pool_queue (Worker.Dispatcher, req); return req; } -#if NET_2_0 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, @@ -1928,20 +959,17 @@ namespace System.Net.Sockets if (!connected) throw new SocketException ((int)SocketError.NotConnected); - SocketAsyncResult req; + SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.SendGeneric); + req.Buffers = buffers; + req.SockFlags = socketFlags; + int count; 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); - } + writeQ.Enqueue (req.Worker); + count = writeQ.Count; } - - return(req); + if (count == 1) + socket_pool_queue (Worker.Dispatcher, req); + return req; } [CLSCompliant (false)] @@ -1960,7 +988,43 @@ namespace System.Net.Sockets return (BeginSend (buffers, socketFlags, callback, state)); } - [MonoTODO ("Not implemented")] + delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags); + + sealed class SendFileAsyncResult : IAsyncResult { + IAsyncResult ares; + SendFileHandler d; + + public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares) + { + this.d = d; + this.ares = ares; + } + + public object AsyncState { + get { return ares.AsyncState; } + } + + public WaitHandle AsyncWaitHandle { + get { return ares.AsyncWaitHandle; } + } + + public bool CompletedSynchronously { + get { return ares.CompletedSynchronously; } + } + + public bool IsCompleted { + get { return ares.IsCompleted; } + } + + public SendFileHandler Delegate { + get { return d; } + } + + public IAsyncResult Original { + get { return ares; } + } + } + public IAsyncResult BeginSendFile (string fileName, AsyncCallback callback, object state) @@ -1974,10 +1038,9 @@ namespace System.Net.Sockets if (!File.Exists (fileName)) throw new FileNotFoundException (); - throw new NotImplementedException (); + return BeginSendFile (fileName, null, null, 0, callback, state); } - [MonoTODO ("Not implemented")] public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, @@ -1994,9 +1057,9 @@ namespace System.Net.Sockets if (!File.Exists (fileName)) throw new FileNotFoundException (); - throw new NotImplementedException (); + SendFileHandler d = new SendFileHandler (SendFile); + return new SendFileAsyncResult (d, d.BeginInvoke (fileName, preBuffer, postBuffer, flags, callback, state)); } -#endif public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, @@ -2010,30 +1073,21 @@ namespace System.Net.Sockets if (buffer == null) throw new ArgumentNullException ("buffer"); - if (offset < 0) - throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0"); - - if (size < 0) - throw new ArgumentOutOfRangeException ("size", "size must be >= 0"); - - if (offset + size > buffer.Length) - throw new ArgumentOutOfRangeException ("offset, size", "offset + size exceeds the buffer length"); + CheckRange (buffer, offset, size); - SocketAsyncResult req; + SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.SendTo); + req.Buffer = buffer; + req.Offset = offset; + req.Size = size; + req.SockFlags = socket_flags; + req.EndPoint = remote_end; + int count; lock (writeQ) { - req = new SocketAsyncResult (this, state, callback, SocketOperation.SendTo); - req.Buffer = buffer; - req.Offset = offset; - req.Size = size; - req.SockFlags = socket_flags; - req.EndPoint = remote_end; - writeQ.Enqueue (req); - if (writeQ.Count == 1) { - Worker worker = new Worker (req); - SocketAsyncCall sac = new SocketAsyncCall (worker.SendTo); - sac.BeginInvoke (null, req); - } + writeQ.Enqueue (req.Worker); + count = writeQ.Count; } + if (count == 1) + socket_pool_queue (Worker.Dispatcher, req); return req; } @@ -2055,129 +1109,12 @@ namespace System.Net.Sockets 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; } - // Closes the socket - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern static void Close_internal(IntPtr socket, out int error); - - public void Close() - { - ((IDisposable) this).Dispose (); - } - -#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 - - // Connects to the remote address - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern static void Connect_internal(IntPtr sock, - SocketAddress sa, - out int error); - - public void Connect(EndPoint remote_end) { - 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); - } - -#if NET_2_1 - // Check for SL2.0b1 restrictions - // - tcp only - // - SiteOfOrigin - // - port 4502->4532 + default - if (protocol_type != ProtocolType.Tcp) - throw new SocketException ((int) SocketError.AccessDenied); - //FIXME: replace 80 by Application.Curent.Host.Source.Port - if (remote_end is IPEndPoint) - if (((remote_end as IPEndPoint).Port < 4502 || (remote_end as IPEndPoint).Port > 4530) && (remote_end as IPEndPoint).Port != 80) - throw new SocketException ((int) SocketError.AccessDenied); - else //unsuported endpoint type - throw new SocketException ((int) SocketError.AccessDenied); - //FIXME: check for Application.Curent.Host.Source.DnsSafeHost -#endif - -#if NET_2_0 - /* TODO: check this for the 1.1 profile too */ - if (islistening) - throw new InvalidOperationException (); -#endif - - SocketAddress serial = remote_end.Serialize (); - int error = 0; - - blocking_thread = Thread.CurrentThread; - try { - Connect_internal (socket, serial, out error); - } catch (ThreadAbortException) { - if (disposed) { -#if !NET_2_1 //2.1 profile does not contains Thread.ResetAbort - Thread.ResetAbort (); -#endif - error = (int) SocketError.Interrupted; - } - } finally { - blocking_thread = null; - } - - if (error != 0) - throw new SocketException (error); - - connected=true; - -#if NET_2_0 - isbound = true; -#endif - - seed_endpoint = remote_end; - } - -#if NET_2_0 public void Connect (IPAddress address, int port) { Connect (new IPEndPoint (address, port)); @@ -2199,15 +1136,15 @@ namespace System.Net.Sockets throw new InvalidOperationException (); /* FIXME: do non-blocking sockets Poll here? */ + int error = 0; foreach (IPAddress address in addresses) { - IPEndPoint iep = new IPEndPoint (address, - port); + IPEndPoint iep = new IPEndPoint (address, port); SocketAddress serial = iep.Serialize (); - int error = 0; Connect_internal (socket, serial, out error); if (error == 0) { connected = true; + isbound = true; seed_endpoint = iep; return; } else if (error != (int)SocketError.InProgress && @@ -2217,38 +1154,41 @@ namespace System.Net.Sockets if (!blocking) { Poll (-1, SelectMode.SelectWrite); - int success = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error); - if (success == 0) { + error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error); + if (error == 0) { connected = true; + isbound = true; seed_endpoint = iep; return; } } } + if (error != 0) + throw new SocketException (error); } public void Connect (string host, int port) { - IPHostEntry hostent = Dns.GetHostEntry (host); - Connect (hostent.AddressList, port); + IPAddress [] addresses = Dns.GetHostAddresses (host); + Connect (addresses, port); } -#if NET_2_0 +#if !MOONLIGHT 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); - + e.curSocket = this; + e.Worker.Init (this, e, SocketOperation.Disconnect); + socket_pool_queue (Worker.Dispatcher, e.Worker.result); return true; } #endif + [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern static void Disconnect_internal(IntPtr sock, - bool reuse, - out int error); + 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 @@ -2279,18 +1219,24 @@ namespace System.Net.Sockets } } - [MonoTODO ("Not implemented")] +#if !MOBILE + [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")] 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 (); + var si = new SocketInformation (); + si.Options = + (islistening ? SocketInformationOptions.Listening : 0) | + (connected ? SocketInformationOptions.Connected : 0) | + (blocking ? 0 : SocketInformationOptions.NonBlocking) | + (useoverlappedIO ? SocketInformationOptions.UseOnlyOverlappedIO : 0); + + si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, isbound ? 1 : 0, (long)socket); + socket = (IntPtr) (-1); + + return si; } #endif - + public Socket EndAccept (IAsyncResult result) { int bytes; @@ -2299,23 +1245,13 @@ namespace System.Net.Sockets return(EndAccept (out buffer, out bytes, result)); } -#if NET_2_0 - public Socket EndAccept (out byte[] buffer, - IAsyncResult asyncResult) + public Socket EndAccept (out byte[] buffer, IAsyncResult asyncResult) { int bytes; - return(EndAccept (out buffer, out bytes, asyncResult)); } -#endif -#if NET_2_0 - public -#else - private -#endif - Socket EndAccept (out byte[] buffer, out int bytesTransferred, - IAsyncResult asyncResult) + public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult) { if (disposed && closed) throw new ObjectDisposedException (GetType ().ToString ()); @@ -2327,6 +1263,8 @@ namespace System.Net.Sockets if (req == null) throw new ArgumentException ("Invalid IAsyncResult", "asyncResult"); + if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1) + throw InvalidAsyncOp ("EndAccept"); if (!asyncResult.IsCompleted) asyncResult.AsyncWaitHandle.WaitOne (); @@ -2350,13 +1288,15 @@ 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(); } -#if NET_2_0 +#if !MOONLIGHT public void EndDisconnect (IAsyncResult asyncResult) { if (disposed && closed) @@ -2369,6 +1309,8 @@ namespace System.Net.Sockets if (req == null) throw new ArgumentException ("Invalid IAsyncResult", "asyncResult"); + if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1) + throw InvalidAsyncOp ("EndDisconnect"); if (!asyncResult.IsCompleted) asyncResult.AsyncWaitHandle.WaitOne (); @@ -2376,60 +1318,6 @@ namespace System.Net.Sockets } #endif - public int EndReceive (IAsyncResult result) - { - SocketError error; - - return (EndReceive (result, out error)); - } - -#if NET_2_0 - public -#else - private -#endif - int EndReceive (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", "asyncResult"); - - if (!asyncResult.IsCompleted) - asyncResult.AsyncWaitHandle.WaitOne (); - - errorCode = req.ErrorCode; - req.CheckIfThrowDelayedException (); - - return(req.Total); - } - - public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point) - { - if (disposed && closed) - throw new ObjectDisposedException (GetType ().ToString ()); - - if (result == null) - throw new ArgumentNullException ("result"); - - SocketAsyncResult req = result as SocketAsyncResult; - if (req == null) - throw new ArgumentException ("Invalid IAsyncResult", "result"); - - if (!result.IsCompleted) - result.AsyncWaitHandle.WaitOne(); - - req.CheckIfThrowDelayedException(); - end_point = req.EndPoint; - return req.Total; - } - -#if NET_2_0 [MonoTODO] public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, @@ -2449,45 +1337,11 @@ namespace System.Net.Sockets 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 (!asyncResult.IsCompleted) - asyncResult.AsyncWaitHandle.WaitOne (); - - errorCode = req.ErrorCode; - req.CheckIfThrowDelayedException (); - - return(req.Total); - } -#if NET_2_0 - [MonoTODO] public void EndSendFile (IAsyncResult asyncResult) { if (disposed && closed) @@ -2496,14 +1350,14 @@ namespace System.Net.Sockets if (asyncResult == null) throw new ArgumentNullException ("asyncResult"); - SocketAsyncResult req = asyncResult as SocketAsyncResult; - if (req == null) + SendFileAsyncResult ares = asyncResult as SendFileAsyncResult; + if (ares == null) throw new ArgumentException ("Invalid IAsyncResult", "asyncResult"); - throw new NotImplementedException (); + ares.Delegate.EndInvoke (ares.Original); } -#endif +#if !MOONLIGHT public int EndSendTo (IAsyncResult result) { if (disposed && closed) @@ -2516,70 +1370,47 @@ 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(); req.CheckIfThrowDelayedException(); return req.Total; } - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern static void GetSocketOption_obj_internal(IntPtr socket, - SocketOptionLevel level, SocketOptionName name, out object obj_val, - out int error); +#endif [MethodImplAttribute(MethodImplOptions.InternalCall)] 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, + + 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, + + GetSocketOption_arr_internal (socket, optionLevel, optionName, ref byte_val, out error); if (error != 0) throw new SocketException (error); @@ -2590,7 +1421,8 @@ namespace System.Net.Sockets // See Socket.IOControl, WSAIoctl documentation in MSDN. The // common options between UNIX and Winsock are FIONREAD, // FIONBIO and SIOCATMARK. Anything else will depend on the - // system. + // system except SIO_KEEPALIVE_VALS which is properly handled + // on both windows and linux. [MethodImplAttribute(MethodImplOptions.InternalCall)] extern static int WSAIoctl (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error); @@ -2613,51 +1445,31 @@ namespace System.Net.Sockets return result; } -#if NET_2_0 - [MonoTODO] - public int IOControl (IOControlCode ioControlCode, - byte[] optionInValue, - byte[] optionOutValue) + public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue) { - /* Probably just needs to mirror the int - * overload, but more investigation needed. - */ - throw new NotImplementedException (); + return IOControl ((int) ioControlCode, optionInValue, optionOutValue); } -#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) throw new SocketException (error); -#if NET_2_0 islistening = true; -#endif } - [MethodImplAttribute(MethodImplOptions.InternalCall)] - extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error); - public bool Poll (int time_us, SelectMode mode) { if (disposed && closed) @@ -2687,74 +1499,17 @@ 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. - */ - internal bool Poll (int time_us, SelectMode mode, out int socket_error) - { - 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."); - - int error; - bool result = Poll_internal (socket, mode, time_us, out error); - if (error != 0) - throw new SocketException (error); - - socket_error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error); - - if (mode == SelectMode.SelectWrite && result) { - /* 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; - } - } - - return result; - } - -#if NET_2_0 - public bool ReceiveAsync (SocketAsyncEventArgs e) - { - // NO check is made whether e != null in MS.NET (NRE is thrown in such case) - // - // LAME SPEC: the ArgumentException is never thrown, instead an NRE is - // thrown when e.Buffer and e.BufferList are null (works fine when one is - // set to a valid object) - if (disposed && closed) - throw new ObjectDisposedException (GetType ().ToString ()); - - // 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."); - - e.DoOperation (SocketAsyncOperation.Receive, this); - - // We always return true for now - return true; - } -#endif - - public int Receive (byte [] buf) + public int Receive (byte [] buffer) { 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, SocketFlags.None, out error); if (error != SocketError.Success) throw new SocketException ((int) error); @@ -2762,41 +1517,17 @@ namespace System.Net.Sockets return ret; } - public int Receive (byte [] buf, SocketFlags flags) - { - if (disposed && closed) - throw new ObjectDisposedException (GetType ().ToString ()); - - if (buf == null) - throw new ArgumentNullException ("buf"); - - SocketError error; - - int ret = Receive_nochecks (buf, 0, buf.Length, 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; - } - - public int Receive (byte [] buf, int size, SocketFlags flags) + public int Receive (byte [] buffer, SocketFlags flags) { if (disposed && closed) throw new ObjectDisposedException (GetType ().ToString ()); - if (buf == null) - throw new ArgumentNullException ("buf"); - - if (size < 0 || size > buf.Length) - throw new ArgumentOutOfRangeException ("size"); + if (buffer == null) + throw new ArgumentNullException ("buffer"); SocketError error; - int ret = Receive_nochecks (buf, 0, size, flags, out error); + int ret = Receive_nochecks (buffer, 0, buffer.Length, flags, out error); if (error != SocketError.Success) { if (error == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set @@ -2807,23 +1538,19 @@ namespace System.Net.Sockets return ret; } - public int Receive (byte [] buf, int offset, int size, 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 (offset < 0 || offset > buf.Length) - throw new ArgumentOutOfRangeException ("offset"); + CheckRange (buffer, 0, size); - if (size < 0 || offset + size > buf.Length) - throw new ArgumentOutOfRangeException ("size"); - SocketError error; - int ret = Receive_nochecks (buf, offset, size, 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 @@ -2834,131 +1561,43 @@ namespace System.Net.Sockets return ret; } -#if NET_2_0 - public int Receive (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error) + 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 (offset < 0 || offset > buf.Length) - throw new ArgumentOutOfRangeException ("offset"); - - if (size < 0 || offset + size > buf.Length) - throw new ArgumentOutOfRangeException ("size"); - - return Receive_nochecks (buf, offset, size, flags, out error); - } + if (buffer == null) + throw new ArgumentNullException ("buffer"); - [MethodImplAttribute (MethodImplOptions.InternalCall)] - private extern static int Receive_internal (IntPtr sock, - WSABUF[] bufarray, - SocketFlags flags, - out int error); - - public int Receive (IList> buffers) - { - int ret; - SocketError error; - - ret = Receive (buffers, SocketFlags.None, out error); - if (error != SocketError.Success) { - throw new SocketException ((int)error); - } + CheckRange (buffer, offset, size); - return(ret); - } - - [CLSCompliant (false)] - public int Receive (IList> buffers, - SocketFlags socketFlags) - { - int ret; SocketError error; + + int ret = Receive_nochecks (buffer, offset, size, flags, out error); - ret = Receive (buffers, socketFlags, out error); if (error != SocketError.Success) { - throw new SocketException ((int)error); + 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; } - [CLSCompliant (false)] - public int Receive (IList> buffers, - SocketFlags socketFlags, - out SocketError errorCode) + public int Receive (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error) { - if (buffers == null || - buffers.Count == 0) { - throw new ArgumentNullException ("buffers"); - } - - if (disposed && closed) { + if (disposed && closed) throw new ObjectDisposedException (GetType ().ToString ()); - } - - int numsegments = buffers.Count; - int nativeError; - int ret; - - /* 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]; - - for(int i = 0; i < numsegments; i++) { - ArraySegment 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 = Receive_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); - } -#endif + if (buffer == null) + throw new ArgumentNullException ("buffer"); - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern static int Receive_internal(IntPtr sock, - byte[] buffer, - int offset, - int count, - SocketFlags flags, - out int error); - - internal 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; + CheckRange (buffer, offset, size); - return ret; + return Receive_nochecks (buffer, offset, size, flags, out error); } -#if NET_2_0 +#if !MOONLIGHT public bool ReceiveFromAsync (SocketAsyncEventArgs e) { if (disposed && closed) @@ -2970,57 +1609,69 @@ namespace System.Net.Sockets if (e.RemoteEndPoint == null) throw new ArgumentNullException ("remoteEP", "Value cannot be null."); - e.DoOperation (SocketAsyncOperation.ReceiveFrom, this); - - // We always return true for now + e.curSocket = this; + e.Worker.Init (this, e, SocketOperation.ReceiveFrom); + SocketAsyncResult res = e.Worker.result; + res.Buffer = e.Buffer; + res.Offset = e.Offset; + res.Size = e.Count; + res.EndPoint = e.RemoteEndPoint; + res.SockFlags = e.SocketFlags; + int count; + lock (readQ) { + readQ.Enqueue (e.Worker); + count = readQ.Count; + } + if (count == 1) + socket_pool_queue (Worker.Dispatcher, res); return true; } #endif - - 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 (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, 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)] @@ -3032,25 +1683,21 @@ 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 (remote_end == null) - throw new ArgumentNullException ("remote_end"); + if (buffer == null) + throw new ArgumentNullException ("buffer"); - if (offset < 0 || offset > buf.Length) - throw new ArgumentOutOfRangeException ("offset"); + if (remoteEP == null) + throw new ArgumentNullException ("remoteEP"); - if (size < 0 || offset + size > buf.Length) - throw new ArgumentOutOfRangeException ("size"); + CheckRange (buffer, offset, size); - return ReceiveFrom_nochecks (buf, offset, size, flags, ref remote_end); + return ReceiveFrom_nochecks (buffer, offset, size, flags, ref remoteEP); } internal int ReceiveFrom_nochecks (byte [] buf, int offset, int size, SocketFlags flags, @@ -3082,10 +1729,7 @@ namespace System.Net.Sockets } connected = true; - -#if NET_2_0 isbound = true; -#endif // If sockaddr is null then we're a connection // oriented protocol and should ignore the @@ -3103,7 +1747,6 @@ namespace System.Net.Sockets return cnt; } -#if NET_2_0 [MonoTODO ("Not implemented")] public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e) { @@ -3130,11 +1773,7 @@ namespace System.Net.Sockets if (remoteEP == null) throw new ArgumentNullException ("remoteEP"); - if (offset < 0 || offset > buffer.Length) - throw new ArgumentOutOfRangeException ("offset"); - - if (size < 0 || offset + size > buffer.Length) - throw new ArgumentOutOfRangeException ("size"); + CheckRange (buffer, offset, size); /* FIXME: figure out how we get hold of the * IPPacketInformation @@ -3153,22 +1792,6 @@ namespace System.Net.Sockets throw new NotImplementedException (); } - public bool SendAsync (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.Buffer == null && e.BufferList == null) - throw new ArgumentException ("Either e.Buffer or e.BufferList must be valid buffers."); - - e.DoOperation (SocketAsyncOperation.Send, this); - - // We always return true for now - return true; - } -#endif - public int Send (byte [] buf) { if (disposed && closed) @@ -3213,8 +1836,7 @@ namespace System.Net.Sockets if (buf == null) throw new ArgumentNullException ("buf"); - if (size < 0 || size > buf.Length) - throw new ArgumentOutOfRangeException ("size"); + CheckRange (buf, 0, size); SocketError error; @@ -3234,11 +1856,7 @@ namespace System.Net.Sockets if (buf == null) throw new ArgumentNullException ("buffer"); - if (offset < 0 || offset > buf.Length) - throw new ArgumentOutOfRangeException ("offset"); - - if (size < 0 || offset + size > buf.Length) - throw new ArgumentOutOfRangeException ("size"); + CheckRange (buf, offset, size); SocketError error; @@ -3250,7 +1868,6 @@ namespace System.Net.Sockets return ret; } -#if NET_2_0 public int Send (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error) { if (disposed && closed) @@ -3259,126 +1876,14 @@ namespace System.Net.Sockets if (buf == null) throw new ArgumentNullException ("buffer"); - if (offset < 0 || offset > buf.Length) - throw new ArgumentOutOfRangeException ("offset"); - - if (size < 0 || offset + size > buf.Length) - throw new ArgumentOutOfRangeException ("size"); + CheckRange (buf, offset, size); return Send_nochecks (buf, offset, size, flags, out error); } - [MethodImplAttribute (MethodImplOptions.InternalCall)] - private extern static int Send_internal (IntPtr sock, - WSABUF[] bufarray, - SocketFlags flags, - out int error); - - public int Send (IList> buffers) - { - 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> 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> 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 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); - } -#endif - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern static int Send_internal(IntPtr sock, - byte[] buf, int offset, - int count, - SocketFlags flags, - out int error); - - internal int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error) - { - if (size == 0) { - error = SocketError.Success; - return 0; - } - - int nativeError; - - int ret = Send_internal (socket, buf, offset, size, flags, out nativeError); - - error = (SocketError)nativeError; + private extern static bool SendFile (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags); - if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) - connected = false; - else - connected = true; - - return ret; - } - -#if NET_2_0 - [MonoTODO ("Not implemented")] public void SendFile (string fileName) { if (disposed && closed) @@ -3390,14 +1895,9 @@ namespace System.Net.Sockets if (!blocking) throw new InvalidOperationException (); - if (!File.Exists (fileName)) - throw new FileNotFoundException (); - - /* FIXME: Implement TransmitFile */ - throw new NotImplementedException (); + SendFile (fileName, null, null, 0); } - [MonoTODO ("Not implemented")] public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags) { if (disposed && closed) @@ -3409,25 +1909,41 @@ namespace System.Net.Sockets if (!blocking) throw new InvalidOperationException (); - if (!File.Exists (fileName)) - throw new FileNotFoundException (); - - /* FIXME: Implement TransmitFile */ - throw new NotImplementedException (); + if (!SendFile (socket, fileName, preBuffer, postBuffer, flags)) { + SocketException exc = new SocketException (); + if (exc.ErrorCode == 2 || exc.ErrorCode == 3) + throw new FileNotFoundException (); + throw exc; + } } +#if !MOONLIGHT 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.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."); - - e.DoOperation (SocketAsyncOperation.SendTo, this); - // We always return true for now + e.curSocket = this; + e.Worker.Init (this, e, SocketOperation.SendTo); + SocketAsyncResult res = e.Worker.result; + res.Buffer = e.Buffer; + res.Offset = e.Offset; + res.Size = e.Count; + res.SockFlags = e.SocketFlags; + res.EndPoint = e.RemoteEndPoint; + int count; + lock (writeQ) { + writeQ.Enqueue (e.Worker); + count = writeQ.Count; + } + if (count == 1) + socket_pool_queue (Worker.Dispatcher, res); return true; } #endif @@ -3471,8 +1987,7 @@ namespace System.Net.Sockets if (remote_end == null) throw new ArgumentNullException ("remote_end"); - if (size < 0 || size > buffer.Length) - throw new ArgumentOutOfRangeException ("size"); + CheckRange (buffer, 0, size); return SendTo_nochecks (buffer, 0, size, flags, remote_end); } @@ -3498,11 +2013,7 @@ namespace System.Net.Sockets if (remote_end == null) throw new ArgumentNullException("remote_end"); - if (offset < 0 || offset > buffer.Length) - throw new ArgumentOutOfRangeException ("offset"); - - if (size < 0 || offset + size > buffer.Length) - throw new ArgumentOutOfRangeException ("size"); + CheckRange (buffer, offset, size); return SendTo_nochecks (buffer, offset, size, flags, remote_end); } @@ -3525,155 +2036,85 @@ 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); - if (error != 0) + 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("opt_value"); + // 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 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); -#else - throw new ArgumentException ("Use an integer 1 (true) or 0 (false) instead of a boolean.", "opt_value"); -#endif + if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) { + LingerOption linger = optionValue as LingerOption; + if (linger == null) + throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue"); + 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) + throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue"); + 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) + throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue"); + SetSocketOption_internal (socket, optionLevel, optionName, multicast, null, 0, out error); } else { - SetSocketOption_internal (socket, level, name, opt_value, null, 0, out error); + throw new ArgumentException ("Invalid value specified.", "optionValue"); } - 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); - - if (error != 0) + 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); - } - -#if ONLY_1_1 - public override int GetHashCode () - { - // 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 - - 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); - } } } +