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)
10 // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
11 // http://www.myelin.co.nz
12 // (c) 2004-2006 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
.Runtime
.CompilerServices
;
40 using System
.Runtime
.InteropServices
;
41 using System
.Threading
;
42 using System
.Reflection
;
44 using System
.Security
;
48 using System
.Net
.Configuration
;
52 using System
.Collections
.Generic
;
54 using System
.Net
.NetworkInformation
;
59 namespace System
.Net
.Sockets
{
61 public partial class Socket
: IDisposable
{
64 * These two fields are looked up by name by the runtime, don't change
65 * their name without also updating the runtime code.
67 private static int ipv4Supported
= -1, ipv6Supported
= -1;
71 // initialize ipv4Supported and ipv6Supported
72 CheckProtocolSupport ();
75 internal static void CheckProtocolSupport ()
77 if(ipv4Supported
== -1) {
79 Socket tmp
= new Socket(AddressFamily
.InterNetwork
, SocketType
.Stream
, ProtocolType
.Tcp
);
88 if (ipv6Supported
== -1) {
90 #if NET_2_0 && CONFIGURATION_DEP
91 SettingsSection config
;
92 config
= (SettingsSection
) System
.Configuration
.ConfigurationManager
.GetSection ("system.net/settings");
94 ipv6Supported
= config
.Ipv6
.Enabled
? -1 : 0;
96 NetConfig config
= System
.Configuration
.ConfigurationSettings
.GetConfig("system.net/settings") as NetConfig
;
98 ipv6Supported
= config
.ipv6Enabled
? -1 : 0;
101 if (ipv6Supported
!= 0) {
103 Socket tmp
= new Socket(AddressFamily
.InterNetworkV6
, SocketType
.Stream
, ProtocolType
.Tcp
);
114 public static bool SupportsIPv4
{
116 CheckProtocolSupport();
117 return ipv4Supported
== 1;
122 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
124 public static bool SupportsIPv6
{
126 CheckProtocolSupport();
127 return ipv6Supported
== 1;
131 public static bool OSSupportsIPv4
{
133 CheckProtocolSupport();
134 return ipv4Supported
== 1;
139 public static bool OSSupportsIPv6
{
141 CheckProtocolSupport();
142 return ipv6Supported
== 1;
146 public static bool OSSupportsIPv6
{
148 NetworkInterface
[] nics
= NetworkInterface
.GetAllNetworkInterfaces ();
150 foreach (NetworkInterface adapter
in nics
) {
151 if (adapter
.Supports (NetworkInterfaceComponent
.IPv6
))
159 /* the field "socket" is looked up by name by the runtime */
160 private IntPtr socket
;
161 private AddressFamily address_family
;
162 private SocketType socket_type
;
163 private ProtocolType protocol_type
;
164 internal bool blocking
=true;
165 Thread blocking_thread
;
167 private bool isbound
;
169 /* When true, the socket was connected at the time of
170 * the last IO operation
172 private bool connected
;
173 /* true if we called Close_internal */
175 internal bool disposed
;
178 * This EndPoint is used when creating new endpoints. Because
179 * there are many types of EndPoints possible,
180 * seed_endpoint.Create(addr) is used for creating new ones.
181 * As such, this value is set on Bind, SentTo, ReceiveFrom,
184 internal EndPoint seed_endpoint
= null;
187 // Creates a new system socket, returning the handle
188 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
189 private extern IntPtr
Socket_internal(AddressFamily family
,
195 public Socket(AddressFamily family
, SocketType type
, ProtocolType proto
)
198 if (family
== AddressFamily
.Unspecified
)
199 throw new ArgumentException ("family");
201 address_family
=family
;
207 socket
= Socket_internal (family
, type
, proto
, out error
);
209 throw new SocketException (error
);
221 public AddressFamily AddressFamily
{
222 get { return address_family; }
226 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
227 private extern static void Blocking_internal(IntPtr socket
,
231 public bool Blocking
{
236 if (disposed
&& closed
)
237 throw new ObjectDisposedException (GetType ().ToString ());
241 Blocking_internal (socket
, value, out error
);
244 throw new SocketException (error
);
250 public bool Connected
{
251 get { return connected; }
252 internal set { connected = value; }
255 public ProtocolType ProtocolType
{
256 get { return protocol_type; }
259 public bool NoDelay
{
261 if (disposed
&& closed
)
262 throw new ObjectDisposedException (GetType ().ToString ());
266 return (int)(GetSocketOption (
267 SocketOptionLevel
.Tcp
,
268 SocketOptionName
.NoDelay
)) != 0;
272 if (disposed
&& closed
)
273 throw new ObjectDisposedException (GetType ().ToString ());
278 SocketOptionLevel
.Tcp
,
279 SocketOptionName
.NoDelay
, value ? 1 : 0);
283 public int ReceiveBufferSize
{
285 if (disposed
&& closed
) {
286 throw new ObjectDisposedException (GetType ().ToString ());
288 return((int)GetSocketOption (SocketOptionLevel
.Socket
, SocketOptionName
.ReceiveBuffer
));
291 if (disposed
&& closed
) {
292 throw new ObjectDisposedException (GetType ().ToString ());
295 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
298 SetSocketOption (SocketOptionLevel
.Socket
, SocketOptionName
.ReceiveBuffer
, value);
302 public int SendBufferSize
{
304 if (disposed
&& closed
) {
305 throw new ObjectDisposedException (GetType ().ToString ());
307 return((int)GetSocketOption (SocketOptionLevel
.Socket
, SocketOptionName
.SendBuffer
));
310 if (disposed
&& closed
) {
311 throw new ObjectDisposedException (GetType ().ToString ());
314 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
317 SetSocketOption (SocketOptionLevel
.Socket
,
318 SocketOptionName
.SendBuffer
,
325 if (disposed
&& closed
) {
326 throw new ObjectDisposedException (GetType ().ToString ());
331 if (address_family
== AddressFamily
.InterNetwork
) {
332 ttl_val
= (short)((int)GetSocketOption (SocketOptionLevel
.IP
, SocketOptionName
.IpTimeToLive
));
333 } else if (address_family
== AddressFamily
.InterNetworkV6
) {
334 ttl_val
= (short)((int)GetSocketOption (SocketOptionLevel
.IPv6
, SocketOptionName
.HopLimit
));
336 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
342 if (disposed
&& closed
) {
343 throw new ObjectDisposedException (GetType ().ToString ());
346 if (address_family
== AddressFamily
.InterNetwork
) {
347 SetSocketOption (SocketOptionLevel
.IP
, SocketOptionName
.IpTimeToLive
, value);
348 } else if (address_family
== AddressFamily
.InterNetworkV6
) {
349 SetSocketOption (SocketOptionLevel
.IPv6
, SocketOptionName
.HopLimit
, value);
351 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
356 // Returns the remote endpoint details in addr and port
357 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
358 private extern static SocketAddress
RemoteEndPoint_internal(IntPtr socket
, out int error
);
360 public EndPoint RemoteEndPoint
{
362 if (disposed
&& closed
)
363 throw new ObjectDisposedException (GetType ().ToString ());
366 * If the seed EndPoint is null, Connect, Bind,
367 * etc has not yet been called. MS returns null
370 if (seed_endpoint
== null)
376 sa
=RemoteEndPoint_internal(socket
, out error
);
379 throw new SocketException (error
);
381 return seed_endpoint
.Create (sa
);
385 protected virtual void Dispose (bool explicitDisposing
)
392 if ((int) socket
!= -1) {
396 socket
= (IntPtr
) (-1);
397 Close_internal (x
, out error
);
398 if (blocking_thread
!= null) {
399 blocking_thread
.Abort ();
400 blocking_thread
= null;
403 throw new SocketException (error
);
408 public void Dispose ()
410 void IDisposable
.Dispose ()
414 GC
.SuppressFinalize (this);
418 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
419 private extern static void Close_internal(IntPtr socket
, out int error
);
423 ((IDisposable
) this).Dispose ();
426 // Connects to the remote address
427 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
428 private extern static void Connect_internal(IntPtr sock
,
432 public void Connect (EndPoint remoteEP
)
434 SocketAddress serial
= null;
436 if (disposed
&& closed
)
437 throw new ObjectDisposedException (GetType ().ToString ());
439 if (remoteEP
== null)
440 throw new ArgumentNullException ("remoteEP");
442 IPEndPoint ep
= remoteEP
as IPEndPoint
;
444 if (ep
.Address
.Equals (IPAddress
.Any
) || ep
.Address
.Equals (IPAddress
.IPv6Any
))
445 throw new SocketException ((int) SocketError
.AddressNotAvailable
);
447 #if NET_2_1 && !MONOTOUCH
448 if (protocol_type
!= ProtocolType
.Tcp
)
449 throw new SocketException ((int) SocketError
.AccessDenied
);
451 DnsEndPoint dep
= (remoteEP
as DnsEndPoint
);
453 serial
= dep
.AsIPEndPoint ().Serialize ();
455 serial
= remoteEP
.Serialize ();
457 /* TODO: check this for the 1.1 profile too */
459 throw new InvalidOperationException ();
461 serial
= remoteEP
.Serialize ();
463 serial
= remoteEP
.Serialize ();
468 blocking_thread
= Thread
.CurrentThread
;
470 Connect_internal (socket
, serial
, out error
);
471 } catch (ThreadAbortException
) {
473 Thread
.ResetAbort ();
474 error
= (int) SocketError
.Interrupted
;
477 blocking_thread
= null;
481 throw new SocketException (error
);
489 seed_endpoint
= remoteEP
;
493 public bool ReceiveAsync (SocketAsyncEventArgs e
)
495 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
497 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
498 // thrown when e.Buffer and e.BufferList are null (works fine when one is
499 // set to a valid object)
500 if (disposed
&& closed
)
501 throw new ObjectDisposedException (GetType ().ToString ());
503 // We do not support recv into multiple buffers yet
504 if (e
.BufferList
!= null)
505 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
507 e
.DoOperation (SocketAsyncOperation
.Receive
, this);
509 // We always return true for now
513 public bool SendAsync (SocketAsyncEventArgs e
)
515 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
517 if (disposed
&& closed
)
518 throw new ObjectDisposedException (GetType ().ToString ());
519 if (e
.Buffer
== null && e
.BufferList
== null)
520 throw new ArgumentException ("Either e.Buffer or e.BufferList must be valid buffers.");
522 e
.DoOperation (SocketAsyncOperation
.Send
, this);
524 // We always return true for now
529 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
530 extern static bool Poll_internal (IntPtr socket
, SelectMode mode
, int timeout
, out int error
);
532 /* This overload is needed as the async Connect method
533 * also needs to check the socket error status, but
534 * getsockopt(..., SO_ERROR) clears the error.
536 internal bool Poll (int time_us
, SelectMode mode
, out int socket_error
)
538 if (disposed
&& closed
)
539 throw new ObjectDisposedException (GetType ().ToString ());
541 if (mode
!= SelectMode
.SelectRead
&&
542 mode
!= SelectMode
.SelectWrite
&&
543 mode
!= SelectMode
.SelectError
)
544 throw new NotSupportedException ("'mode' parameter is not valid.");
547 bool result
= Poll_internal (socket
, mode
, time_us
, out error
);
549 throw new SocketException (error
);
551 socket_error
= (int)GetSocketOption (SocketOptionLevel
.Socket
, SocketOptionName
.Error
);
553 if (mode
== SelectMode
.SelectWrite
&& result
) {
554 /* Update the connected state; for
555 * non-blocking Connect()s this is
556 * when we can find out that the
559 if (socket_error
== 0) {
567 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
568 private extern static int Receive_internal(IntPtr sock
,
575 internal int Receive_nochecks (byte [] buf
, int offset
, int size
, SocketFlags flags
, out SocketError error
)
578 int ret
= Receive_internal (socket
, buf
, offset
, size
, flags
, out nativeError
);
579 error
= (SocketError
) nativeError
;
580 if (error
!= SocketError
.Success
&& error
!= SocketError
.WouldBlock
&& error
!= SocketError
.InProgress
)
588 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
589 private extern static void GetSocketOption_obj_internal(IntPtr socket
,
590 SocketOptionLevel level
, SocketOptionName name
, out object obj_val
,
593 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
594 private extern static int Send_internal(IntPtr sock
,
595 byte[] buf
, int offset
,
600 internal int Send_nochecks (byte [] buf
, int offset
, int size
, SocketFlags flags
, out SocketError error
)
603 error
= SocketError
.Success
;
609 int ret
= Send_internal (socket
, buf
, offset
, size
, flags
, out nativeError
);
611 error
= (SocketError
)nativeError
;
613 if (error
!= SocketError
.Success
&& error
!= SocketError
.WouldBlock
&& error
!= SocketError
.InProgress
)
621 public object GetSocketOption (SocketOptionLevel optionLevel
, SocketOptionName optionName
)
623 if (disposed
&& closed
)
624 throw new ObjectDisposedException (GetType ().ToString ());
629 GetSocketOption_obj_internal (socket
, optionLevel
, optionName
, out obj_val
,
632 throw new SocketException (error
);
634 if (optionName
== SocketOptionName
.Linger
) {
635 return((LingerOption
)obj_val
);
636 } else if (optionName
== SocketOptionName
.AddMembership
||
637 optionName
== SocketOptionName
.DropMembership
) {
638 return((MulticastOption
)obj_val
);
639 } else if (obj_val
is int) {
640 return((int)obj_val
);
646 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
647 private extern static void Shutdown_internal (IntPtr socket
, SocketShutdown how
, out int error
);
649 public void Shutdown (SocketShutdown how
)
651 if (disposed
&& closed
)
652 throw new ObjectDisposedException (GetType ().ToString ());
656 Shutdown_internal (socket
, how
, out error
);
659 throw new SocketException (error
);
662 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
663 private extern static void SetSocketOption_internal (IntPtr socket
, SocketOptionLevel level
,
664 SocketOptionName name
, object obj_val
,
665 byte [] byte_val
, int int_val
,
668 public void SetSocketOption (SocketOptionLevel optionLevel
, SocketOptionName optionName
, int optionValue
)
670 if (disposed
&& closed
)
671 throw new ObjectDisposedException (GetType ().ToString ());
675 SetSocketOption_internal (socket
, optionLevel
, optionName
, null,
676 null, optionValue
, out error
);
679 throw new SocketException (error
);
682 private void ThrowIfUpd ()
685 if (protocol_type
== ProtocolType
.Udp
)
686 throw new SocketException ((int)SocketError
.ProtocolOption
);
690 #if NET_2_1 && !MONOTOUCH
691 static MethodInfo check_socket_policy
;
693 static void CheckConnect (SocketAsyncEventArgs e
, bool checkPolicy
)
695 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
697 if (e
.RemoteEndPoint
== null)
698 throw new ArgumentNullException ("remoteEP");
699 if (e
.BufferList
!= null)
700 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
705 e
.SocketError
= SocketError
.AccessDenied
;
706 if (check_socket_policy
== null) {
707 Type type
= Type
.GetType ("System.Windows.Browser.Net.CrossDomainPolicyManager, System.Windows.Browser, Version=2.0.5.0, Culture=Neutral, PublicKeyToken=7cec85d7bea7798e");
708 check_socket_policy
= type
.GetMethod ("CheckEndPoint");
709 if (check_socket_policy
== null)
710 throw new SecurityException ();
712 if ((bool) check_socket_policy
.Invoke (null, new object [1] { e.RemoteEndPoint }
))
713 e
.SocketError
= SocketError
.Success
;
716 // only _directly_ used (with false) to download the socket policy
717 internal bool ConnectAsync (SocketAsyncEventArgs e
, bool checkPolicy
)
719 if (disposed
&& closed
)
720 throw new ObjectDisposedException (GetType ().ToString ());
722 CheckConnect (e
, checkPolicy
);
724 e
.DoOperation (SocketAsyncOperation
.Connect
, this);
726 // We always return true for now
730 public bool ConnectAsync (SocketAsyncEventArgs e
)
732 return ConnectAsync (e
, true);
735 public static bool ConnectAsync (SocketType socketType
, ProtocolType protocolType
, SocketAsyncEventArgs e
)
737 CheckConnect (e
, true);
739 Socket s
= new Socket (AddressFamily
.InterNetwork
, socketType
, protocolType
);
740 e
.DoOperation (SocketAsyncOperation
.Connect
, s
);
742 // We always return true for now
746 public static void CancelConnectAsync (SocketAsyncEventArgs e
)
749 throw new ArgumentNullException ("e");
751 Socket s
= e
.ConnectSocket
;
752 if ((s
!= null) && (s
.blocking_thread
!= null))
753 s
.blocking_thread
.Abort ();