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;
52 namespace System.Net.Sockets {
54 public partial class Socket : IDisposable {
55 [StructLayout (LayoutKind.Sequential)]
61 // Used by the runtime
62 internal enum SocketOperation {
79 [StructLayout (LayoutKind.Sequential)]
80 internal sealed class SocketAsyncResult: IAsyncResult
82 /* Same structure in the runtime */
84 Keep this in sync with MonoSocketAsyncResult in
85 metadata/socket-io.h and ProcessAsyncReader
86 in System.Diagnostics/Process.cs.
92 AsyncCallback callback; // used from the runtime
93 WaitHandle waithandle;
95 Exception delayedException;
97 public EndPoint EndPoint; // Connect,ReceiveFrom,SendTo
98 public byte [] Buffer; // Receive,ReceiveFrom,Send,SendTo
99 public int Offset; // Receive,ReceiveFrom,Send,SendTo
100 public int Size; // Receive,ReceiveFrom,Send,SendTo
101 public SocketFlags SockFlags; // Receive,ReceiveFrom,Send,SendTo
102 public Socket AcceptSocket; // AcceptReceive
103 public IPAddress[] Addresses; // Connect
104 public int Port; // Connect
105 public IList<ArraySegment<byte>> Buffers; // Receive, Send
106 public bool ReuseSocket; // Disconnect
114 public bool blocking;
116 public SocketOperation operation;
118 public int EndCalled;
120 // These fields are not in MonoSocketAsyncResult
121 public Worker Worker;
122 public int CurrentAddress; // Connect
124 public SocketAsyncResult ()
128 public void Init (Socket sock, object state, AsyncCallback callback, SocketOperation operation)
132 this.blocking = sock.blocking;
133 this.handle = sock.socket;
135 this.blocking = true;
136 this.handle = IntPtr.Zero;
139 this.callback = callback;
140 GC.KeepAlive (this.callback);
141 this.operation = operation;
142 SockFlags = SocketFlags.None;
143 if (waithandle != null)
144 ((ManualResetEvent) waithandle).Reset ();
146 delayedException = null;
161 completed_sync = false;
170 public void DoMConnectCallback ()
172 if (callback == null)
174 ThreadPool.UnsafeQueueUserWorkItem (_ => { callback (this); }, null);
177 public void Dispose ()
179 Init (null, null, null, 0);
180 if (waithandle != null) {
186 public SocketAsyncResult (Socket sock, object state, AsyncCallback callback, SocketOperation operation)
189 this.blocking = sock.blocking;
190 this.handle = sock.socket;
192 this.callback = callback;
193 GC.KeepAlive (this.callback);
194 this.operation = operation;
195 SockFlags = SocketFlags.None;
196 Worker = new Worker (this);
199 public void CheckIfThrowDelayedException ()
201 if (delayedException != null) {
202 Sock.connected = false;
203 throw delayedException;
207 Sock.connected = false;
208 throw new SocketException (error);
212 void CompleteAllOnDispose (Queue queue)
214 object [] pending = queue.ToArray ();
218 for (int i = 0; i < pending.Length; i++) {
219 Worker worker = (Worker) pending [i];
220 SocketAsyncResult ares = worker.result;
221 cb = new WaitCallback (ares.CompleteDisposed);
222 ThreadPool.UnsafeQueueUserWorkItem (cb, null);
226 void CompleteDisposed (object unused)
231 public void Complete ()
233 if (operation != SocketOperation.Receive && Sock.disposed)
234 delayedException = new ObjectDisposedException (Sock.GetType ().ToString ());
239 if (operation == SocketOperation.Receive ||
240 operation == SocketOperation.ReceiveFrom ||
241 operation == SocketOperation.ReceiveGeneric ||
242 operation == SocketOperation.Accept) {
244 } else if (operation == SocketOperation.Send ||
245 operation == SocketOperation.SendTo ||
246 operation == SocketOperation.SendGeneric) {
252 Worker worker = null;
253 SocketAsyncCall sac = null;
255 // queue.Count will only be 0 if the socket is closed while receive/send/accept
256 // operation(s) are pending and at least one call to this method is
257 // waiting on the lock while another one calls CompleteAllOnDispose()
259 queue.Dequeue (); // remove ourselves
260 if (queue.Count > 0) {
261 worker = (Worker) queue.Peek ();
262 if (!Sock.disposed) {
263 sac = Worker.Dispatcher;
265 CompleteAllOnDispose (queue);
271 Socket.socket_pool_queue (sac, worker.result);
273 // IMPORTANT: 'callback', if any is scheduled from unmanaged code
276 public void Complete (bool synch)
278 completed_sync = synch;
282 public void Complete (int total)
288 public void Complete (Exception e, bool synch)
290 completed_sync = synch;
291 delayedException = e;
295 public void Complete (Exception e)
297 delayedException = e;
301 public void Complete (Socket s)
307 public void Complete (Socket s, int total)
314 public object AsyncState {
320 public WaitHandle AsyncWaitHandle {
323 if (waithandle == null)
324 waithandle = new ManualResetEvent (completed);
334 public bool CompletedSynchronously {
336 return(completed_sync);
340 public bool IsCompleted {
347 if (waithandle != null && value) {
348 ((ManualResetEvent) waithandle).Set ();
354 public Socket Socket {
361 get { return total; }
362 set { total = value; }
365 public SocketError ErrorCode {
367 SocketException ex = delayedException as SocketException;
369 return(ex.SocketErrorCode);
372 return((SocketError)error);
374 return(SocketError.Success);
379 internal sealed class Worker
381 public SocketAsyncResult result;
382 SocketAsyncEventArgs args;
384 public Worker (SocketAsyncEventArgs args)
387 result = new SocketAsyncResult ();
388 result.Worker = this;
391 public Worker (SocketAsyncResult ares)
396 public void Dispose ()
398 if (result != null) {
405 public static SocketAsyncCall Dispatcher = new SocketAsyncCall (DispatcherCB);
407 static void DispatcherCB (SocketAsyncResult sar)
409 SocketOperation op = sar.operation;
410 if (op == Socket.SocketOperation.Receive || op == Socket.SocketOperation.ReceiveGeneric ||
411 op == Socket.SocketOperation.RecvJustCallback)
412 sar.Worker.Receive ();
413 else if (op == Socket.SocketOperation.Send || op == Socket.SocketOperation.SendGeneric ||
414 op == Socket.SocketOperation.SendJustCallback)
416 else if (op == Socket.SocketOperation.ReceiveFrom)
417 sar.Worker.ReceiveFrom ();
418 else if (op == Socket.SocketOperation.SendTo)
419 sar.Worker.SendTo ();
420 else if (op == Socket.SocketOperation.Connect)
421 sar.Worker.Connect ();
422 else if (op == Socket.SocketOperation.Accept)
423 sar.Worker.Accept ();
424 else if (op == Socket.SocketOperation.AcceptReceive)
425 sar.Worker.AcceptReceive ();
426 else if (op == Socket.SocketOperation.Disconnect)
427 sar.Worker.Disconnect ();
429 // SendPackets and ReceiveMessageFrom are not implemented yet
431 else if (op == Socket.SocketOperation.ReceiveMessageFrom)
432 async_op = SocketAsyncOperation.ReceiveMessageFrom;
433 else if (op == Socket.SocketOperation.SendPackets)
434 async_op = SocketAsyncOperation.SendPackets;
437 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
440 /* This is called when reusing a SocketAsyncEventArgs */
441 public void Init (Socket sock, SocketAsyncEventArgs args, SocketOperation op)
443 result.Init (sock, args, SocketAsyncEventArgs.Dispatcher, op);
444 result.Worker = this;
445 SocketAsyncOperation async_op;
448 // -SocketOperation.AcceptReceive not used in SocketAsyncEventArgs
449 // -SendPackets and ReceiveMessageFrom are not implemented yet
450 if (op == Socket.SocketOperation.Connect)
451 async_op = SocketAsyncOperation.Connect;
452 else if (op == Socket.SocketOperation.Accept)
453 async_op = SocketAsyncOperation.Accept;
454 else if (op == Socket.SocketOperation.Disconnect)
455 async_op = SocketAsyncOperation.Disconnect;
456 else if (op == Socket.SocketOperation.Receive || op == Socket.SocketOperation.ReceiveGeneric)
457 async_op = SocketAsyncOperation.Receive;
458 else if (op == Socket.SocketOperation.ReceiveFrom)
459 async_op = SocketAsyncOperation.ReceiveFrom;
461 else if (op == Socket.SocketOperation.ReceiveMessageFrom)
462 async_op = SocketAsyncOperation.ReceiveMessageFrom;
464 else if (op == Socket.SocketOperation.Send || op == Socket.SocketOperation.SendGeneric)
465 async_op = SocketAsyncOperation.Send;
467 else if (op == Socket.SocketOperation.SendPackets)
468 async_op = SocketAsyncOperation.SendPackets;
470 else if (op == Socket.SocketOperation.SendTo)
471 async_op = SocketAsyncOperation.SendTo;
473 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
475 args.SetLastOperation (async_op);
476 args.SocketError = SocketError.Success;
477 args.BytesTransferred = 0;
480 public void Accept ()
482 Socket acc_socket = null;
484 if (args != null && args.AcceptSocket != null) {
485 result.Sock.Accept (args.AcceptSocket);
486 acc_socket = args.AcceptSocket;
488 acc_socket = result.Sock.Accept ();
490 args.AcceptSocket = acc_socket;
492 } catch (Exception e) {
497 result.Complete (acc_socket);
500 /* only used in 2.0 profile and newer, but
501 * leave in older profiles to keep interface
502 * to runtime consistent
504 public void AcceptReceive ()
506 Socket acc_socket = null;
508 if (result.AcceptSocket == null) {
509 acc_socket = result.Sock.Accept ();
511 acc_socket = result.AcceptSocket;
512 result.Sock.Accept (acc_socket);
514 } catch (Exception e) {
519 /* It seems the MS runtime
520 * special-cases 0-length requested
521 * receive data. See bug 464201.
524 if (result.Size > 0) {
527 total = acc_socket.Receive_nochecks (result.Buffer,
533 result.Complete (new SocketException ((int) error));
536 } catch (Exception e) {
542 result.Complete (acc_socket, total);
545 public void Connect ()
547 if (result.EndPoint == null) {
548 result.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
552 SocketAsyncResult mconnect = result.AsyncState as SocketAsyncResult;
553 bool is_mconnect = (mconnect != null && mconnect.Addresses != null);
556 EndPoint ep = result.EndPoint;
557 error_code = (int) result.Sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
558 if (error_code == 0) {
561 result.Sock.seed_endpoint = ep;
562 result.Sock.connected = true;
563 result.Sock.isbound = true;
564 result.Sock.connect_in_progress = false;
568 result.DoMConnectCallback ();
573 result.Sock.connect_in_progress = false;
574 result.Complete (new SocketException (error_code));
578 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
579 mconnect.Complete (new SocketException (error_code));
581 mconnect.DoMConnectCallback ();
584 mconnect.Sock.BeginMConnect (mconnect);
585 } catch (Exception e) {
586 result.Sock.connect_in_progress = false;
591 result.DoMConnectCallback ();
596 /* Also only used in 2.0 profile and newer */
597 public void Disconnect ()
601 result.ReuseSocket = args.DisconnectReuseSocket;
602 result.Sock.Disconnect (result.ReuseSocket);
603 } catch (Exception e) {
610 public void Receive ()
612 if (result.operation == SocketOperation.ReceiveGeneric) {
616 // Actual recv() done in the runtime
620 public void ReceiveFrom ()
624 total = result.Sock.ReceiveFrom_nochecks (result.Buffer,
628 ref result.EndPoint);
629 } catch (Exception e) {
634 result.Complete (total);
637 public void ReceiveGeneric ()
641 total = result.Sock.Receive (result.Buffers, result.SockFlags);
642 } catch (Exception e) {
646 result.Complete (total);
651 void UpdateSendValues (int last_sent)
653 if (result.error == 0) {
654 send_so_far += last_sent;
655 result.Offset += last_sent;
656 result.Size -= last_sent;
662 if (result.operation == SocketOperation.SendGeneric) {
666 // Actual send() done in the runtime
667 if (result.error == 0) {
668 UpdateSendValues (result.Total);
669 if (result.Sock.disposed) {
674 if (result.Size > 0) {
675 Socket.socket_pool_queue (Worker.Dispatcher, result);
676 return; // Have to finish writing everything. See bug #74475.
678 result.Total = send_so_far;
684 public void SendTo ()
688 total = result.Sock.SendTo_nochecks (result.Buffer,
694 UpdateSendValues (total);
695 if (result.Size > 0) {
696 Socket.socket_pool_queue (Worker.Dispatcher, result);
697 return; // Have to finish writing everything. See bug #74475.
699 result.Total = send_so_far;
701 } catch (Exception e) {
710 public void SendGeneric ()
714 total = result.Sock.Send (result.Buffers, result.SockFlags);
715 } catch (Exception e) {
719 result.Complete (total);
723 private Queue readQ = new Queue (2);
724 private Queue writeQ = new Queue (2);
726 internal delegate void SocketAsyncCall (SocketAsyncResult sar);
729 * These two fields are looked up by name by the runtime, don't change
730 * their name without also updating the runtime code.
732 private static int ipv4Supported = -1, ipv6Supported = -1;
737 // initialize ipv4Supported and ipv6Supported
738 CheckProtocolSupport ();
741 internal static void CheckProtocolSupport ()
743 if(ipv4Supported == -1) {
745 Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
754 if (ipv6Supported == -1) {
755 // We need to put a try/catch around ConfigurationManager methods as will always throw an exception
756 // when run in a mono embedded application. This occurs as embedded applications do not have a setup
757 // for application config. The exception is not thrown when called from a normal .NET application.
759 // We, then, need to guard calls to the ConfigurationManager. If the config is not found or throws an
760 // exception, will fall through to the existing Socket / API directly below in the code.
762 // Also note that catching ConfigurationErrorsException specifically would require library dependency
763 // System.Configuration, and wanted to avoid that.
765 #if CONFIGURATION_DEP
767 SettingsSection config;
768 config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
770 ipv6Supported = config.Ipv6.Enabled ? -1 : 0;
776 NetConfig config = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig;
778 ipv6Supported = config.ipv6Enabled ? -1 : 0;
784 if (ipv6Supported != 0) {
786 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
797 public static bool SupportsIPv4 {
799 CheckProtocolSupport();
800 return ipv4Supported == 1;
804 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
805 public static bool SupportsIPv6 {
807 CheckProtocolSupport();
808 return ipv6Supported == 1;
812 public static bool OSSupportsIPv4 {
814 CheckProtocolSupport();
815 return ipv4Supported == 1;
820 public static bool OSSupportsIPv6 {
822 CheckProtocolSupport();
823 return ipv6Supported == 1;
827 public static bool OSSupportsIPv6 {
829 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
831 foreach (NetworkInterface adapter in nics) {
832 if (adapter.Supports (NetworkInterfaceComponent.IPv6))
840 /* the field "socket" is looked up by name by the runtime */
841 private IntPtr socket;
842 private AddressFamily address_family;
843 private SocketType socket_type;
844 private ProtocolType protocol_type;
845 internal bool blocking=true;
846 List<Thread> blocking_threads;
847 private bool isbound;
848 /* When true, the socket was connected at the time of
849 * the last IO operation
851 private bool connected;
852 /* true if we called Close_internal */
854 internal bool disposed;
855 bool connect_in_progress;
858 * This EndPoint is used when creating new endpoints. Because
859 * there are many types of EndPoints possible,
860 * seed_endpoint.Create(addr) is used for creating new ones.
861 * As such, this value is set on Bind, SentTo, ReceiveFrom,
864 internal EndPoint seed_endpoint = null;
866 void RegisterForBlockingSyscall ()
868 while (blocking_threads == null) {
869 //In the rare event this CAS fail, there's a good chance other thread won, so we're kosher.
870 //In the VERY rare event of all CAS fail together, we pay the full price of of failure.
871 Interlocked.CompareExchange (ref blocking_threads, new List<Thread> (), null);
877 /* We must use a finally block here to make this atomic. */
878 lock (blocking_threads) {
879 blocking_threads.Add (Thread.CurrentThread);
884 /* This must be called from a finally block! */
885 void UnRegisterForBlockingSyscall ()
887 //If this NRE, we're in deep problems because Register Must have
888 lock (blocking_threads) {
889 blocking_threads.Remove (Thread.CurrentThread);
893 void AbortRegisteredThreads () {
894 if (blocking_threads == null)
897 lock (blocking_threads) {
898 foreach (var t in blocking_threads)
899 cancel_blocking_socket_operation (t);
900 blocking_threads.Clear ();
904 // Creates a new system socket, returning the handle
905 [MethodImplAttribute(MethodImplOptions.InternalCall)]
906 private extern IntPtr Socket_internal(AddressFamily family,
911 public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
913 #if NET_2_1 && !MOBILE
914 switch (addressFamily) {
915 case AddressFamily.InterNetwork: // ok
916 case AddressFamily.InterNetworkV6: // ok
917 case AddressFamily.Unknown: // SocketException will be thrown later (with right error #)
919 // case AddressFamily.Unspecified:
921 throw new ArgumentException ("addressFamily");
924 switch (socketType) {
925 case SocketType.Stream: // ok
926 case SocketType.Unknown: // SocketException will be thrown later (with right error #)
929 throw new ArgumentException ("socketType");
932 switch (protocolType) {
933 case ProtocolType.Tcp: // ok
934 case ProtocolType.Unspecified: // ok
935 case ProtocolType.Unknown: // SocketException will be thrown later (with right error #)
938 throw new ArgumentException ("protocolType");
941 address_family = addressFamily;
942 socket_type = socketType;
943 protocol_type = protocolType;
947 socket = Socket_internal (addressFamily, socketType, protocolType, out error);
949 throw new SocketException (error);
950 #if !NET_2_1 || MOBILE
956 [MonoTODO ("Currently hardcoded to IPv4. Ideally, support v4/v6 dual-stack.")]
957 public Socket (SocketType socketType, ProtocolType protocolType)
958 : this (AddressFamily.InterNetwork, socketType, protocolType)
969 public AddressFamily AddressFamily {
970 get { return address_family; }
973 [MethodImplAttribute(MethodImplOptions.InternalCall)]
974 private extern static void Blocking_internal(IntPtr socket,
978 public bool Blocking {
983 if (disposed && closed)
984 throw new ObjectDisposedException (GetType ().ToString ());
988 Blocking_internal (socket, value, out error);
991 throw new SocketException (error);
997 public bool Connected {
998 get { return connected; }
999 internal set { connected = value; }
1002 public ProtocolType ProtocolType {
1003 get { return protocol_type; }
1006 public bool NoDelay {
1008 if (disposed && closed)
1009 throw new ObjectDisposedException (GetType ().ToString ());
1013 return (int)(GetSocketOption (
1014 SocketOptionLevel.Tcp,
1015 SocketOptionName.NoDelay)) != 0;
1019 if (disposed && closed)
1020 throw new ObjectDisposedException (GetType ().ToString ());
1025 SocketOptionLevel.Tcp,
1026 SocketOptionName.NoDelay, value ? 1 : 0);
1030 public int ReceiveBufferSize {
1032 if (disposed && closed) {
1033 throw new ObjectDisposedException (GetType ().ToString ());
1035 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer));
1038 if (disposed && closed) {
1039 throw new ObjectDisposedException (GetType ().ToString ());
1042 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
1045 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
1049 public int SendBufferSize {
1051 if (disposed && closed) {
1052 throw new ObjectDisposedException (GetType ().ToString ());
1054 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer));
1057 if (disposed && closed) {
1058 throw new ObjectDisposedException (GetType ().ToString ());
1061 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
1064 SetSocketOption (SocketOptionLevel.Socket,
1065 SocketOptionName.SendBuffer,
1072 if (disposed && closed) {
1073 throw new ObjectDisposedException (GetType ().ToString ());
1078 if (address_family == AddressFamily.InterNetwork) {
1079 ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive));
1080 } else if (address_family == AddressFamily.InterNetworkV6) {
1081 ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit));
1083 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
1089 if (disposed && closed) {
1090 throw new ObjectDisposedException (GetType ().ToString ());
1093 throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
1096 if (address_family == AddressFamily.InterNetwork) {
1097 SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
1098 } else if (address_family == AddressFamily.InterNetworkV6) {
1099 SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
1101 throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
1106 // Returns the remote endpoint details in addr and port
1107 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1108 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket, int family, out int error);
1110 public EndPoint RemoteEndPoint {
1112 if (disposed && closed)
1113 throw new ObjectDisposedException (GetType ().ToString ());
1116 * If the seed EndPoint is null, Connect, Bind,
1117 * etc has not yet been called. MS returns null
1120 if (!connected || seed_endpoint == null)
1125 sa=RemoteEndPoint_internal(socket, (int) address_family, out error);
1128 throw new SocketException (error);
1130 return seed_endpoint.Create (sa);
1134 void Linger (IntPtr handle)
1136 if (!connected || linger_timeout <= 0)
1139 // We don't want to receive any more data
1141 Shutdown_internal (handle, SocketShutdown.Receive, out error);
1145 int seconds = linger_timeout / 1000;
1146 int ms = linger_timeout % 1000;
1148 // If the other end closes, this will return 'true' with 'Available' == 0
1149 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
1155 LingerOption linger = new LingerOption (true, seconds);
1156 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
1157 /* Not needed, we're closing upon return */
1162 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1163 static extern void cancel_blocking_socket_operation (Thread thread);
1165 protected virtual void Dispose (bool disposing)
1171 bool was_connected = connected;
1173 if ((int) socket != -1) {
1177 socket = (IntPtr) (-1);
1179 AbortRegisteredThreads ();
1183 //DateTime start = DateTime.UtcNow;
1184 Close_internal (x, out error);
1185 //Console.WriteLine ("Time spent in Close_internal: {0}ms", (DateTime.UtcNow - start).TotalMilliseconds);
1187 throw new SocketException (error);
1192 public void Dispose ()
1194 void IDisposable.Dispose ()
1198 GC.SuppressFinalize (this);
1201 // Closes the socket
1202 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1203 private extern static void Close_internal(IntPtr socket, out int error);
1205 public void Close ()
1208 ((IDisposable) this).Dispose ();
1211 public void Close (int timeout)
1213 linger_timeout = timeout;
1214 ((IDisposable) this).Dispose ();
1217 // Connects to the remote address
1218 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1219 private extern static void Connect_internal(IntPtr sock,
1223 public void Connect (EndPoint remoteEP)
1225 SocketAddress serial = null;
1227 if (disposed && closed)
1228 throw new ObjectDisposedException (GetType ().ToString ());
1230 if (remoteEP == null)
1231 throw new ArgumentNullException ("remoteEP");
1233 IPEndPoint ep = remoteEP as IPEndPoint;
1234 if (ep != null && socket_type != SocketType.Dgram) /* Dgram uses Any to 'disconnect' */
1235 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1236 throw new SocketException ((int) SocketError.AddressNotAvailable);
1239 throw new InvalidOperationException ();
1240 serial = remoteEP.Serialize ();
1245 RegisterForBlockingSyscall ();
1246 Connect_internal (socket, serial, out error);
1248 UnRegisterForBlockingSyscall ();
1251 if (error == 0 || error == 10035)
1252 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1256 error = SOCKET_CLOSED;
1257 throw new SocketException (error);
1260 if (socket_type == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)))
1267 public bool ReceiveAsync (SocketAsyncEventArgs e)
1269 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1270 if (disposed && closed)
1271 throw new ObjectDisposedException (GetType ().ToString ());
1273 // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1274 // thrown when e.Buffer and e.BufferList are null (works fine when one is
1275 // set to a valid object)
1276 if (e.Buffer == null && e.BufferList == null)
1277 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1280 SocketOperation op = (e.Buffer != null) ? SocketOperation.Receive : SocketOperation.ReceiveGeneric;
1281 e.Worker.Init (this, e, op);
1282 SocketAsyncResult res = e.Worker.result;
1283 if (e.Buffer != null) {
1284 res.Buffer = e.Buffer;
1285 res.Offset = e.Offset;
1288 res.Buffers = e.BufferList;
1290 res.SockFlags = e.SocketFlags;
1293 readQ.Enqueue (e.Worker);
1294 count = readQ.Count;
1297 // Receive takes care of ReceiveGeneric
1298 socket_pool_queue (Worker.Dispatcher, res);
1304 public bool SendAsync (SocketAsyncEventArgs e)
1306 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1307 if (disposed && closed)
1308 throw new ObjectDisposedException (GetType ().ToString ());
1309 if (e.Buffer == null && e.BufferList == null)
1310 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1313 SocketOperation op = (e.Buffer != null) ? SocketOperation.Send : SocketOperation.SendGeneric;
1314 e.Worker.Init (this, e, op);
1315 SocketAsyncResult res = e.Worker.result;
1316 if (e.Buffer != null) {
1317 res.Buffer = e.Buffer;
1318 res.Offset = e.Offset;
1321 res.Buffers = e.BufferList;
1323 res.SockFlags = e.SocketFlags;
1326 writeQ.Enqueue (e.Worker);
1327 count = writeQ.Count;
1330 // Send takes care of SendGeneric
1331 socket_pool_queue (Worker.Dispatcher, res);
1336 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1337 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
1339 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1340 private extern static int Receive_internal(IntPtr sock,
1347 internal int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
1350 int ret = Receive_internal (socket, buf, offset, size, flags, out nativeError);
1351 error = (SocketError) nativeError;
1352 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
1362 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1363 private extern static void GetSocketOption_obj_internal(IntPtr socket,
1364 SocketOptionLevel level, SocketOptionName name, out object obj_val,
1367 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1368 private extern static int Send_internal(IntPtr sock,
1369 byte[] buf, int offset,
1374 internal int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
1377 error = SocketError.Success;
1383 int ret = Send_internal (socket, buf, offset, size, flags, out nativeError);
1385 error = (SocketError)nativeError;
1387 if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
1397 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
1399 if (disposed && closed)
1400 throw new ObjectDisposedException (GetType ().ToString ());
1405 GetSocketOption_obj_internal (socket, optionLevel, optionName, out obj_val,
1408 throw new SocketException (error);
1410 if (optionName == SocketOptionName.Linger) {
1411 return((LingerOption)obj_val);
1412 } else if (optionName == SocketOptionName.AddMembership ||
1413 optionName == SocketOptionName.DropMembership) {
1414 return((MulticastOption)obj_val);
1415 } else if (obj_val is int) {
1416 return((int)obj_val);
1422 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1423 private extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
1425 public void Shutdown (SocketShutdown how)
1427 if (disposed && closed)
1428 throw new ObjectDisposedException (GetType ().ToString ());
1431 throw new SocketException (10057); // Not connected
1435 Shutdown_internal (socket, how, out error);
1437 throw new SocketException (error);
1440 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1441 private extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level,
1442 SocketOptionName name, object obj_val,
1443 byte [] byte_val, int int_val,
1446 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
1448 if (disposed && closed)
1449 throw new ObjectDisposedException (GetType ().ToString ());
1453 SetSocketOption_internal (socket, optionLevel, optionName, null,
1454 null, optionValue, out error);
1457 throw new SocketException (error);
1460 private void ThrowIfUpd ()
1462 #if !NET_2_1 || MOBILE
1463 if (protocol_type == ProtocolType.Udp)
1464 throw new SocketException ((int)SocketError.ProtocolOption);
1469 IAsyncResult BeginConnect(EndPoint end_point, AsyncCallback callback, object state)
1471 if (disposed && closed)
1472 throw new ObjectDisposedException (GetType ().ToString ());
1474 if (end_point == null)
1475 throw new ArgumentNullException ("end_point");
1477 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Connect);
1478 req.EndPoint = end_point;
1480 // Bug #75154: Connect() should not succeed for .Any addresses.
1481 if (end_point is IPEndPoint) {
1482 IPEndPoint ep = (IPEndPoint) end_point;
1483 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1484 req.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1490 if (connect_in_progress) {
1491 // This could happen when multiple IPs are used
1492 // Calling connect() again will reset the connection attempt and cause
1493 // an error. Better to just close the socket and move on.
1494 connect_in_progress = false;
1495 Close_internal (socket, out error);
1496 socket = Socket_internal (address_family, socket_type, protocol_type, out error);
1498 throw new SocketException (error);
1500 bool blk = blocking;
1503 SocketAddress serial = end_point.Serialize ();
1504 Connect_internal (socket, serial, out error);
1511 req.Complete (true);
1515 if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1519 req.Complete (new SocketException (error), true);
1526 connect_in_progress = true;
1527 socket_pool_queue (Worker.Dispatcher, req);
1532 IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1535 if (disposed && closed)
1536 throw new ObjectDisposedException (GetType ().ToString ());
1538 if (addresses == null)
1539 throw new ArgumentNullException ("addresses");
1541 if (addresses.Length == 0)
1542 throw new ArgumentException ("Empty addresses list");
1544 if (this.AddressFamily != AddressFamily.InterNetwork &&
1545 this.AddressFamily != AddressFamily.InterNetworkV6)
1546 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1548 if (port <= 0 || port > 65535)
1549 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1551 throw new InvalidOperationException ();
1553 SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Connect);
1554 req.Addresses = addresses;
1557 return BeginMConnect (req);
1560 IAsyncResult BeginMConnect (SocketAsyncResult req)
1562 IAsyncResult ares = null;
1563 Exception exc = null;
1564 for (int i = req.CurrentAddress; i < req.Addresses.Length; i++) {
1565 IPAddress addr = req.Addresses [i];
1566 IPEndPoint ep = new IPEndPoint (addr, req.Port);
1568 req.CurrentAddress++;
1569 ares = BeginConnect (ep, null, req);
1570 if (ares.IsCompleted && ares.CompletedSynchronously) {
1571 ((SocketAsyncResult) ares).CheckIfThrowDelayedException ();
1572 req.DoMConnectCallback ();
1575 } catch (Exception e) {
1587 // Returns false when it is ok to use RemoteEndPoint
1588 // true when addresses must be used (and addresses could be null/empty)
1589 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1593 // Connect to the first address that match the host name, like:
1594 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1595 // while skipping entries that do not match the address family
1596 DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1598 addresses = Dns.GetHostAddresses (dep.Host);
1601 e.ConnectByNameError = null;
1605 return false; // < NET_4_0 -> use remote endpoint
1609 bool ConnectAsyncReal (SocketAsyncEventArgs e)
1611 bool use_remoteep = true;
1613 IPAddress [] addresses = null;
1614 use_remoteep = !GetCheckedIPs (e, out addresses);
1617 Worker w = e.Worker;
1618 w.Init (this, e, SocketOperation.Connect);
1619 SocketAsyncResult result = w.result;
1620 IAsyncResult ares = null;
1623 result.EndPoint = e.RemoteEndPoint;
1624 ares = BeginConnect (e.RemoteEndPoint, SocketAsyncEventArgs.Dispatcher, e);
1629 DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1630 result.Addresses = addresses;
1631 result.Port = dep.Port;
1633 ares = BeginConnect (addresses, dep.Port, SocketAsyncEventArgs.Dispatcher, e);
1636 if (ares.IsCompleted && ares.CompletedSynchronously) {
1637 ((SocketAsyncResult) ares).CheckIfThrowDelayedException ();
1640 } catch (Exception exc) {
1641 result.Complete (exc, true);
1647 public bool ConnectAsync (SocketAsyncEventArgs e)
1649 // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1650 if (disposed && closed)
1651 throw new ObjectDisposedException (GetType ().ToString ());
1653 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1654 if (e.RemoteEndPoint == null)
1655 throw new ArgumentNullException ("remoteEP");
1657 return ConnectAsyncReal (e);
1660 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1661 private extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
1663 int Receive (IList<ArraySegment<byte>> buffers)
1667 ret = Receive (buffers, SocketFlags.None, out error);
1668 if (error != SocketError.Success) {
1669 throw new SocketException ((int)error);
1674 [CLSCompliant (false)]
1676 int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1680 ret = Receive (buffers, socketFlags, out error);
1681 if (error != SocketError.Success) {
1682 throw new SocketException ((int)error);
1687 [CLSCompliant (false)]
1689 int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1691 if (disposed && closed)
1692 throw new ObjectDisposedException (GetType ().ToString ());
1694 if (buffers == null ||
1695 buffers.Count == 0) {
1696 throw new ArgumentNullException ("buffers");
1699 int numsegments = buffers.Count;
1703 /* Only example I can find of sending a byte
1704 * array reference directly into an internal
1706 * System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1707 * so taking a lead from that...
1709 WSABUF[] bufarray = new WSABUF[numsegments];
1710 GCHandle[] gch = new GCHandle[numsegments];
1712 for(int i = 0; i < numsegments; i++) {
1713 ArraySegment<byte> segment = buffers[i];
1715 if (segment.Offset < 0 || segment.Count < 0 ||
1716 segment.Count > segment.Array.Length - segment.Offset)
1717 throw new ArgumentOutOfRangeException ("segment");
1719 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1720 bufarray[i].len = segment.Count;
1721 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1725 ret = Receive_internal (socket, bufarray,
1729 for(int i = 0; i < numsegments; i++) {
1730 if (gch[i].IsAllocated) {
1736 errorCode = (SocketError)nativeError;
1740 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1741 private extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
1743 int Send (IList<ArraySegment<byte>> buffers)
1747 ret = Send (buffers, SocketFlags.None, out error);
1748 if (error != SocketError.Success) {
1749 throw new SocketException ((int)error);
1755 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1759 ret = Send (buffers, socketFlags, out error);
1760 if (error != SocketError.Success) {
1761 throw new SocketException ((int)error);
1766 [CLSCompliant (false)]
1768 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1770 if (disposed && closed)
1771 throw new ObjectDisposedException (GetType ().ToString ());
1772 if (buffers == null)
1773 throw new ArgumentNullException ("buffers");
1774 if (buffers.Count == 0)
1775 throw new ArgumentException ("Buffer is empty", "buffers");
1776 int numsegments = buffers.Count;
1780 WSABUF[] bufarray = new WSABUF[numsegments];
1781 GCHandle[] gch = new GCHandle[numsegments];
1782 for(int i = 0; i < numsegments; i++) {
1783 ArraySegment<byte> segment = buffers[i];
1785 if (segment.Offset < 0 || segment.Count < 0 ||
1786 segment.Count > segment.Array.Length - segment.Offset)
1787 throw new ArgumentOutOfRangeException ("segment");
1789 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1790 bufarray[i].len = segment.Count;
1791 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1795 ret = Send_internal (socket, bufarray, socketFlags, out nativeError);
1797 for(int i = 0; i < numsegments; i++) {
1798 if (gch[i].IsAllocated) {
1803 errorCode = (SocketError)nativeError;
1807 Exception InvalidAsyncOp (string method)
1809 return new InvalidOperationException (method + " can only be called once per asynchronous operation");
1813 int EndReceive (IAsyncResult result)
1816 int bytesReceived = EndReceive (result, out error);
1817 if (error != SocketError.Success) {
1818 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
1820 throw new SocketException ((int)error);
1822 return bytesReceived;
1826 int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
1828 if (disposed && closed)
1829 throw new ObjectDisposedException (GetType ().ToString ());
1831 if (asyncResult == null)
1832 throw new ArgumentNullException ("asyncResult");
1834 SocketAsyncResult req = asyncResult as SocketAsyncResult;
1836 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
1838 if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1839 throw InvalidAsyncOp ("EndReceive");
1840 if (!asyncResult.IsCompleted)
1841 asyncResult.AsyncWaitHandle.WaitOne ();
1843 errorCode = req.ErrorCode;
1844 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
1845 // kinds of exceptions that should be thrown.
1846 if (errorCode == SocketError.Success)
1847 req.CheckIfThrowDelayedException();
1853 int EndSend (IAsyncResult result)
1856 int bytesSent = EndSend (result, out error);
1857 if (error != SocketError.Success) {
1858 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
1860 throw new SocketException ((int)error);
1866 int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
1868 if (disposed && closed)
1869 throw new ObjectDisposedException (GetType ().ToString ());
1870 if (asyncResult == null)
1871 throw new ArgumentNullException ("asyncResult");
1873 SocketAsyncResult req = asyncResult as SocketAsyncResult;
1875 throw new ArgumentException ("Invalid IAsyncResult", "result");
1877 if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1878 throw InvalidAsyncOp ("EndSend");
1879 if (!asyncResult.IsCompleted)
1880 asyncResult.AsyncWaitHandle.WaitOne ();
1882 errorCode = req.ErrorCode;
1883 // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
1884 // kinds of exceptions that should be thrown.
1885 if (errorCode == SocketError.Success)
1886 req.CheckIfThrowDelayedException ();
1891 // Used by Udpclient
1893 int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
1895 if (disposed && closed)
1896 throw new ObjectDisposedException (GetType ().ToString ());
1899 throw new ArgumentNullException ("result");
1901 if (end_point == null)
1902 throw new ArgumentNullException ("remote_end");
1904 SocketAsyncResult req = result as SocketAsyncResult;
1906 throw new ArgumentException ("Invalid IAsyncResult", "result");
1908 if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1909 throw InvalidAsyncOp ("EndReceiveFrom");
1910 if (!result.IsCompleted)
1911 result.AsyncWaitHandle.WaitOne();
1913 req.CheckIfThrowDelayedException();
1914 end_point = req.EndPoint;
1918 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1919 static extern void socket_pool_queue (SocketAsyncCall d, SocketAsyncResult r);