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 var handle = Socket_internal (addressFamily, socketType, protocolType, out error);
208 this.safe_handle = new SafeSocketHandle (handle, true);
211 throw new SocketException (error);
213 #if !NET_2_1 || MOBILE
219 public Socket (SocketInformation socketInformation)
221 this.is_listening = (socketInformation.Options & SocketInformationOptions.Listening) != 0;
222 this.is_connected = (socketInformation.Options & SocketInformationOptions.Connected) != 0;
223 this.is_blocking = (socketInformation.Options & SocketInformationOptions.NonBlocking) == 0;
224 this.use_overlapped_io = (socketInformation.Options & SocketInformationOptions.UseOnlyOverlappedIO) != 0;
226 var result = Mono.DataConverter.Unpack ("iiiil", socketInformation.ProtocolInformation, 0);
228 this.address_family = (AddressFamily) (int) result [0];
229 this.socket_type = (SocketType) (int) result [1];
230 this.protocol_type = (ProtocolType) (int) result [2];
231 this.is_bound = (ProtocolType) (int) result [3] != 0;
232 this.safe_handle = new SafeSocketHandle ((IntPtr) (long) result [4], true);
238 /* private constructor used by Accept, which already has a socket handle to use */
239 internal Socket(AddressFamily family, SocketType type, ProtocolType proto, SafeSocketHandle safe_handle)
241 this.address_family = family;
242 this.socket_type = type;
243 this.protocol_type = proto;
245 this.safe_handle = safe_handle;
246 this.is_connected = true;
254 void SocketDefaults ()
257 /* Need to test IPv6 further */
258 if (address_family == AddressFamily.InterNetwork
259 // || address_family == AddressFamily.InterNetworkV6
261 /* This is the default, but it probably has nasty side
262 * effects on Linux, as the socket option is kludged by
263 * turning on or off PMTU discovery... */
264 this.DontFragment = false;
267 /* Microsoft sets these to 8192, but we are going to keep them
268 * both to the OS defaults as these have a big performance impact.
269 * on WebClient performance. */
270 // this.ReceiveBufferSize = 8192;
271 // this.SendBufferSize = 8192;
272 } catch (SocketException) {
276 /* Creates a new system socket, returning the handle */
277 [MethodImplAttribute(MethodImplOptions.InternalCall)]
278 extern IntPtr Socket_internal (AddressFamily family, SocketType type, ProtocolType proto, out int error);
284 [ObsoleteAttribute ("Use OSSupportsIPv4 instead")]
285 public static bool SupportsIPv4 {
286 get { return ipv4_supported == 1; }
289 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
290 public static bool SupportsIPv6 {
291 get { return ipv6_supported == 1; }
295 public static bool OSSupportsIPv4 {
296 get { return ipv4_supported == 1; }
299 public static bool OSSupportsIPv4 {
301 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
303 foreach (NetworkInterface adapter in nics) {
304 if (adapter.Supports (NetworkInterfaceComponent.IPv4))
314 public static bool OSSupportsIPv6 {
315 get { return ipv6_supported == 1; }
318 public static bool OSSupportsIPv6 {
320 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
322 foreach (NetworkInterface adapter in nics) {
323 if (adapter.Supports (NetworkInterfaceComponent.IPv6))
332 public int Available {
334 ThrowIfDisposedAndClosed ();
337 ret = Available_internal (safe_handle, out error);
340 throw new SocketException (error);
346 static int Available_internal (SafeSocketHandle safeHandle, out int error)
348 bool release = false;
350 safeHandle.DangerousAddRef (ref release);
351 return Available_internal (safeHandle.DangerousGetHandle (), out error);
354 safeHandle.DangerousRelease ();
358 /* Returns the amount of data waiting to be read on socket */
359 [MethodImplAttribute(MethodImplOptions.InternalCall)]
360 extern static int Available_internal (IntPtr socket, out int error);
362 public bool DontFragment {
364 ThrowIfDisposedAndClosed ();
366 switch (address_family) {
367 case AddressFamily.InterNetwork:
368 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment)) != 0;
369 case AddressFamily.InterNetworkV6:
370 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment)) != 0;
372 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
376 ThrowIfDisposedAndClosed ();
378 switch (address_family) {
379 case AddressFamily.InterNetwork:
380 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
382 case AddressFamily.InterNetworkV6:
383 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment, value ? 1 : 0);
386 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
391 public bool EnableBroadcast {
393 ThrowIfDisposedAndClosed ();
395 if (protocol_type != ProtocolType.Udp)
396 throw new SocketException ((int) SocketError.ProtocolOption);
398 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0;
401 ThrowIfDisposedAndClosed ();
403 if (protocol_type != ProtocolType.Udp)
404 throw new SocketException ((int) SocketError.ProtocolOption);
406 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
410 public bool ExclusiveAddressUse {
412 ThrowIfDisposedAndClosed ();
414 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse)) != 0;
417 ThrowIfDisposedAndClosed ();
420 throw new InvalidOperationException ("Bind has already been called for this socket");
422 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
426 public bool IsBound {
432 public LingerOption LingerState {
434 ThrowIfDisposedAndClosed ();
436 return (LingerOption) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger);
439 ThrowIfDisposedAndClosed ();
440 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger, value);
444 public bool MulticastLoopback {
446 ThrowIfDisposedAndClosed ();
448 /* Even though this option can be set for TCP sockets on Linux, throw
449 * this exception anyway to be compatible (the MSDN docs say
450 * "Setting this property on a Transmission Control Protocol (TCP)
451 * socket will have no effect." but the MS runtime throws the
453 if (protocol_type == ProtocolType.Tcp)
454 throw new SocketException ((int)SocketError.ProtocolOption);
456 switch (address_family) {
457 case AddressFamily.InterNetwork:
458 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
459 case AddressFamily.InterNetworkV6:
460 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
462 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
466 ThrowIfDisposedAndClosed ();
468 /* Even though this option can be set for TCP sockets on Linux, throw
469 * this exception anyway to be compatible (the MSDN docs say
470 * "Setting this property on a Transmission Control Protocol (TCP)
471 * socket will have no effect." but the MS runtime throws the
473 if (protocol_type == ProtocolType.Tcp)
474 throw new SocketException ((int)SocketError.ProtocolOption);
476 switch (address_family) {
477 case AddressFamily.InterNetwork:
478 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
480 case AddressFamily.InterNetworkV6:
481 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
484 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
489 public bool DualMode {
491 if (AddressFamily != AddressFamily.InterNetworkV6)
492 throw new NotSupportedException("This protocol version is not supported");
494 return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only) == 0);
497 if (AddressFamily != AddressFamily.InterNetworkV6)
498 throw new NotSupportedException("This protocol version is not supported");
500 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1);
504 private bool IsDualMode {
506 return AddressFamily == AddressFamily.InterNetworkV6 && DualMode;
510 [MonoTODO ("This doesn't do anything on Mono yet")]
511 public bool UseOnlyOverlappedIO {
512 get { return use_overlapped_io; }
513 set { use_overlapped_io = value; }
516 public IntPtr Handle {
517 get { return safe_handle.DangerousGetHandle (); }
520 // Wish: support non-IP endpoints.
521 public EndPoint LocalEndPoint {
523 ThrowIfDisposedAndClosed ();
525 /* If the seed EndPoint is null, Connect, Bind, etc has not yet
526 * been called. MS returns null in this case. */
527 if (seed_endpoint == null)
531 SocketAddress sa = LocalEndPoint_internal (safe_handle, (int) address_family, out error);
534 throw new SocketException (error);
536 return seed_endpoint.Create (sa);
540 static SocketAddress LocalEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
542 bool release = false;
544 safeHandle.DangerousAddRef (ref release);
545 return LocalEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
548 safeHandle.DangerousRelease ();
552 /* Returns the local endpoint details in addr and port */
553 [MethodImplAttribute(MethodImplOptions.InternalCall)]
554 extern static SocketAddress LocalEndPoint_internal (IntPtr socket, int family, out int error);
556 public SocketType SocketType {
557 get { return socket_type; }
560 public int SendTimeout {
562 ThrowIfDisposedAndClosed ();
564 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
567 ThrowIfDisposedAndClosed ();
570 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
572 /* According to the MSDN docs we should adjust values between 1 and
573 * 499 to 500, but the MS runtime doesn't do this. */
577 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
581 public int ReceiveTimeout {
583 ThrowIfDisposedAndClosed ();
585 return (int) GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
588 ThrowIfDisposedAndClosed ();
591 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
596 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, value);
600 public AddressFamily AddressFamily {
601 get { return address_family; }
604 public bool Blocking {
605 get { return is_blocking; }
607 ThrowIfDisposedAndClosed ();
610 Blocking_internal (safe_handle, value, out error);
613 throw new SocketException (error);
619 static void Blocking_internal (SafeSocketHandle safeHandle, bool block, out int error)
621 bool release = false;
623 safeHandle.DangerousAddRef (ref release);
624 Blocking_internal (safeHandle.DangerousGetHandle (), block, out error);
627 safeHandle.DangerousRelease ();
631 [MethodImplAttribute(MethodImplOptions.InternalCall)]
632 internal extern static void Blocking_internal(IntPtr socket, bool block, out int error);
634 public bool Connected {
635 get { return is_connected; }
636 internal set { is_connected = value; }
639 public ProtocolType ProtocolType {
640 get { return protocol_type; }
643 public bool NoDelay {
645 ThrowIfDisposedAndClosed ();
648 return ((int) GetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay)) != 0;
652 ThrowIfDisposedAndClosed ();
655 SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
659 public int ReceiveBufferSize {
661 ThrowIfDisposedAndClosed ();
663 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer);
666 ThrowIfDisposedAndClosed ();
669 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
671 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
675 public int SendBufferSize {
677 ThrowIfDisposedAndClosed ();
679 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer);
682 ThrowIfDisposedAndClosed ();
685 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
687 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer, value);
693 ThrowIfDisposedAndClosed ();
695 switch (address_family) {
696 case AddressFamily.InterNetwork:
697 return (short) (int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
698 case AddressFamily.InterNetworkV6:
699 return (short) (int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit);
701 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
705 ThrowIfDisposedAndClosed ();
708 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
710 switch (address_family) {
711 case AddressFamily.InterNetwork:
712 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
714 case AddressFamily.InterNetworkV6:
715 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
718 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
723 public EndPoint RemoteEndPoint {
725 ThrowIfDisposedAndClosed ();
727 /* If the seed EndPoint is null, Connect, Bind, etc has
728 * not yet been called. MS returns null in this case. */
729 if (!is_connected || seed_endpoint == null)
733 SocketAddress sa = RemoteEndPoint_internal (safe_handle, (int) address_family, out error);
736 throw new SocketException (error);
738 return seed_endpoint.Create (sa);
742 static SocketAddress RemoteEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
744 bool release = false;
746 safeHandle.DangerousAddRef (ref release);
747 return RemoteEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
750 safeHandle.DangerousRelease ();
754 /* Returns the remote endpoint details in addr and port */
755 [MethodImplAttribute(MethodImplOptions.InternalCall)]
756 extern static SocketAddress RemoteEndPoint_internal (IntPtr socket, int family, out int error);
762 public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
764 var list = new List<Socket> ();
765 AddSockets (list, checkRead, "checkRead");
766 AddSockets (list, checkWrite, "checkWrite");
767 AddSockets (list, checkError, "checkError");
770 throw new ArgumentNullException ("checkRead, checkWrite, checkError", "All the lists are null or empty.");
772 /* The 'sockets' array contains:
773 * - READ socket 0-n, null,
774 * - WRITE socket 0-n, null,
775 * - ERROR socket 0-n, null */
776 Socket [] sockets = list.ToArray ();
779 Select_internal (ref sockets, microSeconds, out error);
782 throw new SocketException (error);
784 if (sockets == null) {
785 if (checkRead != null)
787 if (checkWrite != null)
789 if (checkError != null)
795 int count = sockets.Length;
796 IList currentList = checkRead;
798 for (int i = 0; i < count; i++) {
799 Socket sock = sockets [i];
800 if (sock == null) { // separator
801 if (currentList != null) {
802 // Remove non-signaled sockets after the current one
803 int to_remove = currentList.Count - currentIdx;
804 for (int k = 0; k < to_remove; k++)
805 currentList.RemoveAt (currentIdx);
807 currentList = (mode == 0) ? checkWrite : checkError;
813 if (mode == 1 && currentList == checkWrite && !sock.is_connected) {
814 if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
815 sock.is_connected = true;
818 /* Remove non-signaled sockets before the current one */
819 while (((Socket) currentList [currentIdx]) != sock)
820 currentList.RemoveAt (currentIdx);
826 static void AddSockets (List<Socket> sockets, IList list, string name)
829 foreach (Socket sock in list) {
830 if (sock == null) // MS throws a NullRef
831 throw new ArgumentNullException ("name", "Contains a null element");
839 [MethodImplAttribute(MethodImplOptions.InternalCall)]
840 extern static void Select_internal (ref Socket [] sockets, int microSeconds, out int error);
846 public bool Poll (int time_us, SelectMode mode)
848 ThrowIfDisposedAndClosed ();
850 if (mode != SelectMode.SelectRead && mode != SelectMode.SelectWrite && mode != SelectMode.SelectError)
851 throw new NotSupportedException ("'mode' parameter is not valid.");
854 bool result = Poll_internal (safe_handle, mode, time_us, out error);
857 throw new SocketException (error);
859 if (mode == SelectMode.SelectWrite && result && !is_connected) {
860 /* Update the is_connected state; for non-blocking Connect()
861 * this is when we can find out that the connect succeeded. */
862 if ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
869 static bool Poll_internal (SafeSocketHandle safeHandle, SelectMode mode, int timeout, out int error)
871 bool release = false;
873 safeHandle.DangerousAddRef (ref release);
874 return Poll_internal (safeHandle.DangerousGetHandle (), mode, timeout, out error);
877 safeHandle.DangerousRelease ();
881 [MethodImplAttribute(MethodImplOptions.InternalCall)]
882 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
888 public Socket Accept()
890 ThrowIfDisposedAndClosed ();
893 SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
897 error = SOCKET_CLOSED_CODE;
898 throw new SocketException(error);
901 Socket accepted = new Socket (this.AddressFamily, this.SocketType, this.ProtocolType, safe_handle) {
902 seed_endpoint = this.seed_endpoint,
903 Blocking = this.Blocking,
909 internal void Accept (Socket acceptSocket)
911 ThrowIfDisposedAndClosed ();
914 SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
918 error = SOCKET_CLOSED_CODE;
919 throw new SocketException (error);
922 acceptSocket.address_family = this.AddressFamily;
923 acceptSocket.socket_type = this.SocketType;
924 acceptSocket.protocol_type = this.ProtocolType;
925 acceptSocket.safe_handle = safe_handle;
926 acceptSocket.is_connected = true;
927 acceptSocket.seed_endpoint = this.seed_endpoint;
928 acceptSocket.Blocking = this.Blocking;
930 // FIXME: figure out what if anything else needs to be reset
933 public bool AcceptAsync (SocketAsyncEventArgs e)
935 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
937 ThrowIfDisposedAndClosed ();
940 throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
942 throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
943 if (e.BufferList != null)
944 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
946 throw new ArgumentOutOfRangeException ("e.Count");
948 Socket acceptSocket = e.AcceptSocket;
949 if (acceptSocket != null) {
950 if (acceptSocket.is_bound || acceptSocket.is_connected)
951 throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
954 InitSocketAsyncEventArgs (e, AcceptAsyncCallback, e, SocketOperation.Accept);
956 QueueIOSelectorJob (readQ, e.socket_async_result.handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, e.socket_async_result));
961 static AsyncCallback AcceptAsyncCallback = new AsyncCallback (ares => {
962 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
964 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
965 throw new InvalidOperationException ("No operation in progress");
968 e.AcceptSocket = e.current_socket.EndAccept (ares);
969 } catch (SocketException ex) {
970 e.SocketError = ex.SocketErrorCode;
971 } catch (ObjectDisposedException) {
972 e.SocketError = SocketError.OperationAborted;
974 if (e.AcceptSocket == null)
975 e.AcceptSocket = new Socket (e.current_socket.AddressFamily, e.current_socket.SocketType, e.current_socket.ProtocolType, null);
980 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
982 ThrowIfDisposedAndClosed ();
984 if (!is_bound || !is_listening)
985 throw new InvalidOperationException ();
987 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Accept);
989 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, sockares));
994 static IOAsyncCallback BeginAcceptCallback = new IOAsyncCallback (ares => {
995 SocketAsyncResult sockares = (SocketAsyncResult) ares;
996 Socket socket = null;
999 socket = sockares.socket.Accept ();
1000 } catch (Exception e) {
1001 sockares.Complete (e);
1005 sockares.Complete (socket);
1008 public IAsyncResult BeginAccept (int receiveSize, AsyncCallback callback, object state)
1010 ThrowIfDisposedAndClosed ();
1012 if (receiveSize < 0)
1013 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
1015 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
1016 Buffer = new byte [receiveSize],
1019 SockFlags = SocketFlags.None,
1022 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
1027 public IAsyncResult BeginAccept (Socket acceptSocket, int receiveSize, AsyncCallback callback, object state)
1029 ThrowIfDisposedAndClosed ();
1031 if (receiveSize < 0)
1032 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
1034 if (acceptSocket != null) {
1035 ThrowIfDisposedAndClosed (acceptSocket);
1037 if (acceptSocket.IsBound)
1038 throw new InvalidOperationException ();
1040 /* For some reason the MS runtime
1041 * barfs if the new socket is not TCP,
1042 * even though it's just about to blow
1043 * away all those parameters
1045 if (acceptSocket.ProtocolType != ProtocolType.Tcp)
1046 throw new SocketException ((int)SocketError.InvalidArgument);
1049 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
1050 Buffer = new byte [receiveSize],
1053 SockFlags = SocketFlags.None,
1054 AcceptSocket = acceptSocket,
1057 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
1062 static IOAsyncCallback BeginAcceptReceiveCallback = new IOAsyncCallback (ares => {
1063 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1064 Socket acc_socket = null;
1067 if (sockares.AcceptSocket == null) {
1068 acc_socket = sockares.socket.Accept ();
1070 acc_socket = sockares.AcceptSocket;
1071 sockares.socket.Accept (acc_socket);
1073 } catch (Exception e) {
1074 sockares.Complete (e);
1078 /* It seems the MS runtime special-cases 0-length requested receive data. See bug 464201. */
1080 if (sockares.Size > 0) {
1083 total = acc_socket.Receive_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out error);
1085 sockares.Complete (new SocketException ((int) error));
1088 } catch (Exception e) {
1089 sockares.Complete (e);
1094 sockares.Complete (acc_socket, total);
1097 public Socket EndAccept (IAsyncResult result)
1101 return EndAccept (out buffer, out bytes, result);
1104 public Socket EndAccept (out byte[] buffer, IAsyncResult asyncResult)
1107 return EndAccept (out buffer, out bytes, asyncResult);
1110 public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
1112 ThrowIfDisposedAndClosed ();
1114 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndAccept", "asyncResult");
1116 if (!sockares.IsCompleted)
1117 sockares.AsyncWaitHandle.WaitOne ();
1119 sockares.CheckIfThrowDelayedException ();
1121 buffer = sockares.Buffer;
1122 bytesTransferred = sockares.Total;
1124 return sockares.AcceptedSocket;
1127 static SafeSocketHandle Accept_internal (SafeSocketHandle safeHandle, out int error, bool blocking)
1130 safeHandle.RegisterForBlockingSyscall ();
1131 var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
1132 return new SafeSocketHandle (ret, true);
1134 safeHandle.UnRegisterForBlockingSyscall ();
1138 /* Creates a new system socket, returning the handle */
1139 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1140 extern static IntPtr Accept_internal (IntPtr sock, out int error, bool blocking);
1146 public void Bind (EndPoint local_end)
1148 ThrowIfDisposedAndClosed ();
1150 if (local_end == null)
1151 throw new ArgumentNullException("local_end");
1154 Bind_internal (safe_handle, local_end.Serialize(), out error);
1157 throw new SocketException (error);
1161 seed_endpoint = local_end;
1164 private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1166 bool release = false;
1168 safeHandle.DangerousAddRef (ref release);
1169 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
1172 safeHandle.DangerousRelease ();
1176 // Creates a new system socket, returning the handle
1177 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1178 private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
1184 public void Listen (int backlog)
1186 ThrowIfDisposedAndClosed ();
1189 throw new SocketException ((int) SocketError.InvalidArgument);
1192 Listen_internal(safe_handle, backlog, out error);
1195 throw new SocketException (error);
1197 is_listening = true;
1200 static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
1202 bool release = false;
1204 safeHandle.DangerousAddRef (ref release);
1205 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
1208 safeHandle.DangerousRelease ();
1212 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1213 extern static void Listen_internal (IntPtr sock, int backlog, out int error);
1219 public void Connect (IPAddress address, int port)
1221 Connect (new IPEndPoint (address, port));
1224 public void Connect (string host, int port)
1226 Connect (Dns.GetHostAddresses (host), port);
1229 public void Connect (IPAddress[] addresses, int port)
1231 ThrowIfDisposedAndClosed ();
1233 if (addresses == null)
1234 throw new ArgumentNullException ("addresses");
1235 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1236 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1238 throw new InvalidOperationException ();
1240 // FIXME: do non-blocking sockets Poll here?
1242 foreach (IPAddress address in addresses) {
1243 IPEndPoint iep = new IPEndPoint (address, port);
1245 Connect_internal (safe_handle, iep.Serialize (), out error);
1247 is_connected = true;
1249 seed_endpoint = iep;
1252 if (error != (int)SocketError.InProgress && error != (int)SocketError.WouldBlock)
1256 Poll (-1, SelectMode.SelectWrite);
1257 error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1259 is_connected = true;
1261 seed_endpoint = iep;
1268 throw new SocketException (error);
1272 public void Connect (EndPoint remoteEP)
1274 ThrowIfDisposedAndClosed ();
1276 if (remoteEP == null)
1277 throw new ArgumentNullException ("remoteEP");
1279 IPEndPoint ep = remoteEP as IPEndPoint;
1280 /* Dgram uses Any to 'disconnect' */
1281 if (ep != null && socket_type != SocketType.Dgram) {
1282 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1283 throw new SocketException ((int) SocketError.AddressNotAvailable);
1287 throw new InvalidOperationException ();
1289 SocketAddress serial = remoteEP.Serialize ();
1292 Connect_internal (safe_handle, serial, out error);
1294 if (error == 0 || error == 10035)
1295 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1299 error = SOCKET_CLOSED_CODE;
1300 throw new SocketException (error);
1303 is_connected = !(socket_type == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
1307 public bool ConnectAsync (SocketAsyncEventArgs e)
1309 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1311 ThrowIfDisposedAndClosed ();
1314 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1315 if (e.RemoteEndPoint == null)
1316 throw new ArgumentNullException ("remoteEP");
1318 InitSocketAsyncEventArgs (e, ConnectAsyncCallback, e, SocketOperation.Connect);
1321 IPAddress [] addresses;
1322 SocketAsyncResult ares;
1324 if (!GetCheckedIPs (e, out addresses)) {
1325 e.socket_async_result.EndPoint = e.RemoteEndPoint;
1326 ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
1328 DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1329 e.socket_async_result.Addresses = addresses;
1330 e.socket_async_result.Port = dep.Port;
1331 ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
1334 if (ares.IsCompleted && ares.CompletedSynchronously) {
1335 ares.CheckIfThrowDelayedException ();
1338 } catch (Exception exc) {
1339 e.socket_async_result.Complete (exc, true);
1346 static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
1347 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1349 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1350 throw new InvalidOperationException ("No operation in progress");
1353 e.current_socket.EndConnect (ares);
1354 } catch (SocketException se) {
1355 e.SocketError = se.SocketErrorCode;
1356 } catch (ObjectDisposedException) {
1357 e.SocketError = SocketError.OperationAborted;
1363 public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback callback, object state)
1365 ThrowIfDisposedAndClosed ();
1367 if (address == null)
1368 throw new ArgumentNullException ("address");
1369 if (address.ToString ().Length == 0)
1370 throw new ArgumentException ("The length of the IP address is zero");
1371 if (port <= 0 || port > 65535)
1372 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1374 throw new InvalidOperationException ();
1376 return BeginConnect (new IPEndPoint (address, port), callback, state);
1379 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
1381 ThrowIfDisposedAndClosed ();
1384 throw new ArgumentNullException ("host");
1385 if (address_family != AddressFamily.InterNetwork && address_family != AddressFamily.InterNetworkV6)
1386 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1387 if (port <= 0 || port > 65535)
1388 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1390 throw new InvalidOperationException ();
1392 return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1395 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
1397 ThrowIfDisposedAndClosed ();
1399 if (end_point == null)
1400 throw new ArgumentNullException ("end_point");
1402 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1403 EndPoint = end_point,
1406 // Bug #75154: Connect() should not succeed for .Any addresses.
1407 if (end_point is IPEndPoint) {
1408 IPEndPoint ep = (IPEndPoint) end_point;
1409 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1410 sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1417 if (connect_in_progress) {
1418 // This could happen when multiple IPs are used
1419 // Calling connect() again will reset the connection attempt and cause
1420 // an error. Better to just close the socket and move on.
1421 connect_in_progress = false;
1422 safe_handle.Dispose ();
1423 var handle = Socket_internal (address_family, socket_type, protocol_type, out error);
1424 safe_handle = new SafeSocketHandle (handle, true);
1426 throw new SocketException (error);
1429 bool blk = is_blocking;
1432 Connect_internal (safe_handle, end_point.Serialize (), out error);
1438 is_connected = true;
1440 sockares.Complete (true);
1444 if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1446 is_connected = false;
1448 sockares.Complete (new SocketException (error), true);
1453 is_connected = false;
1455 connect_in_progress = true;
1457 IOSelector.Add (sockares.handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
1462 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1464 ThrowIfDisposedAndClosed ();
1466 if (addresses == null)
1467 throw new ArgumentNullException ("addresses");
1468 if (addresses.Length == 0)
1469 throw new ArgumentException ("Empty addresses list");
1470 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1471 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1472 if (port <= 0 || port > 65535)
1473 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1475 throw new InvalidOperationException ();
1477 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1478 Addresses = addresses,
1482 is_connected = false;
1484 return BeginMConnect (sockares);
1487 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1489 SocketAsyncResult ares = null;
1490 Exception exc = null;
1491 AsyncCallback callback;
1493 for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1495 sockares.CurrentAddress++;
1497 ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1498 if (ares.IsCompleted && ares.CompletedSynchronously) {
1499 ares.CheckIfThrowDelayedException ();
1501 callback = ares.AsyncCallback;
1502 if (callback != null)
1503 ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
1507 } catch (Exception e) {
1519 static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
1520 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1522 if (sockares.EndPoint == null) {
1523 sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
1527 SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
1528 bool is_mconnect = mconnect != null && mconnect.Addresses != null;
1531 EndPoint ep = sockares.EndPoint;
1532 int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1534 if (error_code == 0) {
1536 sockares = mconnect;
1538 sockares.socket.seed_endpoint = ep;
1539 sockares.socket.is_connected = true;
1540 sockares.socket.is_bound = true;
1541 sockares.socket.connect_in_progress = false;
1543 sockares.Complete ();
1548 sockares.socket.connect_in_progress = false;
1549 sockares.Complete (new SocketException (error_code));
1553 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
1554 mconnect.Complete (new SocketException (error_code));
1558 mconnect.socket.BeginMConnect (mconnect);
1559 } catch (Exception e) {
1560 sockares.socket.connect_in_progress = false;
1563 sockares = mconnect;
1565 sockares.Complete (e);
1570 public void EndConnect (IAsyncResult result)
1572 ThrowIfDisposedAndClosed ();
1574 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1576 if (!sockares.IsCompleted)
1577 sockares.AsyncWaitHandle.WaitOne();
1579 sockares.CheckIfThrowDelayedException();
1582 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1585 safeHandle.RegisterForBlockingSyscall ();
1586 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
1588 safeHandle.UnRegisterForBlockingSyscall ();
1592 /* Connects to the remote address */
1593 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1594 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error);
1597 * - false when it is ok to use RemoteEndPoint
1598 * - true when addresses must be used (and addresses could be null/empty) */
1599 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1603 // Connect to the first address that match the host name, like:
1604 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1605 // while skipping entries that do not match the address family
1606 DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1608 addresses = Dns.GetHostAddresses (dep.Host);
1611 e.ConnectByNameError = null;
1620 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1621 * if the platform is newer than w2k. We should be able to cope... */
1622 public void Disconnect (bool reuseSocket)
1624 ThrowIfDisposedAndClosed ();
1627 Disconnect_internal (safe_handle, reuseSocket, out error);
1631 /* ERROR_NOT_SUPPORTED */
1632 throw new PlatformNotSupportedException ();
1634 throw new SocketException (error);
1638 is_connected = false;
1640 /* Do managed housekeeping here... */
1644 public bool DisconnectAsync (SocketAsyncEventArgs e)
1646 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1648 ThrowIfDisposedAndClosed ();
1650 InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
1652 IOSelector.Add (e.socket_async_result.handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
1657 static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
1658 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1660 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1661 throw new InvalidOperationException ("No operation in progress");
1664 e.current_socket.EndDisconnect (ares);
1665 } catch (SocketException ex) {
1666 e.SocketError = ex.SocketErrorCode;
1667 } catch (ObjectDisposedException) {
1668 e.SocketError = SocketError.OperationAborted;
1674 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1676 ThrowIfDisposedAndClosed ();
1678 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1679 ReuseSocket = reuseSocket,
1682 IOSelector.Add (sockares.handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
1687 static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
1688 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1691 sockares.socket.Disconnect (sockares.ReuseSocket);
1692 } catch (Exception e) {
1693 sockares.Complete (e);
1697 sockares.Complete ();
1700 public void EndDisconnect (IAsyncResult asyncResult)
1702 ThrowIfDisposedAndClosed ();
1704 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1706 if (!sockares.IsCompleted)
1707 sockares.AsyncWaitHandle.WaitOne ();
1709 sockares.CheckIfThrowDelayedException ();
1712 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1714 bool release = false;
1716 safeHandle.DangerousAddRef (ref release);
1717 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1720 safeHandle.DangerousRelease ();
1724 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1725 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1731 public int Receive (byte [] buffer)
1733 return Receive (buffer, SocketFlags.None);
1736 public int Receive (byte [] buffer, SocketFlags flags)
1738 ThrowIfDisposedAndClosed ();
1739 ThrowIfBufferNull (buffer);
1740 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
1743 int ret = Receive_nochecks (buffer, 0, buffer.Length, flags, out error);
1745 if (error != SocketError.Success) {
1746 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1747 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1748 throw new SocketException ((int) error);
1754 public int Receive (byte [] buffer, int size, SocketFlags flags)
1756 ThrowIfDisposedAndClosed ();
1757 ThrowIfBufferNull (buffer);
1758 ThrowIfBufferOutOfRange (buffer, 0, size);
1761 int ret = Receive_nochecks (buffer, 0, size, flags, out error);
1763 if (error != SocketError.Success) {
1764 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1765 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1766 throw new SocketException ((int) error);
1772 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags)
1774 ThrowIfDisposedAndClosed ();
1775 ThrowIfBufferNull (buffer);
1776 ThrowIfBufferOutOfRange (buffer, offset, size);
1779 int ret = Receive_nochecks (buffer, offset, size, flags, out error);
1781 if (error != SocketError.Success) {
1782 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1783 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1784 throw new SocketException ((int) error);
1790 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
1792 ThrowIfDisposedAndClosed ();
1793 ThrowIfBufferNull (buffer);
1794 ThrowIfBufferOutOfRange (buffer, offset, size);
1796 return Receive_nochecks (buffer, offset, size, flags, out error);
1799 public int Receive (IList<ArraySegment<byte>> buffers)
1802 int ret = Receive (buffers, SocketFlags.None, out error);
1804 if (error != SocketError.Success)
1805 throw new SocketException ((int) error);
1810 [CLSCompliant (false)]
1811 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1814 int ret = Receive (buffers, socketFlags, out error);
1816 if (error != SocketError.Success)
1817 throw new SocketException ((int) error);
1822 [CLSCompliant (false)]
1823 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1825 ThrowIfDisposedAndClosed ();
1827 if (buffers == null || buffers.Count == 0)
1828 throw new ArgumentNullException ("buffers");
1830 int numsegments = buffers.Count;
1834 /* Only example I can find of sending a byte array reference directly into an internal
1835 * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1836 * so taking a lead from that... */
1837 WSABUF[] bufarray = new WSABUF[numsegments];
1838 GCHandle[] gch = new GCHandle[numsegments];
1840 for (int i = 0; i < numsegments; i++) {
1841 ArraySegment<byte> segment = buffers[i];
1843 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1844 throw new ArgumentOutOfRangeException ("segment");
1846 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1847 bufarray[i].len = segment.Count;
1848 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1852 ret = Receive_internal (safe_handle, bufarray, socketFlags, out nativeError);
1854 for (int i = 0; i < numsegments; i++) {
1855 if (gch[i].IsAllocated)
1860 errorCode = (SocketError) nativeError;
1865 public bool ReceiveAsync (SocketAsyncEventArgs e)
1867 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1869 ThrowIfDisposedAndClosed ();
1871 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1872 // thrown when e.Buffer and e.BufferList are null (works fine when one is
1873 // set to a valid object)
1874 if (e.Buffer == null && e.BufferList == null)
1875 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1877 if (e.Buffer == null) {
1878 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
1880 e.socket_async_result.Buffers = e.BufferList;
1882 QueueIOSelectorJob (readQ, e.socket_async_result.handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
1884 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
1886 e.socket_async_result.Buffer = e.Buffer;
1887 e.socket_async_result.Offset = e.Offset;
1888 e.socket_async_result.Size = e.Count;
1890 QueueIOSelectorJob (readQ, e.socket_async_result.handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
1896 static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
1897 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1899 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1900 throw new InvalidOperationException ("No operation in progress");
1903 e.BytesTransferred = e.current_socket.EndReceive (ares);
1904 } catch (SocketException se){
1905 e.SocketError = se.SocketErrorCode;
1906 } catch (ObjectDisposedException) {
1907 e.SocketError = SocketError.OperationAborted;
1913 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
1915 ThrowIfDisposedAndClosed ();
1916 ThrowIfBufferNull (buffer);
1917 ThrowIfBufferOutOfRange (buffer, offset, size);
1919 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1923 SockFlags = socket_flags,
1926 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
1931 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags flags, out SocketError error, AsyncCallback callback, object state)
1933 /* As far as I can tell from the docs and from experimentation, a pointer to the
1934 * SocketError parameter is not supposed to be saved for the async parts. And as we don't
1935 * set any socket errors in the setup code, we just have to set it to Success. */
1936 error = SocketError.Success;
1937 return BeginReceive (buffer, offset, size, flags, callback, state);
1940 static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
1941 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1945 total = Receive_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
1946 } catch (Exception e) {
1947 sockares.Complete (e);
1951 sockares.Complete (total);
1954 [CLSCompliant (false)]
1955 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
1957 ThrowIfDisposedAndClosed ();
1959 if (buffers == null)
1960 throw new ArgumentNullException ("buffers");
1962 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1964 SockFlags = socketFlags,
1967 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
1972 [CLSCompliant (false)]
1973 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1975 /* I assume the same SocketError semantics as above */
1976 errorCode = SocketError.Success;
1977 return BeginReceive (buffers, socketFlags, callback, state);
1980 static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
1981 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1985 total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
1986 } catch (Exception e) {
1987 sockares.Complete (e);
1991 sockares.Complete (total);
1994 public int EndReceive (IAsyncResult result)
1997 int bytesReceived = EndReceive (result, out error);
1999 if (error != SocketError.Success) {
2000 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2001 is_connected = false;
2002 throw new SocketException ((int)error);
2005 return bytesReceived;
2008 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
2010 ThrowIfDisposedAndClosed ();
2012 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
2014 if (!sockares.IsCompleted)
2015 sockares.AsyncWaitHandle.WaitOne ();
2017 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
2018 // kinds of exceptions that should be thrown.
2019 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2020 sockares.CheckIfThrowDelayedException();
2022 return sockares.Total;
2025 int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2028 int ret = Receive_internal (safe_handle, buf, offset, size, flags, out nativeError);
2030 error = (SocketError) nativeError;
2031 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2032 is_connected = false;
2035 is_connected = true;
2041 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2044 safeHandle.RegisterForBlockingSyscall ();
2045 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2047 safeHandle.UnRegisterForBlockingSyscall ();
2051 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2052 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2054 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
2057 safeHandle.RegisterForBlockingSyscall ();
2058 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
2060 safeHandle.UnRegisterForBlockingSyscall ();
2064 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2065 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error);
2071 public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
2073 ThrowIfDisposedAndClosed ();
2074 ThrowIfBufferNull (buffer);
2076 return ReceiveFrom (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
2079 public int ReceiveFrom (byte [] buffer, SocketFlags flags, ref EndPoint remoteEP)
2081 ThrowIfDisposedAndClosed ();
2082 ThrowIfBufferNull (buffer);
2084 return ReceiveFrom (buffer, 0, buffer.Length, flags, ref remoteEP);
2087 public int ReceiveFrom (byte [] buffer, int size, SocketFlags flags, ref EndPoint remoteEP)
2089 ThrowIfDisposedAndClosed ();
2090 ThrowIfBufferNull (buffer);
2091 ThrowIfBufferOutOfRange (buffer, 0, size);
2093 return ReceiveFrom (buffer, 0, size, flags, ref remoteEP);
2096 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags flags, ref EndPoint remoteEP)
2098 ThrowIfDisposedAndClosed ();
2099 ThrowIfBufferNull (buffer);
2100 ThrowIfBufferOutOfRange (buffer, offset, size);
2102 if (remoteEP == null)
2103 throw new ArgumentNullException ("remoteEP");
2106 return ReceiveFrom_nochecks_exc (buffer, offset, size, flags, ref remoteEP, true, out error);
2109 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
2111 ThrowIfDisposedAndClosed ();
2113 // We do not support recv into multiple buffers yet
2114 if (e.BufferList != null)
2115 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2116 if (e.RemoteEndPoint == null)
2117 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2119 InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
2121 e.socket_async_result.Buffer = e.Buffer;
2122 e.socket_async_result.Offset = e.Offset;
2123 e.socket_async_result.Size = e.Count;
2124 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2125 e.socket_async_result.SockFlags = e.SocketFlags;
2127 QueueIOSelectorJob (readQ, e.socket_async_result.handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
2132 static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
2133 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2135 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2136 throw new InvalidOperationException ("No operation in progress");
2139 e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
2140 } catch (SocketException ex) {
2141 e.SocketError = ex.SocketErrorCode;
2142 } catch (ObjectDisposedException) {
2143 e.SocketError = SocketError.OperationAborted;
2149 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
2151 ThrowIfDisposedAndClosed ();
2152 ThrowIfBufferNull (buffer);
2153 ThrowIfBufferOutOfRange (buffer, offset, size);
2155 if (remote_end == null)
2156 throw new ArgumentNullException ("remote_end");
2158 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
2162 SockFlags = socket_flags,
2163 EndPoint = remote_end,
2166 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
2171 static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
2172 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2177 total = sockares.socket.ReceiveFrom_nochecks_exc (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, true, out error);
2178 } catch (Exception e) {
2179 sockares.Complete (e);
2183 sockares.Complete (total);
2186 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
2188 ThrowIfDisposedAndClosed ();
2190 if (end_point == null)
2191 throw new ArgumentNullException ("remote_end");
2193 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
2195 if (!sockares.IsCompleted)
2196 sockares.AsyncWaitHandle.WaitOne();
2198 sockares.CheckIfThrowDelayedException();
2200 end_point = sockares.EndPoint;
2202 return sockares.Total;
2205 internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end, bool throwOnError, out int error)
2207 SocketAddress sockaddr = remote_end.Serialize();
2209 int cnt = ReceiveFrom_internal (safe_handle, buf, offset, size, flags, ref sockaddr, out error);
2211 SocketError err = (SocketError) error;
2213 if (err != SocketError.WouldBlock && err != SocketError.InProgress) {
2214 is_connected = false;
2215 } else if (err == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
2217 throw new SocketException ((int) SocketError.TimedOut, TIMEOUT_EXCEPTION_MSG);
2218 error = (int) SocketError.TimedOut;
2223 throw new SocketException (error);
2228 is_connected = true;
2231 /* If sockaddr is null then we're a connection oriented protocol and should ignore the
2232 * remote_end parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
2233 if (sockaddr != null) {
2234 /* Stupidly, EndPoint.Create() is an instance method */
2235 remote_end = remote_end.Create (sockaddr);
2238 seed_endpoint = remote_end;
2243 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error)
2246 safeHandle.RegisterForBlockingSyscall ();
2247 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
2249 safeHandle.UnRegisterForBlockingSyscall ();
2253 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2254 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error);
2258 #region ReceiveMessageFrom
2260 [MonoTODO ("Not implemented")]
2261 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
2263 ThrowIfDisposedAndClosed ();
2264 ThrowIfBufferNull (buffer);
2265 ThrowIfBufferOutOfRange (buffer, offset, size);
2267 if (remoteEP == null)
2268 throw new ArgumentNullException ("remoteEP");
2270 // FIXME: figure out how we get hold of the IPPacketInformation
2271 throw new NotImplementedException ();
2274 [MonoTODO ("Not implemented")]
2275 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
2277 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2279 ThrowIfDisposedAndClosed ();
2281 throw new NotImplementedException ();
2285 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
2287 ThrowIfDisposedAndClosed ();
2288 ThrowIfBufferNull (buffer);
2289 ThrowIfBufferOutOfRange (buffer, offset, size);
2291 if (remoteEP == null)
2292 throw new ArgumentNullException ("remoteEP");
2294 throw new NotImplementedException ();
2298 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
2300 ThrowIfDisposedAndClosed ();
2302 if (endPoint == null)
2303 throw new ArgumentNullException ("endPoint");
2305 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
2307 throw new NotImplementedException ();
2314 public int Send (byte [] buffer)
2316 ThrowIfDisposedAndClosed ();
2317 ThrowIfBufferNull (buffer);
2318 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2321 int ret = Send_nochecks (buffer, 0, buffer.Length, SocketFlags.None, out error);
2323 if (error != SocketError.Success)
2324 throw new SocketException ((int) error);
2329 public int Send (byte [] buffer, SocketFlags flags)
2331 ThrowIfDisposedAndClosed ();
2332 ThrowIfBufferNull (buffer);
2333 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2336 int ret = Send_nochecks (buffer, 0, buffer.Length, flags, out error);
2338 if (error != SocketError.Success)
2339 throw new SocketException ((int) error);
2344 public int Send (byte [] buffer, int size, SocketFlags flags)
2346 ThrowIfDisposedAndClosed ();
2347 ThrowIfBufferNull (buffer);
2348 ThrowIfBufferOutOfRange (buffer, 0, size);
2351 int ret = Send_nochecks (buffer, 0, size, flags, out error);
2353 if (error != SocketError.Success)
2354 throw new SocketException ((int) error);
2359 public int Send (byte [] buffer, int offset, int size, SocketFlags flags)
2361 ThrowIfDisposedAndClosed ();
2362 ThrowIfBufferNull (buffer);
2363 ThrowIfBufferOutOfRange (buffer, offset, size);
2366 int ret = Send_nochecks (buffer, offset, size, flags, out error);
2368 if (error != SocketError.Success)
2369 throw new SocketException ((int) error);
2374 public int Send (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
2376 ThrowIfDisposedAndClosed ();
2377 ThrowIfBufferNull (buffer);
2378 ThrowIfBufferOutOfRange (buffer, offset, size);
2380 return Send_nochecks (buffer, offset, size, flags, out error);
2384 int Send (IList<ArraySegment<byte>> buffers)
2387 int ret = Send (buffers, SocketFlags.None, out error);
2389 if (error != SocketError.Success)
2390 throw new SocketException ((int) error);
2396 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
2399 int ret = Send (buffers, socketFlags, out error);
2401 if (error != SocketError.Success)
2402 throw new SocketException ((int) error);
2407 [CLSCompliant (false)]
2408 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
2410 ThrowIfDisposedAndClosed ();
2412 if (buffers == null)
2413 throw new ArgumentNullException ("buffers");
2414 if (buffers.Count == 0)
2415 throw new ArgumentException ("Buffer is empty", "buffers");
2417 int numsegments = buffers.Count;
2421 WSABUF[] bufarray = new WSABUF[numsegments];
2422 GCHandle[] gch = new GCHandle[numsegments];
2424 for(int i = 0; i < numsegments; i++) {
2425 ArraySegment<byte> segment = buffers[i];
2427 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
2428 throw new ArgumentOutOfRangeException ("segment");
2430 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
2431 bufarray[i].len = segment.Count;
2432 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
2436 ret = Send_internal (safe_handle, bufarray, socketFlags, out nativeError);
2438 for(int i = 0; i < numsegments; i++) {
2439 if (gch[i].IsAllocated) {
2445 errorCode = (SocketError)nativeError;
2450 int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2453 error = SocketError.Success;
2458 int ret = Send_internal (safe_handle, buf, offset, size, flags, out nativeError);
2460 error = (SocketError)nativeError;
2462 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2463 is_connected = false;
2466 is_connected = true;
2472 public bool SendAsync (SocketAsyncEventArgs e)
2474 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2476 ThrowIfDisposedAndClosed ();
2478 if (e.Buffer == null && e.BufferList == null)
2479 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
2481 if (e.Buffer == null) {
2482 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
2484 e.socket_async_result.Buffers = e.BufferList;
2486 QueueIOSelectorJob (writeQ, e.socket_async_result.handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
2488 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
2490 e.socket_async_result.Buffer = e.Buffer;
2491 e.socket_async_result.Offset = e.Offset;
2492 e.socket_async_result.Size = e.Count;
2494 QueueIOSelectorJob (writeQ, e.socket_async_result.handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2500 static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
2501 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2503 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2504 throw new InvalidOperationException ("No operation in progress");
2507 e.BytesTransferred = e.current_socket.EndSend (ares);
2508 } catch (SocketException se){
2509 e.SocketError = se.SocketErrorCode;
2510 } catch (ObjectDisposedException) {
2511 e.SocketError = SocketError.OperationAborted;
2517 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2519 if (!is_connected) {
2520 errorCode = SocketError.NotConnected;
2521 throw new SocketException ((int) errorCode);
2524 errorCode = SocketError.Success;
2525 return BeginSend (buffer, offset, size, socketFlags, callback, state);
2528 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
2530 ThrowIfDisposedAndClosed ();
2531 ThrowIfBufferNull (buffer);
2532 ThrowIfBufferOutOfRange (buffer, offset, size);
2535 throw new SocketException ((int)SocketError.NotConnected);
2537 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
2541 SockFlags = socket_flags,
2544 QueueIOSelectorJob (writeQ, sockares.handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
2549 static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
2554 total = Socket.Send_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
2555 } catch (Exception e) {
2556 sockares.Complete (e);
2560 if (sockares.error == 0) {
2561 sent_so_far += total;
2562 sockares.Offset += total;
2563 sockares.Size -= total;
2565 if (sockares.socket.is_disposed) {
2566 sockares.Complete (total);
2570 if (sockares.Size > 0) {
2571 IOSelector.Add (sockares.handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2572 return; // Have to finish writing everything. See bug #74475.
2575 sockares.Total = sent_so_far;
2578 sockares.Complete (total);
2581 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
2583 ThrowIfDisposedAndClosed ();
2585 if (buffers == null)
2586 throw new ArgumentNullException ("buffers");
2588 throw new SocketException ((int)SocketError.NotConnected);
2590 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
2592 SockFlags = socketFlags,
2595 QueueIOSelectorJob (writeQ, sockares.handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
2600 [CLSCompliant (false)]
2601 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2603 if (!is_connected) {
2604 errorCode = SocketError.NotConnected;
2605 throw new SocketException ((int)errorCode);
2608 errorCode = SocketError.Success;
2609 return BeginSend (buffers, socketFlags, callback, state);
2612 static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
2613 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2617 total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
2618 } catch (Exception e) {
2619 sockares.Complete (e);
2623 sockares.Complete (total);
2626 public int EndSend (IAsyncResult result)
2629 int bytesSent = EndSend (result, out error);
2631 if (error != SocketError.Success) {
2632 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2633 is_connected = false;
2634 throw new SocketException ((int)error);
2640 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
2642 ThrowIfDisposedAndClosed ();
2644 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
2646 if (!sockares.IsCompleted)
2647 sockares.AsyncWaitHandle.WaitOne ();
2649 /* If no socket error occurred, call CheckIfThrowDelayedException in
2650 * case there are other kinds of exceptions that should be thrown.*/
2651 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2652 sockares.CheckIfThrowDelayedException ();
2654 return sockares.Total;
2657 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2659 bool release = false;
2661 safeHandle.DangerousAddRef (ref release);
2662 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2665 safeHandle.DangerousRelease ();
2669 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2670 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2672 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
2675 safeHandle.RegisterForBlockingSyscall ();
2676 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
2678 safeHandle.UnRegisterForBlockingSyscall ();
2682 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2683 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
2689 public int SendTo (byte [] buffer, EndPoint remote_end)
2691 ThrowIfDisposedAndClosed ();
2692 ThrowIfBufferNull (buffer);
2694 return SendTo (buffer, 0, buffer.Length, SocketFlags.None, remote_end);
2697 public int SendTo (byte [] buffer, SocketFlags flags, EndPoint remote_end)
2699 ThrowIfDisposedAndClosed ();
2700 ThrowIfBufferNull (buffer);
2702 return SendTo (buffer, 0, buffer.Length, flags, remote_end);
2705 public int SendTo (byte [] buffer, int size, SocketFlags flags, EndPoint remote_end)
2707 return SendTo (buffer, 0, size, flags, remote_end);
2710 public int SendTo (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2712 ThrowIfDisposedAndClosed ();
2713 ThrowIfBufferNull (buffer);
2714 ThrowIfBufferOutOfRange (buffer, offset, size);
2716 if (remote_end == null)
2717 throw new ArgumentNullException("remote_end");
2719 return SendTo_nochecks (buffer, offset, size, flags, remote_end);
2722 public bool SendToAsync (SocketAsyncEventArgs e)
2724 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2726 ThrowIfDisposedAndClosed ();
2728 if (e.BufferList != null)
2729 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2730 if (e.RemoteEndPoint == null)
2731 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2733 InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2735 e.socket_async_result.Buffer = e.Buffer;
2736 e.socket_async_result.Offset = e.Offset;
2737 e.socket_async_result.Size = e.Count;
2738 e.socket_async_result.SockFlags = e.SocketFlags;
2739 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2741 QueueIOSelectorJob (writeQ, e.socket_async_result.handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2746 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2747 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2749 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2750 throw new InvalidOperationException ("No operation in progress");
2753 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2754 } catch (SocketException ex) {
2755 e.SocketError = ex.SocketErrorCode;
2756 } catch (ObjectDisposedException) {
2757 e.SocketError = SocketError.OperationAborted;
2763 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2765 ThrowIfDisposedAndClosed ();
2766 ThrowIfBufferNull (buffer);
2767 ThrowIfBufferOutOfRange (buffer, offset, size);
2769 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2773 SockFlags = socket_flags,
2774 EndPoint = remote_end,
2777 QueueIOSelectorJob (writeQ, sockares.handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2782 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2786 total = sockares.socket.SendTo_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2788 if (sockares.error == 0) {
2789 sent_so_far += total;
2790 sockares.Offset += total;
2791 sockares.Size -= total;
2794 if (sockares.Size > 0) {
2795 IOSelector.Add (sockares.handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2796 return; // Have to finish writing everything. See bug #74475.
2799 sockares.Total = sent_so_far;
2800 } catch (Exception e) {
2801 sockares.Complete (e);
2805 sockares.Complete ();
2808 public int EndSendTo (IAsyncResult result)
2810 ThrowIfDisposedAndClosed ();
2812 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2814 if (!sockares.IsCompleted)
2815 sockares.AsyncWaitHandle.WaitOne();
2817 sockares.CheckIfThrowDelayedException();
2819 return sockares.Total;
2822 int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2825 int ret = SendTo_internal (safe_handle, buffer, offset, size, flags, remote_end.Serialize (), out error);
2827 SocketError err = (SocketError) error;
2829 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2830 is_connected = false;
2831 throw new SocketException (error);
2834 is_connected = true;
2836 seed_endpoint = remote_end;
2841 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
2844 safeHandle.RegisterForBlockingSyscall ();
2845 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
2847 safeHandle.UnRegisterForBlockingSyscall ();
2851 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2852 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
2858 public void SendFile (string fileName)
2860 ThrowIfDisposedAndClosed ();
2863 throw new NotSupportedException ();
2865 throw new InvalidOperationException ();
2867 SendFile (fileName, null, null, 0);
2870 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2872 ThrowIfDisposedAndClosed ();
2875 throw new NotSupportedException ();
2877 throw new InvalidOperationException ();
2879 if (!SendFile_internal (safe_handle, fileName, preBuffer, postBuffer, flags)) {
2880 SocketException exc = new SocketException ();
2881 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2882 throw new FileNotFoundException ();
2887 public IAsyncResult BeginSendFile (string fileName, AsyncCallback callback, object state)
2889 ThrowIfDisposedAndClosed ();
2892 throw new NotSupportedException ();
2893 if (!File.Exists (fileName))
2894 throw new FileNotFoundException ();
2896 return BeginSendFile (fileName, null, null, 0, callback, state);
2899 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2901 ThrowIfDisposedAndClosed ();
2904 throw new NotSupportedException ();
2905 if (!File.Exists (fileName))
2906 throw new FileNotFoundException ();
2908 SendFileHandler handler = new SendFileHandler (SendFile);
2910 return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2913 public void EndSendFile (IAsyncResult asyncResult)
2915 ThrowIfDisposedAndClosed ();
2917 if (asyncResult == null)
2918 throw new ArgumentNullException ("asyncResult");
2920 SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2922 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2924 ares.Delegate.EndInvoke (ares.Original);
2927 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
2930 safeHandle.RegisterForBlockingSyscall ();
2931 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
2933 safeHandle.UnRegisterForBlockingSyscall ();
2937 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2938 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
2940 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2942 sealed class SendFileAsyncResult : IAsyncResult {
2946 public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2952 public object AsyncState {
2953 get { return ares.AsyncState; }
2956 public WaitHandle AsyncWaitHandle {
2957 get { return ares.AsyncWaitHandle; }
2960 public bool CompletedSynchronously {
2961 get { return ares.CompletedSynchronously; }
2964 public bool IsCompleted {
2965 get { return ares.IsCompleted; }
2968 public SendFileHandler Delegate {
2972 public IAsyncResult Original {
2973 get { return ares; }
2981 [MonoTODO ("Not implemented")]
2982 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2984 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2986 ThrowIfDisposedAndClosed ();
2988 throw new NotImplementedException ();
2993 #region DuplicateAndClose
2996 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2997 public SocketInformation DuplicateAndClose (int targetProcessId)
2999 var si = new SocketInformation ();
3001 (is_listening ? SocketInformationOptions.Listening : 0) |
3002 (is_connected ? SocketInformationOptions.Connected : 0) |
3003 (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
3004 (use_overlapped_io ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
3006 si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, is_bound ? 1 : 0, (long)Handle);
3015 #region GetSocketOption
3017 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3019 ThrowIfDisposedAndClosed ();
3021 if (optionValue == null)
3022 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3025 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref optionValue, out error);
3028 throw new SocketException (error);
3031 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int length)
3033 ThrowIfDisposedAndClosed ();
3036 byte[] byte_val = new byte [length];
3037 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref byte_val, out error);
3040 throw new SocketException (error);
3045 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
3047 ThrowIfDisposedAndClosed ();
3051 GetSocketOption_obj_internal (safe_handle, optionLevel, optionName, out obj_val, out error);
3054 throw new SocketException (error);
3056 if (optionName == SocketOptionName.Linger)
3057 return (LingerOption) obj_val;
3058 else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
3059 return (MulticastOption) obj_val;
3060 else if (obj_val is int)
3061 return (int) obj_val;
3066 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
3068 bool release = false;
3070 safeHandle.DangerousAddRef (ref release);
3071 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
3074 safeHandle.DangerousRelease ();
3078 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3079 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
3081 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
3083 bool release = false;
3085 safeHandle.DangerousAddRef (ref release);
3086 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
3089 safeHandle.DangerousRelease ();
3093 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3094 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
3098 #region SetSocketOption
3100 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3102 ThrowIfDisposedAndClosed ();
3104 // I'd throw an ArgumentNullException, but this is what MS does.
3105 if (optionValue == null)
3106 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3109 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, optionValue, 0, out error);
3112 if (error == (int) SocketError.InvalidArgument)
3113 throw new ArgumentException ();
3114 throw new SocketException (error);
3118 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
3120 ThrowIfDisposedAndClosed ();
3122 // NOTE: if a null is passed, the byte[] overload is used instead...
3123 if (optionValue == null)
3124 throw new ArgumentNullException("optionValue");
3128 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
3129 LingerOption linger = optionValue as LingerOption;
3131 throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
3132 SetSocketOption_internal (safe_handle, optionLevel, optionName, linger, null, 0, out error);
3133 } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3134 MulticastOption multicast = optionValue as MulticastOption;
3135 if (multicast == null)
3136 throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
3137 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3138 } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3139 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
3140 if (multicast == null)
3141 throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
3142 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3144 throw new ArgumentException ("Invalid value specified.", "optionValue");
3148 if (error == (int) SocketError.InvalidArgument)
3149 throw new ArgumentException ();
3150 throw new SocketException (error);
3154 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
3156 ThrowIfDisposedAndClosed ();
3159 int int_val = optionValue ? 1 : 0;
3160 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, int_val, out error);
3163 if (error == (int) SocketError.InvalidArgument)
3164 throw new ArgumentException ();
3165 throw new SocketException (error);
3169 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
3171 ThrowIfDisposedAndClosed ();
3174 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, optionValue, out error);
3177 throw new SocketException (error);
3181 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
3183 bool release = false;
3185 safeHandle.DangerousAddRef (ref release);
3186 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
3189 safeHandle.DangerousRelease ();
3193 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3194 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
3200 public int IOControl (int ioctl_code, byte [] in_value, byte [] out_value)
3203 throw new ObjectDisposedException (GetType ().ToString ());
3206 int result = IOControl_internal (safe_handle, ioctl_code, in_value, out_value, out error);
3209 throw new SocketException (error);
3211 throw new InvalidOperationException ("Must use Blocking property instead.");
3216 public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
3218 return IOControl ((int) ioControlCode, optionInValue, optionOutValue);
3221 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
3223 bool release = false;
3225 safeHandle.DangerousAddRef (ref release);
3226 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
3229 safeHandle.DangerousRelease ();
3233 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
3234 * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
3235 * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
3236 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3237 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
3243 public void Close ()
3249 public void Close (int timeout)
3251 linger_timeout = timeout;
3255 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3256 internal extern static void Close_internal (IntPtr socket, out int error);
3262 public void Shutdown (SocketShutdown how)
3264 ThrowIfDisposedAndClosed ();
3267 throw new SocketException (10057); // Not connected
3270 Shutdown_internal (safe_handle, how, out error);
3273 throw new SocketException (error);
3276 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
3278 bool release = false;
3280 safeHandle.DangerousAddRef (ref release);
3281 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
3284 safeHandle.DangerousRelease ();
3288 [MethodImplAttribute (MethodImplOptions.InternalCall)]
3289 extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
3295 protected virtual void Dispose (bool disposing)
3301 bool was_connected = is_connected;
3302 is_connected = false;
3304 if (safe_handle != null) {
3311 safe_handle.Dispose ();
3315 public void Dispose ()
3318 GC.SuppressFinalize (this);
3321 void Linger (IntPtr handle)
3323 if (!is_connected || linger_timeout <= 0)
3326 /* We don't want to receive any more data */
3328 Shutdown_internal (handle, SocketShutdown.Receive, out error);
3333 int seconds = linger_timeout / 1000;
3334 int ms = linger_timeout % 1000;
3336 /* If the other end closes, this will return 'true' with 'Available' == 0 */
3337 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
3343 LingerOption linger = new LingerOption (true, seconds);
3344 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
3345 /* Not needed, we're closing upon return */
3353 void ThrowIfDisposedAndClosed (Socket socket)
3355 if (socket.is_disposed && socket.is_closed)
3356 throw new ObjectDisposedException (socket.GetType ().ToString ());
3359 void ThrowIfDisposedAndClosed ()
3361 if (is_disposed && is_closed)
3362 throw new ObjectDisposedException (GetType ().ToString ());
3365 void ThrowIfBufferNull (byte[] buffer)
3368 throw new ArgumentNullException ("buffer");
3371 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
3374 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
3375 if (offset > buffer.Length)
3376 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
3378 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
3379 if (size > buffer.Length - offset)
3380 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
3385 #if !NET_2_1 || MOBILE
3386 if (protocol_type == ProtocolType.Udp)
3387 throw new SocketException ((int)SocketError.ProtocolOption);
3391 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
3394 throw new ArgumentNullException (argName);
3396 SocketAsyncResult sockares = ares as SocketAsyncResult;
3397 if (sockares == null)
3398 throw new ArgumentException ("Invalid IAsyncResult", argName);
3399 if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
3400 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
3405 void QueueIOSelectorJob (Queue<KeyValuePair<IntPtr, IOSelectorJob>> queue, IntPtr handle, IOSelectorJob job)
3409 queue.Enqueue (new KeyValuePair<IntPtr, IOSelectorJob> (handle, job));
3410 count = queue.Count;
3414 IOSelector.Add (handle, job);
3417 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
3419 e.socket_async_result.Init (this, callback, state, operation);
3421 e.current_socket = this;
3422 e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
3423 e.SocketError = SocketError.Success;
3424 e.BytesTransferred = 0;
3427 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
3430 case SocketOperation.Connect:
3431 return SocketAsyncOperation.Connect;
3432 case SocketOperation.Accept:
3433 return SocketAsyncOperation.Accept;
3434 case SocketOperation.Disconnect:
3435 return SocketAsyncOperation.Disconnect;
3436 case SocketOperation.Receive:
3437 case SocketOperation.ReceiveGeneric:
3438 return SocketAsyncOperation.Receive;
3439 case SocketOperation.ReceiveFrom:
3440 return SocketAsyncOperation.ReceiveFrom;
3441 case SocketOperation.Send:
3442 case SocketOperation.SendGeneric:
3443 return SocketAsyncOperation.Send;
3444 case SocketOperation.SendTo:
3445 return SocketAsyncOperation.SendTo;
3447 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
3451 [StructLayout (LayoutKind.Sequential)]
3457 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3458 internal static extern void cancel_blocking_socket_operation (Thread thread);
3460 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3461 internal static extern bool SupportsPortReuse ();