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;
48 using System.Collections.Generic;
49 using System.Net.NetworkInformation;
55 namespace System.Net.Sockets {
57 public partial class Socket : IDisposable {
60 * These two fields are looked up by name by the runtime, don't change
61 * their name without also updating the runtime code.
63 private static int ipv4Supported = -1, ipv6Supported = -1;
67 // initialize ipv4Supported and ipv6Supported
68 CheckProtocolSupport ();
71 internal static void CheckProtocolSupport ()
73 if(ipv4Supported == -1) {
75 Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
84 if (ipv6Supported == -1) {
86 #if NET_2_0 && CONFIGURATION_DEP
87 SettingsSection config;
88 config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
90 ipv6Supported = config.Ipv6.Enabled ? -1 : 0;
92 NetConfig config = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig;
94 ipv6Supported = config.ipv6Enabled ? -1 : 0;
97 if (ipv6Supported != 0) {
99 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
110 public static bool SupportsIPv4 {
112 CheckProtocolSupport();
113 return ipv4Supported == 1;
118 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
120 public static bool SupportsIPv6 {
122 CheckProtocolSupport();
123 return ipv6Supported == 1;
127 public static bool OSSupportsIPv4 {
129 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
131 foreach (NetworkInterface adapter in nics) {
132 if (adapter.Supports (NetworkInterfaceComponent.IPv4))
140 public static bool OSSupportsIPv6 {
142 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
144 foreach (NetworkInterface adapter in nics) {
145 if (adapter.Supports (NetworkInterfaceComponent.IPv6))
153 /* the field "socket" is looked up by name by the runtime */
154 private IntPtr socket;
155 private AddressFamily address_family;
156 private SocketType socket_type;
157 private ProtocolType protocol_type;
158 internal bool blocking=true;
159 Thread blocking_thread;
161 private bool isbound;
163 /* When true, the socket was connected at the time of
164 * the last IO operation
166 private bool connected;
167 /* true if we called Close_internal */
169 internal bool disposed;
172 * This EndPoint is used when creating new endpoints. Because
173 * there are many types of EndPoints possible,
174 * seed_endpoint.Create(addr) is used for creating new ones.
175 * As such, this value is set on Bind, SentTo, ReceiveFrom,
178 internal EndPoint seed_endpoint = null;
181 // Creates a new system socket, returning the handle
182 [MethodImplAttribute(MethodImplOptions.InternalCall)]
183 private extern IntPtr Socket_internal(AddressFamily family,
189 public Socket(AddressFamily family, SocketType type, ProtocolType proto)
191 address_family=family;
197 socket = Socket_internal (family, type, proto, out error);
199 throw new SocketException (error);
211 public AddressFamily AddressFamily {
212 get { return address_family; }
216 [MethodImplAttribute(MethodImplOptions.InternalCall)]
217 private extern static void Blocking_internal(IntPtr socket,
221 public bool Blocking {
226 if (disposed && closed)
227 throw new ObjectDisposedException (GetType ().ToString ());
231 Blocking_internal (socket, value, out error);
234 throw new SocketException (error);
240 public bool Connected {
241 get { return connected; }
242 internal set { connected = value; }
245 public ProtocolType ProtocolType {
246 get { return protocol_type; }
249 public bool NoDelay {
251 if (disposed && closed)
252 throw new ObjectDisposedException (GetType ().ToString ());
256 return (int)(GetSocketOption (
257 SocketOptionLevel.Tcp,
258 SocketOptionName.NoDelay)) != 0;
262 if (disposed && closed)
263 throw new ObjectDisposedException (GetType ().ToString ());
268 SocketOptionLevel.Tcp,
269 SocketOptionName.NoDelay, value ? 1 : 0);
273 public int ReceiveBufferSize {
275 if (disposed && closed) {
276 throw new ObjectDisposedException (GetType ().ToString ());
278 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer));
281 if (disposed && closed) {
282 throw new ObjectDisposedException (GetType ().ToString ());
285 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
288 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
292 public int SendBufferSize {
294 if (disposed && closed) {
295 throw new ObjectDisposedException (GetType ().ToString ());
297 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer));
300 if (disposed && closed) {
301 throw new ObjectDisposedException (GetType ().ToString ());
304 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
307 SetSocketOption (SocketOptionLevel.Socket,
308 SocketOptionName.SendBuffer,
315 if (disposed && closed) {
316 throw new ObjectDisposedException (GetType ().ToString ());
321 if (address_family == AddressFamily.InterNetwork) {
322 ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive));
323 } else if (address_family == AddressFamily.InterNetworkV6) {
324 ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit));
326 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
332 if (disposed && closed) {
333 throw new ObjectDisposedException (GetType ().ToString ());
336 if (address_family == AddressFamily.InterNetwork) {
337 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
338 } else if (address_family == AddressFamily.InterNetworkV6) {
339 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
341 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
346 // Returns the remote endpoint details in addr and port
347 [MethodImplAttribute(MethodImplOptions.InternalCall)]
348 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket, out int error);
350 public EndPoint RemoteEndPoint {
352 if (disposed && closed)
353 throw new ObjectDisposedException (GetType ().ToString ());
356 * If the seed EndPoint is null, Connect, Bind,
357 * etc has not yet been called. MS returns null
360 if (seed_endpoint == null)
366 sa=RemoteEndPoint_internal(socket, out error);
369 throw new SocketException (error);
371 return seed_endpoint.Create (sa);
375 protected virtual void Dispose (bool explicitDisposing)
382 if ((int) socket != -1) {
386 socket = (IntPtr) (-1);
387 Close_internal (x, out error);
389 if (blocking_thread != null) {
390 blocking_thread.Abort ();
391 blocking_thread = null;
395 throw new SocketException (error);
400 public void Dispose ()
402 void IDisposable.Dispose ()
406 GC.SuppressFinalize (this);
410 [MethodImplAttribute(MethodImplOptions.InternalCall)]
411 private extern static void Close_internal(IntPtr socket, out int error);
415 ((IDisposable) this).Dispose ();
418 // Connects to the remote address
419 [MethodImplAttribute(MethodImplOptions.InternalCall)]
420 private extern static void Connect_internal(IntPtr sock,
424 public void Connect (EndPoint remote_end)
426 if (disposed && closed)
427 throw new ObjectDisposedException (GetType ().ToString ());
429 if (remote_end == null)
430 throw new ArgumentNullException("remote_end");
432 if (remote_end is IPEndPoint) {
433 IPEndPoint ep = (IPEndPoint) remote_end;
434 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
435 throw new SocketException ((int) SocketError.AddressNotAvailable);
439 // Check for SL2.0b1 restrictions
442 // - port 4502->4532 + default
443 if (protocol_type != ProtocolType.Tcp)
444 throw new SocketException ((int) SocketError.AccessDenied);
445 //FIXME: replace 80 by Application.Curent.Host.Source.Port
446 if (remote_end is IPEndPoint)
447 if (((remote_end as IPEndPoint).Port < 4502 || (remote_end as IPEndPoint).Port > 4530) && (remote_end as IPEndPoint).Port != 80)
448 throw new SocketException ((int) SocketError.AccessDenied);
449 else //unsuported endpoint type
450 throw new SocketException ((int) SocketError.AccessDenied);
451 //FIXME: check for Application.Curent.Host.Source.DnsSafeHost
453 /* TODO: check this for the 1.1 profile too */
455 throw new InvalidOperationException ();
458 SocketAddress serial = remote_end.Serialize ();
461 blocking_thread = Thread.CurrentThread;
463 Connect_internal (socket, serial, out error);
464 } catch (ThreadAbortException) {
466 #if !NET_2_1 //2.1 profile does not contains Thread.ResetAbort
467 Thread.ResetAbort ();
469 error = (int) SocketError.Interrupted;
472 blocking_thread = null;
476 throw new SocketException (error);
484 seed_endpoint = remote_end;
488 public bool ReceiveAsync (SocketAsyncEventArgs e)
490 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
492 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
493 // thrown when e.Buffer and e.BufferList are null (works fine when one is
494 // set to a valid object)
495 if (disposed && closed)
496 throw new ObjectDisposedException (GetType ().ToString ());
498 // We do not support recv into multiple buffers yet
499 if (e.BufferList != null)
500 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
502 e.DoOperation (SocketAsyncOperation.Receive, this);
504 // We always return true for now
508 public bool SendAsync (SocketAsyncEventArgs e)
510 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
512 if (disposed && closed)
513 throw new ObjectDisposedException (GetType ().ToString ());
514 if (e.Buffer == null && e.BufferList == null)
515 throw new ArgumentException ("Either e.Buffer or e.BufferList must be valid buffers.");
517 e.DoOperation (SocketAsyncOperation.Send, this);
519 // We always return true for now
524 [MethodImplAttribute(MethodImplOptions.InternalCall)]
525 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
527 /* This overload is needed as the async Connect method
528 * also needs to check the socket error status, but
529 * getsockopt(..., SO_ERROR) clears the error.
531 internal bool Poll (int time_us, SelectMode mode, out int socket_error)
533 if (disposed && closed)
534 throw new ObjectDisposedException (GetType ().ToString ());
536 if (mode != SelectMode.SelectRead &&
537 mode != SelectMode.SelectWrite &&
538 mode != SelectMode.SelectError)
539 throw new NotSupportedException ("'mode' parameter is not valid.");
542 bool result = Poll_internal (socket, mode, time_us, out error);
544 throw new SocketException (error);
546 socket_error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
548 if (mode == SelectMode.SelectWrite && result) {
549 /* Update the connected state; for
550 * non-blocking Connect()s this is
551 * when we can find out that the
554 if (socket_error == 0) {
562 [MethodImplAttribute(MethodImplOptions.InternalCall)]
563 private extern static int Receive_internal(IntPtr sock,
570 internal int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
573 int ret = Receive_internal (socket, buf, offset, size, flags, out nativeError);
574 error = (SocketError) nativeError;
575 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
583 [MethodImplAttribute(MethodImplOptions.InternalCall)]
584 private extern static void GetSocketOption_obj_internal(IntPtr socket,
585 SocketOptionLevel level, SocketOptionName name, out object obj_val,
588 [MethodImplAttribute(MethodImplOptions.InternalCall)]
589 private extern static int Send_internal(IntPtr sock,
590 byte[] buf, int offset,
595 internal int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
598 error = SocketError.Success;
604 int ret = Send_internal (socket, buf, offset, size, flags, out nativeError);
606 error = (SocketError)nativeError;
608 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
616 public object GetSocketOption (SocketOptionLevel level, SocketOptionName name)
618 if (disposed && closed)
619 throw new ObjectDisposedException (GetType ().ToString ());
624 GetSocketOption_obj_internal(socket, level, name, out obj_val,
627 throw new SocketException (error);
629 if (name == SocketOptionName.Linger) {
630 return((LingerOption)obj_val);
631 } else if (name==SocketOptionName.AddMembership ||
632 name==SocketOptionName.DropMembership) {
633 return((MulticastOption)obj_val);
634 } else if (obj_val is int) {
635 return((int)obj_val);
641 [MethodImplAttribute (MethodImplOptions.InternalCall)]
642 private extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
644 public void Shutdown (SocketShutdown how)
646 if (disposed && closed)
647 throw new ObjectDisposedException (GetType ().ToString ());
651 Shutdown_internal (socket, how, out error);
654 throw new SocketException (error);
657 [MethodImplAttribute(MethodImplOptions.InternalCall)]
658 private extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level,
659 SocketOptionName name, object obj_val,
660 byte [] byte_val, int int_val,
663 public void SetSocketOption (SocketOptionLevel level, SocketOptionName name, int opt_value)
665 if (disposed && closed)
666 throw new ObjectDisposedException (GetType ().ToString ());
670 SetSocketOption_internal(socket, level, name, null,
671 null, opt_value, out error);
674 throw new SocketException (error);
677 private void ThrowIfUpd ()
680 if (protocol_type == ProtocolType.Udp)
681 throw new SocketException ((int)SocketError.ProtocolOption);