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);
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);
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);
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)
1334 safeHandle.RegisterForBlockingSyscall ();
1335 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
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);
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);
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);
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);
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)
1688 safeHandle.RegisterForBlockingSyscall ();
1689 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
1691 safeHandle.UnRegisterForBlockingSyscall ();
1695 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1696 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
1698 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
1701 safeHandle.RegisterForBlockingSyscall ();
1702 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
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);
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);
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)
1872 safeHandle.RegisterForBlockingSyscall ();
1873 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
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);
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);
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);
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);
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)
2177 bool release = false;
2179 safeHandle.DangerousAddRef (ref release);
2180 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2183 safeHandle.DangerousRelease ();
2187 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2188 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2190 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
2193 safeHandle.RegisterForBlockingSyscall ();
2194 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
2196 safeHandle.UnRegisterForBlockingSyscall ();
2200 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2201 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
2207 public int SendTo (byte [] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP)
2209 ThrowIfDisposedAndClosed ();
2210 ThrowIfBufferNull (buffer);
2211 ThrowIfBufferOutOfRange (buffer, offset, size);
2213 if (remoteEP == null)
2214 throw new ArgumentNullException("remoteEP");
2217 int ret = SendTo_internal (m_Handle, buffer, offset, size, socketFlags, remoteEP.Serialize (), out error);
2219 SocketError err = (SocketError) error;
2221 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2222 is_connected = false;
2223 throw new SocketException (error);
2226 is_connected = true;
2228 seed_endpoint = remoteEP;
2233 public bool SendToAsync (SocketAsyncEventArgs e)
2235 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2237 ThrowIfDisposedAndClosed ();
2239 if (e.BufferList != null)
2240 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2241 if (e.RemoteEndPoint == null)
2242 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2244 InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2246 e.socket_async_result.Buffer = e.Buffer;
2247 e.socket_async_result.Offset = e.Offset;
2248 e.socket_async_result.Size = e.Count;
2249 e.socket_async_result.SockFlags = e.SocketFlags;
2250 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2252 QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2257 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2258 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2260 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2261 throw new InvalidOperationException ("No operation in progress");
2264 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2265 } catch (SocketException ex) {
2266 e.SocketError = ex.SocketErrorCode;
2267 } catch (ObjectDisposedException) {
2268 e.SocketError = SocketError.OperationAborted;
2274 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2276 ThrowIfDisposedAndClosed ();
2277 ThrowIfBufferNull (buffer);
2278 ThrowIfBufferOutOfRange (buffer, offset, size);
2280 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2284 SockFlags = socket_flags,
2285 EndPoint = remote_end,
2288 QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2293 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2297 total = sockares.socket.SendTo (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2299 if (sockares.error == 0) {
2300 sent_so_far += total;
2301 sockares.Offset += total;
2302 sockares.Size -= total;
2305 if (sockares.Size > 0) {
2306 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2307 return; // Have to finish writing everything. See bug #74475.
2310 sockares.Total = sent_so_far;
2311 } catch (Exception e) {
2312 sockares.Complete (e);
2316 sockares.Complete ();
2319 public int EndSendTo (IAsyncResult result)
2321 ThrowIfDisposedAndClosed ();
2323 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2325 if (!sockares.IsCompleted)
2326 sockares.AsyncWaitHandle.WaitOne();
2328 sockares.CheckIfThrowDelayedException();
2330 return sockares.Total;
2333 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
2336 safeHandle.RegisterForBlockingSyscall ();
2337 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
2339 safeHandle.UnRegisterForBlockingSyscall ();
2343 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2344 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
2350 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2352 ThrowIfDisposedAndClosed ();
2355 throw new NotSupportedException ();
2357 throw new InvalidOperationException ();
2359 if (!SendFile_internal (m_Handle, fileName, preBuffer, postBuffer, flags)) {
2360 SocketException exc = new SocketException ();
2361 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2362 throw new FileNotFoundException ();
2367 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2369 ThrowIfDisposedAndClosed ();
2372 throw new NotSupportedException ();
2373 if (!File.Exists (fileName))
2374 throw new FileNotFoundException ();
2376 SendFileHandler handler = new SendFileHandler (SendFile);
2378 return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2381 public void EndSendFile (IAsyncResult asyncResult)
2383 ThrowIfDisposedAndClosed ();
2385 if (asyncResult == null)
2386 throw new ArgumentNullException ("asyncResult");
2388 SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2390 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2392 ares.Delegate.EndInvoke (ares.Original);
2395 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
2398 safeHandle.RegisterForBlockingSyscall ();
2399 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
2401 safeHandle.UnRegisterForBlockingSyscall ();
2405 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2406 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
2408 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2410 sealed class SendFileAsyncResult : IAsyncResult {
2414 public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2420 public object AsyncState {
2421 get { return ares.AsyncState; }
2424 public WaitHandle AsyncWaitHandle {
2425 get { return ares.AsyncWaitHandle; }
2428 public bool CompletedSynchronously {
2429 get { return ares.CompletedSynchronously; }
2432 public bool IsCompleted {
2433 get { return ares.IsCompleted; }
2436 public SendFileHandler Delegate {
2440 public IAsyncResult Original {
2441 get { return ares; }
2449 [MonoTODO ("Not implemented")]
2450 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2452 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2454 ThrowIfDisposedAndClosed ();
2456 throw new NotImplementedException ();
2461 #region DuplicateAndClose
2463 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2464 public SocketInformation DuplicateAndClose (int targetProcessId)
2466 var si = new SocketInformation ();
2468 (is_listening ? SocketInformationOptions.Listening : 0) |
2469 (is_connected ? SocketInformationOptions.Connected : 0) |
2470 (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
2471 (useOverlappedIO ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
2473 si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)addressFamily, (int)socketType, (int)protocolType, is_bound ? 1 : 0, (long)Handle);
2481 #region GetSocketOption
2483 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2485 ThrowIfDisposedAndClosed ();
2487 if (optionValue == null)
2488 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2491 GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref optionValue, out error);
2494 throw new SocketException (error);
2497 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength)
2499 ThrowIfDisposedAndClosed ();
2502 byte[] byte_val = new byte [optionLength];
2503 GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref byte_val, out error);
2506 throw new SocketException (error);
2511 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
2513 ThrowIfDisposedAndClosed ();
2517 GetSocketOption_obj_internal (m_Handle, optionLevel, optionName, out obj_val, out error);
2520 throw new SocketException (error);
2522 if (optionName == SocketOptionName.Linger)
2523 return (LingerOption) obj_val;
2524 else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
2525 return (MulticastOption) obj_val;
2526 else if (obj_val is int)
2527 return (int) obj_val;
2532 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
2534 bool release = false;
2536 safeHandle.DangerousAddRef (ref release);
2537 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
2540 safeHandle.DangerousRelease ();
2544 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2545 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
2547 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
2549 bool release = false;
2551 safeHandle.DangerousAddRef (ref release);
2552 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
2555 safeHandle.DangerousRelease ();
2559 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2560 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
2564 #region SetSocketOption
2566 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2568 ThrowIfDisposedAndClosed ();
2570 // I'd throw an ArgumentNullException, but this is what MS does.
2571 if (optionValue == null)
2572 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2575 SetSocketOption_internal (m_Handle, optionLevel, optionName, null, optionValue, 0, out error);
2578 if (error == (int) SocketError.InvalidArgument)
2579 throw new ArgumentException ();
2580 throw new SocketException (error);
2584 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
2586 ThrowIfDisposedAndClosed ();
2588 // NOTE: if a null is passed, the byte[] overload is used instead...
2589 if (optionValue == null)
2590 throw new ArgumentNullException("optionValue");
2594 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
2595 LingerOption linger = optionValue as LingerOption;
2597 throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
2598 SetSocketOption_internal (m_Handle, optionLevel, optionName, linger, null, 0, out error);
2599 } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2600 MulticastOption multicast = optionValue as MulticastOption;
2601 if (multicast == null)
2602 throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
2603 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2604 } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2605 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
2606 if (multicast == null)
2607 throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
2608 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2610 throw new ArgumentException ("Invalid value specified.", "optionValue");
2614 if (error == (int) SocketError.InvalidArgument)
2615 throw new ArgumentException ();
2616 throw new SocketException (error);
2620 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
2622 int int_val = optionValue ? 1 : 0;
2624 SetSocketOption (optionLevel, optionName, int_val);
2627 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
2629 ThrowIfDisposedAndClosed ();
2631 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse (protocolType))
2632 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.");
2635 SetSocketOption_internal (m_Handle, optionLevel, optionName, null, null, optionValue, out error);
2638 if (error == (int) SocketError.InvalidArgument)
2639 throw new ArgumentException ();
2640 throw new SocketException (error);
2644 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
2646 bool release = false;
2648 safeHandle.DangerousAddRef (ref release);
2649 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
2652 safeHandle.DangerousRelease ();
2656 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2657 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
2663 public int IOControl (int ioControlCode, byte [] optionInValue, byte [] optionOutValue)
2666 throw new ObjectDisposedException (GetType ().ToString ());
2669 int result = IOControl_internal (m_Handle, ioControlCode, optionInValue, optionOutValue, out error);
2672 throw new SocketException (error);
2674 throw new InvalidOperationException ("Must use Blocking property instead.");
2679 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
2681 bool release = false;
2683 safeHandle.DangerousAddRef (ref release);
2684 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
2687 safeHandle.DangerousRelease ();
2691 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
2692 * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
2693 * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
2694 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2695 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
2701 public void Close ()
2707 public void Close (int timeout)
2709 linger_timeout = timeout;
2713 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2714 internal extern static void Close_internal (IntPtr socket, out int error);
2720 public void Shutdown (SocketShutdown how)
2722 ThrowIfDisposedAndClosed ();
2725 throw new SocketException (10057); // Not connected
2728 Shutdown_internal (m_Handle, how, out error);
2731 throw new SocketException (error);
2734 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
2736 bool release = false;
2738 safeHandle.DangerousAddRef (ref release);
2739 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
2742 safeHandle.DangerousRelease ();
2746 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2747 internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
2753 protected virtual void Dispose (bool disposing)
2759 bool was_connected = is_connected;
2760 is_connected = false;
2762 if (m_Handle != null) {
2769 m_Handle.Dispose ();
2773 void Linger (IntPtr handle)
2775 if (!is_connected || linger_timeout <= 0)
2778 /* We don't want to receive any more data */
2780 Shutdown_internal (handle, SocketShutdown.Receive, out error);
2785 int seconds = linger_timeout / 1000;
2786 int ms = linger_timeout % 1000;
2788 /* If the other end closes, this will return 'true' with 'Available' == 0 */
2789 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
2795 LingerOption linger = new LingerOption (true, seconds);
2796 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
2797 /* Not needed, we're closing upon return */
2805 void ThrowIfDisposedAndClosed (Socket socket)
2807 if (socket.CleanedUp && socket.is_closed)
2808 throw new ObjectDisposedException (socket.GetType ().ToString ());
2811 void ThrowIfDisposedAndClosed ()
2813 if (CleanedUp && is_closed)
2814 throw new ObjectDisposedException (GetType ().ToString ());
2817 void ThrowIfBufferNull (byte[] buffer)
2820 throw new ArgumentNullException ("buffer");
2823 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
2826 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
2827 if (offset > buffer.Length)
2828 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
2830 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
2831 if (size > buffer.Length - offset)
2832 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
2837 if (protocolType == ProtocolType.Udp)
2838 throw new SocketException ((int)SocketError.ProtocolOption);
2841 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
2844 throw new ArgumentNullException (argName);
2846 SocketAsyncResult sockares = ares as SocketAsyncResult;
2847 if (sockares == null)
2848 throw new ArgumentException ("Invalid IAsyncResult", argName);
2849 if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
2850 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
2855 void QueueIOSelectorJob (SemaphoreSlim sem, IntPtr handle, IOSelectorJob job)
2857 sem.WaitAsync ().ContinueWith (t => {
2859 job.MarkDisposed ();
2863 IOSelector.Add (handle, job);
2867 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
2869 e.socket_async_result.Init (this, callback, state, operation);
2870 if (e.AcceptSocket != null) {
2871 e.socket_async_result.AcceptSocket = e.AcceptSocket;
2873 e.current_socket = this;
2874 e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
2875 e.SocketError = SocketError.Success;
2876 e.BytesTransferred = 0;
2879 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
2882 case SocketOperation.Connect:
2883 return SocketAsyncOperation.Connect;
2884 case SocketOperation.Accept:
2885 return SocketAsyncOperation.Accept;
2886 case SocketOperation.Disconnect:
2887 return SocketAsyncOperation.Disconnect;
2888 case SocketOperation.Receive:
2889 case SocketOperation.ReceiveGeneric:
2890 return SocketAsyncOperation.Receive;
2891 case SocketOperation.ReceiveFrom:
2892 return SocketAsyncOperation.ReceiveFrom;
2893 case SocketOperation.Send:
2894 case SocketOperation.SendGeneric:
2895 return SocketAsyncOperation.Send;
2896 case SocketOperation.SendTo:
2897 return SocketAsyncOperation.SendTo;
2899 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
2903 IPEndPoint RemapIPEndPoint (IPEndPoint input) {
2904 // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
2905 if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
2906 return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
2911 [StructLayout (LayoutKind.Sequential)]
2917 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2918 internal static extern void cancel_blocking_socket_operation (Thread thread);
2920 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2921 internal static extern bool SupportsPortReuse (ProtocolType proto);