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";
58 /* true if we called Close_internal */
66 AddressFamily addressFamily
;
67 SocketType socketType
;
68 ProtocolType protocolType
;
70 /* the field "m_Handle" is looked up by name by the runtime */
71 internal SafeSocketHandle m_Handle
;
74 * This EndPoint is used when creating new endpoints. Because
75 * there are many types of EndPoints possible,
76 * seed_endpoint.Create(addr) is used for creating new ones.
77 * As such, this value is set on Bind, SentTo, ReceiveFrom,
80 internal EndPoint seed_endpoint
= null;
82 internal SemaphoreSlim ReadSem
= new SemaphoreSlim (1, 1);
83 internal SemaphoreSlim WriteSem
= new SemaphoreSlim (1, 1);
85 internal bool is_blocking
= true;
86 internal bool is_bound
;
88 /* When true, the socket was connected at the time of the last IO operation */
89 internal bool is_connected
;
92 internal bool connect_in_progress
;
97 public Socket (SocketInformation socketInformation
)
99 this.is_listening
= (socketInformation
.Options
& SocketInformationOptions
.Listening
) != 0;
100 this.is_connected
= (socketInformation
.Options
& SocketInformationOptions
.Connected
) != 0;
101 this.is_blocking
= (socketInformation
.Options
& SocketInformationOptions
.NonBlocking
) == 0;
102 this.useOverlappedIO
= (socketInformation
.Options
& SocketInformationOptions
.UseOnlyOverlappedIO
) != 0;
104 var result
= Mono
.DataConverter
.Unpack ("iiiil", socketInformation
.ProtocolInformation
, 0);
106 this.addressFamily
= (AddressFamily
) (int) result
[0];
107 this.socketType
= (SocketType
) (int) result
[1];
108 this.protocolType
= (ProtocolType
) (int) result
[2];
109 this.is_bound
= (ProtocolType
) (int) result
[3] != 0;
110 this.m_Handle
= new SafeSocketHandle ((IntPtr
) (long) result
[4], true);
112 InitializeSockets ();
117 /* private constructor used by Accept, which already has a socket handle to use */
118 internal Socket(AddressFamily family
, SocketType type
, ProtocolType proto
, SafeSocketHandle safe_handle
)
120 this.addressFamily
= family
;
121 this.socketType
= type
;
122 this.protocolType
= proto
;
124 this.m_Handle
= safe_handle
;
125 this.is_connected
= true;
127 InitializeSockets ();
130 void SocketDefaults ()
133 /* Need to test IPv6 further */
134 if (addressFamily
== AddressFamily
.InterNetwork
135 // || addressFamily == AddressFamily.InterNetworkV6
137 /* This is the default, but it probably has nasty side
138 * effects on Linux, as the socket option is kludged by
139 * turning on or off PMTU discovery... */
140 this.DontFragment
= false;
141 if (protocolType
== ProtocolType
.Tcp
)
142 this.NoDelay
= false;
143 } else if (addressFamily
== AddressFamily
.InterNetworkV6
) {
144 this.DualMode
= true;
147 /* Microsoft sets these to 8192, but we are going to keep them
148 * both to the OS defaults as these have a big performance impact.
149 * on WebClient performance. */
150 // this.ReceiveBufferSize = 8192;
151 // this.SendBufferSize = 8192;
152 } catch (SocketException
) {
156 /* Creates a new system socket, returning the handle */
157 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
158 extern IntPtr
Socket_internal (AddressFamily family
, SocketType type
, ProtocolType proto
, out int error
);
164 public int Available
{
166 ThrowIfDisposedAndClosed ();
169 ret
= Available_internal (m_Handle
, out error
);
172 throw new SocketException (error
);
178 static int Available_internal (SafeSocketHandle safeHandle
, out int error
)
180 bool release
= false;
182 safeHandle
.DangerousAddRef (ref release
);
183 return Available_internal (safeHandle
.DangerousGetHandle (), out error
);
186 safeHandle
.DangerousRelease ();
190 /* Returns the amount of data waiting to be read on socket */
191 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
192 extern static int Available_internal (IntPtr socket
, out int error
);
194 // FIXME: import from referencesource
195 public bool EnableBroadcast
{
197 ThrowIfDisposedAndClosed ();
199 if (protocolType
!= ProtocolType
.Udp
)
200 throw new SocketException ((int) SocketError
.ProtocolOption
);
202 return ((int) GetSocketOption (SocketOptionLevel
.Socket
, SocketOptionName
.Broadcast
)) != 0;
205 ThrowIfDisposedAndClosed ();
207 if (protocolType
!= ProtocolType
.Udp
)
208 throw new SocketException ((int) SocketError
.ProtocolOption
);
210 SetSocketOption (SocketOptionLevel
.Socket
, SocketOptionName
.Broadcast
, value ? 1 : 0);
214 public bool IsBound
{
220 // FIXME: import from referencesource
221 public bool MulticastLoopback
{
223 ThrowIfDisposedAndClosed ();
225 /* Even though this option can be set for TCP sockets on Linux, throw
226 * this exception anyway to be compatible (the MSDN docs say
227 * "Setting this property on a Transmission Control Protocol (TCP)
228 * socket will have no effect." but the MS runtime throws the
230 if (protocolType
== ProtocolType
.Tcp
)
231 throw new SocketException ((int)SocketError
.ProtocolOption
);
233 switch (addressFamily
) {
234 case AddressFamily
.InterNetwork
:
235 return ((int) GetSocketOption (SocketOptionLevel
.IP
, SocketOptionName
.MulticastLoopback
)) != 0;
236 case AddressFamily
.InterNetworkV6
:
237 return ((int) GetSocketOption (SocketOptionLevel
.IPv6
, SocketOptionName
.MulticastLoopback
)) != 0;
239 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
243 ThrowIfDisposedAndClosed ();
245 /* Even though this option can be set for TCP sockets on Linux, throw
246 * this exception anyway to be compatible (the MSDN docs say
247 * "Setting this property on a Transmission Control Protocol (TCP)
248 * socket will have no effect." but the MS runtime throws the
250 if (protocolType
== ProtocolType
.Tcp
)
251 throw new SocketException ((int)SocketError
.ProtocolOption
);
253 switch (addressFamily
) {
254 case AddressFamily
.InterNetwork
:
255 SetSocketOption (SocketOptionLevel
.IP
, SocketOptionName
.MulticastLoopback
, value ? 1 : 0);
257 case AddressFamily
.InterNetworkV6
:
258 SetSocketOption (SocketOptionLevel
.IPv6
, SocketOptionName
.MulticastLoopback
, value ? 1 : 0);
261 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
266 // Wish: support non-IP endpoints.
267 public EndPoint LocalEndPoint
{
269 ThrowIfDisposedAndClosed ();
271 /* If the seed EndPoint is null, Connect, Bind, etc has not yet
272 * been called. MS returns null in this case. */
273 if (seed_endpoint
== null)
277 SocketAddress sa
= LocalEndPoint_internal (m_Handle
, (int) addressFamily
, out error
);
280 throw new SocketException (error
);
282 return seed_endpoint
.Create (sa
);
286 static SocketAddress
LocalEndPoint_internal (SafeSocketHandle safeHandle
, int family
, out int error
)
288 bool release
= false;
290 safeHandle
.DangerousAddRef (ref release
);
291 return LocalEndPoint_internal (safeHandle
.DangerousGetHandle (), family
, out error
);
294 safeHandle
.DangerousRelease ();
298 /* Returns the local endpoint details in addr and port */
299 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
300 extern static SocketAddress
LocalEndPoint_internal (IntPtr socket
, int family
, out int error
);
302 public bool Blocking
{
303 get { return is_blocking; }
305 ThrowIfDisposedAndClosed ();
308 Blocking_internal (m_Handle
, value, out error
);
311 throw new SocketException (error
);
317 static void Blocking_internal (SafeSocketHandle safeHandle
, bool block
, out int error
)
319 bool release
= false;
321 safeHandle
.DangerousAddRef (ref release
);
322 Blocking_internal (safeHandle
.DangerousGetHandle (), block
, out error
);
325 safeHandle
.DangerousRelease ();
329 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
330 internal extern static void Blocking_internal(IntPtr socket
, bool block
, out int error
);
332 public bool Connected
{
333 get { return is_connected; }
334 internal set { is_connected = value; }
337 // FIXME: import from referencesource
338 public bool NoDelay
{
340 ThrowIfDisposedAndClosed ();
343 return ((int) GetSocketOption (SocketOptionLevel
.Tcp
, SocketOptionName
.NoDelay
)) != 0;
347 ThrowIfDisposedAndClosed ();
349 SetSocketOption (SocketOptionLevel
.Tcp
, SocketOptionName
.NoDelay
, value ? 1 : 0);
353 public EndPoint RemoteEndPoint
{
355 ThrowIfDisposedAndClosed ();
357 /* If the seed EndPoint is null, Connect, Bind, etc has
358 * not yet been called. MS returns null in this case. */
359 if (!is_connected
|| seed_endpoint
== null)
363 SocketAddress sa
= RemoteEndPoint_internal (m_Handle
, (int) addressFamily
, out error
);
366 throw new SocketException (error
);
368 return seed_endpoint
.Create (sa
);
372 static SocketAddress
RemoteEndPoint_internal (SafeSocketHandle safeHandle
, int family
, out int error
)
374 bool release
= false;
376 safeHandle
.DangerousAddRef (ref release
);
377 return RemoteEndPoint_internal (safeHandle
.DangerousGetHandle (), family
, out error
);
380 safeHandle
.DangerousRelease ();
384 /* Returns the remote endpoint details in addr and port */
385 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
386 extern static SocketAddress
RemoteEndPoint_internal (IntPtr socket
, int family
, out int error
);
392 public static void Select (IList checkRead
, IList checkWrite
, IList checkError
, int microSeconds
)
394 var list
= new List
<Socket
> ();
395 AddSockets (list
, checkRead
, "checkRead");
396 AddSockets (list
, checkWrite
, "checkWrite");
397 AddSockets (list
, checkError
, "checkError");
400 throw new ArgumentNullException ("checkRead, checkWrite, checkError", "All the lists are null or empty.");
402 /* The 'sockets' array contains:
403 * - READ socket 0-n, null,
404 * - WRITE socket 0-n, null,
405 * - ERROR socket 0-n, null */
406 Socket
[] sockets
= list
.ToArray ();
409 Select_internal (ref sockets
, microSeconds
, out error
);
412 throw new SocketException (error
);
414 if (sockets
== null) {
415 if (checkRead
!= null)
417 if (checkWrite
!= null)
419 if (checkError
!= null)
425 int count
= sockets
.Length
;
426 IList currentList
= checkRead
;
428 for (int i
= 0; i
< count
; i
++) {
429 Socket sock
= sockets
[i
];
430 if (sock
== null) { // separator
431 if (currentList
!= null) {
432 // Remove non-signaled sockets after the current one
433 int to_remove
= currentList
.Count
- currentIdx
;
434 for (int k
= 0; k
< to_remove
; k
++)
435 currentList
.RemoveAt (currentIdx
);
437 currentList
= (mode
== 0) ? checkWrite
: checkError
;
443 if (mode
== 1 && currentList
== checkWrite
&& !sock
.is_connected
) {
444 if ((int) sock
.GetSocketOption (SocketOptionLevel
.Socket
, SocketOptionName
.Error
) == 0)
445 sock
.is_connected
= true;
448 /* Remove non-signaled sockets before the current one */
449 while (((Socket
) currentList
[currentIdx
]) != sock
)
450 currentList
.RemoveAt (currentIdx
);
456 static void AddSockets (List
<Socket
> sockets
, IList list
, string name
)
459 foreach (Socket sock
in list
) {
460 if (sock
== null) // MS throws a NullRef
461 throw new ArgumentNullException ("name", "Contains a null element");
469 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
470 extern static void Select_internal (ref Socket
[] sockets
, int microSeconds
, out int error
);
476 public bool Poll (int microSeconds
, SelectMode mode
)
478 ThrowIfDisposedAndClosed ();
480 if (mode
!= SelectMode
.SelectRead
&& mode
!= SelectMode
.SelectWrite
&& mode
!= SelectMode
.SelectError
)
481 throw new NotSupportedException ("'mode' parameter is not valid.");
484 bool result
= Poll_internal (m_Handle
, mode
, microSeconds
, out error
);
487 throw new SocketException (error
);
489 if (mode
== SelectMode
.SelectWrite
&& result
&& !is_connected
) {
490 /* Update the is_connected state; for non-blocking Connect()
491 * this is when we can find out that the connect succeeded. */
492 if ((int) GetSocketOption (SocketOptionLevel
.Socket
, SocketOptionName
.Error
) == 0)
499 static bool Poll_internal (SafeSocketHandle safeHandle
, SelectMode mode
, int timeout
, out int error
)
501 bool release
= false;
503 safeHandle
.DangerousAddRef (ref release
);
504 return Poll_internal (safeHandle
.DangerousGetHandle (), mode
, timeout
, out error
);
507 safeHandle
.DangerousRelease ();
511 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
512 extern static bool Poll_internal (IntPtr socket
, SelectMode mode
, int timeout
, out int error
);
518 public Socket
Accept()
520 ThrowIfDisposedAndClosed ();
523 SafeSocketHandle safe_handle
= Accept_internal (this.m_Handle
, out error
, is_blocking
);
527 error
= SOCKET_CLOSED_CODE
;
528 throw new SocketException(error
);
531 Socket accepted
= new Socket (this.AddressFamily
, this.SocketType
, this.ProtocolType
, safe_handle
) {
532 seed_endpoint
= this.seed_endpoint
,
533 Blocking
= this.Blocking
,
539 internal void Accept (Socket acceptSocket
)
541 ThrowIfDisposedAndClosed ();
544 SafeSocketHandle safe_handle
= Accept_internal (this.m_Handle
, out error
, is_blocking
);
548 error
= SOCKET_CLOSED_CODE
;
549 throw new SocketException (error
);
552 acceptSocket
.addressFamily
= this.AddressFamily
;
553 acceptSocket
.socketType
= this.SocketType
;
554 acceptSocket
.protocolType
= this.ProtocolType
;
555 acceptSocket
.m_Handle
= safe_handle
;
556 acceptSocket
.is_connected
= true;
557 acceptSocket
.seed_endpoint
= this.seed_endpoint
;
558 acceptSocket
.Blocking
= this.Blocking
;
560 // FIXME: figure out what if anything else needs to be reset
563 public bool AcceptAsync (SocketAsyncEventArgs e
)
565 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
567 ThrowIfDisposedAndClosed ();
570 throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
572 throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
573 if (e
.BufferList
!= null)
574 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
576 throw new ArgumentOutOfRangeException ("e.Count");
578 Socket acceptSocket
= e
.AcceptSocket
;
579 if (acceptSocket
!= null) {
580 if (acceptSocket
.is_bound
|| acceptSocket
.is_connected
)
581 throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
584 InitSocketAsyncEventArgs (e
, AcceptAsyncCallback
, e
, SocketOperation
.Accept
);
586 QueueIOSelectorJob (ReadSem
, e
.socket_async_result
.Handle
, new IOSelectorJob (IOOperation
.Read
, BeginAcceptCallback
, e
.socket_async_result
));
591 static AsyncCallback AcceptAsyncCallback
= new AsyncCallback (ares
=> {
592 SocketAsyncEventArgs e
= (SocketAsyncEventArgs
) ((SocketAsyncResult
) ares
).AsyncState
;
594 if (Interlocked
.Exchange (ref e
.in_progress
, 0) != 1)
595 throw new InvalidOperationException ("No operation in progress");
598 e
.AcceptSocket
= e
.current_socket
.EndAccept (ares
);
599 } catch (SocketException ex
) {
600 e
.SocketError
= ex
.SocketErrorCode
;
601 } catch (ObjectDisposedException
) {
602 e
.SocketError
= SocketError
.OperationAborted
;
604 if (e
.AcceptSocket
== null)
605 e
.AcceptSocket
= new Socket (e
.current_socket
.AddressFamily
, e
.current_socket
.SocketType
, e
.current_socket
.ProtocolType
, null);
610 public IAsyncResult
BeginAccept(AsyncCallback callback
, object state
)
612 ThrowIfDisposedAndClosed ();
614 if (!is_bound
|| !is_listening
)
615 throw new InvalidOperationException ();
617 SocketAsyncResult sockares
= new SocketAsyncResult (this, callback
, state
, SocketOperation
.Accept
);
619 QueueIOSelectorJob (ReadSem
, sockares
.Handle
, new IOSelectorJob (IOOperation
.Read
, BeginAcceptCallback
, sockares
));
624 static IOAsyncCallback BeginAcceptCallback
= new IOAsyncCallback (ares
=> {
625 SocketAsyncResult sockares
= (SocketAsyncResult
) ares
;
626 Socket acc_socket
= null;
628 if (sockares
.AcceptSocket
== null) {
629 acc_socket
= sockares
.socket
.Accept ();
631 acc_socket
= sockares
.AcceptSocket
;
632 sockares
.socket
.Accept (acc_socket
);
635 } catch (Exception e
) {
636 sockares
.Complete (e
);
639 sockares
.Complete (acc_socket
);
642 public IAsyncResult
BeginAccept (Socket acceptSocket
, int receiveSize
, AsyncCallback callback
, object state
)
644 ThrowIfDisposedAndClosed ();
647 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
649 if (acceptSocket
!= null) {
650 ThrowIfDisposedAndClosed (acceptSocket
);
652 if (acceptSocket
.IsBound
)
653 throw new InvalidOperationException ();
655 /* For some reason the MS runtime
656 * barfs if the new socket is not TCP,
657 * even though it's just about to blow
658 * away all those parameters
660 if (acceptSocket
.ProtocolType
!= ProtocolType
.Tcp
)
661 throw new SocketException ((int)SocketError
.InvalidArgument
);
664 SocketAsyncResult sockares
= new SocketAsyncResult (this, callback
, state
, SocketOperation
.AcceptReceive
) {
665 Buffer
= new byte [receiveSize
],
668 SockFlags
= SocketFlags
.None
,
669 AcceptSocket
= acceptSocket
,
672 QueueIOSelectorJob (ReadSem
, sockares
.Handle
, new IOSelectorJob (IOOperation
.Read
, BeginAcceptReceiveCallback
, sockares
));
677 static IOAsyncCallback BeginAcceptReceiveCallback
= new IOAsyncCallback (ares
=> {
678 SocketAsyncResult sockares
= (SocketAsyncResult
) ares
;
679 Socket acc_socket
= null;
682 if (sockares
.AcceptSocket
== null) {
683 acc_socket
= sockares
.socket
.Accept ();
685 acc_socket
= sockares
.AcceptSocket
;
686 sockares
.socket
.Accept (acc_socket
);
688 } catch (Exception e
) {
689 sockares
.Complete (e
);
693 /* It seems the MS runtime special-cases 0-length requested receive data. See bug 464201. */
695 if (sockares
.Size
> 0) {
698 total
= acc_socket
.Receive (sockares
.Buffer
, sockares
.Offset
, sockares
.Size
, sockares
.SockFlags
, out error
);
700 sockares
.Complete (new SocketException ((int) error
));
703 } catch (Exception e
) {
704 sockares
.Complete (e
);
709 sockares
.Complete (acc_socket
, total
);
712 public Socket
EndAccept (IAsyncResult result
)
716 return EndAccept (out buffer
, out bytes
, result
);
719 public Socket
EndAccept (out byte[] buffer
, out int bytesTransferred
, IAsyncResult asyncResult
)
721 ThrowIfDisposedAndClosed ();
723 SocketAsyncResult sockares
= ValidateEndIAsyncResult (asyncResult
, "EndAccept", "asyncResult");
725 if (!sockares
.IsCompleted
)
726 sockares
.AsyncWaitHandle
.WaitOne ();
728 sockares
.CheckIfThrowDelayedException ();
730 buffer
= sockares
.Buffer
;
731 bytesTransferred
= sockares
.Total
;
733 return sockares
.AcceptedSocket
;
736 static SafeSocketHandle
Accept_internal (SafeSocketHandle safeHandle
, out int error
, bool blocking
)
739 safeHandle
.RegisterForBlockingSyscall ();
740 var ret
= Accept_internal (safeHandle
.DangerousGetHandle (), out error
, blocking
);
741 return new SafeSocketHandle (ret
, true);
743 safeHandle
.UnRegisterForBlockingSyscall ();
747 /* Creates a new system socket, returning the handle */
748 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
749 extern static IntPtr
Accept_internal (IntPtr sock
, out int error
, bool blocking
);
755 public void Bind (EndPoint localEP
)
757 #if FEATURE_NO_BSD_SOCKETS
758 throw new PlatformNotSupportedException ("System.Net.Sockets.Socket:Bind is not supported on this platform.");
760 ThrowIfDisposedAndClosed ();
763 throw new ArgumentNullException("localEP");
765 var ipEndPoint
= localEP
as IPEndPoint
;
766 if (ipEndPoint
!= null) {
767 localEP
= RemapIPEndPoint (ipEndPoint
);
771 Bind_internal (m_Handle
, localEP
.Serialize(), out error
);
774 throw new SocketException (error
);
778 seed_endpoint
= localEP
;
779 #endif // FEATURE_NO_BSD_SOCKETS
782 private static void Bind_internal (SafeSocketHandle safeHandle
, SocketAddress sa
, out int error
)
784 bool release
= false;
786 safeHandle
.DangerousAddRef (ref release
);
787 Bind_internal (safeHandle
.DangerousGetHandle (), sa
, out error
);
790 safeHandle
.DangerousRelease ();
794 // Creates a new system socket, returning the handle
795 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
796 private extern static void Bind_internal(IntPtr sock
, SocketAddress sa
, out int error
);
802 public void Listen (int backlog
)
804 ThrowIfDisposedAndClosed ();
807 throw new SocketException ((int) SocketError
.InvalidArgument
);
810 Listen_internal(m_Handle
, backlog
, out error
);
813 throw new SocketException (error
);
818 static void Listen_internal (SafeSocketHandle safeHandle
, int backlog
, out int error
)
820 bool release
= false;
822 safeHandle
.DangerousAddRef (ref release
);
823 Listen_internal (safeHandle
.DangerousGetHandle (), backlog
, out error
);
826 safeHandle
.DangerousRelease ();
830 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
831 extern static void Listen_internal (IntPtr sock
, int backlog
, out int error
);
837 public void Connect (IPAddress address
, int port
)
839 Connect (new IPEndPoint (address
, port
));
842 public void Connect (string host
, int port
)
844 Connect (Dns
.GetHostAddresses (host
), port
);
847 public void Connect (EndPoint remoteEP
)
849 ThrowIfDisposedAndClosed ();
851 if (remoteEP
== null)
852 throw new ArgumentNullException ("remoteEP");
854 IPEndPoint ep
= remoteEP
as IPEndPoint
;
855 /* Dgram uses Any to 'disconnect' */
856 if (ep
!= null && socketType
!= SocketType
.Dgram
) {
857 if (ep
.Address
.Equals (IPAddress
.Any
) || ep
.Address
.Equals (IPAddress
.IPv6Any
))
858 throw new SocketException ((int) SocketError
.AddressNotAvailable
);
862 throw new InvalidOperationException ();
865 remoteEP
= RemapIPEndPoint (ep
);
868 SocketAddress serial
= remoteEP
.Serialize ();
871 Connect_internal (m_Handle
, serial
, out error
, is_blocking
);
873 if (error
== 0 || error
== 10035)
874 seed_endpoint
= remoteEP
; // Keep the ep around for non-blocking sockets
878 error
= SOCKET_CLOSED_CODE
;
879 throw new SocketException (error
);
882 is_connected
= !(socketType
== SocketType
.Dgram
&& ep
!= null && (ep
.Address
.Equals (IPAddress
.Any
) || ep
.Address
.Equals (IPAddress
.IPv6Any
)));
886 public bool ConnectAsync (SocketAsyncEventArgs e
)
888 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
890 ThrowIfDisposedAndClosed ();
893 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
894 if (e
.RemoteEndPoint
== null)
895 throw new ArgumentNullException ("remoteEP");
897 InitSocketAsyncEventArgs (e
, null, e
, SocketOperation
.Connect
);
900 IPAddress
[] addresses
;
901 SocketAsyncResult ares
;
903 if (!GetCheckedIPs (e
, out addresses
)) {
904 e
.socket_async_result
.EndPoint
= e
.RemoteEndPoint
;
905 ares
= (SocketAsyncResult
) BeginConnect (e
.RemoteEndPoint
, ConnectAsyncCallback
, e
);
907 DnsEndPoint dep
= (e
.RemoteEndPoint
as DnsEndPoint
);
908 e
.socket_async_result
.Addresses
= addresses
;
909 e
.socket_async_result
.Port
= dep
.Port
;
910 ares
= (SocketAsyncResult
) BeginConnect (addresses
, dep
.Port
, ConnectAsyncCallback
, e
);
913 if (ares
.IsCompleted
&& ares
.CompletedSynchronously
) {
914 ares
.CheckIfThrowDelayedException ();
917 } catch (Exception exc
) {
918 e
.socket_async_result
.Complete (exc
, true);
925 public static void CancelConnectAsync (SocketAsyncEventArgs e
)
928 throw new ArgumentNullException("e");
930 if (e
.in_progress
!= 0 && e
.LastOperation
== SocketAsyncOperation
.Connect
)
931 e
.current_socket
.Close();
934 static AsyncCallback ConnectAsyncCallback
= new AsyncCallback (ares
=> {
935 SocketAsyncEventArgs e
= (SocketAsyncEventArgs
) ((SocketAsyncResult
) ares
).AsyncState
;
937 if (Interlocked
.Exchange (ref e
.in_progress
, 0) != 1)
938 throw new InvalidOperationException ("No operation in progress");
941 e
.current_socket
.EndConnect (ares
);
942 } catch (SocketException se
) {
943 e
.SocketError
= se
.SocketErrorCode
;
944 } catch (ObjectDisposedException
) {
945 e
.SocketError
= SocketError
.OperationAborted
;
951 public IAsyncResult
BeginConnect (string host
, int port
, AsyncCallback callback
, object state
)
953 ThrowIfDisposedAndClosed ();
956 throw new ArgumentNullException ("host");
957 if (addressFamily
!= AddressFamily
.InterNetwork
&& addressFamily
!= AddressFamily
.InterNetworkV6
)
958 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
959 if (port
<= 0 || port
> 65535)
960 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
962 throw new InvalidOperationException ();
964 return BeginConnect (Dns
.GetHostAddresses (host
), port
, callback
, state
);
967 public IAsyncResult
BeginConnect (EndPoint end_point
, AsyncCallback callback
, object state
)
969 ThrowIfDisposedAndClosed ();
971 if (end_point
== null)
972 throw new ArgumentNullException ("end_point");
974 throw new InvalidOperationException ();
976 SocketAsyncResult sockares
= new SocketAsyncResult (this, callback
, state
, SocketOperation
.Connect
) {
977 EndPoint
= end_point
,
980 // Bug #75154: Connect() should not succeed for .Any addresses.
981 if (end_point
is IPEndPoint
) {
982 IPEndPoint ep
= (IPEndPoint
) end_point
;
983 if (ep
.Address
.Equals (IPAddress
.Any
) || ep
.Address
.Equals (IPAddress
.IPv6Any
)) {
984 sockares
.Complete (new SocketException ((int) SocketError
.AddressNotAvailable
), true);
988 end_point
= RemapIPEndPoint (ep
);
993 if (connect_in_progress
) {
994 // This could happen when multiple IPs are used
995 // Calling connect() again will reset the connection attempt and cause
996 // an error. Better to just close the socket and move on.
997 connect_in_progress
= false;
999 m_Handle
= new SafeSocketHandle (Socket_internal (addressFamily
, socketType
, protocolType
, out error
), true);
1001 throw new SocketException (error
);
1004 bool blk
= is_blocking
;
1007 Connect_internal (m_Handle
, end_point
.Serialize (), out error
, false);
1013 is_connected
= true;
1015 sockares
.Complete (true);
1019 if (error
!= (int) SocketError
.InProgress
&& error
!= (int) SocketError
.WouldBlock
) {
1021 is_connected
= false;
1023 sockares
.Complete (new SocketException (error
), true);
1028 is_connected
= false;
1030 connect_in_progress
= true;
1032 IOSelector
.Add (sockares
.Handle
, new IOSelectorJob (IOOperation
.Write
, BeginConnectCallback
, sockares
));
1037 public IAsyncResult
BeginConnect (IPAddress
[] addresses
, int port
, AsyncCallback callback
, object state
)
1039 ThrowIfDisposedAndClosed ();
1041 if (addresses
== null)
1042 throw new ArgumentNullException ("addresses");
1043 if (addresses
.Length
== 0)
1044 throw new ArgumentException ("Empty addresses list");
1045 if (this.AddressFamily
!= AddressFamily
.InterNetwork
&& this.AddressFamily
!= AddressFamily
.InterNetworkV6
)
1046 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1047 if (port
<= 0 || port
> 65535)
1048 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1050 throw new InvalidOperationException ();
1052 SocketAsyncResult sockares
= new SocketAsyncResult (this, callback
, state
, SocketOperation
.Connect
) {
1053 Addresses
= addresses
,
1057 is_connected
= false;
1059 return BeginMConnect (sockares
);
1062 internal IAsyncResult
BeginMConnect (SocketAsyncResult sockares
)
1064 SocketAsyncResult ares
= null;
1065 Exception exc
= null;
1066 AsyncCallback callback
;
1068 for (int i
= sockares
.CurrentAddress
; i
< sockares
.Addresses
.Length
; i
++) {
1070 sockares
.CurrentAddress
++;
1072 ares
= (SocketAsyncResult
) BeginConnect (new IPEndPoint (sockares
.Addresses
[i
], sockares
.Port
), null, sockares
);
1073 if (ares
.IsCompleted
&& ares
.CompletedSynchronously
) {
1074 ares
.CheckIfThrowDelayedException ();
1076 callback
= ares
.AsyncCallback
;
1077 if (callback
!= null)
1078 ThreadPool
.UnsafeQueueUserWorkItem (_
=> callback (ares
), null);
1082 } catch (Exception e
) {
1094 static IOAsyncCallback BeginConnectCallback
= new IOAsyncCallback (ares
=> {
1095 SocketAsyncResult sockares
= (SocketAsyncResult
) ares
;
1097 if (sockares
.EndPoint
== null) {
1098 sockares
.Complete (new SocketException ((int)SocketError
.AddressNotAvailable
));
1102 SocketAsyncResult mconnect
= sockares
.AsyncState
as SocketAsyncResult
;
1103 bool is_mconnect
= mconnect
!= null && mconnect
.Addresses
!= null;
1106 EndPoint ep
= sockares
.EndPoint
;
1107 int error_code
= (int) sockares
.socket
.GetSocketOption (SocketOptionLevel
.Socket
, SocketOptionName
.Error
);
1109 if (error_code
== 0) {
1111 sockares
= mconnect
;
1113 sockares
.socket
.seed_endpoint
= ep
;
1114 sockares
.socket
.is_connected
= true;
1115 sockares
.socket
.is_bound
= true;
1116 sockares
.socket
.connect_in_progress
= false;
1118 sockares
.Complete ();
1123 sockares
.socket
.connect_in_progress
= false;
1124 sockares
.Complete (new SocketException (error_code
));
1128 if (mconnect
.CurrentAddress
>= mconnect
.Addresses
.Length
) {
1129 mconnect
.Complete (new SocketException (error_code
));
1133 mconnect
.socket
.BeginMConnect (mconnect
);
1134 } catch (Exception e
) {
1135 sockares
.socket
.connect_in_progress
= false;
1138 sockares
= mconnect
;
1140 sockares
.Complete (e
);
1145 public void EndConnect (IAsyncResult result
)
1147 ThrowIfDisposedAndClosed ();
1149 SocketAsyncResult sockares
= ValidateEndIAsyncResult (result
, "EndConnect", "result");
1151 if (!sockares
.IsCompleted
)
1152 sockares
.AsyncWaitHandle
.WaitOne();
1154 sockares
.CheckIfThrowDelayedException();
1157 static void Connect_internal (SafeSocketHandle safeHandle
, SocketAddress sa
, out int error
, bool blocking
)
1160 safeHandle
.RegisterForBlockingSyscall ();
1161 Connect_internal (safeHandle
.DangerousGetHandle (), sa
, out error
, blocking
);
1163 safeHandle
.UnRegisterForBlockingSyscall ();
1167 /* Connects to the remote address */
1168 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1169 extern static void Connect_internal(IntPtr sock
, SocketAddress sa
, out int error
, bool blocking
);
1172 * - false when it is ok to use RemoteEndPoint
1173 * - true when addresses must be used (and addresses could be null/empty) */
1174 bool GetCheckedIPs (SocketAsyncEventArgs e
, out IPAddress
[] addresses
)
1178 // Connect to the first address that match the host name, like:
1179 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1180 // while skipping entries that do not match the address family
1181 DnsEndPoint dep
= e
.RemoteEndPoint
as DnsEndPoint
;
1183 addresses
= Dns
.GetHostAddresses (dep
.Host
);
1186 e
.ConnectByNameError
= null;
1195 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1196 * if the platform is newer than w2k. We should be able to cope... */
1197 public void Disconnect (bool reuseSocket
)
1199 ThrowIfDisposedAndClosed ();
1202 Disconnect_internal (m_Handle
, reuseSocket
, out error
);
1206 /* ERROR_NOT_SUPPORTED */
1207 throw new PlatformNotSupportedException ();
1209 throw new SocketException (error
);
1213 is_connected
= false;
1215 /* Do managed housekeeping here... */
1219 public bool DisconnectAsync (SocketAsyncEventArgs e
)
1221 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1223 ThrowIfDisposedAndClosed ();
1225 InitSocketAsyncEventArgs (e
, DisconnectAsyncCallback
, e
, SocketOperation
.Disconnect
);
1227 IOSelector
.Add (e
.socket_async_result
.Handle
, new IOSelectorJob (IOOperation
.Write
, BeginDisconnectCallback
, e
.socket_async_result
));
1232 static AsyncCallback DisconnectAsyncCallback
= new AsyncCallback (ares
=> {
1233 SocketAsyncEventArgs e
= (SocketAsyncEventArgs
) ((SocketAsyncResult
) ares
).AsyncState
;
1235 if (Interlocked
.Exchange (ref e
.in_progress
, 0) != 1)
1236 throw new InvalidOperationException ("No operation in progress");
1239 e
.current_socket
.EndDisconnect (ares
);
1240 } catch (SocketException ex
) {
1241 e
.SocketError
= ex
.SocketErrorCode
;
1242 } catch (ObjectDisposedException
) {
1243 e
.SocketError
= SocketError
.OperationAborted
;
1249 public IAsyncResult
BeginDisconnect (bool reuseSocket
, AsyncCallback callback
, object state
)
1251 ThrowIfDisposedAndClosed ();
1253 SocketAsyncResult sockares
= new SocketAsyncResult (this, callback
, state
, SocketOperation
.Disconnect
) {
1254 ReuseSocket
= reuseSocket
,
1257 IOSelector
.Add (sockares
.Handle
, new IOSelectorJob (IOOperation
.Write
, BeginDisconnectCallback
, sockares
));
1262 static IOAsyncCallback BeginDisconnectCallback
= new IOAsyncCallback (ares
=> {
1263 SocketAsyncResult sockares
= (SocketAsyncResult
) ares
;
1266 sockares
.socket
.Disconnect (sockares
.ReuseSocket
);
1267 } catch (Exception e
) {
1268 sockares
.Complete (e
);
1272 sockares
.Complete ();
1275 public void EndDisconnect (IAsyncResult asyncResult
)
1277 ThrowIfDisposedAndClosed ();
1279 SocketAsyncResult sockares
= ValidateEndIAsyncResult (asyncResult
, "EndDisconnect", "asyncResult");
1281 if (!sockares
.IsCompleted
)
1282 sockares
.AsyncWaitHandle
.WaitOne ();
1284 sockares
.CheckIfThrowDelayedException ();
1287 static void Disconnect_internal (SafeSocketHandle safeHandle
, bool reuse
, out int error
)
1289 bool release
= false;
1291 safeHandle
.DangerousAddRef (ref release
);
1292 Disconnect_internal (safeHandle
.DangerousGetHandle (), reuse
, out error
);
1295 safeHandle
.DangerousRelease ();
1299 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1300 extern static void Disconnect_internal (IntPtr sock
, bool reuse
, out int error
);
1306 public int Receive (byte [] buffer
, int offset
, int size
, SocketFlags socketFlags
, out SocketError errorCode
)
1308 ThrowIfDisposedAndClosed ();
1309 ThrowIfBufferNull (buffer
);
1310 ThrowIfBufferOutOfRange (buffer
, offset
, size
);
1313 int ret
= Receive_internal (m_Handle
, buffer
, offset
, size
, socketFlags
, out nativeError
, is_blocking
);
1315 errorCode
= (SocketError
) nativeError
;
1316 if (errorCode
!= SocketError
.Success
&& errorCode
!= SocketError
.WouldBlock
&& errorCode
!= SocketError
.InProgress
) {
1317 is_connected
= false;
1320 is_connected
= true;
1326 [CLSCompliant (false)]
1327 public int Receive (IList
<ArraySegment
<byte>> buffers
, SocketFlags socketFlags
, out SocketError errorCode
)
1329 ThrowIfDisposedAndClosed ();
1331 if (buffers
== null || buffers
.Count
== 0)
1332 throw new ArgumentNullException ("buffers");
1334 int numsegments
= buffers
.Count
;
1338 /* Only example I can find of sending a byte array reference directly into an internal
1339 * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1340 * so taking a lead from that... */
1341 WSABUF
[] bufarray
= new WSABUF
[numsegments
];
1342 GCHandle
[] gch
= new GCHandle
[numsegments
];
1344 for (int i
= 0; i
< numsegments
; i
++) {
1345 ArraySegment
<byte> segment
= buffers
[i
];
1347 if (segment
.Offset
< 0 || segment
.Count
< 0 || segment
.Count
> segment
.Array
.Length
- segment
.Offset
)
1348 throw new ArgumentOutOfRangeException ("segment");
1350 gch
[i
] = GCHandle
.Alloc (segment
.Array
, GCHandleType
.Pinned
);
1351 bufarray
[i
].len
= segment
.Count
;
1352 bufarray
[i
].buf
= Marshal
.UnsafeAddrOfPinnedArrayElement (segment
.Array
, segment
.Offset
);
1356 ret
= Receive_internal (m_Handle
, bufarray
, socketFlags
, out nativeError
, is_blocking
);
1358 for (int i
= 0; i
< numsegments
; i
++) {
1359 if (gch
[i
].IsAllocated
)
1364 errorCode
= (SocketError
) nativeError
;
1369 public bool ReceiveAsync (SocketAsyncEventArgs e
)
1371 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1373 ThrowIfDisposedAndClosed ();
1375 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1376 // thrown when e.Buffer and e.BufferList are null (works fine when one is
1377 // set to a valid object)
1378 if (e
.Buffer
== null && e
.BufferList
== null)
1379 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1381 if (e
.Buffer
== null) {
1382 InitSocketAsyncEventArgs (e
, ReceiveAsyncCallback
, e
, SocketOperation
.ReceiveGeneric
);
1384 e
.socket_async_result
.Buffers
= e
.BufferList
;
1386 QueueIOSelectorJob (ReadSem
, e
.socket_async_result
.Handle
, new IOSelectorJob (IOOperation
.Read
, BeginReceiveGenericCallback
, e
.socket_async_result
));
1388 InitSocketAsyncEventArgs (e
, ReceiveAsyncCallback
, e
, SocketOperation
.Receive
);
1390 e
.socket_async_result
.Buffer
= e
.Buffer
;
1391 e
.socket_async_result
.Offset
= e
.Offset
;
1392 e
.socket_async_result
.Size
= e
.Count
;
1394 QueueIOSelectorJob (ReadSem
, e
.socket_async_result
.Handle
, new IOSelectorJob (IOOperation
.Read
, BeginReceiveCallback
, e
.socket_async_result
));
1400 static AsyncCallback ReceiveAsyncCallback
= new AsyncCallback (ares
=> {
1401 SocketAsyncEventArgs e
= (SocketAsyncEventArgs
) ((SocketAsyncResult
) ares
).AsyncState
;
1403 if (Interlocked
.Exchange (ref e
.in_progress
, 0) != 1)
1404 throw new InvalidOperationException ("No operation in progress");
1407 e
.BytesTransferred
= e
.current_socket
.EndReceive (ares
);
1408 } catch (SocketException se
){
1409 e
.SocketError
= se
.SocketErrorCode
;
1410 } catch (ObjectDisposedException
) {
1411 e
.SocketError
= SocketError
.OperationAborted
;
1417 public IAsyncResult
BeginReceive (byte[] buffer
, int offset
, int size
, SocketFlags socketFlags
, out SocketError errorCode
, AsyncCallback callback
, object state
)
1419 ThrowIfDisposedAndClosed ();
1420 ThrowIfBufferNull (buffer
);
1421 ThrowIfBufferOutOfRange (buffer
, offset
, size
);
1423 /* As far as I can tell from the docs and from experimentation, a pointer to the
1424 * SocketError parameter is not supposed to be saved for the async parts. And as we don't
1425 * set any socket errors in the setup code, we just have to set it to Success. */
1426 errorCode
= SocketError
.Success
;
1428 SocketAsyncResult sockares
= new SocketAsyncResult (this, callback
, state
, SocketOperation
.Receive
) {
1432 SockFlags
= socketFlags
,
1435 QueueIOSelectorJob (ReadSem
, sockares
.Handle
, new IOSelectorJob (IOOperation
.Read
, BeginReceiveCallback
, sockares
));
1440 static IOAsyncCallback BeginReceiveCallback
= new IOAsyncCallback (ares
=> {
1441 SocketAsyncResult sockares
= (SocketAsyncResult
) ares
;
1445 total
= Receive_internal (sockares
.socket
.m_Handle
, sockares
.Buffer
, sockares
.Offset
, sockares
.Size
, sockares
.SockFlags
, out sockares
.error
, sockares
.socket
.is_blocking
);
1446 } catch (Exception e
) {
1447 sockares
.Complete (e
);
1451 sockares
.Complete (total
);
1454 [CLSCompliant (false)]
1455 public IAsyncResult
BeginReceive (IList
<ArraySegment
<byte>> buffers
, SocketFlags socketFlags
, out SocketError errorCode
, AsyncCallback callback
, object state
)
1457 ThrowIfDisposedAndClosed ();
1459 if (buffers
== null)
1460 throw new ArgumentNullException ("buffers");
1462 /* I assume the same SocketError semantics as above */
1463 errorCode
= SocketError
.Success
;
1465 SocketAsyncResult sockares
= new SocketAsyncResult (this, callback
, state
, SocketOperation
.ReceiveGeneric
) {
1467 SockFlags
= socketFlags
,
1470 QueueIOSelectorJob (ReadSem
, sockares
.Handle
, new IOSelectorJob (IOOperation
.Read
, BeginReceiveGenericCallback
, sockares
));
1475 static IOAsyncCallback BeginReceiveGenericCallback
= new IOAsyncCallback (ares
=> {
1476 SocketAsyncResult sockares
= (SocketAsyncResult
) ares
;
1480 total
= sockares
.socket
.Receive (sockares
.Buffers
, sockares
.SockFlags
);
1481 } catch (Exception e
) {
1482 sockares
.Complete (e
);
1486 sockares
.Complete (total
);
1489 public int EndReceive (IAsyncResult asyncResult
, out SocketError errorCode
)
1491 ThrowIfDisposedAndClosed ();
1493 SocketAsyncResult sockares
= ValidateEndIAsyncResult (asyncResult
, "EndReceive", "asyncResult");
1495 if (!sockares
.IsCompleted
)
1496 sockares
.AsyncWaitHandle
.WaitOne ();
1498 errorCode
= sockares
.ErrorCode
;
1500 if (errorCode
!= SocketError
.Success
&& errorCode
!= SocketError
.WouldBlock
&& errorCode
!= SocketError
.InProgress
)
1501 is_connected
= false;
1503 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
1504 // kinds of exceptions that should be thrown.
1505 if (errorCode
== SocketError
.Success
)
1506 sockares
.CheckIfThrowDelayedException();
1508 return sockares
.Total
;
1511 static int Receive_internal (SafeSocketHandle safeHandle
, WSABUF
[] bufarray
, SocketFlags flags
, out int error
, bool blocking
)
1514 safeHandle
.RegisterForBlockingSyscall ();
1515 return Receive_internal (safeHandle
.DangerousGetHandle (), bufarray
, flags
, out error
, blocking
);
1517 safeHandle
.UnRegisterForBlockingSyscall ();
1521 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
1522 extern static int Receive_internal (IntPtr sock
, WSABUF
[] bufarray
, SocketFlags flags
, out int error
, bool blocking
);
1524 static int Receive_internal (SafeSocketHandle safeHandle
, byte[] buffer
, int offset
, int count
, SocketFlags flags
, out int error
, bool blocking
)
1527 safeHandle
.RegisterForBlockingSyscall ();
1528 return Receive_internal (safeHandle
.DangerousGetHandle (), buffer
, offset
, count
, flags
, out error
, blocking
);
1530 safeHandle
.UnRegisterForBlockingSyscall ();
1534 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1535 extern static int Receive_internal(IntPtr sock
, byte[] buffer
, int offset
, int count
, SocketFlags flags
, out int error
, bool blocking
);
1541 public int ReceiveFrom (byte [] buffer
, int offset
, int size
, SocketFlags socketFlags
, ref EndPoint remoteEP
)
1543 ThrowIfDisposedAndClosed ();
1544 ThrowIfBufferNull (buffer
);
1545 ThrowIfBufferOutOfRange (buffer
, offset
, size
);
1547 if (remoteEP
== null)
1548 throw new ArgumentNullException ("remoteEP");
1550 SocketError errorCode
;
1551 int ret
= ReceiveFrom (buffer
, offset
, size
, socketFlags
, ref remoteEP
, out errorCode
);
1553 if (errorCode
!= SocketError
.Success
)
1554 throw new SocketException (errorCode
);
1559 internal int ReceiveFrom (byte [] buffer
, int offset
, int size
, SocketFlags socketFlags
, ref EndPoint remoteEP
, out SocketError errorCode
)
1561 SocketAddress sockaddr
= remoteEP
.Serialize();
1564 int cnt
= ReceiveFrom_internal (m_Handle
, buffer
, offset
, size
, socketFlags
, ref sockaddr
, out nativeError
, is_blocking
);
1566 errorCode
= (SocketError
) nativeError
;
1567 if (errorCode
!= SocketError
.Success
) {
1568 if (errorCode
!= SocketError
.WouldBlock
&& errorCode
!= SocketError
.InProgress
) {
1569 is_connected
= false;
1570 } else if (errorCode
== SocketError
.WouldBlock
&& is_blocking
) { // This might happen when ReceiveTimeout is set
1571 errorCode
= SocketError
.TimedOut
;
1577 is_connected
= true;
1580 /* If sockaddr is null then we're a connection oriented protocol and should ignore the
1581 * remoteEP parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
1582 if (sockaddr
!= null) {
1583 /* Stupidly, EndPoint.Create() is an instance method */
1584 remoteEP
= remoteEP
.Create (sockaddr
);
1587 seed_endpoint
= remoteEP
;
1592 public bool ReceiveFromAsync (SocketAsyncEventArgs e
)
1594 ThrowIfDisposedAndClosed ();
1596 // We do not support recv into multiple buffers yet
1597 if (e
.BufferList
!= null)
1598 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
1599 if (e
.RemoteEndPoint
== null)
1600 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
1602 InitSocketAsyncEventArgs (e
, ReceiveFromAsyncCallback
, e
, SocketOperation
.ReceiveFrom
);
1604 e
.socket_async_result
.Buffer
= e
.Buffer
;
1605 e
.socket_async_result
.Offset
= e
.Offset
;
1606 e
.socket_async_result
.Size
= e
.Count
;
1607 e
.socket_async_result
.EndPoint
= e
.RemoteEndPoint
;
1608 e
.socket_async_result
.SockFlags
= e
.SocketFlags
;
1610 QueueIOSelectorJob (ReadSem
, e
.socket_async_result
.Handle
, new IOSelectorJob (IOOperation
.Read
, BeginReceiveFromCallback
, e
.socket_async_result
));
1615 static AsyncCallback ReceiveFromAsyncCallback
= new AsyncCallback (ares
=> {
1616 SocketAsyncEventArgs e
= (SocketAsyncEventArgs
) ((SocketAsyncResult
) ares
).AsyncState
;
1618 if (Interlocked
.Exchange (ref e
.in_progress
, 0) != 1)
1619 throw new InvalidOperationException ("No operation in progress");
1622 e
.BytesTransferred
= e
.current_socket
.EndReceiveFrom (ares
, ref e
.remote_ep
);
1623 } catch (SocketException ex
) {
1624 e
.SocketError
= ex
.SocketErrorCode
;
1625 } catch (ObjectDisposedException
) {
1626 e
.SocketError
= SocketError
.OperationAborted
;
1632 public IAsyncResult
BeginReceiveFrom (byte[] buffer
, int offset
, int size
, SocketFlags socket_flags
, ref EndPoint remote_end
, AsyncCallback callback
, object state
)
1634 ThrowIfDisposedAndClosed ();
1635 ThrowIfBufferNull (buffer
);
1636 ThrowIfBufferOutOfRange (buffer
, offset
, size
);
1638 if (remote_end
== null)
1639 throw new ArgumentNullException ("remote_end");
1641 SocketAsyncResult sockares
= new SocketAsyncResult (this, callback
, state
, SocketOperation
.ReceiveFrom
) {
1645 SockFlags
= socket_flags
,
1646 EndPoint
= remote_end
,
1649 QueueIOSelectorJob (ReadSem
, sockares
.Handle
, new IOSelectorJob (IOOperation
.Read
, BeginReceiveFromCallback
, sockares
));
1654 static IOAsyncCallback BeginReceiveFromCallback
= new IOAsyncCallback (ares
=> {
1655 SocketAsyncResult sockares
= (SocketAsyncResult
) ares
;
1659 SocketError errorCode
;
1660 total
= sockares
.socket
.ReceiveFrom (sockares
.Buffer
, sockares
.Offset
, sockares
.Size
, sockares
.SockFlags
, ref sockares
.EndPoint
, out errorCode
);
1662 if (errorCode
!= SocketError
.Success
) {
1663 sockares
.Complete (new SocketException (errorCode
));
1666 } catch (Exception e
) {
1667 sockares
.Complete (e
);
1671 sockares
.Complete (total
);
1674 public int EndReceiveFrom(IAsyncResult result
, ref EndPoint end_point
)
1676 ThrowIfDisposedAndClosed ();
1678 if (end_point
== null)
1679 throw new ArgumentNullException ("remote_end");
1681 SocketAsyncResult sockares
= ValidateEndIAsyncResult (result
, "EndReceiveFrom", "result");
1683 if (!sockares
.IsCompleted
)
1684 sockares
.AsyncWaitHandle
.WaitOne();
1686 sockares
.CheckIfThrowDelayedException();
1688 end_point
= sockares
.EndPoint
;
1690 return sockares
.Total
;
1695 static int ReceiveFrom_internal (SafeSocketHandle safeHandle
, byte[] buffer
, int offset
, int count
, SocketFlags flags
, ref SocketAddress sockaddr
, out int error
, bool blocking
)
1698 safeHandle
.RegisterForBlockingSyscall ();
1699 return ReceiveFrom_internal (safeHandle
.DangerousGetHandle (), buffer
, offset
, count
, flags
, ref sockaddr
, out error
, blocking
);
1701 safeHandle
.UnRegisterForBlockingSyscall ();
1705 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1706 extern static int ReceiveFrom_internal(IntPtr sock
, byte[] buffer
, int offset
, int count
, SocketFlags flags
, ref SocketAddress sockaddr
, out int error
, bool blocking
);
1710 #region ReceiveMessageFrom
1712 [MonoTODO ("Not implemented")]
1713 public int ReceiveMessageFrom (byte[] buffer
, int offset
, int size
, ref SocketFlags socketFlags
, ref EndPoint remoteEP
, out IPPacketInformation ipPacketInformation
)
1715 ThrowIfDisposedAndClosed ();
1716 ThrowIfBufferNull (buffer
);
1717 ThrowIfBufferOutOfRange (buffer
, offset
, size
);
1719 if (remoteEP
== null)
1720 throw new ArgumentNullException ("remoteEP");
1722 // FIXME: figure out how we get hold of the IPPacketInformation
1723 throw new NotImplementedException ();
1726 [MonoTODO ("Not implemented")]
1727 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e
)
1729 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1731 ThrowIfDisposedAndClosed ();
1733 throw new NotImplementedException ();
1737 public IAsyncResult
BeginReceiveMessageFrom (byte[] buffer
, int offset
, int size
, SocketFlags socketFlags
, ref EndPoint remoteEP
, AsyncCallback callback
, object state
)
1739 ThrowIfDisposedAndClosed ();
1740 ThrowIfBufferNull (buffer
);
1741 ThrowIfBufferOutOfRange (buffer
, offset
, size
);
1743 if (remoteEP
== null)
1744 throw new ArgumentNullException ("remoteEP");
1746 throw new NotImplementedException ();
1750 public int EndReceiveMessageFrom (IAsyncResult asyncResult
, ref SocketFlags socketFlags
, ref EndPoint endPoint
, out IPPacketInformation ipPacketInformation
)
1752 ThrowIfDisposedAndClosed ();
1754 if (endPoint
== null)
1755 throw new ArgumentNullException ("endPoint");
1757 /*SocketAsyncResult sockares =*/ ValidateEndIAsyncResult (asyncResult
, "EndReceiveMessageFrom", "asyncResult");
1759 throw new NotImplementedException ();
1766 public int Send (byte [] buffer
, int offset
, int size
, SocketFlags socketFlags
, out SocketError errorCode
)
1768 ThrowIfDisposedAndClosed ();
1769 ThrowIfBufferNull (buffer
);
1770 ThrowIfBufferOutOfRange (buffer
, offset
, size
);
1773 errorCode
= SocketError
.Success
;
1780 sent
+= Send_internal (
1781 m_Handle
, buffer
, offset
+ sent
, size
- sent
, socketFlags
, out nativeError
, is_blocking
);
1782 errorCode
= (SocketError
)nativeError
;
1783 if (errorCode
!= SocketError
.Success
&& errorCode
!= SocketError
.WouldBlock
&& errorCode
!= SocketError
.InProgress
) {
1784 is_connected
= false;
1788 is_connected
= true;
1790 } while (sent
< size
);
1795 [CLSCompliant (false)]
1796 public int Send (IList
<ArraySegment
<byte>> buffers
, SocketFlags socketFlags
, out SocketError errorCode
)
1798 ThrowIfDisposedAndClosed ();
1800 if (buffers
== null)
1801 throw new ArgumentNullException ("buffers");
1802 if (buffers
.Count
== 0)
1803 throw new ArgumentException ("Buffer is empty", "buffers");
1805 int numsegments
= buffers
.Count
;
1809 WSABUF
[] bufarray
= new WSABUF
[numsegments
];
1810 GCHandle
[] gch
= new GCHandle
[numsegments
];
1812 for(int i
= 0; i
< numsegments
; i
++) {
1813 ArraySegment
<byte> segment
= buffers
[i
];
1815 if (segment
.Offset
< 0 || segment
.Count
< 0 || segment
.Count
> segment
.Array
.Length
- segment
.Offset
)
1816 throw new ArgumentOutOfRangeException ("segment");
1818 gch
[i
] = GCHandle
.Alloc (segment
.Array
, GCHandleType
.Pinned
);
1819 bufarray
[i
].len
= segment
.Count
;
1820 bufarray
[i
].buf
= Marshal
.UnsafeAddrOfPinnedArrayElement (segment
.Array
, segment
.Offset
);
1824 ret
= Send_internal (m_Handle
, bufarray
, socketFlags
, out nativeError
, is_blocking
);
1826 for(int i
= 0; i
< numsegments
; i
++) {
1827 if (gch
[i
].IsAllocated
) {
1833 errorCode
= (SocketError
)nativeError
;
1838 public bool SendAsync (SocketAsyncEventArgs e
)
1840 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1842 ThrowIfDisposedAndClosed ();
1844 if (e
.Buffer
== null && e
.BufferList
== null)
1845 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1847 if (e
.Buffer
== null) {
1848 InitSocketAsyncEventArgs (e
, SendAsyncCallback
, e
, SocketOperation
.SendGeneric
);
1850 e
.socket_async_result
.Buffers
= e
.BufferList
;
1852 QueueIOSelectorJob (WriteSem
, e
.socket_async_result
.Handle
, new IOSelectorJob (IOOperation
.Write
, BeginSendGenericCallback
, e
.socket_async_result
));
1854 InitSocketAsyncEventArgs (e
, SendAsyncCallback
, e
, SocketOperation
.Send
);
1856 e
.socket_async_result
.Buffer
= e
.Buffer
;
1857 e
.socket_async_result
.Offset
= e
.Offset
;
1858 e
.socket_async_result
.Size
= e
.Count
;
1860 QueueIOSelectorJob (WriteSem
, e
.socket_async_result
.Handle
, new IOSelectorJob (IOOperation
.Write
, s
=> BeginSendCallback ((SocketAsyncResult
) s
, 0), e
.socket_async_result
));
1866 static AsyncCallback SendAsyncCallback
= new AsyncCallback (ares
=> {
1867 SocketAsyncEventArgs e
= (SocketAsyncEventArgs
) ((SocketAsyncResult
) ares
).AsyncState
;
1869 if (Interlocked
.Exchange (ref e
.in_progress
, 0) != 1)
1870 throw new InvalidOperationException ("No operation in progress");
1873 e
.BytesTransferred
= e
.current_socket
.EndSend (ares
);
1874 } catch (SocketException se
){
1875 e
.SocketError
= se
.SocketErrorCode
;
1876 } catch (ObjectDisposedException
) {
1877 e
.SocketError
= SocketError
.OperationAborted
;
1883 public IAsyncResult
BeginSend (byte[] buffer
, int offset
, int size
, SocketFlags socketFlags
, out SocketError errorCode
, AsyncCallback callback
, object state
)
1885 ThrowIfDisposedAndClosed ();
1886 ThrowIfBufferNull (buffer
);
1887 ThrowIfBufferOutOfRange (buffer
, offset
, size
);
1889 if (!is_connected
) {
1890 errorCode
= SocketError
.NotConnected
;
1894 errorCode
= SocketError
.Success
;
1896 SocketAsyncResult sockares
= new SocketAsyncResult (this, callback
, state
, SocketOperation
.Send
) {
1900 SockFlags
= socketFlags
,
1903 QueueIOSelectorJob (WriteSem
, sockares
.Handle
, new IOSelectorJob (IOOperation
.Write
, s
=> BeginSendCallback ((SocketAsyncResult
) s
, 0), sockares
));
1908 static void BeginSendCallback (SocketAsyncResult sockares
, int sent_so_far
)
1913 total
= Socket
.Send_internal (sockares
.socket
.m_Handle
, sockares
.Buffer
, sockares
.Offset
, sockares
.Size
, sockares
.SockFlags
, out sockares
.error
, false);
1914 } catch (Exception e
) {
1915 sockares
.Complete (e
);
1919 if (sockares
.error
== 0) {
1920 sent_so_far
+= total
;
1921 sockares
.Offset
+= total
;
1922 sockares
.Size
-= total
;
1924 if (sockares
.socket
.CleanedUp
) {
1925 sockares
.Complete (total
);
1929 if (sockares
.Size
> 0) {
1930 IOSelector
.Add (sockares
.Handle
, new IOSelectorJob (IOOperation
.Write
, s
=> BeginSendCallback ((SocketAsyncResult
) s
, sent_so_far
), sockares
));
1931 return; // Have to finish writing everything. See bug #74475.
1934 sockares
.Total
= sent_so_far
;
1937 sockares
.Complete (total
);
1940 [CLSCompliant (false)]
1941 public IAsyncResult
BeginSend (IList
<ArraySegment
<byte>> buffers
, SocketFlags socketFlags
, out SocketError errorCode
, AsyncCallback callback
, object state
)
1943 ThrowIfDisposedAndClosed ();
1945 if (buffers
== null)
1946 throw new ArgumentNullException ("buffers");
1948 if (!is_connected
) {
1949 errorCode
= SocketError
.NotConnected
;
1953 errorCode
= SocketError
.Success
;
1955 SocketAsyncResult sockares
= new SocketAsyncResult (this, callback
, state
, SocketOperation
.SendGeneric
) {
1957 SockFlags
= socketFlags
,
1960 QueueIOSelectorJob (WriteSem
, sockares
.Handle
, new IOSelectorJob (IOOperation
.Write
, BeginSendGenericCallback
, sockares
));
1965 static IOAsyncCallback BeginSendGenericCallback
= new IOAsyncCallback (ares
=> {
1966 SocketAsyncResult sockares
= (SocketAsyncResult
) ares
;
1970 total
= sockares
.socket
.Send (sockares
.Buffers
, sockares
.SockFlags
);
1971 } catch (Exception e
) {
1972 sockares
.Complete (e
);
1976 sockares
.Complete (total
);
1979 public int EndSend (IAsyncResult asyncResult
, out SocketError errorCode
)
1981 ThrowIfDisposedAndClosed ();
1983 SocketAsyncResult sockares
= ValidateEndIAsyncResult (asyncResult
, "EndSend", "asyncResult");
1985 if (!sockares
.IsCompleted
)
1986 sockares
.AsyncWaitHandle
.WaitOne ();
1988 errorCode
= sockares
.ErrorCode
;
1990 if (errorCode
!= SocketError
.Success
&& errorCode
!= SocketError
.WouldBlock
&& errorCode
!= SocketError
.InProgress
)
1991 is_connected
= false;
1993 /* If no socket error occurred, call CheckIfThrowDelayedException in
1994 * case there are other kinds of exceptions that should be thrown.*/
1995 if (errorCode
== SocketError
.Success
)
1996 sockares
.CheckIfThrowDelayedException ();
1998 return sockares
.Total
;
2001 static int Send_internal (SafeSocketHandle safeHandle
, WSABUF
[] bufarray
, SocketFlags flags
, out int error
, bool blocking
)
2004 safeHandle
.RegisterForBlockingSyscall ();
2005 return Send_internal (safeHandle
.DangerousGetHandle (), bufarray
, flags
, out error
, blocking
);
2007 safeHandle
.UnRegisterForBlockingSyscall ();
2011 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
2012 extern static int Send_internal (IntPtr sock
, WSABUF
[] bufarray
, SocketFlags flags
, out int error
, bool blocking
);
2014 static int Send_internal (SafeSocketHandle safeHandle
, byte[] buf
, int offset
, int count
, SocketFlags flags
, out int error
, bool blocking
)
2017 safeHandle
.RegisterForBlockingSyscall ();
2018 return Send_internal (safeHandle
.DangerousGetHandle (), buf
, offset
, count
, flags
, out error
, blocking
);
2020 safeHandle
.UnRegisterForBlockingSyscall ();
2024 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
2025 extern static int Send_internal(IntPtr sock
, byte[] buf
, int offset
, int count
, SocketFlags flags
, out int error
, bool blocking
);
2031 public int SendTo (byte [] buffer
, int offset
, int size
, SocketFlags socketFlags
, EndPoint remoteEP
)
2033 ThrowIfDisposedAndClosed ();
2034 ThrowIfBufferNull (buffer
);
2035 ThrowIfBufferOutOfRange (buffer
, offset
, size
);
2037 if (remoteEP
== null)
2038 throw new ArgumentNullException("remoteEP");
2041 int ret
= SendTo_internal (m_Handle
, buffer
, offset
, size
, socketFlags
, remoteEP
.Serialize (), out error
, is_blocking
);
2043 SocketError err
= (SocketError
) error
;
2045 if (err
!= SocketError
.WouldBlock
&& err
!= SocketError
.InProgress
)
2046 is_connected
= false;
2047 throw new SocketException (error
);
2050 is_connected
= true;
2052 seed_endpoint
= remoteEP
;
2057 public bool SendToAsync (SocketAsyncEventArgs e
)
2059 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2061 ThrowIfDisposedAndClosed ();
2063 if (e
.BufferList
!= null)
2064 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2065 if (e
.RemoteEndPoint
== null)
2066 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2068 InitSocketAsyncEventArgs (e
, SendToAsyncCallback
, e
, SocketOperation
.SendTo
);
2070 e
.socket_async_result
.Buffer
= e
.Buffer
;
2071 e
.socket_async_result
.Offset
= e
.Offset
;
2072 e
.socket_async_result
.Size
= e
.Count
;
2073 e
.socket_async_result
.SockFlags
= e
.SocketFlags
;
2074 e
.socket_async_result
.EndPoint
= e
.RemoteEndPoint
;
2076 QueueIOSelectorJob (WriteSem
, e
.socket_async_result
.Handle
, new IOSelectorJob (IOOperation
.Write
, s
=> BeginSendToCallback ((SocketAsyncResult
) s
, 0), e
.socket_async_result
));
2081 static AsyncCallback SendToAsyncCallback
= new AsyncCallback (ares
=> {
2082 SocketAsyncEventArgs e
= (SocketAsyncEventArgs
) ((SocketAsyncResult
) ares
).AsyncState
;
2084 if (Interlocked
.Exchange (ref e
.in_progress
, 0) != 1)
2085 throw new InvalidOperationException ("No operation in progress");
2088 e
.BytesTransferred
= e
.current_socket
.EndSendTo (ares
);
2089 } catch (SocketException ex
) {
2090 e
.SocketError
= ex
.SocketErrorCode
;
2091 } catch (ObjectDisposedException
) {
2092 e
.SocketError
= SocketError
.OperationAborted
;
2098 public IAsyncResult
BeginSendTo(byte[] buffer
, int offset
, int size
, SocketFlags socket_flags
, EndPoint remote_end
, AsyncCallback callback
, object state
)
2100 ThrowIfDisposedAndClosed ();
2101 ThrowIfBufferNull (buffer
);
2102 ThrowIfBufferOutOfRange (buffer
, offset
, size
);
2104 SocketAsyncResult sockares
= new SocketAsyncResult (this, callback
, state
, SocketOperation
.SendTo
) {
2108 SockFlags
= socket_flags
,
2109 EndPoint
= remote_end
,
2112 QueueIOSelectorJob (WriteSem
, sockares
.Handle
, new IOSelectorJob (IOOperation
.Write
, s
=> BeginSendToCallback ((SocketAsyncResult
) s
, 0), sockares
));
2117 static void BeginSendToCallback (SocketAsyncResult sockares
, int sent_so_far
)
2121 total
= sockares
.socket
.SendTo (sockares
.Buffer
, sockares
.Offset
, sockares
.Size
, sockares
.SockFlags
, sockares
.EndPoint
);
2123 if (sockares
.error
== 0) {
2124 sent_so_far
+= total
;
2125 sockares
.Offset
+= total
;
2126 sockares
.Size
-= total
;
2129 if (sockares
.Size
> 0) {
2130 IOSelector
.Add (sockares
.Handle
, new IOSelectorJob (IOOperation
.Write
, s
=> BeginSendToCallback ((SocketAsyncResult
) s
, sent_so_far
), sockares
));
2131 return; // Have to finish writing everything. See bug #74475.
2134 sockares
.Total
= sent_so_far
;
2135 } catch (Exception e
) {
2136 sockares
.Complete (e
);
2140 sockares
.Complete ();
2143 public int EndSendTo (IAsyncResult result
)
2145 ThrowIfDisposedAndClosed ();
2147 SocketAsyncResult sockares
= ValidateEndIAsyncResult (result
, "EndSendTo", "result");
2149 if (!sockares
.IsCompleted
)
2150 sockares
.AsyncWaitHandle
.WaitOne();
2152 sockares
.CheckIfThrowDelayedException();
2154 return sockares
.Total
;
2157 static int SendTo_internal (SafeSocketHandle safeHandle
, byte[] buffer
, int offset
, int count
, SocketFlags flags
, SocketAddress sa
, out int error
, bool blocking
)
2160 safeHandle
.RegisterForBlockingSyscall ();
2161 return SendTo_internal (safeHandle
.DangerousGetHandle (), buffer
, offset
, count
, flags
, sa
, out error
, blocking
);
2163 safeHandle
.UnRegisterForBlockingSyscall ();
2167 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
2168 extern static int SendTo_internal (IntPtr sock
, byte[] buffer
, int offset
, int count
, SocketFlags flags
, SocketAddress sa
, out int error
, bool blocking
);
2174 public void SendFile (string fileName
, byte[] preBuffer
, byte[] postBuffer
, TransmitFileOptions flags
)
2176 ThrowIfDisposedAndClosed ();
2179 throw new NotSupportedException ();
2181 throw new InvalidOperationException ();
2184 if (!SendFile_internal (m_Handle
, fileName
, preBuffer
, postBuffer
, flags
, out error
, is_blocking
) || error
!= 0) {
2185 SocketException exc
= new SocketException (error
);
2186 if (exc
.ErrorCode
== 2 || exc
.ErrorCode
== 3)
2187 throw new FileNotFoundException ();
2192 public IAsyncResult
BeginSendFile (string fileName
, byte[] preBuffer
, byte[] postBuffer
, TransmitFileOptions flags
, AsyncCallback callback
, object state
)
2194 ThrowIfDisposedAndClosed ();
2197 throw new NotSupportedException ();
2198 if (!File
.Exists (fileName
))
2199 throw new FileNotFoundException ();
2201 SendFileHandler handler
= new SendFileHandler (SendFile
);
2203 return new SendFileAsyncResult (handler
, handler
.BeginInvoke (fileName
, preBuffer
, postBuffer
, flags
, ar
=> callback (new SendFileAsyncResult (handler
, ar
)), state
));
2206 public void EndSendFile (IAsyncResult asyncResult
)
2208 ThrowIfDisposedAndClosed ();
2210 if (asyncResult
== null)
2211 throw new ArgumentNullException ("asyncResult");
2213 SendFileAsyncResult ares
= asyncResult
as SendFileAsyncResult
;
2215 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2217 ares
.Delegate
.EndInvoke (ares
.Original
);
2220 static bool SendFile_internal (SafeSocketHandle safeHandle
, string filename
, byte [] pre_buffer
, byte [] post_buffer
, TransmitFileOptions flags
, out int error
, bool blocking
)
2223 safeHandle
.RegisterForBlockingSyscall ();
2224 return SendFile_internal (safeHandle
.DangerousGetHandle (), filename
, pre_buffer
, post_buffer
, flags
, out error
, blocking
);
2226 safeHandle
.UnRegisterForBlockingSyscall ();
2230 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
2231 extern static bool SendFile_internal (IntPtr sock
, string filename
, byte [] pre_buffer
, byte [] post_buffer
, TransmitFileOptions flags
, out int error
, bool blocking
);
2233 delegate void SendFileHandler (string fileName
, byte [] preBuffer
, byte [] postBuffer
, TransmitFileOptions flags
);
2235 sealed class SendFileAsyncResult
: IAsyncResult
{
2239 public SendFileAsyncResult (SendFileHandler d
, IAsyncResult ares
)
2245 public object AsyncState
{
2246 get { return ares.AsyncState; }
2249 public WaitHandle AsyncWaitHandle
{
2250 get { return ares.AsyncWaitHandle; }
2253 public bool CompletedSynchronously
{
2254 get { return ares.CompletedSynchronously; }
2257 public bool IsCompleted
{
2258 get { return ares.IsCompleted; }
2261 public SendFileHandler Delegate
{
2265 public IAsyncResult Original
{
2266 get { return ares; }
2274 [MonoTODO ("Not implemented")]
2275 public bool SendPacketsAsync (SocketAsyncEventArgs e
)
2277 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2279 ThrowIfDisposedAndClosed ();
2281 throw new NotImplementedException ();
2286 #region DuplicateAndClose
2288 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2289 public SocketInformation
DuplicateAndClose (int targetProcessId
)
2291 var si
= new SocketInformation ();
2293 (is_listening
? SocketInformationOptions
.Listening
: 0) |
2294 (is_connected
? SocketInformationOptions
.Connected
: 0) |
2295 (is_blocking
? 0 : SocketInformationOptions
.NonBlocking
) |
2296 (useOverlappedIO
? SocketInformationOptions
.UseOnlyOverlappedIO
: 0);
2299 IntPtr duplicateHandle
;
2300 if (!MonoIO
.DuplicateHandle (System
.Diagnostics
.Process
.GetCurrentProcess ().Handle
, Handle
, new IntPtr (targetProcessId
), out duplicateHandle
, 0, 0, 0x00000002 /* DUPLICATE_SAME_ACCESS */, out error
))
2301 throw MonoIO
.GetException (error
);
2303 si
.ProtocolInformation
= Mono
.DataConverter
.Pack ("iiiil", (int)addressFamily
, (int)socketType
, (int)protocolType
, is_bound
? 1 : 0, (long)duplicateHandle
);
2311 #region GetSocketOption
2313 public void GetSocketOption (SocketOptionLevel optionLevel
, SocketOptionName optionName
, byte [] optionValue
)
2315 ThrowIfDisposedAndClosed ();
2317 if (optionValue
== null)
2318 throw new SocketException ((int) SocketError
.Fault
, "Error trying to dereference an invalid pointer");
2321 GetSocketOption_arr_internal (m_Handle
, optionLevel
, optionName
, ref optionValue
, out error
);
2324 throw new SocketException (error
);
2327 public byte [] GetSocketOption (SocketOptionLevel optionLevel
, SocketOptionName optionName
, int optionLength
)
2329 ThrowIfDisposedAndClosed ();
2332 byte[] byte_val
= new byte [optionLength
];
2333 GetSocketOption_arr_internal (m_Handle
, optionLevel
, optionName
, ref byte_val
, out error
);
2336 throw new SocketException (error
);
2341 public object GetSocketOption (SocketOptionLevel optionLevel
, SocketOptionName optionName
)
2343 ThrowIfDisposedAndClosed ();
2347 GetSocketOption_obj_internal (m_Handle
, optionLevel
, optionName
, out obj_val
, out error
);
2350 throw new SocketException (error
);
2352 if (optionName
== SocketOptionName
.Linger
)
2353 return (LingerOption
) obj_val
;
2354 else if (optionName
== SocketOptionName
.AddMembership
|| optionName
== SocketOptionName
.DropMembership
)
2355 return (MulticastOption
) obj_val
;
2356 else if (obj_val
is int)
2357 return (int) obj_val
;
2362 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle
, SocketOptionLevel level
, SocketOptionName name
, ref byte[] byte_val
, out int error
)
2364 bool release
= false;
2366 safeHandle
.DangerousAddRef (ref release
);
2367 GetSocketOption_arr_internal (safeHandle
.DangerousGetHandle (), level
, name
, ref byte_val
, out error
);
2370 safeHandle
.DangerousRelease ();
2374 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
2375 extern static void GetSocketOption_arr_internal(IntPtr socket
, SocketOptionLevel level
, SocketOptionName name
, ref byte[] byte_val
, out int error
);
2377 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle
, SocketOptionLevel level
, SocketOptionName name
, out object obj_val
, out int error
)
2379 bool release
= false;
2381 safeHandle
.DangerousAddRef (ref release
);
2382 GetSocketOption_obj_internal (safeHandle
.DangerousGetHandle (), level
, name
, out obj_val
, out error
);
2385 safeHandle
.DangerousRelease ();
2389 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
2390 extern static void GetSocketOption_obj_internal(IntPtr socket
, SocketOptionLevel level
, SocketOptionName name
, out object obj_val
, out int error
);
2394 #region SetSocketOption
2396 public void SetSocketOption (SocketOptionLevel optionLevel
, SocketOptionName optionName
, byte [] optionValue
)
2398 ThrowIfDisposedAndClosed ();
2400 // I'd throw an ArgumentNullException, but this is what MS does.
2401 if (optionValue
== null)
2402 throw new SocketException ((int) SocketError
.Fault
, "Error trying to dereference an invalid pointer");
2405 SetSocketOption_internal (m_Handle
, optionLevel
, optionName
, null, optionValue
, 0, out error
);
2408 if (error
== (int) SocketError
.InvalidArgument
)
2409 throw new ArgumentException ();
2410 throw new SocketException (error
);
2414 public void SetSocketOption (SocketOptionLevel optionLevel
, SocketOptionName optionName
, object optionValue
)
2416 ThrowIfDisposedAndClosed ();
2418 // NOTE: if a null is passed, the byte[] overload is used instead...
2419 if (optionValue
== null)
2420 throw new ArgumentNullException("optionValue");
2424 if (optionLevel
== SocketOptionLevel
.Socket
&& optionName
== SocketOptionName
.Linger
) {
2425 LingerOption linger
= optionValue
as LingerOption
;
2427 throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
2428 SetSocketOption_internal (m_Handle
, optionLevel
, optionName
, linger
, null, 0, out error
);
2429 } else if (optionLevel
== SocketOptionLevel
.IP
&& (optionName
== SocketOptionName
.AddMembership
|| optionName
== SocketOptionName
.DropMembership
)) {
2430 MulticastOption multicast
= optionValue
as MulticastOption
;
2431 if (multicast
== null)
2432 throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
2433 SetSocketOption_internal (m_Handle
, optionLevel
, optionName
, multicast
, null, 0, out error
);
2434 } else if (optionLevel
== SocketOptionLevel
.IPv6
&& (optionName
== SocketOptionName
.AddMembership
|| optionName
== SocketOptionName
.DropMembership
)) {
2435 IPv6MulticastOption multicast
= optionValue
as IPv6MulticastOption
;
2436 if (multicast
== null)
2437 throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
2438 SetSocketOption_internal (m_Handle
, optionLevel
, optionName
, multicast
, null, 0, out error
);
2440 throw new ArgumentException ("Invalid value specified.", "optionValue");
2444 if (error
== (int) SocketError
.InvalidArgument
)
2445 throw new ArgumentException ();
2446 throw new SocketException (error
);
2450 public void SetSocketOption (SocketOptionLevel optionLevel
, SocketOptionName optionName
, bool optionValue
)
2452 int int_val
= optionValue
? 1 : 0;
2454 SetSocketOption (optionLevel
, optionName
, int_val
);
2457 public void SetSocketOption (SocketOptionLevel optionLevel
, SocketOptionName optionName
, int optionValue
)
2459 ThrowIfDisposedAndClosed ();
2462 SetSocketOption_internal (m_Handle
, optionLevel
, optionName
, null, null, optionValue
, out error
);
2465 if (error
== (int) SocketError
.InvalidArgument
)
2466 throw new ArgumentException ();
2467 throw new SocketException (error
);
2471 static void SetSocketOption_internal (SafeSocketHandle safeHandle
, SocketOptionLevel level
, SocketOptionName name
, object obj_val
, byte [] byte_val
, int int_val
, out int error
)
2473 bool release
= false;
2475 safeHandle
.DangerousAddRef (ref release
);
2476 SetSocketOption_internal (safeHandle
.DangerousGetHandle (), level
, name
, obj_val
, byte_val
, int_val
, out error
);
2479 safeHandle
.DangerousRelease ();
2483 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
2484 extern static void SetSocketOption_internal (IntPtr socket
, SocketOptionLevel level
, SocketOptionName name
, object obj_val
, byte [] byte_val
, int int_val
, out int error
);
2490 public int IOControl (int ioControlCode
, byte [] optionInValue
, byte [] optionOutValue
)
2493 throw new ObjectDisposedException (GetType ().ToString ());
2496 int result
= IOControl_internal (m_Handle
, ioControlCode
, optionInValue
, optionOutValue
, out error
);
2499 throw new SocketException (error
);
2501 throw new InvalidOperationException ("Must use Blocking property instead.");
2506 static int IOControl_internal (SafeSocketHandle safeHandle
, int ioctl_code
, byte [] input
, byte [] output
, out int error
)
2508 bool release
= false;
2510 safeHandle
.DangerousAddRef (ref release
);
2511 return IOControl_internal (safeHandle
.DangerousGetHandle (), ioctl_code
, input
, output
, out error
);
2514 safeHandle
.DangerousRelease ();
2518 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
2519 * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
2520 * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
2521 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
2522 extern static int IOControl_internal (IntPtr sock
, int ioctl_code
, byte [] input
, byte [] output
, out int error
);
2528 public void Close ()
2534 public void Close (int timeout
)
2536 linger_timeout
= timeout
;
2540 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
2541 internal extern static void Close_internal (IntPtr socket
, out int error
);
2547 public void Shutdown (SocketShutdown how
)
2549 ThrowIfDisposedAndClosed ();
2552 throw new SocketException (10057); // Not connected
2555 Shutdown_internal (m_Handle
, how
, out error
);
2558 throw new SocketException (error
);
2561 static void Shutdown_internal (SafeSocketHandle safeHandle
, SocketShutdown how
, out int error
)
2563 bool release
= false;
2565 safeHandle
.DangerousAddRef (ref release
);
2566 Shutdown_internal (safeHandle
.DangerousGetHandle (), how
, out error
);
2569 safeHandle
.DangerousRelease ();
2573 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
2574 internal extern static void Shutdown_internal (IntPtr socket
, SocketShutdown how
, out int error
);
2580 protected virtual void Dispose (bool disposing
)
2586 bool was_connected
= is_connected
;
2587 is_connected
= false;
2589 if (m_Handle
!= null) {
2596 m_Handle
.Dispose ();
2600 void Linger (IntPtr handle
)
2602 if (!is_connected
|| linger_timeout
<= 0)
2605 /* We don't want to receive any more data */
2607 Shutdown_internal (handle
, SocketShutdown
.Receive
, out error
);
2612 int seconds
= linger_timeout
/ 1000;
2613 int ms
= linger_timeout
% 1000;
2615 /* If the other end closes, this will return 'true' with 'Available' == 0 */
2616 Poll_internal (handle
, SelectMode
.SelectRead
, ms
* 1000, out error
);
2622 LingerOption linger
= new LingerOption (true, seconds
);
2623 SetSocketOption_internal (handle
, SocketOptionLevel
.Socket
, SocketOptionName
.Linger
, linger
, null, 0, out error
);
2624 /* Not needed, we're closing upon return */
2632 void ThrowIfDisposedAndClosed (Socket socket
)
2634 if (socket
.CleanedUp
&& socket
.is_closed
)
2635 throw new ObjectDisposedException (socket
.GetType ().ToString ());
2638 void ThrowIfDisposedAndClosed ()
2640 if (CleanedUp
&& is_closed
)
2641 throw new ObjectDisposedException (GetType ().ToString ());
2644 void ThrowIfBufferNull (byte[] buffer
)
2647 throw new ArgumentNullException ("buffer");
2650 void ThrowIfBufferOutOfRange (byte[] buffer
, int offset
, int size
)
2653 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
2654 if (offset
> buffer
.Length
)
2655 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
2657 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
2658 if (size
> buffer
.Length
- offset
)
2659 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
2664 if (protocolType
== ProtocolType
.Udp
)
2665 throw new SocketException ((int)SocketError
.ProtocolOption
);
2668 SocketAsyncResult
ValidateEndIAsyncResult (IAsyncResult ares
, string methodName
, string argName
)
2671 throw new ArgumentNullException (argName
);
2673 SocketAsyncResult sockares
= ares
as SocketAsyncResult
;
2674 if (sockares
== null)
2675 throw new ArgumentException ("Invalid IAsyncResult", argName
);
2676 if (Interlocked
.CompareExchange (ref sockares
.EndCalled
, 1, 0) == 1)
2677 throw new InvalidOperationException (methodName
+ " can only be called once per asynchronous operation");
2682 void QueueIOSelectorJob (SemaphoreSlim sem
, IntPtr handle
, IOSelectorJob job
)
2684 sem
.WaitAsync ().ContinueWith (t
=> {
2686 job
.MarkDisposed ();
2690 IOSelector
.Add (handle
, job
);
2694 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e
, AsyncCallback callback
, object state
, SocketOperation operation
)
2696 e
.socket_async_result
.Init (this, callback
, state
, operation
);
2697 if (e
.AcceptSocket
!= null) {
2698 e
.socket_async_result
.AcceptSocket
= e
.AcceptSocket
;
2700 e
.current_socket
= this;
2701 e
.SetLastOperation (SocketOperationToSocketAsyncOperation (operation
));
2702 e
.SocketError
= SocketError
.Success
;
2703 e
.BytesTransferred
= 0;
2706 SocketAsyncOperation
SocketOperationToSocketAsyncOperation (SocketOperation op
)
2709 case SocketOperation
.Connect
:
2710 return SocketAsyncOperation
.Connect
;
2711 case SocketOperation
.Accept
:
2712 return SocketAsyncOperation
.Accept
;
2713 case SocketOperation
.Disconnect
:
2714 return SocketAsyncOperation
.Disconnect
;
2715 case SocketOperation
.Receive
:
2716 case SocketOperation
.ReceiveGeneric
:
2717 return SocketAsyncOperation
.Receive
;
2718 case SocketOperation
.ReceiveFrom
:
2719 return SocketAsyncOperation
.ReceiveFrom
;
2720 case SocketOperation
.Send
:
2721 case SocketOperation
.SendGeneric
:
2722 return SocketAsyncOperation
.Send
;
2723 case SocketOperation
.SendTo
:
2724 return SocketAsyncOperation
.SendTo
;
2726 throw new NotImplementedException (String
.Format ("Operation {0} is not implemented", op
));
2730 IPEndPoint
RemapIPEndPoint (IPEndPoint input
) {
2731 // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
2732 if (IsDualMode
&& input
.AddressFamily
== AddressFamily
.InterNetwork
)
2733 return new IPEndPoint (input
.Address
.MapToIPv6 (), input
.Port
);
2738 [StructLayout (LayoutKind
.Sequential
)]
2744 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
2745 internal static extern void cancel_blocking_socket_operation (Thread thread
);
2747 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
2748 internal static extern bool SupportsPortReuse (ProtocolType proto
);
2750 internal static int FamilyHint
{
2753 // MONO_HINT_UNSPECIFIED = 0,
2754 // MONO_HINT_IPV4 = 1,
2755 // MONO_HINT_IPV6 = 2,
2758 if (OSSupportsIPv4
) {
2762 if (OSSupportsIPv6
) {
2763 hint
= hint
== 0 ? 2 : 0;
2770 static bool IsProtocolSupported (NetworkInterfaceComponent networkInterface
)
2775 var nics
= NetworkInterface
.GetAllNetworkInterfaces ();
2776 foreach (var adapter
in nics
) {
2777 if (adapter
.Supports (networkInterface
))