1 // System.Net.Sockets.Socket.cs
4 // Phillip Pearson (pp@myelin.co.nz)
5 // Dick Porter <dick@ximian.com>
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // Sridhar Kulkarni (sridharkulkarni@gmail.com)
8 // Brian Nickel (brian.nickel@gmail.com)
10 // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
11 // http://www.myelin.co.nz
12 // (c) 2004-2011 Novell, Inc. (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System.Collections;
38 using System.Collections.Generic;
39 using System.Runtime.CompilerServices;
40 using System.Runtime.InteropServices;
41 using System.Threading;
42 using System.Reflection;
44 using System.Net.Configuration;
47 using System.Net.NetworkInformation;
49 namespace System.Net.Sockets
51 public partial class Socket : IDisposable
53 const int SOCKET_CLOSED_CODE = 10004;
54 const string TIMEOUT_EXCEPTION_MSG = "A connection attempt failed because the connected party did not properly respond" +
55 "after a period of time, or established connection failed because connected host has failed to respond";
58 * These two fields are looked up by name by the runtime, don't change
59 * their name without also updating the runtime code.
61 static int ipv4_supported = -1;
62 static int ipv6_supported = -1;
64 /* true if we called Close_internal */
68 bool use_overlapped_io;
72 /* the field "safe_handle" is looked up by name by the runtime */
73 SafeSocketHandle safe_handle;
75 AddressFamily address_family;
76 SocketType socket_type;
77 ProtocolType protocol_type;
80 * This EndPoint is used when creating new endpoints. Because
81 * there are many types of EndPoints possible,
82 * seed_endpoint.Create(addr) is used for creating new ones.
83 * As such, this value is set on Bind, SentTo, ReceiveFrom,
86 internal EndPoint seed_endpoint = null;
88 internal Queue readQ = new Queue (2);
89 internal Queue writeQ = new Queue (2);
91 internal bool is_blocking = true;
92 internal bool is_bound;
94 /* When true, the socket was connected at the time of the last IO operation */
95 internal bool is_connected;
97 internal bool is_disposed;
98 internal bool connect_in_progress;
104 if (ipv4_supported == -1) {
106 Socket tmp = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
115 if (ipv6_supported == -1) {
116 // We need to put a try/catch around ConfigurationManager methods as will always throw an exception
117 // when run in a mono embedded application. This occurs as embedded applications do not have a setup
118 // for application config. The exception is not thrown when called from a normal .NET application.
120 // We, then, need to guard calls to the ConfigurationManager. If the config is not found or throws an
121 // exception, will fall through to the existing Socket / API directly below in the code.
123 // Also note that catching ConfigurationErrorsException specifically would require library dependency
124 // System.Configuration, and wanted to avoid that.
126 #if CONFIGURATION_DEP
128 SettingsSection config;
129 config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
131 ipv6_supported = config.Ipv6.Enabled ? -1 : 0;
137 NetConfig config = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig;
139 ipv6_supported = config.ipv6Enabled ? -1 : 0;
145 if (ipv6_supported != 0) {
147 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
158 [MonoTODO ("Currently hardcoded to IPv4. Ideally, support v4/v6 dual-stack.")]
159 public Socket (SocketType socketType, ProtocolType protocolType)
160 : this (AddressFamily.InterNetwork, socketType, protocolType)
164 public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
166 #if NET_2_1 && !MOBILE
167 switch (addressFamily) {
168 case AddressFamily.InterNetwork: // ok
169 case AddressFamily.InterNetworkV6: // ok
170 case AddressFamily.Unknown: // SocketException will be thrown later (with right error #)
172 // case AddressFamily.Unspecified:
174 throw new ArgumentException ("addressFamily");
177 switch (socketType) {
178 case SocketType.Stream: // ok
179 case SocketType.Unknown: // SocketException will be thrown later (with right error #)
182 throw new ArgumentException ("socketType");
185 switch (protocolType) {
186 case ProtocolType.Tcp: // ok
187 case ProtocolType.Unspecified: // ok
188 case ProtocolType.Unknown: // SocketException will be thrown later (with right error #)
191 throw new ArgumentException ("protocolType");
194 this.address_family = addressFamily;
195 this.socket_type = socketType;
196 this.protocol_type = protocolType;
199 var handle = Socket_internal (addressFamily, socketType, protocolType, out error);
201 this.safe_handle = new SafeSocketHandle (handle, true);
204 throw new SocketException (error);
206 #if !NET_2_1 || MOBILE
212 public Socket (SocketInformation socketInformation)
214 this.is_listening = (socketInformation.Options & SocketInformationOptions.Listening) != 0;
215 this.is_connected = (socketInformation.Options & SocketInformationOptions.Connected) != 0;
216 this.is_blocking = (socketInformation.Options & SocketInformationOptions.NonBlocking) == 0;
217 this.use_overlapped_io = (socketInformation.Options & SocketInformationOptions.UseOnlyOverlappedIO) != 0;
219 var result = Mono.DataConverter.Unpack ("iiiil", socketInformation.ProtocolInformation, 0);
221 this.address_family = (AddressFamily) (int) result [0];
222 this.socket_type = (SocketType) (int) result [1];
223 this.protocol_type = (ProtocolType) (int) result [2];
224 this.is_bound = (ProtocolType) (int) result [3] != 0;
225 this.safe_handle = new SafeSocketHandle ((IntPtr) (long) result [4], true);
231 /* private constructor used by Accept, which already has a socket handle to use */
232 internal Socket(AddressFamily family, SocketType type, ProtocolType proto, SafeSocketHandle safe_handle)
234 this.address_family = family;
235 this.socket_type = type;
236 this.protocol_type = proto;
238 this.safe_handle = safe_handle;
239 this.is_connected = true;
247 void SocketDefaults ()
250 /* Need to test IPv6 further */
251 if (address_family == AddressFamily.InterNetwork
252 // || address_family == AddressFamily.InterNetworkV6
254 /* This is the default, but it probably has nasty side
255 * effects on Linux, as the socket option is kludged by
256 * turning on or off PMTU discovery... */
257 this.DontFragment = false;
260 /* Microsoft sets these to 8192, but we are going to keep them
261 * both to the OS defaults as these have a big performance impact.
262 * on WebClient performance. */
263 // this.ReceiveBufferSize = 8192;
264 // this.SendBufferSize = 8192;
265 } catch (SocketException) {
269 /* Creates a new system socket, returning the handle */
270 [MethodImplAttribute(MethodImplOptions.InternalCall)]
271 extern IntPtr Socket_internal (AddressFamily family, SocketType type, ProtocolType proto, out int error);
277 public static bool SupportsIPv4 {
278 get { return ipv4_supported == 1; }
281 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
282 public static bool SupportsIPv6 {
283 get { return ipv6_supported == 1; }
287 public static bool OSSupportsIPv4 {
288 get { return ipv4_supported == 1; }
293 public static bool OSSupportsIPv6 {
294 get { return ipv6_supported == 1; }
297 public static bool OSSupportsIPv6 {
299 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
301 foreach (NetworkInterface adapter in nics) {
302 if (adapter.Supports (NetworkInterfaceComponent.IPv6))
311 public int Available {
313 ThrowIfDisposedAndClosed ();
316 ret = Available_internal (safe_handle, out error);
319 throw new SocketException (error);
325 static int Available_internal (SafeSocketHandle safeHandle, out int error)
327 bool release = false;
329 safeHandle.DangerousAddRef (ref release);
330 return Available_internal (safeHandle.DangerousGetHandle (), out error);
333 safeHandle.DangerousRelease ();
337 /* Returns the amount of data waiting to be read on socket */
338 [MethodImplAttribute(MethodImplOptions.InternalCall)]
339 extern static int Available_internal (IntPtr socket, out int error);
341 public bool DontFragment {
343 ThrowIfDisposedAndClosed ();
345 switch (address_family) {
346 case AddressFamily.InterNetwork:
347 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment)) != 0;
348 case AddressFamily.InterNetworkV6:
349 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment)) != 0;
351 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
355 ThrowIfDisposedAndClosed ();
357 switch (address_family) {
358 case AddressFamily.InterNetwork:
359 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
361 case AddressFamily.InterNetworkV6:
362 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment, value ? 1 : 0);
365 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
370 public bool EnableBroadcast {
372 ThrowIfDisposedAndClosed ();
374 if (protocol_type != ProtocolType.Udp)
375 throw new SocketException ((int) SocketError.ProtocolOption);
377 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0;
380 ThrowIfDisposedAndClosed ();
382 if (protocol_type != ProtocolType.Udp)
383 throw new SocketException ((int) SocketError.ProtocolOption);
385 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
389 public bool ExclusiveAddressUse {
391 ThrowIfDisposedAndClosed ();
393 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse)) != 0;
396 ThrowIfDisposedAndClosed ();
399 throw new InvalidOperationException ("Bind has already been called for this socket");
401 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
405 public bool IsBound {
411 public LingerOption LingerState {
413 ThrowIfDisposedAndClosed ();
415 return (LingerOption) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger);
418 ThrowIfDisposedAndClosed ();
419 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger, value);
423 public bool MulticastLoopback {
425 ThrowIfDisposedAndClosed ();
427 /* Even though this option can be set for TCP sockets on Linux, throw
428 * this exception anyway to be compatible (the MSDN docs say
429 * "Setting this property on a Transmission Control Protocol (TCP)
430 * socket will have no effect." but the MS runtime throws the
432 if (protocol_type == ProtocolType.Tcp)
433 throw new SocketException ((int)SocketError.ProtocolOption);
435 switch (address_family) {
436 case AddressFamily.InterNetwork:
437 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
438 case AddressFamily.InterNetworkV6:
439 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
441 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
445 ThrowIfDisposedAndClosed ();
447 /* Even though this option can be set for TCP sockets on Linux, throw
448 * this exception anyway to be compatible (the MSDN docs say
449 * "Setting this property on a Transmission Control Protocol (TCP)
450 * socket will have no effect." but the MS runtime throws the
452 if (protocol_type == ProtocolType.Tcp)
453 throw new SocketException ((int)SocketError.ProtocolOption);
455 switch (address_family) {
456 case AddressFamily.InterNetwork:
457 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
459 case AddressFamily.InterNetworkV6:
460 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
463 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
468 [MonoTODO ("This doesn't do anything on Mono yet")]
469 public bool UseOnlyOverlappedIO {
470 get { return use_overlapped_io; }
471 set { use_overlapped_io = value; }
474 public IntPtr Handle {
475 get { return safe_handle.DangerousGetHandle (); }
478 // Wish: support non-IP endpoints.
479 public EndPoint LocalEndPoint {
481 ThrowIfDisposedAndClosed ();
483 /* If the seed EndPoint is null, Connect, Bind, etc has not yet
484 * been called. MS returns null in this case. */
485 if (seed_endpoint == null)
489 SocketAddress sa = LocalEndPoint_internal (safe_handle, (int) address_family, out error);
492 throw new SocketException (error);
494 return seed_endpoint.Create (sa);
498 static SocketAddress LocalEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
500 bool release = false;
502 safeHandle.DangerousAddRef (ref release);
503 return LocalEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
506 safeHandle.DangerousRelease ();
510 /* Returns the local endpoint details in addr and port */
511 [MethodImplAttribute(MethodImplOptions.InternalCall)]
512 extern static SocketAddress LocalEndPoint_internal (IntPtr socket, int family, out int error);
514 public SocketType SocketType {
515 get { return socket_type; }
518 public int SendTimeout {
520 ThrowIfDisposedAndClosed ();
522 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
525 ThrowIfDisposedAndClosed ();
528 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
530 /* According to the MSDN docs we should adjust values between 1 and
531 * 499 to 500, but the MS runtime doesn't do this. */
535 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
539 public int ReceiveTimeout {
541 ThrowIfDisposedAndClosed ();
543 return (int) GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
546 ThrowIfDisposedAndClosed ();
549 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
554 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, value);
558 public AddressFamily AddressFamily {
559 get { return address_family; }
562 public bool Blocking {
563 get { return is_blocking; }
565 ThrowIfDisposedAndClosed ();
568 Blocking_internal (safe_handle, value, out error);
571 throw new SocketException (error);
577 static void Blocking_internal (SafeSocketHandle safeHandle, bool block, out int error)
579 bool release = false;
581 safeHandle.DangerousAddRef (ref release);
582 Blocking_internal (safeHandle.DangerousGetHandle (), block, out error);
585 safeHandle.DangerousRelease ();
589 [MethodImplAttribute(MethodImplOptions.InternalCall)]
590 internal extern static void Blocking_internal(IntPtr socket, bool block, out int error);
592 public bool Connected {
593 get { return is_connected; }
594 internal set { is_connected = value; }
597 public ProtocolType ProtocolType {
598 get { return protocol_type; }
601 public bool NoDelay {
603 ThrowIfDisposedAndClosed ();
606 return ((int) GetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay)) != 0;
610 ThrowIfDisposedAndClosed ();
613 SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
617 public int ReceiveBufferSize {
619 ThrowIfDisposedAndClosed ();
621 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer);
624 ThrowIfDisposedAndClosed ();
627 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
629 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
633 public int SendBufferSize {
635 ThrowIfDisposedAndClosed ();
637 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer);
640 ThrowIfDisposedAndClosed ();
643 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
645 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer, value);
651 ThrowIfDisposedAndClosed ();
653 switch (address_family) {
654 case AddressFamily.InterNetwork:
655 return (short) (int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
656 case AddressFamily.InterNetworkV6:
657 return (short) (int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit);
659 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
663 ThrowIfDisposedAndClosed ();
666 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
668 switch (address_family) {
669 case AddressFamily.InterNetwork:
670 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
672 case AddressFamily.InterNetworkV6:
673 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
676 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
681 public EndPoint RemoteEndPoint {
683 ThrowIfDisposedAndClosed ();
685 /* If the seed EndPoint is null, Connect, Bind, etc has
686 * not yet been called. MS returns null in this case. */
687 if (!is_connected || seed_endpoint == null)
691 SocketAddress sa = RemoteEndPoint_internal (safe_handle, (int) address_family, out error);
694 throw new SocketException (error);
696 return seed_endpoint.Create (sa);
700 static SocketAddress RemoteEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
702 bool release = false;
704 safeHandle.DangerousAddRef (ref release);
705 return RemoteEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
708 safeHandle.DangerousRelease ();
712 /* Returns the remote endpoint details in addr and port */
713 [MethodImplAttribute(MethodImplOptions.InternalCall)]
714 extern static SocketAddress RemoteEndPoint_internal (IntPtr socket, int family, out int error);
720 public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
722 var list = new List<Socket> ();
723 AddSockets (list, checkRead, "checkRead");
724 AddSockets (list, checkWrite, "checkWrite");
725 AddSockets (list, checkError, "checkError");
728 throw new ArgumentNullException ("checkRead, checkWrite, checkError", "All the lists are null or empty.");
730 /* The 'sockets' array contains:
731 * - READ socket 0-n, null,
732 * - WRITE socket 0-n, null,
733 * - ERROR socket 0-n, null */
734 Socket [] sockets = list.ToArray ();
737 Select_internal (ref sockets, microSeconds, out error);
740 throw new SocketException (error);
742 if (sockets == null) {
743 if (checkRead != null)
745 if (checkWrite != null)
747 if (checkError != null)
753 int count = sockets.Length;
754 IList currentList = checkRead;
756 for (int i = 0; i < count; i++) {
757 Socket sock = sockets [i];
758 if (sock == null) { // separator
759 if (currentList != null) {
760 // Remove non-signaled sockets after the current one
761 int to_remove = currentList.Count - currentIdx;
762 for (int k = 0; k < to_remove; k++)
763 currentList.RemoveAt (currentIdx);
765 currentList = (mode == 0) ? checkWrite : checkError;
771 if (mode == 1 && currentList == checkWrite && !sock.is_connected) {
772 if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
773 sock.is_connected = true;
776 /* Remove non-signaled sockets before the current one */
777 while (((Socket) currentList [currentIdx]) != sock)
778 currentList.RemoveAt (currentIdx);
784 static void AddSockets (List<Socket> sockets, IList list, string name)
787 foreach (Socket sock in list) {
788 if (sock == null) // MS throws a NullRef
789 throw new ArgumentNullException ("name", "Contains a null element");
797 [MethodImplAttribute(MethodImplOptions.InternalCall)]
798 extern static void Select_internal (ref Socket [] sockets, int microSeconds, out int error);
802 public bool AcceptAsync (SocketAsyncEventArgs e)
804 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
806 if (is_disposed && is_closed)
807 throw new ObjectDisposedException (GetType ().ToString ());
809 throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
811 throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
812 if (e.BufferList != null)
813 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
815 throw new ArgumentOutOfRangeException ("e.Count");
817 Socket acceptSocket = e.AcceptSocket;
818 if (acceptSocket != null) {
819 if (acceptSocket.IsBound || acceptSocket.Connected)
820 throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
824 SocketAsyncWorker w = e.Worker;
825 w.Init (this, e, SocketOperation.Accept);
828 readQ.Enqueue (e.Worker);
832 socket_pool_queue (SocketAsyncWorker.Dispatcher, w.result);
835 // Creates a new system socket, returning the handle
836 [MethodImplAttribute(MethodImplOptions.InternalCall)]
837 private extern static IntPtr Accept_internal(IntPtr sock, out int error, bool blocking);
839 private static SafeSocketHandle Accept_internal(SafeSocketHandle safeHandle, out int error, bool blocking)
842 safeHandle.RegisterForBlockingSyscall ();
843 var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
844 return new SafeSocketHandle (ret, true);
846 safeHandle.UnRegisterForBlockingSyscall ();
850 public Socket Accept() {
851 if (is_disposed && is_closed)
852 throw new ObjectDisposedException (GetType ().ToString ());
855 var sock = Accept_internal(safe_handle, out error, is_blocking);
859 error = SOCKET_CLOSED_CODE;
860 throw new SocketException(error);
863 Socket accepted = new Socket(this.AddressFamily, this.SocketType,
864 this.ProtocolType, sock);
866 accepted.seed_endpoint = this.seed_endpoint;
867 accepted.Blocking = this.Blocking;
871 internal void Accept (Socket acceptSocket)
873 if (is_disposed && is_closed)
874 throw new ObjectDisposedException (GetType ().ToString ());
877 var sock = Accept_internal (safe_handle, out error, is_blocking);
881 error = SOCKET_CLOSED_CODE;
882 throw new SocketException (error);
885 acceptSocket.address_family = this.AddressFamily;
886 acceptSocket.socket_type = this.SocketType;
887 acceptSocket.protocol_type = this.ProtocolType;
888 acceptSocket.safe_handle = sock;
889 acceptSocket.is_connected = true;
890 acceptSocket.seed_endpoint = this.seed_endpoint;
891 acceptSocket.Blocking = this.Blocking;
893 /* FIXME: figure out what if anything else
898 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
900 if (is_disposed && is_closed)
901 throw new ObjectDisposedException (GetType ().ToString ());
903 if (!is_bound || !is_listening)
904 throw new InvalidOperationException ();
906 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Accept);
909 readQ.Enqueue (req.Worker);
913 socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
917 public IAsyncResult BeginAccept (int receiveSize,
918 AsyncCallback callback,
921 if (is_disposed && is_closed)
922 throw new ObjectDisposedException (GetType ().ToString ());
925 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
927 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive);
928 req.Buffer = new byte[receiveSize];
930 req.Size = receiveSize;
931 req.SockFlags = SocketFlags.None;
934 readQ.Enqueue (req.Worker);
938 socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
942 public IAsyncResult BeginAccept (Socket acceptSocket,
944 AsyncCallback callback,
947 if (is_disposed && is_closed)
948 throw new ObjectDisposedException (GetType ().ToString ());
951 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
953 if (acceptSocket != null) {
954 if (acceptSocket.is_disposed && acceptSocket.is_closed)
955 throw new ObjectDisposedException (acceptSocket.GetType ().ToString ());
957 if (acceptSocket.IsBound)
958 throw new InvalidOperationException ();
960 /* For some reason the MS runtime
961 * barfs if the new socket is not TCP,
962 * even though it's just about to blow
963 * away all those parameters
965 if (acceptSocket.ProtocolType != ProtocolType.Tcp)
966 throw new SocketException ((int)SocketError.InvalidArgument);
969 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive);
970 req.Buffer = new byte[receiveSize];
972 req.Size = receiveSize;
973 req.SockFlags = SocketFlags.None;
974 req.AcceptSocket = acceptSocket;
977 readQ.Enqueue (req.Worker);
981 socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
985 public IAsyncResult BeginConnect (IPAddress address, int port,
986 AsyncCallback callback,
989 if (is_disposed && is_closed)
990 throw new ObjectDisposedException (GetType ().ToString ());
993 throw new ArgumentNullException ("address");
995 if (address.ToString ().Length == 0)
996 throw new ArgumentException ("The length of the IP address is zero");
998 if (port <= 0 || port > 65535)
999 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1002 throw new InvalidOperationException ();
1004 IPEndPoint iep = new IPEndPoint (address, port);
1005 return(BeginConnect (iep, callback, state));
1008 public IAsyncResult BeginConnect (string host, int port,
1009 AsyncCallback callback,
1012 if (is_disposed && is_closed)
1013 throw new ObjectDisposedException (GetType ().ToString ());
1016 throw new ArgumentNullException ("host");
1018 if (address_family != AddressFamily.InterNetwork &&
1019 address_family != AddressFamily.InterNetworkV6)
1020 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1022 if (port <= 0 || port > 65535)
1023 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1026 throw new InvalidOperationException ();
1028 return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1031 public IAsyncResult BeginDisconnect (bool reuseSocket,
1032 AsyncCallback callback,
1035 if (is_disposed && is_closed)
1036 throw new ObjectDisposedException (GetType ().ToString ());
1038 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Disconnect);
1039 req.ReuseSocket = reuseSocket;
1040 socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
1044 void CheckRange (byte[] buffer, int offset, int size)
1047 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
1049 if (offset > buffer.Length)
1050 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
1053 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
1055 if (size > buffer.Length - offset)
1056 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
1059 public IAsyncResult BeginReceive(byte[] buffer, int offset,
1061 SocketFlags socket_flags,
1062 AsyncCallback callback,
1065 if (is_disposed && is_closed)
1066 throw new ObjectDisposedException (GetType ().ToString ());
1069 throw new ArgumentNullException ("buffer");
1071 CheckRange (buffer, offset, size);
1073 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Receive);
1074 req.Buffer = buffer;
1075 req.Offset = offset;
1077 req.SockFlags = socket_flags;
1080 readQ.Enqueue (req.Worker);
1081 count = readQ.Count;
1084 socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
1088 public IAsyncResult BeginReceive (byte[] buffer, int offset,
1089 int size, SocketFlags flags,
1090 out SocketError error,
1091 AsyncCallback callback,
1094 /* As far as I can tell from the docs and from
1095 * experimentation, a pointer to the
1096 * SocketError parameter is not supposed to be
1097 * saved for the async parts. And as we don't
1098 * set any socket errors in the setup code, we
1099 * just have to set it to Success.
1101 error = SocketError.Success;
1102 return (BeginReceive (buffer, offset, size, flags, callback, state));
1105 [CLSCompliant (false)]
1106 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers,
1107 SocketFlags socketFlags,
1108 AsyncCallback callback,
1111 if (is_disposed && is_closed)
1112 throw new ObjectDisposedException (GetType ().ToString ());
1114 if (buffers == null)
1115 throw new ArgumentNullException ("buffers");
1117 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveGeneric);
1118 req.Buffers = buffers;
1119 req.SockFlags = socketFlags;
1122 readQ.Enqueue (req.Worker);
1123 count = readQ.Count;
1126 socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
1130 [CLSCompliant (false)]
1131 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers,
1132 SocketFlags socketFlags,
1133 out SocketError errorCode,
1134 AsyncCallback callback,
1137 /* I assume the same SocketError semantics as
1140 errorCode = SocketError.Success;
1141 return (BeginReceive (buffers, socketFlags, callback, state));
1144 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
1146 SocketFlags socket_flags,
1147 ref EndPoint remote_end,
1148 AsyncCallback callback,
1150 if (is_disposed && is_closed)
1151 throw new ObjectDisposedException (GetType ().ToString ());
1154 throw new ArgumentNullException ("buffer");
1156 if (remote_end == null)
1157 throw new ArgumentNullException ("remote_end");
1159 CheckRange (buffer, offset, size);
1161 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveFrom);
1162 req.Buffer = buffer;
1163 req.Offset = offset;
1165 req.SockFlags = socket_flags;
1166 req.EndPoint = remote_end;
1169 readQ.Enqueue (req.Worker);
1170 count = readQ.Count;
1173 socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
1178 public IAsyncResult BeginReceiveMessageFrom (
1179 byte[] buffer, int offset, int size,
1180 SocketFlags socketFlags, ref EndPoint remoteEP,
1181 AsyncCallback callback, object state)
1183 if (is_disposed && is_closed)
1184 throw new ObjectDisposedException (GetType ().ToString ());
1187 throw new ArgumentNullException ("buffer");
1189 if (remoteEP == null)
1190 throw new ArgumentNullException ("remoteEP");
1192 CheckRange (buffer, offset, size);
1194 throw new NotImplementedException ();
1197 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags,
1198 AsyncCallback callback, object state)
1200 if (is_disposed && is_closed)
1201 throw new ObjectDisposedException (GetType ().ToString ());
1204 throw new ArgumentNullException ("buffer");
1206 CheckRange (buffer, offset, size);
1209 throw new SocketException ((int)SocketError.NotConnected);
1211 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Send);
1212 req.Buffer = buffer;
1213 req.Offset = offset;
1215 req.SockFlags = socket_flags;
1218 writeQ.Enqueue (req.Worker);
1219 count = writeQ.Count;
1222 socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
1226 public IAsyncResult BeginSend (byte[] buffer, int offset,
1228 SocketFlags socketFlags,
1229 out SocketError errorCode,
1230 AsyncCallback callback,
1233 if (!is_connected) {
1234 errorCode = SocketError.NotConnected;
1235 throw new SocketException ((int)errorCode);
1238 errorCode = SocketError.Success;
1240 return (BeginSend (buffer, offset, size, socketFlags, callback,
1244 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers,
1245 SocketFlags socketFlags,
1246 AsyncCallback callback,
1249 if (is_disposed && is_closed)
1250 throw new ObjectDisposedException (GetType ().ToString ());
1252 if (buffers == null)
1253 throw new ArgumentNullException ("buffers");
1256 throw new SocketException ((int)SocketError.NotConnected);
1258 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.SendGeneric);
1259 req.Buffers = buffers;
1260 req.SockFlags = socketFlags;
1263 writeQ.Enqueue (req.Worker);
1264 count = writeQ.Count;
1267 socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
1271 [CLSCompliant (false)]
1272 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers,
1273 SocketFlags socketFlags,
1274 out SocketError errorCode,
1275 AsyncCallback callback,
1278 if (!is_connected) {
1279 errorCode = SocketError.NotConnected;
1280 throw new SocketException ((int)errorCode);
1283 errorCode = SocketError.Success;
1284 return (BeginSend (buffers, socketFlags, callback, state));
1287 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
1289 sealed class SendFileAsyncResult : IAsyncResult {
1293 public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
1299 public object AsyncState {
1300 get { return ares.AsyncState; }
1303 public WaitHandle AsyncWaitHandle {
1304 get { return ares.AsyncWaitHandle; }
1307 public bool CompletedSynchronously {
1308 get { return ares.CompletedSynchronously; }
1311 public bool IsCompleted {
1312 get { return ares.IsCompleted; }
1315 public SendFileHandler Delegate {
1319 public IAsyncResult Original {
1320 get { return ares; }
1324 public IAsyncResult BeginSendFile (string fileName,
1325 AsyncCallback callback,
1328 if (is_disposed && is_closed)
1329 throw new ObjectDisposedException (GetType ().ToString ());
1332 throw new NotSupportedException ();
1334 if (!File.Exists (fileName))
1335 throw new FileNotFoundException ();
1337 return BeginSendFile (fileName, null, null, 0, callback, state);
1340 public IAsyncResult BeginSendFile (string fileName,
1343 TransmitFileOptions flags,
1344 AsyncCallback callback,
1347 if (is_disposed && is_closed)
1348 throw new ObjectDisposedException (GetType ().ToString ());
1351 throw new NotSupportedException ();
1353 if (!File.Exists (fileName))
1354 throw new FileNotFoundException ();
1356 SendFileHandler d = new SendFileHandler (SendFile);
1357 return new SendFileAsyncResult (d, d.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => {
1358 SendFileAsyncResult sfar = new SendFileAsyncResult (d, ar);
1363 public IAsyncResult BeginSendTo(byte[] buffer, int offset,
1365 SocketFlags socket_flags,
1366 EndPoint remote_end,
1367 AsyncCallback callback,
1369 if (is_disposed && is_closed)
1370 throw new ObjectDisposedException (GetType ().ToString ());
1373 throw new ArgumentNullException ("buffer");
1375 CheckRange (buffer, offset, size);
1377 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.SendTo);
1378 req.Buffer = buffer;
1379 req.Offset = offset;
1381 req.SockFlags = socket_flags;
1382 req.EndPoint = remote_end;
1385 writeQ.Enqueue (req.Worker);
1386 count = writeQ.Count;
1389 socket_pool_queue (SocketAsyncWorker.Dispatcher, req);
1393 // Creates a new system socket, returning the handle
1394 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1395 private extern static void Bind_internal(IntPtr sock,
1399 private static void Bind_internal (SafeSocketHandle safeHandle,
1403 bool release = false;
1405 safeHandle.DangerousAddRef (ref release);
1406 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
1409 safeHandle.DangerousRelease ();
1413 public void Bind(EndPoint local_end) {
1414 if (is_disposed && is_closed)
1415 throw new ObjectDisposedException (GetType ().ToString ());
1417 if (local_end == null)
1418 throw new ArgumentNullException("local_end");
1422 Bind_internal (safe_handle, local_end.Serialize(), out error);
1424 throw new SocketException (error);
1428 seed_endpoint = local_end;
1431 public void Connect (IPAddress address, int port)
1433 Connect (new IPEndPoint (address, port));
1436 public void Connect (IPAddress[] addresses, int port)
1438 if (is_disposed && is_closed)
1439 throw new ObjectDisposedException (GetType ().ToString ());
1441 if (addresses == null)
1442 throw new ArgumentNullException ("addresses");
1444 if (this.AddressFamily != AddressFamily.InterNetwork &&
1445 this.AddressFamily != AddressFamily.InterNetworkV6)
1446 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1449 throw new InvalidOperationException ();
1451 /* FIXME: do non-blocking sockets Poll here? */
1453 foreach (IPAddress address in addresses) {
1454 IPEndPoint iep = new IPEndPoint (address, port);
1455 SocketAddress serial = iep.Serialize ();
1457 Connect_internal (safe_handle, serial, out error);
1459 is_connected = true;
1461 seed_endpoint = iep;
1463 } else if (error != (int)SocketError.InProgress &&
1464 error != (int)SocketError.WouldBlock) {
1469 Poll (-1, SelectMode.SelectWrite);
1470 error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1472 is_connected = true;
1474 seed_endpoint = iep;
1480 throw new SocketException (error);
1483 public void Connect (string host, int port)
1485 IPAddress [] addresses = Dns.GetHostAddresses (host);
1486 Connect (addresses, port);
1489 public bool DisconnectAsync (SocketAsyncEventArgs e)
1491 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1492 if (is_disposed && is_closed)
1493 throw new ObjectDisposedException (GetType ().ToString ());
1496 e.Worker.Init (this, e, SocketOperation.Disconnect);
1497 socket_pool_queue (SocketAsyncWorker.Dispatcher, e.Worker.result);
1501 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1502 extern static void Disconnect_internal(IntPtr sock, bool reuse, out int error);
1504 private static void Disconnect_internal(SafeSocketHandle safeHandle, bool reuse, out int error)
1506 bool release = false;
1508 safeHandle.DangerousAddRef (ref release);
1509 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1512 safeHandle.DangerousRelease ();
1516 /* According to the docs, the MS runtime will throw
1517 * PlatformNotSupportedException if the platform is
1518 * newer than w2k. We should be able to cope...
1520 public void Disconnect (bool reuseSocket)
1522 if (is_disposed && is_closed)
1523 throw new ObjectDisposedException (GetType ().ToString ());
1527 Disconnect_internal (safe_handle, reuseSocket, out error);
1531 /* ERROR_NOT_SUPPORTED */
1532 throw new PlatformNotSupportedException ();
1534 throw new SocketException (error);
1538 is_connected = false;
1541 /* Do managed housekeeping here... */
1546 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
1547 public SocketInformation DuplicateAndClose (int targetProcessId)
1549 var si = new SocketInformation ();
1551 (is_listening ? SocketInformationOptions.Listening : 0) |
1552 (is_connected ? SocketInformationOptions.Connected : 0) |
1553 (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
1554 (use_overlapped_io ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
1556 si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, is_bound ? 1 : 0, (long)Handle);
1563 public Socket EndAccept (IAsyncResult result)
1568 return(EndAccept (out buffer, out bytes, result));
1571 public Socket EndAccept (out byte[] buffer, IAsyncResult asyncResult)
1574 return(EndAccept (out buffer, out bytes, asyncResult));
1577 public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
1579 if (is_disposed && is_closed)
1580 throw new ObjectDisposedException (GetType ().ToString ());
1582 if (asyncResult == null)
1583 throw new ArgumentNullException ("asyncResult");
1585 SocketAsyncResult req = asyncResult as SocketAsyncResult;
1587 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
1589 if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1590 throw InvalidAsyncOp ("EndAccept");
1591 if (!asyncResult.IsCompleted)
1592 asyncResult.AsyncWaitHandle.WaitOne ();
1594 req.CheckIfThrowDelayedException ();
1596 buffer = req.Buffer;
1597 bytesTransferred = req.Total;
1602 public void EndConnect (IAsyncResult result)
1604 if (is_disposed && is_closed)
1605 throw new ObjectDisposedException (GetType ().ToString ());
1608 throw new ArgumentNullException ("result");
1610 SocketAsyncResult req = result as SocketAsyncResult;
1612 throw new ArgumentException ("Invalid IAsyncResult", "result");
1614 if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1615 throw InvalidAsyncOp ("EndConnect");
1616 if (!result.IsCompleted)
1617 result.AsyncWaitHandle.WaitOne();
1619 req.CheckIfThrowDelayedException();
1622 public void EndDisconnect (IAsyncResult asyncResult)
1624 if (is_disposed && is_closed)
1625 throw new ObjectDisposedException (GetType ().ToString ());
1627 if (asyncResult == null)
1628 throw new ArgumentNullException ("asyncResult");
1630 SocketAsyncResult req = asyncResult as SocketAsyncResult;
1632 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
1634 if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1635 throw InvalidAsyncOp ("EndDisconnect");
1636 if (!asyncResult.IsCompleted)
1637 asyncResult.AsyncWaitHandle.WaitOne ();
1639 req.CheckIfThrowDelayedException ();
1643 public int EndReceiveMessageFrom (IAsyncResult asyncResult,
1644 ref SocketFlags socketFlags,
1645 ref EndPoint endPoint,
1646 out IPPacketInformation ipPacketInformation)
1648 if (is_disposed && is_closed)
1649 throw new ObjectDisposedException (GetType ().ToString ());
1651 if (asyncResult == null)
1652 throw new ArgumentNullException ("asyncResult");
1654 if (endPoint == null)
1655 throw new ArgumentNullException ("endPoint");
1657 SocketAsyncResult req = asyncResult as SocketAsyncResult;
1659 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
1661 if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1662 throw InvalidAsyncOp ("EndReceiveMessageFrom");
1663 throw new NotImplementedException ();
1666 public void EndSendFile (IAsyncResult asyncResult)
1668 if (is_disposed && is_closed)
1669 throw new ObjectDisposedException (GetType ().ToString ());
1671 if (asyncResult == null)
1672 throw new ArgumentNullException ("asyncResult");
1674 SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
1676 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
1678 ares.Delegate.EndInvoke (ares.Original);
1681 public int EndSendTo (IAsyncResult result)
1683 if (is_disposed && is_closed)
1684 throw new ObjectDisposedException (GetType ().ToString ());
1687 throw new ArgumentNullException ("result");
1689 SocketAsyncResult req = result as SocketAsyncResult;
1691 throw new ArgumentException ("Invalid IAsyncResult", "result");
1693 if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1694 throw InvalidAsyncOp ("EndSendTo");
1695 if (!result.IsCompleted)
1696 result.AsyncWaitHandle.WaitOne();
1698 req.CheckIfThrowDelayedException();
1702 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1703 private extern static void GetSocketOption_arr_internal(IntPtr socket,
1704 SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val,
1707 private static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle,
1708 SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val,
1711 bool release = false;
1713 safeHandle.DangerousAddRef (ref release);
1714 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
1717 safeHandle.DangerousRelease ();
1721 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
1723 if (is_disposed && is_closed)
1724 throw new ObjectDisposedException (GetType ().ToString ());
1726 if (optionValue == null)
1727 throw new SocketException ((int) SocketError.Fault,
1728 "Error trying to dereference an invalid pointer");
1732 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref optionValue,
1735 throw new SocketException (error);
1738 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int length)
1740 if (is_disposed && is_closed)
1741 throw new ObjectDisposedException (GetType ().ToString ());
1743 byte[] byte_val=new byte[length];
1746 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref byte_val,
1749 throw new SocketException (error);
1754 // See Socket.IOControl, WSAIoctl documentation in MSDN. The
1755 // common options between UNIX and Winsock are FIONREAD,
1756 // FIONBIO and SIOCATMARK. Anything else will depend on the
1757 // system except SIO_KEEPALIVE_VALS which is properly handled
1758 // on both windows and linux.
1759 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1760 extern static int WSAIoctl (IntPtr sock, int ioctl_code, byte [] input,
1761 byte [] output, out int error);
1763 private static int WSAIoctl (SafeSocketHandle safeHandle, int ioctl_code, byte [] input,
1764 byte [] output, out int error)
1766 bool release = false;
1768 safeHandle.DangerousAddRef (ref release);
1769 return WSAIoctl (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
1772 safeHandle.DangerousRelease ();
1776 public int IOControl (int ioctl_code, byte [] in_value, byte [] out_value)
1779 throw new ObjectDisposedException (GetType ().ToString ());
1782 int result = WSAIoctl (safe_handle, ioctl_code, in_value, out_value,
1786 throw new SocketException (error);
1789 throw new InvalidOperationException ("Must use Blocking property instead.");
1794 public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
1796 return IOControl ((int) ioControlCode, optionInValue, optionOutValue);
1799 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1800 private extern static void Listen_internal(IntPtr sock, int backlog, out int error);
1802 private static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
1804 bool release = false;
1806 safeHandle.DangerousAddRef (ref release);
1807 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
1810 safeHandle.DangerousRelease ();
1814 public void Listen (int backlog)
1816 if (is_disposed && is_closed)
1817 throw new ObjectDisposedException (GetType ().ToString ());
1820 throw new SocketException ((int)SocketError.InvalidArgument);
1823 Listen_internal(safe_handle, backlog, out error);
1826 throw new SocketException (error);
1828 is_listening = true;
1831 public bool Poll (int time_us, SelectMode mode)
1833 if (is_disposed && is_closed)
1834 throw new ObjectDisposedException (GetType ().ToString ());
1836 if (mode != SelectMode.SelectRead &&
1837 mode != SelectMode.SelectWrite &&
1838 mode != SelectMode.SelectError)
1839 throw new NotSupportedException ("'mode' parameter is not valid.");
1842 bool result = Poll_internal (safe_handle, mode, time_us, out error);
1844 throw new SocketException (error);
1846 if (mode == SelectMode.SelectWrite && result && !is_connected) {
1847 /* Update the is_connected state; for
1848 * non-blocking Connect()s this is
1849 * when we can find out that the
1850 * connect succeeded.
1852 if ((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0) {
1853 is_connected = true;
1860 public int Receive (byte [] buffer)
1862 return Receive (buffer, SocketFlags.None);
1865 public int Receive (byte [] buffer, SocketFlags flags)
1867 if (is_disposed && is_closed)
1868 throw new ObjectDisposedException (GetType ().ToString ());
1871 throw new ArgumentNullException ("buffer");
1875 int ret = Receive_nochecks (buffer, 0, buffer.Length, flags, out error);
1877 if (error != SocketError.Success) {
1878 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1879 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1880 throw new SocketException ((int) error);
1886 public int Receive (byte [] buffer, int size, SocketFlags flags)
1888 if (is_disposed && is_closed)
1889 throw new ObjectDisposedException (GetType ().ToString ());
1892 throw new ArgumentNullException ("buffer");
1894 CheckRange (buffer, 0, size);
1898 int ret = Receive_nochecks (buffer, 0, size, flags, out error);
1900 if (error != SocketError.Success) {
1901 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1902 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1903 throw new SocketException ((int) error);
1909 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags)
1911 if (is_disposed && is_closed)
1912 throw new ObjectDisposedException (GetType ().ToString ());
1915 throw new ArgumentNullException ("buffer");
1917 CheckRange (buffer, offset, size);
1921 int ret = Receive_nochecks (buffer, offset, size, flags, out error);
1923 if (error != SocketError.Success) {
1924 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1925 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1926 throw new SocketException ((int) error);
1932 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
1934 if (is_disposed && is_closed)
1935 throw new ObjectDisposedException (GetType ().ToString ());
1938 throw new ArgumentNullException ("buffer");
1940 CheckRange (buffer, offset, size);
1942 return Receive_nochecks (buffer, offset, size, flags, out error);
1945 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
1947 if (is_disposed && is_closed)
1948 throw new ObjectDisposedException (GetType ().ToString ());
1950 // We do not support recv into multiple buffers yet
1951 if (e.BufferList != null)
1952 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
1953 if (e.RemoteEndPoint == null)
1954 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
1957 e.Worker.Init (this, e, SocketOperation.ReceiveFrom);
1958 SocketAsyncResult res = e.Worker.result;
1959 res.Buffer = e.Buffer;
1960 res.Offset = e.Offset;
1962 res.EndPoint = e.RemoteEndPoint;
1963 res.SockFlags = e.SocketFlags;
1966 readQ.Enqueue (e.Worker);
1967 count = readQ.Count;
1970 socket_pool_queue (SocketAsyncWorker.Dispatcher, res);
1974 public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
1976 if (is_disposed && is_closed)
1977 throw new ObjectDisposedException (GetType ().ToString ());
1980 throw new ArgumentNullException ("buffer");
1982 if (remoteEP == null)
1983 throw new ArgumentNullException ("remoteEP");
1985 return ReceiveFrom_nochecks (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
1988 public int ReceiveFrom (byte [] buffer, SocketFlags flags, ref EndPoint remoteEP)
1990 if (is_disposed && is_closed)
1991 throw new ObjectDisposedException (GetType ().ToString ());
1994 throw new ArgumentNullException ("buffer");
1996 if (remoteEP == null)
1997 throw new ArgumentNullException ("remoteEP");
1999 return ReceiveFrom_nochecks (buffer, 0, buffer.Length, flags, ref remoteEP);
2002 public int ReceiveFrom (byte [] buffer, int size, SocketFlags flags,
2003 ref EndPoint remoteEP)
2005 if (is_disposed && is_closed)
2006 throw new ObjectDisposedException (GetType ().ToString ());
2009 throw new ArgumentNullException ("buffer");
2011 if (remoteEP == null)
2012 throw new ArgumentNullException ("remoteEP");
2014 if (size < 0 || size > buffer.Length)
2015 throw new ArgumentOutOfRangeException ("size");
2017 return ReceiveFrom_nochecks (buffer, 0, size, flags, ref remoteEP);
2020 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2021 private extern static int RecvFrom_internal(IntPtr sock,
2026 ref SocketAddress sockaddr,
2029 private static int RecvFrom_internal (SafeSocketHandle safeHandle,
2034 ref SocketAddress sockaddr,
2038 safeHandle.RegisterForBlockingSyscall ();
2039 return RecvFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
2041 safeHandle.UnRegisterForBlockingSyscall ();
2045 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags flags,
2046 ref EndPoint remoteEP)
2048 if (is_disposed && is_closed)
2049 throw new ObjectDisposedException (GetType ().ToString ());
2052 throw new ArgumentNullException ("buffer");
2054 if (remoteEP == null)
2055 throw new ArgumentNullException ("remoteEP");
2057 CheckRange (buffer, offset, size);
2059 return ReceiveFrom_nochecks (buffer, offset, size, flags, ref remoteEP);
2062 internal int ReceiveFrom_nochecks (byte [] buf, int offset, int size, SocketFlags flags,
2063 ref EndPoint remote_end)
2066 return ReceiveFrom_nochecks_exc (buf, offset, size, flags, ref remote_end, true, out error);
2069 internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags,
2070 ref EndPoint remote_end, bool throwOnError, out int error)
2072 SocketAddress sockaddr = remote_end.Serialize();
2073 int cnt = RecvFrom_internal (safe_handle, buf, offset, size, flags, ref sockaddr, out error);
2074 SocketError err = (SocketError) error;
2076 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2077 is_connected = false;
2078 else if (err == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
2080 throw new SocketException ((int) SocketError.TimedOut, TIMEOUT_EXCEPTION_MSG);
2081 error = (int) SocketError.TimedOut;
2086 throw new SocketException (error);
2090 is_connected = true;
2093 // If sockaddr is null then we're a connection
2094 // oriented protocol and should ignore the
2095 // remote_end parameter (see MSDN
2096 // documentation for Socket.ReceiveFrom(...) )
2098 if ( sockaddr != null ) {
2099 // Stupidly, EndPoint.Create() is an
2101 remote_end = remote_end.Create (sockaddr);
2104 seed_endpoint = remote_end;
2109 [MonoTODO ("Not implemented")]
2110 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
2112 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2113 if (is_disposed && is_closed)
2114 throw new ObjectDisposedException (GetType ().ToString ());
2116 throw new NotImplementedException ();
2119 [MonoTODO ("Not implemented")]
2120 public int ReceiveMessageFrom (byte[] buffer, int offset,
2122 ref SocketFlags socketFlags,
2123 ref EndPoint remoteEP,
2124 out IPPacketInformation ipPacketInformation)
2126 if (is_disposed && is_closed)
2127 throw new ObjectDisposedException (GetType ().ToString ());
2130 throw new ArgumentNullException ("buffer");
2132 if (remoteEP == null)
2133 throw new ArgumentNullException ("remoteEP");
2135 CheckRange (buffer, offset, size);
2137 /* FIXME: figure out how we get hold of the
2138 * IPPacketInformation
2140 throw new NotImplementedException ();
2143 [MonoTODO ("Not implemented")]
2144 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2146 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2148 if (is_disposed && is_closed)
2149 throw new ObjectDisposedException (GetType ().ToString ());
2151 throw new NotImplementedException ();
2154 public int Send (byte [] buf)
2156 if (is_disposed && is_closed)
2157 throw new ObjectDisposedException (GetType ().ToString ());
2160 throw new ArgumentNullException ("buf");
2164 int ret = Send_nochecks (buf, 0, buf.Length, SocketFlags.None, out error);
2166 if (error != SocketError.Success)
2167 throw new SocketException ((int) error);
2172 public int Send (byte [] buf, SocketFlags flags)
2174 if (is_disposed && is_closed)
2175 throw new ObjectDisposedException (GetType ().ToString ());
2178 throw new ArgumentNullException ("buf");
2182 int ret = Send_nochecks (buf, 0, buf.Length, flags, out error);
2184 if (error != SocketError.Success)
2185 throw new SocketException ((int) error);
2190 public int Send (byte [] buf, int size, SocketFlags flags)
2192 if (is_disposed && is_closed)
2193 throw new ObjectDisposedException (GetType ().ToString ());
2196 throw new ArgumentNullException ("buf");
2198 CheckRange (buf, 0, size);
2202 int ret = Send_nochecks (buf, 0, size, flags, out error);
2204 if (error != SocketError.Success)
2205 throw new SocketException ((int) error);
2210 public int Send (byte [] buf, int offset, int size, SocketFlags flags)
2212 if (is_disposed && is_closed)
2213 throw new ObjectDisposedException (GetType ().ToString ());
2216 throw new ArgumentNullException ("buffer");
2218 CheckRange (buf, offset, size);
2222 int ret = Send_nochecks (buf, offset, size, flags, out error);
2224 if (error != SocketError.Success)
2225 throw new SocketException ((int) error);
2230 public int Send (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2232 if (is_disposed && is_closed)
2233 throw new ObjectDisposedException (GetType ().ToString ());
2236 throw new ArgumentNullException ("buffer");
2238 CheckRange (buf, offset, size);
2240 return Send_nochecks (buf, offset, size, flags, out error);
2243 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2244 private extern static bool SendFile (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
2246 private static bool SendFile (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
2249 safeHandle.RegisterForBlockingSyscall ();
2250 return SendFile (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
2252 safeHandle.UnRegisterForBlockingSyscall ();
2256 public void SendFile (string fileName)
2258 if (is_disposed && is_closed)
2259 throw new ObjectDisposedException (GetType ().ToString ());
2262 throw new NotSupportedException ();
2265 throw new InvalidOperationException ();
2267 SendFile (fileName, null, null, 0);
2270 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2272 if (is_disposed && is_closed)
2273 throw new ObjectDisposedException (GetType ().ToString ());
2276 throw new NotSupportedException ();
2279 throw new InvalidOperationException ();
2281 if (!SendFile (safe_handle, fileName, preBuffer, postBuffer, flags)) {
2282 SocketException exc = new SocketException ();
2283 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2284 throw new FileNotFoundException ();
2289 public bool SendToAsync (SocketAsyncEventArgs e)
2291 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2293 if (is_disposed && is_closed)
2294 throw new ObjectDisposedException (GetType ().ToString ());
2295 if (e.BufferList != null)
2296 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2297 if (e.RemoteEndPoint == null)
2298 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2301 e.Worker.Init (this, e, SocketOperation.SendTo);
2302 SocketAsyncResult res = e.Worker.result;
2303 res.Buffer = e.Buffer;
2304 res.Offset = e.Offset;
2306 res.SockFlags = e.SocketFlags;
2307 res.EndPoint = e.RemoteEndPoint;
2310 writeQ.Enqueue (e.Worker);
2311 count = writeQ.Count;
2314 socket_pool_queue (SocketAsyncWorker.Dispatcher, res);
2318 public int SendTo (byte [] buffer, EndPoint remote_end)
2320 if (is_disposed && is_closed)
2321 throw new ObjectDisposedException (GetType ().ToString ());
2324 throw new ArgumentNullException ("buffer");
2326 if (remote_end == null)
2327 throw new ArgumentNullException ("remote_end");
2329 return SendTo_nochecks (buffer, 0, buffer.Length, SocketFlags.None, remote_end);
2332 public int SendTo (byte [] buffer, SocketFlags flags, EndPoint remote_end)
2334 if (is_disposed && is_closed)
2335 throw new ObjectDisposedException (GetType ().ToString ());
2338 throw new ArgumentNullException ("buffer");
2340 if (remote_end == null)
2341 throw new ArgumentNullException ("remote_end");
2343 return SendTo_nochecks (buffer, 0, buffer.Length, flags, remote_end);
2346 public int SendTo (byte [] buffer, int size, SocketFlags flags, EndPoint remote_end)
2348 if (is_disposed && is_closed)
2349 throw new ObjectDisposedException (GetType ().ToString ());
2352 throw new ArgumentNullException ("buffer");
2354 if (remote_end == null)
2355 throw new ArgumentNullException ("remote_end");
2357 CheckRange (buffer, 0, size);
2359 return SendTo_nochecks (buffer, 0, size, flags, remote_end);
2362 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2363 private extern static int SendTo_internal(IntPtr sock,
2371 private static int SendTo_internal (SafeSocketHandle safeHandle,
2380 safeHandle.RegisterForBlockingSyscall ();
2381 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
2383 safeHandle.UnRegisterForBlockingSyscall ();
2387 public int SendTo (byte [] buffer, int offset, int size, SocketFlags flags,
2388 EndPoint remote_end)
2390 if (is_disposed && is_closed)
2391 throw new ObjectDisposedException (GetType ().ToString ());
2394 throw new ArgumentNullException ("buffer");
2396 if (remote_end == null)
2397 throw new ArgumentNullException("remote_end");
2399 CheckRange (buffer, offset, size);
2401 return SendTo_nochecks (buffer, offset, size, flags, remote_end);
2404 internal int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags,
2405 EndPoint remote_end)
2407 SocketAddress sockaddr = remote_end.Serialize ();
2411 ret = SendTo_internal (safe_handle, buffer, offset, size, flags, sockaddr, out error);
2413 SocketError err = (SocketError) error;
2415 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2416 is_connected = false;
2418 throw new SocketException (error);
2421 is_connected = true;
2423 seed_endpoint = remote_end;
2428 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2430 if (is_disposed && is_closed)
2431 throw new ObjectDisposedException (GetType ().ToString ());
2433 // I'd throw an ArgumentNullException, but this is what MS does.
2434 if (optionValue == null)
2435 throw new SocketException ((int) SocketError.Fault,
2436 "Error trying to dereference an invalid pointer");
2440 SetSocketOption_internal (safe_handle, optionLevel, optionName, null,
2441 optionValue, 0, out error);
2444 if (error == (int) SocketError.InvalidArgument)
2445 throw new ArgumentException ();
2446 throw new SocketException (error);
2450 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
2452 if (is_disposed && is_closed)
2453 throw new ObjectDisposedException (GetType ().ToString ());
2455 // NOTE: if a null is passed, the byte[] overload is used instead...
2456 if (optionValue == null)
2457 throw new ArgumentNullException("optionValue");
2461 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
2462 LingerOption linger = optionValue as LingerOption;
2464 throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
2465 SetSocketOption_internal (safe_handle, optionLevel, optionName, linger, null, 0, out error);
2466 } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2467 MulticastOption multicast = optionValue as MulticastOption;
2468 if (multicast == null)
2469 throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
2470 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
2471 } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2472 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
2473 if (multicast == null)
2474 throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
2475 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
2477 throw new ArgumentException ("Invalid value specified.", "optionValue");
2481 if (error == (int) SocketError.InvalidArgument)
2482 throw new ArgumentException ();
2483 throw new SocketException (error);
2487 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
2489 if (is_disposed && is_closed)
2490 throw new ObjectDisposedException (GetType ().ToString ());
2493 int int_val = (optionValue) ? 1 : 0;
2494 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, int_val, out error);
2496 if (error == (int) SocketError.InvalidArgument)
2497 throw new ArgumentException ();
2498 throw new SocketException (error);
2502 void ThrowIfDisposedAndClosed ()
2504 if (is_disposed && is_closed)
2505 throw new ObjectDisposedException (GetType ().ToString ());
2510 #if !NET_2_1 || MOBILE
2511 if (protocol_type == ProtocolType.Udp)
2512 throw new SocketException ((int)SocketError.ProtocolOption);