move FrameworkName from corlib to System
[mcs.git] / class / System / System.Net.Sockets / Socket_2_1.cs
blobaf54044c3d50f2039abc56e331ebfc96c0462583
1 // System.Net.Sockets.Socket.cs
2 //
3 // Authors:
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 //
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:
23 //
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 //
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.
36 using System;
37 using System.Net;
38 using System.Collections;
39 using System.Runtime.CompilerServices;
40 using System.Runtime.InteropServices;
41 using System.Threading;
42 using System.IO;
43 using System.Security;
44 using System.Text;
46 #if !NET_2_1
47 using System.Net.Configuration;
48 #endif
50 #if NET_2_0
51 using System.Collections.Generic;
52 #if !NET_2_1
53 using System.Net.NetworkInformation;
54 #endif
55 #endif
57 namespace System.Net.Sockets {
59 public partial class Socket : IDisposable {
62 * These two fields are looked up by name by the runtime, don't change
63 * their name without also updating the runtime code.
65 private static int ipv4Supported = -1, ipv6Supported = -1;
66 int linger_timeout;
68 static Socket ()
70 // initialize ipv4Supported and ipv6Supported
71 CheckProtocolSupport ();
74 internal static void CheckProtocolSupport ()
76 if(ipv4Supported == -1) {
77 try {
78 Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
79 tmp.Close();
81 ipv4Supported = 1;
82 } catch {
83 ipv4Supported = 0;
87 if (ipv6Supported == -1) {
88 #if !NET_2_1
89 #if NET_2_0 && CONFIGURATION_DEP
90 SettingsSection config;
91 config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
92 if (config != null)
93 ipv6Supported = config.Ipv6.Enabled ? -1 : 0;
94 #else
95 NetConfig config = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig;
96 if (config != null)
97 ipv6Supported = config.ipv6Enabled ? -1 : 0;
98 #endif
99 #endif
100 if (ipv6Supported != 0) {
101 try {
102 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
103 tmp.Close();
105 ipv6Supported = 1;
106 } catch {
107 ipv6Supported = 0;
113 public static bool SupportsIPv4 {
114 get {
115 CheckProtocolSupport();
116 return ipv4Supported == 1;
120 #if NET_2_0
121 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
122 #endif
123 public static bool SupportsIPv6 {
124 get {
125 CheckProtocolSupport();
126 return ipv6Supported == 1;
129 #if NET_2_1
130 public static bool OSSupportsIPv4 {
131 get {
132 CheckProtocolSupport();
133 return ipv4Supported == 1;
136 #endif
137 #if NET_2_1
138 public static bool OSSupportsIPv6 {
139 get {
140 CheckProtocolSupport();
141 return ipv6Supported == 1;
144 #elif NET_2_0
145 public static bool OSSupportsIPv6 {
146 get {
147 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
149 foreach (NetworkInterface adapter in nics) {
150 if (adapter.Supports (NetworkInterfaceComponent.IPv6))
151 return true;
153 return false;
156 #endif
158 /* the field "socket" is looked up by name by the runtime */
159 private IntPtr socket;
160 private AddressFamily address_family;
161 private SocketType socket_type;
162 private ProtocolType protocol_type;
163 internal bool blocking=true;
164 Thread blocking_thread;
165 #if NET_2_0
166 private bool isbound;
167 #endif
168 /* When true, the socket was connected at the time of
169 * the last IO operation
171 private bool connected;
172 /* true if we called Close_internal */
173 private bool closed;
174 internal bool disposed;
177 * This EndPoint is used when creating new endpoints. Because
178 * there are many types of EndPoints possible,
179 * seed_endpoint.Create(addr) is used for creating new ones.
180 * As such, this value is set on Bind, SentTo, ReceiveFrom,
181 * Connect, etc.
183 internal EndPoint seed_endpoint = null;
185 #if !TARGET_JVM
186 // Creates a new system socket, returning the handle
187 [MethodImplAttribute(MethodImplOptions.InternalCall)]
188 private extern IntPtr Socket_internal(AddressFamily family,
189 SocketType type,
190 ProtocolType proto,
191 out int error);
192 #endif
194 public Socket(AddressFamily family, SocketType type, ProtocolType proto)
196 #if NET_2_1
197 if (family == AddressFamily.Unspecified)
198 throw new ArgumentException ("family");
199 #endif
200 address_family=family;
201 socket_type=type;
202 protocol_type=proto;
204 int error;
206 socket = Socket_internal (family, type, proto, out error);
207 if (error != 0)
208 throw new SocketException (error);
209 #if !NET_2_1
210 SocketDefaults ();
211 #endif
214 ~Socket ()
216 Dispose (false);
220 public AddressFamily AddressFamily {
221 get { return address_family; }
224 #if !TARGET_JVM
225 [MethodImplAttribute(MethodImplOptions.InternalCall)]
226 private extern static void Blocking_internal(IntPtr socket,
227 bool block,
228 out int error);
229 #endif
231 public bool Blocking {
232 get {
233 return(blocking);
235 set {
236 if (disposed && closed)
237 throw new ObjectDisposedException (GetType ().ToString ());
239 int error;
241 Blocking_internal (socket, value, out error);
243 if (error != 0)
244 throw new SocketException (error);
246 blocking=value;
250 public bool Connected {
251 get { return connected; }
252 internal set { connected = value; }
255 public ProtocolType ProtocolType {
256 get { return protocol_type; }
258 #if NET_2_0
259 public bool NoDelay {
260 get {
261 if (disposed && closed)
262 throw new ObjectDisposedException (GetType ().ToString ());
264 ThrowIfUpd ();
266 return (int)(GetSocketOption (
267 SocketOptionLevel.Tcp,
268 SocketOptionName.NoDelay)) != 0;
271 set {
272 if (disposed && closed)
273 throw new ObjectDisposedException (GetType ().ToString ());
275 ThrowIfUpd ();
277 SetSocketOption (
278 SocketOptionLevel.Tcp,
279 SocketOptionName.NoDelay, value ? 1 : 0);
283 public int ReceiveBufferSize {
284 get {
285 if (disposed && closed) {
286 throw new ObjectDisposedException (GetType ().ToString ());
288 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer));
290 set {
291 if (disposed && closed) {
292 throw new ObjectDisposedException (GetType ().ToString ());
294 if (value < 0) {
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 {
303 get {
304 if (disposed && closed) {
305 throw new ObjectDisposedException (GetType ().ToString ());
307 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer));
309 set {
310 if (disposed && closed) {
311 throw new ObjectDisposedException (GetType ().ToString ());
313 if (value < 0) {
314 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
317 SetSocketOption (SocketOptionLevel.Socket,
318 SocketOptionName.SendBuffer,
319 value);
323 public short Ttl {
324 get {
325 if (disposed && closed) {
326 throw new ObjectDisposedException (GetType ().ToString ());
329 short ttl_val;
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));
335 } else {
336 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
339 return(ttl_val);
341 set {
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);
350 } else {
351 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
355 #endif
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 {
361 get {
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
368 * in this case.
370 if (seed_endpoint == null)
371 return null;
373 SocketAddress sa;
374 int error;
376 sa=RemoteEndPoint_internal(socket, out error);
378 if (error != 0)
379 throw new SocketException (error);
381 return seed_endpoint.Create (sa);
385 void Linger (IntPtr handle)
387 if (!connected || linger_timeout <= 0)
388 return;
390 // We don't want to receive any more data
391 int error;
392 Shutdown_internal (handle, SocketShutdown.Receive, out error);
393 if (error != 0)
394 return;
396 int seconds = linger_timeout / 1000;
397 int ms = linger_timeout % 1000;
398 if (ms > 0) {
399 // If the other end closes, this will return 'true' with 'Available' == 0
400 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
401 if (error != 0)
402 return;
405 if (seconds > 0) {
406 LingerOption linger = new LingerOption (true, seconds);
407 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
408 /* Not needed, we're closing upon return */
409 /*if (error != 0)
410 return; */
414 protected virtual void Dispose (bool explicitDisposing)
416 if (disposed)
417 return;
419 disposed = true;
420 bool was_connected = connected;
421 connected = false;
422 if ((int) socket != -1) {
423 int error;
424 closed = true;
425 IntPtr x = socket;
426 socket = (IntPtr) (-1);
427 Thread th = blocking_thread;
428 if (th != null) {
429 th.Abort ();
430 blocking_thread = null;
433 if (was_connected)
434 Linger (x);
435 //DateTime start = DateTime.UtcNow;
436 Close_internal (x, out error);
437 //Console.WriteLine ("Time spent in Close_internal: {0}ms", (DateTime.UtcNow - start).TotalMilliseconds);
438 if (error != 0)
439 throw new SocketException (error);
443 #if NET_2_1
444 public void Dispose ()
445 #else
446 void IDisposable.Dispose ()
447 #endif
449 Dispose (true);
450 GC.SuppressFinalize (this);
453 // Closes the socket
454 [MethodImplAttribute(MethodImplOptions.InternalCall)]
455 private extern static void Close_internal(IntPtr socket, out int error);
457 public void Close ()
459 linger_timeout = 0;
460 ((IDisposable) this).Dispose ();
463 #if NET_2_0
464 public void Close (int timeout)
466 linger_timeout = timeout;
467 ((IDisposable) this).Dispose ();
469 #endif
471 // Connects to the remote address
472 [MethodImplAttribute(MethodImplOptions.InternalCall)]
473 private extern static void Connect_internal(IntPtr sock,
474 SocketAddress sa,
475 out int error);
477 public void Connect (EndPoint remoteEP)
479 SocketAddress serial = null;
481 if (disposed && closed)
482 throw new ObjectDisposedException (GetType ().ToString ());
484 if (remoteEP == null)
485 throw new ArgumentNullException ("remoteEP");
487 IPEndPoint ep = remoteEP as IPEndPoint;
488 if (ep != null)
489 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
490 throw new SocketException ((int) SocketError.AddressNotAvailable);
492 #if MOONLIGHT
493 if (protocol_type != ProtocolType.Tcp)
494 throw new SocketException ((int) SocketError.AccessDenied);
495 #elif NET_2_0
496 /* TODO: check this for the 1.1 profile too */
497 if (islistening)
498 throw new InvalidOperationException ();
499 #endif
500 serial = remoteEP.Serialize ();
502 int error = 0;
504 blocking_thread = Thread.CurrentThread;
505 try {
506 Connect_internal (socket, serial, out error);
507 } catch (ThreadAbortException) {
508 if (disposed) {
509 Thread.ResetAbort ();
510 error = (int) SocketError.Interrupted;
512 } finally {
513 blocking_thread = null;
516 if (error != 0)
517 throw new SocketException (error);
519 connected=true;
521 #if NET_2_0
522 isbound = true;
523 #endif
525 seed_endpoint = remoteEP;
528 #if NET_2_0
529 public bool ReceiveAsync (SocketAsyncEventArgs e)
531 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
533 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
534 // thrown when e.Buffer and e.BufferList are null (works fine when one is
535 // set to a valid object)
536 if (disposed && closed)
537 throw new ObjectDisposedException (GetType ().ToString ());
539 // We do not support recv into multiple buffers yet
540 if (e.BufferList != null)
541 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
543 e.DoOperation (SocketAsyncOperation.Receive, this);
545 // We always return true for now
546 return true;
549 public bool SendAsync (SocketAsyncEventArgs e)
551 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
553 if (disposed && closed)
554 throw new ObjectDisposedException (GetType ().ToString ());
555 if (e.Buffer == null && e.BufferList == null)
556 throw new ArgumentException ("Either e.Buffer or e.BufferList must be valid buffers.");
558 e.DoOperation (SocketAsyncOperation.Send, this);
560 // We always return true for now
561 return true;
563 #endif
565 [MethodImplAttribute(MethodImplOptions.InternalCall)]
566 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
568 /* This overload is needed as the async Connect method
569 * also needs to check the socket error status, but
570 * getsockopt(..., SO_ERROR) clears the error.
572 internal bool Poll (int time_us, SelectMode mode, out int socket_error)
574 if (disposed && closed)
575 throw new ObjectDisposedException (GetType ().ToString ());
577 if (mode != SelectMode.SelectRead &&
578 mode != SelectMode.SelectWrite &&
579 mode != SelectMode.SelectError)
580 throw new NotSupportedException ("'mode' parameter is not valid.");
582 int error;
583 bool result = Poll_internal (socket, mode, time_us, out error);
584 if (error != 0)
585 throw new SocketException (error);
587 socket_error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
589 if (mode == SelectMode.SelectWrite && result) {
590 /* Update the connected state; for
591 * non-blocking Connect()s this is
592 * when we can find out that the
593 * connect succeeded.
595 if (socket_error == 0) {
596 connected = true;
600 return result;
603 [MethodImplAttribute(MethodImplOptions.InternalCall)]
604 private extern static int Receive_internal(IntPtr sock,
605 byte[] buffer,
606 int offset,
607 int count,
608 SocketFlags flags,
609 out int error);
611 internal int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
613 int nativeError;
614 int ret = Receive_internal (socket, buf, offset, size, flags, out nativeError);
615 error = (SocketError) nativeError;
616 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
617 connected = false;
618 else
619 connected = true;
621 return ret;
624 [MethodImplAttribute(MethodImplOptions.InternalCall)]
625 private extern static void GetSocketOption_obj_internal(IntPtr socket,
626 SocketOptionLevel level, SocketOptionName name, out object obj_val,
627 out int error);
629 [MethodImplAttribute(MethodImplOptions.InternalCall)]
630 private extern static int Send_internal(IntPtr sock,
631 byte[] buf, int offset,
632 int count,
633 SocketFlags flags,
634 out int error);
636 internal int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
638 if (size == 0) {
639 error = SocketError.Success;
640 return 0;
643 int nativeError;
645 int ret = Send_internal (socket, buf, offset, size, flags, out nativeError);
647 error = (SocketError)nativeError;
649 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
650 connected = false;
651 else
652 connected = true;
654 return ret;
657 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
659 if (disposed && closed)
660 throw new ObjectDisposedException (GetType ().ToString ());
662 object obj_val;
663 int error;
665 GetSocketOption_obj_internal (socket, optionLevel, optionName, out obj_val,
666 out error);
667 if (error != 0)
668 throw new SocketException (error);
670 if (optionName == SocketOptionName.Linger) {
671 return((LingerOption)obj_val);
672 } else if (optionName == SocketOptionName.AddMembership ||
673 optionName == SocketOptionName.DropMembership) {
674 return((MulticastOption)obj_val);
675 } else if (obj_val is int) {
676 return((int)obj_val);
677 } else {
678 return(obj_val);
682 [MethodImplAttribute (MethodImplOptions.InternalCall)]
683 private extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
685 public void Shutdown (SocketShutdown how)
687 if (disposed && closed)
688 throw new ObjectDisposedException (GetType ().ToString ());
690 if (!connected)
691 throw new SocketException (10057); // Not connected
693 int error;
695 Shutdown_internal (socket, how, out error);
696 if (error != 0)
697 throw new SocketException (error);
700 [MethodImplAttribute(MethodImplOptions.InternalCall)]
701 private extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level,
702 SocketOptionName name, object obj_val,
703 byte [] byte_val, int int_val,
704 out int error);
706 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
708 if (disposed && closed)
709 throw new ObjectDisposedException (GetType ().ToString ());
711 int error;
713 SetSocketOption_internal (socket, optionLevel, optionName, null,
714 null, optionValue, out error);
716 if (error != 0)
717 throw new SocketException (error);
720 private void ThrowIfUpd ()
722 #if !NET_2_1
723 if (protocol_type == ProtocolType.Udp)
724 throw new SocketException ((int)SocketError.ProtocolOption);
725 #endif
728 #if MOONLIGHT
729 static void CheckConnect (SocketAsyncEventArgs e)
731 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
733 if (e.RemoteEndPoint == null)
734 throw new ArgumentNullException ("remoteEP");
735 if (e.BufferList != null)
736 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
739 public bool ConnectAsync (SocketAsyncEventArgs e)
741 if (disposed && closed)
742 throw new ObjectDisposedException (GetType ().ToString ());
744 CheckConnect (e);
746 e.DoOperation (SocketAsyncOperation.Connect, this);
748 // We always return true for now
749 return true;
752 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
754 // exception ordering requires to check before creating the socket (good thing resource wise too)
755 CheckConnect (e);
757 Socket s = new Socket (AddressFamily.InterNetwork, socketType, protocolType);
758 e.DoOperation (SocketAsyncOperation.Connect, s);
760 // We always return true for now
761 return true;
764 public static void CancelConnectAsync (SocketAsyncEventArgs e)
766 if (e == null)
767 throw new ArgumentNullException ("e");
769 Socket s = e.ConnectSocket;
770 if ((s != null) && (s.blocking_thread != null))
771 s.blocking_thread.Abort ();
773 #endif