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 */
73 AddressFamily addressFamily;
74 SocketType socketType;
75 ProtocolType protocolType;
77 /* the field "m_Handle" is looked up by name by the runtime */
78 internal SafeSocketHandle m_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 SemaphoreSlim ReadSem = new SemaphoreSlim (1, 1);
90 internal SemaphoreSlim WriteSem = new SemaphoreSlim (1, 1);
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;
99 internal bool connect_in_progress;
101 private static volatile bool s_LoggingEnabled = Logging.On;
107 if (ipv4_supported == -1) {
109 Socket tmp = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
118 if (ipv6_supported == -1) {
119 // We need to put a try/catch around ConfigurationManager methods as will always throw an exception
120 // when run in a mono embedded application. This occurs as embedded applications do not have a setup
121 // for application config. The exception is not thrown when called from a normal .NET application.
123 // We, then, need to guard calls to the ConfigurationManager. If the config is not found or throws an
124 // exception, will fall through to the existing Socket / API directly below in the code.
126 // Also note that catching ConfigurationErrorsException specifically would require library dependency
127 // System.Configuration, and wanted to avoid that.
129 #if CONFIGURATION_DEP
131 SettingsSection config;
132 config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
134 ipv6_supported = config.Ipv6.Enabled ? -1 : 0;
140 NetConfig config = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig;
142 ipv6_supported = config.ipv6Enabled ? -1 : 0;
148 if (ipv6_supported != 0) {
150 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
161 public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
163 this.addressFamily = addressFamily;
164 this.socketType = socketType;
165 this.protocolType = protocolType;
168 this.m_Handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
171 throw new SocketException (error);
176 public Socket (SocketInformation socketInformation)
178 this.is_listening = (socketInformation.Options & SocketInformationOptions.Listening) != 0;
179 this.is_connected = (socketInformation.Options & SocketInformationOptions.Connected) != 0;
180 this.is_blocking = (socketInformation.Options & SocketInformationOptions.NonBlocking) == 0;
181 this.useOverlappedIO = (socketInformation.Options & SocketInformationOptions.UseOnlyOverlappedIO) != 0;
183 var result = Mono.DataConverter.Unpack ("iiiil", socketInformation.ProtocolInformation, 0);
185 this.addressFamily = (AddressFamily) (int) result [0];
186 this.socketType = (SocketType) (int) result [1];
187 this.protocolType = (ProtocolType) (int) result [2];
188 this.is_bound = (ProtocolType) (int) result [3] != 0;
189 this.m_Handle = new SafeSocketHandle ((IntPtr) (long) result [4], true);
194 /* private constructor used by Accept, which already has a socket handle to use */
195 internal Socket(AddressFamily family, SocketType type, ProtocolType proto, SafeSocketHandle safe_handle)
197 this.addressFamily = family;
198 this.socketType = type;
199 this.protocolType = proto;
201 this.m_Handle = safe_handle;
202 this.is_connected = true;
205 void SocketDefaults ()
208 /* Need to test IPv6 further */
209 if (addressFamily == AddressFamily.InterNetwork
210 // || addressFamily == AddressFamily.InterNetworkV6
212 /* This is the default, but it probably has nasty side
213 * effects on Linux, as the socket option is kludged by
214 * turning on or off PMTU discovery... */
215 this.DontFragment = false;
216 if (protocolType == ProtocolType.Tcp)
217 this.NoDelay = false;
218 } else if (addressFamily == AddressFamily.InterNetworkV6) {
219 this.DualMode = true;
222 /* Microsoft sets these to 8192, but we are going to keep them
223 * both to the OS defaults as these have a big performance impact.
224 * on WebClient performance. */
225 // this.ReceiveBufferSize = 8192;
226 // this.SendBufferSize = 8192;
227 } catch (SocketException) {
231 /* Creates a new system socket, returning the handle */
232 [MethodImplAttribute(MethodImplOptions.InternalCall)]
233 extern IntPtr Socket_internal (AddressFamily family, SocketType type, ProtocolType proto, out int error);
239 [ObsoleteAttribute ("Use OSSupportsIPv4 instead")]
240 public static bool SupportsIPv4 {
241 get { return ipv4_supported == 1; }
244 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
245 public static bool SupportsIPv6 {
246 get { return ipv6_supported == 1; }
250 public static bool OSSupportsIPv4 {
251 get { return ipv4_supported == 1; }
254 public static bool OSSupportsIPv4 {
256 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
258 foreach (NetworkInterface adapter in nics) {
259 if (adapter.Supports (NetworkInterfaceComponent.IPv4))
269 public static bool OSSupportsIPv6 {
270 get { return ipv6_supported == 1; }
273 public static bool OSSupportsIPv6 {
275 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
277 foreach (NetworkInterface adapter in nics) {
278 if (adapter.Supports (NetworkInterfaceComponent.IPv6))
287 public int Available {
289 ThrowIfDisposedAndClosed ();
292 ret = Available_internal (m_Handle, out error);
295 throw new SocketException (error);
301 static int Available_internal (SafeSocketHandle safeHandle, out int error)
303 bool release = false;
305 safeHandle.DangerousAddRef (ref release);
306 return Available_internal (safeHandle.DangerousGetHandle (), out error);
309 safeHandle.DangerousRelease ();
313 /* Returns the amount of data waiting to be read on socket */
314 [MethodImplAttribute(MethodImplOptions.InternalCall)]
315 extern static int Available_internal (IntPtr socket, out int error);
317 // FIXME: import from referencesource
318 public bool EnableBroadcast {
320 ThrowIfDisposedAndClosed ();
322 if (protocolType != ProtocolType.Udp)
323 throw new SocketException ((int) SocketError.ProtocolOption);
325 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0;
328 ThrowIfDisposedAndClosed ();
330 if (protocolType != ProtocolType.Udp)
331 throw new SocketException ((int) SocketError.ProtocolOption);
333 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
337 public bool IsBound {
343 // FIXME: import from referencesource
344 public bool MulticastLoopback {
346 ThrowIfDisposedAndClosed ();
348 /* Even though this option can be set for TCP sockets on Linux, throw
349 * this exception anyway to be compatible (the MSDN docs say
350 * "Setting this property on a Transmission Control Protocol (TCP)
351 * socket will have no effect." but the MS runtime throws the
353 if (protocolType == ProtocolType.Tcp)
354 throw new SocketException ((int)SocketError.ProtocolOption);
356 switch (addressFamily) {
357 case AddressFamily.InterNetwork:
358 return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
359 case AddressFamily.InterNetworkV6:
360 return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
362 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
366 ThrowIfDisposedAndClosed ();
368 /* Even though this option can be set for TCP sockets on Linux, throw
369 * this exception anyway to be compatible (the MSDN docs say
370 * "Setting this property on a Transmission Control Protocol (TCP)
371 * socket will have no effect." but the MS runtime throws the
373 if (protocolType == ProtocolType.Tcp)
374 throw new SocketException ((int)SocketError.ProtocolOption);
376 switch (addressFamily) {
377 case AddressFamily.InterNetwork:
378 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
380 case AddressFamily.InterNetworkV6:
381 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
384 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
389 // Wish: support non-IP endpoints.
390 public EndPoint LocalEndPoint {
392 ThrowIfDisposedAndClosed ();
394 /* If the seed EndPoint is null, Connect, Bind, etc has not yet
395 * been called. MS returns null in this case. */
396 if (seed_endpoint == null)
400 SocketAddress sa = LocalEndPoint_internal (m_Handle, (int) addressFamily, out error);
403 throw new SocketException (error);
405 return seed_endpoint.Create (sa);
409 static SocketAddress LocalEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
411 bool release = false;
413 safeHandle.DangerousAddRef (ref release);
414 return LocalEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
417 safeHandle.DangerousRelease ();
421 /* Returns the local endpoint details in addr and port */
422 [MethodImplAttribute(MethodImplOptions.InternalCall)]
423 extern static SocketAddress LocalEndPoint_internal (IntPtr socket, int family, out int error);
425 public bool Blocking {
426 get { return is_blocking; }
428 ThrowIfDisposedAndClosed ();
431 Blocking_internal (m_Handle, value, out error);
434 throw new SocketException (error);
440 static void Blocking_internal (SafeSocketHandle safeHandle, bool block, out int error)
442 bool release = false;
444 safeHandle.DangerousAddRef (ref release);
445 Blocking_internal (safeHandle.DangerousGetHandle (), block, out error);
448 safeHandle.DangerousRelease ();
452 [MethodImplAttribute(MethodImplOptions.InternalCall)]
453 internal extern static void Blocking_internal(IntPtr socket, bool block, out int error);
455 public bool Connected {
456 get { return is_connected; }
457 internal set { is_connected = value; }
460 // FIXME: import from referencesource
461 public bool NoDelay {
463 ThrowIfDisposedAndClosed ();
466 return ((int) GetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay)) != 0;
470 ThrowIfDisposedAndClosed ();
472 SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
476 public EndPoint RemoteEndPoint {
478 ThrowIfDisposedAndClosed ();
480 /* If the seed EndPoint is null, Connect, Bind, etc has
481 * not yet been called. MS returns null in this case. */
482 if (!is_connected || seed_endpoint == null)
486 SocketAddress sa = RemoteEndPoint_internal (m_Handle, (int) addressFamily, out error);
489 throw new SocketException (error);
491 return seed_endpoint.Create (sa);
495 static SocketAddress RemoteEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
497 bool release = false;
499 safeHandle.DangerousAddRef (ref release);
500 return RemoteEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
503 safeHandle.DangerousRelease ();
507 /* Returns the remote endpoint details in addr and port */
508 [MethodImplAttribute(MethodImplOptions.InternalCall)]
509 extern static SocketAddress RemoteEndPoint_internal (IntPtr socket, int family, out int error);
515 public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
517 var list = new List<Socket> ();
518 AddSockets (list, checkRead, "checkRead");
519 AddSockets (list, checkWrite, "checkWrite");
520 AddSockets (list, checkError, "checkError");
523 throw new ArgumentNullException ("checkRead, checkWrite, checkError", "All the lists are null or empty.");
525 /* The 'sockets' array contains:
526 * - READ socket 0-n, null,
527 * - WRITE socket 0-n, null,
528 * - ERROR socket 0-n, null */
529 Socket [] sockets = list.ToArray ();
532 Select_internal (ref sockets, microSeconds, out error);
535 throw new SocketException (error);
537 if (sockets == null) {
538 if (checkRead != null)
540 if (checkWrite != null)
542 if (checkError != null)
548 int count = sockets.Length;
549 IList currentList = checkRead;
551 for (int i = 0; i < count; i++) {
552 Socket sock = sockets [i];
553 if (sock == null) { // separator
554 if (currentList != null) {
555 // Remove non-signaled sockets after the current one
556 int to_remove = currentList.Count - currentIdx;
557 for (int k = 0; k < to_remove; k++)
558 currentList.RemoveAt (currentIdx);
560 currentList = (mode == 0) ? checkWrite : checkError;
566 if (mode == 1 && currentList == checkWrite && !sock.is_connected) {
567 if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
568 sock.is_connected = true;
571 /* Remove non-signaled sockets before the current one */
572 while (((Socket) currentList [currentIdx]) != sock)
573 currentList.RemoveAt (currentIdx);
579 static void AddSockets (List<Socket> sockets, IList list, string name)
582 foreach (Socket sock in list) {
583 if (sock == null) // MS throws a NullRef
584 throw new ArgumentNullException ("name", "Contains a null element");
592 [MethodImplAttribute(MethodImplOptions.InternalCall)]
593 extern static void Select_internal (ref Socket [] sockets, int microSeconds, out int error);
599 public bool Poll (int microSeconds, SelectMode mode)
601 ThrowIfDisposedAndClosed ();
603 if (mode != SelectMode.SelectRead && mode != SelectMode.SelectWrite && mode != SelectMode.SelectError)
604 throw new NotSupportedException ("'mode' parameter is not valid.");
607 bool result = Poll_internal (m_Handle, mode, microSeconds, out error);
610 throw new SocketException (error);
612 if (mode == SelectMode.SelectWrite && result && !is_connected) {
613 /* Update the is_connected state; for non-blocking Connect()
614 * this is when we can find out that the connect succeeded. */
615 if ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
622 static bool Poll_internal (SafeSocketHandle safeHandle, SelectMode mode, int timeout, out int error)
624 bool release = false;
626 safeHandle.DangerousAddRef (ref release);
627 return Poll_internal (safeHandle.DangerousGetHandle (), mode, timeout, out error);
630 safeHandle.DangerousRelease ();
634 [MethodImplAttribute(MethodImplOptions.InternalCall)]
635 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
641 public Socket Accept()
643 ThrowIfDisposedAndClosed ();
646 SafeSocketHandle safe_handle = Accept_internal (this.m_Handle, out error, is_blocking);
650 error = SOCKET_CLOSED_CODE;
651 throw new SocketException(error);
654 Socket accepted = new Socket (this.AddressFamily, this.SocketType, this.ProtocolType, safe_handle) {
655 seed_endpoint = this.seed_endpoint,
656 Blocking = this.Blocking,
662 internal void Accept (Socket acceptSocket)
664 ThrowIfDisposedAndClosed ();
667 SafeSocketHandle safe_handle = Accept_internal (this.m_Handle, out error, is_blocking);
671 error = SOCKET_CLOSED_CODE;
672 throw new SocketException (error);
675 acceptSocket.addressFamily = this.AddressFamily;
676 acceptSocket.socketType = this.SocketType;
677 acceptSocket.protocolType = this.ProtocolType;
678 acceptSocket.m_Handle = safe_handle;
679 acceptSocket.is_connected = true;
680 acceptSocket.seed_endpoint = this.seed_endpoint;
681 acceptSocket.Blocking = this.Blocking;
683 // FIXME: figure out what if anything else needs to be reset
686 public bool AcceptAsync (SocketAsyncEventArgs e)
688 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
690 ThrowIfDisposedAndClosed ();
693 throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
695 throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
696 if (e.BufferList != null)
697 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
699 throw new ArgumentOutOfRangeException ("e.Count");
701 Socket acceptSocket = e.AcceptSocket;
702 if (acceptSocket != null) {
703 if (acceptSocket.is_bound || acceptSocket.is_connected)
704 throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
707 InitSocketAsyncEventArgs (e, AcceptAsyncCallback, e, SocketOperation.Accept);
709 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, e.socket_async_result));
714 static AsyncCallback AcceptAsyncCallback = new AsyncCallback (ares => {
715 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
717 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
718 throw new InvalidOperationException ("No operation in progress");
721 e.AcceptSocket = e.current_socket.EndAccept (ares);
722 } catch (SocketException ex) {
723 e.SocketError = ex.SocketErrorCode;
724 } catch (ObjectDisposedException) {
725 e.SocketError = SocketError.OperationAborted;
727 if (e.AcceptSocket == null)
728 e.AcceptSocket = new Socket (e.current_socket.AddressFamily, e.current_socket.SocketType, e.current_socket.ProtocolType, null);
733 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
735 ThrowIfDisposedAndClosed ();
737 if (!is_bound || !is_listening)
738 throw new InvalidOperationException ();
740 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Accept);
742 QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, sockares));
747 static IOAsyncCallback BeginAcceptCallback = new IOAsyncCallback (ares => {
748 SocketAsyncResult sockares = (SocketAsyncResult) ares;
749 Socket acc_socket = null;
751 if (sockares.AcceptSocket == null) {
752 acc_socket = sockares.socket.Accept ();
754 acc_socket = sockares.AcceptSocket;
755 sockares.socket.Accept (acc_socket);
758 } catch (Exception e) {
759 sockares.Complete (e);
762 sockares.Complete (acc_socket);
765 public IAsyncResult BeginAccept (Socket acceptSocket, int receiveSize, AsyncCallback callback, object state)
767 ThrowIfDisposedAndClosed ();
770 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
772 if (acceptSocket != null) {
773 ThrowIfDisposedAndClosed (acceptSocket);
775 if (acceptSocket.IsBound)
776 throw new InvalidOperationException ();
778 /* For some reason the MS runtime
779 * barfs if the new socket is not TCP,
780 * even though it's just about to blow
781 * away all those parameters
783 if (acceptSocket.ProtocolType != ProtocolType.Tcp)
784 throw new SocketException ((int)SocketError.InvalidArgument);
787 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
788 Buffer = new byte [receiveSize],
791 SockFlags = SocketFlags.None,
792 AcceptSocket = acceptSocket,
795 QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
800 static IOAsyncCallback BeginAcceptReceiveCallback = new IOAsyncCallback (ares => {
801 SocketAsyncResult sockares = (SocketAsyncResult) ares;
802 Socket acc_socket = null;
805 if (sockares.AcceptSocket == null) {
806 acc_socket = sockares.socket.Accept ();
808 acc_socket = sockares.AcceptSocket;
809 sockares.socket.Accept (acc_socket);
811 } catch (Exception e) {
812 sockares.Complete (e);
816 /* It seems the MS runtime special-cases 0-length requested receive data. See bug 464201. */
818 if (sockares.Size > 0) {
821 total = acc_socket.Receive (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out error);
823 sockares.Complete (new SocketException ((int) error));
826 } catch (Exception e) {
827 sockares.Complete (e);
832 sockares.Complete (acc_socket, total);
835 public Socket EndAccept (IAsyncResult result)
839 return EndAccept (out buffer, out bytes, result);
842 public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
844 ThrowIfDisposedAndClosed ();
846 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndAccept", "asyncResult");
848 if (!sockares.IsCompleted)
849 sockares.AsyncWaitHandle.WaitOne ();
851 sockares.CheckIfThrowDelayedException ();
853 buffer = sockares.Buffer;
854 bytesTransferred = sockares.Total;
856 return sockares.AcceptedSocket;
859 static SafeSocketHandle Accept_internal (SafeSocketHandle safeHandle, out int error, bool blocking)
862 safeHandle.RegisterForBlockingSyscall ();
863 var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
864 return new SafeSocketHandle (ret, true);
866 safeHandle.UnRegisterForBlockingSyscall ();
870 /* Creates a new system socket, returning the handle */
871 [MethodImplAttribute(MethodImplOptions.InternalCall)]
872 extern static IntPtr Accept_internal (IntPtr sock, out int error, bool blocking);
878 public void Bind (EndPoint localEP)
880 #if FEATURE_NO_BSD_SOCKETS
881 throw new PlatformNotSupportedException ("System.Net.Sockets.Socket:Bind is not supported on this platform.");
883 ThrowIfDisposedAndClosed ();
886 throw new ArgumentNullException("localEP");
888 var ipEndPoint = localEP as IPEndPoint;
889 if (ipEndPoint != null) {
890 localEP = RemapIPEndPoint (ipEndPoint);
894 Bind_internal (m_Handle, localEP.Serialize(), out error);
897 throw new SocketException (error);
901 seed_endpoint = localEP;
902 #endif // FEATURE_NO_BSD_SOCKETS
905 private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
907 bool release = false;
909 safeHandle.DangerousAddRef (ref release);
910 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
913 safeHandle.DangerousRelease ();
917 // Creates a new system socket, returning the handle
918 [MethodImplAttribute(MethodImplOptions.InternalCall)]
919 private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
925 public void Listen (int backlog)
927 ThrowIfDisposedAndClosed ();
930 throw new SocketException ((int) SocketError.InvalidArgument);
933 Listen_internal(m_Handle, backlog, out error);
936 throw new SocketException (error);
941 static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
943 bool release = false;
945 safeHandle.DangerousAddRef (ref release);
946 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
949 safeHandle.DangerousRelease ();
953 [MethodImplAttribute(MethodImplOptions.InternalCall)]
954 extern static void Listen_internal (IntPtr sock, int backlog, out int error);
960 public void Connect (IPAddress address, int port)
962 Connect (new IPEndPoint (address, port));
965 public void Connect (string host, int port)
967 Connect (Dns.GetHostAddresses (host), port);
970 public void Connect (IPAddress[] addresses, int port)
972 ThrowIfDisposedAndClosed ();
974 if (addresses == null)
975 throw new ArgumentNullException ("addresses");
976 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
977 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
979 throw new InvalidOperationException ();
981 // FIXME: do non-blocking sockets Poll here?
983 foreach (IPAddress address in addresses) {
984 IPEndPoint iep = new IPEndPoint (address, port);
986 iep = RemapIPEndPoint (iep);
988 Connect_internal (m_Handle, iep.Serialize (), out error, is_blocking);
995 if (error != (int)SocketError.InProgress && error != (int)SocketError.WouldBlock)
999 Poll (-1, SelectMode.SelectWrite);
1000 error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1002 is_connected = true;
1004 seed_endpoint = iep;
1011 throw new SocketException (error);
1015 public void Connect (EndPoint remoteEP)
1017 ThrowIfDisposedAndClosed ();
1019 if (remoteEP == null)
1020 throw new ArgumentNullException ("remoteEP");
1022 IPEndPoint ep = remoteEP as IPEndPoint;
1023 /* Dgram uses Any to 'disconnect' */
1024 if (ep != null && socketType != SocketType.Dgram) {
1025 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1026 throw new SocketException ((int) SocketError.AddressNotAvailable);
1030 throw new InvalidOperationException ();
1033 remoteEP = RemapIPEndPoint (ep);
1036 SocketAddress serial = remoteEP.Serialize ();
1039 Connect_internal (m_Handle, serial, out error, is_blocking);
1041 if (error == 0 || error == 10035)
1042 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1046 error = SOCKET_CLOSED_CODE;
1047 throw new SocketException (error);
1050 is_connected = !(socketType == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
1054 public bool ConnectAsync (SocketAsyncEventArgs e)
1056 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1058 ThrowIfDisposedAndClosed ();
1061 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1062 if (e.RemoteEndPoint == null)
1063 throw new ArgumentNullException ("remoteEP");
1065 InitSocketAsyncEventArgs (e, null, e, SocketOperation.Connect);
1068 IPAddress [] addresses;
1069 SocketAsyncResult ares;
1071 if (!GetCheckedIPs (e, out addresses)) {
1072 e.socket_async_result.EndPoint = e.RemoteEndPoint;
1073 ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
1075 DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1076 e.socket_async_result.Addresses = addresses;
1077 e.socket_async_result.Port = dep.Port;
1078 ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
1081 if (ares.IsCompleted && ares.CompletedSynchronously) {
1082 ares.CheckIfThrowDelayedException ();
1085 } catch (Exception exc) {
1086 e.socket_async_result.Complete (exc, true);
1093 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
1095 var sock = new Socket (e.RemoteEndPoint.AddressFamily, socketType, protocolType);
1096 return sock.ConnectAsync (e);
1099 public static void CancelConnectAsync (SocketAsyncEventArgs e)
1102 throw new ArgumentNullException("e");
1104 if (e.in_progress != 0 && e.LastOperation == SocketAsyncOperation.Connect)
1105 e.current_socket.Close();
1108 static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
1109 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1111 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1112 throw new InvalidOperationException ("No operation in progress");
1115 e.current_socket.EndConnect (ares);
1116 } catch (SocketException se) {
1117 e.SocketError = se.SocketErrorCode;
1118 } catch (ObjectDisposedException) {
1119 e.SocketError = SocketError.OperationAborted;
1125 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
1127 ThrowIfDisposedAndClosed ();
1130 throw new ArgumentNullException ("host");
1131 if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6)
1132 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1133 if (port <= 0 || port > 65535)
1134 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1136 throw new InvalidOperationException ();
1138 return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1141 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
1143 ThrowIfDisposedAndClosed ();
1145 if (end_point == null)
1146 throw new ArgumentNullException ("end_point");
1148 throw new InvalidOperationException ();
1150 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1151 EndPoint = end_point,
1154 // Bug #75154: Connect() should not succeed for .Any addresses.
1155 if (end_point is IPEndPoint) {
1156 IPEndPoint ep = (IPEndPoint) end_point;
1157 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1158 sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1162 end_point = RemapIPEndPoint (ep);
1167 if (connect_in_progress) {
1168 // This could happen when multiple IPs are used
1169 // Calling connect() again will reset the connection attempt and cause
1170 // an error. Better to just close the socket and move on.
1171 connect_in_progress = false;
1172 m_Handle.Dispose ();
1173 m_Handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
1175 throw new SocketException (error);
1178 bool blk = is_blocking;
1181 Connect_internal (m_Handle, end_point.Serialize (), out error, false);
1187 is_connected = true;
1189 sockares.Complete (true);
1193 if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1195 is_connected = false;
1197 sockares.Complete (new SocketException (error), true);
1202 is_connected = false;
1204 connect_in_progress = true;
1206 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
1211 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1213 ThrowIfDisposedAndClosed ();
1215 if (addresses == null)
1216 throw new ArgumentNullException ("addresses");
1217 if (addresses.Length == 0)
1218 throw new ArgumentException ("Empty addresses list");
1219 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1220 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1221 if (port <= 0 || port > 65535)
1222 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1224 throw new InvalidOperationException ();
1226 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1227 Addresses = addresses,
1231 is_connected = false;
1233 return BeginMConnect (sockares);
1236 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1238 SocketAsyncResult ares = null;
1239 Exception exc = null;
1240 AsyncCallback callback;
1242 for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1244 sockares.CurrentAddress++;
1246 ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1247 if (ares.IsCompleted && ares.CompletedSynchronously) {
1248 ares.CheckIfThrowDelayedException ();
1250 callback = ares.AsyncCallback;
1251 if (callback != null)
1252 ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
1256 } catch (Exception e) {
1268 static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
1269 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1271 if (sockares.EndPoint == null) {
1272 sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
1276 SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
1277 bool is_mconnect = mconnect != null && mconnect.Addresses != null;
1280 EndPoint ep = sockares.EndPoint;
1281 int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1283 if (error_code == 0) {
1285 sockares = mconnect;
1287 sockares.socket.seed_endpoint = ep;
1288 sockares.socket.is_connected = true;
1289 sockares.socket.is_bound = true;
1290 sockares.socket.connect_in_progress = false;
1292 sockares.Complete ();
1297 sockares.socket.connect_in_progress = false;
1298 sockares.Complete (new SocketException (error_code));
1302 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
1303 mconnect.Complete (new SocketException (error_code));
1307 mconnect.socket.BeginMConnect (mconnect);
1308 } catch (Exception e) {
1309 sockares.socket.connect_in_progress = false;
1312 sockares = mconnect;
1314 sockares.Complete (e);
1319 public void EndConnect (IAsyncResult result)
1321 ThrowIfDisposedAndClosed ();
1323 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1325 if (!sockares.IsCompleted)
1326 sockares.AsyncWaitHandle.WaitOne();
1328 sockares.CheckIfThrowDelayedException();
1331 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error, bool blocking)
1334 safeHandle.RegisterForBlockingSyscall ();
1335 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error, blocking);
1337 safeHandle.UnRegisterForBlockingSyscall ();
1341 /* Connects to the remote address */
1342 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1343 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error, bool blocking);
1346 * - false when it is ok to use RemoteEndPoint
1347 * - true when addresses must be used (and addresses could be null/empty) */
1348 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1352 // Connect to the first address that match the host name, like:
1353 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1354 // while skipping entries that do not match the address family
1355 DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1357 addresses = Dns.GetHostAddresses (dep.Host);
1360 e.ConnectByNameError = null;
1369 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1370 * if the platform is newer than w2k. We should be able to cope... */
1371 public void Disconnect (bool reuseSocket)
1373 ThrowIfDisposedAndClosed ();
1376 Disconnect_internal (m_Handle, reuseSocket, out error);
1380 /* ERROR_NOT_SUPPORTED */
1381 throw new PlatformNotSupportedException ();
1383 throw new SocketException (error);
1387 is_connected = false;
1389 /* Do managed housekeeping here... */
1393 public bool DisconnectAsync (SocketAsyncEventArgs e)
1395 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1397 ThrowIfDisposedAndClosed ();
1399 InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
1401 IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
1406 static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
1407 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1409 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1410 throw new InvalidOperationException ("No operation in progress");
1413 e.current_socket.EndDisconnect (ares);
1414 } catch (SocketException ex) {
1415 e.SocketError = ex.SocketErrorCode;
1416 } catch (ObjectDisposedException) {
1417 e.SocketError = SocketError.OperationAborted;
1423 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1425 ThrowIfDisposedAndClosed ();
1427 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1428 ReuseSocket = reuseSocket,
1431 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
1436 static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
1437 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1440 sockares.socket.Disconnect (sockares.ReuseSocket);
1441 } catch (Exception e) {
1442 sockares.Complete (e);
1446 sockares.Complete ();
1449 public void EndDisconnect (IAsyncResult asyncResult)
1451 ThrowIfDisposedAndClosed ();
1453 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1455 if (!sockares.IsCompleted)
1456 sockares.AsyncWaitHandle.WaitOne ();
1458 sockares.CheckIfThrowDelayedException ();
1461 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1463 bool release = false;
1465 safeHandle.DangerousAddRef (ref release);
1466 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1469 safeHandle.DangerousRelease ();
1473 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1474 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1480 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1482 ThrowIfDisposedAndClosed ();
1483 ThrowIfBufferNull (buffer);
1484 ThrowIfBufferOutOfRange (buffer, offset, size);
1487 int ret = Receive_internal (m_Handle, buffer, offset, size, socketFlags, out nativeError, is_blocking);
1489 errorCode = (SocketError) nativeError;
1490 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1491 is_connected = false;
1494 is_connected = true;
1500 [CLSCompliant (false)]
1501 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1503 ThrowIfDisposedAndClosed ();
1505 if (buffers == null || buffers.Count == 0)
1506 throw new ArgumentNullException ("buffers");
1508 int numsegments = buffers.Count;
1512 /* Only example I can find of sending a byte array reference directly into an internal
1513 * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1514 * so taking a lead from that... */
1515 WSABUF[] bufarray = new WSABUF[numsegments];
1516 GCHandle[] gch = new GCHandle[numsegments];
1518 for (int i = 0; i < numsegments; i++) {
1519 ArraySegment<byte> segment = buffers[i];
1521 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1522 throw new ArgumentOutOfRangeException ("segment");
1524 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1525 bufarray[i].len = segment.Count;
1526 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1530 ret = Receive_internal (m_Handle, bufarray, socketFlags, out nativeError, is_blocking);
1532 for (int i = 0; i < numsegments; i++) {
1533 if (gch[i].IsAllocated)
1538 errorCode = (SocketError) nativeError;
1543 public bool ReceiveAsync (SocketAsyncEventArgs e)
1545 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1547 ThrowIfDisposedAndClosed ();
1549 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1550 // thrown when e.Buffer and e.BufferList are null (works fine when one is
1551 // set to a valid object)
1552 if (e.Buffer == null && e.BufferList == null)
1553 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1555 if (e.Buffer == null) {
1556 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
1558 e.socket_async_result.Buffers = e.BufferList;
1560 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
1562 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
1564 e.socket_async_result.Buffer = e.Buffer;
1565 e.socket_async_result.Offset = e.Offset;
1566 e.socket_async_result.Size = e.Count;
1568 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
1574 static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
1575 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1577 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1578 throw new InvalidOperationException ("No operation in progress");
1581 e.BytesTransferred = e.current_socket.EndReceive (ares);
1582 } catch (SocketException se){
1583 e.SocketError = se.SocketErrorCode;
1584 } catch (ObjectDisposedException) {
1585 e.SocketError = SocketError.OperationAborted;
1591 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1593 ThrowIfDisposedAndClosed ();
1594 ThrowIfBufferNull (buffer);
1595 ThrowIfBufferOutOfRange (buffer, offset, size);
1597 /* As far as I can tell from the docs and from experimentation, a pointer to the
1598 * SocketError parameter is not supposed to be saved for the async parts. And as we don't
1599 * set any socket errors in the setup code, we just have to set it to Success. */
1600 errorCode = SocketError.Success;
1602 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1606 SockFlags = socketFlags,
1609 QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
1614 static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
1615 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1619 total = Receive_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error, sockares.socket.is_blocking);
1620 } catch (Exception e) {
1621 sockares.Complete (e);
1625 sockares.Complete (total);
1628 [CLSCompliant (false)]
1629 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1631 ThrowIfDisposedAndClosed ();
1633 if (buffers == null)
1634 throw new ArgumentNullException ("buffers");
1636 /* I assume the same SocketError semantics as above */
1637 errorCode = SocketError.Success;
1639 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1641 SockFlags = socketFlags,
1644 QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
1649 static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
1650 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1654 total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
1655 } catch (Exception e) {
1656 sockares.Complete (e);
1660 sockares.Complete (total);
1663 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
1665 ThrowIfDisposedAndClosed ();
1667 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
1669 if (!sockares.IsCompleted)
1670 sockares.AsyncWaitHandle.WaitOne ();
1672 errorCode = sockares.ErrorCode;
1674 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress)
1675 is_connected = false;
1677 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
1678 // kinds of exceptions that should be thrown.
1679 if (errorCode == SocketError.Success)
1680 sockares.CheckIfThrowDelayedException();
1682 return sockares.Total;
1685 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking)
1688 safeHandle.RegisterForBlockingSyscall ();
1689 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error, blocking);
1691 safeHandle.UnRegisterForBlockingSyscall ();
1695 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1696 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking);
1698 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error, bool blocking)
1701 safeHandle.RegisterForBlockingSyscall ();
1702 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error, blocking);
1704 safeHandle.UnRegisterForBlockingSyscall ();
1708 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1709 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error, bool blocking);
1715 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
1717 ThrowIfDisposedAndClosed ();
1718 ThrowIfBufferNull (buffer);
1719 ThrowIfBufferOutOfRange (buffer, offset, size);
1721 if (remoteEP == null)
1722 throw new ArgumentNullException ("remoteEP");
1724 SocketError errorCode;
1725 int ret = ReceiveFrom (buffer, offset, size, socketFlags, ref remoteEP, out errorCode);
1727 if (errorCode != SocketError.Success)
1728 throw new SocketException (errorCode);
1733 internal int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, out SocketError errorCode)
1735 SocketAddress sockaddr = remoteEP.Serialize();
1738 int cnt = ReceiveFrom_internal (m_Handle, buffer, offset, size, socketFlags, ref sockaddr, out nativeError, is_blocking);
1740 errorCode = (SocketError) nativeError;
1741 if (errorCode != SocketError.Success) {
1742 if (errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1743 is_connected = false;
1744 } else if (errorCode == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
1745 errorCode = SocketError.TimedOut;
1751 is_connected = true;
1754 /* If sockaddr is null then we're a connection oriented protocol and should ignore the
1755 * remoteEP parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
1756 if (sockaddr != null) {
1757 /* Stupidly, EndPoint.Create() is an instance method */
1758 remoteEP = remoteEP.Create (sockaddr);
1761 seed_endpoint = remoteEP;
1766 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
1768 ThrowIfDisposedAndClosed ();
1770 // We do not support recv into multiple buffers yet
1771 if (e.BufferList != null)
1772 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
1773 if (e.RemoteEndPoint == null)
1774 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
1776 InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
1778 e.socket_async_result.Buffer = e.Buffer;
1779 e.socket_async_result.Offset = e.Offset;
1780 e.socket_async_result.Size = e.Count;
1781 e.socket_async_result.EndPoint = e.RemoteEndPoint;
1782 e.socket_async_result.SockFlags = e.SocketFlags;
1784 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
1789 static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
1790 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1792 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1793 throw new InvalidOperationException ("No operation in progress");
1796 e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
1797 } catch (SocketException ex) {
1798 e.SocketError = ex.SocketErrorCode;
1799 } catch (ObjectDisposedException) {
1800 e.SocketError = SocketError.OperationAborted;
1806 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
1808 ThrowIfDisposedAndClosed ();
1809 ThrowIfBufferNull (buffer);
1810 ThrowIfBufferOutOfRange (buffer, offset, size);
1812 if (remote_end == null)
1813 throw new ArgumentNullException ("remote_end");
1815 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
1819 SockFlags = socket_flags,
1820 EndPoint = remote_end,
1823 QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
1828 static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
1829 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1833 SocketError errorCode;
1834 total = sockares.socket.ReceiveFrom (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, out errorCode);
1836 if (errorCode != SocketError.Success) {
1837 sockares.Complete (new SocketException (errorCode));
1840 } catch (Exception e) {
1841 sockares.Complete (e);
1845 sockares.Complete (total);
1848 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
1850 ThrowIfDisposedAndClosed ();
1852 if (end_point == null)
1853 throw new ArgumentNullException ("remote_end");
1855 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
1857 if (!sockares.IsCompleted)
1858 sockares.AsyncWaitHandle.WaitOne();
1860 sockares.CheckIfThrowDelayedException();
1862 end_point = sockares.EndPoint;
1864 return sockares.Total;
1869 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking)
1872 safeHandle.RegisterForBlockingSyscall ();
1873 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error, blocking);
1875 safeHandle.UnRegisterForBlockingSyscall ();
1879 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1880 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking);
1884 #region ReceiveMessageFrom
1886 [MonoTODO ("Not implemented")]
1887 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
1889 ThrowIfDisposedAndClosed ();
1890 ThrowIfBufferNull (buffer);
1891 ThrowIfBufferOutOfRange (buffer, offset, size);
1893 if (remoteEP == null)
1894 throw new ArgumentNullException ("remoteEP");
1896 // FIXME: figure out how we get hold of the IPPacketInformation
1897 throw new NotImplementedException ();
1900 [MonoTODO ("Not implemented")]
1901 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
1903 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1905 ThrowIfDisposedAndClosed ();
1907 throw new NotImplementedException ();
1911 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
1913 ThrowIfDisposedAndClosed ();
1914 ThrowIfBufferNull (buffer);
1915 ThrowIfBufferOutOfRange (buffer, offset, size);
1917 if (remoteEP == null)
1918 throw new ArgumentNullException ("remoteEP");
1920 throw new NotImplementedException ();
1924 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
1926 ThrowIfDisposedAndClosed ();
1928 if (endPoint == null)
1929 throw new ArgumentNullException ("endPoint");
1931 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
1933 throw new NotImplementedException ();
1940 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1942 ThrowIfDisposedAndClosed ();
1943 ThrowIfBufferNull (buffer);
1944 ThrowIfBufferOutOfRange (buffer, offset, size);
1947 errorCode = SocketError.Success;
1954 sent += Send_internal (
1955 m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_blocking);
1956 errorCode = (SocketError)nativeError;
1957 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1958 is_connected = false;
1962 is_connected = true;
1964 } while (sent < size);
1969 [CLSCompliant (false)]
1970 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1972 ThrowIfDisposedAndClosed ();
1974 if (buffers == null)
1975 throw new ArgumentNullException ("buffers");
1976 if (buffers.Count == 0)
1977 throw new ArgumentException ("Buffer is empty", "buffers");
1979 int numsegments = buffers.Count;
1983 WSABUF[] bufarray = new WSABUF[numsegments];
1984 GCHandle[] gch = new GCHandle[numsegments];
1986 for(int i = 0; i < numsegments; i++) {
1987 ArraySegment<byte> segment = buffers[i];
1989 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1990 throw new ArgumentOutOfRangeException ("segment");
1992 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1993 bufarray[i].len = segment.Count;
1994 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1998 ret = Send_internal (m_Handle, bufarray, socketFlags, out nativeError, is_blocking);
2000 for(int i = 0; i < numsegments; i++) {
2001 if (gch[i].IsAllocated) {
2007 errorCode = (SocketError)nativeError;
2012 public bool SendAsync (SocketAsyncEventArgs e)
2014 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2016 ThrowIfDisposedAndClosed ();
2018 if (e.Buffer == null && e.BufferList == null)
2019 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
2021 if (e.Buffer == null) {
2022 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
2024 e.socket_async_result.Buffers = e.BufferList;
2026 QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
2028 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
2030 e.socket_async_result.Buffer = e.Buffer;
2031 e.socket_async_result.Offset = e.Offset;
2032 e.socket_async_result.Size = e.Count;
2034 QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2040 static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
2041 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2043 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2044 throw new InvalidOperationException ("No operation in progress");
2047 e.BytesTransferred = e.current_socket.EndSend (ares);
2048 } catch (SocketException se){
2049 e.SocketError = se.SocketErrorCode;
2050 } catch (ObjectDisposedException) {
2051 e.SocketError = SocketError.OperationAborted;
2057 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2059 ThrowIfDisposedAndClosed ();
2060 ThrowIfBufferNull (buffer);
2061 ThrowIfBufferOutOfRange (buffer, offset, size);
2063 if (!is_connected) {
2064 errorCode = SocketError.NotConnected;
2068 errorCode = SocketError.Success;
2070 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
2074 SockFlags = socketFlags,
2077 QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
2082 static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
2087 total = Socket.Send_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error, false);
2088 } catch (Exception e) {
2089 sockares.Complete (e);
2093 if (sockares.error == 0) {
2094 sent_so_far += total;
2095 sockares.Offset += total;
2096 sockares.Size -= total;
2098 if (sockares.socket.CleanedUp) {
2099 sockares.Complete (total);
2103 if (sockares.Size > 0) {
2104 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2105 return; // Have to finish writing everything. See bug #74475.
2108 sockares.Total = sent_so_far;
2111 sockares.Complete (total);
2114 [CLSCompliant (false)]
2115 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2117 ThrowIfDisposedAndClosed ();
2119 if (buffers == null)
2120 throw new ArgumentNullException ("buffers");
2122 if (!is_connected) {
2123 errorCode = SocketError.NotConnected;
2127 errorCode = SocketError.Success;
2129 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
2131 SockFlags = socketFlags,
2134 QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
2139 static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
2140 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2144 total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
2145 } catch (Exception e) {
2146 sockares.Complete (e);
2150 sockares.Complete (total);
2153 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
2155 ThrowIfDisposedAndClosed ();
2157 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
2159 if (!sockares.IsCompleted)
2160 sockares.AsyncWaitHandle.WaitOne ();
2162 errorCode = sockares.ErrorCode;
2164 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress)
2165 is_connected = false;
2167 /* If no socket error occurred, call CheckIfThrowDelayedException in
2168 * case there are other kinds of exceptions that should be thrown.*/
2169 if (errorCode == SocketError.Success)
2170 sockares.CheckIfThrowDelayedException ();
2172 return sockares.Total;
2175 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking)
2178 safeHandle.RegisterForBlockingSyscall ();
2179 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error, blocking);
2181 safeHandle.UnRegisterForBlockingSyscall ();
2185 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2186 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking);
2188 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error, bool blocking)
2191 safeHandle.RegisterForBlockingSyscall ();
2192 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error, blocking);
2194 safeHandle.UnRegisterForBlockingSyscall ();
2198 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2199 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error, bool blocking);
2205 public int SendTo (byte [] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP)
2207 ThrowIfDisposedAndClosed ();
2208 ThrowIfBufferNull (buffer);
2209 ThrowIfBufferOutOfRange (buffer, offset, size);
2211 if (remoteEP == null)
2212 throw new ArgumentNullException("remoteEP");
2215 int ret = SendTo_internal (m_Handle, buffer, offset, size, socketFlags, remoteEP.Serialize (), out error, is_blocking);
2217 SocketError err = (SocketError) error;
2219 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2220 is_connected = false;
2221 throw new SocketException (error);
2224 is_connected = true;
2226 seed_endpoint = remoteEP;
2231 public bool SendToAsync (SocketAsyncEventArgs e)
2233 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2235 ThrowIfDisposedAndClosed ();
2237 if (e.BufferList != null)
2238 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2239 if (e.RemoteEndPoint == null)
2240 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2242 InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2244 e.socket_async_result.Buffer = e.Buffer;
2245 e.socket_async_result.Offset = e.Offset;
2246 e.socket_async_result.Size = e.Count;
2247 e.socket_async_result.SockFlags = e.SocketFlags;
2248 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2250 QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2255 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2256 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2258 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2259 throw new InvalidOperationException ("No operation in progress");
2262 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2263 } catch (SocketException ex) {
2264 e.SocketError = ex.SocketErrorCode;
2265 } catch (ObjectDisposedException) {
2266 e.SocketError = SocketError.OperationAborted;
2272 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2274 ThrowIfDisposedAndClosed ();
2275 ThrowIfBufferNull (buffer);
2276 ThrowIfBufferOutOfRange (buffer, offset, size);
2278 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2282 SockFlags = socket_flags,
2283 EndPoint = remote_end,
2286 QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2291 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2295 total = sockares.socket.SendTo (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2297 if (sockares.error == 0) {
2298 sent_so_far += total;
2299 sockares.Offset += total;
2300 sockares.Size -= total;
2303 if (sockares.Size > 0) {
2304 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2305 return; // Have to finish writing everything. See bug #74475.
2308 sockares.Total = sent_so_far;
2309 } catch (Exception e) {
2310 sockares.Complete (e);
2314 sockares.Complete ();
2317 public int EndSendTo (IAsyncResult result)
2319 ThrowIfDisposedAndClosed ();
2321 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2323 if (!sockares.IsCompleted)
2324 sockares.AsyncWaitHandle.WaitOne();
2326 sockares.CheckIfThrowDelayedException();
2328 return sockares.Total;
2331 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking)
2334 safeHandle.RegisterForBlockingSyscall ();
2335 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error, blocking);
2337 safeHandle.UnRegisterForBlockingSyscall ();
2341 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2342 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking);
2348 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2350 ThrowIfDisposedAndClosed ();
2353 throw new NotSupportedException ();
2355 throw new InvalidOperationException ();
2358 if (!SendFile_internal (m_Handle, fileName, preBuffer, postBuffer, flags, out error, is_blocking) || error != 0) {
2359 SocketException exc = new SocketException (error);
2360 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2361 throw new FileNotFoundException ();
2366 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2368 ThrowIfDisposedAndClosed ();
2371 throw new NotSupportedException ();
2372 if (!File.Exists (fileName))
2373 throw new FileNotFoundException ();
2375 SendFileHandler handler = new SendFileHandler (SendFile);
2377 return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2380 public void EndSendFile (IAsyncResult asyncResult)
2382 ThrowIfDisposedAndClosed ();
2384 if (asyncResult == null)
2385 throw new ArgumentNullException ("asyncResult");
2387 SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2389 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2391 ares.Delegate.EndInvoke (ares.Original);
2394 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags, out int error, bool blocking)
2397 safeHandle.RegisterForBlockingSyscall ();
2398 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags, out error, blocking);
2400 safeHandle.UnRegisterForBlockingSyscall ();
2404 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2405 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags, out int error, bool blocking);
2407 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2409 sealed class SendFileAsyncResult : IAsyncResult {
2413 public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2419 public object AsyncState {
2420 get { return ares.AsyncState; }
2423 public WaitHandle AsyncWaitHandle {
2424 get { return ares.AsyncWaitHandle; }
2427 public bool CompletedSynchronously {
2428 get { return ares.CompletedSynchronously; }
2431 public bool IsCompleted {
2432 get { return ares.IsCompleted; }
2435 public SendFileHandler Delegate {
2439 public IAsyncResult Original {
2440 get { return ares; }
2448 [MonoTODO ("Not implemented")]
2449 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2451 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2453 ThrowIfDisposedAndClosed ();
2455 throw new NotImplementedException ();
2460 #region DuplicateAndClose
2462 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2463 public SocketInformation DuplicateAndClose (int targetProcessId)
2465 var si = new SocketInformation ();
2467 (is_listening ? SocketInformationOptions.Listening : 0) |
2468 (is_connected ? SocketInformationOptions.Connected : 0) |
2469 (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
2470 (useOverlappedIO ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
2472 si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)addressFamily, (int)socketType, (int)protocolType, is_bound ? 1 : 0, (long)Handle);
2480 #region GetSocketOption
2482 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2484 ThrowIfDisposedAndClosed ();
2486 if (optionValue == null)
2487 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2490 GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref optionValue, out error);
2493 throw new SocketException (error);
2496 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength)
2498 ThrowIfDisposedAndClosed ();
2501 byte[] byte_val = new byte [optionLength];
2502 GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref byte_val, out error);
2505 throw new SocketException (error);
2510 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
2512 ThrowIfDisposedAndClosed ();
2516 GetSocketOption_obj_internal (m_Handle, optionLevel, optionName, out obj_val, out error);
2519 throw new SocketException (error);
2521 if (optionName == SocketOptionName.Linger)
2522 return (LingerOption) obj_val;
2523 else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
2524 return (MulticastOption) obj_val;
2525 else if (obj_val is int)
2526 return (int) obj_val;
2531 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
2533 bool release = false;
2535 safeHandle.DangerousAddRef (ref release);
2536 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
2539 safeHandle.DangerousRelease ();
2543 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2544 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
2546 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
2548 bool release = false;
2550 safeHandle.DangerousAddRef (ref release);
2551 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
2554 safeHandle.DangerousRelease ();
2558 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2559 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
2563 #region SetSocketOption
2565 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2567 ThrowIfDisposedAndClosed ();
2569 // I'd throw an ArgumentNullException, but this is what MS does.
2570 if (optionValue == null)
2571 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2574 SetSocketOption_internal (m_Handle, optionLevel, optionName, null, optionValue, 0, out error);
2577 if (error == (int) SocketError.InvalidArgument)
2578 throw new ArgumentException ();
2579 throw new SocketException (error);
2583 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
2585 ThrowIfDisposedAndClosed ();
2587 // NOTE: if a null is passed, the byte[] overload is used instead...
2588 if (optionValue == null)
2589 throw new ArgumentNullException("optionValue");
2593 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
2594 LingerOption linger = optionValue as LingerOption;
2596 throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
2597 SetSocketOption_internal (m_Handle, optionLevel, optionName, linger, null, 0, out error);
2598 } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2599 MulticastOption multicast = optionValue as MulticastOption;
2600 if (multicast == null)
2601 throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
2602 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2603 } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2604 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
2605 if (multicast == null)
2606 throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
2607 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2609 throw new ArgumentException ("Invalid value specified.", "optionValue");
2613 if (error == (int) SocketError.InvalidArgument)
2614 throw new ArgumentException ();
2615 throw new SocketException (error);
2619 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
2621 int int_val = optionValue ? 1 : 0;
2623 SetSocketOption (optionLevel, optionName, int_val);
2626 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
2628 ThrowIfDisposedAndClosed ();
2630 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse (protocolType))
2631 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.");
2634 SetSocketOption_internal (m_Handle, optionLevel, optionName, null, null, optionValue, out error);
2637 if (error == (int) SocketError.InvalidArgument)
2638 throw new ArgumentException ();
2639 throw new SocketException (error);
2643 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
2645 bool release = false;
2647 safeHandle.DangerousAddRef (ref release);
2648 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
2651 safeHandle.DangerousRelease ();
2655 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2656 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
2662 public int IOControl (int ioControlCode, byte [] optionInValue, byte [] optionOutValue)
2665 throw new ObjectDisposedException (GetType ().ToString ());
2668 int result = IOControl_internal (m_Handle, ioControlCode, optionInValue, optionOutValue, out error);
2671 throw new SocketException (error);
2673 throw new InvalidOperationException ("Must use Blocking property instead.");
2678 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
2680 bool release = false;
2682 safeHandle.DangerousAddRef (ref release);
2683 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
2686 safeHandle.DangerousRelease ();
2690 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
2691 * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
2692 * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
2693 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2694 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
2700 public void Close ()
2706 public void Close (int timeout)
2708 linger_timeout = timeout;
2712 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2713 internal extern static void Close_internal (IntPtr socket, out int error);
2719 public void Shutdown (SocketShutdown how)
2721 ThrowIfDisposedAndClosed ();
2724 throw new SocketException (10057); // Not connected
2727 Shutdown_internal (m_Handle, how, out error);
2730 throw new SocketException (error);
2733 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
2735 bool release = false;
2737 safeHandle.DangerousAddRef (ref release);
2738 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
2741 safeHandle.DangerousRelease ();
2745 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2746 internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
2752 protected virtual void Dispose (bool disposing)
2758 bool was_connected = is_connected;
2759 is_connected = false;
2761 if (m_Handle != null) {
2768 m_Handle.Dispose ();
2772 void Linger (IntPtr handle)
2774 if (!is_connected || linger_timeout <= 0)
2777 /* We don't want to receive any more data */
2779 Shutdown_internal (handle, SocketShutdown.Receive, out error);
2784 int seconds = linger_timeout / 1000;
2785 int ms = linger_timeout % 1000;
2787 /* If the other end closes, this will return 'true' with 'Available' == 0 */
2788 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
2794 LingerOption linger = new LingerOption (true, seconds);
2795 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
2796 /* Not needed, we're closing upon return */
2804 void ThrowIfDisposedAndClosed (Socket socket)
2806 if (socket.CleanedUp && socket.is_closed)
2807 throw new ObjectDisposedException (socket.GetType ().ToString ());
2810 void ThrowIfDisposedAndClosed ()
2812 if (CleanedUp && is_closed)
2813 throw new ObjectDisposedException (GetType ().ToString ());
2816 void ThrowIfBufferNull (byte[] buffer)
2819 throw new ArgumentNullException ("buffer");
2822 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
2825 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
2826 if (offset > buffer.Length)
2827 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
2829 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
2830 if (size > buffer.Length - offset)
2831 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
2836 if (protocolType == ProtocolType.Udp)
2837 throw new SocketException ((int)SocketError.ProtocolOption);
2840 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
2843 throw new ArgumentNullException (argName);
2845 SocketAsyncResult sockares = ares as SocketAsyncResult;
2846 if (sockares == null)
2847 throw new ArgumentException ("Invalid IAsyncResult", argName);
2848 if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
2849 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
2854 void QueueIOSelectorJob (SemaphoreSlim sem, IntPtr handle, IOSelectorJob job)
2856 sem.WaitAsync ().ContinueWith (t => {
2858 job.MarkDisposed ();
2862 IOSelector.Add (handle, job);
2866 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
2868 e.socket_async_result.Init (this, callback, state, operation);
2869 if (e.AcceptSocket != null) {
2870 e.socket_async_result.AcceptSocket = e.AcceptSocket;
2872 e.current_socket = this;
2873 e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
2874 e.SocketError = SocketError.Success;
2875 e.BytesTransferred = 0;
2878 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
2881 case SocketOperation.Connect:
2882 return SocketAsyncOperation.Connect;
2883 case SocketOperation.Accept:
2884 return SocketAsyncOperation.Accept;
2885 case SocketOperation.Disconnect:
2886 return SocketAsyncOperation.Disconnect;
2887 case SocketOperation.Receive:
2888 case SocketOperation.ReceiveGeneric:
2889 return SocketAsyncOperation.Receive;
2890 case SocketOperation.ReceiveFrom:
2891 return SocketAsyncOperation.ReceiveFrom;
2892 case SocketOperation.Send:
2893 case SocketOperation.SendGeneric:
2894 return SocketAsyncOperation.Send;
2895 case SocketOperation.SendTo:
2896 return SocketAsyncOperation.SendTo;
2898 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
2902 IPEndPoint RemapIPEndPoint (IPEndPoint input) {
2903 // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
2904 if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
2905 return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
2910 [StructLayout (LayoutKind.Sequential)]
2916 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2917 internal static extern void cancel_blocking_socket_operation (Thread thread);
2919 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2920 internal static extern bool SupportsPortReuse (ProtocolType proto);