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;
235 /* Microsoft sets these to 8192, but we are going to keep them
236 * both to the OS defaults as these have a big performance impact.
237 * on WebClient performance. */
238 // this.ReceiveBufferSize = 8192;
239 // this.SendBufferSize = 8192;
240 } catch (SocketException) {
244 /* Creates a new system socket, returning the handle */
245 [MethodImplAttribute(MethodImplOptions.InternalCall)]
246 extern IntPtr Socket_internal (AddressFamily family, SocketType type, ProtocolType proto, out int error);
252 [ObsoleteAttribute ("Use OSSupportsIPv4 instead")]
253 public static bool SupportsIPv4 {
254 get { return ipv4_supported == 1; }
257 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
258 public static bool SupportsIPv6 {
259 get { return ipv6_supported == 1; }
263 public static bool OSSupportsIPv4 {
264 get { return ipv4_supported == 1; }
267 public static bool OSSupportsIPv4 {
269 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
271 foreach (NetworkInterface adapter in nics) {
272 if (adapter.Supports (NetworkInterfaceComponent.IPv4))
282 public static bool OSSupportsIPv6 {
283 get { return ipv6_supported == 1; }
286 public static bool OSSupportsIPv6 {
288 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
290 foreach (NetworkInterface adapter in nics) {
291 if (adapter.Supports (NetworkInterfaceComponent.IPv6))
300 public int Available {
302 ThrowIfDisposedAndClosed ();
305 ret = Available_internal (safe_handle, out error);
308 throw new SocketException (error);
314 static int Available_internal (SafeSocketHandle safeHandle, out int error)
316 bool release = false;
318 safeHandle.DangerousAddRef (ref release);
319 return Available_internal (safeHandle.DangerousGetHandle (), out error);
322 safeHandle.DangerousRelease ();
326 /* Returns the amount of data waiting to be read on socket */
327 [MethodImplAttribute(MethodImplOptions.InternalCall)]
328 extern static int Available_internal (IntPtr socket, out int error);
330 public bool DontFragment {
332 ThrowIfDisposedAndClosed ();
334 switch (address_family) {
335 case AddressFamily.InterNetwork:
336 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment)) != 0;
337 case AddressFamily.InterNetworkV6:
338 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment)) != 0;
340 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
344 ThrowIfDisposedAndClosed ();
346 switch (address_family) {
347 case AddressFamily.InterNetwork:
348 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
350 case AddressFamily.InterNetworkV6:
351 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment, value ? 1 : 0);
354 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
359 public bool EnableBroadcast {
361 ThrowIfDisposedAndClosed ();
363 if (protocol_type != ProtocolType.Udp)
364 throw new SocketException ((int) SocketError.ProtocolOption);
366 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0;
369 ThrowIfDisposedAndClosed ();
371 if (protocol_type != ProtocolType.Udp)
372 throw new SocketException ((int) SocketError.ProtocolOption);
374 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
378 public bool ExclusiveAddressUse {
380 ThrowIfDisposedAndClosed ();
382 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse)) != 0;
385 ThrowIfDisposedAndClosed ();
388 throw new InvalidOperationException ("Bind has already been called for this socket");
390 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
394 public bool IsBound {
400 public LingerOption LingerState {
402 ThrowIfDisposedAndClosed ();
404 return (LingerOption) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger);
407 ThrowIfDisposedAndClosed ();
408 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger, value);
412 public bool MulticastLoopback {
414 ThrowIfDisposedAndClosed ();
416 /* Even though this option can be set for TCP sockets on Linux, throw
417 * this exception anyway to be compatible (the MSDN docs say
418 * "Setting this property on a Transmission Control Protocol (TCP)
419 * socket will have no effect." but the MS runtime throws the
421 if (protocol_type == ProtocolType.Tcp)
422 throw new SocketException ((int)SocketError.ProtocolOption);
424 switch (address_family) {
425 case AddressFamily.InterNetwork:
426 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
427 case AddressFamily.InterNetworkV6:
428 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
430 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
434 ThrowIfDisposedAndClosed ();
436 /* Even though this option can be set for TCP sockets on Linux, throw
437 * this exception anyway to be compatible (the MSDN docs say
438 * "Setting this property on a Transmission Control Protocol (TCP)
439 * socket will have no effect." but the MS runtime throws the
441 if (protocol_type == ProtocolType.Tcp)
442 throw new SocketException ((int)SocketError.ProtocolOption);
444 switch (address_family) {
445 case AddressFamily.InterNetwork:
446 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
448 case AddressFamily.InterNetworkV6:
449 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
452 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
457 public bool DualMode {
459 if (AddressFamily != AddressFamily.InterNetworkV6)
460 throw new NotSupportedException("This protocol version is not supported");
462 return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only) == 0);
465 if (AddressFamily != AddressFamily.InterNetworkV6)
466 throw new NotSupportedException("This protocol version is not supported");
468 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1);
472 private bool IsDualMode {
474 return AddressFamily == AddressFamily.InterNetworkV6 && DualMode;
478 [MonoTODO ("This doesn't do anything on Mono yet")]
479 public bool UseOnlyOverlappedIO {
480 get { return use_overlapped_io; }
481 set { use_overlapped_io = value; }
484 public IntPtr Handle {
485 get { return safe_handle.DangerousGetHandle (); }
488 // Wish: support non-IP endpoints.
489 public EndPoint LocalEndPoint {
491 ThrowIfDisposedAndClosed ();
493 /* If the seed EndPoint is null, Connect, Bind, etc has not yet
494 * been called. MS returns null in this case. */
495 if (seed_endpoint == null)
499 SocketAddress sa = LocalEndPoint_internal (safe_handle, (int) address_family, out error);
502 throw new SocketException (error);
504 return seed_endpoint.Create (sa);
508 static SocketAddress LocalEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
510 bool release = false;
512 safeHandle.DangerousAddRef (ref release);
513 return LocalEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
516 safeHandle.DangerousRelease ();
520 /* Returns the local endpoint details in addr and port */
521 [MethodImplAttribute(MethodImplOptions.InternalCall)]
522 extern static SocketAddress LocalEndPoint_internal (IntPtr socket, int family, out int error);
524 public SocketType SocketType {
525 get { return socket_type; }
528 public int SendTimeout {
530 ThrowIfDisposedAndClosed ();
532 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
535 ThrowIfDisposedAndClosed ();
538 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
540 /* According to the MSDN docs we should adjust values between 1 and
541 * 499 to 500, but the MS runtime doesn't do this. */
545 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
549 public int ReceiveTimeout {
551 ThrowIfDisposedAndClosed ();
553 return (int) GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
556 ThrowIfDisposedAndClosed ();
559 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
564 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, value);
568 public AddressFamily AddressFamily {
569 get { return address_family; }
572 public bool Blocking {
573 get { return is_blocking; }
575 ThrowIfDisposedAndClosed ();
578 Blocking_internal (safe_handle, value, out error);
581 throw new SocketException (error);
587 static void Blocking_internal (SafeSocketHandle safeHandle, bool block, out int error)
589 bool release = false;
591 safeHandle.DangerousAddRef (ref release);
592 Blocking_internal (safeHandle.DangerousGetHandle (), block, out error);
595 safeHandle.DangerousRelease ();
599 [MethodImplAttribute(MethodImplOptions.InternalCall)]
600 internal extern static void Blocking_internal(IntPtr socket, bool block, out int error);
602 public bool Connected {
603 get { return is_connected; }
604 internal set { is_connected = value; }
607 public ProtocolType ProtocolType {
608 get { return protocol_type; }
611 public bool NoDelay {
613 ThrowIfDisposedAndClosed ();
616 return ((int) GetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay)) != 0;
620 ThrowIfDisposedAndClosed ();
623 SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
627 public int ReceiveBufferSize {
629 ThrowIfDisposedAndClosed ();
631 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer);
634 ThrowIfDisposedAndClosed ();
637 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
639 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
643 public int SendBufferSize {
645 ThrowIfDisposedAndClosed ();
647 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer);
650 ThrowIfDisposedAndClosed ();
653 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
655 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer, value);
661 ThrowIfDisposedAndClosed ();
663 switch (address_family) {
664 case AddressFamily.InterNetwork:
665 return (short) (int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
666 case AddressFamily.InterNetworkV6:
667 return (short) (int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit);
669 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
673 ThrowIfDisposedAndClosed ();
675 if (value < 0 || value > 255)
676 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero or greater than 255.");
678 switch (address_family) {
679 case AddressFamily.InterNetwork:
680 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
682 case AddressFamily.InterNetworkV6:
683 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
686 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
691 public EndPoint RemoteEndPoint {
693 ThrowIfDisposedAndClosed ();
695 /* If the seed EndPoint is null, Connect, Bind, etc has
696 * not yet been called. MS returns null in this case. */
697 if (!is_connected || seed_endpoint == null)
701 SocketAddress sa = RemoteEndPoint_internal (safe_handle, (int) address_family, out error);
704 throw new SocketException (error);
706 return seed_endpoint.Create (sa);
710 static SocketAddress RemoteEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
712 bool release = false;
714 safeHandle.DangerousAddRef (ref release);
715 return RemoteEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
718 safeHandle.DangerousRelease ();
722 /* Returns the remote endpoint details in addr and port */
723 [MethodImplAttribute(MethodImplOptions.InternalCall)]
724 extern static SocketAddress RemoteEndPoint_internal (IntPtr socket, int family, out int error);
730 public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
732 var list = new List<Socket> ();
733 AddSockets (list, checkRead, "checkRead");
734 AddSockets (list, checkWrite, "checkWrite");
735 AddSockets (list, checkError, "checkError");
738 throw new ArgumentNullException ("checkRead, checkWrite, checkError", "All the lists are null or empty.");
740 /* The 'sockets' array contains:
741 * - READ socket 0-n, null,
742 * - WRITE socket 0-n, null,
743 * - ERROR socket 0-n, null */
744 Socket [] sockets = list.ToArray ();
747 Select_internal (ref sockets, microSeconds, out error);
750 throw new SocketException (error);
752 if (sockets == null) {
753 if (checkRead != null)
755 if (checkWrite != null)
757 if (checkError != null)
763 int count = sockets.Length;
764 IList currentList = checkRead;
766 for (int i = 0; i < count; i++) {
767 Socket sock = sockets [i];
768 if (sock == null) { // separator
769 if (currentList != null) {
770 // Remove non-signaled sockets after the current one
771 int to_remove = currentList.Count - currentIdx;
772 for (int k = 0; k < to_remove; k++)
773 currentList.RemoveAt (currentIdx);
775 currentList = (mode == 0) ? checkWrite : checkError;
781 if (mode == 1 && currentList == checkWrite && !sock.is_connected) {
782 if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
783 sock.is_connected = true;
786 /* Remove non-signaled sockets before the current one */
787 while (((Socket) currentList [currentIdx]) != sock)
788 currentList.RemoveAt (currentIdx);
794 static void AddSockets (List<Socket> sockets, IList list, string name)
797 foreach (Socket sock in list) {
798 if (sock == null) // MS throws a NullRef
799 throw new ArgumentNullException ("name", "Contains a null element");
807 [MethodImplAttribute(MethodImplOptions.InternalCall)]
808 extern static void Select_internal (ref Socket [] sockets, int microSeconds, out int error);
814 public bool Poll (int microSeconds, SelectMode mode)
816 ThrowIfDisposedAndClosed ();
818 if (mode != SelectMode.SelectRead && mode != SelectMode.SelectWrite && mode != SelectMode.SelectError)
819 throw new NotSupportedException ("'mode' parameter is not valid.");
822 bool result = Poll_internal (safe_handle, mode, microSeconds, out error);
825 throw new SocketException (error);
827 if (mode == SelectMode.SelectWrite && result && !is_connected) {
828 /* Update the is_connected state; for non-blocking Connect()
829 * this is when we can find out that the connect succeeded. */
830 if ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
837 static bool Poll_internal (SafeSocketHandle safeHandle, SelectMode mode, int timeout, out int error)
839 bool release = false;
841 safeHandle.DangerousAddRef (ref release);
842 return Poll_internal (safeHandle.DangerousGetHandle (), mode, timeout, out error);
845 safeHandle.DangerousRelease ();
849 [MethodImplAttribute(MethodImplOptions.InternalCall)]
850 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
856 public Socket Accept()
858 ThrowIfDisposedAndClosed ();
861 SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
865 error = SOCKET_CLOSED_CODE;
866 throw new SocketException(error);
869 Socket accepted = new Socket (this.AddressFamily, this.SocketType, this.ProtocolType, safe_handle) {
870 seed_endpoint = this.seed_endpoint,
871 Blocking = this.Blocking,
877 internal void Accept (Socket acceptSocket)
879 ThrowIfDisposedAndClosed ();
882 SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
886 error = SOCKET_CLOSED_CODE;
887 throw new SocketException (error);
890 acceptSocket.address_family = this.AddressFamily;
891 acceptSocket.socket_type = this.SocketType;
892 acceptSocket.protocol_type = this.ProtocolType;
893 acceptSocket.safe_handle = safe_handle;
894 acceptSocket.is_connected = true;
895 acceptSocket.seed_endpoint = this.seed_endpoint;
896 acceptSocket.Blocking = this.Blocking;
898 // FIXME: figure out what if anything else needs to be reset
901 public bool AcceptAsync (SocketAsyncEventArgs e)
903 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
905 ThrowIfDisposedAndClosed ();
908 throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
910 throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
911 if (e.BufferList != null)
912 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
914 throw new ArgumentOutOfRangeException ("e.Count");
916 Socket acceptSocket = e.AcceptSocket;
917 if (acceptSocket != null) {
918 if (acceptSocket.is_bound || acceptSocket.is_connected)
919 throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
922 InitSocketAsyncEventArgs (e, AcceptAsyncCallback, e, SocketOperation.Accept);
924 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, e.socket_async_result));
929 static AsyncCallback AcceptAsyncCallback = new AsyncCallback (ares => {
930 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
932 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
933 throw new InvalidOperationException ("No operation in progress");
936 e.AcceptSocket = e.current_socket.EndAccept (ares);
937 } catch (SocketException ex) {
938 e.SocketError = ex.SocketErrorCode;
939 } catch (ObjectDisposedException) {
940 e.SocketError = SocketError.OperationAborted;
942 if (e.AcceptSocket == null)
943 e.AcceptSocket = new Socket (e.current_socket.AddressFamily, e.current_socket.SocketType, e.current_socket.ProtocolType, null);
948 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
950 ThrowIfDisposedAndClosed ();
952 if (!is_bound || !is_listening)
953 throw new InvalidOperationException ();
955 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Accept);
957 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, sockares));
962 static IOAsyncCallback BeginAcceptCallback = new IOAsyncCallback (ares => {
963 SocketAsyncResult sockares = (SocketAsyncResult) ares;
964 Socket acc_socket = null;
966 if (sockares.AcceptSocket == null) {
967 acc_socket = sockares.socket.Accept ();
969 acc_socket = sockares.AcceptSocket;
970 sockares.socket.Accept (acc_socket);
973 } catch (Exception e) {
974 sockares.Complete (e);
977 sockares.Complete (acc_socket);
980 public IAsyncResult BeginAccept (int receiveSize, AsyncCallback callback, object state)
982 ThrowIfDisposedAndClosed ();
985 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
987 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
988 Buffer = new byte [receiveSize],
991 SockFlags = SocketFlags.None,
994 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
999 public IAsyncResult BeginAccept (Socket acceptSocket, int receiveSize, AsyncCallback callback, object state)
1001 ThrowIfDisposedAndClosed ();
1003 if (receiveSize < 0)
1004 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
1006 if (acceptSocket != null) {
1007 ThrowIfDisposedAndClosed (acceptSocket);
1009 if (acceptSocket.IsBound)
1010 throw new InvalidOperationException ();
1012 /* For some reason the MS runtime
1013 * barfs if the new socket is not TCP,
1014 * even though it's just about to blow
1015 * away all those parameters
1017 if (acceptSocket.ProtocolType != ProtocolType.Tcp)
1018 throw new SocketException ((int)SocketError.InvalidArgument);
1021 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
1022 Buffer = new byte [receiveSize],
1025 SockFlags = SocketFlags.None,
1026 AcceptSocket = acceptSocket,
1029 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
1034 static IOAsyncCallback BeginAcceptReceiveCallback = new IOAsyncCallback (ares => {
1035 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1036 Socket acc_socket = null;
1039 if (sockares.AcceptSocket == null) {
1040 acc_socket = sockares.socket.Accept ();
1042 acc_socket = sockares.AcceptSocket;
1043 sockares.socket.Accept (acc_socket);
1045 } catch (Exception e) {
1046 sockares.Complete (e);
1050 /* It seems the MS runtime special-cases 0-length requested receive data. See bug 464201. */
1052 if (sockares.Size > 0) {
1055 total = acc_socket.Receive_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out error);
1057 sockares.Complete (new SocketException ((int) error));
1060 } catch (Exception e) {
1061 sockares.Complete (e);
1066 sockares.Complete (acc_socket, total);
1069 public Socket EndAccept (IAsyncResult result)
1073 return EndAccept (out buffer, out bytes, result);
1076 public Socket EndAccept (out byte[] buffer, IAsyncResult asyncResult)
1079 return EndAccept (out buffer, out bytes, asyncResult);
1082 public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
1084 ThrowIfDisposedAndClosed ();
1086 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndAccept", "asyncResult");
1088 if (!sockares.IsCompleted)
1089 sockares.AsyncWaitHandle.WaitOne ();
1091 sockares.CheckIfThrowDelayedException ();
1093 buffer = sockares.Buffer;
1094 bytesTransferred = sockares.Total;
1096 return sockares.AcceptedSocket;
1099 static SafeSocketHandle Accept_internal (SafeSocketHandle safeHandle, out int error, bool blocking)
1102 safeHandle.RegisterForBlockingSyscall ();
1103 var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
1104 return new SafeSocketHandle (ret, true);
1106 safeHandle.UnRegisterForBlockingSyscall ();
1110 /* Creates a new system socket, returning the handle */
1111 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1112 extern static IntPtr Accept_internal (IntPtr sock, out int error, bool blocking);
1118 public void Bind (EndPoint localEP)
1120 ThrowIfDisposedAndClosed ();
1122 if (localEP == null)
1123 throw new ArgumentNullException("localEP");
1125 var ipEndPoint = localEP as IPEndPoint;
1126 if (ipEndPoint != null) {
1127 localEP = RemapIPEndPoint (ipEndPoint);
1131 Bind_internal (safe_handle, localEP.Serialize(), out error);
1134 throw new SocketException (error);
1138 seed_endpoint = localEP;
1141 private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1143 bool release = false;
1145 safeHandle.DangerousAddRef (ref release);
1146 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
1149 safeHandle.DangerousRelease ();
1153 // Creates a new system socket, returning the handle
1154 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1155 private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
1161 public void Listen (int backlog)
1163 ThrowIfDisposedAndClosed ();
1166 throw new SocketException ((int) SocketError.InvalidArgument);
1169 Listen_internal(safe_handle, backlog, out error);
1172 throw new SocketException (error);
1174 is_listening = true;
1177 static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
1179 bool release = false;
1181 safeHandle.DangerousAddRef (ref release);
1182 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
1185 safeHandle.DangerousRelease ();
1189 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1190 extern static void Listen_internal (IntPtr sock, int backlog, out int error);
1196 public void Connect (IPAddress address, int port)
1198 Connect (new IPEndPoint (address, port));
1201 public void Connect (string host, int port)
1203 Connect (Dns.GetHostAddresses (host), port);
1206 public void Connect (IPAddress[] addresses, int port)
1208 ThrowIfDisposedAndClosed ();
1210 if (addresses == null)
1211 throw new ArgumentNullException ("addresses");
1212 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1213 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1215 throw new InvalidOperationException ();
1217 // FIXME: do non-blocking sockets Poll here?
1219 foreach (IPAddress address in addresses) {
1220 IPEndPoint iep = new IPEndPoint (address, port);
1222 iep = RemapIPEndPoint (iep);
1224 Connect_internal (safe_handle, iep.Serialize (), out error);
1226 is_connected = true;
1228 seed_endpoint = iep;
1231 if (error != (int)SocketError.InProgress && error != (int)SocketError.WouldBlock)
1235 Poll (-1, SelectMode.SelectWrite);
1236 error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1238 is_connected = true;
1240 seed_endpoint = iep;
1247 throw new SocketException (error);
1251 public void Connect (EndPoint remoteEP)
1253 ThrowIfDisposedAndClosed ();
1255 if (remoteEP == null)
1256 throw new ArgumentNullException ("remoteEP");
1258 IPEndPoint ep = remoteEP as IPEndPoint;
1259 /* Dgram uses Any to 'disconnect' */
1260 if (ep != null && socket_type != SocketType.Dgram) {
1261 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1262 throw new SocketException ((int) SocketError.AddressNotAvailable);
1266 throw new InvalidOperationException ();
1269 remoteEP = RemapIPEndPoint (ep);
1272 SocketAddress serial = remoteEP.Serialize ();
1275 Connect_internal (safe_handle, serial, out error);
1277 if (error == 0 || error == 10035)
1278 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1282 error = SOCKET_CLOSED_CODE;
1283 throw new SocketException (error);
1286 is_connected = !(socket_type == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
1290 public bool ConnectAsync (SocketAsyncEventArgs e)
1292 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1294 ThrowIfDisposedAndClosed ();
1297 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1298 if (e.RemoteEndPoint == null)
1299 throw new ArgumentNullException ("remoteEP");
1301 InitSocketAsyncEventArgs (e, null, e, SocketOperation.Connect);
1304 IPAddress [] addresses;
1305 SocketAsyncResult ares;
1307 if (!GetCheckedIPs (e, out addresses)) {
1308 e.socket_async_result.EndPoint = e.RemoteEndPoint;
1309 ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
1311 DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1312 e.socket_async_result.Addresses = addresses;
1313 e.socket_async_result.Port = dep.Port;
1314 ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
1317 if (ares.IsCompleted && ares.CompletedSynchronously) {
1318 ares.CheckIfThrowDelayedException ();
1321 } catch (Exception exc) {
1322 e.socket_async_result.Complete (exc, true);
1329 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
1331 var sock = new Socket (e.RemoteEndPoint.AddressFamily, socketType, protocolType);
1332 return sock.ConnectAsync (e);
1335 public static void CancelConnectAsync (SocketAsyncEventArgs e)
1338 throw new ArgumentNullException("e");
1340 if (e.in_progress != 0 && e.LastOperation == SocketAsyncOperation.Connect)
1341 e.current_socket.Close();
1344 static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
1345 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1347 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1348 throw new InvalidOperationException ("No operation in progress");
1351 e.current_socket.EndConnect (ares);
1352 } catch (SocketException se) {
1353 e.SocketError = se.SocketErrorCode;
1354 } catch (ObjectDisposedException) {
1355 e.SocketError = SocketError.OperationAborted;
1361 public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback callback, object state)
1363 ThrowIfDisposedAndClosed ();
1365 if (address == null)
1366 throw new ArgumentNullException ("address");
1367 if (address.ToString ().Length == 0)
1368 throw new ArgumentException ("The length of the IP address is zero");
1369 if (port <= 0 || port > 65535)
1370 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1372 throw new InvalidOperationException ();
1374 return BeginConnect (new IPEndPoint (address, port), callback, state);
1377 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
1379 ThrowIfDisposedAndClosed ();
1382 throw new ArgumentNullException ("host");
1383 if (address_family != AddressFamily.InterNetwork && address_family != AddressFamily.InterNetworkV6)
1384 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1385 if (port <= 0 || port > 65535)
1386 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1388 throw new InvalidOperationException ();
1390 return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1393 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
1395 ThrowIfDisposedAndClosed ();
1397 if (end_point == null)
1398 throw new ArgumentNullException ("end_point");
1400 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1401 EndPoint = end_point,
1404 // Bug #75154: Connect() should not succeed for .Any addresses.
1405 if (end_point is IPEndPoint) {
1406 IPEndPoint ep = (IPEndPoint) end_point;
1407 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1408 sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1412 end_point = RemapIPEndPoint (ep);
1417 if (connect_in_progress) {
1418 // This could happen when multiple IPs are used
1419 // Calling connect() again will reset the connection attempt and cause
1420 // an error. Better to just close the socket and move on.
1421 connect_in_progress = false;
1422 safe_handle.Dispose ();
1423 safe_handle = new SafeSocketHandle (Socket_internal (address_family, socket_type, protocol_type, out error), true);
1425 throw new SocketException (error);
1428 bool blk = is_blocking;
1431 Connect_internal (safe_handle, end_point.Serialize (), out error);
1437 is_connected = true;
1439 sockares.Complete (true);
1443 if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1445 is_connected = false;
1447 sockares.Complete (new SocketException (error), true);
1452 is_connected = false;
1454 connect_in_progress = true;
1456 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
1461 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1463 ThrowIfDisposedAndClosed ();
1465 if (addresses == null)
1466 throw new ArgumentNullException ("addresses");
1467 if (addresses.Length == 0)
1468 throw new ArgumentException ("Empty addresses list");
1469 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1470 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1471 if (port <= 0 || port > 65535)
1472 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1474 throw new InvalidOperationException ();
1476 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1477 Addresses = addresses,
1481 is_connected = false;
1483 return BeginMConnect (sockares);
1486 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1488 SocketAsyncResult ares = null;
1489 Exception exc = null;
1490 AsyncCallback callback;
1492 for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1494 sockares.CurrentAddress++;
1496 ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1497 if (ares.IsCompleted && ares.CompletedSynchronously) {
1498 ares.CheckIfThrowDelayedException ();
1500 callback = ares.AsyncCallback;
1501 if (callback != null)
1502 ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
1506 } catch (Exception e) {
1518 static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
1519 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1521 if (sockares.EndPoint == null) {
1522 sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
1526 SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
1527 bool is_mconnect = mconnect != null && mconnect.Addresses != null;
1530 EndPoint ep = sockares.EndPoint;
1531 int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1533 if (error_code == 0) {
1535 sockares = mconnect;
1537 sockares.socket.seed_endpoint = ep;
1538 sockares.socket.is_connected = true;
1539 sockares.socket.is_bound = true;
1540 sockares.socket.connect_in_progress = false;
1542 sockares.Complete ();
1547 sockares.socket.connect_in_progress = false;
1548 sockares.Complete (new SocketException (error_code));
1552 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
1553 mconnect.Complete (new SocketException (error_code));
1557 mconnect.socket.BeginMConnect (mconnect);
1558 } catch (Exception e) {
1559 sockares.socket.connect_in_progress = false;
1562 sockares = mconnect;
1564 sockares.Complete (e);
1569 public void EndConnect (IAsyncResult result)
1571 ThrowIfDisposedAndClosed ();
1573 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1575 if (!sockares.IsCompleted)
1576 sockares.AsyncWaitHandle.WaitOne();
1578 sockares.CheckIfThrowDelayedException();
1581 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1584 safeHandle.RegisterForBlockingSyscall ();
1585 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
1587 safeHandle.UnRegisterForBlockingSyscall ();
1591 /* Connects to the remote address */
1592 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1593 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error);
1596 * - false when it is ok to use RemoteEndPoint
1597 * - true when addresses must be used (and addresses could be null/empty) */
1598 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1602 // Connect to the first address that match the host name, like:
1603 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1604 // while skipping entries that do not match the address family
1605 DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1607 addresses = Dns.GetHostAddresses (dep.Host);
1610 e.ConnectByNameError = null;
1619 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1620 * if the platform is newer than w2k. We should be able to cope... */
1621 public void Disconnect (bool reuseSocket)
1623 ThrowIfDisposedAndClosed ();
1626 Disconnect_internal (safe_handle, reuseSocket, out error);
1630 /* ERROR_NOT_SUPPORTED */
1631 throw new PlatformNotSupportedException ();
1633 throw new SocketException (error);
1637 is_connected = false;
1639 /* Do managed housekeeping here... */
1643 public bool DisconnectAsync (SocketAsyncEventArgs e)
1645 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1647 ThrowIfDisposedAndClosed ();
1649 InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
1651 IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
1656 static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
1657 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1659 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1660 throw new InvalidOperationException ("No operation in progress");
1663 e.current_socket.EndDisconnect (ares);
1664 } catch (SocketException ex) {
1665 e.SocketError = ex.SocketErrorCode;
1666 } catch (ObjectDisposedException) {
1667 e.SocketError = SocketError.OperationAborted;
1673 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1675 ThrowIfDisposedAndClosed ();
1677 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1678 ReuseSocket = reuseSocket,
1681 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
1686 static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
1687 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1690 sockares.socket.Disconnect (sockares.ReuseSocket);
1691 } catch (Exception e) {
1692 sockares.Complete (e);
1696 sockares.Complete ();
1699 public void EndDisconnect (IAsyncResult asyncResult)
1701 ThrowIfDisposedAndClosed ();
1703 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1705 if (!sockares.IsCompleted)
1706 sockares.AsyncWaitHandle.WaitOne ();
1708 sockares.CheckIfThrowDelayedException ();
1711 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1713 bool release = false;
1715 safeHandle.DangerousAddRef (ref release);
1716 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1719 safeHandle.DangerousRelease ();
1723 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1724 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1730 public int Receive (byte [] buffer)
1732 return Receive (buffer, SocketFlags.None);
1735 public int Receive (byte [] buffer, SocketFlags socketFlags)
1737 ThrowIfDisposedAndClosed ();
1738 ThrowIfBufferNull (buffer);
1739 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
1742 int ret = Receive_nochecks (buffer, 0, buffer.Length, socketFlags, out error);
1744 if (error != SocketError.Success) {
1745 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1746 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1747 throw new SocketException ((int) error);
1753 public int Receive (byte [] buffer, int size, SocketFlags socketFlags)
1755 ThrowIfDisposedAndClosed ();
1756 ThrowIfBufferNull (buffer);
1757 ThrowIfBufferOutOfRange (buffer, 0, size);
1760 int ret = Receive_nochecks (buffer, 0, size, socketFlags, out error);
1762 if (error != SocketError.Success) {
1763 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1764 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1765 throw new SocketException ((int) error);
1771 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags)
1773 ThrowIfDisposedAndClosed ();
1774 ThrowIfBufferNull (buffer);
1775 ThrowIfBufferOutOfRange (buffer, offset, size);
1778 int ret = Receive_nochecks (buffer, offset, size, socketFlags, out error);
1780 if (error != SocketError.Success) {
1781 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1782 throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1783 throw new SocketException ((int) error);
1789 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1791 ThrowIfDisposedAndClosed ();
1792 ThrowIfBufferNull (buffer);
1793 ThrowIfBufferOutOfRange (buffer, offset, size);
1795 return Receive_nochecks (buffer, offset, size, socketFlags, out errorCode);
1798 public int Receive (IList<ArraySegment<byte>> buffers)
1801 int ret = Receive (buffers, SocketFlags.None, out error);
1803 if (error != SocketError.Success)
1804 throw new SocketException ((int) error);
1809 [CLSCompliant (false)]
1810 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1813 int ret = Receive (buffers, socketFlags, out error);
1815 if (error != SocketError.Success)
1816 throw new SocketException ((int) error);
1821 [CLSCompliant (false)]
1822 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1824 ThrowIfDisposedAndClosed ();
1826 if (buffers == null || buffers.Count == 0)
1827 throw new ArgumentNullException ("buffers");
1829 int numsegments = buffers.Count;
1833 /* Only example I can find of sending a byte array reference directly into an internal
1834 * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1835 * so taking a lead from that... */
1836 WSABUF[] bufarray = new WSABUF[numsegments];
1837 GCHandle[] gch = new GCHandle[numsegments];
1839 for (int i = 0; i < numsegments; i++) {
1840 ArraySegment<byte> segment = buffers[i];
1842 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1843 throw new ArgumentOutOfRangeException ("segment");
1845 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1846 bufarray[i].len = segment.Count;
1847 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1851 ret = Receive_internal (safe_handle, bufarray, socketFlags, out nativeError);
1853 for (int i = 0; i < numsegments; i++) {
1854 if (gch[i].IsAllocated)
1859 errorCode = (SocketError) nativeError;
1864 public bool ReceiveAsync (SocketAsyncEventArgs e)
1866 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1868 ThrowIfDisposedAndClosed ();
1870 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1871 // thrown when e.Buffer and e.BufferList are null (works fine when one is
1872 // set to a valid object)
1873 if (e.Buffer == null && e.BufferList == null)
1874 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1876 if (e.Buffer == null) {
1877 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
1879 e.socket_async_result.Buffers = e.BufferList;
1881 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
1883 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
1885 e.socket_async_result.Buffer = e.Buffer;
1886 e.socket_async_result.Offset = e.Offset;
1887 e.socket_async_result.Size = e.Count;
1889 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
1895 static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
1896 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1898 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1899 throw new InvalidOperationException ("No operation in progress");
1902 e.BytesTransferred = e.current_socket.EndReceive (ares);
1903 } catch (SocketException se){
1904 e.SocketError = se.SocketErrorCode;
1905 } catch (ObjectDisposedException) {
1906 e.SocketError = SocketError.OperationAborted;
1912 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
1914 ThrowIfDisposedAndClosed ();
1915 ThrowIfBufferNull (buffer);
1916 ThrowIfBufferOutOfRange (buffer, offset, size);
1918 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1922 SockFlags = socket_flags,
1925 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
1930 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags flags, out SocketError error, AsyncCallback callback, object state)
1932 /* As far as I can tell from the docs and from experimentation, a pointer to the
1933 * SocketError parameter is not supposed to be saved for the async parts. And as we don't
1934 * set any socket errors in the setup code, we just have to set it to Success. */
1935 error = SocketError.Success;
1936 return BeginReceive (buffer, offset, size, flags, callback, state);
1939 static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
1940 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1944 total = Receive_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
1945 } catch (Exception e) {
1946 sockares.Complete (e);
1950 sockares.Complete (total);
1953 [CLSCompliant (false)]
1954 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
1956 ThrowIfDisposedAndClosed ();
1958 if (buffers == null)
1959 throw new ArgumentNullException ("buffers");
1961 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1963 SockFlags = socketFlags,
1966 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
1971 [CLSCompliant (false)]
1972 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1974 /* I assume the same SocketError semantics as above */
1975 errorCode = SocketError.Success;
1976 return BeginReceive (buffers, socketFlags, callback, state);
1979 static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
1980 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1984 total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
1985 } catch (Exception e) {
1986 sockares.Complete (e);
1990 sockares.Complete (total);
1993 public int EndReceive (IAsyncResult result)
1996 int bytesReceived = EndReceive (result, out error);
1998 if (error != SocketError.Success) {
1999 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2000 is_connected = false;
2001 throw new SocketException ((int)error);
2004 return bytesReceived;
2007 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
2009 ThrowIfDisposedAndClosed ();
2011 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
2013 if (!sockares.IsCompleted)
2014 sockares.AsyncWaitHandle.WaitOne ();
2016 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
2017 // kinds of exceptions that should be thrown.
2018 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2019 sockares.CheckIfThrowDelayedException();
2021 return sockares.Total;
2024 int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2027 int ret = Receive_internal (safe_handle, buf, offset, size, flags, out nativeError);
2029 error = (SocketError) nativeError;
2030 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2031 is_connected = false;
2034 is_connected = true;
2040 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2043 safeHandle.RegisterForBlockingSyscall ();
2044 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2046 safeHandle.UnRegisterForBlockingSyscall ();
2050 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2051 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2053 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
2056 safeHandle.RegisterForBlockingSyscall ();
2057 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
2059 safeHandle.UnRegisterForBlockingSyscall ();
2063 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2064 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error);
2070 public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
2072 ThrowIfDisposedAndClosed ();
2073 ThrowIfBufferNull (buffer);
2075 return ReceiveFrom (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
2078 public int ReceiveFrom (byte [] buffer, SocketFlags socketFlags, ref EndPoint remoteEP)
2080 ThrowIfDisposedAndClosed ();
2081 ThrowIfBufferNull (buffer);
2083 return ReceiveFrom (buffer, 0, buffer.Length, socketFlags, ref remoteEP);
2086 public int ReceiveFrom (byte [] buffer, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
2088 ThrowIfDisposedAndClosed ();
2089 ThrowIfBufferNull (buffer);
2090 ThrowIfBufferOutOfRange (buffer, 0, size);
2092 return ReceiveFrom (buffer, 0, size, socketFlags, ref remoteEP);
2095 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
2097 ThrowIfDisposedAndClosed ();
2098 ThrowIfBufferNull (buffer);
2099 ThrowIfBufferOutOfRange (buffer, offset, size);
2101 if (remoteEP == null)
2102 throw new ArgumentNullException ("remoteEP");
2105 return ReceiveFrom_nochecks_exc (buffer, offset, size, socketFlags, ref remoteEP, true, out error);
2108 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
2110 ThrowIfDisposedAndClosed ();
2112 // We do not support recv into multiple buffers yet
2113 if (e.BufferList != null)
2114 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2115 if (e.RemoteEndPoint == null)
2116 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2118 InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
2120 e.socket_async_result.Buffer = e.Buffer;
2121 e.socket_async_result.Offset = e.Offset;
2122 e.socket_async_result.Size = e.Count;
2123 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2124 e.socket_async_result.SockFlags = e.SocketFlags;
2126 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
2131 static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
2132 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2134 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2135 throw new InvalidOperationException ("No operation in progress");
2138 e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
2139 } catch (SocketException ex) {
2140 e.SocketError = ex.SocketErrorCode;
2141 } catch (ObjectDisposedException) {
2142 e.SocketError = SocketError.OperationAborted;
2148 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
2150 ThrowIfDisposedAndClosed ();
2151 ThrowIfBufferNull (buffer);
2152 ThrowIfBufferOutOfRange (buffer, offset, size);
2154 if (remote_end == null)
2155 throw new ArgumentNullException ("remote_end");
2157 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
2161 SockFlags = socket_flags,
2162 EndPoint = remote_end,
2165 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
2170 static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
2171 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2176 total = sockares.socket.ReceiveFrom_nochecks_exc (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, true, out error);
2177 } catch (Exception e) {
2178 sockares.Complete (e);
2182 sockares.Complete (total);
2185 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
2187 ThrowIfDisposedAndClosed ();
2189 if (end_point == null)
2190 throw new ArgumentNullException ("remote_end");
2192 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
2194 if (!sockares.IsCompleted)
2195 sockares.AsyncWaitHandle.WaitOne();
2197 sockares.CheckIfThrowDelayedException();
2199 end_point = sockares.EndPoint;
2201 return sockares.Total;
2204 internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end, bool throwOnError, out int error)
2206 SocketAddress sockaddr = remote_end.Serialize();
2208 int cnt = ReceiveFrom_internal (safe_handle, buf, offset, size, flags, ref sockaddr, out error);
2210 SocketError err = (SocketError) error;
2212 if (err != SocketError.WouldBlock && err != SocketError.InProgress) {
2213 is_connected = false;
2214 } else if (err == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
2216 throw new SocketException ((int) SocketError.TimedOut, TIMEOUT_EXCEPTION_MSG);
2217 error = (int) SocketError.TimedOut;
2222 throw new SocketException (error);
2227 is_connected = true;
2230 /* If sockaddr is null then we're a connection oriented protocol and should ignore the
2231 * remote_end parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
2232 if (sockaddr != null) {
2233 /* Stupidly, EndPoint.Create() is an instance method */
2234 remote_end = remote_end.Create (sockaddr);
2237 seed_endpoint = remote_end;
2242 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error)
2245 safeHandle.RegisterForBlockingSyscall ();
2246 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
2248 safeHandle.UnRegisterForBlockingSyscall ();
2252 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2253 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error);
2257 #region ReceiveMessageFrom
2259 [MonoTODO ("Not implemented")]
2260 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
2262 ThrowIfDisposedAndClosed ();
2263 ThrowIfBufferNull (buffer);
2264 ThrowIfBufferOutOfRange (buffer, offset, size);
2266 if (remoteEP == null)
2267 throw new ArgumentNullException ("remoteEP");
2269 // FIXME: figure out how we get hold of the IPPacketInformation
2270 throw new NotImplementedException ();
2273 [MonoTODO ("Not implemented")]
2274 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
2276 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2278 ThrowIfDisposedAndClosed ();
2280 throw new NotImplementedException ();
2284 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
2286 ThrowIfDisposedAndClosed ();
2287 ThrowIfBufferNull (buffer);
2288 ThrowIfBufferOutOfRange (buffer, offset, size);
2290 if (remoteEP == null)
2291 throw new ArgumentNullException ("remoteEP");
2293 throw new NotImplementedException ();
2297 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
2299 ThrowIfDisposedAndClosed ();
2301 if (endPoint == null)
2302 throw new ArgumentNullException ("endPoint");
2304 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
2306 throw new NotImplementedException ();
2313 public int Send (byte [] buffer)
2315 ThrowIfDisposedAndClosed ();
2316 ThrowIfBufferNull (buffer);
2317 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2320 int ret = Send_nochecks (buffer, 0, buffer.Length, SocketFlags.None, out error);
2322 if (error != SocketError.Success)
2323 throw new SocketException ((int) error);
2328 public int Send (byte [] buffer, SocketFlags socketFlags)
2330 ThrowIfDisposedAndClosed ();
2331 ThrowIfBufferNull (buffer);
2332 ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2335 int ret = Send_nochecks (buffer, 0, buffer.Length, socketFlags, out error);
2337 if (error != SocketError.Success)
2338 throw new SocketException ((int) error);
2343 public int Send (byte [] buffer, int size, SocketFlags socketFlags)
2345 ThrowIfDisposedAndClosed ();
2346 ThrowIfBufferNull (buffer);
2347 ThrowIfBufferOutOfRange (buffer, 0, size);
2350 int ret = Send_nochecks (buffer, 0, size, socketFlags, out error);
2352 if (error != SocketError.Success)
2353 throw new SocketException ((int) error);
2358 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags)
2360 ThrowIfDisposedAndClosed ();
2361 ThrowIfBufferNull (buffer);
2362 ThrowIfBufferOutOfRange (buffer, offset, size);
2365 int ret = Send_nochecks (buffer, offset, size, socketFlags, out error);
2367 if (error != SocketError.Success)
2368 throw new SocketException ((int) error);
2373 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
2375 ThrowIfDisposedAndClosed ();
2376 ThrowIfBufferNull (buffer);
2377 ThrowIfBufferOutOfRange (buffer, offset, size);
2379 return Send_nochecks (buffer, offset, size, socketFlags, out errorCode);
2383 int Send (IList<ArraySegment<byte>> buffers)
2386 int ret = Send (buffers, SocketFlags.None, out error);
2388 if (error != SocketError.Success)
2389 throw new SocketException ((int) error);
2395 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
2398 int ret = Send (buffers, socketFlags, out error);
2400 if (error != SocketError.Success)
2401 throw new SocketException ((int) error);
2406 [CLSCompliant (false)]
2407 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
2409 ThrowIfDisposedAndClosed ();
2411 if (buffers == null)
2412 throw new ArgumentNullException ("buffers");
2413 if (buffers.Count == 0)
2414 throw new ArgumentException ("Buffer is empty", "buffers");
2416 int numsegments = buffers.Count;
2420 WSABUF[] bufarray = new WSABUF[numsegments];
2421 GCHandle[] gch = new GCHandle[numsegments];
2423 for(int i = 0; i < numsegments; i++) {
2424 ArraySegment<byte> segment = buffers[i];
2426 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
2427 throw new ArgumentOutOfRangeException ("segment");
2429 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
2430 bufarray[i].len = segment.Count;
2431 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
2435 ret = Send_internal (safe_handle, bufarray, socketFlags, out nativeError);
2437 for(int i = 0; i < numsegments; i++) {
2438 if (gch[i].IsAllocated) {
2444 errorCode = (SocketError)nativeError;
2449 int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2452 error = SocketError.Success;
2457 int ret = Send_internal (safe_handle, buf, offset, size, flags, out nativeError);
2459 error = (SocketError)nativeError;
2461 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2462 is_connected = false;
2465 is_connected = true;
2471 public bool SendAsync (SocketAsyncEventArgs e)
2473 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2475 ThrowIfDisposedAndClosed ();
2477 if (e.Buffer == null && e.BufferList == null)
2478 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
2480 if (e.Buffer == null) {
2481 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
2483 e.socket_async_result.Buffers = e.BufferList;
2485 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
2487 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
2489 e.socket_async_result.Buffer = e.Buffer;
2490 e.socket_async_result.Offset = e.Offset;
2491 e.socket_async_result.Size = e.Count;
2493 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2499 static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
2500 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2502 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2503 throw new InvalidOperationException ("No operation in progress");
2506 e.BytesTransferred = e.current_socket.EndSend (ares);
2507 } catch (SocketException se){
2508 e.SocketError = se.SocketErrorCode;
2509 } catch (ObjectDisposedException) {
2510 e.SocketError = SocketError.OperationAborted;
2516 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2518 if (!is_connected) {
2519 errorCode = SocketError.NotConnected;
2520 throw new SocketException ((int) errorCode);
2523 errorCode = SocketError.Success;
2524 return BeginSend (buffer, offset, size, socketFlags, callback, state);
2527 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
2529 ThrowIfDisposedAndClosed ();
2530 ThrowIfBufferNull (buffer);
2531 ThrowIfBufferOutOfRange (buffer, offset, size);
2534 throw new SocketException ((int)SocketError.NotConnected);
2536 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
2540 SockFlags = socket_flags,
2543 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
2548 static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
2553 total = Socket.Send_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
2554 } catch (Exception e) {
2555 sockares.Complete (e);
2559 if (sockares.error == 0) {
2560 sent_so_far += total;
2561 sockares.Offset += total;
2562 sockares.Size -= total;
2564 if (sockares.socket.is_disposed) {
2565 sockares.Complete (total);
2569 if (sockares.Size > 0) {
2570 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2571 return; // Have to finish writing everything. See bug #74475.
2574 sockares.Total = sent_so_far;
2577 sockares.Complete (total);
2580 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
2582 ThrowIfDisposedAndClosed ();
2584 if (buffers == null)
2585 throw new ArgumentNullException ("buffers");
2587 throw new SocketException ((int)SocketError.NotConnected);
2589 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
2591 SockFlags = socketFlags,
2594 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
2599 [CLSCompliant (false)]
2600 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2602 if (!is_connected) {
2603 errorCode = SocketError.NotConnected;
2604 throw new SocketException ((int)errorCode);
2607 errorCode = SocketError.Success;
2608 return BeginSend (buffers, socketFlags, callback, state);
2611 static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
2612 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2616 total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
2617 } catch (Exception e) {
2618 sockares.Complete (e);
2622 sockares.Complete (total);
2625 public int EndSend (IAsyncResult result)
2628 int bytesSent = EndSend (result, out error);
2630 if (error != SocketError.Success) {
2631 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2632 is_connected = false;
2633 throw new SocketException ((int)error);
2639 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
2641 ThrowIfDisposedAndClosed ();
2643 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
2645 if (!sockares.IsCompleted)
2646 sockares.AsyncWaitHandle.WaitOne ();
2648 /* If no socket error occurred, call CheckIfThrowDelayedException in
2649 * case there are other kinds of exceptions that should be thrown.*/
2650 if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2651 sockares.CheckIfThrowDelayedException ();
2653 return sockares.Total;
2656 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2658 bool release = false;
2660 safeHandle.DangerousAddRef (ref release);
2661 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2664 safeHandle.DangerousRelease ();
2668 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2669 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2671 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
2674 safeHandle.RegisterForBlockingSyscall ();
2675 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
2677 safeHandle.UnRegisterForBlockingSyscall ();
2681 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2682 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
2688 public int SendTo (byte [] buffer, EndPoint remoteEP)
2690 ThrowIfDisposedAndClosed ();
2691 ThrowIfBufferNull (buffer);
2693 return SendTo (buffer, 0, buffer.Length, SocketFlags.None, remoteEP);
2696 public int SendTo (byte [] buffer, SocketFlags socketFlags, EndPoint remoteEP)
2698 ThrowIfDisposedAndClosed ();
2699 ThrowIfBufferNull (buffer);
2701 return SendTo (buffer, 0, buffer.Length, socketFlags, remoteEP);
2704 public int SendTo (byte [] buffer, int size, SocketFlags socketFlags, EndPoint remoteEP)
2706 return SendTo (buffer, 0, size, socketFlags, remoteEP);
2709 public int SendTo (byte [] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP)
2711 ThrowIfDisposedAndClosed ();
2712 ThrowIfBufferNull (buffer);
2713 ThrowIfBufferOutOfRange (buffer, offset, size);
2715 if (remoteEP == null)
2716 throw new ArgumentNullException("remoteEP");
2718 return SendTo_nochecks (buffer, offset, size, socketFlags, remoteEP);
2721 public bool SendToAsync (SocketAsyncEventArgs e)
2723 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2725 ThrowIfDisposedAndClosed ();
2727 if (e.BufferList != null)
2728 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2729 if (e.RemoteEndPoint == null)
2730 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2732 InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2734 e.socket_async_result.Buffer = e.Buffer;
2735 e.socket_async_result.Offset = e.Offset;
2736 e.socket_async_result.Size = e.Count;
2737 e.socket_async_result.SockFlags = e.SocketFlags;
2738 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2740 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2745 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2746 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2748 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2749 throw new InvalidOperationException ("No operation in progress");
2752 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2753 } catch (SocketException ex) {
2754 e.SocketError = ex.SocketErrorCode;
2755 } catch (ObjectDisposedException) {
2756 e.SocketError = SocketError.OperationAborted;
2762 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2764 ThrowIfDisposedAndClosed ();
2765 ThrowIfBufferNull (buffer);
2766 ThrowIfBufferOutOfRange (buffer, offset, size);
2768 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2772 SockFlags = socket_flags,
2773 EndPoint = remote_end,
2776 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2781 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2785 total = sockares.socket.SendTo_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2787 if (sockares.error == 0) {
2788 sent_so_far += total;
2789 sockares.Offset += total;
2790 sockares.Size -= total;
2793 if (sockares.Size > 0) {
2794 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2795 return; // Have to finish writing everything. See bug #74475.
2798 sockares.Total = sent_so_far;
2799 } catch (Exception e) {
2800 sockares.Complete (e);
2804 sockares.Complete ();
2807 public int EndSendTo (IAsyncResult result)
2809 ThrowIfDisposedAndClosed ();
2811 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2813 if (!sockares.IsCompleted)
2814 sockares.AsyncWaitHandle.WaitOne();
2816 sockares.CheckIfThrowDelayedException();
2818 return sockares.Total;
2821 int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2824 int ret = SendTo_internal (safe_handle, buffer, offset, size, flags, remote_end.Serialize (), out error);
2826 SocketError err = (SocketError) error;
2828 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2829 is_connected = false;
2830 throw new SocketException (error);
2833 is_connected = true;
2835 seed_endpoint = remote_end;
2840 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
2843 safeHandle.RegisterForBlockingSyscall ();
2844 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
2846 safeHandle.UnRegisterForBlockingSyscall ();
2850 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2851 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
2857 public void SendFile (string fileName)
2859 ThrowIfDisposedAndClosed ();
2862 throw new NotSupportedException ();
2864 throw new InvalidOperationException ();
2866 SendFile (fileName, null, null, 0);
2869 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2871 ThrowIfDisposedAndClosed ();
2874 throw new NotSupportedException ();
2876 throw new InvalidOperationException ();
2878 if (!SendFile_internal (safe_handle, fileName, preBuffer, postBuffer, flags)) {
2879 SocketException exc = new SocketException ();
2880 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2881 throw new FileNotFoundException ();
2886 public IAsyncResult BeginSendFile (string fileName, AsyncCallback callback, object state)
2888 ThrowIfDisposedAndClosed ();
2891 throw new NotSupportedException ();
2892 if (!File.Exists (fileName))
2893 throw new FileNotFoundException ();
2895 return BeginSendFile (fileName, null, null, 0, callback, state);
2898 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2900 ThrowIfDisposedAndClosed ();
2903 throw new NotSupportedException ();
2904 if (!File.Exists (fileName))
2905 throw new FileNotFoundException ();
2907 SendFileHandler handler = new SendFileHandler (SendFile);
2909 return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2912 public void EndSendFile (IAsyncResult asyncResult)
2914 ThrowIfDisposedAndClosed ();
2916 if (asyncResult == null)
2917 throw new ArgumentNullException ("asyncResult");
2919 SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2921 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2923 ares.Delegate.EndInvoke (ares.Original);
2926 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
2929 safeHandle.RegisterForBlockingSyscall ();
2930 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
2932 safeHandle.UnRegisterForBlockingSyscall ();
2936 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2937 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
2939 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2941 sealed class SendFileAsyncResult : IAsyncResult {
2945 public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2951 public object AsyncState {
2952 get { return ares.AsyncState; }
2955 public WaitHandle AsyncWaitHandle {
2956 get { return ares.AsyncWaitHandle; }
2959 public bool CompletedSynchronously {
2960 get { return ares.CompletedSynchronously; }
2963 public bool IsCompleted {
2964 get { return ares.IsCompleted; }
2967 public SendFileHandler Delegate {
2971 public IAsyncResult Original {
2972 get { return ares; }
2980 [MonoTODO ("Not implemented")]
2981 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2983 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2985 ThrowIfDisposedAndClosed ();
2987 throw new NotImplementedException ();
2992 #region DuplicateAndClose
2995 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2996 public SocketInformation DuplicateAndClose (int targetProcessId)
2998 var si = new SocketInformation ();
3000 (is_listening ? SocketInformationOptions.Listening : 0) |
3001 (is_connected ? SocketInformationOptions.Connected : 0) |
3002 (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
3003 (use_overlapped_io ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
3005 si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, is_bound ? 1 : 0, (long)Handle);
3014 #region GetSocketOption
3016 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3018 ThrowIfDisposedAndClosed ();
3020 if (optionValue == null)
3021 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3024 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref optionValue, out error);
3027 throw new SocketException (error);
3030 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength)
3032 ThrowIfDisposedAndClosed ();
3035 byte[] byte_val = new byte [optionLength];
3036 GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref byte_val, out error);
3039 throw new SocketException (error);
3044 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
3046 ThrowIfDisposedAndClosed ();
3050 GetSocketOption_obj_internal (safe_handle, optionLevel, optionName, out obj_val, out error);
3053 throw new SocketException (error);
3055 if (optionName == SocketOptionName.Linger)
3056 return (LingerOption) obj_val;
3057 else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
3058 return (MulticastOption) obj_val;
3059 else if (obj_val is int)
3060 return (int) obj_val;
3065 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
3067 bool release = false;
3069 safeHandle.DangerousAddRef (ref release);
3070 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
3073 safeHandle.DangerousRelease ();
3077 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3078 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
3080 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
3082 bool release = false;
3084 safeHandle.DangerousAddRef (ref release);
3085 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
3088 safeHandle.DangerousRelease ();
3092 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3093 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
3097 #region SetSocketOption
3099 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3101 ThrowIfDisposedAndClosed ();
3103 // I'd throw an ArgumentNullException, but this is what MS does.
3104 if (optionValue == null)
3105 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3108 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, optionValue, 0, out error);
3111 if (error == (int) SocketError.InvalidArgument)
3112 throw new ArgumentException ();
3113 throw new SocketException (error);
3117 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
3119 ThrowIfDisposedAndClosed ();
3121 // NOTE: if a null is passed, the byte[] overload is used instead...
3122 if (optionValue == null)
3123 throw new ArgumentNullException("optionValue");
3127 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
3128 LingerOption linger = optionValue as LingerOption;
3130 throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
3131 SetSocketOption_internal (safe_handle, optionLevel, optionName, linger, null, 0, out error);
3132 } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3133 MulticastOption multicast = optionValue as MulticastOption;
3134 if (multicast == null)
3135 throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
3136 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3137 } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3138 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
3139 if (multicast == null)
3140 throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
3141 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3143 throw new ArgumentException ("Invalid value specified.", "optionValue");
3147 if (error == (int) SocketError.InvalidArgument)
3148 throw new ArgumentException ();
3149 throw new SocketException (error);
3153 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
3155 int int_val = optionValue ? 1 : 0;
3157 SetSocketOption (optionLevel, optionName, int_val);
3160 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
3162 ThrowIfDisposedAndClosed ();
3164 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse (protocol_type))
3165 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.");
3168 SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, optionValue, out error);
3171 if (error == (int) SocketError.InvalidArgument)
3172 throw new ArgumentException ();
3173 throw new SocketException (error);
3177 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
3179 bool release = false;
3181 safeHandle.DangerousAddRef (ref release);
3182 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
3185 safeHandle.DangerousRelease ();
3189 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3190 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
3196 public int IOControl (int ioControlCode, byte [] optionInValue, byte [] optionOutValue)
3199 throw new ObjectDisposedException (GetType ().ToString ());
3202 int result = IOControl_internal (safe_handle, ioControlCode, optionInValue, optionOutValue, out error);
3205 throw new SocketException (error);
3207 throw new InvalidOperationException ("Must use Blocking property instead.");
3212 public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
3214 return IOControl ((int) ioControlCode, optionInValue, optionOutValue);
3217 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
3219 bool release = false;
3221 safeHandle.DangerousAddRef (ref release);
3222 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
3225 safeHandle.DangerousRelease ();
3229 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
3230 * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
3231 * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
3232 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3233 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
3239 public void Close ()
3245 public void Close (int timeout)
3247 linger_timeout = timeout;
3251 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3252 internal extern static void Close_internal (IntPtr socket, out int error);
3258 public void Shutdown (SocketShutdown how)
3260 ThrowIfDisposedAndClosed ();
3263 throw new SocketException (10057); // Not connected
3266 Shutdown_internal (safe_handle, how, out error);
3269 throw new SocketException (error);
3272 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
3274 bool release = false;
3276 safeHandle.DangerousAddRef (ref release);
3277 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
3280 safeHandle.DangerousRelease ();
3284 [MethodImplAttribute (MethodImplOptions.InternalCall)]
3285 internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
3291 protected virtual void Dispose (bool disposing)
3297 bool was_connected = is_connected;
3298 is_connected = false;
3300 if (safe_handle != null) {
3307 safe_handle.Dispose ();
3311 public void Dispose ()
3314 GC.SuppressFinalize (this);
3317 void Linger (IntPtr handle)
3319 if (!is_connected || linger_timeout <= 0)
3322 /* We don't want to receive any more data */
3324 Shutdown_internal (handle, SocketShutdown.Receive, out error);
3329 int seconds = linger_timeout / 1000;
3330 int ms = linger_timeout % 1000;
3332 /* If the other end closes, this will return 'true' with 'Available' == 0 */
3333 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
3339 LingerOption linger = new LingerOption (true, seconds);
3340 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
3341 /* Not needed, we're closing upon return */
3349 void ThrowIfDisposedAndClosed (Socket socket)
3351 if (socket.is_disposed && socket.is_closed)
3352 throw new ObjectDisposedException (socket.GetType ().ToString ());
3355 void ThrowIfDisposedAndClosed ()
3357 if (is_disposed && is_closed)
3358 throw new ObjectDisposedException (GetType ().ToString ());
3361 void ThrowIfBufferNull (byte[] buffer)
3364 throw new ArgumentNullException ("buffer");
3367 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
3370 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
3371 if (offset > buffer.Length)
3372 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
3374 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
3375 if (size > buffer.Length - offset)
3376 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
3381 if (protocol_type == ProtocolType.Udp)
3382 throw new SocketException ((int)SocketError.ProtocolOption);
3385 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
3388 throw new ArgumentNullException (argName);
3390 SocketAsyncResult sockares = ares as SocketAsyncResult;
3391 if (sockares == null)
3392 throw new ArgumentException ("Invalid IAsyncResult", argName);
3393 if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
3394 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
3399 void QueueIOSelectorJob (Queue<KeyValuePair<IntPtr, IOSelectorJob>> queue, IntPtr handle, IOSelectorJob job)
3403 queue.Enqueue (new KeyValuePair<IntPtr, IOSelectorJob> (handle, job));
3404 count = queue.Count;
3408 IOSelector.Add (handle, job);
3411 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
3413 e.socket_async_result.Init (this, callback, state, operation);
3414 if (e.AcceptSocket != null) {
3415 e.socket_async_result.AcceptSocket = e.AcceptSocket;
3417 e.current_socket = this;
3418 e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
3419 e.SocketError = SocketError.Success;
3420 e.BytesTransferred = 0;
3423 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
3426 case SocketOperation.Connect:
3427 return SocketAsyncOperation.Connect;
3428 case SocketOperation.Accept:
3429 return SocketAsyncOperation.Accept;
3430 case SocketOperation.Disconnect:
3431 return SocketAsyncOperation.Disconnect;
3432 case SocketOperation.Receive:
3433 case SocketOperation.ReceiveGeneric:
3434 return SocketAsyncOperation.Receive;
3435 case SocketOperation.ReceiveFrom:
3436 return SocketAsyncOperation.ReceiveFrom;
3437 case SocketOperation.Send:
3438 case SocketOperation.SendGeneric:
3439 return SocketAsyncOperation.Send;
3440 case SocketOperation.SendTo:
3441 return SocketAsyncOperation.SendTo;
3443 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
3447 IPEndPoint RemapIPEndPoint (IPEndPoint input) {
3448 // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
3449 if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
3450 return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
3455 [StructLayout (LayoutKind.Sequential)]
3461 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3462 internal static extern void cancel_blocking_socket_operation (Thread thread);
3464 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3465 internal static extern bool SupportsPortReuse (ProtocolType proto);