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.Net.Configuration;
45 using System.Security;
49 using System.Collections.Generic;
50 using System.Net.NetworkInformation;
56 namespace System.Net.Sockets {
58 public partial class Socket : IDisposable {
61 * These two fields are looked up by name by the runtime, don't change
62 * their name without also updating the runtime code.
64 private static int ipv4Supported = -1, ipv6Supported = -1;
68 // initialize ipv4Supported and ipv6Supported
69 CheckProtocolSupport ();
72 internal static void CheckProtocolSupport ()
74 if(ipv4Supported == -1) {
76 Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
85 if (ipv6Supported == -1) {
87 #if NET_2_0 && CONFIGURATION_DEP
88 SettingsSection config;
89 config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
91 ipv6Supported = config.Ipv6.Enabled ? -1 : 0;
93 NetConfig config = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig;
95 ipv6Supported = config.ipv6Enabled ? -1 : 0;
98 if (ipv6Supported != 0) {
100 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
111 public static bool SupportsIPv4 {
113 CheckProtocolSupport();
114 return ipv4Supported == 1;
119 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
121 public static bool SupportsIPv6 {
123 CheckProtocolSupport();
124 return ipv6Supported == 1;
128 public static bool OSSupportsIPv4 {
130 CheckProtocolSupport();
131 return ipv4Supported == 1;
136 public static bool OSSupportsIPv6 {
138 CheckProtocolSupport();
139 return ipv6Supported == 1;
143 public static bool OSSupportsIPv6 {
145 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
147 foreach (NetworkInterface adapter in nics) {
148 if (adapter.Supports (NetworkInterfaceComponent.IPv6))
156 /* the field "socket" is looked up by name by the runtime */
157 private IntPtr socket;
158 private AddressFamily address_family;
159 private SocketType socket_type;
160 private ProtocolType protocol_type;
161 internal bool blocking=true;
162 Thread blocking_thread;
164 private bool isbound;
166 /* When true, the socket was connected at the time of
167 * the last IO operation
169 private bool connected;
170 /* true if we called Close_internal */
172 internal bool disposed;
175 * This EndPoint is used when creating new endpoints. Because
176 * there are many types of EndPoints possible,
177 * seed_endpoint.Create(addr) is used for creating new ones.
178 * As such, this value is set on Bind, SentTo, ReceiveFrom,
181 internal EndPoint seed_endpoint = null;
184 // Creates a new system socket, returning the handle
185 [MethodImplAttribute(MethodImplOptions.InternalCall)]
186 private extern IntPtr Socket_internal(AddressFamily family,
192 public Socket(AddressFamily family, SocketType type, ProtocolType proto)
194 address_family=family;
200 socket = Socket_internal (family, type, proto, out error);
202 throw new SocketException (error);
214 public AddressFamily AddressFamily {
215 get { return address_family; }
219 [MethodImplAttribute(MethodImplOptions.InternalCall)]
220 private extern static void Blocking_internal(IntPtr socket,
224 public bool Blocking {
229 if (disposed && closed)
230 throw new ObjectDisposedException (GetType ().ToString ());
234 Blocking_internal (socket, value, out error);
237 throw new SocketException (error);
243 public bool Connected {
244 get { return connected; }
245 internal set { connected = value; }
248 public ProtocolType ProtocolType {
249 get { return protocol_type; }
252 public bool NoDelay {
254 if (disposed && closed)
255 throw new ObjectDisposedException (GetType ().ToString ());
259 return (int)(GetSocketOption (
260 SocketOptionLevel.Tcp,
261 SocketOptionName.NoDelay)) != 0;
265 if (disposed && closed)
266 throw new ObjectDisposedException (GetType ().ToString ());
271 SocketOptionLevel.Tcp,
272 SocketOptionName.NoDelay, value ? 1 : 0);
276 public int ReceiveBufferSize {
278 if (disposed && closed) {
279 throw new ObjectDisposedException (GetType ().ToString ());
281 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer));
284 if (disposed && closed) {
285 throw new ObjectDisposedException (GetType ().ToString ());
288 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
291 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
295 public int SendBufferSize {
297 if (disposed && closed) {
298 throw new ObjectDisposedException (GetType ().ToString ());
300 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer));
303 if (disposed && closed) {
304 throw new ObjectDisposedException (GetType ().ToString ());
307 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
310 SetSocketOption (SocketOptionLevel.Socket,
311 SocketOptionName.SendBuffer,
318 if (disposed && closed) {
319 throw new ObjectDisposedException (GetType ().ToString ());
324 if (address_family == AddressFamily.InterNetwork) {
325 ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive));
326 } else if (address_family == AddressFamily.InterNetworkV6) {
327 ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit));
329 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
335 if (disposed && closed) {
336 throw new ObjectDisposedException (GetType ().ToString ());
339 if (address_family == AddressFamily.InterNetwork) {
340 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
341 } else if (address_family == AddressFamily.InterNetworkV6) {
342 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
344 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
349 // Returns the remote endpoint details in addr and port
350 [MethodImplAttribute(MethodImplOptions.InternalCall)]
351 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket, out int error);
353 public EndPoint RemoteEndPoint {
355 if (disposed && closed)
356 throw new ObjectDisposedException (GetType ().ToString ());
359 * If the seed EndPoint is null, Connect, Bind,
360 * etc has not yet been called. MS returns null
363 if (seed_endpoint == null)
369 sa=RemoteEndPoint_internal(socket, out error);
372 throw new SocketException (error);
374 return seed_endpoint.Create (sa);
378 protected virtual void Dispose (bool explicitDisposing)
385 if ((int) socket != -1) {
389 socket = (IntPtr) (-1);
390 Close_internal (x, out error);
391 if (blocking_thread != null) {
392 blocking_thread.Abort ();
393 blocking_thread = null;
396 throw new SocketException (error);
401 public void Dispose ()
403 void IDisposable.Dispose ()
407 GC.SuppressFinalize (this);
411 [MethodImplAttribute(MethodImplOptions.InternalCall)]
412 private extern static void Close_internal(IntPtr socket, out int error);
416 ((IDisposable) this).Dispose ();
419 // Connects to the remote address
420 [MethodImplAttribute(MethodImplOptions.InternalCall)]
421 private extern static void Connect_internal(IntPtr sock,
425 public void Connect (EndPoint remote_end)
427 SocketAddress serial = null;
429 if (disposed && closed)
430 throw new ObjectDisposedException (GetType ().ToString ());
432 if (remote_end == null)
433 throw new ArgumentNullException("remote_end");
435 if (remote_end is IPEndPoint) {
436 IPEndPoint ep = (IPEndPoint) remote_end;
437 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
438 throw new SocketException ((int) SocketError.AddressNotAvailable);
441 if (protocol_type != ProtocolType.Tcp)
442 throw new SocketException ((int) SocketError.AccessDenied);
444 DnsEndPoint dep = (remote_end as DnsEndPoint);
446 serial = dep.AsIPEndPoint ().Serialize ();
448 serial = remote_end.Serialize ();
450 /* TODO: check this for the 1.1 profile too */
452 throw new InvalidOperationException ();
454 serial = remote_end.Serialize ();
456 serial = remote_end.Serialize ();
461 blocking_thread = Thread.CurrentThread;
463 Connect_internal (socket, serial, out error);
464 } catch (ThreadAbortException) {
466 Thread.ResetAbort ();
467 error = (int) SocketError.Interrupted;
470 blocking_thread = null;
474 throw new SocketException (error);
482 seed_endpoint = remote_end;
486 public bool ReceiveAsync (SocketAsyncEventArgs e)
488 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
490 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
491 // thrown when e.Buffer and e.BufferList are null (works fine when one is
492 // set to a valid object)
493 if (disposed && closed)
494 throw new ObjectDisposedException (GetType ().ToString ());
496 // We do not support recv into multiple buffers yet
497 if (e.BufferList != null)
498 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
500 e.DoOperation (SocketAsyncOperation.Receive, this);
502 // We always return true for now
506 public bool SendAsync (SocketAsyncEventArgs e)
508 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
510 if (disposed && closed)
511 throw new ObjectDisposedException (GetType ().ToString ());
512 if (e.Buffer == null && e.BufferList == null)
513 throw new ArgumentException ("Either e.Buffer or e.BufferList must be valid buffers.");
515 e.DoOperation (SocketAsyncOperation.Send, this);
517 // We always return true for now
522 [MethodImplAttribute(MethodImplOptions.InternalCall)]
523 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
525 /* This overload is needed as the async Connect method
526 * also needs to check the socket error status, but
527 * getsockopt(..., SO_ERROR) clears the error.
529 internal bool Poll (int time_us, SelectMode mode, out int socket_error)
531 if (disposed && closed)
532 throw new ObjectDisposedException (GetType ().ToString ());
534 if (mode != SelectMode.SelectRead &&
535 mode != SelectMode.SelectWrite &&
536 mode != SelectMode.SelectError)
537 throw new NotSupportedException ("'mode' parameter is not valid.");
540 bool result = Poll_internal (socket, mode, time_us, out error);
542 throw new SocketException (error);
544 socket_error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
546 if (mode == SelectMode.SelectWrite && result) {
547 /* Update the connected state; for
548 * non-blocking Connect()s this is
549 * when we can find out that the
552 if (socket_error == 0) {
560 [MethodImplAttribute(MethodImplOptions.InternalCall)]
561 private extern static int Receive_internal(IntPtr sock,
568 internal int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
571 int ret = Receive_internal (socket, buf, offset, size, flags, out nativeError);
572 error = (SocketError) nativeError;
573 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
581 [MethodImplAttribute(MethodImplOptions.InternalCall)]
582 private extern static void GetSocketOption_obj_internal(IntPtr socket,
583 SocketOptionLevel level, SocketOptionName name, out object obj_val,
586 [MethodImplAttribute(MethodImplOptions.InternalCall)]
587 private extern static int Send_internal(IntPtr sock,
588 byte[] buf, int offset,
593 internal int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
596 error = SocketError.Success;
602 int ret = Send_internal (socket, buf, offset, size, flags, out nativeError);
604 error = (SocketError)nativeError;
606 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
614 public object GetSocketOption (SocketOptionLevel level, SocketOptionName name)
616 if (disposed && closed)
617 throw new ObjectDisposedException (GetType ().ToString ());
622 GetSocketOption_obj_internal(socket, level, name, out obj_val,
625 throw new SocketException (error);
627 if (name == SocketOptionName.Linger) {
628 return((LingerOption)obj_val);
629 } else if (name==SocketOptionName.AddMembership ||
630 name==SocketOptionName.DropMembership) {
631 return((MulticastOption)obj_val);
632 } else if (obj_val is int) {
633 return((int)obj_val);
639 [MethodImplAttribute (MethodImplOptions.InternalCall)]
640 private extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
642 public void Shutdown (SocketShutdown how)
644 if (disposed && closed)
645 throw new ObjectDisposedException (GetType ().ToString ());
649 Shutdown_internal (socket, how, out error);
652 throw new SocketException (error);
655 [MethodImplAttribute(MethodImplOptions.InternalCall)]
656 private extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level,
657 SocketOptionName name, object obj_val,
658 byte [] byte_val, int int_val,
661 public void SetSocketOption (SocketOptionLevel level, SocketOptionName name, int opt_value)
663 if (disposed && closed)
664 throw new ObjectDisposedException (GetType ().ToString ());
668 SetSocketOption_internal(socket, level, name, null,
669 null, opt_value, out error);
672 throw new SocketException (error);
675 private void ThrowIfUpd ()
678 if (protocol_type == ProtocolType.Udp)
679 throw new SocketException ((int)SocketError.ProtocolOption);
684 static MethodInfo check_socket_policy;
686 static void CheckConnect (SocketAsyncEventArgs e, bool checkPolicy)
688 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
690 if (e.RemoteEndPoint == null)
691 throw new ArgumentNullException ("remoteEP");
692 if (e.BufferList != null)
693 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
698 if (check_socket_policy == null) {
699 Type type = Type.GetType ("System.Windows.Browser.Net.CrossDomainPolicyManager, System.Windows.Browser, Version=2.0.5.0, Culture=Neutral, PublicKeyToken=7cec85d7bea7798e");
700 check_socket_policy = type.GetMethod ("CheckEndPoint");
701 if (check_socket_policy == null)
702 throw new SecurityException ();
704 if (!(bool) check_socket_policy.Invoke (null, new object [1] { e.RemoteEndPoint }))
705 throw new SecurityException ();
708 // only _directly_ used (with false) to download the socket policy
709 internal bool ConnectAsync (SocketAsyncEventArgs e, bool checkPolicy)
711 if (disposed && closed)
712 throw new ObjectDisposedException (GetType ().ToString ());
714 CheckConnect (e, checkPolicy);
716 e.DoOperation (SocketAsyncOperation.Connect, this);
718 // We always return true for now
722 public bool ConnectAsync (SocketAsyncEventArgs e)
724 return ConnectAsync (e, true);
727 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
729 CheckConnect (e, true);
731 Socket s = new Socket (AddressFamily.InterNetwork, socketType, protocolType);
732 e.DoOperation (SocketAsyncOperation.Connect, s);
734 // We always return true for now
738 public static void CancelConnectAsync (SocketAsyncEventArgs e)
741 throw new ArgumentNullException ("e");
743 Socket s = e.ConnectSocket;
744 if ((s != null) && (s.blocking_thread != null))
745 s.blocking_thread.Abort ();