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.");
955 e.Worker.Init (this, e, SocketOperation.Accept);
957 SocketAsyncResult sockares = e.Worker.result;
959 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, s => ((SocketAsyncResult) s).Worker.Accept (), sockares));
964 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
966 ThrowIfDisposedAndClosed ();
968 if (!is_bound || !is_listening)
969 throw new InvalidOperationException ();
971 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Accept);
973 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, s => ((SocketAsyncResult) s).Worker.Accept (), sockares));
978 public IAsyncResult BeginAccept (int receiveSize, AsyncCallback callback, object state)
980 ThrowIfDisposedAndClosed ();
983 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
985 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
986 Buffer = new byte [receiveSize],
989 SockFlags = SocketFlags.None,
992 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, s => ((SocketAsyncResult) s).Worker.AcceptReceive (), sockares));
997 public IAsyncResult BeginAccept (Socket acceptSocket, int receiveSize, AsyncCallback callback, object state)
999 ThrowIfDisposedAndClosed ();
1001 if (receiveSize < 0)
1002 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
1004 if (acceptSocket != null) {
1005 ThrowIfDisposedAndClosed (acceptSocket);
1007 if (acceptSocket.IsBound)
1008 throw new InvalidOperationException ();
1010 /* For some reason the MS runtime
1011 * barfs if the new socket is not TCP,
1012 * even though it's just about to blow
1013 * away all those parameters
1015 if (acceptSocket.ProtocolType != ProtocolType.Tcp)
1016 throw new SocketException ((int)SocketError.InvalidArgument);
1019 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
1020 Buffer = new byte [receiveSize],
1023 SockFlags = SocketFlags.None,
1024 AcceptSocket = acceptSocket,
1027 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, s => ((SocketAsyncResult) s).Worker.AcceptReceive (), sockares));
1032 public Socket EndAccept (IAsyncResult result)
1036 return EndAccept (out buffer, out bytes, result);
1039 public Socket EndAccept (out byte[] buffer, IAsyncResult asyncResult)
1042 return EndAccept (out buffer, out bytes, asyncResult);
1045 public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
1047 ThrowIfDisposedAndClosed ();
1049 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndAccept", "asyncResult");
1051 if (!sockares.IsCompleted)
1052 sockares.AsyncWaitHandle.WaitOne ();
1054 sockares.CheckIfThrowDelayedException ();
1056 buffer = sockares.Buffer;
1057 bytesTransferred = sockares.Total;
1059 return sockares.Socket;
1062 static SafeSocketHandle Accept_internal (SafeSocketHandle safeHandle, out int error, bool blocking)
1065 safeHandle.RegisterForBlockingSyscall ();
1066 var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
1067 return new SafeSocketHandle (ret, true);
1069 safeHandle.UnRegisterForBlockingSyscall ();
1073 /* Creates a new system socket, returning the handle */
1074 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1075 extern static IntPtr Accept_internal (IntPtr sock, out int error, bool blocking);
1081 public void Bind (EndPoint local_end)
1083 ThrowIfDisposedAndClosed ();
1085 if (local_end == null)
1086 throw new ArgumentNullException("local_end");
1089 Bind_internal (safe_handle, local_end.Serialize(), out error);
1092 throw new SocketException (error);
1096 seed_endpoint = local_end;
1099 private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1101 bool release = false;
1103 safeHandle.DangerousAddRef (ref release);
1104 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
1107 safeHandle.DangerousRelease ();
1111 // Creates a new system socket, returning the handle
1112 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1113 private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
1119 public void Listen (int backlog)
1121 ThrowIfDisposedAndClosed ();
1124 throw new SocketException ((int) SocketError.InvalidArgument);
1127 Listen_internal(safe_handle, backlog, out error);
1130 throw new SocketException (error);
1132 is_listening = true;
1135 static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
1137 bool release = false;
1139 safeHandle.DangerousAddRef (ref release);
1140 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
1143 safeHandle.DangerousRelease ();
1147 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1148 extern static void Listen_internal (IntPtr sock, int backlog, out int error);
1154 public void Connect (IPAddress address, int port)
1156 Connect (new IPEndPoint (address, port));
1159 public void Connect (string host, int port)
1161 Connect (Dns.GetHostAddresses (host), port);
1164 public void Connect (IPAddress[] addresses, int port)
1166 ThrowIfDisposedAndClosed ();
1168 if (addresses == null)
1169 throw new ArgumentNullException ("addresses");
1170 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1171 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1173 throw new InvalidOperationException ();
1175 // FIXME: do non-blocking sockets Poll here?
1177 foreach (IPAddress address in addresses) {
1178 IPEndPoint iep = new IPEndPoint (address, port);
1180 Connect_internal (safe_handle, iep.Serialize (), out error);
1182 is_connected = true;
1184 seed_endpoint = iep;
1187 if (error != (int)SocketError.InProgress && error != (int)SocketError.WouldBlock)
1191 Poll (-1, SelectMode.SelectWrite);
1192 error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1194 is_connected = true;
1196 seed_endpoint = iep;
1203 throw new SocketException (error);
1207 public void Connect (EndPoint remoteEP)
1209 ThrowIfDisposedAndClosed ();
1211 if (remoteEP == null)
1212 throw new ArgumentNullException ("remoteEP");
1214 IPEndPoint ep = remoteEP as IPEndPoint;
1215 /* Dgram uses Any to 'disconnect' */
1216 if (ep != null && socket_type != SocketType.Dgram) {
1217 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1218 throw new SocketException ((int) SocketError.AddressNotAvailable);
1222 throw new InvalidOperationException ();
1224 SocketAddress serial = remoteEP.Serialize ();
1227 Connect_internal (safe_handle, serial, out error);
1229 if (error == 0 || error == 10035)
1230 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1234 error = SOCKET_CLOSED_CODE;
1235 throw new SocketException (error);
1238 is_connected = !(socket_type == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
1242 public bool ConnectAsync (SocketAsyncEventArgs e)
1244 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1246 ThrowIfDisposedAndClosed ();
1249 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1250 if (e.RemoteEndPoint == null)
1251 throw new ArgumentNullException ("remoteEP");
1254 e.Worker.Init (this, e, SocketOperation.Connect);
1256 SocketAsyncResult result = e.Worker.result;
1259 IPAddress [] addresses;
1262 if (!GetCheckedIPs (e, out addresses)) {
1263 result.EndPoint = e.RemoteEndPoint;
1264 ares = BeginConnect (e.RemoteEndPoint, SocketAsyncEventArgs.Dispatcher, e);
1266 DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1267 result.Addresses = addresses;
1268 result.Port = dep.Port;
1269 ares = BeginConnect (addresses, dep.Port, SocketAsyncEventArgs.Dispatcher, e);
1272 if (ares.IsCompleted && ares.CompletedSynchronously) {
1273 ((SocketAsyncResult) ares).CheckIfThrowDelayedException ();
1276 } catch (Exception exc) {
1277 result.Complete (exc, true);
1284 public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback callback, object state)
1286 ThrowIfDisposedAndClosed ();
1288 if (address == null)
1289 throw new ArgumentNullException ("address");
1290 if (address.ToString ().Length == 0)
1291 throw new ArgumentException ("The length of the IP address is zero");
1292 if (port <= 0 || port > 65535)
1293 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1295 throw new InvalidOperationException ();
1297 return BeginConnect (new IPEndPoint (address, port), callback, state);
1300 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
1302 ThrowIfDisposedAndClosed ();
1305 throw new ArgumentNullException ("host");
1306 if (address_family != AddressFamily.InterNetwork && address_family != AddressFamily.InterNetworkV6)
1307 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1308 if (port <= 0 || port > 65535)
1309 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1311 throw new InvalidOperationException ();
1313 return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1316 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
1318 ThrowIfDisposedAndClosed ();
1320 if (end_point == null)
1321 throw new ArgumentNullException ("end_point");
1323 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1324 EndPoint = end_point,
1327 // Bug #75154: Connect() should not succeed for .Any addresses.
1328 if (end_point is IPEndPoint) {
1329 IPEndPoint ep = (IPEndPoint) end_point;
1330 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1331 sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1338 if (connect_in_progress) {
1339 // This could happen when multiple IPs are used
1340 // Calling connect() again will reset the connection attempt and cause
1341 // an error. Better to just close the socket and move on.
1342 connect_in_progress = false;
1343 safe_handle.Dispose ();
1344 var handle = Socket_internal (address_family, socket_type, protocol_type, out error);
1345 safe_handle = new SafeSocketHandle (handle, true);
1347 throw new SocketException (error);
1350 bool blk = is_blocking;
1353 Connect_internal (safe_handle, end_point.Serialize (), out error);
1359 is_connected = true;
1361 sockares.Complete (true);
1365 if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1367 is_connected = false;
1369 sockares.Complete (new SocketException (error), true);
1374 is_connected = false;
1376 connect_in_progress = true;
1378 IOSelector.Add (sockares.handle, new IOSelectorJob (IOOperation.Write, s => ((SocketAsyncResult) s).Worker.Connect (), sockares));
1383 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1385 ThrowIfDisposedAndClosed ();
1387 if (addresses == null)
1388 throw new ArgumentNullException ("addresses");
1389 if (addresses.Length == 0)
1390 throw new ArgumentException ("Empty addresses list");
1391 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1392 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1393 if (port <= 0 || port > 65535)
1394 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1396 throw new InvalidOperationException ();
1398 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1399 Addresses = addresses,
1403 is_connected = false;
1405 return BeginMConnect (sockares);
1408 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1410 SocketAsyncResult ares = null;
1411 Exception exc = null;
1412 AsyncCallback callback;
1414 for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1416 sockares.CurrentAddress++;
1418 ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1419 if (ares.IsCompleted && ares.CompletedSynchronously) {
1420 ares.CheckIfThrowDelayedException ();
1422 callback = ares.AsyncCallback;
1423 if (callback != null)
1424 ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
1428 } catch (Exception e) {
1440 public void EndConnect (IAsyncResult result)
1442 ThrowIfDisposedAndClosed ();
1444 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1446 if (!sockares.IsCompleted)
1447 sockares.AsyncWaitHandle.WaitOne();
1449 sockares.CheckIfThrowDelayedException();
1452 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1455 safeHandle.RegisterForBlockingSyscall ();
1456 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
1458 safeHandle.UnRegisterForBlockingSyscall ();
1462 /* Connects to the remote address */
1463 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1464 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error);
1467 * - false when it is ok to use RemoteEndPoint
1468 * - true when addresses must be used (and addresses could be null/empty) */
1469 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1473 // Connect to the first address that match the host name, like:
1474 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1475 // while skipping entries that do not match the address family
1476 DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1478 addresses = Dns.GetHostAddresses (dep.Host);
1481 e.ConnectByNameError = null;
1490 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1491 * if the platform is newer than w2k. We should be able to cope... */
1492 public void Disconnect (bool reuseSocket)
1494 ThrowIfDisposedAndClosed ();
1497 Disconnect_internal (safe_handle, reuseSocket, out error);
1501 /* ERROR_NOT_SUPPORTED */
1502 throw new PlatformNotSupportedException ();
1504 throw new SocketException (error);
1508 is_connected = false;
1510 /* Do managed housekeeping here... */
1514 public bool DisconnectAsync (SocketAsyncEventArgs e)
1516 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1518 ThrowIfDisposedAndClosed ();
1521 e.Worker.Init (this, e, SocketOperation.Disconnect);
1523 SocketAsyncResult sockares = e.Worker.result;
1525 IOSelector.Add (sockares.handle, new IOSelectorJob (IOOperation.Write, s => ((SocketAsyncResult) s).Worker.Disconnect (), sockares));
1531 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1533 ThrowIfDisposedAndClosed ();
1535 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1536 ReuseSocket = reuseSocket,
1539 IOSelector.Add (sockares.handle, new IOSelectorJob (IOOperation.Write, s => ((SocketAsyncResult) s).Worker.Disconnect (), sockares));
1544 public void EndDisconnect (IAsyncResult asyncResult)
1546 ThrowIfDisposedAndClosed ();
1548 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1550 if (!sockares.IsCompleted)
1551 sockares.AsyncWaitHandle.WaitOne ();
1553 sockares.CheckIfThrowDelayedException ();
1556 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1558 bool release = false;
1560 safeHandle.DangerousAddRef (ref release);
1561 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1564 safeHandle.DangerousRelease ();
1568 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1569 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1575 public int Receive (byte [] buffer)
1577 return Receive (buffer, SocketFlags.None);
1580 public int Receive (byte [] buffer, SocketFlags flags)
1582 ThrowIfDisposedAndClosed ();
1583 ThrowIfBufferNull (buffer);
1584 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
1587 int ret = Receive_nochecks (buffer, 0, buffer.Length, flags, out error);
1589 if (error != SocketError.Success) {
1590 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1591 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1592 throw new SocketException ((int) error);
1598 public int Receive (byte [] buffer, int size, SocketFlags flags)
1600 ThrowIfDisposedAndClosed ();
1601 ThrowIfBufferNull (buffer);
1602 ThrowIfBufferOutOfRange (buffer, 0, size);
1605 int ret = Receive_nochecks (buffer, 0, size, flags, out error);
1607 if (error != SocketError.Success) {
1608 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1609 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1610 throw new SocketException ((int) error);
1616 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags)
1618 ThrowIfDisposedAndClosed ();
1619 ThrowIfBufferNull (buffer);
1620 ThrowIfBufferOutOfRange (buffer, offset, size);
1623 int ret = Receive_nochecks (buffer, offset, size, flags, out error);
1625 if (error != SocketError.Success) {
1626 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1627 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1628 throw new SocketException ((int) error);
1634 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
1636 ThrowIfDisposedAndClosed ();
1637 ThrowIfBufferNull (buffer);
1638 ThrowIfBufferOutOfRange (buffer, offset, size);
1640 return Receive_nochecks (buffer, offset, size, flags, out error);
1643 public int Receive (IList<ArraySegment<byte>> buffers)
1646 int ret = Receive (buffers, SocketFlags.None, out error);
1648 if (error != SocketError.Success)
1649 throw new SocketException ((int) error);
1654 [CLSCompliant (false)]
1655 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1658 int ret = Receive (buffers, socketFlags, out error);
1660 if (error != SocketError.Success)
1661 throw new SocketException ((int) error);
1666 [CLSCompliant (false)]
1667 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1669 ThrowIfDisposedAndClosed ();
1671 if (buffers == null || buffers.Count == 0)
1672 throw new ArgumentNullException ("buffers");
1674 int numsegments = buffers.Count;
1678 /* Only example I can find of sending a byte array reference directly into an internal
1679 * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1680 * so taking a lead from that... */
1681 WSABUF[] bufarray = new WSABUF[numsegments];
1682 GCHandle[] gch = new GCHandle[numsegments];
1684 for (int i = 0; i < numsegments; i++) {
1685 ArraySegment<byte> segment = buffers[i];
1687 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1688 throw new ArgumentOutOfRangeException ("segment");
1690 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1691 bufarray[i].len = segment.Count;
1692 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1696 ret = Receive_internal (safe_handle, bufarray, socketFlags, out nativeError);
1698 for (int i = 0; i < numsegments; i++) {
1699 if (gch[i].IsAllocated)
1704 errorCode = (SocketError) nativeError;
1709 public bool ReceiveAsync (SocketAsyncEventArgs e)
1711 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1713 ThrowIfDisposedAndClosed ();
1715 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1716 // thrown when e.Buffer and e.BufferList are null (works fine when one is
1717 // set to a valid object)
1718 if (e.Buffer == null && e.BufferList == null)
1719 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1722 e.Worker.Init (this, e, e.Buffer != null ? SocketOperation.Receive : SocketOperation.ReceiveGeneric);
1724 SocketAsyncResult sockares = e.Worker.result;
1725 sockares.SockFlags = e.SocketFlags;
1727 if (e.Buffer != null) {
1728 sockares.Buffer = e.Buffer;
1729 sockares.Offset = e.Offset;
1730 sockares.Size = e.Count;
1732 sockares.Buffers = e.BufferList;
1735 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, s => ((SocketAsyncResult) s).Worker.Receive (), sockares));
1740 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
1742 ThrowIfDisposedAndClosed ();
1743 ThrowIfBufferNull (buffer);
1744 ThrowIfBufferOutOfRange (buffer, offset, size);
1746 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1750 SockFlags = socket_flags,
1753 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, s => ((SocketAsyncResult) s).Worker.Receive (), sockares));
1758 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags flags, out SocketError error, AsyncCallback callback, object state)
1760 /* As far as I can tell from the docs and from experimentation, a pointer to the
1761 * SocketError parameter is not supposed to be saved for the async parts. And as we don't
1762 * set any socket errors in the setup code, we just have to set it to Success. */
1763 error = SocketError.Success;
1764 return BeginReceive (buffer, offset, size, flags, callback, state);
1767 [CLSCompliant (false)]
1768 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
1770 ThrowIfDisposedAndClosed ();
1772 if (buffers == null)
1773 throw new ArgumentNullException ("buffers");
1775 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1777 SockFlags = socketFlags,
1780 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, s => ((SocketAsyncResult) s).Worker.Receive (), sockares));
1785 [CLSCompliant (false)]
1786 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1788 /* I assume the same SocketError semantics as above */
1789 errorCode = SocketError.Success;
1790 return BeginReceive (buffers, socketFlags, callback, state);
1793 public int EndReceive (IAsyncResult result)
1796 int bytesReceived = EndReceive (result, out error);
1798 if (error != SocketError.Success) {
1799 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
1800 is_connected = false;
1801 throw new SocketException ((int)error);
1804 return bytesReceived;
1807 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
1809 ThrowIfDisposedAndClosed ();
1811 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
1813 if (!sockares.IsCompleted)
1814 sockares.AsyncWaitHandle.WaitOne ();
1816 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
1817 // kinds of exceptions that should be thrown.
1818 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
1819 sockares.CheckIfThrowDelayedException();
1821 return sockares.Total;
1824 internal int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
1827 int ret = Receive_internal (safe_handle, buf, offset, size, flags, out nativeError);
1829 error = (SocketError) nativeError;
1830 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
1831 is_connected = false;
1834 is_connected = true;
1840 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
1843 safeHandle.RegisterForBlockingSyscall ();
1844 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
1846 safeHandle.UnRegisterForBlockingSyscall ();
1850 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1851 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
1853 internal static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
1856 safeHandle.RegisterForBlockingSyscall ();
1857 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
1859 safeHandle.UnRegisterForBlockingSyscall ();
1863 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1864 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error);
1870 public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
1872 ThrowIfDisposedAndClosed ();
1873 ThrowIfBufferNull (buffer);
1874 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
1876 if (remoteEP == null)
1877 throw new ArgumentNullException ("remoteEP");
1879 return ReceiveFrom_nochecks (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
1882 public int ReceiveFrom (byte [] buffer, SocketFlags flags, ref EndPoint remoteEP)
1884 ThrowIfDisposedAndClosed ();
1885 ThrowIfBufferNull (buffer);
1886 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
1888 if (remoteEP == null)
1889 throw new ArgumentNullException ("remoteEP");
1891 return ReceiveFrom_nochecks (buffer, 0, buffer.Length, flags, ref remoteEP);
1894 public int ReceiveFrom (byte [] buffer, int size, SocketFlags flags, ref EndPoint remoteEP)
1896 ThrowIfDisposedAndClosed ();
1897 ThrowIfBufferNull (buffer);
1898 ThrowIfBufferOutOfRange (buffer, 0, size);
1900 if (remoteEP == null)
1901 throw new ArgumentNullException ("remoteEP");
1903 return ReceiveFrom_nochecks (buffer, 0, size, flags, ref remoteEP);
1906 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags flags, ref EndPoint remoteEP)
1908 ThrowIfDisposedAndClosed ();
1909 ThrowIfBufferNull (buffer);
1910 ThrowIfBufferOutOfRange (buffer, offset, size);
1912 if (remoteEP == null)
1913 throw new ArgumentNullException ("remoteEP");
1915 return ReceiveFrom_nochecks (buffer, offset, size, flags, ref remoteEP);
1918 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
1920 ThrowIfDisposedAndClosed ();
1922 // We do not support recv into multiple buffers yet
1923 if (e.BufferList != null)
1924 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
1925 if (e.RemoteEndPoint == null)
1926 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
1929 e.Worker.Init (this, e, SocketOperation.ReceiveFrom);
1931 SocketAsyncResult sockares = e.Worker.result;
1932 sockares.Buffer = e.Buffer;
1933 sockares.Offset = e.Offset;
1934 sockares.Size = e.Count;
1935 sockares.EndPoint = e.RemoteEndPoint;
1936 sockares.SockFlags = e.SocketFlags;
1938 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, s => ((SocketAsyncResult) s).Worker.ReceiveFrom (), sockares));
1943 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
1945 ThrowIfDisposedAndClosed ();
1946 ThrowIfBufferNull (buffer);
1947 ThrowIfBufferOutOfRange (buffer, offset, size);
1949 if (remote_end == null)
1950 throw new ArgumentNullException ("remote_end");
1952 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
1956 SockFlags = socket_flags,
1957 EndPoint = remote_end,
1960 QueueIOSelectorJob (readQ, sockares.handle, new IOSelectorJob (IOOperation.Read, s => ((SocketAsyncResult) s).Worker.ReceiveFrom (), sockares));
1965 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
1967 ThrowIfDisposedAndClosed ();
1969 if (end_point == null)
1970 throw new ArgumentNullException ("remote_end");
1972 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
1974 if (!sockares.IsCompleted)
1975 sockares.AsyncWaitHandle.WaitOne();
1977 sockares.CheckIfThrowDelayedException();
1979 end_point = sockares.EndPoint;
1981 return sockares.Total;
1984 internal int ReceiveFrom_nochecks (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end)
1987 return ReceiveFrom_nochecks_exc (buf, offset, size, flags, ref remote_end, true, out error);
1990 internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end, bool throwOnError, out int error)
1992 SocketAddress sockaddr = remote_end.Serialize();
1994 int cnt = ReceiveFrom_internal (safe_handle, buf, offset, size, flags, ref sockaddr, out error);
1996 SocketError err = (SocketError) error;
1998 if (err != SocketError.WouldBlock && err != SocketError.InProgress) {
1999 is_connected = false;
2000 } else if (err == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
2002 throw new SocketException ((int) SocketError.TimedOut, TIMEOUT_EXCEPTION_MSG);
2003 error = (int) SocketError.TimedOut;
2008 throw new SocketException (error);
2013 is_connected = true;
2016 /* If sockaddr is null then we're a connection oriented protocol and should ignore the
2017 * remote_end parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
2018 if (sockaddr != null) {
2019 /* Stupidly, EndPoint.Create() is an instance method */
2020 remote_end = remote_end.Create (sockaddr);
2023 seed_endpoint = remote_end;
2028 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error)
2031 safeHandle.RegisterForBlockingSyscall ();
2032 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
2034 safeHandle.UnRegisterForBlockingSyscall ();
2038 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2039 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error);
2043 #region ReceiveMessageFrom
2045 [MonoTODO ("Not implemented")]
2046 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
2048 ThrowIfDisposedAndClosed ();
2049 ThrowIfBufferNull (buffer);
2050 ThrowIfBufferOutOfRange (buffer, offset, size);
2052 if (remoteEP == null)
2053 throw new ArgumentNullException ("remoteEP");
2055 // FIXME: figure out how we get hold of the IPPacketInformation
2056 throw new NotImplementedException ();
2059 [MonoTODO ("Not implemented")]
2060 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
2062 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2064 ThrowIfDisposedAndClosed ();
2066 throw new NotImplementedException ();
2070 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
2072 ThrowIfDisposedAndClosed ();
2073 ThrowIfBufferNull (buffer);
2074 ThrowIfBufferOutOfRange (buffer, offset, size);
2076 if (remoteEP == null)
2077 throw new ArgumentNullException ("remoteEP");
2079 throw new NotImplementedException ();
2083 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
2085 ThrowIfDisposedAndClosed ();
2087 if (endPoint == null)
2088 throw new ArgumentNullException ("endPoint");
2090 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
2092 throw new NotImplementedException ();
2099 public int Send (byte [] buffer)
2101 ThrowIfDisposedAndClosed ();
2102 ThrowIfBufferNull (buffer);
2103 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2106 int ret = Send_nochecks (buffer, 0, buffer.Length, SocketFlags.None, out error);
2108 if (error != SocketError.Success)
2109 throw new SocketException ((int) error);
2114 public int Send (byte [] buffer, SocketFlags flags)
2116 ThrowIfDisposedAndClosed ();
2117 ThrowIfBufferNull (buffer);
2118 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2121 int ret = Send_nochecks (buffer, 0, buffer.Length, flags, out error);
2123 if (error != SocketError.Success)
2124 throw new SocketException ((int) error);
2129 public int Send (byte [] buffer, int size, SocketFlags flags)
2131 ThrowIfDisposedAndClosed ();
2132 ThrowIfBufferNull (buffer);
2133 ThrowIfBufferOutOfRange (buffer, 0, size);
2136 int ret = Send_nochecks (buffer, 0, size, flags, out error);
2138 if (error != SocketError.Success)
2139 throw new SocketException ((int) error);
2144 public int Send (byte [] buffer, int offset, int size, SocketFlags flags)
2146 ThrowIfDisposedAndClosed ();
2147 ThrowIfBufferNull (buffer);
2148 ThrowIfBufferOutOfRange (buffer, offset, size);
2151 int ret = Send_nochecks (buffer, offset, size, flags, out error);
2153 if (error != SocketError.Success)
2154 throw new SocketException ((int) error);
2159 public int Send (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
2161 ThrowIfDisposedAndClosed ();
2162 ThrowIfBufferNull (buffer);
2163 ThrowIfBufferOutOfRange (buffer, offset, size);
2165 return Send_nochecks (buffer, offset, size, flags, out error);
2169 int Send (IList<ArraySegment<byte>> buffers)
2172 int ret = Send (buffers, SocketFlags.None, out error);
2174 if (error != SocketError.Success)
2175 throw new SocketException ((int) error);
2181 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
2184 int ret = Send (buffers, socketFlags, out error);
2186 if (error != SocketError.Success)
2187 throw new SocketException ((int) error);
2192 [CLSCompliant (false)]
2193 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
2195 ThrowIfDisposedAndClosed ();
2197 if (buffers == null)
2198 throw new ArgumentNullException ("buffers");
2199 if (buffers.Count == 0)
2200 throw new ArgumentException ("Buffer is empty", "buffers");
2202 int numsegments = buffers.Count;
2206 WSABUF[] bufarray = new WSABUF[numsegments];
2207 GCHandle[] gch = new GCHandle[numsegments];
2209 for(int i = 0; i < numsegments; i++) {
2210 ArraySegment<byte> segment = buffers[i];
2212 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
2213 throw new ArgumentOutOfRangeException ("segment");
2215 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
2216 bufarray[i].len = segment.Count;
2217 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
2221 ret = Send_internal (safe_handle, bufarray, socketFlags, out nativeError);
2223 for(int i = 0; i < numsegments; i++) {
2224 if (gch[i].IsAllocated) {
2230 errorCode = (SocketError)nativeError;
2235 internal int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2238 error = SocketError.Success;
2243 int ret = Send_internal (safe_handle, buf, offset, size, flags, out nativeError);
2245 error = (SocketError)nativeError;
2247 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2248 is_connected = false;
2251 is_connected = true;
2257 public bool SendAsync (SocketAsyncEventArgs e)
2259 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2261 ThrowIfDisposedAndClosed ();
2263 if (e.Buffer == null && e.BufferList == null)
2264 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
2267 e.Worker.Init (this, e, e.Buffer != null ? SocketOperation.Send : SocketOperation.SendGeneric);
2269 SocketAsyncResult sockares = e.Worker.result;
2270 sockares.SockFlags = e.SocketFlags;
2272 if (e.Buffer != null) {
2273 sockares.Buffer = e.Buffer;
2274 sockares.Offset = e.Offset;
2275 sockares.Size = e.Count;
2277 sockares.Buffers = e.BufferList;
2280 QueueIOSelectorJob (writeQ, sockares.handle, new IOSelectorJob (IOOperation.Write, s => ((SocketAsyncResult) s).Worker.Send (), sockares));
2285 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2287 if (!is_connected) {
2288 errorCode = SocketError.NotConnected;
2289 throw new SocketException ((int) errorCode);
2292 errorCode = SocketError.Success;
2293 return BeginSend (buffer, offset, size, socketFlags, callback, state);
2296 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
2298 ThrowIfDisposedAndClosed ();
2299 ThrowIfBufferNull (buffer);
2300 ThrowIfBufferOutOfRange (buffer, offset, size);
2303 throw new SocketException ((int)SocketError.NotConnected);
2305 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
2309 SockFlags = socket_flags,
2312 QueueIOSelectorJob (writeQ, sockares.handle, new IOSelectorJob (IOOperation.Write, s => ((SocketAsyncResult) s).Worker.Send (), sockares));
2317 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
2319 ThrowIfDisposedAndClosed ();
2321 if (buffers == null)
2322 throw new ArgumentNullException ("buffers");
2324 throw new SocketException ((int)SocketError.NotConnected);
2326 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
2328 SockFlags = socketFlags,
2331 QueueIOSelectorJob (writeQ, sockares.handle, new IOSelectorJob (IOOperation.Write, s => ((SocketAsyncResult) s).Worker.SendGeneric (), sockares));
2336 [CLSCompliant (false)]
2337 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2339 if (!is_connected) {
2340 errorCode = SocketError.NotConnected;
2341 throw new SocketException ((int)errorCode);
2344 errorCode = SocketError.Success;
2345 return BeginSend (buffers, socketFlags, callback, state);
2348 public int EndSend (IAsyncResult result)
2351 int bytesSent = EndSend (result, out error);
2353 if (error != SocketError.Success) {
2354 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2355 is_connected = false;
2356 throw new SocketException ((int)error);
2362 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
2364 ThrowIfDisposedAndClosed ();
2366 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
2368 if (!sockares.IsCompleted)
2369 sockares.AsyncWaitHandle.WaitOne ();
2371 /* If no socket error occurred, call CheckIfThrowDelayedException in
2372 * case there are other kinds of exceptions that should be thrown.*/
2373 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2374 sockares.CheckIfThrowDelayedException ();
2376 return sockares.Total;
2379 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2381 bool release = false;
2383 safeHandle.DangerousAddRef (ref release);
2384 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2387 safeHandle.DangerousRelease ();
2391 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2392 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2394 internal static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
2397 safeHandle.RegisterForBlockingSyscall ();
2398 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
2400 safeHandle.UnRegisterForBlockingSyscall ();
2404 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2405 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
2411 public int SendTo (byte [] buffer, EndPoint remote_end)
2413 ThrowIfDisposedAndClosed ();
2414 ThrowIfBufferNull (buffer);
2415 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2417 if (remote_end == null)
2418 throw new ArgumentNullException ("remote_end");
2420 return SendTo_nochecks (buffer, 0, buffer.Length, SocketFlags.None, remote_end);
2423 public int SendTo (byte [] buffer, SocketFlags flags, EndPoint remote_end)
2425 ThrowIfDisposedAndClosed ();
2426 ThrowIfBufferNull (buffer);
2427 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2429 if (remote_end == null)
2430 throw new ArgumentNullException ("remote_end");
2432 return SendTo_nochecks (buffer, 0, buffer.Length, flags, remote_end);
2435 public int SendTo (byte [] buffer, int size, SocketFlags flags, EndPoint remote_end)
2437 ThrowIfDisposedAndClosed ();
2438 ThrowIfBufferNull (buffer);
2439 ThrowIfBufferOutOfRange (buffer, 0, size);
2441 if (remote_end == null)
2442 throw new ArgumentNullException ("remote_end");
2444 return SendTo_nochecks (buffer, 0, size, flags, remote_end);
2447 public int SendTo (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2449 ThrowIfDisposedAndClosed ();
2450 ThrowIfBufferNull (buffer);
2451 ThrowIfBufferOutOfRange (buffer, offset, size);
2453 if (remote_end == null)
2454 throw new ArgumentNullException("remote_end");
2456 return SendTo_nochecks (buffer, offset, size, flags, remote_end);
2459 internal int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2462 int ret = SendTo_internal (safe_handle, buffer, offset, size, flags, remote_end.Serialize (), out error);
2464 SocketError err = (SocketError) error;
2466 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2467 is_connected = false;
2468 throw new SocketException (error);
2471 is_connected = true;
2473 seed_endpoint = remote_end;
2478 public bool SendToAsync (SocketAsyncEventArgs e)
2480 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2482 ThrowIfDisposedAndClosed ();
2484 if (e.BufferList != null)
2485 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2486 if (e.RemoteEndPoint == null)
2487 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2490 e.Worker.Init (this, e, SocketOperation.SendTo);
2492 SocketAsyncResult sockares = e.Worker.result;
2493 sockares.Buffer = e.Buffer;
2494 sockares.Offset = e.Offset;
2495 sockares.Size = e.Count;
2496 sockares.SockFlags = e.SocketFlags;
2497 sockares.EndPoint = e.RemoteEndPoint;
2499 QueueIOSelectorJob (writeQ, sockares.handle, new IOSelectorJob (IOOperation.Write, s => ((SocketAsyncResult) s).Worker.SendTo (), sockares));
2505 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2507 ThrowIfDisposedAndClosed ();
2508 ThrowIfBufferNull (buffer);
2509 ThrowIfBufferOutOfRange (buffer, offset, size);
2511 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2515 SockFlags = socket_flags,
2516 EndPoint = remote_end,
2519 QueueIOSelectorJob (writeQ, sockares.handle, new IOSelectorJob (IOOperation.Write, s => ((SocketAsyncResult) s).Worker.SendTo (), sockares));
2524 public int EndSendTo (IAsyncResult result)
2526 ThrowIfDisposedAndClosed ();
2528 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2530 if (!sockares.IsCompleted)
2531 sockares.AsyncWaitHandle.WaitOne();
2533 sockares.CheckIfThrowDelayedException();
2535 return sockares.Total;
2538 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
2541 safeHandle.RegisterForBlockingSyscall ();
2542 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
2544 safeHandle.UnRegisterForBlockingSyscall ();
2548 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2549 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
2555 public void SendFile (string fileName)
2557 ThrowIfDisposedAndClosed ();
2560 throw new NotSupportedException ();
2562 throw new InvalidOperationException ();
2564 SendFile (fileName, null, null, 0);
2567 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2569 ThrowIfDisposedAndClosed ();
2572 throw new NotSupportedException ();
2574 throw new InvalidOperationException ();
2576 if (!SendFile_internal (safe_handle, fileName, preBuffer, postBuffer, flags)) {
2577 SocketException exc = new SocketException ();
2578 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2579 throw new FileNotFoundException ();
2584 public IAsyncResult BeginSendFile (string fileName, AsyncCallback callback, object state)
2586 ThrowIfDisposedAndClosed ();
2589 throw new NotSupportedException ();
2590 if (!File.Exists (fileName))
2591 throw new FileNotFoundException ();
2593 return BeginSendFile (fileName, null, null, 0, callback, state);
2596 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2598 ThrowIfDisposedAndClosed ();
2601 throw new NotSupportedException ();
2602 if (!File.Exists (fileName))
2603 throw new FileNotFoundException ();
2605 SendFileHandler handler = new SendFileHandler (SendFile);
2607 return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2610 public void EndSendFile (IAsyncResult asyncResult)
2612 ThrowIfDisposedAndClosed ();
2614 if (asyncResult == null)
2615 throw new ArgumentNullException ("asyncResult");
2617 SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2619 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2621 ares.Delegate.EndInvoke (ares.Original);
2624 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
2627 safeHandle.RegisterForBlockingSyscall ();
2628 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
2630 safeHandle.UnRegisterForBlockingSyscall ();
2634 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2635 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
2637 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2639 sealed class SendFileAsyncResult : IAsyncResult {
2643 public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2649 public object AsyncState {
2650 get { return ares.AsyncState; }
2653 public WaitHandle AsyncWaitHandle {
2654 get { return ares.AsyncWaitHandle; }
2657 public bool CompletedSynchronously {
2658 get { return ares.CompletedSynchronously; }
2661 public bool IsCompleted {
2662 get { return ares.IsCompleted; }
2665 public SendFileHandler Delegate {
2669 public IAsyncResult Original {
2670 get { return ares; }
2678 [MonoTODO ("Not implemented")]
2679 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2681 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2683 ThrowIfDisposedAndClosed ();
2685 throw new NotImplementedException ();
2690 #region DuplicateAndClose
2693 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2694 public SocketInformation DuplicateAndClose (int targetProcessId)
2696 var si = new SocketInformation ();
2698 (is_listening ? SocketInformationOptions.Listening : 0) |
2699 (is_connected ? SocketInformationOptions.Connected : 0) |
2700 (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
2701 (use_overlapped_io ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
2703 si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, is_bound ? 1 : 0, (long)Handle);
2712 #region GetSocketOption
2714 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2716 ThrowIfDisposedAndClosed ();
2718 if (optionValue == null)
2719 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2722 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref optionValue, out error);
2725 throw new SocketException (error);
2728 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int length)
2730 ThrowIfDisposedAndClosed ();
2733 byte[] byte_val = new byte [length];
2734 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref byte_val, out error);
2737 throw new SocketException (error);
2742 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
2744 ThrowIfDisposedAndClosed ();
2748 GetSocketOption_obj_internal (safe_handle, optionLevel, optionName, out obj_val, out error);
2751 throw new SocketException (error);
2753 if (optionName == SocketOptionName.Linger)
2754 return (LingerOption) obj_val;
2755 else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
2756 return (MulticastOption) obj_val;
2757 else if (obj_val is int)
2758 return (int) obj_val;
2763 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
2765 bool release = false;
2767 safeHandle.DangerousAddRef (ref release);
2768 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
2771 safeHandle.DangerousRelease ();
2775 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2776 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
2778 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
2780 bool release = false;
2782 safeHandle.DangerousAddRef (ref release);
2783 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
2786 safeHandle.DangerousRelease ();
2790 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2791 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
2795 #region SetSocketOption
2797 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2799 ThrowIfDisposedAndClosed ();
2801 // I'd throw an ArgumentNullException, but this is what MS does.
2802 if (optionValue == null)
2803 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2806 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, optionValue, 0, out error);
2809 if (error == (int) SocketError.InvalidArgument)
2810 throw new ArgumentException ();
2811 throw new SocketException (error);
2815 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
2817 ThrowIfDisposedAndClosed ();
2819 // NOTE: if a null is passed, the byte[] overload is used instead...
2820 if (optionValue == null)
2821 throw new ArgumentNullException("optionValue");
2825 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
2826 LingerOption linger = optionValue as LingerOption;
2828 throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
2829 SetSocketOption_internal (safe_handle, optionLevel, optionName, linger, null, 0, out error);
2830 } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2831 MulticastOption multicast = optionValue as MulticastOption;
2832 if (multicast == null)
2833 throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
2834 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
2835 } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2836 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
2837 if (multicast == null)
2838 throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
2839 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
2841 throw new ArgumentException ("Invalid value specified.", "optionValue");
2845 if (error == (int) SocketError.InvalidArgument)
2846 throw new ArgumentException ();
2847 throw new SocketException (error);
2851 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
2853 ThrowIfDisposedAndClosed ();
2856 int int_val = optionValue ? 1 : 0;
2857 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, int_val, out error);
2860 if (error == (int) SocketError.InvalidArgument)
2861 throw new ArgumentException ();
2862 throw new SocketException (error);
2866 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
2868 ThrowIfDisposedAndClosed ();
2871 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, optionValue, out error);
2874 throw new SocketException (error);
2878 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
2880 bool release = false;
2882 safeHandle.DangerousAddRef (ref release);
2883 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
2886 safeHandle.DangerousRelease ();
2890 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2891 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
2897 public int IOControl (int ioctl_code, byte [] in_value, byte [] out_value)
2900 throw new ObjectDisposedException (GetType ().ToString ());
2903 int result = IOControl_internal (safe_handle, ioctl_code, in_value, out_value, out error);
2906 throw new SocketException (error);
2908 throw new InvalidOperationException ("Must use Blocking property instead.");
2913 public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
2915 return IOControl ((int) ioControlCode, optionInValue, optionOutValue);
2918 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
2920 bool release = false;
2922 safeHandle.DangerousAddRef (ref release);
2923 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
2926 safeHandle.DangerousRelease ();
2930 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
2931 * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
2932 * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
2933 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2934 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
2940 public void Close ()
2946 public void Close (int timeout)
2948 linger_timeout = timeout;
2952 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2953 internal extern static void Close_internal (IntPtr socket, out int error);
2959 public void Shutdown (SocketShutdown how)
2961 ThrowIfDisposedAndClosed ();
2964 throw new SocketException (10057); // Not connected
2967 Shutdown_internal (safe_handle, how, out error);
2970 throw new SocketException (error);
2973 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
2975 bool release = false;
2977 safeHandle.DangerousAddRef (ref release);
2978 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
2981 safeHandle.DangerousRelease ();
2985 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2986 extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
2992 protected virtual void Dispose (bool disposing)
2998 bool was_connected = is_connected;
2999 is_connected = false;
3001 if (safe_handle != null) {
3008 safe_handle.Dispose ();
3012 public void Dispose ()
3015 GC.SuppressFinalize (this);
3018 void Linger (IntPtr handle)
3020 if (!is_connected || linger_timeout <= 0)
3023 /* We don't want to receive any more data */
3025 Shutdown_internal (handle, SocketShutdown.Receive, out error);
3030 int seconds = linger_timeout / 1000;
3031 int ms = linger_timeout % 1000;
3033 /* If the other end closes, this will return 'true' with 'Available' == 0 */
3034 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
3040 LingerOption linger = new LingerOption (true, seconds);
3041 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
3042 /* Not needed, we're closing upon return */
3050 void ThrowIfDisposedAndClosed (Socket socket)
3052 if (socket.is_disposed && socket.is_closed)
3053 throw new ObjectDisposedException (socket.GetType ().ToString ());
3056 void ThrowIfDisposedAndClosed ()
3058 if (is_disposed && is_closed)
3059 throw new ObjectDisposedException (GetType ().ToString ());
3062 void ThrowIfBufferNull (byte[] buffer)
3065 throw new ArgumentNullException ("buffer");
3068 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
3071 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
3072 if (offset > buffer.Length)
3073 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
3075 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
3076 if (size > buffer.Length - offset)
3077 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
3082 #if !NET_2_1 || MOBILE
3083 if (protocol_type == ProtocolType.Udp)
3084 throw new SocketException ((int)SocketError.ProtocolOption);
3088 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
3091 throw new ArgumentNullException (argName);
3093 SocketAsyncResult sockares = ares as SocketAsyncResult;
3094 if (sockares == null)
3095 throw new ArgumentException ("Invalid IAsyncResult", argName);
3096 if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
3097 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
3102 void QueueIOSelectorJob (Queue<KeyValuePair<IntPtr, IOSelectorJob>> queue, IntPtr handle, IOSelectorJob job)
3106 queue.Enqueue (new KeyValuePair<IntPtr, IOSelectorJob> (handle, job));
3107 count = queue.Count;
3111 IOSelector.Add (handle, job);
3114 [StructLayout (LayoutKind.Sequential)]
3120 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3121 internal static extern void cancel_blocking_socket_operation (Thread thread);