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 Queue<KeyValuePair<IntPtr, IOSelectorJob>> readQ = new Queue<KeyValuePair<IntPtr, IOSelectorJob>> (2);
90 internal Queue<KeyValuePair<IntPtr, IOSelectorJob>> writeQ = new Queue<KeyValuePair<IntPtr, IOSelectorJob>> (2);
92 internal bool is_blocking = true;
93 internal bool is_bound;
95 /* When true, the socket was connected at the time of the last IO operation */
96 internal bool is_connected;
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 (readQ, 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 (readQ, 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 (readQ, 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 ThrowIfDisposedAndClosed ();
883 throw new ArgumentNullException("localEP");
885 var ipEndPoint = localEP as IPEndPoint;
886 if (ipEndPoint != null) {
887 localEP = RemapIPEndPoint (ipEndPoint);
891 Bind_internal (m_Handle, localEP.Serialize(), out error);
894 throw new SocketException (error);
898 seed_endpoint = localEP;
901 private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
903 bool release = false;
905 safeHandle.DangerousAddRef (ref release);
906 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
909 safeHandle.DangerousRelease ();
913 // Creates a new system socket, returning the handle
914 [MethodImplAttribute(MethodImplOptions.InternalCall)]
915 private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
921 public void Listen (int backlog)
923 ThrowIfDisposedAndClosed ();
926 throw new SocketException ((int) SocketError.InvalidArgument);
929 Listen_internal(m_Handle, backlog, out error);
932 throw new SocketException (error);
937 static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
939 bool release = false;
941 safeHandle.DangerousAddRef (ref release);
942 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
945 safeHandle.DangerousRelease ();
949 [MethodImplAttribute(MethodImplOptions.InternalCall)]
950 extern static void Listen_internal (IntPtr sock, int backlog, out int error);
956 public void Connect (IPAddress address, int port)
958 Connect (new IPEndPoint (address, port));
961 public void Connect (string host, int port)
963 Connect (Dns.GetHostAddresses (host), port);
966 public void Connect (IPAddress[] addresses, int port)
968 ThrowIfDisposedAndClosed ();
970 if (addresses == null)
971 throw new ArgumentNullException ("addresses");
972 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
973 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
975 throw new InvalidOperationException ();
977 // FIXME: do non-blocking sockets Poll here?
979 foreach (IPAddress address in addresses) {
980 IPEndPoint iep = new IPEndPoint (address, port);
982 iep = RemapIPEndPoint (iep);
984 Connect_internal (m_Handle, iep.Serialize (), out error);
991 if (error != (int)SocketError.InProgress && error != (int)SocketError.WouldBlock)
995 Poll (-1, SelectMode.SelectWrite);
996 error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1000 seed_endpoint = iep;
1007 throw new SocketException (error);
1011 public void Connect (EndPoint remoteEP)
1013 ThrowIfDisposedAndClosed ();
1015 if (remoteEP == null)
1016 throw new ArgumentNullException ("remoteEP");
1018 IPEndPoint ep = remoteEP as IPEndPoint;
1019 /* Dgram uses Any to 'disconnect' */
1020 if (ep != null && socketType != SocketType.Dgram) {
1021 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1022 throw new SocketException ((int) SocketError.AddressNotAvailable);
1026 throw new InvalidOperationException ();
1029 remoteEP = RemapIPEndPoint (ep);
1032 SocketAddress serial = remoteEP.Serialize ();
1035 Connect_internal (m_Handle, serial, out error);
1037 if (error == 0 || error == 10035)
1038 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1042 error = SOCKET_CLOSED_CODE;
1043 throw new SocketException (error);
1046 is_connected = !(socketType == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
1050 public bool ConnectAsync (SocketAsyncEventArgs e)
1052 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1054 ThrowIfDisposedAndClosed ();
1057 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1058 if (e.RemoteEndPoint == null)
1059 throw new ArgumentNullException ("remoteEP");
1061 InitSocketAsyncEventArgs (e, null, e, SocketOperation.Connect);
1064 IPAddress [] addresses;
1065 SocketAsyncResult ares;
1067 if (!GetCheckedIPs (e, out addresses)) {
1068 e.socket_async_result.EndPoint = e.RemoteEndPoint;
1069 ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
1071 DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1072 e.socket_async_result.Addresses = addresses;
1073 e.socket_async_result.Port = dep.Port;
1074 ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
1077 if (ares.IsCompleted && ares.CompletedSynchronously) {
1078 ares.CheckIfThrowDelayedException ();
1081 } catch (Exception exc) {
1082 e.socket_async_result.Complete (exc, true);
1089 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
1091 var sock = new Socket (e.RemoteEndPoint.AddressFamily, socketType, protocolType);
1092 return sock.ConnectAsync (e);
1095 public static void CancelConnectAsync (SocketAsyncEventArgs e)
1098 throw new ArgumentNullException("e");
1100 if (e.in_progress != 0 && e.LastOperation == SocketAsyncOperation.Connect)
1101 e.current_socket.Close();
1104 static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
1105 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1107 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1108 throw new InvalidOperationException ("No operation in progress");
1111 e.current_socket.EndConnect (ares);
1112 } catch (SocketException se) {
1113 e.SocketError = se.SocketErrorCode;
1114 } catch (ObjectDisposedException) {
1115 e.SocketError = SocketError.OperationAborted;
1121 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
1123 ThrowIfDisposedAndClosed ();
1126 throw new ArgumentNullException ("host");
1127 if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6)
1128 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1129 if (port <= 0 || port > 65535)
1130 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1132 throw new InvalidOperationException ();
1134 return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1137 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
1139 ThrowIfDisposedAndClosed ();
1141 if (end_point == null)
1142 throw new ArgumentNullException ("end_point");
1144 throw new InvalidOperationException ();
1146 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1147 EndPoint = end_point,
1150 // Bug #75154: Connect() should not succeed for .Any addresses.
1151 if (end_point is IPEndPoint) {
1152 IPEndPoint ep = (IPEndPoint) end_point;
1153 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1154 sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1158 end_point = RemapIPEndPoint (ep);
1163 if (connect_in_progress) {
1164 // This could happen when multiple IPs are used
1165 // Calling connect() again will reset the connection attempt and cause
1166 // an error. Better to just close the socket and move on.
1167 connect_in_progress = false;
1168 m_Handle.Dispose ();
1169 m_Handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
1171 throw new SocketException (error);
1174 bool blk = is_blocking;
1177 Connect_internal (m_Handle, end_point.Serialize (), out error);
1183 is_connected = true;
1185 sockares.Complete (true);
1189 if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1191 is_connected = false;
1193 sockares.Complete (new SocketException (error), true);
1198 is_connected = false;
1200 connect_in_progress = true;
1202 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
1207 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1209 ThrowIfDisposedAndClosed ();
1211 if (addresses == null)
1212 throw new ArgumentNullException ("addresses");
1213 if (addresses.Length == 0)
1214 throw new ArgumentException ("Empty addresses list");
1215 if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1216 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1217 if (port <= 0 || port > 65535)
1218 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1220 throw new InvalidOperationException ();
1222 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1223 Addresses = addresses,
1227 is_connected = false;
1229 return BeginMConnect (sockares);
1232 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1234 SocketAsyncResult ares = null;
1235 Exception exc = null;
1236 AsyncCallback callback;
1238 for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1240 sockares.CurrentAddress++;
1242 ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1243 if (ares.IsCompleted && ares.CompletedSynchronously) {
1244 ares.CheckIfThrowDelayedException ();
1246 callback = ares.AsyncCallback;
1247 if (callback != null)
1248 ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
1252 } catch (Exception e) {
1264 static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
1265 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1267 if (sockares.EndPoint == null) {
1268 sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
1272 SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
1273 bool is_mconnect = mconnect != null && mconnect.Addresses != null;
1276 EndPoint ep = sockares.EndPoint;
1277 int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1279 if (error_code == 0) {
1281 sockares = mconnect;
1283 sockares.socket.seed_endpoint = ep;
1284 sockares.socket.is_connected = true;
1285 sockares.socket.is_bound = true;
1286 sockares.socket.connect_in_progress = false;
1288 sockares.Complete ();
1293 sockares.socket.connect_in_progress = false;
1294 sockares.Complete (new SocketException (error_code));
1298 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
1299 mconnect.Complete (new SocketException (error_code));
1303 mconnect.socket.BeginMConnect (mconnect);
1304 } catch (Exception e) {
1305 sockares.socket.connect_in_progress = false;
1308 sockares = mconnect;
1310 sockares.Complete (e);
1315 public void EndConnect (IAsyncResult result)
1317 ThrowIfDisposedAndClosed ();
1319 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1321 if (!sockares.IsCompleted)
1322 sockares.AsyncWaitHandle.WaitOne();
1324 sockares.CheckIfThrowDelayedException();
1327 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1330 safeHandle.RegisterForBlockingSyscall ();
1331 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
1333 safeHandle.UnRegisterForBlockingSyscall ();
1337 /* Connects to the remote address */
1338 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1339 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error);
1342 * - false when it is ok to use RemoteEndPoint
1343 * - true when addresses must be used (and addresses could be null/empty) */
1344 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1348 // Connect to the first address that match the host name, like:
1349 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1350 // while skipping entries that do not match the address family
1351 DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1353 addresses = Dns.GetHostAddresses (dep.Host);
1356 e.ConnectByNameError = null;
1365 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1366 * if the platform is newer than w2k. We should be able to cope... */
1367 public void Disconnect (bool reuseSocket)
1369 ThrowIfDisposedAndClosed ();
1372 Disconnect_internal (m_Handle, reuseSocket, out error);
1376 /* ERROR_NOT_SUPPORTED */
1377 throw new PlatformNotSupportedException ();
1379 throw new SocketException (error);
1383 is_connected = false;
1385 /* Do managed housekeeping here... */
1389 public bool DisconnectAsync (SocketAsyncEventArgs e)
1391 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1393 ThrowIfDisposedAndClosed ();
1395 InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
1397 IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
1402 static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
1403 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1405 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1406 throw new InvalidOperationException ("No operation in progress");
1409 e.current_socket.EndDisconnect (ares);
1410 } catch (SocketException ex) {
1411 e.SocketError = ex.SocketErrorCode;
1412 } catch (ObjectDisposedException) {
1413 e.SocketError = SocketError.OperationAborted;
1419 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1421 ThrowIfDisposedAndClosed ();
1423 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1424 ReuseSocket = reuseSocket,
1427 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
1432 static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
1433 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1436 sockares.socket.Disconnect (sockares.ReuseSocket);
1437 } catch (Exception e) {
1438 sockares.Complete (e);
1442 sockares.Complete ();
1445 public void EndDisconnect (IAsyncResult asyncResult)
1447 ThrowIfDisposedAndClosed ();
1449 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1451 if (!sockares.IsCompleted)
1452 sockares.AsyncWaitHandle.WaitOne ();
1454 sockares.CheckIfThrowDelayedException ();
1457 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1459 bool release = false;
1461 safeHandle.DangerousAddRef (ref release);
1462 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1465 safeHandle.DangerousRelease ();
1469 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1470 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1476 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1478 ThrowIfDisposedAndClosed ();
1479 ThrowIfBufferNull (buffer);
1480 ThrowIfBufferOutOfRange (buffer, offset, size);
1483 int ret = Receive_internal (m_Handle, buffer, offset, size, socketFlags, out nativeError);
1485 errorCode = (SocketError) nativeError;
1486 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1487 is_connected = false;
1490 is_connected = true;
1496 [CLSCompliant (false)]
1497 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1499 ThrowIfDisposedAndClosed ();
1501 if (buffers == null || buffers.Count == 0)
1502 throw new ArgumentNullException ("buffers");
1504 int numsegments = buffers.Count;
1508 /* Only example I can find of sending a byte array reference directly into an internal
1509 * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1510 * so taking a lead from that... */
1511 WSABUF[] bufarray = new WSABUF[numsegments];
1512 GCHandle[] gch = new GCHandle[numsegments];
1514 for (int i = 0; i < numsegments; i++) {
1515 ArraySegment<byte> segment = buffers[i];
1517 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1518 throw new ArgumentOutOfRangeException ("segment");
1520 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1521 bufarray[i].len = segment.Count;
1522 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1526 ret = Receive_internal (m_Handle, bufarray, socketFlags, out nativeError);
1528 for (int i = 0; i < numsegments; i++) {
1529 if (gch[i].IsAllocated)
1534 errorCode = (SocketError) nativeError;
1539 public bool ReceiveAsync (SocketAsyncEventArgs e)
1541 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1543 ThrowIfDisposedAndClosed ();
1545 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1546 // thrown when e.Buffer and e.BufferList are null (works fine when one is
1547 // set to a valid object)
1548 if (e.Buffer == null && e.BufferList == null)
1549 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1551 if (e.Buffer == null) {
1552 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
1554 e.socket_async_result.Buffers = e.BufferList;
1556 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
1558 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
1560 e.socket_async_result.Buffer = e.Buffer;
1561 e.socket_async_result.Offset = e.Offset;
1562 e.socket_async_result.Size = e.Count;
1564 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
1570 static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
1571 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1573 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1574 throw new InvalidOperationException ("No operation in progress");
1577 e.BytesTransferred = e.current_socket.EndReceive (ares);
1578 } catch (SocketException se){
1579 e.SocketError = se.SocketErrorCode;
1580 } catch (ObjectDisposedException) {
1581 e.SocketError = SocketError.OperationAborted;
1587 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1589 ThrowIfDisposedAndClosed ();
1590 ThrowIfBufferNull (buffer);
1591 ThrowIfBufferOutOfRange (buffer, offset, size);
1593 /* As far as I can tell from the docs and from experimentation, a pointer to the
1594 * SocketError parameter is not supposed to be saved for the async parts. And as we don't
1595 * set any socket errors in the setup code, we just have to set it to Success. */
1596 errorCode = SocketError.Success;
1598 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1602 SockFlags = socketFlags,
1605 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
1610 static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
1611 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1615 total = Receive_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
1616 } catch (Exception e) {
1617 sockares.Complete (e);
1621 sockares.Complete (total);
1624 [CLSCompliant (false)]
1625 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1627 ThrowIfDisposedAndClosed ();
1629 if (buffers == null)
1630 throw new ArgumentNullException ("buffers");
1632 /* I assume the same SocketError semantics as above */
1633 errorCode = SocketError.Success;
1635 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1637 SockFlags = socketFlags,
1640 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
1645 static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
1646 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1650 total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
1651 } catch (Exception e) {
1652 sockares.Complete (e);
1656 sockares.Complete (total);
1659 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
1661 ThrowIfDisposedAndClosed ();
1663 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
1665 if (!sockares.IsCompleted)
1666 sockares.AsyncWaitHandle.WaitOne ();
1668 errorCode = sockares.ErrorCode;
1670 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress)
1671 is_connected = false;
1673 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
1674 // kinds of exceptions that should be thrown.
1675 if (errorCode == SocketError.Success)
1676 sockares.CheckIfThrowDelayedException();
1678 return sockares.Total;
1681 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
1684 safeHandle.RegisterForBlockingSyscall ();
1685 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
1687 safeHandle.UnRegisterForBlockingSyscall ();
1691 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1692 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
1694 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
1697 safeHandle.RegisterForBlockingSyscall ();
1698 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
1700 safeHandle.UnRegisterForBlockingSyscall ();
1704 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1705 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error);
1711 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
1713 ThrowIfDisposedAndClosed ();
1714 ThrowIfBufferNull (buffer);
1715 ThrowIfBufferOutOfRange (buffer, offset, size);
1717 if (remoteEP == null)
1718 throw new ArgumentNullException ("remoteEP");
1720 SocketError errorCode;
1721 int ret = ReceiveFrom (buffer, offset, size, socketFlags, ref remoteEP, out errorCode);
1723 if (errorCode != SocketError.Success)
1724 throw new SocketException (errorCode);
1729 internal int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, out SocketError errorCode)
1731 SocketAddress sockaddr = remoteEP.Serialize();
1734 int cnt = ReceiveFrom_internal (m_Handle, buffer, offset, size, socketFlags, ref sockaddr, out nativeError);
1736 errorCode = (SocketError) nativeError;
1737 if (errorCode != SocketError.Success) {
1738 if (errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1739 is_connected = false;
1740 } else if (errorCode == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
1741 errorCode = SocketError.TimedOut;
1747 is_connected = true;
1750 /* If sockaddr is null then we're a connection oriented protocol and should ignore the
1751 * remoteEP parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
1752 if (sockaddr != null) {
1753 /* Stupidly, EndPoint.Create() is an instance method */
1754 remoteEP = remoteEP.Create (sockaddr);
1757 seed_endpoint = remoteEP;
1762 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
1764 ThrowIfDisposedAndClosed ();
1766 // We do not support recv into multiple buffers yet
1767 if (e.BufferList != null)
1768 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
1769 if (e.RemoteEndPoint == null)
1770 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
1772 InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
1774 e.socket_async_result.Buffer = e.Buffer;
1775 e.socket_async_result.Offset = e.Offset;
1776 e.socket_async_result.Size = e.Count;
1777 e.socket_async_result.EndPoint = e.RemoteEndPoint;
1778 e.socket_async_result.SockFlags = e.SocketFlags;
1780 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
1785 static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
1786 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1788 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1789 throw new InvalidOperationException ("No operation in progress");
1792 e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
1793 } catch (SocketException ex) {
1794 e.SocketError = ex.SocketErrorCode;
1795 } catch (ObjectDisposedException) {
1796 e.SocketError = SocketError.OperationAborted;
1802 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
1804 ThrowIfDisposedAndClosed ();
1805 ThrowIfBufferNull (buffer);
1806 ThrowIfBufferOutOfRange (buffer, offset, size);
1808 if (remote_end == null)
1809 throw new ArgumentNullException ("remote_end");
1811 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
1815 SockFlags = socket_flags,
1816 EndPoint = remote_end,
1819 QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
1824 static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
1825 SocketAsyncResult sockares = (SocketAsyncResult) ares;
1829 SocketError errorCode;
1830 total = sockares.socket.ReceiveFrom (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, out errorCode);
1832 if (errorCode != SocketError.Success) {
1833 sockares.Complete (new SocketException (errorCode));
1836 } catch (Exception e) {
1837 sockares.Complete (e);
1841 sockares.Complete (total);
1844 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
1846 ThrowIfDisposedAndClosed ();
1848 if (end_point == null)
1849 throw new ArgumentNullException ("remote_end");
1851 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
1853 if (!sockares.IsCompleted)
1854 sockares.AsyncWaitHandle.WaitOne();
1856 sockares.CheckIfThrowDelayedException();
1858 end_point = sockares.EndPoint;
1860 return sockares.Total;
1865 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error)
1868 safeHandle.RegisterForBlockingSyscall ();
1869 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
1871 safeHandle.UnRegisterForBlockingSyscall ();
1875 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1876 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error);
1880 #region ReceiveMessageFrom
1882 [MonoTODO ("Not implemented")]
1883 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
1885 ThrowIfDisposedAndClosed ();
1886 ThrowIfBufferNull (buffer);
1887 ThrowIfBufferOutOfRange (buffer, offset, size);
1889 if (remoteEP == null)
1890 throw new ArgumentNullException ("remoteEP");
1892 // FIXME: figure out how we get hold of the IPPacketInformation
1893 throw new NotImplementedException ();
1896 [MonoTODO ("Not implemented")]
1897 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
1899 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1901 ThrowIfDisposedAndClosed ();
1903 throw new NotImplementedException ();
1907 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
1909 ThrowIfDisposedAndClosed ();
1910 ThrowIfBufferNull (buffer);
1911 ThrowIfBufferOutOfRange (buffer, offset, size);
1913 if (remoteEP == null)
1914 throw new ArgumentNullException ("remoteEP");
1916 throw new NotImplementedException ();
1920 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
1922 ThrowIfDisposedAndClosed ();
1924 if (endPoint == null)
1925 throw new ArgumentNullException ("endPoint");
1927 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
1929 throw new NotImplementedException ();
1936 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1938 ThrowIfDisposedAndClosed ();
1939 ThrowIfBufferNull (buffer);
1940 ThrowIfBufferOutOfRange (buffer, offset, size);
1943 errorCode = SocketError.Success;
1950 sent += Send_internal (
1951 m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError);
1952 errorCode = (SocketError)nativeError;
1953 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1954 is_connected = false;
1958 is_connected = true;
1960 } while (sent < size);
1965 [CLSCompliant (false)]
1966 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1968 ThrowIfDisposedAndClosed ();
1970 if (buffers == null)
1971 throw new ArgumentNullException ("buffers");
1972 if (buffers.Count == 0)
1973 throw new ArgumentException ("Buffer is empty", "buffers");
1975 int numsegments = buffers.Count;
1979 WSABUF[] bufarray = new WSABUF[numsegments];
1980 GCHandle[] gch = new GCHandle[numsegments];
1982 for(int i = 0; i < numsegments; i++) {
1983 ArraySegment<byte> segment = buffers[i];
1985 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1986 throw new ArgumentOutOfRangeException ("segment");
1988 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1989 bufarray[i].len = segment.Count;
1990 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1994 ret = Send_internal (m_Handle, bufarray, socketFlags, out nativeError);
1996 for(int i = 0; i < numsegments; i++) {
1997 if (gch[i].IsAllocated) {
2003 errorCode = (SocketError)nativeError;
2008 public bool SendAsync (SocketAsyncEventArgs e)
2010 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2012 ThrowIfDisposedAndClosed ();
2014 if (e.Buffer == null && e.BufferList == null)
2015 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
2017 if (e.Buffer == null) {
2018 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
2020 e.socket_async_result.Buffers = e.BufferList;
2022 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
2024 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
2026 e.socket_async_result.Buffer = e.Buffer;
2027 e.socket_async_result.Offset = e.Offset;
2028 e.socket_async_result.Size = e.Count;
2030 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2036 static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
2037 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2039 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2040 throw new InvalidOperationException ("No operation in progress");
2043 e.BytesTransferred = e.current_socket.EndSend (ares);
2044 } catch (SocketException se){
2045 e.SocketError = se.SocketErrorCode;
2046 } catch (ObjectDisposedException) {
2047 e.SocketError = SocketError.OperationAborted;
2053 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2055 ThrowIfDisposedAndClosed ();
2056 ThrowIfBufferNull (buffer);
2057 ThrowIfBufferOutOfRange (buffer, offset, size);
2059 if (!is_connected) {
2060 errorCode = SocketError.NotConnected;
2064 errorCode = SocketError.Success;
2066 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
2070 SockFlags = socketFlags,
2073 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
2078 static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
2083 total = Socket.Send_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
2084 } catch (Exception e) {
2085 sockares.Complete (e);
2089 if (sockares.error == 0) {
2090 sent_so_far += total;
2091 sockares.Offset += total;
2092 sockares.Size -= total;
2094 if (sockares.socket.CleanedUp) {
2095 sockares.Complete (total);
2099 if (sockares.Size > 0) {
2100 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2101 return; // Have to finish writing everything. See bug #74475.
2104 sockares.Total = sent_so_far;
2107 sockares.Complete (total);
2110 [CLSCompliant (false)]
2111 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2113 ThrowIfDisposedAndClosed ();
2115 if (buffers == null)
2116 throw new ArgumentNullException ("buffers");
2118 if (!is_connected) {
2119 errorCode = SocketError.NotConnected;
2123 errorCode = SocketError.Success;
2125 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
2127 SockFlags = socketFlags,
2130 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
2135 static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
2136 SocketAsyncResult sockares = (SocketAsyncResult) ares;
2140 total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
2141 } catch (Exception e) {
2142 sockares.Complete (e);
2146 sockares.Complete (total);
2149 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
2151 ThrowIfDisposedAndClosed ();
2153 SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
2155 if (!sockares.IsCompleted)
2156 sockares.AsyncWaitHandle.WaitOne ();
2158 errorCode = sockares.ErrorCode;
2160 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress)
2161 is_connected = false;
2163 /* If no socket error occurred, call CheckIfThrowDelayedException in
2164 * case there are other kinds of exceptions that should be thrown.*/
2165 if (errorCode == SocketError.Success)
2166 sockares.CheckIfThrowDelayedException ();
2168 return sockares.Total;
2171 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2173 bool release = false;
2175 safeHandle.DangerousAddRef (ref release);
2176 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2179 safeHandle.DangerousRelease ();
2183 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2184 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2186 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
2189 safeHandle.RegisterForBlockingSyscall ();
2190 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
2192 safeHandle.UnRegisterForBlockingSyscall ();
2196 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2197 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
2203 public int SendTo (byte [] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP)
2205 ThrowIfDisposedAndClosed ();
2206 ThrowIfBufferNull (buffer);
2207 ThrowIfBufferOutOfRange (buffer, offset, size);
2209 if (remoteEP == null)
2210 throw new ArgumentNullException("remoteEP");
2213 int ret = SendTo_internal (m_Handle, buffer, offset, size, socketFlags, remoteEP.Serialize (), out error);
2215 SocketError err = (SocketError) error;
2217 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2218 is_connected = false;
2219 throw new SocketException (error);
2222 is_connected = true;
2224 seed_endpoint = remoteEP;
2229 public bool SendToAsync (SocketAsyncEventArgs e)
2231 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2233 ThrowIfDisposedAndClosed ();
2235 if (e.BufferList != null)
2236 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2237 if (e.RemoteEndPoint == null)
2238 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2240 InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2242 e.socket_async_result.Buffer = e.Buffer;
2243 e.socket_async_result.Offset = e.Offset;
2244 e.socket_async_result.Size = e.Count;
2245 e.socket_async_result.SockFlags = e.SocketFlags;
2246 e.socket_async_result.EndPoint = e.RemoteEndPoint;
2248 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2253 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2254 SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2256 if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2257 throw new InvalidOperationException ("No operation in progress");
2260 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2261 } catch (SocketException ex) {
2262 e.SocketError = ex.SocketErrorCode;
2263 } catch (ObjectDisposedException) {
2264 e.SocketError = SocketError.OperationAborted;
2270 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2272 ThrowIfDisposedAndClosed ();
2273 ThrowIfBufferNull (buffer);
2274 ThrowIfBufferOutOfRange (buffer, offset, size);
2276 SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2280 SockFlags = socket_flags,
2281 EndPoint = remote_end,
2284 QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2289 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2293 total = sockares.socket.SendTo (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2295 if (sockares.error == 0) {
2296 sent_so_far += total;
2297 sockares.Offset += total;
2298 sockares.Size -= total;
2301 if (sockares.Size > 0) {
2302 IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2303 return; // Have to finish writing everything. See bug #74475.
2306 sockares.Total = sent_so_far;
2307 } catch (Exception e) {
2308 sockares.Complete (e);
2312 sockares.Complete ();
2315 public int EndSendTo (IAsyncResult result)
2317 ThrowIfDisposedAndClosed ();
2319 SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2321 if (!sockares.IsCompleted)
2322 sockares.AsyncWaitHandle.WaitOne();
2324 sockares.CheckIfThrowDelayedException();
2326 return sockares.Total;
2329 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
2332 safeHandle.RegisterForBlockingSyscall ();
2333 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
2335 safeHandle.UnRegisterForBlockingSyscall ();
2339 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2340 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
2346 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2348 ThrowIfDisposedAndClosed ();
2351 throw new NotSupportedException ();
2353 throw new InvalidOperationException ();
2355 if (!SendFile_internal (m_Handle, fileName, preBuffer, postBuffer, flags)) {
2356 SocketException exc = new SocketException ();
2357 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2358 throw new FileNotFoundException ();
2363 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2365 ThrowIfDisposedAndClosed ();
2368 throw new NotSupportedException ();
2369 if (!File.Exists (fileName))
2370 throw new FileNotFoundException ();
2372 SendFileHandler handler = new SendFileHandler (SendFile);
2374 return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2377 public void EndSendFile (IAsyncResult asyncResult)
2379 ThrowIfDisposedAndClosed ();
2381 if (asyncResult == null)
2382 throw new ArgumentNullException ("asyncResult");
2384 SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2386 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2388 ares.Delegate.EndInvoke (ares.Original);
2391 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
2394 safeHandle.RegisterForBlockingSyscall ();
2395 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
2397 safeHandle.UnRegisterForBlockingSyscall ();
2401 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2402 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
2404 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2406 sealed class SendFileAsyncResult : IAsyncResult {
2410 public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2416 public object AsyncState {
2417 get { return ares.AsyncState; }
2420 public WaitHandle AsyncWaitHandle {
2421 get { return ares.AsyncWaitHandle; }
2424 public bool CompletedSynchronously {
2425 get { return ares.CompletedSynchronously; }
2428 public bool IsCompleted {
2429 get { return ares.IsCompleted; }
2432 public SendFileHandler Delegate {
2436 public IAsyncResult Original {
2437 get { return ares; }
2445 [MonoTODO ("Not implemented")]
2446 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2448 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2450 ThrowIfDisposedAndClosed ();
2452 throw new NotImplementedException ();
2457 #region DuplicateAndClose
2459 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2460 public SocketInformation DuplicateAndClose (int targetProcessId)
2462 var si = new SocketInformation ();
2464 (is_listening ? SocketInformationOptions.Listening : 0) |
2465 (is_connected ? SocketInformationOptions.Connected : 0) |
2466 (is_blocking ? 0 : SocketInformationOptions.NonBlocking) |
2467 (useOverlappedIO ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
2469 si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)addressFamily, (int)socketType, (int)protocolType, is_bound ? 1 : 0, (long)Handle);
2477 #region GetSocketOption
2479 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2481 ThrowIfDisposedAndClosed ();
2483 if (optionValue == null)
2484 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2487 GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref optionValue, out error);
2490 throw new SocketException (error);
2493 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength)
2495 ThrowIfDisposedAndClosed ();
2498 byte[] byte_val = new byte [optionLength];
2499 GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref byte_val, out error);
2502 throw new SocketException (error);
2507 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
2509 ThrowIfDisposedAndClosed ();
2513 GetSocketOption_obj_internal (m_Handle, optionLevel, optionName, out obj_val, out error);
2516 throw new SocketException (error);
2518 if (optionName == SocketOptionName.Linger)
2519 return (LingerOption) obj_val;
2520 else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
2521 return (MulticastOption) obj_val;
2522 else if (obj_val is int)
2523 return (int) obj_val;
2528 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
2530 bool release = false;
2532 safeHandle.DangerousAddRef (ref release);
2533 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
2536 safeHandle.DangerousRelease ();
2540 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2541 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
2543 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
2545 bool release = false;
2547 safeHandle.DangerousAddRef (ref release);
2548 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
2551 safeHandle.DangerousRelease ();
2555 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2556 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
2560 #region SetSocketOption
2562 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2564 ThrowIfDisposedAndClosed ();
2566 // I'd throw an ArgumentNullException, but this is what MS does.
2567 if (optionValue == null)
2568 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2571 SetSocketOption_internal (m_Handle, optionLevel, optionName, null, optionValue, 0, out error);
2574 if (error == (int) SocketError.InvalidArgument)
2575 throw new ArgumentException ();
2576 throw new SocketException (error);
2580 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
2582 ThrowIfDisposedAndClosed ();
2584 // NOTE: if a null is passed, the byte[] overload is used instead...
2585 if (optionValue == null)
2586 throw new ArgumentNullException("optionValue");
2590 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
2591 LingerOption linger = optionValue as LingerOption;
2593 throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
2594 SetSocketOption_internal (m_Handle, optionLevel, optionName, linger, null, 0, out error);
2595 } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2596 MulticastOption multicast = optionValue as MulticastOption;
2597 if (multicast == null)
2598 throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
2599 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2600 } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2601 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
2602 if (multicast == null)
2603 throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
2604 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2606 throw new ArgumentException ("Invalid value specified.", "optionValue");
2610 if (error == (int) SocketError.InvalidArgument)
2611 throw new ArgumentException ();
2612 throw new SocketException (error);
2616 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
2618 int int_val = optionValue ? 1 : 0;
2620 SetSocketOption (optionLevel, optionName, int_val);
2623 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
2625 ThrowIfDisposedAndClosed ();
2627 if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse (protocolType))
2628 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.");
2631 SetSocketOption_internal (m_Handle, optionLevel, optionName, null, null, optionValue, out error);
2634 if (error == (int) SocketError.InvalidArgument)
2635 throw new ArgumentException ();
2636 throw new SocketException (error);
2640 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
2642 bool release = false;
2644 safeHandle.DangerousAddRef (ref release);
2645 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
2648 safeHandle.DangerousRelease ();
2652 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2653 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
2659 public int IOControl (int ioControlCode, byte [] optionInValue, byte [] optionOutValue)
2662 throw new ObjectDisposedException (GetType ().ToString ());
2665 int result = IOControl_internal (m_Handle, ioControlCode, optionInValue, optionOutValue, out error);
2668 throw new SocketException (error);
2670 throw new InvalidOperationException ("Must use Blocking property instead.");
2675 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
2677 bool release = false;
2679 safeHandle.DangerousAddRef (ref release);
2680 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
2683 safeHandle.DangerousRelease ();
2687 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
2688 * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
2689 * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
2690 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2691 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
2697 public void Close ()
2703 public void Close (int timeout)
2705 linger_timeout = timeout;
2709 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2710 internal extern static void Close_internal (IntPtr socket, out int error);
2716 public void Shutdown (SocketShutdown how)
2718 ThrowIfDisposedAndClosed ();
2721 throw new SocketException (10057); // Not connected
2724 Shutdown_internal (m_Handle, how, out error);
2727 throw new SocketException (error);
2730 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
2732 bool release = false;
2734 safeHandle.DangerousAddRef (ref release);
2735 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
2738 safeHandle.DangerousRelease ();
2742 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2743 internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
2749 protected virtual void Dispose (bool disposing)
2755 bool was_connected = is_connected;
2756 is_connected = false;
2758 if (m_Handle != null) {
2765 m_Handle.Dispose ();
2769 void Linger (IntPtr handle)
2771 if (!is_connected || linger_timeout <= 0)
2774 /* We don't want to receive any more data */
2776 Shutdown_internal (handle, SocketShutdown.Receive, out error);
2781 int seconds = linger_timeout / 1000;
2782 int ms = linger_timeout % 1000;
2784 /* If the other end closes, this will return 'true' with 'Available' == 0 */
2785 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
2791 LingerOption linger = new LingerOption (true, seconds);
2792 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
2793 /* Not needed, we're closing upon return */
2801 void ThrowIfDisposedAndClosed (Socket socket)
2803 if (socket.CleanedUp && socket.is_closed)
2804 throw new ObjectDisposedException (socket.GetType ().ToString ());
2807 void ThrowIfDisposedAndClosed ()
2809 if (CleanedUp && is_closed)
2810 throw new ObjectDisposedException (GetType ().ToString ());
2813 void ThrowIfBufferNull (byte[] buffer)
2816 throw new ArgumentNullException ("buffer");
2819 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
2822 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
2823 if (offset > buffer.Length)
2824 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
2826 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
2827 if (size > buffer.Length - offset)
2828 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
2833 if (protocolType == ProtocolType.Udp)
2834 throw new SocketException ((int)SocketError.ProtocolOption);
2837 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
2840 throw new ArgumentNullException (argName);
2842 SocketAsyncResult sockares = ares as SocketAsyncResult;
2843 if (sockares == null)
2844 throw new ArgumentException ("Invalid IAsyncResult", argName);
2845 if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
2846 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
2851 void QueueIOSelectorJob (Queue<KeyValuePair<IntPtr, IOSelectorJob>> queue, IntPtr handle, IOSelectorJob job)
2855 queue.Enqueue (new KeyValuePair<IntPtr, IOSelectorJob> (handle, job));
2856 count = queue.Count;
2860 IOSelector.Add (handle, job);
2863 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
2865 e.socket_async_result.Init (this, callback, state, operation);
2866 if (e.AcceptSocket != null) {
2867 e.socket_async_result.AcceptSocket = e.AcceptSocket;
2869 e.current_socket = this;
2870 e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
2871 e.SocketError = SocketError.Success;
2872 e.BytesTransferred = 0;
2875 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
2878 case SocketOperation.Connect:
2879 return SocketAsyncOperation.Connect;
2880 case SocketOperation.Accept:
2881 return SocketAsyncOperation.Accept;
2882 case SocketOperation.Disconnect:
2883 return SocketAsyncOperation.Disconnect;
2884 case SocketOperation.Receive:
2885 case SocketOperation.ReceiveGeneric:
2886 return SocketAsyncOperation.Receive;
2887 case SocketOperation.ReceiveFrom:
2888 return SocketAsyncOperation.ReceiveFrom;
2889 case SocketOperation.Send:
2890 case SocketOperation.SendGeneric:
2891 return SocketAsyncOperation.Send;
2892 case SocketOperation.SendTo:
2893 return SocketAsyncOperation.SendTo;
2895 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
2899 IPEndPoint RemapIPEndPoint (IPEndPoint input) {
2900 // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
2901 if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
2902 return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
2907 [StructLayout (LayoutKind.Sequential)]
2913 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2914 internal static extern void cancel_blocking_socket_operation (Thread thread);
2916 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2917 internal static extern bool SupportsPortReuse (ProtocolType proto);