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 #if NET_2_1 && !MOBILE
174 switch (addressFamily) {
175 case AddressFamily.InterNetwork: // ok
176 case AddressFamily.InterNetworkV6: // ok
177 case AddressFamily.Unknown: // SocketException will be thrown later (with right error #)
179 // case AddressFamily.Unspecified:
181 throw new ArgumentException ("addressFamily");
184 switch (socketType) {
185 case SocketType.Stream: // ok
186 case SocketType.Unknown: // SocketException will be thrown later (with right error #)
189 throw new ArgumentException ("socketType");
192 switch (protocolType) {
193 case ProtocolType.Tcp: // ok
194 case ProtocolType.Unspecified: // ok
195 case ProtocolType.Unknown: // SocketException will be thrown later (with right error #)
198 throw new ArgumentException ("protocolType");
201 this.address_family = addressFamily;
202 this.socket_type = socketType;
203 this.protocol_type = protocolType;
206 this.safe_handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
209 throw new SocketException (error);
211 #if !NET_2_1 || MOBILE
217 public Socket (SocketInformation socketInformation)
219 this.is_listening = (socketInformation.Options & SocketInformationOptions.Listening) != 0;
220 this.is_connected = (socketInformation.Options & SocketInformationOptions.Connected) != 0;
221 this.is_blocking = (socketInformation.Options & SocketInformationOptions.NonBlocking) == 0;
222 this.use_overlapped_io = (socketInformation.Options & SocketInformationOptions.UseOnlyOverlappedIO) != 0;
224 var result = Mono.DataConverter.Unpack ("iiiil", socketInformation.ProtocolInformation, 0);
226 this.address_family = (AddressFamily) (int) result [0];
227 this.socket_type = (SocketType) (int) result [1];
228 this.protocol_type = (ProtocolType) (int) result [2];
229 this.is_bound = (ProtocolType) (int) result [3] != 0;
230 this.safe_handle = new SafeSocketHandle ((IntPtr) (long) result [4], true);
236 /* private constructor used by Accept, which already has a socket handle to use */
237 internal Socket(AddressFamily family, SocketType type, ProtocolType proto, SafeSocketHandle safe_handle)
239 this.address_family = family;
240 this.socket_type = type;
241 this.protocol_type = proto;
243 this.safe_handle = safe_handle;
244 this.is_connected = true;
252 void SocketDefaults ()
255 /* Need to test IPv6 further */
256 if (address_family == AddressFamily.InterNetwork
257 // || address_family == AddressFamily.InterNetworkV6
259 /* This is the default, but it probably has nasty side
260 * effects on Linux, as the socket option is kludged by
261 * turning on or off PMTU discovery... */
262 this.DontFragment = false;
265 /* Microsoft sets these to 8192, but we are going to keep them
266 * both to the OS defaults as these have a big performance impact.
267 * on WebClient performance. */
268 // this.ReceiveBufferSize = 8192;
269 // this.SendBufferSize = 8192;
270 } catch (SocketException) {
274 /* Creates a new system socket, returning the handle */
275 [MethodImplAttribute(MethodImplOptions.InternalCall)]
276 extern IntPtr Socket_internal (AddressFamily family, SocketType type, ProtocolType proto, out int error);
282 [ObsoleteAttribute ("Use OSSupportsIPv4 instead")]
283 public static bool SupportsIPv4 {
284 get { return ipv4_supported == 1; }
287 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
288 public static bool SupportsIPv6 {
289 get { return ipv6_supported == 1; }
293 public static bool OSSupportsIPv4 {
294 get { return ipv4_supported == 1; }
297 public static bool OSSupportsIPv4 {
299 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
301 foreach (NetworkInterface adapter in nics) {
302 if (adapter.Supports (NetworkInterfaceComponent.IPv4))
312 public static bool OSSupportsIPv6 {
313 get { return ipv6_supported == 1; }
316 public static bool OSSupportsIPv6 {
318 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
320 foreach (NetworkInterface adapter in nics) {
321 if (adapter.Supports (NetworkInterfaceComponent.IPv6))
330 public int Available {
332 ThrowIfDisposedAndClosed ();
335 ret = Available_internal (safe_handle, out error);
338 throw new SocketException (error);
344 static int Available_internal (SafeSocketHandle safeHandle, out int error)
346 bool release = false;
348 safeHandle.DangerousAddRef (ref release);
349 return Available_internal (safeHandle.DangerousGetHandle (), out error);
352 safeHandle.DangerousRelease ();
356 /* Returns the amount of data waiting to be read on socket */
357 [MethodImplAttribute(MethodImplOptions.InternalCall)]
358 extern static int Available_internal (IntPtr socket, out int error);
360 public bool DontFragment {
362 ThrowIfDisposedAndClosed ();
364 switch (address_family) {
365 case AddressFamily.InterNetwork:
366 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment)) != 0;
367 case AddressFamily.InterNetworkV6:
368 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment)) != 0;
370 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
374 ThrowIfDisposedAndClosed ();
376 switch (address_family) {
377 case AddressFamily.InterNetwork:
378 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
380 case AddressFamily.InterNetworkV6:
381 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment, value ? 1 : 0);
384 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
389 public bool EnableBroadcast {
391 ThrowIfDisposedAndClosed ();
393 if (protocol_type != ProtocolType.Udp)
394 throw new SocketException ((int) SocketError.ProtocolOption);
396 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0;
399 ThrowIfDisposedAndClosed ();
401 if (protocol_type != ProtocolType.Udp)
402 throw new SocketException ((int) SocketError.ProtocolOption);
404 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
408 public bool ExclusiveAddressUse {
410 ThrowIfDisposedAndClosed ();
412 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse)) != 0;
415 ThrowIfDisposedAndClosed ();
418 throw new InvalidOperationException ("Bind has already been called for this socket");
420 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
424 public bool IsBound {
430 public LingerOption LingerState {
432 ThrowIfDisposedAndClosed ();
434 return (LingerOption) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger);
437 ThrowIfDisposedAndClosed ();
438 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger, value);
442 public bool MulticastLoopback {
444 ThrowIfDisposedAndClosed ();
446 /* Even though this option can be set for TCP sockets on Linux, throw
447 * this exception anyway to be compatible (the MSDN docs say
448 * "Setting this property on a Transmission Control Protocol (TCP)
449 * socket will have no effect." but the MS runtime throws the
451 if (protocol_type == ProtocolType.Tcp)
452 throw new SocketException ((int)SocketError.ProtocolOption);
454 switch (address_family) {
455 case AddressFamily.InterNetwork:
456 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
457 case AddressFamily.InterNetworkV6:
458 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
460 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
464 ThrowIfDisposedAndClosed ();
466 /* Even though this option can be set for TCP sockets on Linux, throw
467 * this exception anyway to be compatible (the MSDN docs say
468 * "Setting this property on a Transmission Control Protocol (TCP)
469 * socket will have no effect." but the MS runtime throws the
471 if (protocol_type == ProtocolType.Tcp)
472 throw new SocketException ((int)SocketError.ProtocolOption);
474 switch (address_family) {
475 case AddressFamily.InterNetwork:
476 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
478 case AddressFamily.InterNetworkV6:
479 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
482 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
487 public bool DualMode {
489 if (AddressFamily != AddressFamily.InterNetworkV6)
490 throw new NotSupportedException("This protocol version is not supported");
492 return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only) == 0);
495 if (AddressFamily != AddressFamily.InterNetworkV6)
496 throw new NotSupportedException("This protocol version is not supported");
498 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1);
502 private bool IsDualMode {
504 return AddressFamily == AddressFamily.InterNetworkV6 && DualMode;
508 [MonoTODO ("This doesn't do anything on Mono yet")]
509 public bool UseOnlyOverlappedIO {
510 get { return use_overlapped_io; }
511 set { use_overlapped_io = value; }
514 public IntPtr Handle {
515 get { return safe_handle.DangerousGetHandle (); }
518 // Wish: support non-IP endpoints.
519 public EndPoint LocalEndPoint {
521 ThrowIfDisposedAndClosed ();
523 /* If the seed EndPoint is null, Connect, Bind, etc has not yet
524 * been called. MS returns null in this case. */
525 if (seed_endpoint == null)
529 SocketAddress sa = LocalEndPoint_internal (safe_handle, (int) address_family, out error);
532 throw new SocketException (error);
534 return seed_endpoint.Create (sa);
538 static SocketAddress LocalEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
540 bool release = false;
542 safeHandle.DangerousAddRef (ref release);
543 return LocalEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
546 safeHandle.DangerousRelease ();
550 /* Returns the local endpoint details in addr and port */
551 [MethodImplAttribute(MethodImplOptions.InternalCall)]
552 extern static SocketAddress LocalEndPoint_internal (IntPtr socket, int family, out int error);
554 public SocketType SocketType {
555 get { return socket_type; }
558 public int SendTimeout {
560 ThrowIfDisposedAndClosed ();
562 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
565 ThrowIfDisposedAndClosed ();
568 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
570 /* According to the MSDN docs we should adjust values between 1 and
571 * 499 to 500, but the MS runtime doesn't do this. */
575 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
579 public int ReceiveTimeout {
581 ThrowIfDisposedAndClosed ();
583 return (int) GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
586 ThrowIfDisposedAndClosed ();
589 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
594 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, value);
598 public AddressFamily AddressFamily {
599 get { return address_family; }
602 public bool Blocking {
603 get { return is_blocking; }
605 ThrowIfDisposedAndClosed ();
608 Blocking_internal (safe_handle, value, out error);
611 throw new SocketException (error);
617 static void Blocking_internal (SafeSocketHandle safeHandle, bool block, out int error)
619 bool release = false;
621 safeHandle.DangerousAddRef (ref release);
622 Blocking_internal (safeHandle.DangerousGetHandle (), block, out error);
625 safeHandle.DangerousRelease ();
629 [MethodImplAttribute(MethodImplOptions.InternalCall)]
630 internal extern static void Blocking_internal(IntPtr socket, bool block, out int error);
632 public bool Connected {
633 get { return is_connected; }
634 internal set { is_connected = value; }
637 public ProtocolType ProtocolType {
638 get { return protocol_type; }
641 public bool NoDelay {
643 ThrowIfDisposedAndClosed ();
646 return ((int) GetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay)) != 0;
650 ThrowIfDisposedAndClosed ();
653 SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
657 public int ReceiveBufferSize {
659 ThrowIfDisposedAndClosed ();
661 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer);
664 ThrowIfDisposedAndClosed ();
667 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
669 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
673 public int SendBufferSize {
675 ThrowIfDisposedAndClosed ();
677 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer);
680 ThrowIfDisposedAndClosed ();
683 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
685 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer, value);
691 ThrowIfDisposedAndClosed ();
693 switch (address_family) {
694 case AddressFamily.InterNetwork:
695 return (short) (int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
696 case AddressFamily.InterNetworkV6:
697 return (short) (int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit);
699 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
703 ThrowIfDisposedAndClosed ();
705 if (value < 0 || value > 255)
706 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero or greater than 255.");
708 switch (address_family) {
709 case AddressFamily.InterNetwork:
710 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
712 case AddressFamily.InterNetworkV6:
713 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
716 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
721 public EndPoint RemoteEndPoint {
723 ThrowIfDisposedAndClosed ();
725 /* If the seed EndPoint is null, Connect, Bind, etc has
726 * not yet been called. MS returns null in this case. */
727 if (!is_connected || seed_endpoint == null)
731 SocketAddress sa = RemoteEndPoint_internal (safe_handle, (int) address_family, out error);
734 throw new SocketException (error);
736 return seed_endpoint.Create (sa);
740 static SocketAddress RemoteEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
742 bool release = false;
744 safeHandle.DangerousAddRef (ref release);
745 return RemoteEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
748 safeHandle.DangerousRelease ();
752 /* Returns the remote endpoint details in addr and port */
753 [MethodImplAttribute(MethodImplOptions.InternalCall)]
754 extern static SocketAddress RemoteEndPoint_internal (IntPtr socket, int family, out int error);
760 public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
762 var list = new List<Socket> ();
763 AddSockets (list, checkRead, "checkRead");
764 AddSockets (list, checkWrite, "checkWrite");
765 AddSockets (list, checkError, "checkError");
768 throw new ArgumentNullException ("checkRead, checkWrite, checkError", "All the lists are null or empty.");
770 /* The 'sockets' array contains:
771 * - READ socket 0-n, null,
772 * - WRITE socket 0-n, null,
773 * - ERROR socket 0-n, null */
774 Socket [] sockets = list.ToArray ();
777 Select_internal (ref sockets, microSeconds, out error);
780 throw new SocketException (error);
782 if (sockets == null) {
783 if (checkRead != null)
785 if (checkWrite != null)
787 if (checkError != null)
793 int count = sockets.Length;
794 IList currentList = checkRead;
796 for (int i = 0; i < count; i++) {
797 Socket sock = sockets [i];
798 if (sock == null) { // separator
799 if (currentList != null) {
800 // Remove non-signaled sockets after the current one
801 int to_remove = currentList.Count - currentIdx;
802 for (int k = 0; k < to_remove; k++)
803 currentList.RemoveAt (currentIdx);
805 currentList = (mode == 0) ? checkWrite : checkError;
811 if (mode == 1 && currentList == checkWrite && !sock.is_connected) {
812 if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
813 sock.is_connected = true;
816 /* Remove non-signaled sockets before the current one */
817 while (((Socket) currentList [currentIdx]) != sock)
818 currentList.RemoveAt (currentIdx);
824 static void AddSockets (List<Socket> sockets, IList list, string name)
827 foreach (Socket sock in list) {
828 if (sock == null) // MS throws a NullRef
829 throw new ArgumentNullException ("name", "Contains a null element");
837 [MethodImplAttribute(MethodImplOptions.InternalCall)]
838 extern static void Select_internal (ref Socket [] sockets, int microSeconds, out int error);
844 public bool Poll (int time_us, SelectMode mode)
846 ThrowIfDisposedAndClosed ();
848 if (mode != SelectMode.SelectRead && mode != SelectMode.SelectWrite && mode != SelectMode.SelectError)
849 throw new NotSupportedException ("'mode' parameter is not valid.");
852 bool result = Poll_internal (safe_handle, mode, time_us, out error);
855 throw new SocketException (error);
857 if (mode == SelectMode.SelectWrite && result && !is_connected) {
858 /* Update the is_connected state; for non-blocking Connect()
859 * this is when we can find out that the connect succeeded. */
860 if ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
867 static bool Poll_internal (SafeSocketHandle safeHandle, SelectMode mode, int timeout, out int error)
869 bool release = false;
871 safeHandle.DangerousAddRef (ref release);
872 return Poll_internal (safeHandle.DangerousGetHandle (), mode, timeout, out error);
875 safeHandle.DangerousRelease ();
879 [MethodImplAttribute(MethodImplOptions.InternalCall)]
880 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
886 public Socket Accept()
888 ThrowIfDisposedAndClosed ();
891 SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
895 error = SOCKET_CLOSED_CODE;
896 throw new SocketException(error);
899 Socket accepted = new Socket (this.AddressFamily, this.SocketType, this.ProtocolType, safe_handle) {
900 seed_endpoint = this.seed_endpoint,
901 Blocking = this.Blocking,
907 internal void Accept (Socket acceptSocket)
909 ThrowIfDisposedAndClosed ();
912 SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
916 error = SOCKET_CLOSED_CODE;
917 throw new SocketException (error);
920 acceptSocket.address_family = this.AddressFamily;
921 acceptSocket.socket_type = this.SocketType;
922 acceptSocket.protocol_type = this.ProtocolType;
923 acceptSocket.safe_handle = safe_handle;
924 acceptSocket.is_connected = true;
925 acceptSocket.seed_endpoint = this.seed_endpoint;
926 acceptSocket.Blocking = this.Blocking;
928 // FIXME: figure out what if anything else needs to be reset
931 public bool AcceptAsync (SocketAsyncEventArgs e)
933 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
935 ThrowIfDisposedAndClosed ();
938 throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
940 throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
941 if (e.BufferList != null)
942 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
944 throw new ArgumentOutOfRangeException ("e.Count");
946 Socket acceptSocket = e.AcceptSocket;
947 if (acceptSocket != null) {
948 if (acceptSocket.is_bound || acceptSocket.is_connected)
949 throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
952 InitSocketAsyncEventArgs (e, AcceptAsyncCallback, e, SocketOperation.Accept);
954 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, e.socket_async_result));
959 static AsyncCallback AcceptAsyncCallback = new AsyncCallback (ares => {
960 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
962 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
963 throw new InvalidOperationException ("No operation in progress");
966 e.AcceptSocket = e.current_socket.EndAccept (ares);
967 } catch (SocketException ex) {
968 e.SocketError = ex.SocketErrorCode;
969 } catch (ObjectDisposedException) {
970 e.SocketError = SocketError.OperationAborted;
972 if (e.AcceptSocket == null)
973 e.AcceptSocket = new Socket (e.current_socket.AddressFamily, e.current_socket.SocketType, e.current_socket.ProtocolType, null);
978 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
980 ThrowIfDisposedAndClosed ();
982 if (!is_bound || !is_listening)
983 throw new InvalidOperationException ();
985 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Accept);
987 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, sockares));
992 static IOAsyncCallback BeginAcceptCallback = new IOAsyncCallback (ares => {
993 SocketAsyncResult sockares = (SocketAsyncResult) ares;
994 Socket acc_socket = null;
996 if (sockares.AcceptSocket == null) {
997 acc_socket = sockares.socket.Accept ();
999 acc_socket = sockares.AcceptSocket;
1000 sockares.socket.Accept (acc_socket);
1003 } catch (Exception e) {
1004 sockares.Complete (e);
1007 sockares.Complete (acc_socket);
1010 public IAsyncResult BeginAccept (int receiveSize, AsyncCallback callback, object state)
1012 ThrowIfDisposedAndClosed ();
1014 if (receiveSize < 0)
1015 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
1017 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
1018 Buffer = new byte [receiveSize],
1021 SockFlags = SocketFlags.None,
1024 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
1029 public IAsyncResult BeginAccept (Socket acceptSocket, int receiveSize, AsyncCallback callback, object state)
1031 ThrowIfDisposedAndClosed ();
1033 if (receiveSize < 0)
1034 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
1036 if (acceptSocket != null) {
1037 ThrowIfDisposedAndClosed (acceptSocket);
1039 if (acceptSocket.IsBound)
1040 throw new InvalidOperationException ();
1042 /* For some reason the MS runtime
1043 * barfs if the new socket is not TCP,
1044 * even though it's just about to blow
1045 * away all those parameters
1047 if (acceptSocket.ProtocolType != ProtocolType.Tcp)
1048 throw new SocketException ((int)SocketError.InvalidArgument);
1051 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
1052 Buffer = new byte [receiveSize],
1055 SockFlags = SocketFlags.None,
1056 AcceptSocket = acceptSocket,
1059 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
1064 static IOAsyncCallback BeginAcceptReceiveCallback = new IOAsyncCallback (ares => {
1065 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1066 Socket acc_socket = null;
1069 if (sockares.AcceptSocket == null) {
1070 acc_socket = sockares.socket.Accept ();
1072 acc_socket = sockares.AcceptSocket;
1073 sockares.socket.Accept (acc_socket);
1075 } catch (Exception e) {
1076 sockares.Complete (e);
1080 /* It seems the MS runtime special-cases 0-length requested receive data. See bug 464201. */
1082 if (sockares.Size > 0) {
1085 total = acc_socket.Receive_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out error);
1087 sockares.Complete (new SocketException ((int) error));
1090 } catch (Exception e) {
1091 sockares.Complete (e);
1096 sockares.Complete (acc_socket, total);
1099 public Socket EndAccept (IAsyncResult result)
1103 return EndAccept (out buffer, out bytes, result);
1106 public Socket EndAccept (out byte[] buffer, IAsyncResult asyncResult)
1109 return EndAccept (out buffer, out bytes, asyncResult);
1112 public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
1114 ThrowIfDisposedAndClosed ();
1116 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndAccept", "asyncResult");
1118 if (!sockares.IsCompleted)
1119 sockares.AsyncWaitHandle.WaitOne ();
1121 sockares.CheckIfThrowDelayedException ();
1123 buffer = sockares.Buffer;
1124 bytesTransferred = sockares.Total;
1126 return sockares.AcceptedSocket;
1129 static SafeSocketHandle Accept_internal (SafeSocketHandle safeHandle, out int error, bool blocking)
1132 safeHandle.RegisterForBlockingSyscall ();
1133 var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
1134 return new SafeSocketHandle (ret, true);
1136 safeHandle.UnRegisterForBlockingSyscall ();
1140 /* Creates a new system socket, returning the handle */
1141 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1142 extern static IntPtr Accept_internal (IntPtr sock, out int error, bool blocking);
1148 public void Bind (EndPoint local_end)
1150 ThrowIfDisposedAndClosed ();
1152 if (local_end == null)
1153 throw new ArgumentNullException("local_end");
1155 var ipEndPoint = local_end as IPEndPoint;
1156 if (ipEndPoint != null) {
1157 local_end = RemapIPEndPoint (ipEndPoint);
1161 Bind_internal (safe_handle, local_end.Serialize(), out error);
1164 throw new SocketException (error);
1168 seed_endpoint = local_end;
1171 private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1173 bool release = false;
1175 safeHandle.DangerousAddRef (ref release);
1176 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
1179 safeHandle.DangerousRelease ();
1183 // Creates a new system socket, returning the handle
1184 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1185 private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
1191 public void Listen (int backlog)
1193 ThrowIfDisposedAndClosed ();
1196 throw new SocketException ((int) SocketError.InvalidArgument);
1199 Listen_internal(safe_handle, backlog, out error);
1202 throw new SocketException (error);
1204 is_listening = true;
1207 static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
1209 bool release = false;
1211 safeHandle.DangerousAddRef (ref release);
1212 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
1215 safeHandle.DangerousRelease ();
1219 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1220 extern static void Listen_internal (IntPtr sock, int backlog, out int error);
1226 public void Connect (IPAddress address, int port)
1228 Connect (new IPEndPoint (address, port));
1231 public void Connect (string host, int port)
1233 Connect (Dns.GetHostAddresses (host), port);
1236 public void Connect (IPAddress[] addresses, int port)
1238 ThrowIfDisposedAndClosed ();
1240 if (addresses == null)
1241 throw new ArgumentNullException ("addresses");
1242 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1243 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1245 throw new InvalidOperationException ();
1247 // FIXME: do non-blocking sockets Poll here?
1249 foreach (IPAddress address in addresses) {
1250 IPEndPoint iep = new IPEndPoint (address, port);
1252 iep = RemapIPEndPoint (iep);
1254 Connect_internal (safe_handle, iep.Serialize (), out error);
1256 is_connected = true;
1258 seed_endpoint = iep;
1261 if (error != (int)SocketError.InProgress && error != (int)SocketError.WouldBlock)
1265 Poll (-1, SelectMode.SelectWrite);
1266 error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1268 is_connected = true;
1270 seed_endpoint = iep;
1277 throw new SocketException (error);
1281 public void Connect (EndPoint remoteEP)
1283 ThrowIfDisposedAndClosed ();
1285 if (remoteEP == null)
1286 throw new ArgumentNullException ("remoteEP");
1288 IPEndPoint ep = remoteEP as IPEndPoint;
1289 /* Dgram uses Any to 'disconnect' */
1290 if (ep != null && socket_type != SocketType.Dgram) {
1291 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1292 throw new SocketException ((int) SocketError.AddressNotAvailable);
1296 throw new InvalidOperationException ();
1299 remoteEP = RemapIPEndPoint (ep);
1302 SocketAddress serial = remoteEP.Serialize ();
1305 Connect_internal (safe_handle, serial, out error);
1307 if (error == 0 || error == 10035)
1308 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1312 error = SOCKET_CLOSED_CODE;
1313 throw new SocketException (error);
1316 is_connected = !(socket_type == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
1320 public bool ConnectAsync (SocketAsyncEventArgs e)
1322 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1324 ThrowIfDisposedAndClosed ();
1327 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1328 if (e.RemoteEndPoint == null)
1329 throw new ArgumentNullException ("remoteEP");
1331 InitSocketAsyncEventArgs (e, null, e, SocketOperation.Connect);
1334 IPAddress [] addresses;
1335 SocketAsyncResult ares;
1337 if (!GetCheckedIPs (e, out addresses)) {
1338 e.socket_async_result.EndPoint = e.RemoteEndPoint;
1339 ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
1341 DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1342 e.socket_async_result.Addresses = addresses;
1343 e.socket_async_result.Port = dep.Port;
1344 ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
1347 if (ares.IsCompleted && ares.CompletedSynchronously) {
1348 ares.CheckIfThrowDelayedException ();
1351 } catch (Exception exc) {
1352 e.socket_async_result.Complete (exc, true);
1359 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
1361 var sock = new Socket (e.RemoteEndPoint.AddressFamily, socketType, protocolType);
1362 return sock.ConnectAsync (e);
1365 public static void CancelConnectAsync (SocketAsyncEventArgs e)
1368 throw new ArgumentNullException("e");
1370 if (e.in_progress != 0 && e.LastOperation == SocketAsyncOperation.Connect)
1371 e.current_socket.Close();
1374 static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
1375 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1377 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1378 throw new InvalidOperationException ("No operation in progress");
1381 e.current_socket.EndConnect (ares);
1382 } catch (SocketException se) {
1383 e.SocketError = se.SocketErrorCode;
1384 } catch (ObjectDisposedException) {
1385 e.SocketError = SocketError.OperationAborted;
1391 public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback callback, object state)
1393 ThrowIfDisposedAndClosed ();
1395 if (address == null)
1396 throw new ArgumentNullException ("address");
1397 if (address.ToString ().Length == 0)
1398 throw new ArgumentException ("The length of the IP address is zero");
1399 if (port <= 0 || port > 65535)
1400 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1402 throw new InvalidOperationException ();
1404 return BeginConnect (new IPEndPoint (address, port), callback, state);
1407 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
1409 ThrowIfDisposedAndClosed ();
1412 throw new ArgumentNullException ("host");
1413 if (address_family != AddressFamily.InterNetwork && address_family != AddressFamily.InterNetworkV6)
1414 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1415 if (port <= 0 || port > 65535)
1416 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1418 throw new InvalidOperationException ();
1420 return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1423 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
1425 ThrowIfDisposedAndClosed ();
1427 if (end_point == null)
1428 throw new ArgumentNullException ("end_point");
1430 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1431 EndPoint = end_point,
1434 // Bug #75154: Connect() should not succeed for .Any addresses.
1435 if (end_point is IPEndPoint) {
1436 IPEndPoint ep = (IPEndPoint) end_point;
1437 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1438 sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1442 end_point = RemapIPEndPoint (ep);
1447 if (connect_in_progress) {
1448 // This could happen when multiple IPs are used
1449 // Calling connect() again will reset the connection attempt and cause
1450 // an error. Better to just close the socket and move on.
1451 connect_in_progress = false;
1452 safe_handle.Dispose ();
1453 safe_handle = new SafeSocketHandle (Socket_internal (address_family, socket_type, protocol_type, out error), true);
1455 throw new SocketException (error);
1458 bool blk = is_blocking;
1461 Connect_internal (safe_handle, end_point.Serialize (), out error);
1467 is_connected = true;
1469 sockares.Complete (true);
1473 if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1475 is_connected = false;
1477 sockares.Complete (new SocketException (error), true);
1482 is_connected = false;
1484 connect_in_progress = true;
1486 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
1491 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1493 ThrowIfDisposedAndClosed ();
1495 if (addresses == null)
1496 throw new ArgumentNullException ("addresses");
1497 if (addresses.Length == 0)
1498 throw new ArgumentException ("Empty addresses list");
1499 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1500 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1501 if (port <= 0 || port > 65535)
1502 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1504 throw new InvalidOperationException ();
1506 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1507 Addresses = addresses,
1511 is_connected = false;
1513 return BeginMConnect (sockares);
1516 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1518 SocketAsyncResult ares = null;
1519 Exception exc = null;
1520 AsyncCallback callback;
1522 for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1524 sockares.CurrentAddress++;
1526 ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1527 if (ares.IsCompleted && ares.CompletedSynchronously) {
1528 ares.CheckIfThrowDelayedException ();
1530 callback = ares.AsyncCallback;
1531 if (callback != null)
1532 ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
1536 } catch (Exception e) {
1548 static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
1549 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1551 if (sockares.EndPoint == null) {
1552 sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
1556 SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
1557 bool is_mconnect = mconnect != null && mconnect.Addresses != null;
1560 EndPoint ep = sockares.EndPoint;
1561 int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1563 if (error_code == 0) {
1565 sockares = mconnect;
1567 sockares.socket.seed_endpoint = ep;
1568 sockares.socket.is_connected = true;
1569 sockares.socket.is_bound = true;
1570 sockares.socket.connect_in_progress = false;
1572 sockares.Complete ();
1577 sockares.socket.connect_in_progress = false;
1578 sockares.Complete (new SocketException (error_code));
1582 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
1583 mconnect.Complete (new SocketException (error_code));
1587 mconnect.socket.BeginMConnect (mconnect);
1588 } catch (Exception e) {
1589 sockares.socket.connect_in_progress = false;
1592 sockares = mconnect;
1594 sockares.Complete (e);
1599 public void EndConnect (IAsyncResult result)
1601 ThrowIfDisposedAndClosed ();
1603 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1605 if (!sockares.IsCompleted)
1606 sockares.AsyncWaitHandle.WaitOne();
1608 sockares.CheckIfThrowDelayedException();
1611 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1614 safeHandle.RegisterForBlockingSyscall ();
1615 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
1617 safeHandle.UnRegisterForBlockingSyscall ();
1621 /* Connects to the remote address */
1622 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1623 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error);
1626 * - false when it is ok to use RemoteEndPoint
1627 * - true when addresses must be used (and addresses could be null/empty) */
1628 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1632 // Connect to the first address that match the host name, like:
1633 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1634 // while skipping entries that do not match the address family
1635 DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1637 addresses = Dns.GetHostAddresses (dep.Host);
1640 e.ConnectByNameError = null;
1649 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1650 * if the platform is newer than w2k. We should be able to cope... */
1651 public void Disconnect (bool reuseSocket)
1653 ThrowIfDisposedAndClosed ();
1656 Disconnect_internal (safe_handle, reuseSocket, out error);
1660 /* ERROR_NOT_SUPPORTED */
1661 throw new PlatformNotSupportedException ();
1663 throw new SocketException (error);
1667 is_connected = false;
1669 /* Do managed housekeeping here... */
1673 public bool DisconnectAsync (SocketAsyncEventArgs e)
1675 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1677 ThrowIfDisposedAndClosed ();
1679 InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
1681 IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
1686 static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
1687 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1689 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1690 throw new InvalidOperationException ("No operation in progress");
1693 e.current_socket.EndDisconnect (ares);
1694 } catch (SocketException ex) {
1695 e.SocketError = ex.SocketErrorCode;
1696 } catch (ObjectDisposedException) {
1697 e.SocketError = SocketError.OperationAborted;
1703 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1705 ThrowIfDisposedAndClosed ();
1707 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1708 ReuseSocket = reuseSocket,
1711 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
1716 static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
1717 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1720 sockares.socket.Disconnect (sockares.ReuseSocket);
1721 } catch (Exception e) {
1722 sockares.Complete (e);
1726 sockares.Complete ();
1729 public void EndDisconnect (IAsyncResult asyncResult)
1731 ThrowIfDisposedAndClosed ();
1733 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1735 if (!sockares.IsCompleted)
1736 sockares.AsyncWaitHandle.WaitOne ();
1738 sockares.CheckIfThrowDelayedException ();
1741 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1743 bool release = false;
1745 safeHandle.DangerousAddRef (ref release);
1746 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1749 safeHandle.DangerousRelease ();
1753 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1754 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1760 public int Receive (byte [] buffer)
1762 return Receive (buffer, SocketFlags.None);
1765 public int Receive (byte [] buffer, SocketFlags flags)
1767 ThrowIfDisposedAndClosed ();
1768 ThrowIfBufferNull (buffer);
1769 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
1772 int ret = Receive_nochecks (buffer, 0, buffer.Length, flags, out error);
1774 if (error != SocketError.Success) {
1775 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1776 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1777 throw new SocketException ((int) error);
1783 public int Receive (byte [] buffer, int size, SocketFlags flags)
1785 ThrowIfDisposedAndClosed ();
1786 ThrowIfBufferNull (buffer);
1787 ThrowIfBufferOutOfRange (buffer, 0, size);
1790 int ret = Receive_nochecks (buffer, 0, size, flags, out error);
1792 if (error != SocketError.Success) {
1793 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1794 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1795 throw new SocketException ((int) error);
1801 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags)
1803 ThrowIfDisposedAndClosed ();
1804 ThrowIfBufferNull (buffer);
1805 ThrowIfBufferOutOfRange (buffer, offset, size);
1808 int ret = Receive_nochecks (buffer, offset, size, flags, out error);
1810 if (error != SocketError.Success) {
1811 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1812 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1813 throw new SocketException ((int) error);
1819 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
1821 ThrowIfDisposedAndClosed ();
1822 ThrowIfBufferNull (buffer);
1823 ThrowIfBufferOutOfRange (buffer, offset, size);
1825 return Receive_nochecks (buffer, offset, size, flags, out error);
1828 public int Receive (IList<ArraySegment<byte>> buffers)
1831 int ret = Receive (buffers, SocketFlags.None, out error);
1833 if (error != SocketError.Success)
1834 throw new SocketException ((int) error);
1839 [CLSCompliant (false)]
1840 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1843 int ret = Receive (buffers, socketFlags, out error);
1845 if (error != SocketError.Success)
1846 throw new SocketException ((int) error);
1851 [CLSCompliant (false)]
1852 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1854 ThrowIfDisposedAndClosed ();
1856 if (buffers == null || buffers.Count == 0)
1857 throw new ArgumentNullException ("buffers");
1859 int numsegments = buffers.Count;
1863 /* Only example I can find of sending a byte array reference directly into an internal
1864 * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1865 * so taking a lead from that... */
1866 WSABUF[] bufarray = new WSABUF[numsegments];
1867 GCHandle[] gch = new GCHandle[numsegments];
1869 for (int i = 0; i < numsegments; i++) {
1870 ArraySegment<byte> segment = buffers[i];
1872 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1873 throw new ArgumentOutOfRangeException ("segment");
1875 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1876 bufarray[i].len = segment.Count;
1877 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1881 ret = Receive_internal (safe_handle, bufarray, socketFlags, out nativeError);
1883 for (int i = 0; i < numsegments; i++) {
1884 if (gch[i].IsAllocated)
1889 errorCode = (SocketError) nativeError;
1894 public bool ReceiveAsync (SocketAsyncEventArgs e)
1896 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1898 ThrowIfDisposedAndClosed ();
1900 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1901 // thrown when e.Buffer and e.BufferList are null (works fine when one is
1902 // set to a valid object)
1903 if (e.Buffer == null && e.BufferList == null)
1904 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1906 if (e.Buffer == null) {
1907 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
1909 e.socket_async_result.Buffers = e.BufferList;
1911 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
1913 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
1915 e.socket_async_result.Buffer = e.Buffer;
1916 e.socket_async_result.Offset = e.Offset;
1917 e.socket_async_result.Size = e.Count;
1919 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
1925 static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
1926 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1928 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1929 throw new InvalidOperationException ("No operation in progress");
1932 e.BytesTransferred = e.current_socket.EndReceive (ares);
1933 } catch (SocketException se){
1934 e.SocketError = se.SocketErrorCode;
1935 } catch (ObjectDisposedException) {
1936 e.SocketError = SocketError.OperationAborted;
1942 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
1944 ThrowIfDisposedAndClosed ();
1945 ThrowIfBufferNull (buffer);
1946 ThrowIfBufferOutOfRange (buffer, offset, size);
1948 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1952 SockFlags = socket_flags,
1955 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
1960 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags flags, out SocketError error, AsyncCallback callback, object state)
1962 /* As far as I can tell from the docs and from experimentation, a pointer to the
1963 * SocketError parameter is not supposed to be saved for the async parts. And as we don't
1964 * set any socket errors in the setup code, we just have to set it to Success. */
1965 error = SocketError.Success;
1966 return BeginReceive (buffer, offset, size, flags, callback, state);
1969 static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
1970 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1974 total = Receive_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
1975 } catch (Exception e) {
1976 sockares.Complete (e);
1980 sockares.Complete (total);
1983 [CLSCompliant (false)]
1984 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
1986 ThrowIfDisposedAndClosed ();
1988 if (buffers == null)
1989 throw new ArgumentNullException ("buffers");
1991 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1993 SockFlags = socketFlags,
1996 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
2001 [CLSCompliant (false)]
2002 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2004 /* I assume the same SocketError semantics as above */
2005 errorCode = SocketError.Success;
2006 return BeginReceive (buffers, socketFlags, callback, state);
2009 static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
2010 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2014 total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
2015 } catch (Exception e) {
2016 sockares.Complete (e);
2020 sockares.Complete (total);
2023 public int EndReceive (IAsyncResult result)
2026 int bytesReceived = EndReceive (result, out error);
2028 if (error != SocketError.Success) {
2029 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2030 is_connected = false;
2031 throw new SocketException ((int)error);
2034 return bytesReceived;
2037 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
2039 ThrowIfDisposedAndClosed ();
2041 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
2043 if (!sockares.IsCompleted)
2044 sockares.AsyncWaitHandle.WaitOne ();
2046 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
2047 // kinds of exceptions that should be thrown.
2048 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2049 sockares.CheckIfThrowDelayedException();
2051 return sockares.Total;
2054 int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2057 int ret = Receive_internal (safe_handle, buf, offset, size, flags, out nativeError);
2059 error = (SocketError) nativeError;
2060 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2061 is_connected = false;
2064 is_connected = true;
2070 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2073 safeHandle.RegisterForBlockingSyscall ();
2074 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2076 safeHandle.UnRegisterForBlockingSyscall ();
2080 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2081 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2083 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
2086 safeHandle.RegisterForBlockingSyscall ();
2087 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
2089 safeHandle.UnRegisterForBlockingSyscall ();
2093 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2094 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error);
2100 public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
2102 ThrowIfDisposedAndClosed ();
2103 ThrowIfBufferNull (buffer);
2105 return ReceiveFrom (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
2108 public int ReceiveFrom (byte [] buffer, SocketFlags flags, ref EndPoint remoteEP)
2110 ThrowIfDisposedAndClosed ();
2111 ThrowIfBufferNull (buffer);
2113 return ReceiveFrom (buffer, 0, buffer.Length, flags, ref remoteEP);
2116 public int ReceiveFrom (byte [] buffer, int size, SocketFlags flags, ref EndPoint remoteEP)
2118 ThrowIfDisposedAndClosed ();
2119 ThrowIfBufferNull (buffer);
2120 ThrowIfBufferOutOfRange (buffer, 0, size);
2122 return ReceiveFrom (buffer, 0, size, flags, ref remoteEP);
2125 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags flags, ref EndPoint remoteEP)
2127 ThrowIfDisposedAndClosed ();
2128 ThrowIfBufferNull (buffer);
2129 ThrowIfBufferOutOfRange (buffer, offset, size);
2131 if (remoteEP == null)
2132 throw new ArgumentNullException ("remoteEP");
2135 return ReceiveFrom_nochecks_exc (buffer, offset, size, flags, ref remoteEP, true, out error);
2138 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
2140 ThrowIfDisposedAndClosed ();
2142 // We do not support recv into multiple buffers yet
2143 if (e.BufferList != null)
2144 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2145 if (e.RemoteEndPoint == null)
2146 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2148 InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
2150 e.socket_async_result.Buffer = e.Buffer;
2151 e.socket_async_result.Offset = e.Offset;
2152 e.socket_async_result.Size = e.Count;
2153 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2154 e.socket_async_result.SockFlags = e.SocketFlags;
2156 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
2161 static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
2162 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2164 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2165 throw new InvalidOperationException ("No operation in progress");
2168 e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
2169 } catch (SocketException ex) {
2170 e.SocketError = ex.SocketErrorCode;
2171 } catch (ObjectDisposedException) {
2172 e.SocketError = SocketError.OperationAborted;
2178 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
2180 ThrowIfDisposedAndClosed ();
2181 ThrowIfBufferNull (buffer);
2182 ThrowIfBufferOutOfRange (buffer, offset, size);
2184 if (remote_end == null)
2185 throw new ArgumentNullException ("remote_end");
2187 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
2191 SockFlags = socket_flags,
2192 EndPoint = remote_end,
2195 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
2200 static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
2201 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2206 total = sockares.socket.ReceiveFrom_nochecks_exc (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, true, out error);
2207 } catch (Exception e) {
2208 sockares.Complete (e);
2212 sockares.Complete (total);
2215 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
2217 ThrowIfDisposedAndClosed ();
2219 if (end_point == null)
2220 throw new ArgumentNullException ("remote_end");
2222 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
2224 if (!sockares.IsCompleted)
2225 sockares.AsyncWaitHandle.WaitOne();
2227 sockares.CheckIfThrowDelayedException();
2229 end_point = sockares.EndPoint;
2231 return sockares.Total;
2234 internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end, bool throwOnError, out int error)
2236 SocketAddress sockaddr = remote_end.Serialize();
2238 int cnt = ReceiveFrom_internal (safe_handle, buf, offset, size, flags, ref sockaddr, out error);
2240 SocketError err = (SocketError) error;
2242 if (err != SocketError.WouldBlock && err != SocketError.InProgress) {
2243 is_connected = false;
2244 } else if (err == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
2246 throw new SocketException ((int) SocketError.TimedOut, TIMEOUT_EXCEPTION_MSG);
2247 error = (int) SocketError.TimedOut;
2252 throw new SocketException (error);
2257 is_connected = true;
2260 /* If sockaddr is null then we're a connection oriented protocol and should ignore the
2261 * remote_end parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
2262 if (sockaddr != null) {
2263 /* Stupidly, EndPoint.Create() is an instance method */
2264 remote_end = remote_end.Create (sockaddr);
2267 seed_endpoint = remote_end;
2272 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error)
2275 safeHandle.RegisterForBlockingSyscall ();
2276 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
2278 safeHandle.UnRegisterForBlockingSyscall ();
2282 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2283 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error);
2287 #region ReceiveMessageFrom
2289 [MonoTODO ("Not implemented")]
2290 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
2292 ThrowIfDisposedAndClosed ();
2293 ThrowIfBufferNull (buffer);
2294 ThrowIfBufferOutOfRange (buffer, offset, size);
2296 if (remoteEP == null)
2297 throw new ArgumentNullException ("remoteEP");
2299 // FIXME: figure out how we get hold of the IPPacketInformation
2300 throw new NotImplementedException ();
2303 [MonoTODO ("Not implemented")]
2304 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
2306 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2308 ThrowIfDisposedAndClosed ();
2310 throw new NotImplementedException ();
2314 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
2316 ThrowIfDisposedAndClosed ();
2317 ThrowIfBufferNull (buffer);
2318 ThrowIfBufferOutOfRange (buffer, offset, size);
2320 if (remoteEP == null)
2321 throw new ArgumentNullException ("remoteEP");
2323 throw new NotImplementedException ();
2327 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
2329 ThrowIfDisposedAndClosed ();
2331 if (endPoint == null)
2332 throw new ArgumentNullException ("endPoint");
2334 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
2336 throw new NotImplementedException ();
2343 public int Send (byte [] buffer)
2345 ThrowIfDisposedAndClosed ();
2346 ThrowIfBufferNull (buffer);
2347 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2350 int ret = Send_nochecks (buffer, 0, buffer.Length, SocketFlags.None, out error);
2352 if (error != SocketError.Success)
2353 throw new SocketException ((int) error);
2358 public int Send (byte [] buffer, SocketFlags flags)
2360 ThrowIfDisposedAndClosed ();
2361 ThrowIfBufferNull (buffer);
2362 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2365 int ret = Send_nochecks (buffer, 0, buffer.Length, flags, out error);
2367 if (error != SocketError.Success)
2368 throw new SocketException ((int) error);
2373 public int Send (byte [] buffer, int size, SocketFlags flags)
2375 ThrowIfDisposedAndClosed ();
2376 ThrowIfBufferNull (buffer);
2377 ThrowIfBufferOutOfRange (buffer, 0, size);
2380 int ret = Send_nochecks (buffer, 0, size, flags, out error);
2382 if (error != SocketError.Success)
2383 throw new SocketException ((int) error);
2388 public int Send (byte [] buffer, int offset, int size, SocketFlags flags)
2390 ThrowIfDisposedAndClosed ();
2391 ThrowIfBufferNull (buffer);
2392 ThrowIfBufferOutOfRange (buffer, offset, size);
2395 int ret = Send_nochecks (buffer, offset, size, flags, out error);
2397 if (error != SocketError.Success)
2398 throw new SocketException ((int) error);
2403 public int Send (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
2405 ThrowIfDisposedAndClosed ();
2406 ThrowIfBufferNull (buffer);
2407 ThrowIfBufferOutOfRange (buffer, offset, size);
2409 return Send_nochecks (buffer, offset, size, flags, out error);
2413 int Send (IList<ArraySegment<byte>> buffers)
2416 int ret = Send (buffers, SocketFlags.None, out error);
2418 if (error != SocketError.Success)
2419 throw new SocketException ((int) error);
2425 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
2428 int ret = Send (buffers, socketFlags, out error);
2430 if (error != SocketError.Success)
2431 throw new SocketException ((int) error);
2436 [CLSCompliant (false)]
2437 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
2439 ThrowIfDisposedAndClosed ();
2441 if (buffers == null)
2442 throw new ArgumentNullException ("buffers");
2443 if (buffers.Count == 0)
2444 throw new ArgumentException ("Buffer is empty", "buffers");
2446 int numsegments = buffers.Count;
2450 WSABUF[] bufarray = new WSABUF[numsegments];
2451 GCHandle[] gch = new GCHandle[numsegments];
2453 for(int i = 0; i < numsegments; i++) {
2454 ArraySegment<byte> segment = buffers[i];
2456 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
2457 throw new ArgumentOutOfRangeException ("segment");
2459 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
2460 bufarray[i].len = segment.Count;
2461 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
2465 ret = Send_internal (safe_handle, bufarray, socketFlags, out nativeError);
2467 for(int i = 0; i < numsegments; i++) {
2468 if (gch[i].IsAllocated) {
2474 errorCode = (SocketError)nativeError;
2479 int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2482 error = SocketError.Success;
2487 int ret = Send_internal (safe_handle, buf, offset, size, flags, out nativeError);
2489 error = (SocketError)nativeError;
2491 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2492 is_connected = false;
2495 is_connected = true;
2501 public bool SendAsync (SocketAsyncEventArgs e)
2503 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2505 ThrowIfDisposedAndClosed ();
2507 if (e.Buffer == null && e.BufferList == null)
2508 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
2510 if (e.Buffer == null) {
2511 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
2513 e.socket_async_result.Buffers = e.BufferList;
2515 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
2517 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
2519 e.socket_async_result.Buffer = e.Buffer;
2520 e.socket_async_result.Offset = e.Offset;
2521 e.socket_async_result.Size = e.Count;
2523 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2529 static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
2530 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2532 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2533 throw new InvalidOperationException ("No operation in progress");
2536 e.BytesTransferred = e.current_socket.EndSend (ares);
2537 } catch (SocketException se){
2538 e.SocketError = se.SocketErrorCode;
2539 } catch (ObjectDisposedException) {
2540 e.SocketError = SocketError.OperationAborted;
2546 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2548 if (!is_connected) {
2549 errorCode = SocketError.NotConnected;
2550 throw new SocketException ((int) errorCode);
2553 errorCode = SocketError.Success;
2554 return BeginSend (buffer, offset, size, socketFlags, callback, state);
2557 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
2559 ThrowIfDisposedAndClosed ();
2560 ThrowIfBufferNull (buffer);
2561 ThrowIfBufferOutOfRange (buffer, offset, size);
2564 throw new SocketException ((int)SocketError.NotConnected);
2566 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
2570 SockFlags = socket_flags,
2573 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
2578 static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
2583 total = Socket.Send_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
2584 } catch (Exception e) {
2585 sockares.Complete (e);
2589 if (sockares.error == 0) {
2590 sent_so_far += total;
2591 sockares.Offset += total;
2592 sockares.Size -= total;
2594 if (sockares.socket.is_disposed) {
2595 sockares.Complete (total);
2599 if (sockares.Size > 0) {
2600 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2601 return; // Have to finish writing everything. See bug #74475.
2604 sockares.Total = sent_so_far;
2607 sockares.Complete (total);
2610 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
2612 ThrowIfDisposedAndClosed ();
2614 if (buffers == null)
2615 throw new ArgumentNullException ("buffers");
2617 throw new SocketException ((int)SocketError.NotConnected);
2619 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
2621 SockFlags = socketFlags,
2624 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
2629 [CLSCompliant (false)]
2630 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2632 if (!is_connected) {
2633 errorCode = SocketError.NotConnected;
2634 throw new SocketException ((int)errorCode);
2637 errorCode = SocketError.Success;
2638 return BeginSend (buffers, socketFlags, callback, state);
2641 static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
2642 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2646 total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
2647 } catch (Exception e) {
2648 sockares.Complete (e);
2652 sockares.Complete (total);
2655 public int EndSend (IAsyncResult result)
2658 int bytesSent = EndSend (result, out error);
2660 if (error != SocketError.Success) {
2661 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2662 is_connected = false;
2663 throw new SocketException ((int)error);
2669 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
2671 ThrowIfDisposedAndClosed ();
2673 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
2675 if (!sockares.IsCompleted)
2676 sockares.AsyncWaitHandle.WaitOne ();
2678 /* If no socket error occurred, call CheckIfThrowDelayedException in
2679 * case there are other kinds of exceptions that should be thrown.*/
2680 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2681 sockares.CheckIfThrowDelayedException ();
2683 return sockares.Total;
2686 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2688 bool release = false;
2690 safeHandle.DangerousAddRef (ref release);
2691 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2694 safeHandle.DangerousRelease ();
2698 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2699 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2701 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
2704 safeHandle.RegisterForBlockingSyscall ();
2705 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
2707 safeHandle.UnRegisterForBlockingSyscall ();
2711 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2712 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
2718 public int SendTo (byte [] buffer, EndPoint remote_end)
2720 ThrowIfDisposedAndClosed ();
2721 ThrowIfBufferNull (buffer);
2723 return SendTo (buffer, 0, buffer.Length, SocketFlags.None, remote_end);
2726 public int SendTo (byte [] buffer, SocketFlags flags, EndPoint remote_end)
2728 ThrowIfDisposedAndClosed ();
2729 ThrowIfBufferNull (buffer);
2731 return SendTo (buffer, 0, buffer.Length, flags, remote_end);
2734 public int SendTo (byte [] buffer, int size, SocketFlags flags, EndPoint remote_end)
2736 return SendTo (buffer, 0, size, flags, remote_end);
2739 public int SendTo (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2741 ThrowIfDisposedAndClosed ();
2742 ThrowIfBufferNull (buffer);
2743 ThrowIfBufferOutOfRange (buffer, offset, size);
2745 if (remote_end == null)
2746 throw new ArgumentNullException("remote_end");
2748 return SendTo_nochecks (buffer, offset, size, flags, remote_end);
2751 public bool SendToAsync (SocketAsyncEventArgs e)
2753 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2755 ThrowIfDisposedAndClosed ();
2757 if (e.BufferList != null)
2758 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2759 if (e.RemoteEndPoint == null)
2760 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2762 InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2764 e.socket_async_result.Buffer = e.Buffer;
2765 e.socket_async_result.Offset = e.Offset;
2766 e.socket_async_result.Size = e.Count;
2767 e.socket_async_result.SockFlags = e.SocketFlags;
2768 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2770 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2775 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2776 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2778 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2779 throw new InvalidOperationException ("No operation in progress");
2782 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2783 } catch (SocketException ex) {
2784 e.SocketError = ex.SocketErrorCode;
2785 } catch (ObjectDisposedException) {
2786 e.SocketError = SocketError.OperationAborted;
2792 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2794 ThrowIfDisposedAndClosed ();
2795 ThrowIfBufferNull (buffer);
2796 ThrowIfBufferOutOfRange (buffer, offset, size);
2798 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2802 SockFlags = socket_flags,
2803 EndPoint = remote_end,
2806 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2811 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2815 total = sockares.socket.SendTo_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2817 if (sockares.error == 0) {
2818 sent_so_far += total;
2819 sockares.Offset += total;
2820 sockares.Size -= total;
2823 if (sockares.Size > 0) {
2824 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2825 return; // Have to finish writing everything. See bug #74475.
2828 sockares.Total = sent_so_far;
2829 } catch (Exception e) {
2830 sockares.Complete (e);
2834 sockares.Complete ();
2837 public int EndSendTo (IAsyncResult result)
2839 ThrowIfDisposedAndClosed ();
2841 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2843 if (!sockares.IsCompleted)
2844 sockares.AsyncWaitHandle.WaitOne();
2846 sockares.CheckIfThrowDelayedException();
2848 return sockares.Total;
2851 int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2854 int ret = SendTo_internal (safe_handle, buffer, offset, size, flags, remote_end.Serialize (), out error);
2856 SocketError err = (SocketError) error;
2858 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2859 is_connected = false;
2860 throw new SocketException (error);
2863 is_connected = true;
2865 seed_endpoint = remote_end;
2870 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
2873 safeHandle.RegisterForBlockingSyscall ();
2874 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
2876 safeHandle.UnRegisterForBlockingSyscall ();
2880 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2881 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
2887 public void SendFile (string fileName)
2889 ThrowIfDisposedAndClosed ();
2892 throw new NotSupportedException ();
2894 throw new InvalidOperationException ();
2896 SendFile (fileName, null, null, 0);
2899 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2901 ThrowIfDisposedAndClosed ();
2904 throw new NotSupportedException ();
2906 throw new InvalidOperationException ();
2908 if (!SendFile_internal (safe_handle, fileName, preBuffer, postBuffer, flags)) {
2909 SocketException exc = new SocketException ();
2910 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2911 throw new FileNotFoundException ();
2916 public IAsyncResult BeginSendFile (string fileName, AsyncCallback callback, object state)
2918 ThrowIfDisposedAndClosed ();
2921 throw new NotSupportedException ();
2922 if (!File.Exists (fileName))
2923 throw new FileNotFoundException ();
2925 return BeginSendFile (fileName, null, null, 0, callback, state);
2928 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2930 ThrowIfDisposedAndClosed ();
2933 throw new NotSupportedException ();
2934 if (!File.Exists (fileName))
2935 throw new FileNotFoundException ();
2937 SendFileHandler handler = new SendFileHandler (SendFile);
2939 return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2942 public void EndSendFile (IAsyncResult asyncResult)
2944 ThrowIfDisposedAndClosed ();
2946 if (asyncResult == null)
2947 throw new ArgumentNullException ("asyncResult");
2949 SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2951 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2953 ares.Delegate.EndInvoke (ares.Original);
2956 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
2959 safeHandle.RegisterForBlockingSyscall ();
2960 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
2962 safeHandle.UnRegisterForBlockingSyscall ();
2966 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2967 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
2969 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2971 sealed class SendFileAsyncResult : IAsyncResult {
2975 public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2981 public object AsyncState {
2982 get { return ares.AsyncState; }
2985 public WaitHandle AsyncWaitHandle {
2986 get { return ares.AsyncWaitHandle; }
2989 public bool CompletedSynchronously {
2990 get { return ares.CompletedSynchronously; }
2993 public bool IsCompleted {
2994 get { return ares.IsCompleted; }
2997 public SendFileHandler Delegate {
3001 public IAsyncResult Original {
3002 get { return ares; }
3010 [MonoTODO ("Not implemented")]
3011 public bool SendPacketsAsync (SocketAsyncEventArgs e)
3013 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
3015 ThrowIfDisposedAndClosed ();
3017 throw new NotImplementedException ();
3022 #region DuplicateAndClose
3025 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
3026 public SocketInformation DuplicateAndClose (int targetProcessId)
3028 var si = new SocketInformation ();
3030 (is_listening ? SocketInformationOptions.Listening : 0) |
3031 (is_connected ? SocketInformationOptions.Connected : 0) |
3032 (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
3033 (use_overlapped_io ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
3035 si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, is_bound ? 1 : 0, (long)Handle);
3044 #region GetSocketOption
3046 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3048 ThrowIfDisposedAndClosed ();
3050 if (optionValue == null)
3051 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3054 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref optionValue, out error);
3057 throw new SocketException (error);
3060 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int length)
3062 ThrowIfDisposedAndClosed ();
3065 byte[] byte_val = new byte [length];
3066 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref byte_val, out error);
3069 throw new SocketException (error);
3074 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
3076 ThrowIfDisposedAndClosed ();
3080 GetSocketOption_obj_internal (safe_handle, optionLevel, optionName, out obj_val, out error);
3083 throw new SocketException (error);
3085 if (optionName == SocketOptionName.Linger)
3086 return (LingerOption) obj_val;
3087 else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
3088 return (MulticastOption) obj_val;
3089 else if (obj_val is int)
3090 return (int) obj_val;
3095 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
3097 bool release = false;
3099 safeHandle.DangerousAddRef (ref release);
3100 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
3103 safeHandle.DangerousRelease ();
3107 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3108 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
3110 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
3112 bool release = false;
3114 safeHandle.DangerousAddRef (ref release);
3115 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
3118 safeHandle.DangerousRelease ();
3122 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3123 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
3127 #region SetSocketOption
3129 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3131 ThrowIfDisposedAndClosed ();
3133 // I'd throw an ArgumentNullException, but this is what MS does.
3134 if (optionValue == null)
3135 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3138 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, optionValue, 0, out error);
3141 if (error == (int) SocketError.InvalidArgument)
3142 throw new ArgumentException ();
3143 throw new SocketException (error);
3147 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
3149 ThrowIfDisposedAndClosed ();
3151 // NOTE: if a null is passed, the byte[] overload is used instead...
3152 if (optionValue == null)
3153 throw new ArgumentNullException("optionValue");
3157 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
3158 LingerOption linger = optionValue as LingerOption;
3160 throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
3161 SetSocketOption_internal (safe_handle, optionLevel, optionName, linger, null, 0, out error);
3162 } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3163 MulticastOption multicast = optionValue as MulticastOption;
3164 if (multicast == null)
3165 throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
3166 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3167 } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3168 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
3169 if (multicast == null)
3170 throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
3171 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3173 throw new ArgumentException ("Invalid value specified.", "optionValue");
3177 if (error == (int) SocketError.InvalidArgument)
3178 throw new ArgumentException ();
3179 throw new SocketException (error);
3183 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
3185 int int_val = optionValue ? 1 : 0;
3187 SetSocketOption (optionLevel, optionName, int_val);
3190 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
3192 ThrowIfDisposedAndClosed ();
3194 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse (protocol_type))
3195 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.");
3198 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, optionValue, out error);
3201 if (error == (int) SocketError.InvalidArgument)
3202 throw new ArgumentException ();
3203 throw new SocketException (error);
3207 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
3209 bool release = false;
3211 safeHandle.DangerousAddRef (ref release);
3212 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
3215 safeHandle.DangerousRelease ();
3219 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3220 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
3226 public int IOControl (int ioctl_code, byte [] in_value, byte [] out_value)
3229 throw new ObjectDisposedException (GetType ().ToString ());
3232 int result = IOControl_internal (safe_handle, ioctl_code, in_value, out_value, out error);
3235 throw new SocketException (error);
3237 throw new InvalidOperationException ("Must use Blocking property instead.");
3242 public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
3244 return IOControl ((int) ioControlCode, optionInValue, optionOutValue);
3247 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
3249 bool release = false;
3251 safeHandle.DangerousAddRef (ref release);
3252 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
3255 safeHandle.DangerousRelease ();
3259 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
3260 * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
3261 * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
3262 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3263 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
3269 public void Close ()
3275 public void Close (int timeout)
3277 linger_timeout = timeout;
3281 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3282 internal extern static void Close_internal (IntPtr socket, out int error);
3288 public void Shutdown (SocketShutdown how)
3290 ThrowIfDisposedAndClosed ();
3293 throw new SocketException (10057); // Not connected
3296 Shutdown_internal (safe_handle, how, out error);
3299 throw new SocketException (error);
3302 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
3304 bool release = false;
3306 safeHandle.DangerousAddRef (ref release);
3307 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
3310 safeHandle.DangerousRelease ();
3314 [MethodImplAttribute (MethodImplOptions.InternalCall)]
3315 internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
3321 protected virtual void Dispose (bool disposing)
3327 bool was_connected = is_connected;
3328 is_connected = false;
3330 if (safe_handle != null) {
3337 safe_handle.Dispose ();
3341 public void Dispose ()
3344 GC.SuppressFinalize (this);
3347 void Linger (IntPtr handle)
3349 if (!is_connected || linger_timeout <= 0)
3352 /* We don't want to receive any more data */
3354 Shutdown_internal (handle, SocketShutdown.Receive, out error);
3359 int seconds = linger_timeout / 1000;
3360 int ms = linger_timeout % 1000;
3362 /* If the other end closes, this will return 'true' with 'Available' == 0 */
3363 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
3369 LingerOption linger = new LingerOption (true, seconds);
3370 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
3371 /* Not needed, we're closing upon return */
3379 void ThrowIfDisposedAndClosed (Socket socket)
3381 if (socket.is_disposed && socket.is_closed)
3382 throw new ObjectDisposedException (socket.GetType ().ToString ());
3385 void ThrowIfDisposedAndClosed ()
3387 if (is_disposed && is_closed)
3388 throw new ObjectDisposedException (GetType ().ToString ());
3391 void ThrowIfBufferNull (byte[] buffer)
3394 throw new ArgumentNullException ("buffer");
3397 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
3400 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
3401 if (offset > buffer.Length)
3402 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
3404 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
3405 if (size > buffer.Length - offset)
3406 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
3411 #if !NET_2_1 || MOBILE
3412 if (protocol_type == ProtocolType.Udp)
3413 throw new SocketException ((int)SocketError.ProtocolOption);
3417 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
3420 throw new ArgumentNullException (argName);
3422 SocketAsyncResult sockares = ares as SocketAsyncResult;
3423 if (sockares == null)
3424 throw new ArgumentException ("Invalid IAsyncResult", argName);
3425 if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
3426 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
3431 void QueueIOSelectorJob (Queue<KeyValuePair<IntPtr, IOSelectorJob>> queue, IntPtr handle, IOSelectorJob job)
3435 queue.Enqueue (new KeyValuePair<IntPtr, IOSelectorJob> (handle, job));
3436 count = queue.Count;
3440 IOSelector.Add (handle, job);
3443 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
3445 e.socket_async_result.Init (this, callback, state, operation);
3446 if (e.AcceptSocket != null) {
3447 e.socket_async_result.AcceptSocket = e.AcceptSocket;
3449 e.current_socket = this;
3450 e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
3451 e.SocketError = SocketError.Success;
3452 e.BytesTransferred = 0;
3455 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
3458 case SocketOperation.Connect:
3459 return SocketAsyncOperation.Connect;
3460 case SocketOperation.Accept:
3461 return SocketAsyncOperation.Accept;
3462 case SocketOperation.Disconnect:
3463 return SocketAsyncOperation.Disconnect;
3464 case SocketOperation.Receive:
3465 case SocketOperation.ReceiveGeneric:
3466 return SocketAsyncOperation.Receive;
3467 case SocketOperation.ReceiveFrom:
3468 return SocketAsyncOperation.ReceiveFrom;
3469 case SocketOperation.Send:
3470 case SocketOperation.SendGeneric:
3471 return SocketAsyncOperation.Send;
3472 case SocketOperation.SendTo:
3473 return SocketAsyncOperation.SendTo;
3475 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
3479 IPEndPoint RemapIPEndPoint (IPEndPoint input) {
3480 // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
3481 if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
3482 return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
3487 [StructLayout (LayoutKind.Sequential)]
3493 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3494 internal static extern void cancel_blocking_socket_operation (Thread thread);
3496 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3497 internal static extern bool SupportsPortReuse (ProtocolType proto);