1 // System.Net.Sockets.Socket.cs
4 // Phillip Pearson (pp@myelin.co.nz)
5 // Dick Porter <dick@ximian.com>
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // Sridhar Kulkarni (sridharkulkarni@gmail.com)
8 // Brian Nickel (brian.nickel@gmail.com)
9 // Ludovic Henry (ludovic@xamarin.com)
11 // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
12 // http://www.myelin.co.nz
13 // (c) 2004-2011 Novell, Inc. (http://www.novell.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 using System.Collections;
39 using System.Collections.Generic;
40 using System.Runtime.CompilerServices;
41 using System.Runtime.InteropServices;
42 using System.Threading;
43 using System.Reflection;
45 using System.Net.Configuration;
48 using System.Net.NetworkInformation;
50 namespace System.Net.Sockets
52 public partial class Socket : IDisposable
54 const int SOCKET_CLOSED_CODE = 10004;
55 const string TIMEOUT_EXCEPTION_MSG = "A connection attempt failed because the connected party did not properly respond" +
56 "after a period of time, or established connection failed because connected host has failed to respond";
59 * These two fields are looked up by name by the runtime, don't change
60 * their name without also updating the runtime code.
62 static int ipv4_supported = -1;
63 static int ipv6_supported = -1;
65 /* true if we called Close_internal */
69 bool use_overlapped_io;
73 AddressFamily address_family;
74 SocketType socket_type;
75 ProtocolType protocol_type;
77 /* the field "safe_handle" is looked up by name by the runtime */
78 internal SafeSocketHandle safe_handle;
81 * This EndPoint is used when creating new endpoints. Because
82 * there are many types of EndPoints possible,
83 * seed_endpoint.Create(addr) is used for creating new ones.
84 * As such, this value is set on Bind, SentTo, ReceiveFrom,
87 internal EndPoint seed_endpoint = null;
89 internal Queue<KeyValuePair<IntPtr, IOSelectorJob>> readQ = new Queue<KeyValuePair<IntPtr, IOSelectorJob>> (2);
90 internal Queue<KeyValuePair<IntPtr, IOSelectorJob>> writeQ = new Queue<KeyValuePair<IntPtr, IOSelectorJob>> (2);
92 internal bool is_blocking = true;
93 internal bool is_bound;
95 /* When true, the socket was connected at the time of the last IO operation */
96 internal bool is_connected;
98 internal bool is_disposed;
99 internal bool connect_in_progress;
105 if (ipv4_supported == -1) {
107 Socket tmp = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
116 if (ipv6_supported == -1) {
117 // We need to put a try/catch around ConfigurationManager methods as will always throw an exception
118 // when run in a mono embedded application. This occurs as embedded applications do not have a setup
119 // for application config. The exception is not thrown when called from a normal .NET application.
121 // We, then, need to guard calls to the ConfigurationManager. If the config is not found or throws an
122 // exception, will fall through to the existing Socket / API directly below in the code.
124 // Also note that catching ConfigurationErrorsException specifically would require library dependency
125 // System.Configuration, and wanted to avoid that.
127 #if CONFIGURATION_DEP
129 SettingsSection config;
130 config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
132 ipv6_supported = config.Ipv6.Enabled ? -1 : 0;
138 NetConfig config = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig;
140 ipv6_supported = config.ipv6Enabled ? -1 : 0;
146 if (ipv6_supported != 0) {
148 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
160 // This constructor is used by servers that want to listen for instance on both
161 // ipv4 and ipv6. Mono has historically done that if you use InterNetworkV6 (at
162 // least on Unix), because that is the default behavior unless the IPV6_V6ONLY
163 // option is explicitly set by using setsockopt (sock, IPPROTO_IPV6, IPV6_ONLY)
165 public Socket (SocketType socketType, ProtocolType protocolType)
166 : this (AddressFamily.InterNetworkV6, socketType, protocolType)
171 public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
173 this.address_family = addressFamily;
174 this.socket_type = socketType;
175 this.protocol_type = protocolType;
178 this.safe_handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
181 throw new SocketException (error);
187 public Socket (SocketInformation socketInformation)
189 this.is_listening = (socketInformation.Options & SocketInformationOptions.Listening) != 0;
190 this.is_connected = (socketInformation.Options & SocketInformationOptions.Connected) != 0;
191 this.is_blocking = (socketInformation.Options & SocketInformationOptions.NonBlocking) == 0;
192 this.use_overlapped_io = (socketInformation.Options & SocketInformationOptions.UseOnlyOverlappedIO) != 0;
194 var result = Mono.DataConverter.Unpack ("iiiil", socketInformation.ProtocolInformation, 0);
196 this.address_family = (AddressFamily) (int) result [0];
197 this.socket_type = (SocketType) (int) result [1];
198 this.protocol_type = (ProtocolType) (int) result [2];
199 this.is_bound = (ProtocolType) (int) result [3] != 0;
200 this.safe_handle = new SafeSocketHandle ((IntPtr) (long) result [4], true);
206 /* private constructor used by Accept, which already has a socket handle to use */
207 internal Socket(AddressFamily family, SocketType type, ProtocolType proto, SafeSocketHandle safe_handle)
209 this.address_family = family;
210 this.socket_type = type;
211 this.protocol_type = proto;
213 this.safe_handle = safe_handle;
214 this.is_connected = true;
222 void SocketDefaults ()
225 /* Need to test IPv6 further */
226 if (address_family == AddressFamily.InterNetwork
227 // || address_family == AddressFamily.InterNetworkV6
229 /* This is the default, but it probably has nasty side
230 * effects on Linux, as the socket option is kludged by
231 * turning on or off PMTU discovery... */
232 this.DontFragment = false;
233 this.NoDelay = false;
234 } else if (address_family == AddressFamily.InterNetworkV6) {
235 this.DualMode = true;
238 /* Microsoft sets these to 8192, but we are going to keep them
239 * both to the OS defaults as these have a big performance impact.
240 * on WebClient performance. */
241 // this.ReceiveBufferSize = 8192;
242 // this.SendBufferSize = 8192;
243 } catch (SocketException) {
247 /* Creates a new system socket, returning the handle */
248 [MethodImplAttribute(MethodImplOptions.InternalCall)]
249 extern IntPtr Socket_internal (AddressFamily family, SocketType type, ProtocolType proto, out int error);
255 [ObsoleteAttribute ("Use OSSupportsIPv4 instead")]
256 public static bool SupportsIPv4 {
257 get { return ipv4_supported == 1; }
260 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
261 public static bool SupportsIPv6 {
262 get { return ipv6_supported == 1; }
266 public static bool OSSupportsIPv4 {
267 get { return ipv4_supported == 1; }
270 public static bool OSSupportsIPv4 {
272 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
274 foreach (NetworkInterface adapter in nics) {
275 if (adapter.Supports (NetworkInterfaceComponent.IPv4))
285 public static bool OSSupportsIPv6 {
286 get { return ipv6_supported == 1; }
289 public static bool OSSupportsIPv6 {
291 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
293 foreach (NetworkInterface adapter in nics) {
294 if (adapter.Supports (NetworkInterfaceComponent.IPv6))
303 public int Available {
305 ThrowIfDisposedAndClosed ();
308 ret = Available_internal (safe_handle, out error);
311 throw new SocketException (error);
317 static int Available_internal (SafeSocketHandle safeHandle, out int error)
319 bool release = false;
321 safeHandle.DangerousAddRef (ref release);
322 return Available_internal (safeHandle.DangerousGetHandle (), out error);
325 safeHandle.DangerousRelease ();
329 /* Returns the amount of data waiting to be read on socket */
330 [MethodImplAttribute(MethodImplOptions.InternalCall)]
331 extern static int Available_internal (IntPtr socket, out int error);
333 public bool DontFragment {
335 ThrowIfDisposedAndClosed ();
337 switch (address_family) {
338 case AddressFamily.InterNetwork:
339 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment)) != 0;
340 case AddressFamily.InterNetworkV6:
341 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment)) != 0;
343 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
347 ThrowIfDisposedAndClosed ();
349 switch (address_family) {
350 case AddressFamily.InterNetwork:
351 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
353 case AddressFamily.InterNetworkV6:
354 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment, value ? 1 : 0);
357 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
362 public bool EnableBroadcast {
364 ThrowIfDisposedAndClosed ();
366 if (protocol_type != ProtocolType.Udp)
367 throw new SocketException ((int) SocketError.ProtocolOption);
369 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0;
372 ThrowIfDisposedAndClosed ();
374 if (protocol_type != ProtocolType.Udp)
375 throw new SocketException ((int) SocketError.ProtocolOption);
377 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
381 public bool ExclusiveAddressUse {
383 ThrowIfDisposedAndClosed ();
385 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse)) != 0;
388 ThrowIfDisposedAndClosed ();
391 throw new InvalidOperationException ("Bind has already been called for this socket");
393 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
397 public bool IsBound {
403 public LingerOption LingerState {
405 ThrowIfDisposedAndClosed ();
407 return (LingerOption) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger);
410 ThrowIfDisposedAndClosed ();
411 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger, value);
415 public bool MulticastLoopback {
417 ThrowIfDisposedAndClosed ();
419 /* Even though this option can be set for TCP sockets on Linux, throw
420 * this exception anyway to be compatible (the MSDN docs say
421 * "Setting this property on a Transmission Control Protocol (TCP)
422 * socket will have no effect." but the MS runtime throws the
424 if (protocol_type == ProtocolType.Tcp)
425 throw new SocketException ((int)SocketError.ProtocolOption);
427 switch (address_family) {
428 case AddressFamily.InterNetwork:
429 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
430 case AddressFamily.InterNetworkV6:
431 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
433 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
437 ThrowIfDisposedAndClosed ();
439 /* Even though this option can be set for TCP sockets on Linux, throw
440 * this exception anyway to be compatible (the MSDN docs say
441 * "Setting this property on a Transmission Control Protocol (TCP)
442 * socket will have no effect." but the MS runtime throws the
444 if (protocol_type == ProtocolType.Tcp)
445 throw new SocketException ((int)SocketError.ProtocolOption);
447 switch (address_family) {
448 case AddressFamily.InterNetwork:
449 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
451 case AddressFamily.InterNetworkV6:
452 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
455 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
460 public bool DualMode {
462 if (AddressFamily != AddressFamily.InterNetworkV6)
463 throw new NotSupportedException("This protocol version is not supported");
465 return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only) == 0);
468 if (AddressFamily != AddressFamily.InterNetworkV6)
469 throw new NotSupportedException("This protocol version is not supported");
471 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1);
475 private bool IsDualMode {
477 return AddressFamily == AddressFamily.InterNetworkV6 && DualMode;
481 [MonoTODO ("This doesn't do anything on Mono yet")]
482 public bool UseOnlyOverlappedIO {
483 get { return use_overlapped_io; }
484 set { use_overlapped_io = value; }
487 public IntPtr Handle {
488 get { return safe_handle.DangerousGetHandle (); }
491 // Wish: support non-IP endpoints.
492 public EndPoint LocalEndPoint {
494 ThrowIfDisposedAndClosed ();
496 /* If the seed EndPoint is null, Connect, Bind, etc has not yet
497 * been called. MS returns null in this case. */
498 if (seed_endpoint == null)
502 SocketAddress sa = LocalEndPoint_internal (safe_handle, (int) address_family, out error);
505 throw new SocketException (error);
507 return seed_endpoint.Create (sa);
511 static SocketAddress LocalEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
513 bool release = false;
515 safeHandle.DangerousAddRef (ref release);
516 return LocalEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
519 safeHandle.DangerousRelease ();
523 /* Returns the local endpoint details in addr and port */
524 [MethodImplAttribute(MethodImplOptions.InternalCall)]
525 extern static SocketAddress LocalEndPoint_internal (IntPtr socket, int family, out int error);
527 public SocketType SocketType {
528 get { return socket_type; }
531 public int SendTimeout {
533 ThrowIfDisposedAndClosed ();
535 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
538 ThrowIfDisposedAndClosed ();
541 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
543 /* According to the MSDN docs we should adjust values between 1 and
544 * 499 to 500, but the MS runtime doesn't do this. */
548 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
552 public int ReceiveTimeout {
554 ThrowIfDisposedAndClosed ();
556 return (int) GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
559 ThrowIfDisposedAndClosed ();
562 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
567 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, value);
571 public AddressFamily AddressFamily {
572 get { return address_family; }
575 public bool Blocking {
576 get { return is_blocking; }
578 ThrowIfDisposedAndClosed ();
581 Blocking_internal (safe_handle, value, out error);
584 throw new SocketException (error);
590 static void Blocking_internal (SafeSocketHandle safeHandle, bool block, out int error)
592 bool release = false;
594 safeHandle.DangerousAddRef (ref release);
595 Blocking_internal (safeHandle.DangerousGetHandle (), block, out error);
598 safeHandle.DangerousRelease ();
602 [MethodImplAttribute(MethodImplOptions.InternalCall)]
603 internal extern static void Blocking_internal(IntPtr socket, bool block, out int error);
605 public bool Connected {
606 get { return is_connected; }
607 internal set { is_connected = value; }
610 public ProtocolType ProtocolType {
611 get { return protocol_type; }
614 public bool NoDelay {
616 ThrowIfDisposedAndClosed ();
619 return ((int) GetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay)) != 0;
623 ThrowIfDisposedAndClosed ();
626 SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
630 public int ReceiveBufferSize {
632 ThrowIfDisposedAndClosed ();
634 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer);
637 ThrowIfDisposedAndClosed ();
640 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
642 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
646 public int SendBufferSize {
648 ThrowIfDisposedAndClosed ();
650 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer);
653 ThrowIfDisposedAndClosed ();
656 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
658 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer, value);
664 ThrowIfDisposedAndClosed ();
666 switch (address_family) {
667 case AddressFamily.InterNetwork:
668 return (short) (int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
669 case AddressFamily.InterNetworkV6:
670 return (short) (int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit);
672 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
676 ThrowIfDisposedAndClosed ();
678 if (value < 0 || value > 255)
679 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero or greater than 255.");
681 switch (address_family) {
682 case AddressFamily.InterNetwork:
683 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
685 case AddressFamily.InterNetworkV6:
686 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
689 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
694 public EndPoint RemoteEndPoint {
696 ThrowIfDisposedAndClosed ();
698 /* If the seed EndPoint is null, Connect, Bind, etc has
699 * not yet been called. MS returns null in this case. */
700 if (!is_connected || seed_endpoint == null)
704 SocketAddress sa = RemoteEndPoint_internal (safe_handle, (int) address_family, out error);
707 throw new SocketException (error);
709 return seed_endpoint.Create (sa);
713 static SocketAddress RemoteEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
715 bool release = false;
717 safeHandle.DangerousAddRef (ref release);
718 return RemoteEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
721 safeHandle.DangerousRelease ();
725 /* Returns the remote endpoint details in addr and port */
726 [MethodImplAttribute(MethodImplOptions.InternalCall)]
727 extern static SocketAddress RemoteEndPoint_internal (IntPtr socket, int family, out int error);
733 public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
735 var list = new List<Socket> ();
736 AddSockets (list, checkRead, "checkRead");
737 AddSockets (list, checkWrite, "checkWrite");
738 AddSockets (list, checkError, "checkError");
741 throw new ArgumentNullException ("checkRead, checkWrite, checkError", "All the lists are null or empty.");
743 /* The 'sockets' array contains:
744 * - READ socket 0-n, null,
745 * - WRITE socket 0-n, null,
746 * - ERROR socket 0-n, null */
747 Socket [] sockets = list.ToArray ();
750 Select_internal (ref sockets, microSeconds, out error);
753 throw new SocketException (error);
755 if (sockets == null) {
756 if (checkRead != null)
758 if (checkWrite != null)
760 if (checkError != null)
766 int count = sockets.Length;
767 IList currentList = checkRead;
769 for (int i = 0; i < count; i++) {
770 Socket sock = sockets [i];
771 if (sock == null) { // separator
772 if (currentList != null) {
773 // Remove non-signaled sockets after the current one
774 int to_remove = currentList.Count - currentIdx;
775 for (int k = 0; k < to_remove; k++)
776 currentList.RemoveAt (currentIdx);
778 currentList = (mode == 0) ? checkWrite : checkError;
784 if (mode == 1 && currentList == checkWrite && !sock.is_connected) {
785 if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
786 sock.is_connected = true;
789 /* Remove non-signaled sockets before the current one */
790 while (((Socket) currentList [currentIdx]) != sock)
791 currentList.RemoveAt (currentIdx);
797 static void AddSockets (List<Socket> sockets, IList list, string name)
800 foreach (Socket sock in list) {
801 if (sock == null) // MS throws a NullRef
802 throw new ArgumentNullException ("name", "Contains a null element");
810 [MethodImplAttribute(MethodImplOptions.InternalCall)]
811 extern static void Select_internal (ref Socket [] sockets, int microSeconds, out int error);
817 public bool Poll (int microSeconds, SelectMode mode)
819 ThrowIfDisposedAndClosed ();
821 if (mode != SelectMode.SelectRead && mode != SelectMode.SelectWrite && mode != SelectMode.SelectError)
822 throw new NotSupportedException ("'mode' parameter is not valid.");
825 bool result = Poll_internal (safe_handle, mode, microSeconds, out error);
828 throw new SocketException (error);
830 if (mode == SelectMode.SelectWrite && result && !is_connected) {
831 /* Update the is_connected state; for non-blocking Connect()
832 * this is when we can find out that the connect succeeded. */
833 if ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
840 static bool Poll_internal (SafeSocketHandle safeHandle, SelectMode mode, int timeout, out int error)
842 bool release = false;
844 safeHandle.DangerousAddRef (ref release);
845 return Poll_internal (safeHandle.DangerousGetHandle (), mode, timeout, out error);
848 safeHandle.DangerousRelease ();
852 [MethodImplAttribute(MethodImplOptions.InternalCall)]
853 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
859 public Socket Accept()
861 ThrowIfDisposedAndClosed ();
864 SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
868 error = SOCKET_CLOSED_CODE;
869 throw new SocketException(error);
872 Socket accepted = new Socket (this.AddressFamily, this.SocketType, this.ProtocolType, safe_handle) {
873 seed_endpoint = this.seed_endpoint,
874 Blocking = this.Blocking,
880 internal void Accept (Socket acceptSocket)
882 ThrowIfDisposedAndClosed ();
885 SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
889 error = SOCKET_CLOSED_CODE;
890 throw new SocketException (error);
893 acceptSocket.address_family = this.AddressFamily;
894 acceptSocket.socket_type = this.SocketType;
895 acceptSocket.protocol_type = this.ProtocolType;
896 acceptSocket.safe_handle = safe_handle;
897 acceptSocket.is_connected = true;
898 acceptSocket.seed_endpoint = this.seed_endpoint;
899 acceptSocket.Blocking = this.Blocking;
901 // FIXME: figure out what if anything else needs to be reset
904 public bool AcceptAsync (SocketAsyncEventArgs e)
906 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
908 ThrowIfDisposedAndClosed ();
911 throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
913 throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
914 if (e.BufferList != null)
915 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
917 throw new ArgumentOutOfRangeException ("e.Count");
919 Socket acceptSocket = e.AcceptSocket;
920 if (acceptSocket != null) {
921 if (acceptSocket.is_bound || acceptSocket.is_connected)
922 throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
925 InitSocketAsyncEventArgs (e, AcceptAsyncCallback, e, SocketOperation.Accept);
927 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, e.socket_async_result));
932 static AsyncCallback AcceptAsyncCallback = new AsyncCallback (ares => {
933 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
935 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
936 throw new InvalidOperationException ("No operation in progress");
939 e.AcceptSocket = e.current_socket.EndAccept (ares);
940 } catch (SocketException ex) {
941 e.SocketError = ex.SocketErrorCode;
942 } catch (ObjectDisposedException) {
943 e.SocketError = SocketError.OperationAborted;
945 if (e.AcceptSocket == null)
946 e.AcceptSocket = new Socket (e.current_socket.AddressFamily, e.current_socket.SocketType, e.current_socket.ProtocolType, null);
951 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
953 ThrowIfDisposedAndClosed ();
955 if (!is_bound || !is_listening)
956 throw new InvalidOperationException ();
958 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Accept);
960 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, sockares));
965 static IOAsyncCallback BeginAcceptCallback = new IOAsyncCallback (ares => {
966 SocketAsyncResult sockares = (SocketAsyncResult) ares;
967 Socket acc_socket = null;
969 if (sockares.AcceptSocket == null) {
970 acc_socket = sockares.socket.Accept ();
972 acc_socket = sockares.AcceptSocket;
973 sockares.socket.Accept (acc_socket);
976 } catch (Exception e) {
977 sockares.Complete (e);
980 sockares.Complete (acc_socket);
983 public IAsyncResult BeginAccept (int receiveSize, AsyncCallback callback, object state)
985 ThrowIfDisposedAndClosed ();
988 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
990 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
991 Buffer = new byte [receiveSize],
994 SockFlags = SocketFlags.None,
997 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
1002 public IAsyncResult BeginAccept (Socket acceptSocket, int receiveSize, AsyncCallback callback, object state)
1004 ThrowIfDisposedAndClosed ();
1006 if (receiveSize < 0)
1007 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
1009 if (acceptSocket != null) {
1010 ThrowIfDisposedAndClosed (acceptSocket);
1012 if (acceptSocket.IsBound)
1013 throw new InvalidOperationException ();
1015 /* For some reason the MS runtime
1016 * barfs if the new socket is not TCP,
1017 * even though it's just about to blow
1018 * away all those parameters
1020 if (acceptSocket.ProtocolType != ProtocolType.Tcp)
1021 throw new SocketException ((int)SocketError.InvalidArgument);
1024 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
1025 Buffer = new byte [receiveSize],
1028 SockFlags = SocketFlags.None,
1029 AcceptSocket = acceptSocket,
1032 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
1037 static IOAsyncCallback BeginAcceptReceiveCallback = new IOAsyncCallback (ares => {
1038 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1039 Socket acc_socket = null;
1042 if (sockares.AcceptSocket == null) {
1043 acc_socket = sockares.socket.Accept ();
1045 acc_socket = sockares.AcceptSocket;
1046 sockares.socket.Accept (acc_socket);
1048 } catch (Exception e) {
1049 sockares.Complete (e);
1053 /* It seems the MS runtime special-cases 0-length requested receive data. See bug 464201. */
1055 if (sockares.Size > 0) {
1058 total = acc_socket.Receive_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out error);
1060 sockares.Complete (new SocketException ((int) error));
1063 } catch (Exception e) {
1064 sockares.Complete (e);
1069 sockares.Complete (acc_socket, total);
1072 public Socket EndAccept (IAsyncResult result)
1076 return EndAccept (out buffer, out bytes, result);
1079 public Socket EndAccept (out byte[] buffer, IAsyncResult asyncResult)
1082 return EndAccept (out buffer, out bytes, asyncResult);
1085 public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
1087 ThrowIfDisposedAndClosed ();
1089 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndAccept", "asyncResult");
1091 if (!sockares.IsCompleted)
1092 sockares.AsyncWaitHandle.WaitOne ();
1094 sockares.CheckIfThrowDelayedException ();
1096 buffer = sockares.Buffer;
1097 bytesTransferred = sockares.Total;
1099 return sockares.AcceptedSocket;
1102 static SafeSocketHandle Accept_internal (SafeSocketHandle safeHandle, out int error, bool blocking)
1105 safeHandle.RegisterForBlockingSyscall ();
1106 var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
1107 return new SafeSocketHandle (ret, true);
1109 safeHandle.UnRegisterForBlockingSyscall ();
1113 /* Creates a new system socket, returning the handle */
1114 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1115 extern static IntPtr Accept_internal (IntPtr sock, out int error, bool blocking);
1121 public void Bind (EndPoint localEP)
1123 ThrowIfDisposedAndClosed ();
1125 if (localEP == null)
1126 throw new ArgumentNullException("localEP");
1128 var ipEndPoint = localEP as IPEndPoint;
1129 if (ipEndPoint != null) {
1130 localEP = RemapIPEndPoint (ipEndPoint);
1134 Bind_internal (safe_handle, localEP.Serialize(), out error);
1137 throw new SocketException (error);
1141 seed_endpoint = localEP;
1144 private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1146 bool release = false;
1148 safeHandle.DangerousAddRef (ref release);
1149 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
1152 safeHandle.DangerousRelease ();
1156 // Creates a new system socket, returning the handle
1157 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1158 private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
1164 public void Listen (int backlog)
1166 ThrowIfDisposedAndClosed ();
1169 throw new SocketException ((int) SocketError.InvalidArgument);
1172 Listen_internal(safe_handle, backlog, out error);
1175 throw new SocketException (error);
1177 is_listening = true;
1180 static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
1182 bool release = false;
1184 safeHandle.DangerousAddRef (ref release);
1185 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
1188 safeHandle.DangerousRelease ();
1192 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1193 extern static void Listen_internal (IntPtr sock, int backlog, out int error);
1199 public void Connect (IPAddress address, int port)
1201 Connect (new IPEndPoint (address, port));
1204 public void Connect (string host, int port)
1206 Connect (Dns.GetHostAddresses (host), port);
1209 public void Connect (IPAddress[] addresses, int port)
1211 ThrowIfDisposedAndClosed ();
1213 if (addresses == null)
1214 throw new ArgumentNullException ("addresses");
1215 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1216 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1218 throw new InvalidOperationException ();
1220 // FIXME: do non-blocking sockets Poll here?
1222 foreach (IPAddress address in addresses) {
1223 IPEndPoint iep = new IPEndPoint (address, port);
1225 iep = RemapIPEndPoint (iep);
1227 Connect_internal (safe_handle, iep.Serialize (), out error);
1229 is_connected = true;
1231 seed_endpoint = iep;
1234 if (error != (int)SocketError.InProgress && error != (int)SocketError.WouldBlock)
1238 Poll (-1, SelectMode.SelectWrite);
1239 error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1241 is_connected = true;
1243 seed_endpoint = iep;
1250 throw new SocketException (error);
1254 public void Connect (EndPoint remoteEP)
1256 ThrowIfDisposedAndClosed ();
1258 if (remoteEP == null)
1259 throw new ArgumentNullException ("remoteEP");
1261 IPEndPoint ep = remoteEP as IPEndPoint;
1262 /* Dgram uses Any to 'disconnect' */
1263 if (ep != null && socket_type != SocketType.Dgram) {
1264 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1265 throw new SocketException ((int) SocketError.AddressNotAvailable);
1269 throw new InvalidOperationException ();
1272 remoteEP = RemapIPEndPoint (ep);
1275 SocketAddress serial = remoteEP.Serialize ();
1278 Connect_internal (safe_handle, serial, out error);
1280 if (error == 0 || error == 10035)
1281 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1285 error = SOCKET_CLOSED_CODE;
1286 throw new SocketException (error);
1289 is_connected = !(socket_type == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
1293 public bool ConnectAsync (SocketAsyncEventArgs e)
1295 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1297 ThrowIfDisposedAndClosed ();
1300 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1301 if (e.RemoteEndPoint == null)
1302 throw new ArgumentNullException ("remoteEP");
1304 InitSocketAsyncEventArgs (e, null, e, SocketOperation.Connect);
1307 IPAddress [] addresses;
1308 SocketAsyncResult ares;
1310 if (!GetCheckedIPs (e, out addresses)) {
1311 e.socket_async_result.EndPoint = e.RemoteEndPoint;
1312 ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
1314 DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1315 e.socket_async_result.Addresses = addresses;
1316 e.socket_async_result.Port = dep.Port;
1317 ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
1320 if (ares.IsCompleted && ares.CompletedSynchronously) {
1321 ares.CheckIfThrowDelayedException ();
1324 } catch (Exception exc) {
1325 e.socket_async_result.Complete (exc, true);
1332 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
1334 var sock = new Socket (e.RemoteEndPoint.AddressFamily, socketType, protocolType);
1335 return sock.ConnectAsync (e);
1338 public static void CancelConnectAsync (SocketAsyncEventArgs e)
1341 throw new ArgumentNullException("e");
1343 if (e.in_progress != 0 && e.LastOperation == SocketAsyncOperation.Connect)
1344 e.current_socket.Close();
1347 static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
1348 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1350 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1351 throw new InvalidOperationException ("No operation in progress");
1354 e.current_socket.EndConnect (ares);
1355 } catch (SocketException se) {
1356 e.SocketError = se.SocketErrorCode;
1357 } catch (ObjectDisposedException) {
1358 e.SocketError = SocketError.OperationAborted;
1364 public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback callback, object state)
1366 ThrowIfDisposedAndClosed ();
1368 if (address == null)
1369 throw new ArgumentNullException ("address");
1370 if (address.ToString ().Length == 0)
1371 throw new ArgumentException ("The length of the IP address is zero");
1372 if (port <= 0 || port > 65535)
1373 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1375 throw new InvalidOperationException ();
1377 return BeginConnect (new IPEndPoint (address, port), callback, state);
1380 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
1382 ThrowIfDisposedAndClosed ();
1385 throw new ArgumentNullException ("host");
1386 if (address_family != AddressFamily.InterNetwork && address_family != AddressFamily.InterNetworkV6)
1387 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1388 if (port <= 0 || port > 65535)
1389 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1391 throw new InvalidOperationException ();
1393 return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1396 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
1398 ThrowIfDisposedAndClosed ();
1400 if (end_point == null)
1401 throw new ArgumentNullException ("end_point");
1403 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1404 EndPoint = end_point,
1407 // Bug #75154: Connect() should not succeed for .Any addresses.
1408 if (end_point is IPEndPoint) {
1409 IPEndPoint ep = (IPEndPoint) end_point;
1410 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1411 sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1415 end_point = RemapIPEndPoint (ep);
1420 if (connect_in_progress) {
1421 // This could happen when multiple IPs are used
1422 // Calling connect() again will reset the connection attempt and cause
1423 // an error. Better to just close the socket and move on.
1424 connect_in_progress = false;
1425 safe_handle.Dispose ();
1426 safe_handle = new SafeSocketHandle (Socket_internal (address_family, socket_type, protocol_type, out error), true);
1428 throw new SocketException (error);
1431 bool blk = is_blocking;
1434 Connect_internal (safe_handle, end_point.Serialize (), out error);
1440 is_connected = true;
1442 sockares.Complete (true);
1446 if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1448 is_connected = false;
1450 sockares.Complete (new SocketException (error), true);
1455 is_connected = false;
1457 connect_in_progress = true;
1459 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
1464 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1466 ThrowIfDisposedAndClosed ();
1468 if (addresses == null)
1469 throw new ArgumentNullException ("addresses");
1470 if (addresses.Length == 0)
1471 throw new ArgumentException ("Empty addresses list");
1472 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1473 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1474 if (port <= 0 || port > 65535)
1475 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1477 throw new InvalidOperationException ();
1479 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1480 Addresses = addresses,
1484 is_connected = false;
1486 return BeginMConnect (sockares);
1489 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1491 SocketAsyncResult ares = null;
1492 Exception exc = null;
1493 AsyncCallback callback;
1495 for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1497 sockares.CurrentAddress++;
1499 ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1500 if (ares.IsCompleted && ares.CompletedSynchronously) {
1501 ares.CheckIfThrowDelayedException ();
1503 callback = ares.AsyncCallback;
1504 if (callback != null)
1505 ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
1509 } catch (Exception e) {
1521 static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
1522 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1524 if (sockares.EndPoint == null) {
1525 sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
1529 SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
1530 bool is_mconnect = mconnect != null && mconnect.Addresses != null;
1533 EndPoint ep = sockares.EndPoint;
1534 int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1536 if (error_code == 0) {
1538 sockares = mconnect;
1540 sockares.socket.seed_endpoint = ep;
1541 sockares.socket.is_connected = true;
1542 sockares.socket.is_bound = true;
1543 sockares.socket.connect_in_progress = false;
1545 sockares.Complete ();
1550 sockares.socket.connect_in_progress = false;
1551 sockares.Complete (new SocketException (error_code));
1555 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
1556 mconnect.Complete (new SocketException (error_code));
1560 mconnect.socket.BeginMConnect (mconnect);
1561 } catch (Exception e) {
1562 sockares.socket.connect_in_progress = false;
1565 sockares = mconnect;
1567 sockares.Complete (e);
1572 public void EndConnect (IAsyncResult result)
1574 ThrowIfDisposedAndClosed ();
1576 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1578 if (!sockares.IsCompleted)
1579 sockares.AsyncWaitHandle.WaitOne();
1581 sockares.CheckIfThrowDelayedException();
1584 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1587 safeHandle.RegisterForBlockingSyscall ();
1588 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
1590 safeHandle.UnRegisterForBlockingSyscall ();
1594 /* Connects to the remote address */
1595 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1596 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error);
1599 * - false when it is ok to use RemoteEndPoint
1600 * - true when addresses must be used (and addresses could be null/empty) */
1601 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1605 // Connect to the first address that match the host name, like:
1606 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1607 // while skipping entries that do not match the address family
1608 DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1610 addresses = Dns.GetHostAddresses (dep.Host);
1613 e.ConnectByNameError = null;
1622 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1623 * if the platform is newer than w2k. We should be able to cope... */
1624 public void Disconnect (bool reuseSocket)
1626 ThrowIfDisposedAndClosed ();
1629 Disconnect_internal (safe_handle, reuseSocket, out error);
1633 /* ERROR_NOT_SUPPORTED */
1634 throw new PlatformNotSupportedException ();
1636 throw new SocketException (error);
1640 is_connected = false;
1642 /* Do managed housekeeping here... */
1646 public bool DisconnectAsync (SocketAsyncEventArgs e)
1648 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1650 ThrowIfDisposedAndClosed ();
1652 InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
1654 IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
1659 static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
1660 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1662 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1663 throw new InvalidOperationException ("No operation in progress");
1666 e.current_socket.EndDisconnect (ares);
1667 } catch (SocketException ex) {
1668 e.SocketError = ex.SocketErrorCode;
1669 } catch (ObjectDisposedException) {
1670 e.SocketError = SocketError.OperationAborted;
1676 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1678 ThrowIfDisposedAndClosed ();
1680 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1681 ReuseSocket = reuseSocket,
1684 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
1689 static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
1690 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1693 sockares.socket.Disconnect (sockares.ReuseSocket);
1694 } catch (Exception e) {
1695 sockares.Complete (e);
1699 sockares.Complete ();
1702 public void EndDisconnect (IAsyncResult asyncResult)
1704 ThrowIfDisposedAndClosed ();
1706 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1708 if (!sockares.IsCompleted)
1709 sockares.AsyncWaitHandle.WaitOne ();
1711 sockares.CheckIfThrowDelayedException ();
1714 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1716 bool release = false;
1718 safeHandle.DangerousAddRef (ref release);
1719 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1722 safeHandle.DangerousRelease ();
1726 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1727 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1733 public int Receive (byte [] buffer)
1735 return Receive (buffer, SocketFlags.None);
1738 public int Receive (byte [] buffer, SocketFlags socketFlags)
1740 ThrowIfDisposedAndClosed ();
1741 ThrowIfBufferNull (buffer);
1742 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
1745 int ret = Receive_nochecks (buffer, 0, buffer.Length, socketFlags, out error);
1747 if (error != SocketError.Success) {
1748 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1749 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1750 throw new SocketException ((int) error);
1756 public int Receive (byte [] buffer, int size, SocketFlags socketFlags)
1758 ThrowIfDisposedAndClosed ();
1759 ThrowIfBufferNull (buffer);
1760 ThrowIfBufferOutOfRange (buffer, 0, size);
1763 int ret = Receive_nochecks (buffer, 0, size, socketFlags, out error);
1765 if (error != SocketError.Success) {
1766 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1767 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1768 throw new SocketException ((int) error);
1774 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags)
1776 ThrowIfDisposedAndClosed ();
1777 ThrowIfBufferNull (buffer);
1778 ThrowIfBufferOutOfRange (buffer, offset, size);
1781 int ret = Receive_nochecks (buffer, offset, size, socketFlags, out error);
1783 if (error != SocketError.Success) {
1784 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1785 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1786 throw new SocketException ((int) error);
1792 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1794 ThrowIfDisposedAndClosed ();
1795 ThrowIfBufferNull (buffer);
1796 ThrowIfBufferOutOfRange (buffer, offset, size);
1798 return Receive_nochecks (buffer, offset, size, socketFlags, out errorCode);
1801 public int Receive (IList<ArraySegment<byte>> buffers)
1804 int ret = Receive (buffers, SocketFlags.None, out error);
1806 if (error != SocketError.Success)
1807 throw new SocketException ((int) error);
1812 [CLSCompliant (false)]
1813 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1816 int ret = Receive (buffers, socketFlags, out error);
1818 if (error != SocketError.Success)
1819 throw new SocketException ((int) error);
1824 [CLSCompliant (false)]
1825 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1827 ThrowIfDisposedAndClosed ();
1829 if (buffers == null || buffers.Count == 0)
1830 throw new ArgumentNullException ("buffers");
1832 int numsegments = buffers.Count;
1836 /* Only example I can find of sending a byte array reference directly into an internal
1837 * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1838 * so taking a lead from that... */
1839 WSABUF[] bufarray = new WSABUF[numsegments];
1840 GCHandle[] gch = new GCHandle[numsegments];
1842 for (int i = 0; i < numsegments; i++) {
1843 ArraySegment<byte> segment = buffers[i];
1845 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1846 throw new ArgumentOutOfRangeException ("segment");
1848 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1849 bufarray[i].len = segment.Count;
1850 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1854 ret = Receive_internal (safe_handle, bufarray, socketFlags, out nativeError);
1856 for (int i = 0; i < numsegments; i++) {
1857 if (gch[i].IsAllocated)
1862 errorCode = (SocketError) nativeError;
1867 public bool ReceiveAsync (SocketAsyncEventArgs e)
1869 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1871 ThrowIfDisposedAndClosed ();
1873 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1874 // thrown when e.Buffer and e.BufferList are null (works fine when one is
1875 // set to a valid object)
1876 if (e.Buffer == null && e.BufferList == null)
1877 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1879 if (e.Buffer == null) {
1880 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
1882 e.socket_async_result.Buffers = e.BufferList;
1884 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
1886 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
1888 e.socket_async_result.Buffer = e.Buffer;
1889 e.socket_async_result.Offset = e.Offset;
1890 e.socket_async_result.Size = e.Count;
1892 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
1898 static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
1899 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1901 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1902 throw new InvalidOperationException ("No operation in progress");
1905 e.BytesTransferred = e.current_socket.EndReceive (ares);
1906 } catch (SocketException se){
1907 e.SocketError = se.SocketErrorCode;
1908 } catch (ObjectDisposedException) {
1909 e.SocketError = SocketError.OperationAborted;
1915 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
1917 ThrowIfDisposedAndClosed ();
1918 ThrowIfBufferNull (buffer);
1919 ThrowIfBufferOutOfRange (buffer, offset, size);
1921 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1925 SockFlags = socket_flags,
1928 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
1933 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags flags, out SocketError error, AsyncCallback callback, object state)
1935 /* As far as I can tell from the docs and from experimentation, a pointer to the
1936 * SocketError parameter is not supposed to be saved for the async parts. And as we don't
1937 * set any socket errors in the setup code, we just have to set it to Success. */
1938 error = SocketError.Success;
1939 return BeginReceive (buffer, offset, size, flags, callback, state);
1942 static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
1943 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1947 total = Receive_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
1948 } catch (Exception e) {
1949 sockares.Complete (e);
1953 sockares.Complete (total);
1956 [CLSCompliant (false)]
1957 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
1959 ThrowIfDisposedAndClosed ();
1961 if (buffers == null)
1962 throw new ArgumentNullException ("buffers");
1964 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1966 SockFlags = socketFlags,
1969 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
1974 [CLSCompliant (false)]
1975 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1977 /* I assume the same SocketError semantics as above */
1978 errorCode = SocketError.Success;
1979 return BeginReceive (buffers, socketFlags, callback, state);
1982 static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
1983 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1987 total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
1988 } catch (Exception e) {
1989 sockares.Complete (e);
1993 sockares.Complete (total);
1996 public int EndReceive (IAsyncResult result)
1999 int bytesReceived = EndReceive (result, out error);
2001 if (error != SocketError.Success) {
2002 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2003 is_connected = false;
2004 throw new SocketException ((int)error);
2007 return bytesReceived;
2010 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
2012 ThrowIfDisposedAndClosed ();
2014 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
2016 if (!sockares.IsCompleted)
2017 sockares.AsyncWaitHandle.WaitOne ();
2019 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
2020 // kinds of exceptions that should be thrown.
2021 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2022 sockares.CheckIfThrowDelayedException();
2024 return sockares.Total;
2027 int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2030 int ret = Receive_internal (safe_handle, buf, offset, size, flags, out nativeError);
2032 error = (SocketError) nativeError;
2033 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2034 is_connected = false;
2037 is_connected = true;
2043 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2046 safeHandle.RegisterForBlockingSyscall ();
2047 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2049 safeHandle.UnRegisterForBlockingSyscall ();
2053 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2054 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2056 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
2059 safeHandle.RegisterForBlockingSyscall ();
2060 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
2062 safeHandle.UnRegisterForBlockingSyscall ();
2066 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2067 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error);
2073 public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
2075 ThrowIfDisposedAndClosed ();
2076 ThrowIfBufferNull (buffer);
2078 return ReceiveFrom (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
2081 public int ReceiveFrom (byte [] buffer, SocketFlags socketFlags, ref EndPoint remoteEP)
2083 ThrowIfDisposedAndClosed ();
2084 ThrowIfBufferNull (buffer);
2086 return ReceiveFrom (buffer, 0, buffer.Length, socketFlags, ref remoteEP);
2089 public int ReceiveFrom (byte [] buffer, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
2091 ThrowIfDisposedAndClosed ();
2092 ThrowIfBufferNull (buffer);
2093 ThrowIfBufferOutOfRange (buffer, 0, size);
2095 return ReceiveFrom (buffer, 0, size, socketFlags, ref remoteEP);
2098 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
2100 ThrowIfDisposedAndClosed ();
2101 ThrowIfBufferNull (buffer);
2102 ThrowIfBufferOutOfRange (buffer, offset, size);
2104 if (remoteEP == null)
2105 throw new ArgumentNullException ("remoteEP");
2108 return ReceiveFrom_nochecks_exc (buffer, offset, size, socketFlags, ref remoteEP, true, out error);
2111 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
2113 ThrowIfDisposedAndClosed ();
2115 // We do not support recv into multiple buffers yet
2116 if (e.BufferList != null)
2117 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2118 if (e.RemoteEndPoint == null)
2119 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2121 InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
2123 e.socket_async_result.Buffer = e.Buffer;
2124 e.socket_async_result.Offset = e.Offset;
2125 e.socket_async_result.Size = e.Count;
2126 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2127 e.socket_async_result.SockFlags = e.SocketFlags;
2129 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
2134 static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
2135 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2137 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2138 throw new InvalidOperationException ("No operation in progress");
2141 e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
2142 } catch (SocketException ex) {
2143 e.SocketError = ex.SocketErrorCode;
2144 } catch (ObjectDisposedException) {
2145 e.SocketError = SocketError.OperationAborted;
2151 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
2153 ThrowIfDisposedAndClosed ();
2154 ThrowIfBufferNull (buffer);
2155 ThrowIfBufferOutOfRange (buffer, offset, size);
2157 if (remote_end == null)
2158 throw new ArgumentNullException ("remote_end");
2160 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
2164 SockFlags = socket_flags,
2165 EndPoint = remote_end,
2168 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
2173 static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
2174 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2179 total = sockares.socket.ReceiveFrom_nochecks_exc (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, true, out error);
2180 } catch (Exception e) {
2181 sockares.Complete (e);
2185 sockares.Complete (total);
2188 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
2190 ThrowIfDisposedAndClosed ();
2192 if (end_point == null)
2193 throw new ArgumentNullException ("remote_end");
2195 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
2197 if (!sockares.IsCompleted)
2198 sockares.AsyncWaitHandle.WaitOne();
2200 sockares.CheckIfThrowDelayedException();
2202 end_point = sockares.EndPoint;
2204 return sockares.Total;
2207 internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end, bool throwOnError, out int error)
2209 SocketAddress sockaddr = remote_end.Serialize();
2211 int cnt = ReceiveFrom_internal (safe_handle, buf, offset, size, flags, ref sockaddr, out error);
2213 SocketError err = (SocketError) error;
2215 if (err != SocketError.WouldBlock && err != SocketError.InProgress) {
2216 is_connected = false;
2217 } else if (err == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
2219 throw new SocketException ((int) SocketError.TimedOut, TIMEOUT_EXCEPTION_MSG);
2220 error = (int) SocketError.TimedOut;
2225 throw new SocketException (error);
2230 is_connected = true;
2233 /* If sockaddr is null then we're a connection oriented protocol and should ignore the
2234 * remote_end parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
2235 if (sockaddr != null) {
2236 /* Stupidly, EndPoint.Create() is an instance method */
2237 remote_end = remote_end.Create (sockaddr);
2240 seed_endpoint = remote_end;
2245 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error)
2248 safeHandle.RegisterForBlockingSyscall ();
2249 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
2251 safeHandle.UnRegisterForBlockingSyscall ();
2255 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2256 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error);
2260 #region ReceiveMessageFrom
2262 [MonoTODO ("Not implemented")]
2263 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
2265 ThrowIfDisposedAndClosed ();
2266 ThrowIfBufferNull (buffer);
2267 ThrowIfBufferOutOfRange (buffer, offset, size);
2269 if (remoteEP == null)
2270 throw new ArgumentNullException ("remoteEP");
2272 // FIXME: figure out how we get hold of the IPPacketInformation
2273 throw new NotImplementedException ();
2276 [MonoTODO ("Not implemented")]
2277 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
2279 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2281 ThrowIfDisposedAndClosed ();
2283 throw new NotImplementedException ();
2287 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
2289 ThrowIfDisposedAndClosed ();
2290 ThrowIfBufferNull (buffer);
2291 ThrowIfBufferOutOfRange (buffer, offset, size);
2293 if (remoteEP == null)
2294 throw new ArgumentNullException ("remoteEP");
2296 throw new NotImplementedException ();
2300 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
2302 ThrowIfDisposedAndClosed ();
2304 if (endPoint == null)
2305 throw new ArgumentNullException ("endPoint");
2307 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
2309 throw new NotImplementedException ();
2316 public int Send (byte [] buffer)
2318 ThrowIfDisposedAndClosed ();
2319 ThrowIfBufferNull (buffer);
2320 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2323 int ret = Send_nochecks (buffer, 0, buffer.Length, SocketFlags.None, out error);
2325 if (error != SocketError.Success)
2326 throw new SocketException ((int) error);
2331 public int Send (byte [] buffer, SocketFlags socketFlags)
2333 ThrowIfDisposedAndClosed ();
2334 ThrowIfBufferNull (buffer);
2335 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2338 int ret = Send_nochecks (buffer, 0, buffer.Length, socketFlags, out error);
2340 if (error != SocketError.Success)
2341 throw new SocketException ((int) error);
2346 public int Send (byte [] buffer, int size, SocketFlags socketFlags)
2348 ThrowIfDisposedAndClosed ();
2349 ThrowIfBufferNull (buffer);
2350 ThrowIfBufferOutOfRange (buffer, 0, size);
2353 int ret = Send_nochecks (buffer, 0, size, socketFlags, out error);
2355 if (error != SocketError.Success)
2356 throw new SocketException ((int) error);
2361 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags)
2363 ThrowIfDisposedAndClosed ();
2364 ThrowIfBufferNull (buffer);
2365 ThrowIfBufferOutOfRange (buffer, offset, size);
2368 int ret = Send_nochecks (buffer, offset, size, socketFlags, out error);
2370 if (error != SocketError.Success)
2371 throw new SocketException ((int) error);
2376 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
2378 ThrowIfDisposedAndClosed ();
2379 ThrowIfBufferNull (buffer);
2380 ThrowIfBufferOutOfRange (buffer, offset, size);
2382 return Send_nochecks (buffer, offset, size, socketFlags, out errorCode);
2386 int Send (IList<ArraySegment<byte>> buffers)
2389 int ret = Send (buffers, SocketFlags.None, out error);
2391 if (error != SocketError.Success)
2392 throw new SocketException ((int) error);
2398 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
2401 int ret = Send (buffers, socketFlags, out error);
2403 if (error != SocketError.Success)
2404 throw new SocketException ((int) error);
2409 [CLSCompliant (false)]
2410 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
2412 ThrowIfDisposedAndClosed ();
2414 if (buffers == null)
2415 throw new ArgumentNullException ("buffers");
2416 if (buffers.Count == 0)
2417 throw new ArgumentException ("Buffer is empty", "buffers");
2419 int numsegments = buffers.Count;
2423 WSABUF[] bufarray = new WSABUF[numsegments];
2424 GCHandle[] gch = new GCHandle[numsegments];
2426 for(int i = 0; i < numsegments; i++) {
2427 ArraySegment<byte> segment = buffers[i];
2429 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
2430 throw new ArgumentOutOfRangeException ("segment");
2432 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
2433 bufarray[i].len = segment.Count;
2434 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
2438 ret = Send_internal (safe_handle, bufarray, socketFlags, out nativeError);
2440 for(int i = 0; i < numsegments; i++) {
2441 if (gch[i].IsAllocated) {
2447 errorCode = (SocketError)nativeError;
2452 int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2455 error = SocketError.Success;
2460 int ret = Send_internal (safe_handle, buf, offset, size, flags, out nativeError);
2462 error = (SocketError)nativeError;
2464 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2465 is_connected = false;
2468 is_connected = true;
2474 public bool SendAsync (SocketAsyncEventArgs e)
2476 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2478 ThrowIfDisposedAndClosed ();
2480 if (e.Buffer == null && e.BufferList == null)
2481 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
2483 if (e.Buffer == null) {
2484 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
2486 e.socket_async_result.Buffers = e.BufferList;
2488 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
2490 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
2492 e.socket_async_result.Buffer = e.Buffer;
2493 e.socket_async_result.Offset = e.Offset;
2494 e.socket_async_result.Size = e.Count;
2496 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2502 static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
2503 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2505 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2506 throw new InvalidOperationException ("No operation in progress");
2509 e.BytesTransferred = e.current_socket.EndSend (ares);
2510 } catch (SocketException se){
2511 e.SocketError = se.SocketErrorCode;
2512 } catch (ObjectDisposedException) {
2513 e.SocketError = SocketError.OperationAborted;
2519 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2521 if (!is_connected) {
2522 errorCode = SocketError.NotConnected;
2523 throw new SocketException ((int) errorCode);
2526 errorCode = SocketError.Success;
2527 return BeginSend (buffer, offset, size, socketFlags, callback, state);
2530 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
2532 ThrowIfDisposedAndClosed ();
2533 ThrowIfBufferNull (buffer);
2534 ThrowIfBufferOutOfRange (buffer, offset, size);
2537 throw new SocketException ((int)SocketError.NotConnected);
2539 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
2543 SockFlags = socket_flags,
2546 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
2551 static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
2556 total = Socket.Send_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
2557 } catch (Exception e) {
2558 sockares.Complete (e);
2562 if (sockares.error == 0) {
2563 sent_so_far += total;
2564 sockares.Offset += total;
2565 sockares.Size -= total;
2567 if (sockares.socket.is_disposed) {
2568 sockares.Complete (total);
2572 if (sockares.Size > 0) {
2573 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2574 return; // Have to finish writing everything. See bug #74475.
2577 sockares.Total = sent_so_far;
2580 sockares.Complete (total);
2583 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
2585 ThrowIfDisposedAndClosed ();
2587 if (buffers == null)
2588 throw new ArgumentNullException ("buffers");
2590 throw new SocketException ((int)SocketError.NotConnected);
2592 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
2594 SockFlags = socketFlags,
2597 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
2602 [CLSCompliant (false)]
2603 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2605 if (!is_connected) {
2606 errorCode = SocketError.NotConnected;
2607 throw new SocketException ((int)errorCode);
2610 errorCode = SocketError.Success;
2611 return BeginSend (buffers, socketFlags, callback, state);
2614 static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
2615 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2619 total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
2620 } catch (Exception e) {
2621 sockares.Complete (e);
2625 sockares.Complete (total);
2628 public int EndSend (IAsyncResult result)
2631 int bytesSent = EndSend (result, out error);
2633 if (error != SocketError.Success) {
2634 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2635 is_connected = false;
2636 throw new SocketException ((int)error);
2642 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
2644 ThrowIfDisposedAndClosed ();
2646 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
2648 if (!sockares.IsCompleted)
2649 sockares.AsyncWaitHandle.WaitOne ();
2651 /* If no socket error occurred, call CheckIfThrowDelayedException in
2652 * case there are other kinds of exceptions that should be thrown.*/
2653 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2654 sockares.CheckIfThrowDelayedException ();
2656 return sockares.Total;
2659 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2661 bool release = false;
2663 safeHandle.DangerousAddRef (ref release);
2664 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2667 safeHandle.DangerousRelease ();
2671 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2672 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2674 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
2677 safeHandle.RegisterForBlockingSyscall ();
2678 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
2680 safeHandle.UnRegisterForBlockingSyscall ();
2684 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2685 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
2691 public int SendTo (byte [] buffer, EndPoint remoteEP)
2693 ThrowIfDisposedAndClosed ();
2694 ThrowIfBufferNull (buffer);
2696 return SendTo (buffer, 0, buffer.Length, SocketFlags.None, remoteEP);
2699 public int SendTo (byte [] buffer, SocketFlags socketFlags, EndPoint remoteEP)
2701 ThrowIfDisposedAndClosed ();
2702 ThrowIfBufferNull (buffer);
2704 return SendTo (buffer, 0, buffer.Length, socketFlags, remoteEP);
2707 public int SendTo (byte [] buffer, int size, SocketFlags socketFlags, EndPoint remoteEP)
2709 return SendTo (buffer, 0, size, socketFlags, remoteEP);
2712 public int SendTo (byte [] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP)
2714 ThrowIfDisposedAndClosed ();
2715 ThrowIfBufferNull (buffer);
2716 ThrowIfBufferOutOfRange (buffer, offset, size);
2718 if (remoteEP == null)
2719 throw new ArgumentNullException("remoteEP");
2721 return SendTo_nochecks (buffer, offset, size, socketFlags, remoteEP);
2724 public bool SendToAsync (SocketAsyncEventArgs e)
2726 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2728 ThrowIfDisposedAndClosed ();
2730 if (e.BufferList != null)
2731 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2732 if (e.RemoteEndPoint == null)
2733 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2735 InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2737 e.socket_async_result.Buffer = e.Buffer;
2738 e.socket_async_result.Offset = e.Offset;
2739 e.socket_async_result.Size = e.Count;
2740 e.socket_async_result.SockFlags = e.SocketFlags;
2741 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2743 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2748 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2749 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2751 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2752 throw new InvalidOperationException ("No operation in progress");
2755 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2756 } catch (SocketException ex) {
2757 e.SocketError = ex.SocketErrorCode;
2758 } catch (ObjectDisposedException) {
2759 e.SocketError = SocketError.OperationAborted;
2765 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2767 ThrowIfDisposedAndClosed ();
2768 ThrowIfBufferNull (buffer);
2769 ThrowIfBufferOutOfRange (buffer, offset, size);
2771 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2775 SockFlags = socket_flags,
2776 EndPoint = remote_end,
2779 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2784 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2788 total = sockares.socket.SendTo_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2790 if (sockares.error == 0) {
2791 sent_so_far += total;
2792 sockares.Offset += total;
2793 sockares.Size -= total;
2796 if (sockares.Size > 0) {
2797 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2798 return; // Have to finish writing everything. See bug #74475.
2801 sockares.Total = sent_so_far;
2802 } catch (Exception e) {
2803 sockares.Complete (e);
2807 sockares.Complete ();
2810 public int EndSendTo (IAsyncResult result)
2812 ThrowIfDisposedAndClosed ();
2814 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2816 if (!sockares.IsCompleted)
2817 sockares.AsyncWaitHandle.WaitOne();
2819 sockares.CheckIfThrowDelayedException();
2821 return sockares.Total;
2824 int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2827 int ret = SendTo_internal (safe_handle, buffer, offset, size, flags, remote_end.Serialize (), out error);
2829 SocketError err = (SocketError) error;
2831 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2832 is_connected = false;
2833 throw new SocketException (error);
2836 is_connected = true;
2838 seed_endpoint = remote_end;
2843 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
2846 safeHandle.RegisterForBlockingSyscall ();
2847 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
2849 safeHandle.UnRegisterForBlockingSyscall ();
2853 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2854 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
2860 public void SendFile (string fileName)
2862 ThrowIfDisposedAndClosed ();
2865 throw new NotSupportedException ();
2867 throw new InvalidOperationException ();
2869 SendFile (fileName, null, null, 0);
2872 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2874 ThrowIfDisposedAndClosed ();
2877 throw new NotSupportedException ();
2879 throw new InvalidOperationException ();
2881 if (!SendFile_internal (safe_handle, fileName, preBuffer, postBuffer, flags)) {
2882 SocketException exc = new SocketException ();
2883 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2884 throw new FileNotFoundException ();
2889 public IAsyncResult BeginSendFile (string fileName, AsyncCallback callback, object state)
2891 ThrowIfDisposedAndClosed ();
2894 throw new NotSupportedException ();
2895 if (!File.Exists (fileName))
2896 throw new FileNotFoundException ();
2898 return BeginSendFile (fileName, null, null, 0, callback, state);
2901 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2903 ThrowIfDisposedAndClosed ();
2906 throw new NotSupportedException ();
2907 if (!File.Exists (fileName))
2908 throw new FileNotFoundException ();
2910 SendFileHandler handler = new SendFileHandler (SendFile);
2912 return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2915 public void EndSendFile (IAsyncResult asyncResult)
2917 ThrowIfDisposedAndClosed ();
2919 if (asyncResult == null)
2920 throw new ArgumentNullException ("asyncResult");
2922 SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2924 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2926 ares.Delegate.EndInvoke (ares.Original);
2929 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
2932 safeHandle.RegisterForBlockingSyscall ();
2933 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
2935 safeHandle.UnRegisterForBlockingSyscall ();
2939 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2940 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
2942 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2944 sealed class SendFileAsyncResult : IAsyncResult {
2948 public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2954 public object AsyncState {
2955 get { return ares.AsyncState; }
2958 public WaitHandle AsyncWaitHandle {
2959 get { return ares.AsyncWaitHandle; }
2962 public bool CompletedSynchronously {
2963 get { return ares.CompletedSynchronously; }
2966 public bool IsCompleted {
2967 get { return ares.IsCompleted; }
2970 public SendFileHandler Delegate {
2974 public IAsyncResult Original {
2975 get { return ares; }
2983 [MonoTODO ("Not implemented")]
2984 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2986 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2988 ThrowIfDisposedAndClosed ();
2990 throw new NotImplementedException ();
2995 #region DuplicateAndClose
2998 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2999 public SocketInformation DuplicateAndClose (int targetProcessId)
3001 var si = new SocketInformation ();
3003 (is_listening ? SocketInformationOptions.Listening : 0) |
3004 (is_connected ? SocketInformationOptions.Connected : 0) |
3005 (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
3006 (use_overlapped_io ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
3008 si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, is_bound ? 1 : 0, (long)Handle);
3017 #region GetSocketOption
3019 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3021 ThrowIfDisposedAndClosed ();
3023 if (optionValue == null)
3024 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3027 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref optionValue, out error);
3030 throw new SocketException (error);
3033 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength)
3035 ThrowIfDisposedAndClosed ();
3038 byte[] byte_val = new byte [optionLength];
3039 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref byte_val, out error);
3042 throw new SocketException (error);
3047 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
3049 ThrowIfDisposedAndClosed ();
3053 GetSocketOption_obj_internal (safe_handle, optionLevel, optionName, out obj_val, out error);
3056 throw new SocketException (error);
3058 if (optionName == SocketOptionName.Linger)
3059 return (LingerOption) obj_val;
3060 else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
3061 return (MulticastOption) obj_val;
3062 else if (obj_val is int)
3063 return (int) obj_val;
3068 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
3070 bool release = false;
3072 safeHandle.DangerousAddRef (ref release);
3073 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
3076 safeHandle.DangerousRelease ();
3080 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3081 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
3083 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
3085 bool release = false;
3087 safeHandle.DangerousAddRef (ref release);
3088 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
3091 safeHandle.DangerousRelease ();
3095 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3096 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
3100 #region SetSocketOption
3102 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3104 ThrowIfDisposedAndClosed ();
3106 // I'd throw an ArgumentNullException, but this is what MS does.
3107 if (optionValue == null)
3108 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3111 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, optionValue, 0, out error);
3114 if (error == (int) SocketError.InvalidArgument)
3115 throw new ArgumentException ();
3116 throw new SocketException (error);
3120 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
3122 ThrowIfDisposedAndClosed ();
3124 // NOTE: if a null is passed, the byte[] overload is used instead...
3125 if (optionValue == null)
3126 throw new ArgumentNullException("optionValue");
3130 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
3131 LingerOption linger = optionValue as LingerOption;
3133 throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
3134 SetSocketOption_internal (safe_handle, optionLevel, optionName, linger, null, 0, out error);
3135 } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3136 MulticastOption multicast = optionValue as MulticastOption;
3137 if (multicast == null)
3138 throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
3139 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3140 } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3141 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
3142 if (multicast == null)
3143 throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
3144 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3146 throw new ArgumentException ("Invalid value specified.", "optionValue");
3150 if (error == (int) SocketError.InvalidArgument)
3151 throw new ArgumentException ();
3152 throw new SocketException (error);
3156 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
3158 int int_val = optionValue ? 1 : 0;
3160 SetSocketOption (optionLevel, optionName, int_val);
3163 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
3165 ThrowIfDisposedAndClosed ();
3167 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse (protocol_type))
3168 throw new SocketException ((int) SocketError.OperationNotSupported, "Operating system sockets do not support ReuseAddress.\nIf your socket is not intended to bind to the same address and port multiple times remove this option, otherwise you should ignore this exception inside a try catch and check that ReuseAddress is true before binding to the same address and port multiple times.");
3171 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, optionValue, out error);
3174 if (error == (int) SocketError.InvalidArgument)
3175 throw new ArgumentException ();
3176 throw new SocketException (error);
3180 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
3182 bool release = false;
3184 safeHandle.DangerousAddRef (ref release);
3185 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
3188 safeHandle.DangerousRelease ();
3192 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3193 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
3199 public int IOControl (int ioControlCode, byte [] optionInValue, byte [] optionOutValue)
3202 throw new ObjectDisposedException (GetType ().ToString ());
3205 int result = IOControl_internal (safe_handle, ioControlCode, optionInValue, optionOutValue, out error);
3208 throw new SocketException (error);
3210 throw new InvalidOperationException ("Must use Blocking property instead.");
3215 public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
3217 return IOControl ((int) ioControlCode, optionInValue, optionOutValue);
3220 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
3222 bool release = false;
3224 safeHandle.DangerousAddRef (ref release);
3225 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
3228 safeHandle.DangerousRelease ();
3232 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
3233 * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
3234 * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
3235 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3236 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
3242 public void Close ()
3248 public void Close (int timeout)
3250 linger_timeout = timeout;
3254 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3255 internal extern static void Close_internal (IntPtr socket, out int error);
3261 public void Shutdown (SocketShutdown how)
3263 ThrowIfDisposedAndClosed ();
3266 throw new SocketException (10057); // Not connected
3269 Shutdown_internal (safe_handle, how, out error);
3272 throw new SocketException (error);
3275 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
3277 bool release = false;
3279 safeHandle.DangerousAddRef (ref release);
3280 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
3283 safeHandle.DangerousRelease ();
3287 [MethodImplAttribute (MethodImplOptions.InternalCall)]
3288 internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
3294 protected virtual void Dispose (bool disposing)
3300 bool was_connected = is_connected;
3301 is_connected = false;
3303 if (safe_handle != null) {
3310 safe_handle.Dispose ();
3314 public void Dispose ()
3317 GC.SuppressFinalize (this);
3320 void Linger (IntPtr handle)
3322 if (!is_connected || linger_timeout <= 0)
3325 /* We don't want to receive any more data */
3327 Shutdown_internal (handle, SocketShutdown.Receive, out error);
3332 int seconds = linger_timeout / 1000;
3333 int ms = linger_timeout % 1000;
3335 /* If the other end closes, this will return 'true' with 'Available' == 0 */
3336 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
3342 LingerOption linger = new LingerOption (true, seconds);
3343 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
3344 /* Not needed, we're closing upon return */
3352 void ThrowIfDisposedAndClosed (Socket socket)
3354 if (socket.is_disposed && socket.is_closed)
3355 throw new ObjectDisposedException (socket.GetType ().ToString ());
3358 void ThrowIfDisposedAndClosed ()
3360 if (is_disposed && is_closed)
3361 throw new ObjectDisposedException (GetType ().ToString ());
3364 void ThrowIfBufferNull (byte[] buffer)
3367 throw new ArgumentNullException ("buffer");
3370 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
3373 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
3374 if (offset > buffer.Length)
3375 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
3377 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
3378 if (size > buffer.Length - offset)
3379 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
3384 if (protocol_type == ProtocolType.Udp)
3385 throw new SocketException ((int)SocketError.ProtocolOption);
3388 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
3391 throw new ArgumentNullException (argName);
3393 SocketAsyncResult sockares = ares as SocketAsyncResult;
3394 if (sockares == null)
3395 throw new ArgumentException ("Invalid IAsyncResult", argName);
3396 if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
3397 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
3402 void QueueIOSelectorJob (Queue<KeyValuePair<IntPtr, IOSelectorJob>> queue, IntPtr handle, IOSelectorJob job)
3406 queue.Enqueue (new KeyValuePair<IntPtr, IOSelectorJob> (handle, job));
3407 count = queue.Count;
3411 IOSelector.Add (handle, job);
3414 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
3416 e.socket_async_result.Init (this, callback, state, operation);
3417 if (e.AcceptSocket != null) {
3418 e.socket_async_result.AcceptSocket = e.AcceptSocket;
3420 e.current_socket = this;
3421 e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
3422 e.SocketError = SocketError.Success;
3423 e.BytesTransferred = 0;
3426 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
3429 case SocketOperation.Connect:
3430 return SocketAsyncOperation.Connect;
3431 case SocketOperation.Accept:
3432 return SocketAsyncOperation.Accept;
3433 case SocketOperation.Disconnect:
3434 return SocketAsyncOperation.Disconnect;
3435 case SocketOperation.Receive:
3436 case SocketOperation.ReceiveGeneric:
3437 return SocketAsyncOperation.Receive;
3438 case SocketOperation.ReceiveFrom:
3439 return SocketAsyncOperation.ReceiveFrom;
3440 case SocketOperation.Send:
3441 case SocketOperation.SendGeneric:
3442 return SocketAsyncOperation.Send;
3443 case SocketOperation.SendTo:
3444 return SocketAsyncOperation.SendTo;
3446 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
3450 IPEndPoint RemapIPEndPoint (IPEndPoint input) {
3451 // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
3452 if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
3453 return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
3458 [StructLayout (LayoutKind.Sequential)]
3464 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3465 internal static extern void cancel_blocking_socket_operation (Thread thread);
3467 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3468 internal static extern bool SupportsPortReuse (ProtocolType proto);