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";
59 * These two fields are looked up by name by the runtime, don't change
60 * their name without also updating the runtime code.
62 static int ipv4_supported = -1;
63 static int ipv6_supported = -1;
65 /* true if we called Close_internal */
69 bool use_overlapped_io;
73 AddressFamily address_family;
74 SocketType socket_type;
75 ProtocolType protocol_type;
77 /* the field "safe_handle" is looked up by name by the runtime */
78 internal SafeSocketHandle safe_handle;
81 * This EndPoint is used when creating new endpoints. Because
82 * there are many types of EndPoints possible,
83 * seed_endpoint.Create(addr) is used for creating new ones.
84 * As such, this value is set on Bind, SentTo, ReceiveFrom,
87 internal EndPoint seed_endpoint = null;
89 internal Queue<KeyValuePair<IntPtr, IOSelectorJob>> readQ = new Queue<KeyValuePair<IntPtr, IOSelectorJob>> (2);
90 internal Queue<KeyValuePair<IntPtr, IOSelectorJob>> writeQ = new Queue<KeyValuePair<IntPtr, IOSelectorJob>> (2);
92 internal bool is_blocking = true;
93 internal bool is_bound;
95 /* When true, the socket was connected at the time of the last IO operation */
96 internal bool is_connected;
98 internal bool is_disposed;
99 internal bool connect_in_progress;
105 if (ipv4_supported == -1) {
107 Socket tmp = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
116 if (ipv6_supported == -1) {
117 // We need to put a try/catch around ConfigurationManager methods as will always throw an exception
118 // when run in a mono embedded application. This occurs as embedded applications do not have a setup
119 // for application config. The exception is not thrown when called from a normal .NET application.
121 // We, then, need to guard calls to the ConfigurationManager. If the config is not found or throws an
122 // exception, will fall through to the existing Socket / API directly below in the code.
124 // Also note that catching ConfigurationErrorsException specifically would require library dependency
125 // System.Configuration, and wanted to avoid that.
127 #if CONFIGURATION_DEP
129 SettingsSection config;
130 config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
132 ipv6_supported = config.Ipv6.Enabled ? -1 : 0;
138 NetConfig config = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig;
140 ipv6_supported = config.ipv6Enabled ? -1 : 0;
146 if (ipv6_supported != 0) {
148 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
160 // This constructor is used by servers that want to listen for instance on both
161 // ipv4 and ipv6. Mono has historically done that if you use InterNetworkV6 (at
162 // least on Unix), because that is the default behavior unless the IPV6_V6ONLY
163 // option is explicitly set by using setsockopt (sock, IPPROTO_IPV6, IPV6_ONLY)
165 public Socket (SocketType socketType, ProtocolType protocolType)
166 : this (AddressFamily.InterNetworkV6, socketType, protocolType)
171 public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
173 this.address_family = addressFamily;
174 this.socket_type = socketType;
175 this.protocol_type = protocolType;
178 this.safe_handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
181 throw new SocketException (error);
187 public Socket (SocketInformation socketInformation)
189 this.is_listening = (socketInformation.Options & SocketInformationOptions.Listening) != 0;
190 this.is_connected = (socketInformation.Options & SocketInformationOptions.Connected) != 0;
191 this.is_blocking = (socketInformation.Options & SocketInformationOptions.NonBlocking) == 0;
192 this.use_overlapped_io = (socketInformation.Options & SocketInformationOptions.UseOnlyOverlappedIO) != 0;
194 var result = Mono.DataConverter.Unpack ("iiiil", socketInformation.ProtocolInformation, 0);
196 this.address_family = (AddressFamily) (int) result [0];
197 this.socket_type = (SocketType) (int) result [1];
198 this.protocol_type = (ProtocolType) (int) result [2];
199 this.is_bound = (ProtocolType) (int) result [3] != 0;
200 this.safe_handle = new SafeSocketHandle ((IntPtr) (long) result [4], true);
206 /* private constructor used by Accept, which already has a socket handle to use */
207 internal Socket(AddressFamily family, SocketType type, ProtocolType proto, SafeSocketHandle safe_handle)
209 this.address_family = family;
210 this.socket_type = type;
211 this.protocol_type = proto;
213 this.safe_handle = safe_handle;
214 this.is_connected = true;
222 void SocketDefaults ()
225 /* Need to test IPv6 further */
226 if (address_family == AddressFamily.InterNetwork
227 // || address_family == AddressFamily.InterNetworkV6
229 /* This is the default, but it probably has nasty side
230 * effects on Linux, as the socket option is kludged by
231 * turning on or off PMTU discovery... */
232 this.DontFragment = false;
233 if (protocol_type == ProtocolType.Tcp)
234 this.NoDelay = false;
235 } else if (address_family == AddressFamily.InterNetworkV6) {
236 this.DualMode = true;
239 /* Microsoft sets these to 8192, but we are going to keep them
240 * both to the OS defaults as these have a big performance impact.
241 * on WebClient performance. */
242 // this.ReceiveBufferSize = 8192;
243 // this.SendBufferSize = 8192;
244 } catch (SocketException) {
248 /* Creates a new system socket, returning the handle */
249 [MethodImplAttribute(MethodImplOptions.InternalCall)]
250 extern IntPtr Socket_internal (AddressFamily family, SocketType type, ProtocolType proto, out int error);
256 [ObsoleteAttribute ("Use OSSupportsIPv4 instead")]
257 public static bool SupportsIPv4 {
258 get { return ipv4_supported == 1; }
261 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
262 public static bool SupportsIPv6 {
263 get { return ipv6_supported == 1; }
267 public static bool OSSupportsIPv4 {
268 get { return ipv4_supported == 1; }
271 public static bool OSSupportsIPv4 {
273 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
275 foreach (NetworkInterface adapter in nics) {
276 if (adapter.Supports (NetworkInterfaceComponent.IPv4))
286 public static bool OSSupportsIPv6 {
287 get { return ipv6_supported == 1; }
290 public static bool OSSupportsIPv6 {
292 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
294 foreach (NetworkInterface adapter in nics) {
295 if (adapter.Supports (NetworkInterfaceComponent.IPv6))
304 public int Available {
306 ThrowIfDisposedAndClosed ();
309 ret = Available_internal (safe_handle, out error);
312 throw new SocketException (error);
318 static int Available_internal (SafeSocketHandle safeHandle, out int error)
320 bool release = false;
322 safeHandle.DangerousAddRef (ref release);
323 return Available_internal (safeHandle.DangerousGetHandle (), out error);
326 safeHandle.DangerousRelease ();
330 /* Returns the amount of data waiting to be read on socket */
331 [MethodImplAttribute(MethodImplOptions.InternalCall)]
332 extern static int Available_internal (IntPtr socket, out int error);
334 public bool DontFragment {
336 ThrowIfDisposedAndClosed ();
338 switch (address_family) {
339 case AddressFamily.InterNetwork:
340 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment)) != 0;
341 case AddressFamily.InterNetworkV6:
342 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment)) != 0;
344 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
348 ThrowIfDisposedAndClosed ();
350 switch (address_family) {
351 case AddressFamily.InterNetwork:
352 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
354 case AddressFamily.InterNetworkV6:
355 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment, value ? 1 : 0);
358 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
363 public bool EnableBroadcast {
365 ThrowIfDisposedAndClosed ();
367 if (protocol_type != ProtocolType.Udp)
368 throw new SocketException ((int) SocketError.ProtocolOption);
370 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0;
373 ThrowIfDisposedAndClosed ();
375 if (protocol_type != ProtocolType.Udp)
376 throw new SocketException ((int) SocketError.ProtocolOption);
378 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
382 public bool ExclusiveAddressUse {
384 ThrowIfDisposedAndClosed ();
386 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse)) != 0;
389 ThrowIfDisposedAndClosed ();
392 throw new InvalidOperationException ("Bind has already been called for this socket");
394 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
398 public bool IsBound {
404 public LingerOption LingerState {
406 ThrowIfDisposedAndClosed ();
408 return (LingerOption) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger);
411 ThrowIfDisposedAndClosed ();
412 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger, value);
416 public bool MulticastLoopback {
418 ThrowIfDisposedAndClosed ();
420 /* Even though this option can be set for TCP sockets on Linux, throw
421 * this exception anyway to be compatible (the MSDN docs say
422 * "Setting this property on a Transmission Control Protocol (TCP)
423 * socket will have no effect." but the MS runtime throws the
425 if (protocol_type == ProtocolType.Tcp)
426 throw new SocketException ((int)SocketError.ProtocolOption);
428 switch (address_family) {
429 case AddressFamily.InterNetwork:
430 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
431 case AddressFamily.InterNetworkV6:
432 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
434 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
438 ThrowIfDisposedAndClosed ();
440 /* Even though this option can be set for TCP sockets on Linux, throw
441 * this exception anyway to be compatible (the MSDN docs say
442 * "Setting this property on a Transmission Control Protocol (TCP)
443 * socket will have no effect." but the MS runtime throws the
445 if (protocol_type == ProtocolType.Tcp)
446 throw new SocketException ((int)SocketError.ProtocolOption);
448 switch (address_family) {
449 case AddressFamily.InterNetwork:
450 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
452 case AddressFamily.InterNetworkV6:
453 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
456 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
461 public bool DualMode {
463 if (AddressFamily != AddressFamily.InterNetworkV6)
464 throw new NotSupportedException("This protocol version is not supported");
466 return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only) == 0);
469 if (AddressFamily != AddressFamily.InterNetworkV6)
470 throw new NotSupportedException("This protocol version is not supported");
472 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1);
476 private bool IsDualMode {
478 return AddressFamily == AddressFamily.InterNetworkV6 && DualMode;
482 [MonoTODO ("This doesn't do anything on Mono yet")]
483 public bool UseOnlyOverlappedIO {
484 get { return use_overlapped_io; }
485 set { use_overlapped_io = value; }
488 public IntPtr Handle {
489 get { return safe_handle.DangerousGetHandle (); }
492 // Wish: support non-IP endpoints.
493 public EndPoint LocalEndPoint {
495 ThrowIfDisposedAndClosed ();
497 /* If the seed EndPoint is null, Connect, Bind, etc has not yet
498 * been called. MS returns null in this case. */
499 if (seed_endpoint == null)
503 SocketAddress sa = LocalEndPoint_internal (safe_handle, (int) address_family, out error);
506 throw new SocketException (error);
508 return seed_endpoint.Create (sa);
512 static SocketAddress LocalEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
514 bool release = false;
516 safeHandle.DangerousAddRef (ref release);
517 return LocalEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
520 safeHandle.DangerousRelease ();
524 /* Returns the local endpoint details in addr and port */
525 [MethodImplAttribute(MethodImplOptions.InternalCall)]
526 extern static SocketAddress LocalEndPoint_internal (IntPtr socket, int family, out int error);
528 public SocketType SocketType {
529 get { return socket_type; }
532 public int SendTimeout {
534 ThrowIfDisposedAndClosed ();
536 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
539 ThrowIfDisposedAndClosed ();
542 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
544 /* According to the MSDN docs we should adjust values between 1 and
545 * 499 to 500, but the MS runtime doesn't do this. */
549 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
553 public int ReceiveTimeout {
555 ThrowIfDisposedAndClosed ();
557 return (int) GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
560 ThrowIfDisposedAndClosed ();
563 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
568 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, value);
572 public AddressFamily AddressFamily {
573 get { return address_family; }
576 public bool Blocking {
577 get { return is_blocking; }
579 ThrowIfDisposedAndClosed ();
582 Blocking_internal (safe_handle, value, out error);
585 throw new SocketException (error);
591 static void Blocking_internal (SafeSocketHandle safeHandle, bool block, out int error)
593 bool release = false;
595 safeHandle.DangerousAddRef (ref release);
596 Blocking_internal (safeHandle.DangerousGetHandle (), block, out error);
599 safeHandle.DangerousRelease ();
603 [MethodImplAttribute(MethodImplOptions.InternalCall)]
604 internal extern static void Blocking_internal(IntPtr socket, bool block, out int error);
606 public bool Connected {
607 get { return is_connected; }
608 internal set { is_connected = value; }
611 public ProtocolType ProtocolType {
612 get { return protocol_type; }
615 public bool NoDelay {
617 ThrowIfDisposedAndClosed ();
620 return ((int) GetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay)) != 0;
624 ThrowIfDisposedAndClosed ();
626 SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
630 public int ReceiveBufferSize {
632 ThrowIfDisposedAndClosed ();
634 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer);
637 ThrowIfDisposedAndClosed ();
640 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
642 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
646 public int SendBufferSize {
648 ThrowIfDisposedAndClosed ();
650 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer);
653 ThrowIfDisposedAndClosed ();
656 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
658 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer, value);
664 ThrowIfDisposedAndClosed ();
666 switch (address_family) {
667 case AddressFamily.InterNetwork:
668 return (short) (int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
669 case AddressFamily.InterNetworkV6:
670 return (short) (int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit);
672 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
676 ThrowIfDisposedAndClosed ();
678 if (value < 0 || value > 255)
679 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero or greater than 255.");
681 switch (address_family) {
682 case AddressFamily.InterNetwork:
683 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
685 case AddressFamily.InterNetworkV6:
686 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
689 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
694 public EndPoint RemoteEndPoint {
696 ThrowIfDisposedAndClosed ();
698 /* If the seed EndPoint is null, Connect, Bind, etc has
699 * not yet been called. MS returns null in this case. */
700 if (!is_connected || seed_endpoint == null)
704 SocketAddress sa = RemoteEndPoint_internal (safe_handle, (int) address_family, out error);
707 throw new SocketException (error);
709 return seed_endpoint.Create (sa);
713 static SocketAddress RemoteEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
715 bool release = false;
717 safeHandle.DangerousAddRef (ref release);
718 return RemoteEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
721 safeHandle.DangerousRelease ();
725 /* Returns the remote endpoint details in addr and port */
726 [MethodImplAttribute(MethodImplOptions.InternalCall)]
727 extern static SocketAddress RemoteEndPoint_internal (IntPtr socket, int family, out int error);
733 public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
735 var list = new List<Socket> ();
736 AddSockets (list, checkRead, "checkRead");
737 AddSockets (list, checkWrite, "checkWrite");
738 AddSockets (list, checkError, "checkError");
741 throw new ArgumentNullException ("checkRead, checkWrite, checkError", "All the lists are null or empty.");
743 /* The 'sockets' array contains:
744 * - READ socket 0-n, null,
745 * - WRITE socket 0-n, null,
746 * - ERROR socket 0-n, null */
747 Socket [] sockets = list.ToArray ();
750 Select_internal (ref sockets, microSeconds, out error);
753 throw new SocketException (error);
755 if (sockets == null) {
756 if (checkRead != null)
758 if (checkWrite != null)
760 if (checkError != null)
766 int count = sockets.Length;
767 IList currentList = checkRead;
769 for (int i = 0; i < count; i++) {
770 Socket sock = sockets [i];
771 if (sock == null) { // separator
772 if (currentList != null) {
773 // Remove non-signaled sockets after the current one
774 int to_remove = currentList.Count - currentIdx;
775 for (int k = 0; k < to_remove; k++)
776 currentList.RemoveAt (currentIdx);
778 currentList = (mode == 0) ? checkWrite : checkError;
784 if (mode == 1 && currentList == checkWrite && !sock.is_connected) {
785 if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
786 sock.is_connected = true;
789 /* Remove non-signaled sockets before the current one */
790 while (((Socket) currentList [currentIdx]) != sock)
791 currentList.RemoveAt (currentIdx);
797 static void AddSockets (List<Socket> sockets, IList list, string name)
800 foreach (Socket sock in list) {
801 if (sock == null) // MS throws a NullRef
802 throw new ArgumentNullException ("name", "Contains a null element");
810 [MethodImplAttribute(MethodImplOptions.InternalCall)]
811 extern static void Select_internal (ref Socket [] sockets, int microSeconds, out int error);
817 public bool Poll (int microSeconds, SelectMode mode)
819 ThrowIfDisposedAndClosed ();
821 if (mode != SelectMode.SelectRead && mode != SelectMode.SelectWrite && mode != SelectMode.SelectError)
822 throw new NotSupportedException ("'mode' parameter is not valid.");
825 bool result = Poll_internal (safe_handle, mode, microSeconds, out error);
828 throw new SocketException (error);
830 if (mode == SelectMode.SelectWrite && result && !is_connected) {
831 /* Update the is_connected state; for non-blocking Connect()
832 * this is when we can find out that the connect succeeded. */
833 if ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
840 static bool Poll_internal (SafeSocketHandle safeHandle, SelectMode mode, int timeout, out int error)
842 bool release = false;
844 safeHandle.DangerousAddRef (ref release);
845 return Poll_internal (safeHandle.DangerousGetHandle (), mode, timeout, out error);
848 safeHandle.DangerousRelease ();
852 [MethodImplAttribute(MethodImplOptions.InternalCall)]
853 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
859 public Socket Accept()
861 ThrowIfDisposedAndClosed ();
864 SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
868 error = SOCKET_CLOSED_CODE;
869 throw new SocketException(error);
872 Socket accepted = new Socket (this.AddressFamily, this.SocketType, this.ProtocolType, safe_handle) {
873 seed_endpoint = this.seed_endpoint,
874 Blocking = this.Blocking,
880 internal void Accept (Socket acceptSocket)
882 ThrowIfDisposedAndClosed ();
885 SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
889 error = SOCKET_CLOSED_CODE;
890 throw new SocketException (error);
893 acceptSocket.address_family = this.AddressFamily;
894 acceptSocket.socket_type = this.SocketType;
895 acceptSocket.protocol_type = this.ProtocolType;
896 acceptSocket.safe_handle = safe_handle;
897 acceptSocket.is_connected = true;
898 acceptSocket.seed_endpoint = this.seed_endpoint;
899 acceptSocket.Blocking = this.Blocking;
901 // FIXME: figure out what if anything else needs to be reset
904 public bool AcceptAsync (SocketAsyncEventArgs e)
906 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
908 ThrowIfDisposedAndClosed ();
911 throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
913 throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
914 if (e.BufferList != null)
915 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
917 throw new ArgumentOutOfRangeException ("e.Count");
919 Socket acceptSocket = e.AcceptSocket;
920 if (acceptSocket != null) {
921 if (acceptSocket.is_bound || acceptSocket.is_connected)
922 throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
925 InitSocketAsyncEventArgs (e, AcceptAsyncCallback, e, SocketOperation.Accept);
927 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, e.socket_async_result));
932 static AsyncCallback AcceptAsyncCallback = new AsyncCallback (ares => {
933 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
935 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
936 throw new InvalidOperationException ("No operation in progress");
939 e.AcceptSocket = e.current_socket.EndAccept (ares);
940 } catch (SocketException ex) {
941 e.SocketError = ex.SocketErrorCode;
942 } catch (ObjectDisposedException) {
943 e.SocketError = SocketError.OperationAborted;
945 if (e.AcceptSocket == null)
946 e.AcceptSocket = new Socket (e.current_socket.AddressFamily, e.current_socket.SocketType, e.current_socket.ProtocolType, null);
951 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
953 ThrowIfDisposedAndClosed ();
955 if (!is_bound || !is_listening)
956 throw new InvalidOperationException ();
958 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Accept);
960 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, sockares));
965 static IOAsyncCallback BeginAcceptCallback = new IOAsyncCallback (ares => {
966 SocketAsyncResult sockares = (SocketAsyncResult) ares;
967 Socket acc_socket = null;
969 if (sockares.AcceptSocket == null) {
970 acc_socket = sockares.socket.Accept ();
972 acc_socket = sockares.AcceptSocket;
973 sockares.socket.Accept (acc_socket);
976 } catch (Exception e) {
977 sockares.Complete (e);
980 sockares.Complete (acc_socket);
983 public IAsyncResult BeginAccept (int receiveSize, AsyncCallback callback, object state)
985 ThrowIfDisposedAndClosed ();
988 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
990 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
991 Buffer = new byte [receiveSize],
994 SockFlags = SocketFlags.None,
997 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
1002 public IAsyncResult BeginAccept (Socket acceptSocket, int receiveSize, AsyncCallback callback, object state)
1004 ThrowIfDisposedAndClosed ();
1006 if (receiveSize < 0)
1007 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
1009 if (acceptSocket != null) {
1010 ThrowIfDisposedAndClosed (acceptSocket);
1012 if (acceptSocket.IsBound)
1013 throw new InvalidOperationException ();
1015 /* For some reason the MS runtime
1016 * barfs if the new socket is not TCP,
1017 * even though it's just about to blow
1018 * away all those parameters
1020 if (acceptSocket.ProtocolType != ProtocolType.Tcp)
1021 throw new SocketException ((int)SocketError.InvalidArgument);
1024 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
1025 Buffer = new byte [receiveSize],
1028 SockFlags = SocketFlags.None,
1029 AcceptSocket = acceptSocket,
1032 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
1037 static IOAsyncCallback BeginAcceptReceiveCallback = new IOAsyncCallback (ares => {
1038 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1039 Socket acc_socket = null;
1042 if (sockares.AcceptSocket == null) {
1043 acc_socket = sockares.socket.Accept ();
1045 acc_socket = sockares.AcceptSocket;
1046 sockares.socket.Accept (acc_socket);
1048 } catch (Exception e) {
1049 sockares.Complete (e);
1053 /* It seems the MS runtime special-cases 0-length requested receive data. See bug 464201. */
1055 if (sockares.Size > 0) {
1058 total = acc_socket.Receive_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out error);
1060 sockares.Complete (new SocketException ((int) error));
1063 } catch (Exception e) {
1064 sockares.Complete (e);
1069 sockares.Complete (acc_socket, total);
1072 public Socket EndAccept (IAsyncResult result)
1076 return EndAccept (out buffer, out bytes, result);
1079 public Socket EndAccept (out byte[] buffer, IAsyncResult asyncResult)
1082 return EndAccept (out buffer, out bytes, asyncResult);
1085 public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
1087 ThrowIfDisposedAndClosed ();
1089 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndAccept", "asyncResult");
1091 if (!sockares.IsCompleted)
1092 sockares.AsyncWaitHandle.WaitOne ();
1094 sockares.CheckIfThrowDelayedException ();
1096 buffer = sockares.Buffer;
1097 bytesTransferred = sockares.Total;
1099 return sockares.AcceptedSocket;
1102 static SafeSocketHandle Accept_internal (SafeSocketHandle safeHandle, out int error, bool blocking)
1105 safeHandle.RegisterForBlockingSyscall ();
1106 var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
1107 return new SafeSocketHandle (ret, true);
1109 safeHandle.UnRegisterForBlockingSyscall ();
1113 /* Creates a new system socket, returning the handle */
1114 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1115 extern static IntPtr Accept_internal (IntPtr sock, out int error, bool blocking);
1121 public void Bind (EndPoint localEP)
1123 ThrowIfDisposedAndClosed ();
1125 if (localEP == null)
1126 throw new ArgumentNullException("localEP");
1128 var ipEndPoint = localEP as IPEndPoint;
1129 if (ipEndPoint != null) {
1130 localEP = RemapIPEndPoint (ipEndPoint);
1134 Bind_internal (safe_handle, localEP.Serialize(), out error);
1137 throw new SocketException (error);
1141 seed_endpoint = localEP;
1144 private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1146 bool release = false;
1148 safeHandle.DangerousAddRef (ref release);
1149 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
1152 safeHandle.DangerousRelease ();
1156 // Creates a new system socket, returning the handle
1157 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1158 private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
1164 public void Listen (int backlog)
1166 ThrowIfDisposedAndClosed ();
1169 throw new SocketException ((int) SocketError.InvalidArgument);
1172 Listen_internal(safe_handle, backlog, out error);
1175 throw new SocketException (error);
1177 is_listening = true;
1180 static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
1182 bool release = false;
1184 safeHandle.DangerousAddRef (ref release);
1185 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
1188 safeHandle.DangerousRelease ();
1192 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1193 extern static void Listen_internal (IntPtr sock, int backlog, out int error);
1199 public void Connect (IPAddress address, int port)
1201 Connect (new IPEndPoint (address, port));
1204 public void Connect (string host, int port)
1206 Connect (Dns.GetHostAddresses (host), port);
1209 public void Connect (IPAddress[] addresses, int port)
1211 ThrowIfDisposedAndClosed ();
1213 if (addresses == null)
1214 throw new ArgumentNullException ("addresses");
1215 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1216 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1218 throw new InvalidOperationException ();
1220 // FIXME: do non-blocking sockets Poll here?
1222 foreach (IPAddress address in addresses) {
1223 IPEndPoint iep = new IPEndPoint (address, port);
1225 iep = RemapIPEndPoint (iep);
1227 Connect_internal (safe_handle, iep.Serialize (), out error);
1229 is_connected = true;
1231 seed_endpoint = iep;
1234 if (error != (int)SocketError.InProgress && error != (int)SocketError.WouldBlock)
1238 Poll (-1, SelectMode.SelectWrite);
1239 error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1241 is_connected = true;
1243 seed_endpoint = iep;
1250 throw new SocketException (error);
1254 public void Connect (EndPoint remoteEP)
1256 ThrowIfDisposedAndClosed ();
1258 if (remoteEP == null)
1259 throw new ArgumentNullException ("remoteEP");
1261 IPEndPoint ep = remoteEP as IPEndPoint;
1262 /* Dgram uses Any to 'disconnect' */
1263 if (ep != null && socket_type != SocketType.Dgram) {
1264 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1265 throw new SocketException ((int) SocketError.AddressNotAvailable);
1269 throw new InvalidOperationException ();
1272 remoteEP = RemapIPEndPoint (ep);
1275 SocketAddress serial = remoteEP.Serialize ();
1278 Connect_internal (safe_handle, serial, out error);
1280 if (error == 0 || error == 10035)
1281 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1285 error = SOCKET_CLOSED_CODE;
1286 throw new SocketException (error);
1289 is_connected = !(socket_type == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
1293 public bool ConnectAsync (SocketAsyncEventArgs e)
1295 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1297 ThrowIfDisposedAndClosed ();
1300 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1301 if (e.RemoteEndPoint == null)
1302 throw new ArgumentNullException ("remoteEP");
1304 InitSocketAsyncEventArgs (e, null, e, SocketOperation.Connect);
1307 IPAddress [] addresses;
1308 SocketAsyncResult ares;
1310 if (!GetCheckedIPs (e, out addresses)) {
1311 e.socket_async_result.EndPoint = e.RemoteEndPoint;
1312 ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
1314 DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1315 e.socket_async_result.Addresses = addresses;
1316 e.socket_async_result.Port = dep.Port;
1317 ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
1320 if (ares.IsCompleted && ares.CompletedSynchronously) {
1321 ares.CheckIfThrowDelayedException ();
1324 } catch (Exception exc) {
1325 e.socket_async_result.Complete (exc, true);
1332 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
1334 var sock = new Socket (e.RemoteEndPoint.AddressFamily, socketType, protocolType);
1335 return sock.ConnectAsync (e);
1338 public static void CancelConnectAsync (SocketAsyncEventArgs e)
1341 throw new ArgumentNullException("e");
1343 if (e.in_progress != 0 && e.LastOperation == SocketAsyncOperation.Connect)
1344 e.current_socket.Close();
1347 static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
1348 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1350 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1351 throw new InvalidOperationException ("No operation in progress");
1354 e.current_socket.EndConnect (ares);
1355 } catch (SocketException se) {
1356 e.SocketError = se.SocketErrorCode;
1357 } catch (ObjectDisposedException) {
1358 e.SocketError = SocketError.OperationAborted;
1364 public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback callback, object state)
1366 ThrowIfDisposedAndClosed ();
1368 if (address == null)
1369 throw new ArgumentNullException ("address");
1370 if (address.ToString ().Length == 0)
1371 throw new ArgumentException ("The length of the IP address is zero");
1372 if (port <= 0 || port > 65535)
1373 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1375 throw new InvalidOperationException ();
1377 return BeginConnect (new IPEndPoint (address, port), callback, state);
1380 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
1382 ThrowIfDisposedAndClosed ();
1385 throw new ArgumentNullException ("host");
1386 if (address_family != AddressFamily.InterNetwork && address_family != AddressFamily.InterNetworkV6)
1387 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1388 if (port <= 0 || port > 65535)
1389 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1391 throw new InvalidOperationException ();
1393 return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1396 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
1398 ThrowIfDisposedAndClosed ();
1400 if (end_point == null)
1401 throw new ArgumentNullException ("end_point");
1403 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1404 EndPoint = end_point,
1407 // Bug #75154: Connect() should not succeed for .Any addresses.
1408 if (end_point is IPEndPoint) {
1409 IPEndPoint ep = (IPEndPoint) end_point;
1410 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1411 sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1415 end_point = RemapIPEndPoint (ep);
1420 if (connect_in_progress) {
1421 // This could happen when multiple IPs are used
1422 // Calling connect() again will reset the connection attempt and cause
1423 // an error. Better to just close the socket and move on.
1424 connect_in_progress = false;
1425 safe_handle.Dispose ();
1426 safe_handle = new SafeSocketHandle (Socket_internal (address_family, socket_type, protocol_type, out error), true);
1428 throw new SocketException (error);
1431 bool blk = is_blocking;
1434 Connect_internal (safe_handle, end_point.Serialize (), out error);
1440 is_connected = true;
1442 sockares.Complete (true);
1446 if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1448 is_connected = false;
1450 sockares.Complete (new SocketException (error), true);
1455 is_connected = false;
1457 connect_in_progress = true;
1459 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
1464 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1466 ThrowIfDisposedAndClosed ();
1468 if (addresses == null)
1469 throw new ArgumentNullException ("addresses");
1470 if (addresses.Length == 0)
1471 throw new ArgumentException ("Empty addresses list");
1472 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1473 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1474 if (port <= 0 || port > 65535)
1475 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1477 throw new InvalidOperationException ();
1479 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1480 Addresses = addresses,
1484 is_connected = false;
1486 return BeginMConnect (sockares);
1489 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1491 SocketAsyncResult ares = null;
1492 Exception exc = null;
1493 AsyncCallback callback;
1495 for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1497 sockares.CurrentAddress++;
1499 ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1500 if (ares.IsCompleted && ares.CompletedSynchronously) {
1501 ares.CheckIfThrowDelayedException ();
1503 callback = ares.AsyncCallback;
1504 if (callback != null)
1505 ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
1509 } catch (Exception e) {
1521 static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
1522 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1524 if (sockares.EndPoint == null) {
1525 sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
1529 SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
1530 bool is_mconnect = mconnect != null && mconnect.Addresses != null;
1533 EndPoint ep = sockares.EndPoint;
1534 int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1536 if (error_code == 0) {
1538 sockares = mconnect;
1540 sockares.socket.seed_endpoint = ep;
1541 sockares.socket.is_connected = true;
1542 sockares.socket.is_bound = true;
1543 sockares.socket.connect_in_progress = false;
1545 sockares.Complete ();
1550 sockares.socket.connect_in_progress = false;
1551 sockares.Complete (new SocketException (error_code));
1555 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
1556 mconnect.Complete (new SocketException (error_code));
1560 mconnect.socket.BeginMConnect (mconnect);
1561 } catch (Exception e) {
1562 sockares.socket.connect_in_progress = false;
1565 sockares = mconnect;
1567 sockares.Complete (e);
1572 public void EndConnect (IAsyncResult result)
1574 ThrowIfDisposedAndClosed ();
1576 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1578 if (!sockares.IsCompleted)
1579 sockares.AsyncWaitHandle.WaitOne();
1581 sockares.CheckIfThrowDelayedException();
1584 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1587 safeHandle.RegisterForBlockingSyscall ();
1588 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
1590 safeHandle.UnRegisterForBlockingSyscall ();
1594 /* Connects to the remote address */
1595 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1596 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error);
1599 * - false when it is ok to use RemoteEndPoint
1600 * - true when addresses must be used (and addresses could be null/empty) */
1601 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1605 // Connect to the first address that match the host name, like:
1606 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1607 // while skipping entries that do not match the address family
1608 DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1610 addresses = Dns.GetHostAddresses (dep.Host);
1613 e.ConnectByNameError = null;
1622 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1623 * if the platform is newer than w2k. We should be able to cope... */
1624 public void Disconnect (bool reuseSocket)
1626 ThrowIfDisposedAndClosed ();
1629 Disconnect_internal (safe_handle, reuseSocket, out error);
1633 /* ERROR_NOT_SUPPORTED */
1634 throw new PlatformNotSupportedException ();
1636 throw new SocketException (error);
1640 is_connected = false;
1642 /* Do managed housekeeping here... */
1646 public bool DisconnectAsync (SocketAsyncEventArgs e)
1648 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1650 ThrowIfDisposedAndClosed ();
1652 InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
1654 IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
1659 static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
1660 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1662 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1663 throw new InvalidOperationException ("No operation in progress");
1666 e.current_socket.EndDisconnect (ares);
1667 } catch (SocketException ex) {
1668 e.SocketError = ex.SocketErrorCode;
1669 } catch (ObjectDisposedException) {
1670 e.SocketError = SocketError.OperationAborted;
1676 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1678 ThrowIfDisposedAndClosed ();
1680 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1681 ReuseSocket = reuseSocket,
1684 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
1689 static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
1690 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1693 sockares.socket.Disconnect (sockares.ReuseSocket);
1694 } catch (Exception e) {
1695 sockares.Complete (e);
1699 sockares.Complete ();
1702 public void EndDisconnect (IAsyncResult asyncResult)
1704 ThrowIfDisposedAndClosed ();
1706 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1708 if (!sockares.IsCompleted)
1709 sockares.AsyncWaitHandle.WaitOne ();
1711 sockares.CheckIfThrowDelayedException ();
1714 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1716 bool release = false;
1718 safeHandle.DangerousAddRef (ref release);
1719 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1722 safeHandle.DangerousRelease ();
1726 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1727 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1733 public int Receive (byte [] buffer)
1735 return Receive (buffer, SocketFlags.None);
1738 public int Receive (byte [] buffer, SocketFlags socketFlags)
1740 ThrowIfDisposedAndClosed ();
1741 ThrowIfBufferNull (buffer);
1742 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
1745 int ret = Receive_nochecks (buffer, 0, buffer.Length, socketFlags, out error);
1747 if (error != SocketError.Success) {
1748 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1749 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1750 throw new SocketException ((int) error);
1756 public int Receive (byte [] buffer, int size, SocketFlags socketFlags)
1758 ThrowIfDisposedAndClosed ();
1759 ThrowIfBufferNull (buffer);
1760 ThrowIfBufferOutOfRange (buffer, 0, size);
1763 int ret = Receive_nochecks (buffer, 0, size, socketFlags, out error);
1765 if (error != SocketError.Success) {
1766 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1767 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1768 throw new SocketException ((int) error);
1774 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags)
1776 ThrowIfDisposedAndClosed ();
1777 ThrowIfBufferNull (buffer);
1778 ThrowIfBufferOutOfRange (buffer, offset, size);
1781 int ret = Receive_nochecks (buffer, offset, size, socketFlags, out error);
1783 if (error != SocketError.Success) {
1784 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1785 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1786 throw new SocketException ((int) error);
1792 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1794 ThrowIfDisposedAndClosed ();
1795 ThrowIfBufferNull (buffer);
1796 ThrowIfBufferOutOfRange (buffer, offset, size);
1798 return Receive_nochecks (buffer, offset, size, socketFlags, out errorCode);
1801 public int Receive (IList<ArraySegment<byte>> buffers)
1804 int ret = Receive (buffers, SocketFlags.None, out error);
1806 if (error != SocketError.Success)
1807 throw new SocketException ((int) error);
1812 [CLSCompliant (false)]
1813 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1816 int ret = Receive (buffers, socketFlags, out error);
1818 if (error != SocketError.Success)
1819 throw new SocketException ((int) error);
1824 [CLSCompliant (false)]
1825 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1827 ThrowIfDisposedAndClosed ();
1829 if (buffers == null || buffers.Count == 0)
1830 throw new ArgumentNullException ("buffers");
1832 int numsegments = buffers.Count;
1836 /* Only example I can find of sending a byte array reference directly into an internal
1837 * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1838 * so taking a lead from that... */
1839 WSABUF[] bufarray = new WSABUF[numsegments];
1840 GCHandle[] gch = new GCHandle[numsegments];
1842 for (int i = 0; i < numsegments; i++) {
1843 ArraySegment<byte> segment = buffers[i];
1845 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1846 throw new ArgumentOutOfRangeException ("segment");
1848 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1849 bufarray[i].len = segment.Count;
1850 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1854 ret = Receive_internal (safe_handle, bufarray, socketFlags, out nativeError);
1856 for (int i = 0; i < numsegments; i++) {
1857 if (gch[i].IsAllocated)
1862 errorCode = (SocketError) nativeError;
1867 public bool ReceiveAsync (SocketAsyncEventArgs e)
1869 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1871 ThrowIfDisposedAndClosed ();
1873 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1874 // thrown when e.Buffer and e.BufferList are null (works fine when one is
1875 // set to a valid object)
1876 if (e.Buffer == null && e.BufferList == null)
1877 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1879 if (e.Buffer == null) {
1880 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
1882 e.socket_async_result.Buffers = e.BufferList;
1884 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
1886 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
1888 e.socket_async_result.Buffer = e.Buffer;
1889 e.socket_async_result.Offset = e.Offset;
1890 e.socket_async_result.Size = e.Count;
1892 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
1898 static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
1899 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1901 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1902 throw new InvalidOperationException ("No operation in progress");
1905 e.BytesTransferred = e.current_socket.EndReceive (ares);
1906 } catch (SocketException se){
1907 e.SocketError = se.SocketErrorCode;
1908 } catch (ObjectDisposedException) {
1909 e.SocketError = SocketError.OperationAborted;
1915 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
1917 ThrowIfDisposedAndClosed ();
1918 ThrowIfBufferNull (buffer);
1919 ThrowIfBufferOutOfRange (buffer, offset, size);
1921 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1925 SockFlags = socket_flags,
1928 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
1933 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags flags, out SocketError error, AsyncCallback callback, object state)
1935 /* As far as I can tell from the docs and from experimentation, a pointer to the
1936 * SocketError parameter is not supposed to be saved for the async parts. And as we don't
1937 * set any socket errors in the setup code, we just have to set it to Success. */
1938 error = SocketError.Success;
1939 return BeginReceive (buffer, offset, size, flags, callback, state);
1942 static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
1943 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1947 total = Receive_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
1948 } catch (Exception e) {
1949 sockares.Complete (e);
1953 sockares.Complete (total);
1956 [CLSCompliant (false)]
1957 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
1959 ThrowIfDisposedAndClosed ();
1961 if (buffers == null)
1962 throw new ArgumentNullException ("buffers");
1964 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1966 SockFlags = socketFlags,
1969 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
1974 [CLSCompliant (false)]
1975 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1977 /* I assume the same SocketError semantics as above */
1978 errorCode = SocketError.Success;
1979 return BeginReceive (buffers, socketFlags, callback, state);
1982 static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
1983 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1987 total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
1988 } catch (Exception e) {
1989 sockares.Complete (e);
1993 sockares.Complete (total);
1996 public int EndReceive (IAsyncResult result)
1999 int bytesReceived = EndReceive (result, out error);
2001 if (error != SocketError.Success) {
2002 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2003 is_connected = false;
2004 throw new SocketException ((int)error);
2007 return bytesReceived;
2010 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
2012 ThrowIfDisposedAndClosed ();
2014 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
2016 if (!sockares.IsCompleted)
2017 sockares.AsyncWaitHandle.WaitOne ();
2019 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
2020 // kinds of exceptions that should be thrown.
2021 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2022 sockares.CheckIfThrowDelayedException();
2024 return sockares.Total;
2027 int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2030 int ret = Receive_internal (safe_handle, buf, offset, size, flags, out nativeError);
2032 error = (SocketError) nativeError;
2033 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2034 is_connected = false;
2037 is_connected = true;
2043 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2046 safeHandle.RegisterForBlockingSyscall ();
2047 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2049 safeHandle.UnRegisterForBlockingSyscall ();
2053 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2054 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2056 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
2059 safeHandle.RegisterForBlockingSyscall ();
2060 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
2062 safeHandle.UnRegisterForBlockingSyscall ();
2066 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2067 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error);
2073 public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
2075 ThrowIfDisposedAndClosed ();
2076 ThrowIfBufferNull (buffer);
2078 return ReceiveFrom (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
2081 public int ReceiveFrom (byte [] buffer, SocketFlags socketFlags, ref EndPoint remoteEP)
2083 ThrowIfDisposedAndClosed ();
2084 ThrowIfBufferNull (buffer);
2086 return ReceiveFrom (buffer, 0, buffer.Length, socketFlags, ref remoteEP);
2089 public int ReceiveFrom (byte [] buffer, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
2091 ThrowIfDisposedAndClosed ();
2092 ThrowIfBufferNull (buffer);
2093 ThrowIfBufferOutOfRange (buffer, 0, size);
2095 return ReceiveFrom (buffer, 0, size, socketFlags, ref remoteEP);
2098 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
2100 ThrowIfDisposedAndClosed ();
2101 ThrowIfBufferNull (buffer);
2102 ThrowIfBufferOutOfRange (buffer, offset, size);
2104 if (remoteEP == null)
2105 throw new ArgumentNullException ("remoteEP");
2108 return ReceiveFrom_nochecks_exc (buffer, offset, size, socketFlags, ref remoteEP, true, out error);
2111 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
2113 ThrowIfDisposedAndClosed ();
2115 // We do not support recv into multiple buffers yet
2116 if (e.BufferList != null)
2117 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2118 if (e.RemoteEndPoint == null)
2119 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2121 InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
2123 e.socket_async_result.Buffer = e.Buffer;
2124 e.socket_async_result.Offset = e.Offset;
2125 e.socket_async_result.Size = e.Count;
2126 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2127 e.socket_async_result.SockFlags = e.SocketFlags;
2129 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
2134 static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
2135 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2137 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2138 throw new InvalidOperationException ("No operation in progress");
2141 e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
2142 } catch (SocketException ex) {
2143 e.SocketError = ex.SocketErrorCode;
2144 } catch (ObjectDisposedException) {
2145 e.SocketError = SocketError.OperationAborted;
2151 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
2153 ThrowIfDisposedAndClosed ();
2154 ThrowIfBufferNull (buffer);
2155 ThrowIfBufferOutOfRange (buffer, offset, size);
2157 if (remote_end == null)
2158 throw new ArgumentNullException ("remote_end");
2160 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
2164 SockFlags = socket_flags,
2165 EndPoint = remote_end,
2168 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
2173 static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
2174 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2179 total = sockares.socket.ReceiveFrom_nochecks_exc (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, true, out error);
2180 } catch (Exception e) {
2181 sockares.Complete (e);
2185 sockares.Complete (total);
2188 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
2190 ThrowIfDisposedAndClosed ();
2192 if (end_point == null)
2193 throw new ArgumentNullException ("remote_end");
2195 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
2197 if (!sockares.IsCompleted)
2198 sockares.AsyncWaitHandle.WaitOne();
2200 sockares.CheckIfThrowDelayedException();
2202 end_point = sockares.EndPoint;
2204 return sockares.Total;
2207 internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end, bool throwOnError, out int error)
2209 SocketAddress sockaddr = remote_end.Serialize();
2211 int cnt = ReceiveFrom_internal (safe_handle, buf, offset, size, flags, ref sockaddr, out error);
2213 SocketError err = (SocketError) error;
2215 if (err != SocketError.WouldBlock && err != SocketError.InProgress) {
2216 is_connected = false;
2217 } else if (err == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
2219 throw new SocketException ((int) SocketError.TimedOut, TIMEOUT_EXCEPTION_MSG);
2220 error = (int) SocketError.TimedOut;
2225 throw new SocketException (error);
2230 is_connected = true;
2233 /* If sockaddr is null then we're a connection oriented protocol and should ignore the
2234 * remote_end parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
2235 if (sockaddr != null) {
2236 /* Stupidly, EndPoint.Create() is an instance method */
2237 remote_end = remote_end.Create (sockaddr);
2240 seed_endpoint = remote_end;
2245 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error)
2248 safeHandle.RegisterForBlockingSyscall ();
2249 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
2251 safeHandle.UnRegisterForBlockingSyscall ();
2255 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2256 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error);
2260 #region ReceiveMessageFrom
2262 [MonoTODO ("Not implemented")]
2263 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
2265 ThrowIfDisposedAndClosed ();
2266 ThrowIfBufferNull (buffer);
2267 ThrowIfBufferOutOfRange (buffer, offset, size);
2269 if (remoteEP == null)
2270 throw new ArgumentNullException ("remoteEP");
2272 // FIXME: figure out how we get hold of the IPPacketInformation
2273 throw new NotImplementedException ();
2276 [MonoTODO ("Not implemented")]
2277 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
2279 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2281 ThrowIfDisposedAndClosed ();
2283 throw new NotImplementedException ();
2287 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
2289 ThrowIfDisposedAndClosed ();
2290 ThrowIfBufferNull (buffer);
2291 ThrowIfBufferOutOfRange (buffer, offset, size);
2293 if (remoteEP == null)
2294 throw new ArgumentNullException ("remoteEP");
2296 throw new NotImplementedException ();
2300 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
2302 ThrowIfDisposedAndClosed ();
2304 if (endPoint == null)
2305 throw new ArgumentNullException ("endPoint");
2307 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
2309 throw new NotImplementedException ();
2316 public int Send (byte [] buffer)
2318 ThrowIfDisposedAndClosed ();
2319 ThrowIfBufferNull (buffer);
2320 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2323 int ret = Send_nochecks (buffer, 0, buffer.Length, SocketFlags.None, out error);
2325 if (error != SocketError.Success)
2326 throw new SocketException ((int) error);
2331 public int Send (byte [] buffer, SocketFlags socketFlags)
2333 ThrowIfDisposedAndClosed ();
2334 ThrowIfBufferNull (buffer);
2335 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2338 int ret = Send_nochecks (buffer, 0, buffer.Length, socketFlags, out error);
2340 if (error != SocketError.Success)
2341 throw new SocketException ((int) error);
2346 public int Send (byte [] buffer, int size, SocketFlags socketFlags)
2348 ThrowIfDisposedAndClosed ();
2349 ThrowIfBufferNull (buffer);
2350 ThrowIfBufferOutOfRange (buffer, 0, size);
2353 int ret = Send_nochecks (buffer, 0, size, socketFlags, out error);
2355 if (error != SocketError.Success)
2356 throw new SocketException ((int) error);
2361 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags)
2363 ThrowIfDisposedAndClosed ();
2364 ThrowIfBufferNull (buffer);
2365 ThrowIfBufferOutOfRange (buffer, offset, size);
2368 int ret = Send_nochecks (buffer, offset, size, socketFlags, out error);
2370 if (error != SocketError.Success)
2371 throw new SocketException ((int) error);
2376 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
2378 ThrowIfDisposedAndClosed ();
2379 ThrowIfBufferNull (buffer);
2380 ThrowIfBufferOutOfRange (buffer, offset, size);
2382 return Send_nochecks (buffer, offset, size, socketFlags, out errorCode);
2386 int Send (IList<ArraySegment<byte>> buffers)
2389 int ret = Send (buffers, SocketFlags.None, out error);
2391 if (error != SocketError.Success)
2392 throw new SocketException ((int) error);
2398 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
2401 int ret = Send (buffers, socketFlags, out error);
2403 if (error != SocketError.Success)
2404 throw new SocketException ((int) error);
2409 [CLSCompliant (false)]
2410 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
2412 ThrowIfDisposedAndClosed ();
2414 if (buffers == null)
2415 throw new ArgumentNullException ("buffers");
2416 if (buffers.Count == 0)
2417 throw new ArgumentException ("Buffer is empty", "buffers");
2419 int numsegments = buffers.Count;
2423 WSABUF[] bufarray = new WSABUF[numsegments];
2424 GCHandle[] gch = new GCHandle[numsegments];
2426 for(int i = 0; i < numsegments; i++) {
2427 ArraySegment<byte> segment = buffers[i];
2429 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
2430 throw new ArgumentOutOfRangeException ("segment");
2432 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
2433 bufarray[i].len = segment.Count;
2434 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
2438 ret = Send_internal (safe_handle, bufarray, socketFlags, out nativeError);
2440 for(int i = 0; i < numsegments; i++) {
2441 if (gch[i].IsAllocated) {
2447 errorCode = (SocketError)nativeError;
2452 int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2455 error = SocketError.Success;
2462 sent += Send_internal (safe_handle, buf, offset + sent, size - sent, flags, out nativeError);
2463 error = (SocketError)nativeError;
2464 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2465 is_connected = false;
2469 is_connected = true;
2471 } while (sent < size);
2476 public bool SendAsync (SocketAsyncEventArgs e)
2478 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2480 ThrowIfDisposedAndClosed ();
2482 if (e.Buffer == null && e.BufferList == null)
2483 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
2485 if (e.Buffer == null) {
2486 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
2488 e.socket_async_result.Buffers = e.BufferList;
2490 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
2492 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
2494 e.socket_async_result.Buffer = e.Buffer;
2495 e.socket_async_result.Offset = e.Offset;
2496 e.socket_async_result.Size = e.Count;
2498 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2504 static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
2505 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2507 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2508 throw new InvalidOperationException ("No operation in progress");
2511 e.BytesTransferred = e.current_socket.EndSend (ares);
2512 } catch (SocketException se){
2513 e.SocketError = se.SocketErrorCode;
2514 } catch (ObjectDisposedException) {
2515 e.SocketError = SocketError.OperationAborted;
2521 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2523 if (!is_connected) {
2524 errorCode = SocketError.NotConnected;
2525 throw new SocketException ((int) errorCode);
2528 errorCode = SocketError.Success;
2529 return BeginSend (buffer, offset, size, socketFlags, callback, state);
2532 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
2534 ThrowIfDisposedAndClosed ();
2535 ThrowIfBufferNull (buffer);
2536 ThrowIfBufferOutOfRange (buffer, offset, size);
2539 throw new SocketException ((int)SocketError.NotConnected);
2541 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
2545 SockFlags = socket_flags,
2548 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
2553 static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
2558 total = Socket.Send_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
2559 } catch (Exception e) {
2560 sockares.Complete (e);
2564 if (sockares.error == 0) {
2565 sent_so_far += total;
2566 sockares.Offset += total;
2567 sockares.Size -= total;
2569 if (sockares.socket.is_disposed) {
2570 sockares.Complete (total);
2574 if (sockares.Size > 0) {
2575 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2576 return; // Have to finish writing everything. See bug #74475.
2579 sockares.Total = sent_so_far;
2582 sockares.Complete (total);
2585 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
2587 ThrowIfDisposedAndClosed ();
2589 if (buffers == null)
2590 throw new ArgumentNullException ("buffers");
2592 throw new SocketException ((int)SocketError.NotConnected);
2594 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
2596 SockFlags = socketFlags,
2599 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
2604 [CLSCompliant (false)]
2605 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2607 if (!is_connected) {
2608 errorCode = SocketError.NotConnected;
2609 throw new SocketException ((int)errorCode);
2612 errorCode = SocketError.Success;
2613 return BeginSend (buffers, socketFlags, callback, state);
2616 static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
2617 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2621 total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
2622 } catch (Exception e) {
2623 sockares.Complete (e);
2627 sockares.Complete (total);
2630 public int EndSend (IAsyncResult result)
2633 int bytesSent = EndSend (result, out error);
2635 if (error != SocketError.Success) {
2636 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2637 is_connected = false;
2638 throw new SocketException ((int)error);
2644 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
2646 ThrowIfDisposedAndClosed ();
2648 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
2650 if (!sockares.IsCompleted)
2651 sockares.AsyncWaitHandle.WaitOne ();
2653 /* If no socket error occurred, call CheckIfThrowDelayedException in
2654 * case there are other kinds of exceptions that should be thrown.*/
2655 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2656 sockares.CheckIfThrowDelayedException ();
2658 return sockares.Total;
2661 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2663 bool release = false;
2665 safeHandle.DangerousAddRef (ref release);
2666 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2669 safeHandle.DangerousRelease ();
2673 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2674 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2676 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
2679 safeHandle.RegisterForBlockingSyscall ();
2680 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
2682 safeHandle.UnRegisterForBlockingSyscall ();
2686 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2687 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
2693 public int SendTo (byte [] buffer, EndPoint remoteEP)
2695 ThrowIfDisposedAndClosed ();
2696 ThrowIfBufferNull (buffer);
2698 return SendTo (buffer, 0, buffer.Length, SocketFlags.None, remoteEP);
2701 public int SendTo (byte [] buffer, SocketFlags socketFlags, EndPoint remoteEP)
2703 ThrowIfDisposedAndClosed ();
2704 ThrowIfBufferNull (buffer);
2706 return SendTo (buffer, 0, buffer.Length, socketFlags, remoteEP);
2709 public int SendTo (byte [] buffer, int size, SocketFlags socketFlags, EndPoint remoteEP)
2711 return SendTo (buffer, 0, size, socketFlags, remoteEP);
2714 public int SendTo (byte [] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP)
2716 ThrowIfDisposedAndClosed ();
2717 ThrowIfBufferNull (buffer);
2718 ThrowIfBufferOutOfRange (buffer, offset, size);
2720 if (remoteEP == null)
2721 throw new ArgumentNullException("remoteEP");
2723 return SendTo_nochecks (buffer, offset, size, socketFlags, remoteEP);
2726 public bool SendToAsync (SocketAsyncEventArgs e)
2728 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2730 ThrowIfDisposedAndClosed ();
2732 if (e.BufferList != null)
2733 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2734 if (e.RemoteEndPoint == null)
2735 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2737 InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2739 e.socket_async_result.Buffer = e.Buffer;
2740 e.socket_async_result.Offset = e.Offset;
2741 e.socket_async_result.Size = e.Count;
2742 e.socket_async_result.SockFlags = e.SocketFlags;
2743 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2745 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2750 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2751 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2753 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2754 throw new InvalidOperationException ("No operation in progress");
2757 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2758 } catch (SocketException ex) {
2759 e.SocketError = ex.SocketErrorCode;
2760 } catch (ObjectDisposedException) {
2761 e.SocketError = SocketError.OperationAborted;
2767 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2769 ThrowIfDisposedAndClosed ();
2770 ThrowIfBufferNull (buffer);
2771 ThrowIfBufferOutOfRange (buffer, offset, size);
2773 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2777 SockFlags = socket_flags,
2778 EndPoint = remote_end,
2781 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2786 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2790 total = sockares.socket.SendTo_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2792 if (sockares.error == 0) {
2793 sent_so_far += total;
2794 sockares.Offset += total;
2795 sockares.Size -= total;
2798 if (sockares.Size > 0) {
2799 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2800 return; // Have to finish writing everything. See bug #74475.
2803 sockares.Total = sent_so_far;
2804 } catch (Exception e) {
2805 sockares.Complete (e);
2809 sockares.Complete ();
2812 public int EndSendTo (IAsyncResult result)
2814 ThrowIfDisposedAndClosed ();
2816 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2818 if (!sockares.IsCompleted)
2819 sockares.AsyncWaitHandle.WaitOne();
2821 sockares.CheckIfThrowDelayedException();
2823 return sockares.Total;
2826 int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2829 int ret = SendTo_internal (safe_handle, buffer, offset, size, flags, remote_end.Serialize (), out error);
2831 SocketError err = (SocketError) error;
2833 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2834 is_connected = false;
2835 throw new SocketException (error);
2838 is_connected = true;
2840 seed_endpoint = remote_end;
2845 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
2848 safeHandle.RegisterForBlockingSyscall ();
2849 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
2851 safeHandle.UnRegisterForBlockingSyscall ();
2855 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2856 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
2862 public void SendFile (string fileName)
2864 ThrowIfDisposedAndClosed ();
2867 throw new NotSupportedException ();
2869 throw new InvalidOperationException ();
2871 SendFile (fileName, null, null, 0);
2874 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2876 ThrowIfDisposedAndClosed ();
2879 throw new NotSupportedException ();
2881 throw new InvalidOperationException ();
2883 if (!SendFile_internal (safe_handle, fileName, preBuffer, postBuffer, flags)) {
2884 SocketException exc = new SocketException ();
2885 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2886 throw new FileNotFoundException ();
2891 public IAsyncResult BeginSendFile (string fileName, AsyncCallback callback, object state)
2893 ThrowIfDisposedAndClosed ();
2896 throw new NotSupportedException ();
2897 if (!File.Exists (fileName))
2898 throw new FileNotFoundException ();
2900 return BeginSendFile (fileName, null, null, 0, callback, state);
2903 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2905 ThrowIfDisposedAndClosed ();
2908 throw new NotSupportedException ();
2909 if (!File.Exists (fileName))
2910 throw new FileNotFoundException ();
2912 SendFileHandler handler = new SendFileHandler (SendFile);
2914 return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2917 public void EndSendFile (IAsyncResult asyncResult)
2919 ThrowIfDisposedAndClosed ();
2921 if (asyncResult == null)
2922 throw new ArgumentNullException ("asyncResult");
2924 SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2926 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2928 ares.Delegate.EndInvoke (ares.Original);
2931 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
2934 safeHandle.RegisterForBlockingSyscall ();
2935 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
2937 safeHandle.UnRegisterForBlockingSyscall ();
2941 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2942 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
2944 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2946 sealed class SendFileAsyncResult : IAsyncResult {
2950 public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2956 public object AsyncState {
2957 get { return ares.AsyncState; }
2960 public WaitHandle AsyncWaitHandle {
2961 get { return ares.AsyncWaitHandle; }
2964 public bool CompletedSynchronously {
2965 get { return ares.CompletedSynchronously; }
2968 public bool IsCompleted {
2969 get { return ares.IsCompleted; }
2972 public SendFileHandler Delegate {
2976 public IAsyncResult Original {
2977 get { return ares; }
2985 [MonoTODO ("Not implemented")]
2986 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2988 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2990 ThrowIfDisposedAndClosed ();
2992 throw new NotImplementedException ();
2997 #region DuplicateAndClose
3000 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
3001 public SocketInformation DuplicateAndClose (int targetProcessId)
3003 var si = new SocketInformation ();
3005 (is_listening ? SocketInformationOptions.Listening : 0) |
3006 (is_connected ? SocketInformationOptions.Connected : 0) |
3007 (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
3008 (use_overlapped_io ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
3010 si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, is_bound ? 1 : 0, (long)Handle);
3019 #region GetSocketOption
3021 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3023 ThrowIfDisposedAndClosed ();
3025 if (optionValue == null)
3026 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3029 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref optionValue, out error);
3032 throw new SocketException (error);
3035 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength)
3037 ThrowIfDisposedAndClosed ();
3040 byte[] byte_val = new byte [optionLength];
3041 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref byte_val, out error);
3044 throw new SocketException (error);
3049 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
3051 ThrowIfDisposedAndClosed ();
3055 GetSocketOption_obj_internal (safe_handle, optionLevel, optionName, out obj_val, out error);
3058 throw new SocketException (error);
3060 if (optionName == SocketOptionName.Linger)
3061 return (LingerOption) obj_val;
3062 else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
3063 return (MulticastOption) obj_val;
3064 else if (obj_val is int)
3065 return (int) obj_val;
3070 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
3072 bool release = false;
3074 safeHandle.DangerousAddRef (ref release);
3075 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
3078 safeHandle.DangerousRelease ();
3082 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3083 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
3085 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
3087 bool release = false;
3089 safeHandle.DangerousAddRef (ref release);
3090 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
3093 safeHandle.DangerousRelease ();
3097 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3098 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
3102 #region SetSocketOption
3104 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3106 ThrowIfDisposedAndClosed ();
3108 // I'd throw an ArgumentNullException, but this is what MS does.
3109 if (optionValue == null)
3110 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3113 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, optionValue, 0, out error);
3116 if (error == (int) SocketError.InvalidArgument)
3117 throw new ArgumentException ();
3118 throw new SocketException (error);
3122 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
3124 ThrowIfDisposedAndClosed ();
3126 // NOTE: if a null is passed, the byte[] overload is used instead...
3127 if (optionValue == null)
3128 throw new ArgumentNullException("optionValue");
3132 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
3133 LingerOption linger = optionValue as LingerOption;
3135 throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
3136 SetSocketOption_internal (safe_handle, optionLevel, optionName, linger, null, 0, out error);
3137 } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3138 MulticastOption multicast = optionValue as MulticastOption;
3139 if (multicast == null)
3140 throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
3141 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3142 } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3143 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
3144 if (multicast == null)
3145 throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
3146 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3148 throw new ArgumentException ("Invalid value specified.", "optionValue");
3152 if (error == (int) SocketError.InvalidArgument)
3153 throw new ArgumentException ();
3154 throw new SocketException (error);
3158 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
3160 int int_val = optionValue ? 1 : 0;
3162 SetSocketOption (optionLevel, optionName, int_val);
3165 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
3167 ThrowIfDisposedAndClosed ();
3169 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse (protocol_type))
3170 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.");
3173 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, optionValue, out error);
3176 if (error == (int) SocketError.InvalidArgument)
3177 throw new ArgumentException ();
3178 throw new SocketException (error);
3182 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
3184 bool release = false;
3186 safeHandle.DangerousAddRef (ref release);
3187 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
3190 safeHandle.DangerousRelease ();
3194 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3195 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
3201 public int IOControl (int ioControlCode, byte [] optionInValue, byte [] optionOutValue)
3204 throw new ObjectDisposedException (GetType ().ToString ());
3207 int result = IOControl_internal (safe_handle, ioControlCode, optionInValue, optionOutValue, out error);
3210 throw new SocketException (error);
3212 throw new InvalidOperationException ("Must use Blocking property instead.");
3217 public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
3219 return IOControl ((int) ioControlCode, optionInValue, optionOutValue);
3222 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
3224 bool release = false;
3226 safeHandle.DangerousAddRef (ref release);
3227 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
3230 safeHandle.DangerousRelease ();
3234 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
3235 * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
3236 * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
3237 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3238 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
3244 public void Close ()
3250 public void Close (int timeout)
3252 linger_timeout = timeout;
3256 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3257 internal extern static void Close_internal (IntPtr socket, out int error);
3263 public void Shutdown (SocketShutdown how)
3265 ThrowIfDisposedAndClosed ();
3268 throw new SocketException (10057); // Not connected
3271 Shutdown_internal (safe_handle, how, out error);
3274 throw new SocketException (error);
3277 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
3279 bool release = false;
3281 safeHandle.DangerousAddRef (ref release);
3282 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
3285 safeHandle.DangerousRelease ();
3289 [MethodImplAttribute (MethodImplOptions.InternalCall)]
3290 internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
3296 protected virtual void Dispose (bool disposing)
3302 bool was_connected = is_connected;
3303 is_connected = false;
3305 if (safe_handle != null) {
3312 safe_handle.Dispose ();
3316 public void Dispose ()
3319 GC.SuppressFinalize (this);
3322 void Linger (IntPtr handle)
3324 if (!is_connected || linger_timeout <= 0)
3327 /* We don't want to receive any more data */
3329 Shutdown_internal (handle, SocketShutdown.Receive, out error);
3334 int seconds = linger_timeout / 1000;
3335 int ms = linger_timeout % 1000;
3337 /* If the other end closes, this will return 'true' with 'Available' == 0 */
3338 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
3344 LingerOption linger = new LingerOption (true, seconds);
3345 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
3346 /* Not needed, we're closing upon return */
3354 void ThrowIfDisposedAndClosed (Socket socket)
3356 if (socket.is_disposed && socket.is_closed)
3357 throw new ObjectDisposedException (socket.GetType ().ToString ());
3360 void ThrowIfDisposedAndClosed ()
3362 if (is_disposed && is_closed)
3363 throw new ObjectDisposedException (GetType ().ToString ());
3366 void ThrowIfBufferNull (byte[] buffer)
3369 throw new ArgumentNullException ("buffer");
3372 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
3375 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
3376 if (offset > buffer.Length)
3377 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
3379 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
3380 if (size > buffer.Length - offset)
3381 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
3386 if (protocol_type == ProtocolType.Udp)
3387 throw new SocketException ((int)SocketError.ProtocolOption);
3390 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
3393 throw new ArgumentNullException (argName);
3395 SocketAsyncResult sockares = ares as SocketAsyncResult;
3396 if (sockares == null)
3397 throw new ArgumentException ("Invalid IAsyncResult", argName);
3398 if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
3399 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
3404 void QueueIOSelectorJob (Queue<KeyValuePair<IntPtr, IOSelectorJob>> queue, IntPtr handle, IOSelectorJob job)
3408 queue.Enqueue (new KeyValuePair<IntPtr, IOSelectorJob> (handle, job));
3409 count = queue.Count;
3413 IOSelector.Add (handle, job);
3416 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
3418 e.socket_async_result.Init (this, callback, state, operation);
3419 if (e.AcceptSocket != null) {
3420 e.socket_async_result.AcceptSocket = e.AcceptSocket;
3422 e.current_socket = this;
3423 e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
3424 e.SocketError = SocketError.Success;
3425 e.BytesTransferred = 0;
3428 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
3431 case SocketOperation.Connect:
3432 return SocketAsyncOperation.Connect;
3433 case SocketOperation.Accept:
3434 return SocketAsyncOperation.Accept;
3435 case SocketOperation.Disconnect:
3436 return SocketAsyncOperation.Disconnect;
3437 case SocketOperation.Receive:
3438 case SocketOperation.ReceiveGeneric:
3439 return SocketAsyncOperation.Receive;
3440 case SocketOperation.ReceiveFrom:
3441 return SocketAsyncOperation.ReceiveFrom;
3442 case SocketOperation.Send:
3443 case SocketOperation.SendGeneric:
3444 return SocketAsyncOperation.Send;
3445 case SocketOperation.SendTo:
3446 return SocketAsyncOperation.SendTo;
3448 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
3452 IPEndPoint RemapIPEndPoint (IPEndPoint input) {
3453 // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
3454 if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
3455 return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
3460 [StructLayout (LayoutKind.Sequential)]
3466 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3467 internal static extern void cancel_blocking_socket_operation (Thread thread);
3469 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3470 internal static extern bool SupportsPortReuse (ProtocolType proto);