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 /* the field "safe_handle" is looked up by name by the runtime */
74 SafeSocketHandle safe_handle;
76 AddressFamily address_family;
77 SocketType socket_type;
78 ProtocolType protocol_type;
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<SocketAsyncWorker> readQ = new Queue<SocketAsyncWorker> (2);
90 internal Queue<SocketAsyncWorker> writeQ = new Queue<SocketAsyncWorker> (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)
170 public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
172 #if NET_2_1 && !MOBILE
173 switch (addressFamily) {
174 case AddressFamily.InterNetwork: // ok
175 case AddressFamily.InterNetworkV6: // ok
176 case AddressFamily.Unknown: // SocketException will be thrown later (with right error #)
178 // case AddressFamily.Unspecified:
180 throw new ArgumentException ("addressFamily");
183 switch (socketType) {
184 case SocketType.Stream: // ok
185 case SocketType.Unknown: // SocketException will be thrown later (with right error #)
188 throw new ArgumentException ("socketType");
191 switch (protocolType) {
192 case ProtocolType.Tcp: // ok
193 case ProtocolType.Unspecified: // ok
194 case ProtocolType.Unknown: // SocketException will be thrown later (with right error #)
197 throw new ArgumentException ("protocolType");
200 this.address_family = addressFamily;
201 this.socket_type = socketType;
202 this.protocol_type = protocolType;
205 var handle = Socket_internal (addressFamily, socketType, protocolType, out error);
207 this.safe_handle = new SafeSocketHandle (handle, true);
210 throw new SocketException (error);
212 #if !NET_2_1 || MOBILE
218 public Socket (SocketInformation socketInformation)
220 this.is_listening = (socketInformation.Options & SocketInformationOptions.Listening) != 0;
221 this.is_connected = (socketInformation.Options & SocketInformationOptions.Connected) != 0;
222 this.is_blocking = (socketInformation.Options & SocketInformationOptions.NonBlocking) == 0;
223 this.use_overlapped_io = (socketInformation.Options & SocketInformationOptions.UseOnlyOverlappedIO) != 0;
225 var result = Mono.DataConverter.Unpack ("iiiil", socketInformation.ProtocolInformation, 0);
227 this.address_family = (AddressFamily) (int) result [0];
228 this.socket_type = (SocketType) (int) result [1];
229 this.protocol_type = (ProtocolType) (int) result [2];
230 this.is_bound = (ProtocolType) (int) result [3] != 0;
231 this.safe_handle = new SafeSocketHandle ((IntPtr) (long) result [4], true);
237 /* private constructor used by Accept, which already has a socket handle to use */
238 internal Socket(AddressFamily family, SocketType type, ProtocolType proto, SafeSocketHandle safe_handle)
240 this.address_family = family;
241 this.socket_type = type;
242 this.protocol_type = proto;
244 this.safe_handle = safe_handle;
245 this.is_connected = true;
253 void SocketDefaults ()
256 /* Need to test IPv6 further */
257 if (address_family == AddressFamily.InterNetwork
258 // || address_family == AddressFamily.InterNetworkV6
260 /* This is the default, but it probably has nasty side
261 * effects on Linux, as the socket option is kludged by
262 * turning on or off PMTU discovery... */
263 this.DontFragment = false;
266 /* Microsoft sets these to 8192, but we are going to keep them
267 * both to the OS defaults as these have a big performance impact.
268 * on WebClient performance. */
269 // this.ReceiveBufferSize = 8192;
270 // this.SendBufferSize = 8192;
271 } catch (SocketException) {
275 /* Creates a new system socket, returning the handle */
276 [MethodImplAttribute(MethodImplOptions.InternalCall)]
277 extern IntPtr Socket_internal (AddressFamily family, SocketType type, ProtocolType proto, out int error);
283 public static bool SupportsIPv4 {
284 get { return ipv4_supported == 1; }
287 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
288 public static bool SupportsIPv6 {
289 get { return ipv6_supported == 1; }
293 public static bool OSSupportsIPv4 {
294 get { return ipv4_supported == 1; }
299 public static bool OSSupportsIPv6 {
300 get { return ipv6_supported == 1; }
303 public static bool OSSupportsIPv6 {
305 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
307 foreach (NetworkInterface adapter in nics) {
308 if (adapter.Supports (NetworkInterfaceComponent.IPv6))
317 public int Available {
319 ThrowIfDisposedAndClosed ();
322 ret = Available_internal (safe_handle, out error);
325 throw new SocketException (error);
331 static int Available_internal (SafeSocketHandle safeHandle, out int error)
333 bool release = false;
335 safeHandle.DangerousAddRef (ref release);
336 return Available_internal (safeHandle.DangerousGetHandle (), out error);
339 safeHandle.DangerousRelease ();
343 /* Returns the amount of data waiting to be read on socket */
344 [MethodImplAttribute(MethodImplOptions.InternalCall)]
345 extern static int Available_internal (IntPtr socket, out int error);
347 public bool DontFragment {
349 ThrowIfDisposedAndClosed ();
351 switch (address_family) {
352 case AddressFamily.InterNetwork:
353 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment)) != 0;
354 case AddressFamily.InterNetworkV6:
355 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment)) != 0;
357 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
361 ThrowIfDisposedAndClosed ();
363 switch (address_family) {
364 case AddressFamily.InterNetwork:
365 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
367 case AddressFamily.InterNetworkV6:
368 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment, value ? 1 : 0);
371 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
376 public bool EnableBroadcast {
378 ThrowIfDisposedAndClosed ();
380 if (protocol_type != ProtocolType.Udp)
381 throw new SocketException ((int) SocketError.ProtocolOption);
383 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0;
386 ThrowIfDisposedAndClosed ();
388 if (protocol_type != ProtocolType.Udp)
389 throw new SocketException ((int) SocketError.ProtocolOption);
391 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
395 public bool ExclusiveAddressUse {
397 ThrowIfDisposedAndClosed ();
399 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse)) != 0;
402 ThrowIfDisposedAndClosed ();
405 throw new InvalidOperationException ("Bind has already been called for this socket");
407 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
411 public bool IsBound {
417 public LingerOption LingerState {
419 ThrowIfDisposedAndClosed ();
421 return (LingerOption) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger);
424 ThrowIfDisposedAndClosed ();
425 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger, value);
429 public bool MulticastLoopback {
431 ThrowIfDisposedAndClosed ();
433 /* Even though this option can be set for TCP sockets on Linux, throw
434 * this exception anyway to be compatible (the MSDN docs say
435 * "Setting this property on a Transmission Control Protocol (TCP)
436 * socket will have no effect." but the MS runtime throws the
438 if (protocol_type == ProtocolType.Tcp)
439 throw new SocketException ((int)SocketError.ProtocolOption);
441 switch (address_family) {
442 case AddressFamily.InterNetwork:
443 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
444 case AddressFamily.InterNetworkV6:
445 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
447 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
451 ThrowIfDisposedAndClosed ();
453 /* Even though this option can be set for TCP sockets on Linux, throw
454 * this exception anyway to be compatible (the MSDN docs say
455 * "Setting this property on a Transmission Control Protocol (TCP)
456 * socket will have no effect." but the MS runtime throws the
458 if (protocol_type == ProtocolType.Tcp)
459 throw new SocketException ((int)SocketError.ProtocolOption);
461 switch (address_family) {
462 case AddressFamily.InterNetwork:
463 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
465 case AddressFamily.InterNetworkV6:
466 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
469 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
474 [MonoTODO ("This doesn't do anything on Mono yet")]
475 public bool UseOnlyOverlappedIO {
476 get { return use_overlapped_io; }
477 set { use_overlapped_io = value; }
480 public IntPtr Handle {
481 get { return safe_handle.DangerousGetHandle (); }
484 // Wish: support non-IP endpoints.
485 public EndPoint LocalEndPoint {
487 ThrowIfDisposedAndClosed ();
489 /* If the seed EndPoint is null, Connect, Bind, etc has not yet
490 * been called. MS returns null in this case. */
491 if (seed_endpoint == null)
495 SocketAddress sa = LocalEndPoint_internal (safe_handle, (int) address_family, out error);
498 throw new SocketException (error);
500 return seed_endpoint.Create (sa);
504 static SocketAddress LocalEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
506 bool release = false;
508 safeHandle.DangerousAddRef (ref release);
509 return LocalEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
512 safeHandle.DangerousRelease ();
516 /* Returns the local endpoint details in addr and port */
517 [MethodImplAttribute(MethodImplOptions.InternalCall)]
518 extern static SocketAddress LocalEndPoint_internal (IntPtr socket, int family, out int error);
520 public SocketType SocketType {
521 get { return socket_type; }
524 public int SendTimeout {
526 ThrowIfDisposedAndClosed ();
528 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
531 ThrowIfDisposedAndClosed ();
534 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
536 /* According to the MSDN docs we should adjust values between 1 and
537 * 499 to 500, but the MS runtime doesn't do this. */
541 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
545 public int ReceiveTimeout {
547 ThrowIfDisposedAndClosed ();
549 return (int) GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
552 ThrowIfDisposedAndClosed ();
555 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
560 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, value);
564 public AddressFamily AddressFamily {
565 get { return address_family; }
568 public bool Blocking {
569 get { return is_blocking; }
571 ThrowIfDisposedAndClosed ();
574 Blocking_internal (safe_handle, value, out error);
577 throw new SocketException (error);
583 static void Blocking_internal (SafeSocketHandle safeHandle, bool block, out int error)
585 bool release = false;
587 safeHandle.DangerousAddRef (ref release);
588 Blocking_internal (safeHandle.DangerousGetHandle (), block, out error);
591 safeHandle.DangerousRelease ();
595 [MethodImplAttribute(MethodImplOptions.InternalCall)]
596 internal extern static void Blocking_internal(IntPtr socket, bool block, out int error);
598 public bool Connected {
599 get { return is_connected; }
600 internal set { is_connected = value; }
603 public ProtocolType ProtocolType {
604 get { return protocol_type; }
607 public bool NoDelay {
609 ThrowIfDisposedAndClosed ();
612 return ((int) GetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay)) != 0;
616 ThrowIfDisposedAndClosed ();
619 SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
623 public int ReceiveBufferSize {
625 ThrowIfDisposedAndClosed ();
627 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer);
630 ThrowIfDisposedAndClosed ();
633 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
635 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
639 public int SendBufferSize {
641 ThrowIfDisposedAndClosed ();
643 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer);
646 ThrowIfDisposedAndClosed ();
649 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
651 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer, value);
657 ThrowIfDisposedAndClosed ();
659 switch (address_family) {
660 case AddressFamily.InterNetwork:
661 return (short) (int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
662 case AddressFamily.InterNetworkV6:
663 return (short) (int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit);
665 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
669 ThrowIfDisposedAndClosed ();
672 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
674 switch (address_family) {
675 case AddressFamily.InterNetwork:
676 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
678 case AddressFamily.InterNetworkV6:
679 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
682 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
687 public EndPoint RemoteEndPoint {
689 ThrowIfDisposedAndClosed ();
691 /* If the seed EndPoint is null, Connect, Bind, etc has
692 * not yet been called. MS returns null in this case. */
693 if (!is_connected || seed_endpoint == null)
697 SocketAddress sa = RemoteEndPoint_internal (safe_handle, (int) address_family, out error);
700 throw new SocketException (error);
702 return seed_endpoint.Create (sa);
706 static SocketAddress RemoteEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
708 bool release = false;
710 safeHandle.DangerousAddRef (ref release);
711 return RemoteEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
714 safeHandle.DangerousRelease ();
718 /* Returns the remote endpoint details in addr and port */
719 [MethodImplAttribute(MethodImplOptions.InternalCall)]
720 extern static SocketAddress RemoteEndPoint_internal (IntPtr socket, int family, out int error);
726 public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
728 var list = new List<Socket> ();
729 AddSockets (list, checkRead, "checkRead");
730 AddSockets (list, checkWrite, "checkWrite");
731 AddSockets (list, checkError, "checkError");
734 throw new ArgumentNullException ("checkRead, checkWrite, checkError", "All the lists are null or empty.");
736 /* The 'sockets' array contains:
737 * - READ socket 0-n, null,
738 * - WRITE socket 0-n, null,
739 * - ERROR socket 0-n, null */
740 Socket [] sockets = list.ToArray ();
743 Select_internal (ref sockets, microSeconds, out error);
746 throw new SocketException (error);
748 if (sockets == null) {
749 if (checkRead != null)
751 if (checkWrite != null)
753 if (checkError != null)
759 int count = sockets.Length;
760 IList currentList = checkRead;
762 for (int i = 0; i < count; i++) {
763 Socket sock = sockets [i];
764 if (sock == null) { // separator
765 if (currentList != null) {
766 // Remove non-signaled sockets after the current one
767 int to_remove = currentList.Count - currentIdx;
768 for (int k = 0; k < to_remove; k++)
769 currentList.RemoveAt (currentIdx);
771 currentList = (mode == 0) ? checkWrite : checkError;
777 if (mode == 1 && currentList == checkWrite && !sock.is_connected) {
778 if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
779 sock.is_connected = true;
782 /* Remove non-signaled sockets before the current one */
783 while (((Socket) currentList [currentIdx]) != sock)
784 currentList.RemoveAt (currentIdx);
790 static void AddSockets (List<Socket> sockets, IList list, string name)
793 foreach (Socket sock in list) {
794 if (sock == null) // MS throws a NullRef
795 throw new ArgumentNullException ("name", "Contains a null element");
803 [MethodImplAttribute(MethodImplOptions.InternalCall)]
804 extern static void Select_internal (ref Socket [] sockets, int microSeconds, out int error);
810 public bool Poll (int time_us, SelectMode mode)
812 ThrowIfDisposedAndClosed ();
814 if (mode != SelectMode.SelectRead && mode != SelectMode.SelectWrite && mode != SelectMode.SelectError)
815 throw new NotSupportedException ("'mode' parameter is not valid.");
818 bool result = Poll_internal (safe_handle, mode, time_us, out error);
821 throw new SocketException (error);
823 if (mode == SelectMode.SelectWrite && result && !is_connected) {
824 /* Update the is_connected state; for non-blocking Connect()
825 * this is when we can find out that the connect succeeded. */
826 if ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
833 static bool Poll_internal (SafeSocketHandle safeHandle, SelectMode mode, int timeout, out int error)
835 bool release = false;
837 safeHandle.DangerousAddRef (ref release);
838 return Poll_internal (safeHandle.DangerousGetHandle (), mode, timeout, out error);
841 safeHandle.DangerousRelease ();
845 [MethodImplAttribute(MethodImplOptions.InternalCall)]
846 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
852 public Socket Accept()
854 ThrowIfDisposedAndClosed ();
857 SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
861 error = SOCKET_CLOSED_CODE;
862 throw new SocketException(error);
865 Socket accepted = new Socket (this.AddressFamily, this.SocketType, this.ProtocolType, safe_handle) {
866 seed_endpoint = this.seed_endpoint,
867 Blocking = this.Blocking,
873 internal void Accept (Socket acceptSocket)
875 ThrowIfDisposedAndClosed ();
878 SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
882 error = SOCKET_CLOSED_CODE;
883 throw new SocketException (error);
886 acceptSocket.address_family = this.AddressFamily;
887 acceptSocket.socket_type = this.SocketType;
888 acceptSocket.protocol_type = this.ProtocolType;
889 acceptSocket.safe_handle = safe_handle;
890 acceptSocket.is_connected = true;
891 acceptSocket.seed_endpoint = this.seed_endpoint;
892 acceptSocket.Blocking = this.Blocking;
894 // FIXME: figure out what if anything else needs to be reset
897 public bool AcceptAsync (SocketAsyncEventArgs e)
899 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
901 ThrowIfDisposedAndClosed ();
904 throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
906 throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
907 if (e.BufferList != null)
908 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
910 throw new ArgumentOutOfRangeException ("e.Count");
912 Socket acceptSocket = e.AcceptSocket;
913 if (acceptSocket != null) {
914 if (acceptSocket.is_bound || acceptSocket.is_connected)
915 throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
919 e.Worker.Init (this, e, SocketOperation.Accept);
921 SocketAsyncResult sockares = e.Worker.result;
923 QueueSocketAsyncResult (readQ, e.Worker, sockares);
928 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
930 ThrowIfDisposedAndClosed ();
932 if (!is_bound || !is_listening)
933 throw new InvalidOperationException ();
935 SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.Accept);
937 QueueSocketAsyncResult (readQ, sockares.Worker, sockares);
942 public IAsyncResult BeginAccept (int receiveSize, AsyncCallback callback, object state)
944 ThrowIfDisposedAndClosed ();
947 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
949 SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive) {
950 Buffer = new byte [receiveSize],
953 SockFlags = SocketFlags.None,
956 QueueSocketAsyncResult (readQ, sockares.Worker, sockares);
961 public IAsyncResult BeginAccept (Socket acceptSocket, int receiveSize, AsyncCallback callback, object state)
963 ThrowIfDisposedAndClosed ();
966 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
968 if (acceptSocket != null) {
969 ThrowIfDisposedAndClosed (acceptSocket);
971 if (acceptSocket.IsBound)
972 throw new InvalidOperationException ();
974 /* For some reason the MS runtime
975 * barfs if the new socket is not TCP,
976 * even though it's just about to blow
977 * away all those parameters
979 if (acceptSocket.ProtocolType != ProtocolType.Tcp)
980 throw new SocketException ((int)SocketError.InvalidArgument);
983 SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive) {
984 Buffer = new byte [receiveSize],
987 SockFlags = SocketFlags.None,
988 AcceptSocket = acceptSocket,
991 QueueSocketAsyncResult (readQ, sockares.Worker, sockares);
996 public Socket EndAccept (IAsyncResult result)
1000 return EndAccept (out buffer, out bytes, result);
1003 public Socket EndAccept (out byte[] buffer, IAsyncResult asyncResult)
1006 return EndAccept (out buffer, out bytes, asyncResult);
1009 public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
1011 ThrowIfDisposedAndClosed ();
1013 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndAccept", "asyncResult");
1015 if (!sockares.IsCompleted)
1016 sockares.AsyncWaitHandle.WaitOne ();
1018 sockares.CheckIfThrowDelayedException ();
1020 buffer = sockares.Buffer;
1021 bytesTransferred = sockares.Total;
1023 return sockares.Socket;
1026 static SafeSocketHandle Accept_internal (SafeSocketHandle safeHandle, out int error, bool blocking)
1029 safeHandle.RegisterForBlockingSyscall ();
1030 var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
1031 return new SafeSocketHandle (ret, true);
1033 safeHandle.UnRegisterForBlockingSyscall ();
1037 /* Creates a new system socket, returning the handle */
1038 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1039 extern static IntPtr Accept_internal (IntPtr sock, out int error, bool blocking);
1045 public void Bind (EndPoint local_end)
1047 ThrowIfDisposedAndClosed ();
1049 if (local_end == null)
1050 throw new ArgumentNullException("local_end");
1053 Bind_internal (safe_handle, local_end.Serialize(), out error);
1056 throw new SocketException (error);
1060 seed_endpoint = local_end;
1063 private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1065 bool release = false;
1067 safeHandle.DangerousAddRef (ref release);
1068 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
1071 safeHandle.DangerousRelease ();
1075 // Creates a new system socket, returning the handle
1076 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1077 private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
1083 public void Listen (int backlog)
1085 ThrowIfDisposedAndClosed ();
1088 throw new SocketException ((int) SocketError.InvalidArgument);
1091 Listen_internal(safe_handle, backlog, out error);
1094 throw new SocketException (error);
1096 is_listening = true;
1099 static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
1101 bool release = false;
1103 safeHandle.DangerousAddRef (ref release);
1104 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
1107 safeHandle.DangerousRelease ();
1111 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1112 extern static void Listen_internal (IntPtr sock, int backlog, out int error);
1118 public void Connect (IPAddress address, int port)
1120 Connect (new IPEndPoint (address, port));
1123 public void Connect (string host, int port)
1125 Connect (Dns.GetHostAddresses (host), port);
1128 public void Connect (IPAddress[] addresses, int port)
1130 ThrowIfDisposedAndClosed ();
1132 if (addresses == null)
1133 throw new ArgumentNullException ("addresses");
1134 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1135 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1137 throw new InvalidOperationException ();
1139 // FIXME: do non-blocking sockets Poll here?
1141 foreach (IPAddress address in addresses) {
1142 IPEndPoint iep = new IPEndPoint (address, port);
1144 Connect_internal (safe_handle, iep.Serialize (), out error);
1146 is_connected = true;
1148 seed_endpoint = iep;
1151 if (error != (int)SocketError.InProgress && error != (int)SocketError.WouldBlock)
1155 Poll (-1, SelectMode.SelectWrite);
1156 error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1158 is_connected = true;
1160 seed_endpoint = iep;
1167 throw new SocketException (error);
1171 public void Connect (EndPoint remoteEP)
1173 ThrowIfDisposedAndClosed ();
1175 if (remoteEP == null)
1176 throw new ArgumentNullException ("remoteEP");
1178 IPEndPoint ep = remoteEP as IPEndPoint;
1179 /* Dgram uses Any to 'disconnect' */
1180 if (ep != null && socket_type != SocketType.Dgram) {
1181 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1182 throw new SocketException ((int) SocketError.AddressNotAvailable);
1186 throw new InvalidOperationException ();
1188 SocketAddress serial = remoteEP.Serialize ();
1191 Connect_internal (safe_handle, serial, out error);
1193 if (error == 0 || error == 10035)
1194 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1198 error = SOCKET_CLOSED_CODE;
1199 throw new SocketException (error);
1202 is_connected = !(socket_type == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
1206 public bool ConnectAsync (SocketAsyncEventArgs e)
1208 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1210 ThrowIfDisposedAndClosed ();
1213 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1214 if (e.RemoteEndPoint == null)
1215 throw new ArgumentNullException ("remoteEP");
1218 e.Worker.Init (this, e, SocketOperation.Connect);
1220 SocketAsyncResult result = e.Worker.result;
1223 IPAddress [] addresses;
1226 if (!GetCheckedIPs (e, out addresses)) {
1227 result.EndPoint = e.RemoteEndPoint;
1228 ares = BeginConnect (e.RemoteEndPoint, SocketAsyncEventArgs.Dispatcher, e);
1230 DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1231 result.Addresses = addresses;
1232 result.Port = dep.Port;
1233 ares = BeginConnect (addresses, dep.Port, SocketAsyncEventArgs.Dispatcher, e);
1236 if (ares.IsCompleted && ares.CompletedSynchronously) {
1237 ((SocketAsyncResult) ares).CheckIfThrowDelayedException ();
1240 } catch (Exception exc) {
1241 result.Complete (exc, true);
1248 public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback callback, object state)
1250 ThrowIfDisposedAndClosed ();
1252 if (address == null)
1253 throw new ArgumentNullException ("address");
1254 if (address.ToString ().Length == 0)
1255 throw new ArgumentException ("The length of the IP address is zero");
1256 if (port <= 0 || port > 65535)
1257 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1259 throw new InvalidOperationException ();
1261 return BeginConnect (new IPEndPoint (address, port), callback, state);
1264 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
1266 ThrowIfDisposedAndClosed ();
1269 throw new ArgumentNullException ("host");
1270 if (address_family != AddressFamily.InterNetwork && address_family != AddressFamily.InterNetworkV6)
1271 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1272 if (port <= 0 || port > 65535)
1273 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1275 throw new InvalidOperationException ();
1277 return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1280 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
1282 ThrowIfDisposedAndClosed ();
1284 if (end_point == null)
1285 throw new ArgumentNullException ("end_point");
1287 SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.Connect) {
1288 EndPoint = end_point,
1291 // Bug #75154: Connect() should not succeed for .Any addresses.
1292 if (end_point is IPEndPoint) {
1293 IPEndPoint ep = (IPEndPoint) end_point;
1294 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1295 sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1302 if (connect_in_progress) {
1303 // This could happen when multiple IPs are used
1304 // Calling connect() again will reset the connection attempt and cause
1305 // an error. Better to just close the socket and move on.
1306 connect_in_progress = false;
1307 safe_handle.Dispose ();
1308 var handle = Socket_internal (address_family, socket_type, protocol_type, out error);
1309 safe_handle = new SafeSocketHandle (handle, true);
1311 throw new SocketException (error);
1314 bool blk = is_blocking;
1317 Connect_internal (safe_handle, end_point.Serialize (), out error);
1323 is_connected = true;
1325 sockares.Complete (true);
1329 if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1331 is_connected = false;
1333 sockares.Complete (new SocketException (error), true);
1338 is_connected = false;
1340 connect_in_progress = true;
1342 socket_pool_queue (SocketAsyncWorker.Dispatcher, sockares);
1347 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1349 ThrowIfDisposedAndClosed ();
1351 if (addresses == null)
1352 throw new ArgumentNullException ("addresses");
1353 if (addresses.Length == 0)
1354 throw new ArgumentException ("Empty addresses list");
1355 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1356 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1357 if (port <= 0 || port > 65535)
1358 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1360 throw new InvalidOperationException ();
1362 SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.Connect) {
1363 Addresses = addresses,
1367 is_connected = false;
1369 return BeginMConnect (sockares);
1372 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1374 IAsyncResult ares = null;
1375 Exception exc = null;
1377 for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1379 sockares.CurrentAddress++;
1381 ares = BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1382 if (ares.IsCompleted && ares.CompletedSynchronously) {
1383 ((SocketAsyncResult) ares).CheckIfThrowDelayedException ();
1384 sockares.DoMConnectCallback ();
1388 } catch (Exception e) {
1400 public void EndConnect (IAsyncResult result)
1402 ThrowIfDisposedAndClosed ();
1404 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1406 if (!sockares.IsCompleted)
1407 sockares.AsyncWaitHandle.WaitOne();
1409 sockares.CheckIfThrowDelayedException();
1412 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1415 safeHandle.RegisterForBlockingSyscall ();
1416 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
1418 safeHandle.UnRegisterForBlockingSyscall ();
1422 /* Connects to the remote address */
1423 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1424 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error);
1427 * - false when it is ok to use RemoteEndPoint
1428 * - true when addresses must be used (and addresses could be null/empty) */
1429 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1433 // Connect to the first address that match the host name, like:
1434 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1435 // while skipping entries that do not match the address family
1436 DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1438 addresses = Dns.GetHostAddresses (dep.Host);
1441 e.ConnectByNameError = null;
1450 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1451 * if the platform is newer than w2k. We should be able to cope... */
1452 public void Disconnect (bool reuseSocket)
1454 ThrowIfDisposedAndClosed ();
1457 Disconnect_internal (safe_handle, reuseSocket, out error);
1461 /* ERROR_NOT_SUPPORTED */
1462 throw new PlatformNotSupportedException ();
1464 throw new SocketException (error);
1468 is_connected = false;
1470 /* Do managed housekeeping here... */
1474 public bool DisconnectAsync (SocketAsyncEventArgs e)
1476 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1478 ThrowIfDisposedAndClosed ();
1481 e.Worker.Init (this, e, SocketOperation.Disconnect);
1483 SocketAsyncResult sockares = e.Worker.result;
1485 socket_pool_queue (SocketAsyncWorker.Dispatcher, sockares);
1491 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1493 ThrowIfDisposedAndClosed ();
1495 SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.Disconnect) {
1496 ReuseSocket = reuseSocket,
1499 socket_pool_queue (SocketAsyncWorker.Dispatcher, sockares);
1504 public void EndDisconnect (IAsyncResult asyncResult)
1506 ThrowIfDisposedAndClosed ();
1508 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1510 if (!sockares.IsCompleted)
1511 sockares.AsyncWaitHandle.WaitOne ();
1513 sockares.CheckIfThrowDelayedException ();
1516 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1518 bool release = false;
1520 safeHandle.DangerousAddRef (ref release);
1521 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1524 safeHandle.DangerousRelease ();
1528 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1529 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1535 public int Receive (byte [] buffer)
1537 return Receive (buffer, SocketFlags.None);
1540 public int Receive (byte [] buffer, SocketFlags flags)
1542 ThrowIfDisposedAndClosed ();
1543 ThrowIfBufferNull (buffer);
1544 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
1547 int ret = Receive_nochecks (buffer, 0, buffer.Length, flags, out error);
1549 if (error != SocketError.Success) {
1550 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1551 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1552 throw new SocketException ((int) error);
1558 public int Receive (byte [] buffer, int size, SocketFlags flags)
1560 ThrowIfDisposedAndClosed ();
1561 ThrowIfBufferNull (buffer);
1562 ThrowIfBufferOutOfRange (buffer, 0, size);
1565 int ret = Receive_nochecks (buffer, 0, size, flags, out error);
1567 if (error != SocketError.Success) {
1568 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1569 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1570 throw new SocketException ((int) error);
1576 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags)
1578 ThrowIfDisposedAndClosed ();
1579 ThrowIfBufferNull (buffer);
1580 ThrowIfBufferOutOfRange (buffer, offset, size);
1583 int ret = Receive_nochecks (buffer, offset, size, flags, out error);
1585 if (error != SocketError.Success) {
1586 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1587 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1588 throw new SocketException ((int) error);
1594 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
1596 ThrowIfDisposedAndClosed ();
1597 ThrowIfBufferNull (buffer);
1598 ThrowIfBufferOutOfRange (buffer, offset, size);
1600 return Receive_nochecks (buffer, offset, size, flags, out error);
1603 public int Receive (IList<ArraySegment<byte>> buffers)
1606 int ret = Receive (buffers, SocketFlags.None, out error);
1608 if (error != SocketError.Success)
1609 throw new SocketException ((int) error);
1614 [CLSCompliant (false)]
1615 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1618 int ret = Receive (buffers, socketFlags, out error);
1620 if (error != SocketError.Success)
1621 throw new SocketException ((int) error);
1626 [CLSCompliant (false)]
1627 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1629 ThrowIfDisposedAndClosed ();
1631 if (buffers == null || buffers.Count == 0)
1632 throw new ArgumentNullException ("buffers");
1634 int numsegments = buffers.Count;
1638 /* Only example I can find of sending a byte array reference directly into an internal
1639 * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1640 * so taking a lead from that... */
1641 WSABUF[] bufarray = new WSABUF[numsegments];
1642 GCHandle[] gch = new GCHandle[numsegments];
1644 for (int i = 0; i < numsegments; i++) {
1645 ArraySegment<byte> segment = buffers[i];
1647 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1648 throw new ArgumentOutOfRangeException ("segment");
1650 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1651 bufarray[i].len = segment.Count;
1652 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1656 ret = Receive_internal (safe_handle, bufarray, socketFlags, out nativeError);
1658 for (int i = 0; i < numsegments; i++) {
1659 if (gch[i].IsAllocated)
1664 errorCode = (SocketError) nativeError;
1669 public bool ReceiveAsync (SocketAsyncEventArgs e)
1671 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1673 ThrowIfDisposedAndClosed ();
1675 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1676 // thrown when e.Buffer and e.BufferList are null (works fine when one is
1677 // set to a valid object)
1678 if (e.Buffer == null && e.BufferList == null)
1679 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1682 e.Worker.Init (this, e, e.Buffer != null ? SocketOperation.Receive : SocketOperation.ReceiveGeneric);
1684 SocketAsyncResult sockares = e.Worker.result;
1685 sockares.SockFlags = e.SocketFlags;
1687 if (e.Buffer != null) {
1688 sockares.Buffer = e.Buffer;
1689 sockares.Offset = e.Offset;
1690 sockares.Size = e.Count;
1692 sockares.Buffers = e.BufferList;
1695 // Receive takes care of ReceiveGeneric
1696 QueueSocketAsyncResult (readQ, e.Worker, sockares);
1701 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
1703 ThrowIfDisposedAndClosed ();
1704 ThrowIfBufferNull (buffer);
1705 ThrowIfBufferOutOfRange (buffer, offset, size);
1707 SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.Receive) {
1711 SockFlags = socket_flags,
1714 QueueSocketAsyncResult (readQ, sockares.Worker, sockares);
1719 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags flags, out SocketError error, AsyncCallback callback, object state)
1721 /* As far as I can tell from the docs and from experimentation, a pointer to the
1722 * SocketError parameter is not supposed to be saved for the async parts. And as we don't
1723 * set any socket errors in the setup code, we just have to set it to Success. */
1724 error = SocketError.Success;
1725 return BeginReceive (buffer, offset, size, flags, callback, state);
1728 [CLSCompliant (false)]
1729 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
1731 ThrowIfDisposedAndClosed ();
1733 if (buffers == null)
1734 throw new ArgumentNullException ("buffers");
1736 SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveGeneric) {
1738 SockFlags = socketFlags,
1741 QueueSocketAsyncResult (readQ, sockares.Worker, sockares);
1746 [CLSCompliant (false)]
1747 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1749 /* I assume the same SocketError semantics as above */
1750 errorCode = SocketError.Success;
1751 return BeginReceive (buffers, socketFlags, callback, state);
1754 public int EndReceive (IAsyncResult result)
1757 int bytesReceived = EndReceive (result, out error);
1759 if (error != SocketError.Success) {
1760 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
1761 is_connected = false;
1762 throw new SocketException ((int)error);
1765 return bytesReceived;
1768 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
1770 ThrowIfDisposedAndClosed ();
1772 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
1774 if (!sockares.IsCompleted)
1775 sockares.AsyncWaitHandle.WaitOne ();
1777 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
1778 // kinds of exceptions that should be thrown.
1779 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
1780 sockares.CheckIfThrowDelayedException();
1782 return sockares.Total;
1785 internal int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
1788 int ret = Receive_internal (safe_handle, buf, offset, size, flags, out nativeError);
1790 error = (SocketError) nativeError;
1791 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
1792 is_connected = false;
1795 is_connected = true;
1801 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
1804 safeHandle.RegisterForBlockingSyscall ();
1805 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
1807 safeHandle.UnRegisterForBlockingSyscall ();
1811 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1812 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
1814 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
1817 safeHandle.RegisterForBlockingSyscall ();
1818 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
1820 safeHandle.UnRegisterForBlockingSyscall ();
1824 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1825 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error);
1831 public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
1833 ThrowIfDisposedAndClosed ();
1834 ThrowIfBufferNull (buffer);
1835 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
1837 if (remoteEP == null)
1838 throw new ArgumentNullException ("remoteEP");
1840 return ReceiveFrom_nochecks (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
1843 public int ReceiveFrom (byte [] buffer, SocketFlags flags, ref EndPoint remoteEP)
1845 ThrowIfDisposedAndClosed ();
1846 ThrowIfBufferNull (buffer);
1847 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
1849 if (remoteEP == null)
1850 throw new ArgumentNullException ("remoteEP");
1852 return ReceiveFrom_nochecks (buffer, 0, buffer.Length, flags, ref remoteEP);
1855 public int ReceiveFrom (byte [] buffer, int size, SocketFlags flags, ref EndPoint remoteEP)
1857 ThrowIfDisposedAndClosed ();
1858 ThrowIfBufferNull (buffer);
1859 ThrowIfBufferOutOfRange (buffer, 0, size);
1861 if (remoteEP == null)
1862 throw new ArgumentNullException ("remoteEP");
1864 return ReceiveFrom_nochecks (buffer, 0, size, flags, ref remoteEP);
1867 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags flags, ref EndPoint remoteEP)
1869 ThrowIfDisposedAndClosed ();
1870 ThrowIfBufferNull (buffer);
1871 ThrowIfBufferOutOfRange (buffer, offset, size);
1873 if (remoteEP == null)
1874 throw new ArgumentNullException ("remoteEP");
1876 return ReceiveFrom_nochecks (buffer, offset, size, flags, ref remoteEP);
1879 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
1881 ThrowIfDisposedAndClosed ();
1883 // We do not support recv into multiple buffers yet
1884 if (e.BufferList != null)
1885 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
1886 if (e.RemoteEndPoint == null)
1887 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
1890 e.Worker.Init (this, e, SocketOperation.ReceiveFrom);
1892 SocketAsyncResult sockares = e.Worker.result;
1893 sockares.Buffer = e.Buffer;
1894 sockares.Offset = e.Offset;
1895 sockares.Size = e.Count;
1896 sockares.EndPoint = e.RemoteEndPoint;
1897 sockares.SockFlags = e.SocketFlags;
1899 QueueSocketAsyncResult (readQ, e.Worker, sockares);
1904 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
1906 ThrowIfDisposedAndClosed ();
1907 ThrowIfBufferNull (buffer);
1908 ThrowIfBufferOutOfRange (buffer, offset, size);
1910 if (remote_end == null)
1911 throw new ArgumentNullException ("remote_end");
1913 SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveFrom) {
1917 SockFlags = socket_flags,
1918 EndPoint = remote_end,
1921 QueueSocketAsyncResult (readQ, sockares.Worker, sockares);
1926 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
1928 ThrowIfDisposedAndClosed ();
1930 if (end_point == null)
1931 throw new ArgumentNullException ("remote_end");
1933 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
1935 if (!sockares.IsCompleted)
1936 sockares.AsyncWaitHandle.WaitOne();
1938 sockares.CheckIfThrowDelayedException();
1940 end_point = sockares.EndPoint;
1942 return sockares.Total;
1945 internal int ReceiveFrom_nochecks (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end)
1948 return ReceiveFrom_nochecks_exc (buf, offset, size, flags, ref remote_end, true, out error);
1951 internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end, bool throwOnError, out int error)
1953 SocketAddress sockaddr = remote_end.Serialize();
1955 int cnt = ReceiveFrom_internal (safe_handle, buf, offset, size, flags, ref sockaddr, out error);
1957 SocketError err = (SocketError) error;
1959 if (err != SocketError.WouldBlock && err != SocketError.InProgress) {
1960 is_connected = false;
1961 } else if (err == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
1963 throw new SocketException ((int) SocketError.TimedOut, TIMEOUT_EXCEPTION_MSG);
1964 error = (int) SocketError.TimedOut;
1969 throw new SocketException (error);
1974 is_connected = true;
1977 /* If sockaddr is null then we're a connection oriented protocol and should ignore the
1978 * remote_end parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
1979 if (sockaddr != null) {
1980 /* Stupidly, EndPoint.Create() is an instance method */
1981 remote_end = remote_end.Create (sockaddr);
1984 seed_endpoint = remote_end;
1989 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error)
1992 safeHandle.RegisterForBlockingSyscall ();
1993 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
1995 safeHandle.UnRegisterForBlockingSyscall ();
1999 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2000 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error);
2004 #region ReceiveMessageFrom
2006 [MonoTODO ("Not implemented")]
2007 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
2009 ThrowIfDisposedAndClosed ();
2010 ThrowIfBufferNull (buffer);
2011 ThrowIfBufferOutOfRange (buffer, offset, size);
2013 if (remoteEP == null)
2014 throw new ArgumentNullException ("remoteEP");
2016 // FIXME: figure out how we get hold of the IPPacketInformation
2017 throw new NotImplementedException ();
2020 [MonoTODO ("Not implemented")]
2021 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
2023 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2025 ThrowIfDisposedAndClosed ();
2027 throw new NotImplementedException ();
2031 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
2033 ThrowIfDisposedAndClosed ();
2034 ThrowIfBufferNull (buffer);
2035 ThrowIfBufferOutOfRange (buffer, offset, size);
2037 if (remoteEP == null)
2038 throw new ArgumentNullException ("remoteEP");
2040 throw new NotImplementedException ();
2044 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
2046 ThrowIfDisposedAndClosed ();
2048 if (endPoint == null)
2049 throw new ArgumentNullException ("endPoint");
2051 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
2053 throw new NotImplementedException ();
2060 public int Send (byte [] buffer)
2062 ThrowIfDisposedAndClosed ();
2063 ThrowIfBufferNull (buffer);
2064 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2067 int ret = Send_nochecks (buffer, 0, buffer.Length, SocketFlags.None, out error);
2069 if (error != SocketError.Success)
2070 throw new SocketException ((int) error);
2075 public int Send (byte [] buffer, SocketFlags flags)
2077 ThrowIfDisposedAndClosed ();
2078 ThrowIfBufferNull (buffer);
2079 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2082 int ret = Send_nochecks (buffer, 0, buffer.Length, flags, out error);
2084 if (error != SocketError.Success)
2085 throw new SocketException ((int) error);
2090 public int Send (byte [] buffer, int size, SocketFlags flags)
2092 ThrowIfDisposedAndClosed ();
2093 ThrowIfBufferNull (buffer);
2094 ThrowIfBufferOutOfRange (buffer, 0, size);
2097 int ret = Send_nochecks (buffer, 0, size, flags, out error);
2099 if (error != SocketError.Success)
2100 throw new SocketException ((int) error);
2105 public int Send (byte [] buffer, int offset, int size, SocketFlags flags)
2107 ThrowIfDisposedAndClosed ();
2108 ThrowIfBufferNull (buffer);
2109 ThrowIfBufferOutOfRange (buffer, offset, size);
2112 int ret = Send_nochecks (buffer, offset, size, flags, out error);
2114 if (error != SocketError.Success)
2115 throw new SocketException ((int) error);
2120 public int Send (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
2122 ThrowIfDisposedAndClosed ();
2123 ThrowIfBufferNull (buffer);
2124 ThrowIfBufferOutOfRange (buffer, offset, size);
2126 return Send_nochecks (buffer, offset, size, flags, out error);
2130 int Send (IList<ArraySegment<byte>> buffers)
2133 int ret = Send (buffers, SocketFlags.None, out error);
2135 if (error != SocketError.Success)
2136 throw new SocketException ((int) error);
2142 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
2145 int ret = Send (buffers, socketFlags, out error);
2147 if (error != SocketError.Success)
2148 throw new SocketException ((int) error);
2153 [CLSCompliant (false)]
2154 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
2156 ThrowIfDisposedAndClosed ();
2158 if (buffers == null)
2159 throw new ArgumentNullException ("buffers");
2160 if (buffers.Count == 0)
2161 throw new ArgumentException ("Buffer is empty", "buffers");
2163 int numsegments = buffers.Count;
2167 WSABUF[] bufarray = new WSABUF[numsegments];
2168 GCHandle[] gch = new GCHandle[numsegments];
2170 for(int i = 0; i < numsegments; i++) {
2171 ArraySegment<byte> segment = buffers[i];
2173 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
2174 throw new ArgumentOutOfRangeException ("segment");
2176 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
2177 bufarray[i].len = segment.Count;
2178 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
2182 ret = Send_internal (safe_handle, bufarray, socketFlags, out nativeError);
2184 for(int i = 0; i < numsegments; i++) {
2185 if (gch[i].IsAllocated) {
2191 errorCode = (SocketError)nativeError;
2196 internal int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2199 error = SocketError.Success;
2204 int ret = Send_internal (safe_handle, buf, offset, size, flags, out nativeError);
2206 error = (SocketError)nativeError;
2208 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2209 is_connected = false;
2212 is_connected = true;
2218 public bool SendAsync (SocketAsyncEventArgs e)
2220 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2222 ThrowIfDisposedAndClosed ();
2224 if (e.Buffer == null && e.BufferList == null)
2225 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
2228 e.Worker.Init (this, e, e.Buffer != null ? SocketOperation.Send : SocketOperation.SendGeneric);
2230 SocketAsyncResult sockares = e.Worker.result;
2231 sockares.SockFlags = e.SocketFlags;
2233 if (e.Buffer != null) {
2234 sockares.Buffer = e.Buffer;
2235 sockares.Offset = e.Offset;
2236 sockares.Size = e.Count;
2238 sockares.Buffers = e.BufferList;
2241 // Send takes care of SendGeneric
2242 QueueSocketAsyncResult (writeQ, e.Worker, sockares);
2247 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2249 if (!is_connected) {
2250 errorCode = SocketError.NotConnected;
2251 throw new SocketException ((int) errorCode);
2254 errorCode = SocketError.Success;
2255 return BeginSend (buffer, offset, size, socketFlags, callback, state);
2258 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
2260 ThrowIfDisposedAndClosed ();
2261 ThrowIfBufferNull (buffer);
2262 ThrowIfBufferOutOfRange (buffer, offset, size);
2265 throw new SocketException ((int)SocketError.NotConnected);
2267 SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.Send) {
2271 SockFlags = socket_flags,
2274 QueueSocketAsyncResult (writeQ, sockares.Worker, sockares);
2279 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
2281 ThrowIfDisposedAndClosed ();
2283 if (buffers == null)
2284 throw new ArgumentNullException ("buffers");
2286 throw new SocketException ((int)SocketError.NotConnected);
2288 SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.SendGeneric) {
2290 SockFlags = socketFlags,
2293 QueueSocketAsyncResult (writeQ, sockares.Worker, sockares);
2298 [CLSCompliant (false)]
2299 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2301 if (!is_connected) {
2302 errorCode = SocketError.NotConnected;
2303 throw new SocketException ((int)errorCode);
2306 errorCode = SocketError.Success;
2307 return BeginSend (buffers, socketFlags, callback, state);
2310 public int EndSend (IAsyncResult result)
2313 int bytesSent = EndSend (result, out error);
2315 if (error != SocketError.Success) {
2316 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2317 is_connected = false;
2318 throw new SocketException ((int)error);
2324 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
2326 ThrowIfDisposedAndClosed ();
2328 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
2330 if (!sockares.IsCompleted)
2331 sockares.AsyncWaitHandle.WaitOne ();
2333 /* If no socket error occurred, call CheckIfThrowDelayedException in
2334 * case there are other kinds of exceptions that should be thrown.*/
2335 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2336 sockares.CheckIfThrowDelayedException ();
2338 return sockares.Total;
2341 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2343 bool release = false;
2345 safeHandle.DangerousAddRef (ref release);
2346 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2349 safeHandle.DangerousRelease ();
2353 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2354 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2356 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
2359 safeHandle.RegisterForBlockingSyscall ();
2360 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
2362 safeHandle.UnRegisterForBlockingSyscall ();
2366 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2367 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
2373 public int SendTo (byte [] buffer, EndPoint remote_end)
2375 ThrowIfDisposedAndClosed ();
2376 ThrowIfBufferNull (buffer);
2377 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2379 if (remote_end == null)
2380 throw new ArgumentNullException ("remote_end");
2382 return SendTo_nochecks (buffer, 0, buffer.Length, SocketFlags.None, remote_end);
2385 public int SendTo (byte [] buffer, SocketFlags flags, EndPoint remote_end)
2387 ThrowIfDisposedAndClosed ();
2388 ThrowIfBufferNull (buffer);
2389 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2391 if (remote_end == null)
2392 throw new ArgumentNullException ("remote_end");
2394 return SendTo_nochecks (buffer, 0, buffer.Length, flags, remote_end);
2397 public int SendTo (byte [] buffer, int size, SocketFlags flags, EndPoint remote_end)
2399 ThrowIfDisposedAndClosed ();
2400 ThrowIfBufferNull (buffer);
2401 ThrowIfBufferOutOfRange (buffer, 0, size);
2403 if (remote_end == null)
2404 throw new ArgumentNullException ("remote_end");
2406 return SendTo_nochecks (buffer, 0, size, flags, remote_end);
2409 public int SendTo (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2411 ThrowIfDisposedAndClosed ();
2412 ThrowIfBufferNull (buffer);
2413 ThrowIfBufferOutOfRange (buffer, offset, size);
2415 if (remote_end == null)
2416 throw new ArgumentNullException("remote_end");
2418 return SendTo_nochecks (buffer, offset, size, flags, remote_end);
2421 internal int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2424 int ret = SendTo_internal (safe_handle, buffer, offset, size, flags, remote_end.Serialize (), out error);
2426 SocketError err = (SocketError) error;
2428 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2429 is_connected = false;
2430 throw new SocketException (error);
2433 is_connected = true;
2435 seed_endpoint = remote_end;
2440 public bool SendToAsync (SocketAsyncEventArgs e)
2442 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2444 ThrowIfDisposedAndClosed ();
2446 if (e.BufferList != null)
2447 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2448 if (e.RemoteEndPoint == null)
2449 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2452 e.Worker.Init (this, e, SocketOperation.SendTo);
2454 SocketAsyncResult sockares = e.Worker.result;
2455 sockares.Buffer = e.Buffer;
2456 sockares.Offset = e.Offset;
2457 sockares.Size = e.Count;
2458 sockares.SockFlags = e.SocketFlags;
2459 sockares.EndPoint = e.RemoteEndPoint;
2461 QueueSocketAsyncResult (writeQ, e.Worker, sockares);
2467 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2469 ThrowIfDisposedAndClosed ();
2470 ThrowIfBufferNull (buffer);
2471 ThrowIfBufferOutOfRange (buffer, offset, size);
2473 SocketAsyncResult sockares = new SocketAsyncResult (this, state, callback, SocketOperation.SendTo) {
2477 SockFlags = socket_flags,
2478 EndPoint = remote_end,
2481 QueueSocketAsyncResult (writeQ, sockares.Worker, sockares);
2486 public int EndSendTo (IAsyncResult result)
2488 ThrowIfDisposedAndClosed ();
2490 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2492 if (!sockares.IsCompleted)
2493 sockares.AsyncWaitHandle.WaitOne();
2495 sockares.CheckIfThrowDelayedException();
2497 return sockares.Total;
2500 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
2503 safeHandle.RegisterForBlockingSyscall ();
2504 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
2506 safeHandle.UnRegisterForBlockingSyscall ();
2510 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2511 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
2517 public void SendFile (string fileName)
2519 ThrowIfDisposedAndClosed ();
2522 throw new NotSupportedException ();
2524 throw new InvalidOperationException ();
2526 SendFile (fileName, null, null, 0);
2529 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2531 ThrowIfDisposedAndClosed ();
2534 throw new NotSupportedException ();
2536 throw new InvalidOperationException ();
2538 if (!SendFile_internal (safe_handle, fileName, preBuffer, postBuffer, flags)) {
2539 SocketException exc = new SocketException ();
2540 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2541 throw new FileNotFoundException ();
2546 public IAsyncResult BeginSendFile (string fileName, AsyncCallback callback, object state)
2548 ThrowIfDisposedAndClosed ();
2551 throw new NotSupportedException ();
2552 if (!File.Exists (fileName))
2553 throw new FileNotFoundException ();
2555 return BeginSendFile (fileName, null, null, 0, callback, state);
2558 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2560 ThrowIfDisposedAndClosed ();
2563 throw new NotSupportedException ();
2564 if (!File.Exists (fileName))
2565 throw new FileNotFoundException ();
2567 SendFileHandler handler = new SendFileHandler (SendFile);
2569 return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2572 public void EndSendFile (IAsyncResult asyncResult)
2574 ThrowIfDisposedAndClosed ();
2576 if (asyncResult == null)
2577 throw new ArgumentNullException ("asyncResult");
2579 SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2581 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2583 ares.Delegate.EndInvoke (ares.Original);
2586 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
2589 safeHandle.RegisterForBlockingSyscall ();
2590 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
2592 safeHandle.UnRegisterForBlockingSyscall ();
2596 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2597 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
2599 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2601 sealed class SendFileAsyncResult : IAsyncResult {
2605 public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2611 public object AsyncState {
2612 get { return ares.AsyncState; }
2615 public WaitHandle AsyncWaitHandle {
2616 get { return ares.AsyncWaitHandle; }
2619 public bool CompletedSynchronously {
2620 get { return ares.CompletedSynchronously; }
2623 public bool IsCompleted {
2624 get { return ares.IsCompleted; }
2627 public SendFileHandler Delegate {
2631 public IAsyncResult Original {
2632 get { return ares; }
2640 [MonoTODO ("Not implemented")]
2641 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2643 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2645 ThrowIfDisposedAndClosed ();
2647 throw new NotImplementedException ();
2652 #region DuplicateAndClose
2655 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2656 public SocketInformation DuplicateAndClose (int targetProcessId)
2658 var si = new SocketInformation ();
2660 (is_listening ? SocketInformationOptions.Listening : 0) |
2661 (is_connected ? SocketInformationOptions.Connected : 0) |
2662 (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
2663 (use_overlapped_io ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
2665 si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, is_bound ? 1 : 0, (long)Handle);
2674 #region GetSocketOption
2676 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2678 ThrowIfDisposedAndClosed ();
2680 if (optionValue == null)
2681 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2684 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref optionValue, out error);
2687 throw new SocketException (error);
2690 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int length)
2692 ThrowIfDisposedAndClosed ();
2695 byte[] byte_val = new byte [length];
2696 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref byte_val, out error);
2699 throw new SocketException (error);
2704 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
2706 ThrowIfDisposedAndClosed ();
2710 GetSocketOption_obj_internal (safe_handle, optionLevel, optionName, out obj_val, out error);
2713 throw new SocketException (error);
2715 if (optionName == SocketOptionName.Linger)
2716 return (LingerOption) obj_val;
2717 else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
2718 return (MulticastOption) obj_val;
2719 else if (obj_val is int)
2720 return (int) obj_val;
2725 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
2727 bool release = false;
2729 safeHandle.DangerousAddRef (ref release);
2730 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
2733 safeHandle.DangerousRelease ();
2737 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2738 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
2740 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
2742 bool release = false;
2744 safeHandle.DangerousAddRef (ref release);
2745 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
2748 safeHandle.DangerousRelease ();
2752 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2753 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
2757 #region SetSocketOption
2759 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2761 ThrowIfDisposedAndClosed ();
2763 // I'd throw an ArgumentNullException, but this is what MS does.
2764 if (optionValue == null)
2765 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2768 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, optionValue, 0, out error);
2771 if (error == (int) SocketError.InvalidArgument)
2772 throw new ArgumentException ();
2773 throw new SocketException (error);
2777 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
2779 ThrowIfDisposedAndClosed ();
2781 // NOTE: if a null is passed, the byte[] overload is used instead...
2782 if (optionValue == null)
2783 throw new ArgumentNullException("optionValue");
2787 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
2788 LingerOption linger = optionValue as LingerOption;
2790 throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
2791 SetSocketOption_internal (safe_handle, optionLevel, optionName, linger, null, 0, out error);
2792 } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2793 MulticastOption multicast = optionValue as MulticastOption;
2794 if (multicast == null)
2795 throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
2796 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
2797 } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2798 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
2799 if (multicast == null)
2800 throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
2801 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
2803 throw new ArgumentException ("Invalid value specified.", "optionValue");
2807 if (error == (int) SocketError.InvalidArgument)
2808 throw new ArgumentException ();
2809 throw new SocketException (error);
2813 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
2815 ThrowIfDisposedAndClosed ();
2818 int int_val = optionValue ? 1 : 0;
2819 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, int_val, out error);
2822 if (error == (int) SocketError.InvalidArgument)
2823 throw new ArgumentException ();
2824 throw new SocketException (error);
2828 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
2830 ThrowIfDisposedAndClosed ();
2833 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, optionValue, out error);
2836 throw new SocketException (error);
2840 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
2842 bool release = false;
2844 safeHandle.DangerousAddRef (ref release);
2845 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
2848 safeHandle.DangerousRelease ();
2852 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2853 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
2859 public int IOControl (int ioctl_code, byte [] in_value, byte [] out_value)
2862 throw new ObjectDisposedException (GetType ().ToString ());
2865 int result = IOControl_internal (safe_handle, ioctl_code, in_value, out_value, out error);
2868 throw new SocketException (error);
2870 throw new InvalidOperationException ("Must use Blocking property instead.");
2875 public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
2877 return IOControl ((int) ioControlCode, optionInValue, optionOutValue);
2880 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
2882 bool release = false;
2884 safeHandle.DangerousAddRef (ref release);
2885 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
2888 safeHandle.DangerousRelease ();
2892 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
2893 * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
2894 * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
2895 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2896 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
2902 public void Close ()
2908 public void Close (int timeout)
2910 linger_timeout = timeout;
2914 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2915 internal extern static void Close_internal (IntPtr socket, out int error);
2921 public void Shutdown (SocketShutdown how)
2923 ThrowIfDisposedAndClosed ();
2926 throw new SocketException (10057); // Not connected
2929 Shutdown_internal (safe_handle, how, out error);
2932 throw new SocketException (error);
2935 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
2937 bool release = false;
2939 safeHandle.DangerousAddRef (ref release);
2940 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
2943 safeHandle.DangerousRelease ();
2947 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2948 extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
2954 protected virtual void Dispose (bool disposing)
2960 bool was_connected = is_connected;
2961 is_connected = false;
2963 if (safe_handle != null) {
2970 safe_handle.Dispose ();
2974 public void Dispose ()
2977 GC.SuppressFinalize (this);
2980 void Linger (IntPtr handle)
2982 if (!is_connected || linger_timeout <= 0)
2985 /* We don't want to receive any more data */
2987 Shutdown_internal (handle, SocketShutdown.Receive, out error);
2992 int seconds = linger_timeout / 1000;
2993 int ms = linger_timeout % 1000;
2995 /* If the other end closes, this will return 'true' with 'Available' == 0 */
2996 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
3002 LingerOption linger = new LingerOption (true, seconds);
3003 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
3004 /* Not needed, we're closing upon return */
3012 void ThrowIfDisposedAndClosed (Socket socket)
3014 if (socket.is_disposed && socket.is_closed)
3015 throw new ObjectDisposedException (socket.GetType ().ToString ());
3018 void ThrowIfDisposedAndClosed ()
3020 if (is_disposed && is_closed)
3021 throw new ObjectDisposedException (GetType ().ToString ());
3024 void ThrowIfBufferNull (byte[] buffer)
3027 throw new ArgumentNullException ("buffer");
3030 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
3033 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
3034 if (offset > buffer.Length)
3035 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
3037 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
3038 if (size > buffer.Length - offset)
3039 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
3044 #if !NET_2_1 || MOBILE
3045 if (protocol_type == ProtocolType.Udp)
3046 throw new SocketException ((int)SocketError.ProtocolOption);
3050 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
3053 throw new ArgumentNullException (argName);
3055 SocketAsyncResult sockares = ares as SocketAsyncResult;
3056 if (sockares == null)
3057 throw new ArgumentException ("Invalid IAsyncResult", argName);
3058 if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
3059 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
3064 void QueueSocketAsyncResult (Queue<SocketAsyncWorker> queue, SocketAsyncWorker worker, SocketAsyncResult sockares)
3068 queue.Enqueue (worker);
3069 count = queue.Count;
3073 socket_pool_queue (SocketAsyncWorker.Dispatcher, sockares);
3076 [StructLayout (LayoutKind.Sequential)]
3082 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3083 internal static extern void cancel_blocking_socket_operation (Thread thread);
3085 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3086 internal static extern void socket_pool_queue (SocketAsyncCallback d, SocketAsyncResult r);