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-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;
44 using System.Security;
48 using System.Net.Configuration;
49 using System.Net.NetworkInformation;
51 #if MOONLIGHT && !INSIDE_SYSTEM
52 using System.Net.Policy;
55 namespace System.Net.Sockets {
57 public partial class Socket : IDisposable {
58 [StructLayout (LayoutKind.Sequential)]
64 // Used by the runtime
65 internal enum SocketOperation {
82 [StructLayout (LayoutKind.Sequential)]
83 internal sealed class SocketAsyncResult: IAsyncResult
85 /* Same structure in the runtime */
87 Keep this in sync with MonoSocketAsyncResult in
88 metadata/socket-io.h and ProcessAsyncReader
89 in System.Diagnostics/Process.cs.
95 AsyncCallback callback; // used from the runtime
96 WaitHandle waithandle;
98 Exception delayedException;
100 public EndPoint EndPoint; // Connect,ReceiveFrom,SendTo
101 public byte [] Buffer; // Receive,ReceiveFrom,Send,SendTo
102 public int Offset; // Receive,ReceiveFrom,Send,SendTo
103 public int Size; // Receive,ReceiveFrom,Send,SendTo
104 public SocketFlags SockFlags; // Receive,ReceiveFrom,Send,SendTo
105 public Socket AcceptSocket; // AcceptReceive
106 public IPAddress[] Addresses; // Connect
107 public int Port; // Connect
108 public IList<ArraySegment<byte>> Buffers; // Receive, Send
109 public bool ReuseSocket; // Disconnect
117 public bool blocking;
119 public SocketOperation operation;
121 public int EndCalled;
123 // These fields are not in MonoSocketAsyncResult
124 public Worker Worker;
125 public int CurrentAddress; // Connect
127 public SocketAsyncResult ()
131 public void Init (Socket sock, object state, AsyncCallback callback, SocketOperation operation)
135 this.blocking = sock.blocking;
136 this.handle = sock.socket;
138 this.blocking = true;
139 this.handle = IntPtr.Zero;
142 this.callback = callback;
143 GC.KeepAlive (this.callback);
144 this.operation = operation;
145 SockFlags = SocketFlags.None;
146 if (waithandle != null)
147 ((ManualResetEvent) waithandle).Reset ();
149 delayedException = null;
164 completed_sync = false;
173 public void DoMConnectCallback ()
175 if (callback == null)
178 ThreadPool.QueueUserWorkItem (_ => { callback (this); }, null);
180 ThreadPool.UnsafeQueueUserWorkItem (_ => { callback (this); }, null);
184 public void Dispose ()
186 Init (null, null, null, 0);
187 if (waithandle != null) {
193 public SocketAsyncResult (Socket sock, object state, AsyncCallback callback, SocketOperation operation)
196 this.blocking = sock.blocking;
197 this.handle = sock.socket;
199 this.callback = callback;
200 GC.KeepAlive (this.callback);
201 this.operation = operation;
202 SockFlags = SocketFlags.None;
203 Worker = new Worker (this);
206 public void CheckIfThrowDelayedException ()
208 if (delayedException != null) {
209 Sock.connected = false;
210 throw delayedException;
214 Sock.connected = false;
215 throw new SocketException (error);
219 void CompleteAllOnDispose (Queue queue)
221 object [] pending = queue.ToArray ();
225 for (int i = 0; i < pending.Length; i++) {
226 Worker worker = (Worker) pending [i];
227 SocketAsyncResult ares = worker.result;
228 cb = new WaitCallback (ares.CompleteDisposed);
230 ThreadPool.QueueUserWorkItem (cb, null);
232 ThreadPool.UnsafeQueueUserWorkItem (cb, null);
237 void CompleteDisposed (object unused)
242 public void Complete ()
244 if (operation != SocketOperation.Receive && Sock.disposed)
245 delayedException = new ObjectDisposedException (Sock.GetType ().ToString ());
250 if (operation == SocketOperation.Receive ||
251 operation == SocketOperation.ReceiveFrom ||
252 operation == SocketOperation.ReceiveGeneric) {
254 } else if (operation == SocketOperation.Send ||
255 operation == SocketOperation.SendTo ||
256 operation == SocketOperation.SendGeneric) {
262 Worker worker = null;
263 SocketAsyncCall sac = null;
265 // queue.Count will only be 0 if the socket is closed while receive/send
266 // operation(s) are pending and at least one call to this method is
267 // waiting on the lock while another one calls CompleteAllOnDispose()
269 queue.Dequeue (); // remove ourselves
270 if (queue.Count > 0) {
271 worker = (Worker) queue.Peek ();
272 if (!Sock.disposed) {
273 sac = Worker.Dispatcher;
275 CompleteAllOnDispose (queue);
281 Socket.socket_pool_queue (sac, worker.result);
283 // IMPORTANT: 'callback', if any is scheduled from unmanaged code
286 public void Complete (bool synch)
288 completed_sync = synch;
292 public void Complete (int total)
298 public void Complete (Exception e, bool synch)
300 completed_sync = synch;
301 delayedException = e;
305 public void Complete (Exception e)
307 delayedException = e;
311 public void Complete (Socket s)
317 public void Complete (Socket s, int total)
324 public object AsyncState {
330 public WaitHandle AsyncWaitHandle {
333 if (waithandle == null)
334 waithandle = new ManualResetEvent (completed);
344 public bool CompletedSynchronously {
346 return(completed_sync);
350 public bool IsCompleted {
357 if (waithandle != null && value) {
358 ((ManualResetEvent) waithandle).Set ();
364 public Socket Socket {
371 get { return total; }
372 set { total = value; }
375 public SocketError ErrorCode {
377 SocketException ex = delayedException as SocketException;
379 return(ex.SocketErrorCode);
382 return((SocketError)error);
384 return(SocketError.Success);
389 internal sealed class Worker
391 public SocketAsyncResult result;
392 SocketAsyncEventArgs args;
394 public Worker (SocketAsyncEventArgs args)
397 result = new SocketAsyncResult ();
398 result.Worker = this;
401 public Worker (SocketAsyncResult ares)
406 public void Dispose ()
408 if (result != null) {
415 public static SocketAsyncCall Dispatcher = new SocketAsyncCall (DispatcherCB);
417 static void DispatcherCB (SocketAsyncResult sar)
419 SocketOperation op = sar.operation;
420 if (op == Socket.SocketOperation.Receive || op == Socket.SocketOperation.ReceiveGeneric ||
421 op == Socket.SocketOperation.RecvJustCallback)
422 sar.Worker.Receive ();
423 else if (op == Socket.SocketOperation.Send || op == Socket.SocketOperation.SendGeneric ||
424 op == Socket.SocketOperation.SendJustCallback)
427 else if (op == Socket.SocketOperation.ReceiveFrom)
428 sar.Worker.ReceiveFrom ();
429 else if (op == Socket.SocketOperation.SendTo)
430 sar.Worker.SendTo ();
432 else if (op == Socket.SocketOperation.Connect)
433 sar.Worker.Connect ();
435 else if (op == Socket.SocketOperation.Accept)
436 sar.Worker.Accept ();
437 else if (op == Socket.SocketOperation.AcceptReceive)
438 sar.Worker.AcceptReceive ();
439 else if (op == Socket.SocketOperation.Disconnect)
440 sar.Worker.Disconnect ();
442 // SendPackets and ReceiveMessageFrom are not implemented yet
444 else if (op == Socket.SocketOperation.ReceiveMessageFrom)
445 async_op = SocketAsyncOperation.ReceiveMessageFrom;
446 else if (op == Socket.SocketOperation.SendPackets)
447 async_op = SocketAsyncOperation.SendPackets;
451 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
454 /* This is called when reusing a SocketAsyncEventArgs */
455 public void Init (Socket sock, SocketAsyncEventArgs args, SocketOperation op)
457 result.Init (sock, args, SocketAsyncEventArgs.Dispatcher, op);
458 result.Worker = this;
459 SocketAsyncOperation async_op;
462 // -SocketOperation.AcceptReceive not used in SocketAsyncEventArgs
463 // -SendPackets and ReceiveMessageFrom are not implemented yet
464 if (op == Socket.SocketOperation.Connect)
465 async_op = SocketAsyncOperation.Connect;
467 else if (op == Socket.SocketOperation.Accept)
468 async_op = SocketAsyncOperation.Accept;
469 else if (op == Socket.SocketOperation.Disconnect)
470 async_op = SocketAsyncOperation.Disconnect;
472 else if (op == Socket.SocketOperation.Receive || op == Socket.SocketOperation.ReceiveGeneric)
473 async_op = SocketAsyncOperation.Receive;
475 else if (op == Socket.SocketOperation.ReceiveFrom)
476 async_op = SocketAsyncOperation.ReceiveFrom;
479 else if (op == Socket.SocketOperation.ReceiveMessageFrom)
480 async_op = SocketAsyncOperation.ReceiveMessageFrom;
482 else if (op == Socket.SocketOperation.Send || op == Socket.SocketOperation.SendGeneric)
483 async_op = SocketAsyncOperation.Send;
486 else if (op == Socket.SocketOperation.SendPackets)
487 async_op = SocketAsyncOperation.SendPackets;
489 else if (op == Socket.SocketOperation.SendTo)
490 async_op = SocketAsyncOperation.SendTo;
493 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
495 args.SetLastOperation (async_op);
496 args.SocketError = SocketError.Success;
497 args.BytesTransferred = 0;
500 public void Accept ()
503 Socket acc_socket = null;
505 if (args != null && args.AcceptSocket != null) {
506 result.Sock.Accept (args.AcceptSocket);
507 acc_socket = args.AcceptSocket;
509 acc_socket = result.Sock.Accept ();
511 args.AcceptSocket = acc_socket;
513 } catch (Exception e) {
518 result.Complete (acc_socket);
522 /* only used in 2.0 profile and newer, but
523 * leave in older profiles to keep interface
524 * to runtime consistent
526 public void AcceptReceive ()
529 Socket acc_socket = null;
531 if (result.AcceptSocket == null) {
532 acc_socket = result.Sock.Accept ();
534 acc_socket = result.AcceptSocket;
535 result.Sock.Accept (acc_socket);
537 } catch (Exception e) {
542 /* It seems the MS runtime
543 * special-cases 0-length requested
544 * receive data. See bug 464201.
547 if (result.Size > 0) {
550 total = acc_socket.Receive_nochecks (result.Buffer,
556 result.Complete (new SocketException ((int) error));
559 } catch (Exception e) {
565 result.Complete (acc_socket, total);
569 public void Connect ()
571 if (result.EndPoint == null) {
572 result.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
576 SocketAsyncResult mconnect = result.AsyncState as SocketAsyncResult;
578 bool is_mconnect = (mconnect != null && mconnect.Addresses != null);
580 bool is_mconnect = false;
584 EndPoint ep = result.EndPoint;
585 SocketAddress serial = ep.Serialize ();
586 Connect_internal (result.Sock.socket, serial, out error_code);
587 if (error_code == 0) {
590 result.Sock.seed_endpoint = ep;
591 result.Sock.connected = true;
595 result.DoMConnectCallback ();
600 result.Complete (new SocketException (error_code));
604 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
605 mconnect.Complete (new SocketException (error_code));
607 mconnect.DoMConnectCallback ();
611 mconnect.Sock.BeginMConnect (mconnect);
613 } catch (Exception e) {
618 result.DoMConnectCallback ();
623 /* Also only used in 2.0 profile and newer */
624 public void Disconnect ()
629 result.ReuseSocket = args.DisconnectReuseSocket;
630 result.Sock.Disconnect (result.ReuseSocket);
631 } catch (Exception e) {
639 public void Receive ()
641 if (result.operation == SocketOperation.ReceiveGeneric) {
645 // Actual recv() done in the runtime
649 public void ReceiveFrom ()
654 total = result.Sock.ReceiveFrom_nochecks (result.Buffer,
658 ref result.EndPoint);
659 } catch (Exception e) {
664 result.Complete (total);
668 public void ReceiveGeneric ()
672 total = result.Sock.Receive (result.Buffers, result.SockFlags);
673 } catch (Exception e) {
677 result.Complete (total);
682 void UpdateSendValues (int last_sent)
684 if (result.error == 0) {
685 send_so_far += last_sent;
686 result.Offset += last_sent;
687 result.Size -= last_sent;
693 if (result.operation == SocketOperation.SendGeneric) {
697 // Actual send() done in the runtime
698 if (result.error == 0) {
699 UpdateSendValues (result.Total);
700 if (result.Sock.disposed) {
705 if (result.Size > 0) {
706 Socket.socket_pool_queue (Worker.Dispatcher, result);
707 return; // Have to finish writing everything. See bug #74475.
709 result.Total = send_so_far;
714 public void SendTo ()
719 total = result.Sock.SendTo_nochecks (result.Buffer,
725 UpdateSendValues (total);
726 if (result.Size > 0) {
727 Socket.socket_pool_queue (Worker.Dispatcher, result);
728 return; // Have to finish writing everything. See bug #74475.
730 result.Total = send_so_far;
731 } catch (Exception e) {
740 public void SendGeneric ()
744 total = result.Sock.Send (result.Buffers, result.SockFlags);
745 } catch (Exception e) {
749 result.Complete (total);
753 private Queue readQ = new Queue (2);
754 private Queue writeQ = new Queue (2);
756 internal delegate void SocketAsyncCall (SocketAsyncResult sar);
759 * These two fields are looked up by name by the runtime, don't change
760 * their name without also updating the runtime code.
762 private static int ipv4Supported = -1, ipv6Supported = -1;
767 // initialize ipv4Supported and ipv6Supported
768 CheckProtocolSupport ();
771 internal static void CheckProtocolSupport ()
773 if(ipv4Supported == -1) {
775 Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
784 if (ipv6Supported == -1) {
786 #if CONFIGURATION_DEP
787 SettingsSection config;
788 config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
790 ipv6Supported = config.Ipv6.Enabled ? -1 : 0;
792 NetConfig config = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig;
794 ipv6Supported = config.ipv6Enabled ? -1 : 0;
797 if (ipv6Supported != 0) {
799 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
810 public static bool SupportsIPv4 {
812 CheckProtocolSupport();
813 return ipv4Supported == 1;
817 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
818 public static bool SupportsIPv6 {
820 CheckProtocolSupport();
821 return ipv6Supported == 1;
825 public static bool OSSupportsIPv4 {
827 CheckProtocolSupport();
828 return ipv4Supported == 1;
833 public static bool OSSupportsIPv6 {
835 CheckProtocolSupport();
836 return ipv6Supported == 1;
840 public static bool OSSupportsIPv6 {
842 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
844 foreach (NetworkInterface adapter in nics) {
845 if (adapter.Supports (NetworkInterfaceComponent.IPv6))
853 /* the field "socket" is looked up by name by the runtime */
854 private IntPtr socket;
855 private AddressFamily address_family;
856 private SocketType socket_type;
857 private ProtocolType protocol_type;
858 internal bool blocking=true;
859 Thread blocking_thread;
860 private bool isbound;
861 /* When true, the socket was connected at the time of
862 * the last IO operation
864 private bool connected;
865 /* true if we called Close_internal */
867 internal bool disposed;
870 * This EndPoint is used when creating new endpoints. Because
871 * there are many types of EndPoints possible,
872 * seed_endpoint.Create(addr) is used for creating new ones.
873 * As such, this value is set on Bind, SentTo, ReceiveFrom,
876 internal EndPoint seed_endpoint = null;
879 // Creates a new system socket, returning the handle
880 [MethodImplAttribute(MethodImplOptions.InternalCall)]
881 private extern IntPtr Socket_internal(AddressFamily family,
887 public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
889 #if NET_2_1 && !MOBILE
890 switch (addressFamily) {
891 case AddressFamily.InterNetwork: // ok
892 case AddressFamily.InterNetworkV6: // ok
893 case AddressFamily.Unknown: // SocketException will be thrown later (with right error #)
895 // case AddressFamily.Unspecified:
897 throw new ArgumentException ("addressFamily");
900 switch (socketType) {
901 case SocketType.Stream: // ok
902 case SocketType.Unknown: // SocketException will be thrown later (with right error #)
905 throw new ArgumentException ("socketType");
908 switch (protocolType) {
909 case ProtocolType.Tcp: // ok
910 case ProtocolType.Unspecified: // ok
911 case ProtocolType.Unknown: // SocketException will be thrown later (with right error #)
914 throw new ArgumentException ("protocolType");
917 address_family = addressFamily;
918 socket_type = socketType;
919 protocol_type = protocolType;
923 socket = Socket_internal (addressFamily, socketType, protocolType, out error);
925 throw new SocketException (error);
926 #if !NET_2_1 || MOBILE
937 public AddressFamily AddressFamily {
938 get { return address_family; }
942 [MethodImplAttribute(MethodImplOptions.InternalCall)]
943 private extern static void Blocking_internal(IntPtr socket,
948 public bool Blocking {
953 if (disposed && closed)
954 throw new ObjectDisposedException (GetType ().ToString ());
958 Blocking_internal (socket, value, out error);
961 throw new SocketException (error);
967 public bool Connected {
968 get { return connected; }
969 internal set { connected = value; }
972 public ProtocolType ProtocolType {
973 get { return protocol_type; }
976 public bool NoDelay {
978 if (disposed && closed)
979 throw new ObjectDisposedException (GetType ().ToString ());
983 return (int)(GetSocketOption (
984 SocketOptionLevel.Tcp,
985 SocketOptionName.NoDelay)) != 0;
989 if (disposed && closed)
990 throw new ObjectDisposedException (GetType ().ToString ());
995 SocketOptionLevel.Tcp,
996 SocketOptionName.NoDelay, value ? 1 : 0);
1000 public int ReceiveBufferSize {
1002 if (disposed && closed) {
1003 throw new ObjectDisposedException (GetType ().ToString ());
1005 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer));
1008 if (disposed && closed) {
1009 throw new ObjectDisposedException (GetType ().ToString ());
1012 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
1015 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
1019 public int SendBufferSize {
1021 if (disposed && closed) {
1022 throw new ObjectDisposedException (GetType ().ToString ());
1024 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer));
1027 if (disposed && closed) {
1028 throw new ObjectDisposedException (GetType ().ToString ());
1031 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
1034 SetSocketOption (SocketOptionLevel.Socket,
1035 SocketOptionName.SendBuffer,
1042 if (disposed && closed) {
1043 throw new ObjectDisposedException (GetType ().ToString ());
1048 if (address_family == AddressFamily.InterNetwork) {
1049 ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive));
1050 } else if (address_family == AddressFamily.InterNetworkV6) {
1051 ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit));
1053 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
1059 if (disposed && closed) {
1060 throw new ObjectDisposedException (GetType ().ToString ());
1063 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
1066 if (address_family == AddressFamily.InterNetwork) {
1067 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
1068 } else if (address_family == AddressFamily.InterNetworkV6) {
1069 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
1071 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
1076 // Returns the remote endpoint details in addr and port
1077 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1078 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket, int family, out int error);
1080 public EndPoint RemoteEndPoint {
1082 if (disposed && closed)
1083 throw new ObjectDisposedException (GetType ().ToString ());
1087 return seed_endpoint;
1090 * If the seed EndPoint is null, Connect, Bind,
1091 * etc has not yet been called. MS returns null
1094 if (!connected || seed_endpoint == null)
1100 sa=RemoteEndPoint_internal(socket, (int) address_family, out error);
1103 throw new SocketException (error);
1105 return seed_endpoint.Create (sa);
1109 void Linger (IntPtr handle)
1111 if (!connected || linger_timeout <= 0)
1114 // We don't want to receive any more data
1116 Shutdown_internal (handle, SocketShutdown.Receive, out error);
1120 int seconds = linger_timeout / 1000;
1121 int ms = linger_timeout % 1000;
1123 // If the other end closes, this will return 'true' with 'Available' == 0
1124 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
1130 LingerOption linger = new LingerOption (true, seconds);
1131 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
1132 /* Not needed, we're closing upon return */
1138 protected virtual void Dispose (bool disposing)
1144 bool was_connected = connected;
1146 if ((int) socket != -1) {
1150 socket = (IntPtr) (-1);
1151 Thread th = blocking_thread;
1154 blocking_thread = null;
1159 //DateTime start = DateTime.UtcNow;
1160 Close_internal (x, out error);
1161 //Console.WriteLine ("Time spent in Close_internal: {0}ms", (DateTime.UtcNow - start).TotalMilliseconds);
1163 throw new SocketException (error);
1167 #if NET_2_1 || NET_4_0
1168 public void Dispose ()
1170 void IDisposable.Dispose ()
1174 GC.SuppressFinalize (this);
1177 // Closes the socket
1178 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1179 private extern static void Close_internal(IntPtr socket, out int error);
1181 public void Close ()
1184 ((IDisposable) this).Dispose ();
1187 public void Close (int timeout)
1189 linger_timeout = timeout;
1190 ((IDisposable) this).Dispose ();
1193 // Connects to the remote address
1194 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1195 private extern static void Connect_internal(IntPtr sock,
1199 public void Connect (EndPoint remoteEP)
1201 SocketAddress serial = null;
1203 if (disposed && closed)
1204 throw new ObjectDisposedException (GetType ().ToString ());
1206 if (remoteEP == null)
1207 throw new ArgumentNullException ("remoteEP");
1209 IPEndPoint ep = remoteEP as IPEndPoint;
1211 if (ep != null && socket_type != SocketType.Dgram) /* Dgram uses Any to 'disconnect' */
1215 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1216 throw new SocketException ((int) SocketError.AddressNotAvailable);
1219 if (protocol_type != ProtocolType.Tcp)
1220 throw new SocketException ((int) SocketError.AccessDenied);
1223 throw new InvalidOperationException ();
1225 serial = remoteEP.Serialize ();
1229 blocking_thread = Thread.CurrentThread;
1231 Connect_internal (socket, serial, out error);
1232 } catch (ThreadAbortException) {
1234 Thread.ResetAbort ();
1235 error = (int) SocketError.Interrupted;
1238 blocking_thread = null;
1241 if (error == 0 || error == 10035)
1242 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1245 throw new SocketException (error);
1248 if (socket_type == SocketType.Dgram && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)))
1258 public bool ReceiveAsync (SocketAsyncEventArgs e)
1260 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1261 if (disposed && closed)
1262 throw new ObjectDisposedException (GetType ().ToString ());
1264 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1265 // thrown when e.Buffer and e.BufferList are null (works fine when one is
1266 // set to a valid object)
1267 if (e.Buffer == null && e.BufferList == null)
1268 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1271 SocketOperation op = (e.Buffer != null) ? SocketOperation.Receive : SocketOperation.ReceiveGeneric;
1272 e.Worker.Init (this, e, op);
1273 SocketAsyncResult res = e.Worker.result;
1274 if (e.Buffer != null) {
1275 res.Buffer = e.Buffer;
1276 res.Offset = e.Offset;
1279 res.Buffers = e.BufferList;
1281 res.SockFlags = e.SocketFlags;
1284 readQ.Enqueue (e.Worker);
1285 count = readQ.Count;
1288 // Receive takes care of ReceiveGeneric
1289 socket_pool_queue (Worker.Dispatcher, res);
1295 public bool SendAsync (SocketAsyncEventArgs e)
1297 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1298 if (disposed && closed)
1299 throw new ObjectDisposedException (GetType ().ToString ());
1300 if (e.Buffer == null && e.BufferList == null)
1301 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1304 SocketOperation op = (e.Buffer != null) ? SocketOperation.Send : SocketOperation.SendGeneric;
1305 e.Worker.Init (this, e, op);
1306 SocketAsyncResult res = e.Worker.result;
1307 if (e.Buffer != null) {
1308 res.Buffer = e.Buffer;
1309 res.Offset = e.Offset;
1312 res.Buffers = e.BufferList;
1314 res.SockFlags = e.SocketFlags;
1317 writeQ.Enqueue (e.Worker);
1318 count = writeQ.Count;
1321 // Send takes care of SendGeneric
1322 socket_pool_queue (Worker.Dispatcher, res);
1327 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1328 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
1330 /* This overload is needed as the async Connect method
1331 * also needs to check the socket error status, but
1332 * getsockopt(..., SO_ERROR) clears the error.
1334 internal bool Poll (int time_us, SelectMode mode, out int socket_error)
1336 if (disposed && closed)
1337 throw new ObjectDisposedException (GetType ().ToString ());
1339 if (mode != SelectMode.SelectRead &&
1340 mode != SelectMode.SelectWrite &&
1341 mode != SelectMode.SelectError)
1342 throw new NotSupportedException ("'mode' parameter is not valid.");
1345 bool result = Poll_internal (socket, mode, time_us, out error);
1347 throw new SocketException (error);
1349 socket_error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1351 if (mode == SelectMode.SelectWrite && result) {
1352 /* Update the connected state; for
1353 * non-blocking Connect()s this is
1354 * when we can find out that the
1355 * connect succeeded.
1357 if (socket_error == 0) {
1366 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1367 private extern static int Receive_internal(IntPtr sock,
1374 internal int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
1377 int ret = Receive_internal (socket, buf, offset, size, flags, out nativeError);
1378 error = (SocketError) nativeError;
1379 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
1389 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1390 private extern static void GetSocketOption_obj_internal(IntPtr socket,
1391 SocketOptionLevel level, SocketOptionName name, out object obj_val,
1394 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1395 private extern static int Send_internal(IntPtr sock,
1396 byte[] buf, int offset,
1401 internal int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
1404 error = SocketError.Success;
1410 int ret = Send_internal (socket, buf, offset, size, flags, out nativeError);
1412 error = (SocketError)nativeError;
1414 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
1424 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
1426 if (disposed && closed)
1427 throw new ObjectDisposedException (GetType ().ToString ());
1432 GetSocketOption_obj_internal (socket, optionLevel, optionName, out obj_val,
1435 throw new SocketException (error);
1437 if (optionName == SocketOptionName.Linger) {
1438 return((LingerOption)obj_val);
1439 } else if (optionName == SocketOptionName.AddMembership ||
1440 optionName == SocketOptionName.DropMembership) {
1441 return((MulticastOption)obj_val);
1442 } else if (obj_val is int) {
1443 return((int)obj_val);
1449 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1450 private extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
1452 public void Shutdown (SocketShutdown how)
1454 if (disposed && closed)
1455 throw new ObjectDisposedException (GetType ().ToString ());
1458 throw new SocketException (10057); // Not connected
1462 Shutdown_internal (socket, how, out error);
1464 throw new SocketException (error);
1467 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1468 private extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level,
1469 SocketOptionName name, object obj_val,
1470 byte [] byte_val, int int_val,
1473 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
1475 if (disposed && closed)
1476 throw new ObjectDisposedException (GetType ().ToString ());
1480 SetSocketOption_internal (socket, optionLevel, optionName, null,
1481 null, optionValue, out error);
1484 throw new SocketException (error);
1487 private void ThrowIfUpd ()
1489 #if !NET_2_1 || MOBILE
1490 if (protocol_type == ProtocolType.Udp)
1491 throw new SocketException ((int)SocketError.ProtocolOption);
1498 IAsyncResult BeginConnect(EndPoint end_point, AsyncCallback callback, object state)
1500 if (disposed && closed)
1501 throw new ObjectDisposedException (GetType ().ToString ());
1503 if (end_point == null)
1504 throw new ArgumentNullException ("end_point");
1506 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Connect);
1507 req.EndPoint = end_point;
1509 // Bug #75154: Connect() should not succeed for .Any addresses.
1510 if (end_point is IPEndPoint) {
1511 IPEndPoint ep = (IPEndPoint) end_point;
1512 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1513 req.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1519 bool blk = blocking;
1522 SocketAddress serial = end_point.Serialize ();
1523 Connect_internal (socket, serial, out error);
1529 req.Complete (true);
1533 if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1536 req.Complete (new SocketException (error), true);
1542 socket_pool_queue (Worker.Dispatcher, req);
1551 IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1554 if (disposed && closed)
1555 throw new ObjectDisposedException (GetType ().ToString ());
1557 if (addresses == null)
1558 throw new ArgumentNullException ("addresses");
1560 if (addresses.Length == 0)
1561 throw new ArgumentException ("Empty addresses list");
1563 if (this.AddressFamily != AddressFamily.InterNetwork &&
1564 this.AddressFamily != AddressFamily.InterNetworkV6)
1565 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1567 if (port <= 0 || port > 65535)
1568 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1571 throw new InvalidOperationException ();
1574 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Connect);
1575 req.Addresses = addresses;
1578 return BeginMConnect (req);
1581 IAsyncResult BeginMConnect (SocketAsyncResult req)
1583 IAsyncResult ares = null;
1584 Exception exc = null;
1585 for (int i = req.CurrentAddress; i < req.Addresses.Length; i++) {
1586 IPAddress addr = req.Addresses [i];
1587 IPEndPoint ep = new IPEndPoint (addr, req.Port);
1589 req.CurrentAddress++;
1590 ares = BeginConnect (ep, null, req);
1591 if (ares.IsCompleted && ares.CompletedSynchronously) {
1592 ((SocketAsyncResult) ares).CheckIfThrowDelayedException ();
1593 req.DoMConnectCallback ();
1596 } catch (Exception e) {
1607 // Returns false when it is ok to use RemoteEndPoint
1608 // true when addresses must be used (and addresses could be null/empty)
1609 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1612 #if MOONLIGHT || NET_4_0
1613 // Connect to the first address that match the host name, like:
1614 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1615 // while skipping entries that do not match the address family
1616 DnsEndPoint dep = (RemoteEndPoint as DnsEndPoint);
1618 addresses = Dns.GetHostAddresses (dep.Host);
1619 IPEndPoint endpoint;
1620 #if MOONLIGHT && !INSIDE_SYSTEM
1621 if (!e.PolicyRestricted && !SecurityManager.HasElevatedPermissions) {
1622 List<IPAddress> valid = new List<IPAddress> ();
1623 foreach (IPAddress a in addresses) {
1624 // if we're not downloading a socket policy then check the policy
1625 // and if we're not running with elevated permissions (SL4 OoB option)
1626 endpoint = new IPEndPoint (a, dep.Port);
1627 if (!CrossDomainPolicyManager.CheckEndPoint (endpoint, e.SocketClientAccessPolicyProtocol))
1631 addresses = valid.ToArray ();
1636 e.ConnectByNameError = null;
1637 #if MOONLIGHT && !INSIDE_SYSTEM
1638 if (!e.PolicyRestricted && !SecurityManager.HasElevatedPermissions) {
1639 if (CrossDomainPolicyManager.CheckEndPoint (RemoteEndPoint, e.SocketClientAccessPolicyProtocol))
1645 return true; // do not use remote endpoint
1647 return false; // < NET_4_0 -> use remote endpoint
1651 bool ConnectAsyncReal (SocketAsyncEventArgs e)
1653 IPAddress [] addresses = null;
1654 bool use_remoteep = true;
1655 #if MOONLIGHT || NET_4_0
1656 use_remoteep = !GetCheckedIPs (e, out addresses);
1659 Worker w = e.Worker;
1660 w.Init (this, e, SocketOperation.Connect);
1661 SocketAsyncResult result = w.result;
1662 IAsyncResult ares = null;
1665 result.EndPoint = e.RemoteEndPoint;
1666 ares = BeginConnect (e.RemoteEndPoint, SocketAsyncEventArgs.Dispatcher, e);
1668 #if MOONLIGHT || NET_4_0
1671 DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1672 result.Addresses = addresses;
1673 result.Port = dep.Port;
1675 ares = BeginConnect (addresses, dep.Port, SocketAsyncEventArgs.Dispatcher, e);
1678 if (ares.IsCompleted && ares.CompletedSynchronously) {
1679 ((SocketAsyncResult) ares).CheckIfThrowDelayedException ();
1682 } catch (Exception exc) {
1683 result.Complete (exc, true);
1690 public bool ConnectAsync (SocketAsyncEventArgs e)
1692 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1693 if (disposed && closed)
1694 throw new ObjectDisposedException (GetType ().ToString ());
1696 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1697 if (e.RemoteEndPoint == null)
1698 throw new ArgumentNullException ("remoteEP");
1700 return ConnectAsyncReal (e);
1704 static void CheckConnect (SocketAsyncEventArgs e)
1706 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1708 if (e.RemoteEndPoint == null)
1709 throw new ArgumentNullException ("remoteEP");
1710 if (e.BufferList != null)
1711 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
1714 public bool ConnectAsync (SocketAsyncEventArgs e)
1716 if (disposed && closed)
1717 throw new ObjectDisposedException (GetType ().ToString ());
1720 // if an address family is specified then they must match
1721 AddressFamily raf = e.RemoteEndPoint.AddressFamily;
1722 if ((raf != AddressFamily.Unspecified) && (raf != AddressFamily))
1723 throw new NotSupportedException ("AddressFamily mismatch between socket and endpoint");
1725 return ConnectAsyncReal (e);
1728 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
1730 // exception ordering requires to check before creating the socket (good thing resource wise too)
1733 // create socket based on the endpoint address family (if specified), otherwise default fo IPv4
1734 AddressFamily raf = e.RemoteEndPoint.AddressFamily;
1735 if (raf == AddressFamily.Unspecified)
1736 raf = AddressFamily.InterNetwork;
1737 Socket s = new Socket (raf, socketType, protocolType);
1738 return s.ConnectAsyncReal (e);
1741 public static void CancelConnectAsync (SocketAsyncEventArgs e)
1744 throw new ArgumentNullException ("e");
1746 // FIXME: this is canceling a synchronous connect, not an async one
1747 Socket s = e.ConnectSocket;
1748 if ((s != null) && (s.blocking_thread != null))
1749 s.blocking_thread.Abort ();
1752 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1753 private extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
1759 int Receive (IList<ArraySegment<byte>> buffers)
1763 ret = Receive (buffers, SocketFlags.None, out error);
1764 if (error != SocketError.Success) {
1765 throw new SocketException ((int)error);
1770 [CLSCompliant (false)]
1776 int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1780 ret = Receive (buffers, socketFlags, out error);
1781 if (error != SocketError.Success) {
1782 throw new SocketException ((int)error);
1787 [CLSCompliant (false)]
1793 int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1795 if (disposed && closed)
1796 throw new ObjectDisposedException (GetType ().ToString ());
1798 if (buffers == null ||
1799 buffers.Count == 0) {
1800 throw new ArgumentNullException ("buffers");
1803 int numsegments = buffers.Count;
1807 /* Only example I can find of sending a byte
1808 * array reference directly into an internal
1810 * System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1811 * so taking a lead from that...
1813 WSABUF[] bufarray = new WSABUF[numsegments];
1814 GCHandle[] gch = new GCHandle[numsegments];
1816 for(int i = 0; i < numsegments; i++) {
1817 ArraySegment<byte> segment = buffers[i];
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 = Receive_internal (socket, bufarray,
1828 for(int i = 0; i < numsegments; i++) {
1829 if (gch[i].IsAllocated) {
1835 errorCode = (SocketError)nativeError;
1839 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1840 private extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
1846 int Send (IList<ArraySegment<byte>> buffers)
1850 ret = Send (buffers, SocketFlags.None, out error);
1851 if (error != SocketError.Success) {
1852 throw new SocketException ((int)error);
1862 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1866 ret = Send (buffers, socketFlags, out error);
1867 if (error != SocketError.Success) {
1868 throw new SocketException ((int)error);
1873 [CLSCompliant (false)]
1879 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1881 if (disposed && closed)
1882 throw new ObjectDisposedException (GetType ().ToString ());
1883 if (buffers == null)
1884 throw new ArgumentNullException ("buffers");
1885 if (buffers.Count == 0)
1886 throw new ArgumentException ("Buffer is empty", "buffers");
1887 int numsegments = buffers.Count;
1891 WSABUF[] bufarray = new WSABUF[numsegments];
1892 GCHandle[] gch = new GCHandle[numsegments];
1893 for(int i = 0; i < numsegments; i++) {
1894 ArraySegment<byte> segment = buffers[i];
1895 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1896 bufarray[i].len = segment.Count;
1897 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1901 ret = Send_internal (socket, bufarray, socketFlags, out nativeError);
1903 for(int i = 0; i < numsegments; i++) {
1904 if (gch[i].IsAllocated) {
1909 errorCode = (SocketError)nativeError;
1913 Exception InvalidAsyncOp (string method)
1915 return new InvalidOperationException (method + " can only be called once per asynchronous operation");
1923 int EndReceive (IAsyncResult result)
1926 int bytesReceived = EndReceive (result, out error);
1927 if (error != SocketError.Success) {
1928 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
1930 throw new SocketException ((int)error);
1932 return bytesReceived;
1940 int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
1942 if (disposed && closed)
1943 throw new ObjectDisposedException (GetType ().ToString ());
1945 if (asyncResult == null)
1946 throw new ArgumentNullException ("asyncResult");
1948 SocketAsyncResult req = asyncResult as SocketAsyncResult;
1950 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
1952 if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1953 throw InvalidAsyncOp ("EndReceive");
1954 if (!asyncResult.IsCompleted)
1955 asyncResult.AsyncWaitHandle.WaitOne ();
1957 errorCode = req.ErrorCode;
1958 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
1959 // kinds of exceptions that should be thrown.
1960 if (errorCode == SocketError.Success)
1961 req.CheckIfThrowDelayedException();
1971 int EndSend (IAsyncResult result)
1974 int bytesSent = EndSend (result, out error);
1975 if (error != SocketError.Success) {
1976 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
1978 throw new SocketException ((int)error);
1988 int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
1990 if (disposed && closed)
1991 throw new ObjectDisposedException (GetType ().ToString ());
1992 if (asyncResult == null)
1993 throw new ArgumentNullException ("asyncResult");
1995 SocketAsyncResult req = asyncResult as SocketAsyncResult;
1997 throw new ArgumentException ("Invalid IAsyncResult", "result");
1999 if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
2000 throw InvalidAsyncOp ("EndSend");
2001 if (!asyncResult.IsCompleted)
2002 asyncResult.AsyncWaitHandle.WaitOne ();
2004 errorCode = req.ErrorCode;
2005 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
2006 // kinds of exceptions that should be thrown.
2007 if (errorCode == SocketError.Success)
2008 req.CheckIfThrowDelayedException ();
2013 // Used by Udpclient
2019 int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
2021 if (disposed && closed)
2022 throw new ObjectDisposedException (GetType ().ToString ());
2025 throw new ArgumentNullException ("result");
2027 if (end_point == null)
2028 throw new ArgumentNullException ("remote_end");
2030 SocketAsyncResult req = result as SocketAsyncResult;
2032 throw new ArgumentException ("Invalid IAsyncResult", "result");
2034 if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
2035 throw InvalidAsyncOp ("EndReceiveFrom");
2036 if (!result.IsCompleted)
2037 result.AsyncWaitHandle.WaitOne();
2039 req.CheckIfThrowDelayedException();
2040 end_point = req.EndPoint;
2044 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2045 static extern void socket_pool_queue (SocketAsyncCall d, SocketAsyncResult r);