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)
9 // Ludovic Henry (ludovic@xamarin.com)
11 // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
12 // http://www.myelin.co.nz
13 // (c) 2004-2011 Novell, Inc. (http://www.novell.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 using System.Collections;
39 using System.Collections.Generic;
40 using System.Runtime.CompilerServices;
41 using System.Runtime.InteropServices;
42 using System.Threading;
43 using System.Reflection;
45 using System.Net.Configuration;
48 using System.Net.NetworkInformation;
50 namespace System.Net.Sockets
52 public partial class Socket : IDisposable
54 const int SOCKET_CLOSED_CODE = 10004;
55 const string TIMEOUT_EXCEPTION_MSG = "A connection attempt failed because the connected party did not properly respond" +
56 "after a period of time, or established connection failed because connected host has failed to respond";
58 /* true if we called Close_internal */
66 AddressFamily addressFamily;
67 SocketType socketType;
68 ProtocolType protocolType;
70 /* the field "m_Handle" is looked up by name by the runtime */
71 internal SafeSocketHandle m_Handle;
74 * This EndPoint is used when creating new endpoints. Because
75 * there are many types of EndPoints possible,
76 * seed_endpoint.Create(addr) is used for creating new ones.
77 * As such, this value is set on Bind, SentTo, ReceiveFrom,
80 internal EndPoint seed_endpoint = null;
82 internal SemaphoreSlim ReadSem = new SemaphoreSlim (1, 1);
83 internal SemaphoreSlim WriteSem = new SemaphoreSlim (1, 1);
85 internal bool is_blocking = true;
86 internal bool is_bound;
88 /* When true, the socket was connected at the time of the last IO operation */
89 internal bool is_connected;
92 internal bool connect_in_progress;
97 public Socket (SocketInformation socketInformation)
99 this.is_listening = (socketInformation.Options & SocketInformationOptions.Listening) != 0;
100 this.is_connected = (socketInformation.Options & SocketInformationOptions.Connected) != 0;
101 this.is_blocking = (socketInformation.Options & SocketInformationOptions.NonBlocking) == 0;
102 this.useOverlappedIO = (socketInformation.Options & SocketInformationOptions.UseOnlyOverlappedIO) != 0;
104 var result = Mono.DataConverter.Unpack ("iiiil", socketInformation.ProtocolInformation, 0);
106 this.addressFamily = (AddressFamily) (int) result [0];
107 this.socketType = (SocketType) (int) result [1];
108 this.protocolType = (ProtocolType) (int) result [2];
109 this.is_bound = (ProtocolType) (int) result [3] != 0;
110 this.m_Handle = new SafeSocketHandle ((IntPtr) (long) result [4], true);
112 InitializeSockets ();
117 /* private constructor used by Accept, which already has a socket handle to use */
118 internal Socket(AddressFamily family, SocketType type, ProtocolType proto, SafeSocketHandle safe_handle)
120 this.addressFamily = family;
121 this.socketType = type;
122 this.protocolType = proto;
124 this.m_Handle = safe_handle;
125 this.is_connected = true;
127 InitializeSockets ();
130 void SocketDefaults ()
133 /* Need to test IPv6 further */
134 if (addressFamily == AddressFamily.InterNetwork
135 // || addressFamily == AddressFamily.InterNetworkV6
137 /* This is the default, but it probably has nasty side
138 * effects on Linux, as the socket option is kludged by
139 * turning on or off PMTU discovery... */
140 this.DontFragment = false;
141 if (protocolType == ProtocolType.Tcp)
142 this.NoDelay = false;
143 } else if (addressFamily == AddressFamily.InterNetworkV6) {
144 this.DualMode = true;
147 /* Microsoft sets these to 8192, but we are going to keep them
148 * both to the OS defaults as these have a big performance impact.
149 * on WebClient performance. */
150 // this.ReceiveBufferSize = 8192;
151 // this.SendBufferSize = 8192;
152 } catch (SocketException) {
156 /* Creates a new system socket, returning the handle */
157 [MethodImplAttribute(MethodImplOptions.InternalCall)]
158 extern IntPtr Socket_internal (AddressFamily family, SocketType type, ProtocolType proto, out int error);
164 public int Available {
166 ThrowIfDisposedAndClosed ();
169 ret = Available_internal (m_Handle, out error);
172 throw new SocketException (error);
178 static int Available_internal (SafeSocketHandle safeHandle, out int error)
180 bool release = false;
182 safeHandle.DangerousAddRef (ref release);
183 return Available_internal (safeHandle.DangerousGetHandle (), out error);
186 safeHandle.DangerousRelease ();
190 /* Returns the amount of data waiting to be read on socket */
191 [MethodImplAttribute(MethodImplOptions.InternalCall)]
192 extern static int Available_internal (IntPtr socket, out int error);
194 // FIXME: import from referencesource
195 public bool EnableBroadcast {
197 ThrowIfDisposedAndClosed ();
199 if (protocolType != ProtocolType.Udp)
200 throw new SocketException ((int) SocketError.ProtocolOption);
202 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0;
205 ThrowIfDisposedAndClosed ();
207 if (protocolType != ProtocolType.Udp)
208 throw new SocketException ((int) SocketError.ProtocolOption);
210 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
214 public bool IsBound {
220 // FIXME: import from referencesource
221 public bool MulticastLoopback {
223 ThrowIfDisposedAndClosed ();
225 /* Even though this option can be set for TCP sockets on Linux, throw
226 * this exception anyway to be compatible (the MSDN docs say
227 * "Setting this property on a Transmission Control Protocol (TCP)
228 * socket will have no effect." but the MS runtime throws the
230 if (protocolType == ProtocolType.Tcp)
231 throw new SocketException ((int)SocketError.ProtocolOption);
233 switch (addressFamily) {
234 case AddressFamily.InterNetwork:
235 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
236 case AddressFamily.InterNetworkV6:
237 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
239 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
243 ThrowIfDisposedAndClosed ();
245 /* Even though this option can be set for TCP sockets on Linux, throw
246 * this exception anyway to be compatible (the MSDN docs say
247 * "Setting this property on a Transmission Control Protocol (TCP)
248 * socket will have no effect." but the MS runtime throws the
250 if (protocolType == ProtocolType.Tcp)
251 throw new SocketException ((int)SocketError.ProtocolOption);
253 switch (addressFamily) {
254 case AddressFamily.InterNetwork:
255 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
257 case AddressFamily.InterNetworkV6:
258 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
261 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
266 // Wish: support non-IP endpoints.
267 public EndPoint LocalEndPoint {
269 ThrowIfDisposedAndClosed ();
271 /* If the seed EndPoint is null, Connect, Bind, etc has not yet
272 * been called. MS returns null in this case. */
273 if (seed_endpoint == null)
277 SocketAddress sa = LocalEndPoint_internal (m_Handle, (int) addressFamily, out error);
280 throw new SocketException (error);
282 return seed_endpoint.Create (sa);
286 static SocketAddress LocalEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
288 bool release = false;
290 safeHandle.DangerousAddRef (ref release);
291 return LocalEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
294 safeHandle.DangerousRelease ();
298 /* Returns the local endpoint details in addr and port */
299 [MethodImplAttribute(MethodImplOptions.InternalCall)]
300 extern static SocketAddress LocalEndPoint_internal (IntPtr socket, int family, out int error);
302 public bool Blocking {
303 get { return is_blocking; }
305 ThrowIfDisposedAndClosed ();
308 Blocking_internal (m_Handle, value, out error);
311 throw new SocketException (error);
317 static void Blocking_internal (SafeSocketHandle safeHandle, bool block, out int error)
319 bool release = false;
321 safeHandle.DangerousAddRef (ref release);
322 Blocking_internal (safeHandle.DangerousGetHandle (), block, out error);
325 safeHandle.DangerousRelease ();
329 [MethodImplAttribute(MethodImplOptions.InternalCall)]
330 internal extern static void Blocking_internal(IntPtr socket, bool block, out int error);
332 public bool Connected {
333 get { return is_connected; }
334 internal set { is_connected = value; }
337 // FIXME: import from referencesource
338 public bool NoDelay {
340 ThrowIfDisposedAndClosed ();
343 return ((int) GetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay)) != 0;
347 ThrowIfDisposedAndClosed ();
349 SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
353 public EndPoint RemoteEndPoint {
355 ThrowIfDisposedAndClosed ();
357 /* If the seed EndPoint is null, Connect, Bind, etc has
358 * not yet been called. MS returns null in this case. */
359 if (!is_connected || seed_endpoint == null)
363 SocketAddress sa = RemoteEndPoint_internal (m_Handle, (int) addressFamily, out error);
366 throw new SocketException (error);
368 return seed_endpoint.Create (sa);
372 static SocketAddress RemoteEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
374 bool release = false;
376 safeHandle.DangerousAddRef (ref release);
377 return RemoteEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
380 safeHandle.DangerousRelease ();
384 /* Returns the remote endpoint details in addr and port */
385 [MethodImplAttribute(MethodImplOptions.InternalCall)]
386 extern static SocketAddress RemoteEndPoint_internal (IntPtr socket, int family, out int error);
392 public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
394 var list = new List<Socket> ();
395 AddSockets (list, checkRead, "checkRead");
396 AddSockets (list, checkWrite, "checkWrite");
397 AddSockets (list, checkError, "checkError");
400 throw new ArgumentNullException ("checkRead, checkWrite, checkError", "All the lists are null or empty.");
402 /* The 'sockets' array contains:
403 * - READ socket 0-n, null,
404 * - WRITE socket 0-n, null,
405 * - ERROR socket 0-n, null */
406 Socket [] sockets = list.ToArray ();
409 Select_internal (ref sockets, microSeconds, out error);
412 throw new SocketException (error);
414 if (sockets == null) {
415 if (checkRead != null)
417 if (checkWrite != null)
419 if (checkError != null)
425 int count = sockets.Length;
426 IList currentList = checkRead;
428 for (int i = 0; i < count; i++) {
429 Socket sock = sockets [i];
430 if (sock == null) { // separator
431 if (currentList != null) {
432 // Remove non-signaled sockets after the current one
433 int to_remove = currentList.Count - currentIdx;
434 for (int k = 0; k < to_remove; k++)
435 currentList.RemoveAt (currentIdx);
437 currentList = (mode == 0) ? checkWrite : checkError;
443 if (mode == 1 && currentList == checkWrite && !sock.is_connected) {
444 if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
445 sock.is_connected = true;
448 /* Remove non-signaled sockets before the current one */
449 while (((Socket) currentList [currentIdx]) != sock)
450 currentList.RemoveAt (currentIdx);
456 static void AddSockets (List<Socket> sockets, IList list, string name)
459 foreach (Socket sock in list) {
460 if (sock == null) // MS throws a NullRef
461 throw new ArgumentNullException ("name", "Contains a null element");
469 [MethodImplAttribute(MethodImplOptions.InternalCall)]
470 extern static void Select_internal (ref Socket [] sockets, int microSeconds, out int error);
476 public bool Poll (int microSeconds, SelectMode mode)
478 ThrowIfDisposedAndClosed ();
480 if (mode != SelectMode.SelectRead && mode != SelectMode.SelectWrite && mode != SelectMode.SelectError)
481 throw new NotSupportedException ("'mode' parameter is not valid.");
484 bool result = Poll_internal (m_Handle, mode, microSeconds, out error);
487 throw new SocketException (error);
489 if (mode == SelectMode.SelectWrite && result && !is_connected) {
490 /* Update the is_connected state; for non-blocking Connect()
491 * this is when we can find out that the connect succeeded. */
492 if ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
499 static bool Poll_internal (SafeSocketHandle safeHandle, SelectMode mode, int timeout, out int error)
501 bool release = false;
503 safeHandle.DangerousAddRef (ref release);
504 return Poll_internal (safeHandle.DangerousGetHandle (), mode, timeout, out error);
507 safeHandle.DangerousRelease ();
511 [MethodImplAttribute(MethodImplOptions.InternalCall)]
512 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
518 public Socket Accept()
520 ThrowIfDisposedAndClosed ();
523 SafeSocketHandle safe_handle = Accept_internal (this.m_Handle, out error, is_blocking);
527 error = SOCKET_CLOSED_CODE;
528 throw new SocketException(error);
531 Socket accepted = new Socket (this.AddressFamily, this.SocketType, this.ProtocolType, safe_handle) {
532 seed_endpoint = this.seed_endpoint,
533 Blocking = this.Blocking,
539 internal void Accept (Socket acceptSocket)
541 ThrowIfDisposedAndClosed ();
544 SafeSocketHandle safe_handle = Accept_internal (this.m_Handle, out error, is_blocking);
548 error = SOCKET_CLOSED_CODE;
549 throw new SocketException (error);
552 acceptSocket.addressFamily = this.AddressFamily;
553 acceptSocket.socketType = this.SocketType;
554 acceptSocket.protocolType = this.ProtocolType;
555 acceptSocket.m_Handle = safe_handle;
556 acceptSocket.is_connected = true;
557 acceptSocket.seed_endpoint = this.seed_endpoint;
558 acceptSocket.Blocking = this.Blocking;
560 // FIXME: figure out what if anything else needs to be reset
563 public bool AcceptAsync (SocketAsyncEventArgs e)
565 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
567 ThrowIfDisposedAndClosed ();
570 throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
572 throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
573 if (e.BufferList != null)
574 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
576 throw new ArgumentOutOfRangeException ("e.Count");
578 Socket acceptSocket = e.AcceptSocket;
579 if (acceptSocket != null) {
580 if (acceptSocket.is_bound || acceptSocket.is_connected)
581 throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
584 InitSocketAsyncEventArgs (e, AcceptAsyncCallback, e, SocketOperation.Accept);
586 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, e.socket_async_result));
591 static AsyncCallback AcceptAsyncCallback = new AsyncCallback (ares => {
592 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
594 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
595 throw new InvalidOperationException ("No operation in progress");
598 e.AcceptSocket = e.current_socket.EndAccept (ares);
599 } catch (SocketException ex) {
600 e.SocketError = ex.SocketErrorCode;
601 } catch (ObjectDisposedException) {
602 e.SocketError = SocketError.OperationAborted;
604 if (e.AcceptSocket == null)
605 e.AcceptSocket = new Socket (e.current_socket.AddressFamily, e.current_socket.SocketType, e.current_socket.ProtocolType, null);
610 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
612 ThrowIfDisposedAndClosed ();
614 if (!is_bound || !is_listening)
615 throw new InvalidOperationException ();
617 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Accept);
619 QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, sockares));
624 static IOAsyncCallback BeginAcceptCallback = new IOAsyncCallback (ares => {
625 SocketAsyncResult sockares = (SocketAsyncResult) ares;
626 Socket acc_socket = null;
628 if (sockares.AcceptSocket == null) {
629 acc_socket = sockares.socket.Accept ();
631 acc_socket = sockares.AcceptSocket;
632 sockares.socket.Accept (acc_socket);
635 } catch (Exception e) {
636 sockares.Complete (e);
639 sockares.Complete (acc_socket);
642 public IAsyncResult BeginAccept (Socket acceptSocket, int receiveSize, AsyncCallback callback, object state)
644 ThrowIfDisposedAndClosed ();
647 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
649 if (acceptSocket != null) {
650 ThrowIfDisposedAndClosed (acceptSocket);
652 if (acceptSocket.IsBound)
653 throw new InvalidOperationException ();
655 /* For some reason the MS runtime
656 * barfs if the new socket is not TCP,
657 * even though it's just about to blow
658 * away all those parameters
660 if (acceptSocket.ProtocolType != ProtocolType.Tcp)
661 throw new SocketException ((int)SocketError.InvalidArgument);
664 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
665 Buffer = new byte [receiveSize],
668 SockFlags = SocketFlags.None,
669 AcceptSocket = acceptSocket,
672 QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
677 static IOAsyncCallback BeginAcceptReceiveCallback = new IOAsyncCallback (ares => {
678 SocketAsyncResult sockares = (SocketAsyncResult) ares;
679 Socket acc_socket = null;
682 if (sockares.AcceptSocket == null) {
683 acc_socket = sockares.socket.Accept ();
685 acc_socket = sockares.AcceptSocket;
686 sockares.socket.Accept (acc_socket);
688 } catch (Exception e) {
689 sockares.Complete (e);
693 /* It seems the MS runtime special-cases 0-length requested receive data. See bug 464201. */
695 if (sockares.Size > 0) {
698 total = acc_socket.Receive (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out error);
700 sockares.Complete (new SocketException ((int) error));
703 } catch (Exception e) {
704 sockares.Complete (e);
709 sockares.Complete (acc_socket, total);
712 public Socket EndAccept (IAsyncResult result)
716 return EndAccept (out buffer, out bytes, result);
719 public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
721 ThrowIfDisposedAndClosed ();
723 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndAccept", "asyncResult");
725 if (!sockares.IsCompleted)
726 sockares.AsyncWaitHandle.WaitOne ();
728 sockares.CheckIfThrowDelayedException ();
730 buffer = sockares.Buffer;
731 bytesTransferred = sockares.Total;
733 return sockares.AcceptedSocket;
736 static SafeSocketHandle Accept_internal (SafeSocketHandle safeHandle, out int error, bool blocking)
739 safeHandle.RegisterForBlockingSyscall ();
740 var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
741 return new SafeSocketHandle (ret, true);
743 safeHandle.UnRegisterForBlockingSyscall ();
747 /* Creates a new system socket, returning the handle */
748 [MethodImplAttribute(MethodImplOptions.InternalCall)]
749 extern static IntPtr Accept_internal (IntPtr sock, out int error, bool blocking);
755 public void Bind (EndPoint localEP)
757 #if FEATURE_NO_BSD_SOCKETS
758 throw new PlatformNotSupportedException ("System.Net.Sockets.Socket:Bind is not supported on this platform.");
760 ThrowIfDisposedAndClosed ();
763 throw new ArgumentNullException("localEP");
765 var ipEndPoint = localEP as IPEndPoint;
766 if (ipEndPoint != null) {
767 localEP = RemapIPEndPoint (ipEndPoint);
771 Bind_internal (m_Handle, localEP.Serialize(), out error);
774 throw new SocketException (error);
778 seed_endpoint = localEP;
779 #endif // FEATURE_NO_BSD_SOCKETS
782 private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
784 bool release = false;
786 safeHandle.DangerousAddRef (ref release);
787 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
790 safeHandle.DangerousRelease ();
794 // Creates a new system socket, returning the handle
795 [MethodImplAttribute(MethodImplOptions.InternalCall)]
796 private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
802 public void Listen (int backlog)
804 ThrowIfDisposedAndClosed ();
807 throw new SocketException ((int) SocketError.InvalidArgument);
810 Listen_internal(m_Handle, backlog, out error);
813 throw new SocketException (error);
818 static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
820 bool release = false;
822 safeHandle.DangerousAddRef (ref release);
823 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
826 safeHandle.DangerousRelease ();
830 [MethodImplAttribute(MethodImplOptions.InternalCall)]
831 extern static void Listen_internal (IntPtr sock, int backlog, out int error);
837 public void Connect (IPAddress address, int port)
839 Connect (new IPEndPoint (address, port));
842 public void Connect (string host, int port)
844 Connect (Dns.GetHostAddresses (host), port);
847 public void Connect (IPAddress[] addresses, int port)
849 ThrowIfDisposedAndClosed ();
851 if (addresses == null)
852 throw new ArgumentNullException ("addresses");
853 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
854 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
856 throw new InvalidOperationException ();
858 // FIXME: do non-blocking sockets Poll here?
860 foreach (IPAddress address in addresses) {
861 IPEndPoint iep = new IPEndPoint (address, port);
863 iep = RemapIPEndPoint (iep);
865 Connect_internal (m_Handle, iep.Serialize (), out error, is_blocking);
872 if (error != (int)SocketError.InProgress && error != (int)SocketError.WouldBlock)
876 Poll (-1, SelectMode.SelectWrite);
877 error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
888 throw new SocketException (error);
892 public void Connect (EndPoint remoteEP)
894 ThrowIfDisposedAndClosed ();
896 if (remoteEP == null)
897 throw new ArgumentNullException ("remoteEP");
899 IPEndPoint ep = remoteEP as IPEndPoint;
900 /* Dgram uses Any to 'disconnect' */
901 if (ep != null && socketType != SocketType.Dgram) {
902 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
903 throw new SocketException ((int) SocketError.AddressNotAvailable);
907 throw new InvalidOperationException ();
910 remoteEP = RemapIPEndPoint (ep);
913 SocketAddress serial = remoteEP.Serialize ();
916 Connect_internal (m_Handle, serial, out error, is_blocking);
918 if (error == 0 || error == 10035)
919 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
923 error = SOCKET_CLOSED_CODE;
924 throw new SocketException (error);
927 is_connected = !(socketType == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
931 public bool ConnectAsync (SocketAsyncEventArgs e)
933 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
935 ThrowIfDisposedAndClosed ();
938 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
939 if (e.RemoteEndPoint == null)
940 throw new ArgumentNullException ("remoteEP");
942 InitSocketAsyncEventArgs (e, null, e, SocketOperation.Connect);
945 IPAddress [] addresses;
946 SocketAsyncResult ares;
948 if (!GetCheckedIPs (e, out addresses)) {
949 e.socket_async_result.EndPoint = e.RemoteEndPoint;
950 ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
952 DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
953 e.socket_async_result.Addresses = addresses;
954 e.socket_async_result.Port = dep.Port;
955 ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
958 if (ares.IsCompleted && ares.CompletedSynchronously) {
959 ares.CheckIfThrowDelayedException ();
962 } catch (Exception exc) {
963 e.socket_async_result.Complete (exc, true);
970 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
972 var sock = new Socket (e.RemoteEndPoint.AddressFamily, socketType, protocolType);
973 return sock.ConnectAsync (e);
976 public static void CancelConnectAsync (SocketAsyncEventArgs e)
979 throw new ArgumentNullException("e");
981 if (e.in_progress != 0 && e.LastOperation == SocketAsyncOperation.Connect)
982 e.current_socket.Close();
985 static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
986 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
988 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
989 throw new InvalidOperationException ("No operation in progress");
992 e.current_socket.EndConnect (ares);
993 } catch (SocketException se) {
994 e.SocketError = se.SocketErrorCode;
995 } catch (ObjectDisposedException) {
996 e.SocketError = SocketError.OperationAborted;
1002 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
1004 ThrowIfDisposedAndClosed ();
1007 throw new ArgumentNullException ("host");
1008 if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6)
1009 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1010 if (port <= 0 || port > 65535)
1011 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1013 throw new InvalidOperationException ();
1015 return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1018 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
1020 ThrowIfDisposedAndClosed ();
1022 if (end_point == null)
1023 throw new ArgumentNullException ("end_point");
1025 throw new InvalidOperationException ();
1027 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1028 EndPoint = end_point,
1031 // Bug #75154: Connect() should not succeed for .Any addresses.
1032 if (end_point is IPEndPoint) {
1033 IPEndPoint ep = (IPEndPoint) end_point;
1034 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1035 sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1039 end_point = RemapIPEndPoint (ep);
1044 if (connect_in_progress) {
1045 // This could happen when multiple IPs are used
1046 // Calling connect() again will reset the connection attempt and cause
1047 // an error. Better to just close the socket and move on.
1048 connect_in_progress = false;
1049 m_Handle.Dispose ();
1050 m_Handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
1052 throw new SocketException (error);
1055 bool blk = is_blocking;
1058 Connect_internal (m_Handle, end_point.Serialize (), out error, false);
1064 is_connected = true;
1066 sockares.Complete (true);
1070 if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1072 is_connected = false;
1074 sockares.Complete (new SocketException (error), true);
1079 is_connected = false;
1081 connect_in_progress = true;
1083 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
1088 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1090 ThrowIfDisposedAndClosed ();
1092 if (addresses == null)
1093 throw new ArgumentNullException ("addresses");
1094 if (addresses.Length == 0)
1095 throw new ArgumentException ("Empty addresses list");
1096 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1097 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1098 if (port <= 0 || port > 65535)
1099 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1101 throw new InvalidOperationException ();
1103 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1104 Addresses = addresses,
1108 is_connected = false;
1110 return BeginMConnect (sockares);
1113 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1115 SocketAsyncResult ares = null;
1116 Exception exc = null;
1117 AsyncCallback callback;
1119 for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1121 sockares.CurrentAddress++;
1123 ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1124 if (ares.IsCompleted && ares.CompletedSynchronously) {
1125 ares.CheckIfThrowDelayedException ();
1127 callback = ares.AsyncCallback;
1128 if (callback != null)
1129 ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
1133 } catch (Exception e) {
1145 static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
1146 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1148 if (sockares.EndPoint == null) {
1149 sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
1153 SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
1154 bool is_mconnect = mconnect != null && mconnect.Addresses != null;
1157 EndPoint ep = sockares.EndPoint;
1158 int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1160 if (error_code == 0) {
1162 sockares = mconnect;
1164 sockares.socket.seed_endpoint = ep;
1165 sockares.socket.is_connected = true;
1166 sockares.socket.is_bound = true;
1167 sockares.socket.connect_in_progress = false;
1169 sockares.Complete ();
1174 sockares.socket.connect_in_progress = false;
1175 sockares.Complete (new SocketException (error_code));
1179 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
1180 mconnect.Complete (new SocketException (error_code));
1184 mconnect.socket.BeginMConnect (mconnect);
1185 } catch (Exception e) {
1186 sockares.socket.connect_in_progress = false;
1189 sockares = mconnect;
1191 sockares.Complete (e);
1196 public void EndConnect (IAsyncResult result)
1198 ThrowIfDisposedAndClosed ();
1200 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1202 if (!sockares.IsCompleted)
1203 sockares.AsyncWaitHandle.WaitOne();
1205 sockares.CheckIfThrowDelayedException();
1208 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error, bool blocking)
1211 safeHandle.RegisterForBlockingSyscall ();
1212 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error, blocking);
1214 safeHandle.UnRegisterForBlockingSyscall ();
1218 /* Connects to the remote address */
1219 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1220 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error, bool blocking);
1223 * - false when it is ok to use RemoteEndPoint
1224 * - true when addresses must be used (and addresses could be null/empty) */
1225 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1229 // Connect to the first address that match the host name, like:
1230 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1231 // while skipping entries that do not match the address family
1232 DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1234 addresses = Dns.GetHostAddresses (dep.Host);
1237 e.ConnectByNameError = null;
1246 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1247 * if the platform is newer than w2k. We should be able to cope... */
1248 public void Disconnect (bool reuseSocket)
1250 ThrowIfDisposedAndClosed ();
1253 Disconnect_internal (m_Handle, reuseSocket, out error);
1257 /* ERROR_NOT_SUPPORTED */
1258 throw new PlatformNotSupportedException ();
1260 throw new SocketException (error);
1264 is_connected = false;
1266 /* Do managed housekeeping here... */
1270 public bool DisconnectAsync (SocketAsyncEventArgs e)
1272 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1274 ThrowIfDisposedAndClosed ();
1276 InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
1278 IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
1283 static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
1284 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1286 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1287 throw new InvalidOperationException ("No operation in progress");
1290 e.current_socket.EndDisconnect (ares);
1291 } catch (SocketException ex) {
1292 e.SocketError = ex.SocketErrorCode;
1293 } catch (ObjectDisposedException) {
1294 e.SocketError = SocketError.OperationAborted;
1300 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1302 ThrowIfDisposedAndClosed ();
1304 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1305 ReuseSocket = reuseSocket,
1308 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
1313 static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
1314 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1317 sockares.socket.Disconnect (sockares.ReuseSocket);
1318 } catch (Exception e) {
1319 sockares.Complete (e);
1323 sockares.Complete ();
1326 public void EndDisconnect (IAsyncResult asyncResult)
1328 ThrowIfDisposedAndClosed ();
1330 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1332 if (!sockares.IsCompleted)
1333 sockares.AsyncWaitHandle.WaitOne ();
1335 sockares.CheckIfThrowDelayedException ();
1338 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1340 bool release = false;
1342 safeHandle.DangerousAddRef (ref release);
1343 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1346 safeHandle.DangerousRelease ();
1350 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1351 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1357 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1359 ThrowIfDisposedAndClosed ();
1360 ThrowIfBufferNull (buffer);
1361 ThrowIfBufferOutOfRange (buffer, offset, size);
1364 int ret = Receive_internal (m_Handle, buffer, offset, size, socketFlags, out nativeError, is_blocking);
1366 errorCode = (SocketError) nativeError;
1367 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1368 is_connected = false;
1371 is_connected = true;
1377 [CLSCompliant (false)]
1378 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1380 ThrowIfDisposedAndClosed ();
1382 if (buffers == null || buffers.Count == 0)
1383 throw new ArgumentNullException ("buffers");
1385 int numsegments = buffers.Count;
1389 /* Only example I can find of sending a byte array reference directly into an internal
1390 * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1391 * so taking a lead from that... */
1392 WSABUF[] bufarray = new WSABUF[numsegments];
1393 GCHandle[] gch = new GCHandle[numsegments];
1395 for (int i = 0; i < numsegments; i++) {
1396 ArraySegment<byte> segment = buffers[i];
1398 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1399 throw new ArgumentOutOfRangeException ("segment");
1401 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1402 bufarray[i].len = segment.Count;
1403 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1407 ret = Receive_internal (m_Handle, bufarray, socketFlags, out nativeError, is_blocking);
1409 for (int i = 0; i < numsegments; i++) {
1410 if (gch[i].IsAllocated)
1415 errorCode = (SocketError) nativeError;
1420 public bool ReceiveAsync (SocketAsyncEventArgs e)
1422 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1424 ThrowIfDisposedAndClosed ();
1426 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1427 // thrown when e.Buffer and e.BufferList are null (works fine when one is
1428 // set to a valid object)
1429 if (e.Buffer == null && e.BufferList == null)
1430 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1432 if (e.Buffer == null) {
1433 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
1435 e.socket_async_result.Buffers = e.BufferList;
1437 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
1439 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
1441 e.socket_async_result.Buffer = e.Buffer;
1442 e.socket_async_result.Offset = e.Offset;
1443 e.socket_async_result.Size = e.Count;
1445 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
1451 static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
1452 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1454 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1455 throw new InvalidOperationException ("No operation in progress");
1458 e.BytesTransferred = e.current_socket.EndReceive (ares);
1459 } catch (SocketException se){
1460 e.SocketError = se.SocketErrorCode;
1461 } catch (ObjectDisposedException) {
1462 e.SocketError = SocketError.OperationAborted;
1468 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1470 ThrowIfDisposedAndClosed ();
1471 ThrowIfBufferNull (buffer);
1472 ThrowIfBufferOutOfRange (buffer, offset, size);
1474 /* As far as I can tell from the docs and from experimentation, a pointer to the
1475 * SocketError parameter is not supposed to be saved for the async parts. And as we don't
1476 * set any socket errors in the setup code, we just have to set it to Success. */
1477 errorCode = SocketError.Success;
1479 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1483 SockFlags = socketFlags,
1486 QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
1491 static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
1492 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1496 total = Receive_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error, sockares.socket.is_blocking);
1497 } catch (Exception e) {
1498 sockares.Complete (e);
1502 sockares.Complete (total);
1505 [CLSCompliant (false)]
1506 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1508 ThrowIfDisposedAndClosed ();
1510 if (buffers == null)
1511 throw new ArgumentNullException ("buffers");
1513 /* I assume the same SocketError semantics as above */
1514 errorCode = SocketError.Success;
1516 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1518 SockFlags = socketFlags,
1521 QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
1526 static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
1527 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1531 total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
1532 } catch (Exception e) {
1533 sockares.Complete (e);
1537 sockares.Complete (total);
1540 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
1542 ThrowIfDisposedAndClosed ();
1544 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
1546 if (!sockares.IsCompleted)
1547 sockares.AsyncWaitHandle.WaitOne ();
1549 errorCode = sockares.ErrorCode;
1551 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress)
1552 is_connected = false;
1554 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
1555 // kinds of exceptions that should be thrown.
1556 if (errorCode == SocketError.Success)
1557 sockares.CheckIfThrowDelayedException();
1559 return sockares.Total;
1562 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking)
1565 safeHandle.RegisterForBlockingSyscall ();
1566 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error, blocking);
1568 safeHandle.UnRegisterForBlockingSyscall ();
1572 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1573 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking);
1575 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error, bool blocking)
1578 safeHandle.RegisterForBlockingSyscall ();
1579 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error, blocking);
1581 safeHandle.UnRegisterForBlockingSyscall ();
1585 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1586 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error, bool blocking);
1592 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
1594 ThrowIfDisposedAndClosed ();
1595 ThrowIfBufferNull (buffer);
1596 ThrowIfBufferOutOfRange (buffer, offset, size);
1598 if (remoteEP == null)
1599 throw new ArgumentNullException ("remoteEP");
1601 SocketError errorCode;
1602 int ret = ReceiveFrom (buffer, offset, size, socketFlags, ref remoteEP, out errorCode);
1604 if (errorCode != SocketError.Success)
1605 throw new SocketException (errorCode);
1610 internal int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, out SocketError errorCode)
1612 SocketAddress sockaddr = remoteEP.Serialize();
1615 int cnt = ReceiveFrom_internal (m_Handle, buffer, offset, size, socketFlags, ref sockaddr, out nativeError, is_blocking);
1617 errorCode = (SocketError) nativeError;
1618 if (errorCode != SocketError.Success) {
1619 if (errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1620 is_connected = false;
1621 } else if (errorCode == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
1622 errorCode = SocketError.TimedOut;
1628 is_connected = true;
1631 /* If sockaddr is null then we're a connection oriented protocol and should ignore the
1632 * remoteEP parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
1633 if (sockaddr != null) {
1634 /* Stupidly, EndPoint.Create() is an instance method */
1635 remoteEP = remoteEP.Create (sockaddr);
1638 seed_endpoint = remoteEP;
1643 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
1645 ThrowIfDisposedAndClosed ();
1647 // We do not support recv into multiple buffers yet
1648 if (e.BufferList != null)
1649 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
1650 if (e.RemoteEndPoint == null)
1651 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
1653 InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
1655 e.socket_async_result.Buffer = e.Buffer;
1656 e.socket_async_result.Offset = e.Offset;
1657 e.socket_async_result.Size = e.Count;
1658 e.socket_async_result.EndPoint = e.RemoteEndPoint;
1659 e.socket_async_result.SockFlags = e.SocketFlags;
1661 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
1666 static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
1667 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1669 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1670 throw new InvalidOperationException ("No operation in progress");
1673 e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
1674 } catch (SocketException ex) {
1675 e.SocketError = ex.SocketErrorCode;
1676 } catch (ObjectDisposedException) {
1677 e.SocketError = SocketError.OperationAborted;
1683 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
1685 ThrowIfDisposedAndClosed ();
1686 ThrowIfBufferNull (buffer);
1687 ThrowIfBufferOutOfRange (buffer, offset, size);
1689 if (remote_end == null)
1690 throw new ArgumentNullException ("remote_end");
1692 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
1696 SockFlags = socket_flags,
1697 EndPoint = remote_end,
1700 QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
1705 static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
1706 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1710 SocketError errorCode;
1711 total = sockares.socket.ReceiveFrom (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, out errorCode);
1713 if (errorCode != SocketError.Success) {
1714 sockares.Complete (new SocketException (errorCode));
1717 } catch (Exception e) {
1718 sockares.Complete (e);
1722 sockares.Complete (total);
1725 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
1727 ThrowIfDisposedAndClosed ();
1729 if (end_point == null)
1730 throw new ArgumentNullException ("remote_end");
1732 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
1734 if (!sockares.IsCompleted)
1735 sockares.AsyncWaitHandle.WaitOne();
1737 sockares.CheckIfThrowDelayedException();
1739 end_point = sockares.EndPoint;
1741 return sockares.Total;
1746 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking)
1749 safeHandle.RegisterForBlockingSyscall ();
1750 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error, blocking);
1752 safeHandle.UnRegisterForBlockingSyscall ();
1756 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1757 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking);
1761 #region ReceiveMessageFrom
1763 [MonoTODO ("Not implemented")]
1764 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
1766 ThrowIfDisposedAndClosed ();
1767 ThrowIfBufferNull (buffer);
1768 ThrowIfBufferOutOfRange (buffer, offset, size);
1770 if (remoteEP == null)
1771 throw new ArgumentNullException ("remoteEP");
1773 // FIXME: figure out how we get hold of the IPPacketInformation
1774 throw new NotImplementedException ();
1777 [MonoTODO ("Not implemented")]
1778 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
1780 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1782 ThrowIfDisposedAndClosed ();
1784 throw new NotImplementedException ();
1788 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
1790 ThrowIfDisposedAndClosed ();
1791 ThrowIfBufferNull (buffer);
1792 ThrowIfBufferOutOfRange (buffer, offset, size);
1794 if (remoteEP == null)
1795 throw new ArgumentNullException ("remoteEP");
1797 throw new NotImplementedException ();
1801 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
1803 ThrowIfDisposedAndClosed ();
1805 if (endPoint == null)
1806 throw new ArgumentNullException ("endPoint");
1808 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
1810 throw new NotImplementedException ();
1817 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1819 ThrowIfDisposedAndClosed ();
1820 ThrowIfBufferNull (buffer);
1821 ThrowIfBufferOutOfRange (buffer, offset, size);
1824 errorCode = SocketError.Success;
1831 sent += Send_internal (
1832 m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_blocking);
1833 errorCode = (SocketError)nativeError;
1834 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1835 is_connected = false;
1839 is_connected = true;
1841 } while (sent < size);
1846 [CLSCompliant (false)]
1847 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1849 ThrowIfDisposedAndClosed ();
1851 if (buffers == null)
1852 throw new ArgumentNullException ("buffers");
1853 if (buffers.Count == 0)
1854 throw new ArgumentException ("Buffer is empty", "buffers");
1856 int numsegments = buffers.Count;
1860 WSABUF[] bufarray = new WSABUF[numsegments];
1861 GCHandle[] gch = new GCHandle[numsegments];
1863 for(int i = 0; i < numsegments; i++) {
1864 ArraySegment<byte> segment = buffers[i];
1866 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1867 throw new ArgumentOutOfRangeException ("segment");
1869 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1870 bufarray[i].len = segment.Count;
1871 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1875 ret = Send_internal (m_Handle, bufarray, socketFlags, out nativeError, is_blocking);
1877 for(int i = 0; i < numsegments; i++) {
1878 if (gch[i].IsAllocated) {
1884 errorCode = (SocketError)nativeError;
1889 public bool SendAsync (SocketAsyncEventArgs e)
1891 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1893 ThrowIfDisposedAndClosed ();
1895 if (e.Buffer == null && e.BufferList == null)
1896 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1898 if (e.Buffer == null) {
1899 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
1901 e.socket_async_result.Buffers = e.BufferList;
1903 QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
1905 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
1907 e.socket_async_result.Buffer = e.Buffer;
1908 e.socket_async_result.Offset = e.Offset;
1909 e.socket_async_result.Size = e.Count;
1911 QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
1917 static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
1918 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1920 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1921 throw new InvalidOperationException ("No operation in progress");
1924 e.BytesTransferred = e.current_socket.EndSend (ares);
1925 } catch (SocketException se){
1926 e.SocketError = se.SocketErrorCode;
1927 } catch (ObjectDisposedException) {
1928 e.SocketError = SocketError.OperationAborted;
1934 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1936 ThrowIfDisposedAndClosed ();
1937 ThrowIfBufferNull (buffer);
1938 ThrowIfBufferOutOfRange (buffer, offset, size);
1940 if (!is_connected) {
1941 errorCode = SocketError.NotConnected;
1945 errorCode = SocketError.Success;
1947 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
1951 SockFlags = socketFlags,
1954 QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
1959 static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
1964 total = Socket.Send_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error, false);
1965 } catch (Exception e) {
1966 sockares.Complete (e);
1970 if (sockares.error == 0) {
1971 sent_so_far += total;
1972 sockares.Offset += total;
1973 sockares.Size -= total;
1975 if (sockares.socket.CleanedUp) {
1976 sockares.Complete (total);
1980 if (sockares.Size > 0) {
1981 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
1982 return; // Have to finish writing everything. See bug #74475.
1985 sockares.Total = sent_so_far;
1988 sockares.Complete (total);
1991 [CLSCompliant (false)]
1992 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1994 ThrowIfDisposedAndClosed ();
1996 if (buffers == null)
1997 throw new ArgumentNullException ("buffers");
1999 if (!is_connected) {
2000 errorCode = SocketError.NotConnected;
2004 errorCode = SocketError.Success;
2006 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
2008 SockFlags = socketFlags,
2011 QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
2016 static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
2017 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2021 total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
2022 } catch (Exception e) {
2023 sockares.Complete (e);
2027 sockares.Complete (total);
2030 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
2032 ThrowIfDisposedAndClosed ();
2034 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
2036 if (!sockares.IsCompleted)
2037 sockares.AsyncWaitHandle.WaitOne ();
2039 errorCode = sockares.ErrorCode;
2041 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress)
2042 is_connected = false;
2044 /* If no socket error occurred, call CheckIfThrowDelayedException in
2045 * case there are other kinds of exceptions that should be thrown.*/
2046 if (errorCode == SocketError.Success)
2047 sockares.CheckIfThrowDelayedException ();
2049 return sockares.Total;
2052 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking)
2055 safeHandle.RegisterForBlockingSyscall ();
2056 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error, blocking);
2058 safeHandle.UnRegisterForBlockingSyscall ();
2062 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2063 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking);
2065 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error, bool blocking)
2068 safeHandle.RegisterForBlockingSyscall ();
2069 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error, blocking);
2071 safeHandle.UnRegisterForBlockingSyscall ();
2075 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2076 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error, bool blocking);
2082 public int SendTo (byte [] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP)
2084 ThrowIfDisposedAndClosed ();
2085 ThrowIfBufferNull (buffer);
2086 ThrowIfBufferOutOfRange (buffer, offset, size);
2088 if (remoteEP == null)
2089 throw new ArgumentNullException("remoteEP");
2092 int ret = SendTo_internal (m_Handle, buffer, offset, size, socketFlags, remoteEP.Serialize (), out error, is_blocking);
2094 SocketError err = (SocketError) error;
2096 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2097 is_connected = false;
2098 throw new SocketException (error);
2101 is_connected = true;
2103 seed_endpoint = remoteEP;
2108 public bool SendToAsync (SocketAsyncEventArgs e)
2110 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2112 ThrowIfDisposedAndClosed ();
2114 if (e.BufferList != null)
2115 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2116 if (e.RemoteEndPoint == null)
2117 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2119 InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2121 e.socket_async_result.Buffer = e.Buffer;
2122 e.socket_async_result.Offset = e.Offset;
2123 e.socket_async_result.Size = e.Count;
2124 e.socket_async_result.SockFlags = e.SocketFlags;
2125 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2127 QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2132 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2133 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2135 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2136 throw new InvalidOperationException ("No operation in progress");
2139 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2140 } catch (SocketException ex) {
2141 e.SocketError = ex.SocketErrorCode;
2142 } catch (ObjectDisposedException) {
2143 e.SocketError = SocketError.OperationAborted;
2149 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2151 ThrowIfDisposedAndClosed ();
2152 ThrowIfBufferNull (buffer);
2153 ThrowIfBufferOutOfRange (buffer, offset, size);
2155 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2159 SockFlags = socket_flags,
2160 EndPoint = remote_end,
2163 QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2168 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2172 total = sockares.socket.SendTo (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2174 if (sockares.error == 0) {
2175 sent_so_far += total;
2176 sockares.Offset += total;
2177 sockares.Size -= total;
2180 if (sockares.Size > 0) {
2181 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2182 return; // Have to finish writing everything. See bug #74475.
2185 sockares.Total = sent_so_far;
2186 } catch (Exception e) {
2187 sockares.Complete (e);
2191 sockares.Complete ();
2194 public int EndSendTo (IAsyncResult result)
2196 ThrowIfDisposedAndClosed ();
2198 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2200 if (!sockares.IsCompleted)
2201 sockares.AsyncWaitHandle.WaitOne();
2203 sockares.CheckIfThrowDelayedException();
2205 return sockares.Total;
2208 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking)
2211 safeHandle.RegisterForBlockingSyscall ();
2212 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error, blocking);
2214 safeHandle.UnRegisterForBlockingSyscall ();
2218 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2219 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking);
2225 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2227 ThrowIfDisposedAndClosed ();
2230 throw new NotSupportedException ();
2232 throw new InvalidOperationException ();
2235 if (!SendFile_internal (m_Handle, fileName, preBuffer, postBuffer, flags, out error, is_blocking) || error != 0) {
2236 SocketException exc = new SocketException (error);
2237 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2238 throw new FileNotFoundException ();
2243 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2245 ThrowIfDisposedAndClosed ();
2248 throw new NotSupportedException ();
2249 if (!File.Exists (fileName))
2250 throw new FileNotFoundException ();
2252 SendFileHandler handler = new SendFileHandler (SendFile);
2254 return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2257 public void EndSendFile (IAsyncResult asyncResult)
2259 ThrowIfDisposedAndClosed ();
2261 if (asyncResult == null)
2262 throw new ArgumentNullException ("asyncResult");
2264 SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2266 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2268 ares.Delegate.EndInvoke (ares.Original);
2271 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags, out int error, bool blocking)
2274 safeHandle.RegisterForBlockingSyscall ();
2275 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags, out error, blocking);
2277 safeHandle.UnRegisterForBlockingSyscall ();
2281 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2282 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags, out int error, bool blocking);
2284 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2286 sealed class SendFileAsyncResult : IAsyncResult {
2290 public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2296 public object AsyncState {
2297 get { return ares.AsyncState; }
2300 public WaitHandle AsyncWaitHandle {
2301 get { return ares.AsyncWaitHandle; }
2304 public bool CompletedSynchronously {
2305 get { return ares.CompletedSynchronously; }
2308 public bool IsCompleted {
2309 get { return ares.IsCompleted; }
2312 public SendFileHandler Delegate {
2316 public IAsyncResult Original {
2317 get { return ares; }
2325 [MonoTODO ("Not implemented")]
2326 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2328 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2330 ThrowIfDisposedAndClosed ();
2332 throw new NotImplementedException ();
2337 #region DuplicateAndClose
2339 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2340 public SocketInformation DuplicateAndClose (int targetProcessId)
2342 var si = new SocketInformation ();
2344 (is_listening ? SocketInformationOptions.Listening : 0) |
2345 (is_connected ? SocketInformationOptions.Connected : 0) |
2346 (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
2347 (useOverlappedIO ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
2349 si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)addressFamily, (int)socketType, (int)protocolType, is_bound ? 1 : 0, (long)Handle);
2357 #region GetSocketOption
2359 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2361 ThrowIfDisposedAndClosed ();
2363 if (optionValue == null)
2364 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2367 GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref optionValue, out error);
2370 throw new SocketException (error);
2373 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength)
2375 ThrowIfDisposedAndClosed ();
2378 byte[] byte_val = new byte [optionLength];
2379 GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref byte_val, out error);
2382 throw new SocketException (error);
2387 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
2389 ThrowIfDisposedAndClosed ();
2393 GetSocketOption_obj_internal (m_Handle, optionLevel, optionName, out obj_val, out error);
2396 throw new SocketException (error);
2398 if (optionName == SocketOptionName.Linger)
2399 return (LingerOption) obj_val;
2400 else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
2401 return (MulticastOption) obj_val;
2402 else if (obj_val is int)
2403 return (int) obj_val;
2408 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
2410 bool release = false;
2412 safeHandle.DangerousAddRef (ref release);
2413 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
2416 safeHandle.DangerousRelease ();
2420 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2421 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
2423 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
2425 bool release = false;
2427 safeHandle.DangerousAddRef (ref release);
2428 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
2431 safeHandle.DangerousRelease ();
2435 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2436 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
2440 #region SetSocketOption
2442 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2444 ThrowIfDisposedAndClosed ();
2446 // I'd throw an ArgumentNullException, but this is what MS does.
2447 if (optionValue == null)
2448 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2451 SetSocketOption_internal (m_Handle, optionLevel, optionName, null, optionValue, 0, out error);
2454 if (error == (int) SocketError.InvalidArgument)
2455 throw new ArgumentException ();
2456 throw new SocketException (error);
2460 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
2462 ThrowIfDisposedAndClosed ();
2464 // NOTE: if a null is passed, the byte[] overload is used instead...
2465 if (optionValue == null)
2466 throw new ArgumentNullException("optionValue");
2470 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
2471 LingerOption linger = optionValue as LingerOption;
2473 throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
2474 SetSocketOption_internal (m_Handle, optionLevel, optionName, linger, null, 0, out error);
2475 } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2476 MulticastOption multicast = optionValue as MulticastOption;
2477 if (multicast == null)
2478 throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
2479 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2480 } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2481 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
2482 if (multicast == null)
2483 throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
2484 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2486 throw new ArgumentException ("Invalid value specified.", "optionValue");
2490 if (error == (int) SocketError.InvalidArgument)
2491 throw new ArgumentException ();
2492 throw new SocketException (error);
2496 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
2498 int int_val = optionValue ? 1 : 0;
2500 SetSocketOption (optionLevel, optionName, int_val);
2503 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
2505 ThrowIfDisposedAndClosed ();
2507 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse (protocolType))
2508 throw new SocketException ((int) SocketError.OperationNotSupported, "Operating system sockets do not support ReuseAddress.\nIf your socket is not intended to bind to the same address and port multiple times remove this option, otherwise you should ignore this exception inside a try catch and check that ReuseAddress is true before binding to the same address and port multiple times.");
2511 SetSocketOption_internal (m_Handle, optionLevel, optionName, null, null, optionValue, out error);
2514 if (error == (int) SocketError.InvalidArgument)
2515 throw new ArgumentException ();
2516 throw new SocketException (error);
2520 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
2522 bool release = false;
2524 safeHandle.DangerousAddRef (ref release);
2525 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
2528 safeHandle.DangerousRelease ();
2532 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2533 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
2539 public int IOControl (int ioControlCode, byte [] optionInValue, byte [] optionOutValue)
2542 throw new ObjectDisposedException (GetType ().ToString ());
2545 int result = IOControl_internal (m_Handle, ioControlCode, optionInValue, optionOutValue, out error);
2548 throw new SocketException (error);
2550 throw new InvalidOperationException ("Must use Blocking property instead.");
2555 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
2557 bool release = false;
2559 safeHandle.DangerousAddRef (ref release);
2560 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
2563 safeHandle.DangerousRelease ();
2567 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
2568 * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
2569 * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
2570 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2571 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
2577 public void Close ()
2583 public void Close (int timeout)
2585 linger_timeout = timeout;
2589 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2590 internal extern static void Close_internal (IntPtr socket, out int error);
2596 public void Shutdown (SocketShutdown how)
2598 ThrowIfDisposedAndClosed ();
2601 throw new SocketException (10057); // Not connected
2604 Shutdown_internal (m_Handle, how, out error);
2607 throw new SocketException (error);
2610 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
2612 bool release = false;
2614 safeHandle.DangerousAddRef (ref release);
2615 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
2618 safeHandle.DangerousRelease ();
2622 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2623 internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
2629 protected virtual void Dispose (bool disposing)
2635 bool was_connected = is_connected;
2636 is_connected = false;
2638 if (m_Handle != null) {
2645 m_Handle.Dispose ();
2649 void Linger (IntPtr handle)
2651 if (!is_connected || linger_timeout <= 0)
2654 /* We don't want to receive any more data */
2656 Shutdown_internal (handle, SocketShutdown.Receive, out error);
2661 int seconds = linger_timeout / 1000;
2662 int ms = linger_timeout % 1000;
2664 /* If the other end closes, this will return 'true' with 'Available' == 0 */
2665 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
2671 LingerOption linger = new LingerOption (true, seconds);
2672 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
2673 /* Not needed, we're closing upon return */
2681 void ThrowIfDisposedAndClosed (Socket socket)
2683 if (socket.CleanedUp && socket.is_closed)
2684 throw new ObjectDisposedException (socket.GetType ().ToString ());
2687 void ThrowIfDisposedAndClosed ()
2689 if (CleanedUp && is_closed)
2690 throw new ObjectDisposedException (GetType ().ToString ());
2693 void ThrowIfBufferNull (byte[] buffer)
2696 throw new ArgumentNullException ("buffer");
2699 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
2702 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
2703 if (offset > buffer.Length)
2704 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
2706 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
2707 if (size > buffer.Length - offset)
2708 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
2713 if (protocolType == ProtocolType.Udp)
2714 throw new SocketException ((int)SocketError.ProtocolOption);
2717 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
2720 throw new ArgumentNullException (argName);
2722 SocketAsyncResult sockares = ares as SocketAsyncResult;
2723 if (sockares == null)
2724 throw new ArgumentException ("Invalid IAsyncResult", argName);
2725 if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
2726 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
2731 void QueueIOSelectorJob (SemaphoreSlim sem, IntPtr handle, IOSelectorJob job)
2733 sem.WaitAsync ().ContinueWith (t => {
2735 job.MarkDisposed ();
2739 IOSelector.Add (handle, job);
2743 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
2745 e.socket_async_result.Init (this, callback, state, operation);
2746 if (e.AcceptSocket != null) {
2747 e.socket_async_result.AcceptSocket = e.AcceptSocket;
2749 e.current_socket = this;
2750 e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
2751 e.SocketError = SocketError.Success;
2752 e.BytesTransferred = 0;
2755 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
2758 case SocketOperation.Connect:
2759 return SocketAsyncOperation.Connect;
2760 case SocketOperation.Accept:
2761 return SocketAsyncOperation.Accept;
2762 case SocketOperation.Disconnect:
2763 return SocketAsyncOperation.Disconnect;
2764 case SocketOperation.Receive:
2765 case SocketOperation.ReceiveGeneric:
2766 return SocketAsyncOperation.Receive;
2767 case SocketOperation.ReceiveFrom:
2768 return SocketAsyncOperation.ReceiveFrom;
2769 case SocketOperation.Send:
2770 case SocketOperation.SendGeneric:
2771 return SocketAsyncOperation.Send;
2772 case SocketOperation.SendTo:
2773 return SocketAsyncOperation.SendTo;
2775 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
2779 IPEndPoint RemapIPEndPoint (IPEndPoint input) {
2780 // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
2781 if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
2782 return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
2787 [StructLayout (LayoutKind.Sequential)]
2793 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2794 internal static extern void cancel_blocking_socket_operation (Thread thread);
2796 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2797 internal static extern bool SupportsPortReuse (ProtocolType proto);
2799 internal static int FamilyHint {
2802 // MONO_HINT_UNSPECIFIED = 0,
2803 // MONO_HINT_IPV4 = 1,
2804 // MONO_HINT_IPV6 = 2,
2807 if (OSSupportsIPv4) {
2811 if (OSSupportsIPv6) {
2812 hint = hint == 0 ? 2 : 0;
2819 static bool IsProtocolSupported (NetworkInterfaceComponent networkInterface)
2824 var nics = NetworkInterface.GetAllNetworkInterfaces ();
2825 foreach (var adapter in nics) {
2826 if (adapter.Supports (networkInterface))