**** Merged from MCS ****
[mono-project.git] / mcs / class / System / System.Net.Sockets / Socket.cs
blob78151c928d63e98ff0c6b535d5e9d83555471a3c
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 //
8 // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
9 // http://www.myelin.co.nz
10 // (c) 2004 Novell, Inc. (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System;
35 using System.Net;
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.InteropServices;
39 using System.Threading;
40 using System.Reflection;
41 using System.IO;
43 namespace System.Net.Sockets
45 public class Socket : IDisposable
47 [StructLayout (LayoutKind.Sequential)]
48 private sealed class SocketAsyncResult: IAsyncResult
50 /* Same structure in the runtime */
51 public Socket Sock;
52 IntPtr handle;
53 object state;
54 AsyncCallback callback;
55 WaitHandle waithandle;
57 Exception delayedException;
59 public EndPoint EndPoint; // Connect,ReceiveFrom,SendTo
60 public byte [] Buffer; // Receive,ReceiveFrom,Send,SendTo
61 public int Offset; // Receive,ReceiveFrom,Send,SendTo
62 public int Size; // Receive,ReceiveFrom,Send,SendTo
63 public SocketFlags SockFlags; // Receive,ReceiveFrom,Send,SendTo
65 // Return values
66 Socket acc_socket;
67 int total;
69 bool completed_sync;
70 bool completed;
71 AsyncCallback real_callback;
72 int error;
74 public SocketAsyncResult (Socket sock, object state, AsyncCallback callback)
76 this.Sock = sock;
77 this.handle = sock.socket;
78 this.state = state;
79 this.real_callback = callback;
80 SockFlags = SocketFlags.None;
83 public void CreateAsyncDelegate ()
85 if (real_callback != null)
86 this.callback = new AsyncCallback (FakeCB);
89 static void FakeCB (IAsyncResult result)
91 SocketAsyncResult ares = (SocketAsyncResult) result;
92 ares.real_callback.BeginInvoke (ares, null, null);
95 public void CheckIfThrowDelayedException ()
97 if (delayedException != null)
98 throw delayedException;
100 if (error != 0)
101 throw new SocketException (error);
104 public void Complete ()
106 IsCompleted = true;
107 if (real_callback != null)
108 real_callback (this);
111 public void Complete (int total)
113 this.total = total;
114 Complete ();
117 public void Complete (Exception e)
119 delayedException = e;
120 Complete ();
123 public void Complete (Socket s)
125 acc_socket = s;
126 Complete ();
129 public object AsyncState {
130 get {
131 return state;
135 public WaitHandle AsyncWaitHandle {
136 get {
137 lock (this) {
138 if (waithandle == null)
139 waithandle = new ManualResetEvent (completed);
142 return waithandle;
144 set {
145 waithandle=value;
149 public bool CompletedSynchronously {
150 get {
151 return(completed_sync);
155 public bool IsCompleted {
156 get {
157 return(completed);
159 set {
160 completed=value;
161 lock (this) {
162 if (waithandle != null && value) {
163 ((ManualResetEvent) waithandle).Set ();
169 public Socket Socket {
170 get {
171 return acc_socket;
175 public int Total {
176 get {
177 return total;
182 private sealed class Worker
184 SocketAsyncResult result;
186 public Worker (SocketAsyncResult ares)
188 this.result = ares;
191 public void Accept ()
193 lock (result) {
194 Socket acc_socket = null;
195 try {
196 if (!result.Sock.blocking)
197 result.Sock.Poll (-1, SelectMode.SelectRead);
199 acc_socket = result.Sock.Accept ();
200 } catch (Exception e) {
201 result.Complete (e);
202 return;
205 result.Complete (acc_socket);
209 public void Connect ()
211 lock (result) {
212 try {
213 result.Sock.Connect (result.EndPoint);
214 } catch (SocketException se) {
215 if (result.Sock.blocking || se.ErrorCode != 10036) {
216 result.Complete (se);
217 return;
220 try {
221 result.Sock.Poll (-1, SelectMode.SelectWrite);
222 result.Sock.Connect (result.EndPoint);
223 } catch (Exception k) {
224 result.Complete (k);
225 return;
227 } catch (Exception e) {
228 result.Complete (e);
229 return;
232 result.Complete ();
236 public void Receive ()
238 lock (result) {
239 int total = 0;
240 try {
241 if (!result.Sock.blocking)
242 result.Sock.Poll (-1, SelectMode.SelectRead);
244 total = result.Sock.Receive_nochecks (result.Buffer,
245 result.Offset,
246 result.Size,
247 result.SockFlags);
248 } catch (Exception e) {
249 result.Complete (e);
250 return;
253 result.Complete (total);
257 public void ReceiveFrom ()
259 lock (result) {
260 int total = 0;
261 try {
262 if (!result.Sock.blocking)
263 result.Sock.Poll (-1, SelectMode.SelectRead);
265 total = result.Sock.ReceiveFrom_nochecks (result.Buffer,
266 result.Offset,
267 result.Size,
268 result.SockFlags,
269 ref result.EndPoint);
270 } catch (Exception e) {
271 result.Complete (e);
272 return;
275 result.Complete (total);
279 public void Send ()
281 lock (result) {
282 int total = 0;
283 try {
284 if (!result.Sock.blocking)
285 result.Sock.Poll (-1, SelectMode.SelectWrite);
287 total = result.Sock.Send_nochecks (result.Buffer,
288 result.Offset,
289 result.Size,
290 result.SockFlags);
291 } catch (Exception e) {
292 result.Complete (e);
293 return;
296 result.Complete (total);
300 public void SendTo() {
301 lock (result) {
302 int total = 0;
303 try {
304 if (!result.Sock.blocking)
305 result.Sock.Poll (-1, SelectMode.SelectWrite);
307 total = result.Sock.SendTo_nochecks (result.Buffer,
308 result.Offset,
309 result.Size,
310 result.SockFlags,
311 result.EndPoint);
312 } catch (Exception e) {
313 result.Complete (e);
314 return;
317 result.Complete (total);
322 /* the field "socket" is looked up by name by the runtime */
323 private IntPtr socket;
324 private AddressFamily address_family;
325 private SocketType socket_type;
326 private ProtocolType protocol_type;
327 internal bool blocking=true;
328 private int pendingEnds;
329 private int closeDelayed;
330 static readonly bool supportsAsync = FakeGetSupportsAsync ();
332 delegate void SocketAsyncCall ();
334 * These two fields are looked up by name by the runtime, don't change
335 * their name without also updating the runtime code.
337 private static int ipv4Supported = -1, ipv6Supported = -1;
339 /* When true, the socket was connected at the time of
340 * the last IO operation
342 private bool connected=false;
343 /* true if we called Close_internal */
344 private bool closed;
346 /* Used in LocalEndPoint and RemoteEndPoint if the
347 * Mono.Posix assembly is available
349 private static object unixendpoint=null;
350 private static Type unixendpointtype=null;
352 [MethodImplAttribute(MethodImplOptions.InternalCall)]
353 private extern static void Select_internal(ref Socket[] read,
354 ref Socket[] write,
355 ref Socket[] err,
356 int timeout,
357 out int error);
359 public static void Select(IList read_list, IList write_list,
360 IList err_list, int time_us) {
361 int read_count = 0, write_count = 0, err_count = 0;
362 Socket[] read_arr = null;
363 Socket[] write_arr = null;
364 Socket[] err_arr = null;
366 if (read_list!=null)
367 read_count=read_list.Count;
369 if (read_count != 0)
370 read_arr=new Socket[read_count];
372 if (write_list!=null)
373 write_count=write_list.Count;
375 if (write_count != 0)
376 write_arr=new Socket[write_count];
378 if (err_list!=null)
379 err_count=err_list.Count;
381 if (err_count != 0)
382 err_arr=new Socket[err_count];
384 if(read_count == 0 && write_count == 0 && err_count == 0) {
385 throw new ArgumentNullException ("read_list, write_list, err_list",
386 "All the lists are null or empty.");
389 int i;
391 if (read_count != 0) {
392 i=0;
394 foreach (Socket s in read_list) {
395 read_arr[i]=s;
396 i++;
400 if (write_count != 0) {
401 i=0;
402 foreach (Socket s in write_list) {
403 write_arr[i]=s;
404 i++;
408 if (err_count != 0) {
409 i=0;
410 foreach (Socket s in err_list) {
411 err_arr[i]=s;
412 i++;
416 int error;
418 Select_internal(ref read_arr, ref write_arr,
419 ref err_arr, time_us, out error);
421 if(error != 0) {
422 throw new SocketException (error);
425 /* Make sure the connected state is updated
426 * for each socket returned from the select;
427 * for non blocking Connect()s, this is when
428 * we find out that the connect succeeded.
431 if(read_list!=null) {
432 read_list.Clear();
433 if (read_arr != null) {
434 for(i=0; i<read_arr.Length; i++) {
435 read_list.Add(read_arr[i]);
436 read_arr[i].connected = true;
441 if(write_list!=null) {
442 write_list.Clear();
443 if (write_arr != null) {
444 for(i=0; i<write_arr.Length; i++) {
445 write_list.Add(write_arr[i]);
446 write_arr[i].connected = true;
451 if(err_list!=null) {
452 err_list.Clear();
453 if (err_arr != null) {
454 for(i=0; i<err_arr.Length; i++) {
455 err_list.Add(err_arr[i]);
456 err_arr[i].connected = true;
462 static Socket() {
463 Assembly ass;
465 try {
466 ass = Assembly.Load (Consts.AssemblyMono_Posix);
467 } catch (FileNotFoundException) {
468 return;
471 unixendpointtype=ass.GetType("Mono.Posix.UnixEndPoint");
473 /* The endpoint Create() method is an instance
474 * method :-(
476 Type[] arg_types=new Type[1];
477 arg_types[0]=typeof(string);
478 ConstructorInfo cons=unixendpointtype.GetConstructor(arg_types);
480 object[] args=new object[1];
481 args[0]="";
483 unixendpoint=cons.Invoke(args);
486 // private constructor used by Accept, which already
487 // has a socket handle to use
488 private Socket(AddressFamily family, SocketType type,
489 ProtocolType proto, IntPtr sock) {
490 address_family=family;
491 socket_type=type;
492 protocol_type=proto;
494 socket=sock;
495 connected=true;
498 // Creates a new system socket, returning the handle
499 [MethodImplAttribute(MethodImplOptions.InternalCall)]
500 private extern IntPtr Socket_internal(AddressFamily family,
501 SocketType type,
502 ProtocolType proto,
503 out int error);
505 public Socket(AddressFamily family, SocketType type,
506 ProtocolType proto) {
507 address_family=family;
508 socket_type=type;
509 protocol_type=proto;
511 int error;
513 socket=Socket_internal(family, type, proto, out error);
514 if (error != 0) {
515 throw new SocketException (error);
519 public AddressFamily AddressFamily {
520 get {
521 return(address_family);
525 // Returns the amount of data waiting to be read on socket
526 [MethodImplAttribute(MethodImplOptions.InternalCall)]
527 private extern static int Available_internal(IntPtr socket,
528 out int error);
530 public int Available {
531 get {
532 if (disposed && closed)
533 throw new ObjectDisposedException (GetType ().ToString ());
535 int ret, error;
537 ret = Available_internal(socket, out error);
539 if (error != 0) {
540 throw new SocketException (error);
543 return(ret);
547 [MethodImplAttribute(MethodImplOptions.InternalCall)]
548 private extern static void Blocking_internal(IntPtr socket,
549 bool block,
550 out int error);
552 public bool Blocking {
553 get {
554 return(blocking);
556 set {
557 int error;
559 Blocking_internal(socket, value, out error);
561 if (error != 0) {
562 throw new SocketException (error);
565 blocking=value;
569 public bool Connected {
570 get {
571 return(connected);
575 public IntPtr Handle {
576 get {
577 return(socket);
581 // Returns the local endpoint details in addr and port
582 [MethodImplAttribute(MethodImplOptions.InternalCall)]
583 private extern static SocketAddress LocalEndPoint_internal(IntPtr socket, out int error);
585 [MonoTODO("Support non-IP endpoints")]
586 public EndPoint LocalEndPoint {
587 get {
588 if (disposed && closed)
589 throw new ObjectDisposedException (GetType ().ToString ());
591 SocketAddress sa;
592 int error;
594 sa=LocalEndPoint_internal(socket, out error);
596 if (error != 0) {
597 throw new SocketException (error);
600 if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6) {
601 // Stupidly, EndPoint.Create() is an
602 // instance method
603 return new IPEndPoint(0, 0).Create(sa);
604 } else if (sa.Family==AddressFamily.Unix &&
605 unixendpoint!=null) {
606 return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
607 } else {
608 throw new NotImplementedException();
613 public ProtocolType ProtocolType {
614 get {
615 return(protocol_type);
619 // Returns the remote endpoint details in addr and port
620 [MethodImplAttribute(MethodImplOptions.InternalCall)]
621 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket, out int error);
623 [MonoTODO("Support non-IP endpoints")]
624 public EndPoint RemoteEndPoint {
625 get {
626 if (disposed && closed)
627 throw new ObjectDisposedException (GetType ().ToString ());
629 SocketAddress sa;
630 int error;
632 sa=RemoteEndPoint_internal(socket, out error);
634 if (error != 0) {
635 throw new SocketException (error);
638 if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6 ) {
639 // Stupidly, EndPoint.Create() is an
640 // instance method
641 return new IPEndPoint(0, 0).Create(sa);
642 } else if (sa.Family==AddressFamily.Unix &&
643 unixendpoint!=null) {
644 return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
645 } else {
646 throw new NotImplementedException();
651 public SocketType SocketType {
652 get {
653 return(socket_type);
657 #if NET_1_1
658 public static bool SupportsIPv4 {
659 get {
660 CheckProtocolSupport();
661 return ipv4Supported == 1;
665 public static bool SupportsIPv6 {
666 get {
667 CheckProtocolSupport();
668 return ipv6Supported == 1;
671 #else
672 internal static bool SupportsIPv4
674 get
676 return true;
680 internal static bool SupportsIPv6
682 get
684 return false;
687 #endif
689 internal static void CheckProtocolSupport()
691 if(ipv4Supported == -1) {
692 try {
693 Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
694 tmp.Close();
696 ipv4Supported = 1;
698 catch {
699 ipv4Supported = 0;
703 if(ipv6Supported == -1) {
704 NetConfig config = (NetConfig)System.Configuration.ConfigurationSettings.GetConfig("system.net/settings");
706 if(config != null)
707 ipv6Supported = config.ipv6Enabled?-1:0;
709 if(ipv6Supported != 0) {
710 try {
711 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
712 tmp.Close();
714 ipv6Supported = 1;
716 catch { }
721 // Creates a new system socket, returning the handle
722 [MethodImplAttribute(MethodImplOptions.InternalCall)]
723 private extern static IntPtr Accept_internal(IntPtr sock,
724 out int error);
726 public Socket Accept() {
727 if (disposed && closed)
728 throw new ObjectDisposedException (GetType ().ToString ());
730 int error;
731 IntPtr sock=Accept_internal(socket, out error);
733 if (!blocking && error == 10035) {
734 Poll (-1, SelectMode.SelectRead);
735 sock = Accept_internal (socket, out error);
738 if (error != 0) {
739 throw new SocketException (error);
742 Socket accepted = new Socket(this.AddressFamily,
743 this.SocketType,
744 this.ProtocolType, sock);
746 // The MS runtime (really the OS, we suspect)
747 // sets newly accepted sockets to have the
748 // same Blocking status as the listening
749 // socket
750 accepted.Blocking = this.Blocking;
751 return(accepted);
754 public IAsyncResult BeginAccept(AsyncCallback callback,
755 object state) {
757 if (disposed && closed)
758 throw new ObjectDisposedException (GetType ().ToString ());
760 Interlocked.Increment (ref pendingEnds);
761 SocketAsyncResult req = new SocketAsyncResult (this, state, callback);
762 Worker worker = new Worker (req);
763 SocketAsyncCall sac = new SocketAsyncCall (worker.Accept);
764 sac.BeginInvoke (null, null);
765 return(req);
768 public IAsyncResult BeginConnect(EndPoint end_point,
769 AsyncCallback callback,
770 object state) {
772 if (disposed && closed)
773 throw new ObjectDisposedException (GetType ().ToString ());
775 if (end_point == null)
776 throw new ArgumentNullException ("end_point");
778 Interlocked.Increment (ref pendingEnds);
779 SocketAsyncResult req = new SocketAsyncResult (this, state, callback);
780 req.EndPoint = end_point;
781 Worker worker = new Worker (req);
782 SocketAsyncCall sac = new SocketAsyncCall (worker.Connect);
783 sac.BeginInvoke (null, null);
784 return(req);
787 public IAsyncResult BeginReceive(byte[] buffer, int offset,
788 int size,
789 SocketFlags socket_flags,
790 AsyncCallback callback,
791 object state) {
793 if (disposed && closed)
794 throw new ObjectDisposedException (GetType ().ToString ());
796 if (buffer == null)
797 throw new ArgumentNullException ("buffer");
799 if (offset < 0 || offset > buffer.Length)
800 throw new ArgumentOutOfRangeException ("offset");
802 if (size < 0 || offset + size > buffer.Length)
803 throw new ArgumentOutOfRangeException ("size");
805 Interlocked.Increment (ref pendingEnds);
806 SocketAsyncResult req = new SocketAsyncResult (this, state, callback);
807 req.Buffer = buffer;
808 req.Offset = offset;
809 req.Size = size;
810 req.SockFlags = socket_flags;
811 if (supportsAsync && socket_type == SocketType.Stream) {
812 int error;
813 req.CreateAsyncDelegate ();
814 KeepReference (req);
815 AsyncReceiveInternal (req, out error);
816 if (error != 0 && error != 10036) // WSAEINPROGRESS
817 throw new SocketException (error);
818 } else {
819 Worker worker = new Worker (req);
820 SocketAsyncCall sac = new SocketAsyncCall (worker.Receive);
821 sac.BeginInvoke (null, null);
824 return req;
827 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
828 int size,
829 SocketFlags socket_flags,
830 ref EndPoint remote_end,
831 AsyncCallback callback,
832 object state) {
833 if (disposed && closed)
834 throw new ObjectDisposedException (GetType ().ToString ());
836 if (buffer == null)
837 throw new ArgumentNullException ("buffer");
839 if (offset < 0)
840 throw new ArgumentOutOfRangeException ("offset must be >= 0");
842 if (size < 0)
843 throw new ArgumentOutOfRangeException ("size must be >= 0");
845 if (offset + size > buffer.Length)
846 throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length");
848 Interlocked.Increment (ref pendingEnds);
849 SocketAsyncResult req = new SocketAsyncResult (this, state, callback);
850 req.Buffer = buffer;
851 req.Offset = offset;
852 req.Size = size;
853 req.SockFlags = socket_flags;
854 req.EndPoint = remote_end;
855 Worker worker = new Worker (req);
856 SocketAsyncCall sac = new SocketAsyncCall (worker.ReceiveFrom);
857 sac.BeginInvoke (null, null);
858 return req;
861 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags,
862 AsyncCallback callback, object state)
864 if (disposed && closed)
865 throw new ObjectDisposedException (GetType ().ToString ());
867 if (buffer == null)
868 throw new ArgumentNullException ("buffer");
870 if (offset < 0)
871 throw new ArgumentOutOfRangeException ("offset must be >= 0");
873 if (size < 0)
874 throw new ArgumentOutOfRangeException ("size must be >= 0");
876 if (offset + size > buffer.Length)
877 throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length");
879 Interlocked.Increment (ref pendingEnds);
880 SocketAsyncResult req = new SocketAsyncResult (this, state, callback);
881 req.Buffer = buffer;
882 req.Offset = offset;
883 req.Size = size;
884 req.SockFlags = socket_flags;
885 if (supportsAsync && socket_type == SocketType.Stream) {
886 int error;
887 req.CreateAsyncDelegate ();
888 KeepReference (req);
889 AsyncSendInternal (req, out error);
890 if (error != 0 && error != 10036) // WSAEINPROGRESS
891 throw new SocketException (error);
892 } else {
893 Worker worker = new Worker (req);
894 SocketAsyncCall sac = new SocketAsyncCall (worker.Send);
895 sac.BeginInvoke (null, null);
897 return req;
900 public IAsyncResult BeginSendTo(byte[] buffer, int offset,
901 int size,
902 SocketFlags socket_flags,
903 EndPoint remote_end,
904 AsyncCallback callback,
905 object state) {
906 if (disposed && closed)
907 throw new ObjectDisposedException (GetType ().ToString ());
909 if (buffer == null)
910 throw new ArgumentNullException ("buffer");
912 if (offset < 0)
913 throw new ArgumentOutOfRangeException ("offset must be >= 0");
915 if (size < 0)
916 throw new ArgumentOutOfRangeException ("size must be >= 0");
918 if (offset + size > buffer.Length)
919 throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length");
921 Interlocked.Increment (ref pendingEnds);
922 SocketAsyncResult req = new SocketAsyncResult (this, state, callback);
923 req.Buffer = buffer;
924 req.Offset = offset;
925 req.Size = size;
926 req.SockFlags = socket_flags;
927 req.EndPoint = remote_end;
928 Worker worker = new Worker(req);
929 SocketAsyncCall sac = new SocketAsyncCall (worker.SendTo);
930 sac.BeginInvoke (null, null);
931 return req;
934 // Creates a new system socket, returning the handle
935 [MethodImplAttribute(MethodImplOptions.InternalCall)]
936 private extern static void Bind_internal(IntPtr sock,
937 SocketAddress sa,
938 out int error);
940 public void Bind(EndPoint local_end) {
941 if (disposed && closed)
942 throw new ObjectDisposedException (GetType ().ToString ());
944 if(local_end==null) {
945 throw new ArgumentNullException("local_end");
948 int error;
950 Bind_internal(socket, local_end.Serialize(),
951 out error);
953 if (error != 0) {
954 throw new SocketException (error);
958 // Closes the socket
959 [MethodImplAttribute(MethodImplOptions.InternalCall)]
960 private extern static void Close_internal(IntPtr socket,
961 out int error);
963 public void Close() {
964 ((IDisposable) this).Dispose ();
967 // Connects to the remote address
968 [MethodImplAttribute(MethodImplOptions.InternalCall)]
969 private extern static void Connect_internal(IntPtr sock,
970 SocketAddress sa,
971 out int error);
973 public void Connect(EndPoint remote_end) {
974 if (disposed && closed)
975 throw new ObjectDisposedException (GetType ().ToString ());
977 if(remote_end==null) {
978 throw new ArgumentNullException("remote_end");
981 int error;
983 SocketAddress serial = remote_end.Serialize ();
984 Connect_internal(socket, serial, out error);
985 if (!blocking && error == 10035) {
986 Poll (-1, SelectMode.SelectWrite);
987 Connect_internal (socket, serial, out error);
990 if (error != 0)
991 throw new SocketException (error);
993 connected=true;
996 public Socket EndAccept(IAsyncResult result) {
997 if (disposed && closed)
998 throw new ObjectDisposedException (GetType ().ToString ());
1000 if (result == null)
1001 throw new ArgumentNullException ("result");
1003 SocketAsyncResult req = result as SocketAsyncResult;
1004 if (req == null)
1005 throw new ArgumentException ("Invalid IAsyncResult", "result");
1007 if (!result.IsCompleted)
1008 result.AsyncWaitHandle.WaitOne();
1010 Interlocked.Decrement (ref pendingEnds);
1011 CheckIfClose ();
1012 req.CheckIfThrowDelayedException();
1013 return req.Socket;
1016 public void EndConnect(IAsyncResult result) {
1017 if (disposed && closed)
1018 throw new ObjectDisposedException (GetType ().ToString ());
1020 if (result == null)
1021 throw new ArgumentNullException ("result");
1023 SocketAsyncResult req = result as SocketAsyncResult;
1024 if (req == null)
1025 throw new ArgumentException ("Invalid IAsyncResult", "result");
1027 if (!result.IsCompleted)
1028 result.AsyncWaitHandle.WaitOne();
1030 Interlocked.Decrement (ref pendingEnds);
1031 CheckIfClose ();
1032 req.CheckIfThrowDelayedException();
1035 public int EndReceive(IAsyncResult result) {
1036 if (disposed && closed)
1037 throw new ObjectDisposedException (GetType ().ToString ());
1039 if (result == null)
1040 throw new ArgumentNullException ("result");
1042 SocketAsyncResult req = result as SocketAsyncResult;
1043 if (req == null)
1044 throw new ArgumentException ("Invalid IAsyncResult", "result");
1046 if (supportsAsync && socket_type == SocketType.Stream)
1047 RemoveReference (req);
1049 if (!result.IsCompleted)
1050 result.AsyncWaitHandle.WaitOne();
1052 Interlocked.Decrement (ref pendingEnds);
1053 CheckIfClose ();
1054 req.CheckIfThrowDelayedException();
1055 return req.Total;
1058 public int EndReceiveFrom(IAsyncResult result,
1059 ref EndPoint end_point) {
1060 if (disposed && closed)
1061 throw new ObjectDisposedException (GetType ().ToString ());
1063 if (result == null)
1064 throw new ArgumentNullException ("result");
1066 SocketAsyncResult req = result as SocketAsyncResult;
1067 if (req == null)
1068 throw new ArgumentException ("Invalid IAsyncResult", "result");
1070 if (!result.IsCompleted)
1071 result.AsyncWaitHandle.WaitOne();
1073 Interlocked.Decrement (ref pendingEnds);
1074 CheckIfClose ();
1075 req.CheckIfThrowDelayedException();
1076 end_point = req.EndPoint;
1077 return req.Total;
1080 public int EndSend(IAsyncResult result) {
1081 if (disposed && closed)
1082 throw new ObjectDisposedException (GetType ().ToString ());
1084 if (result == null)
1085 throw new ArgumentNullException ("result");
1087 SocketAsyncResult req = result as SocketAsyncResult;
1088 if (req == null)
1089 throw new ArgumentException ("Invalid IAsyncResult", "result");
1091 if (supportsAsync && socket_type == SocketType.Stream)
1092 RemoveReference (req);
1094 if (!result.IsCompleted)
1095 result.AsyncWaitHandle.WaitOne();
1097 Interlocked.Decrement (ref pendingEnds);
1098 CheckIfClose ();
1099 req.CheckIfThrowDelayedException();
1100 return req.Total;
1103 public int EndSendTo(IAsyncResult result) {
1104 if (disposed && closed)
1105 throw new ObjectDisposedException (GetType ().ToString ());
1107 if (result == null)
1108 throw new ArgumentNullException ("result");
1110 SocketAsyncResult req = result as SocketAsyncResult;
1111 if (req == null)
1112 throw new ArgumentException ("Invalid IAsyncResult", "result");
1114 if (!result.IsCompleted)
1115 result.AsyncWaitHandle.WaitOne();
1117 Interlocked.Decrement (ref pendingEnds);
1118 CheckIfClose ();
1119 req.CheckIfThrowDelayedException();
1120 return req.Total;
1123 void CheckIfClose ()
1125 if (Interlocked.CompareExchange (ref closeDelayed, 0, 1) == 1 &&
1126 Interlocked.CompareExchange (ref pendingEnds, 0, 0) == 0) {
1127 closed = true;
1129 int error;
1131 Close_internal(socket, out error);
1133 if (error != 0) {
1134 throw new SocketException (error);
1139 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1140 private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
1141 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1142 private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
1144 public object GetSocketOption(SocketOptionLevel level,
1145 SocketOptionName name) {
1146 object obj_val;
1147 int error;
1149 GetSocketOption_obj_internal(socket, level, name,
1150 out obj_val, out error);
1152 if (error != 0) {
1153 throw new SocketException (error);
1156 if(name==SocketOptionName.Linger) {
1157 return((LingerOption)obj_val);
1158 } else if (name==SocketOptionName.AddMembership ||
1159 name==SocketOptionName.DropMembership) {
1160 return((MulticastOption)obj_val);
1161 } else if (obj_val is int) {
1162 return((int)obj_val);
1163 } else {
1164 return(obj_val);
1168 public void GetSocketOption(SocketOptionLevel level,
1169 SocketOptionName name,
1170 byte[] opt_value) {
1171 int opt_value_len=opt_value.Length;
1172 int error;
1174 GetSocketOption_arr_internal(socket, level, name,
1175 ref opt_value, out error);
1177 if (error != 0) {
1178 throw new SocketException (error);
1182 public byte[] GetSocketOption(SocketOptionLevel level,
1183 SocketOptionName name,
1184 int length) {
1185 byte[] byte_val=new byte[length];
1186 int error;
1188 GetSocketOption_arr_internal(socket, level, name,
1189 ref byte_val, out error);
1191 if (error != 0) {
1192 throw new SocketException (error);
1195 return(byte_val);
1198 // See Socket.IOControl, WSAIoctl documentation in MSDN. The
1199 // common options between UNIX and Winsock are FIONREAD,
1200 // FIONBIO and SIOCATMARK. Anything else will depend on the
1201 // system.
1202 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1203 extern static int WSAIoctl (IntPtr sock, int ioctl_code,
1204 byte [] input, byte [] output,
1205 out int error);
1207 public int IOControl (int ioctl_code, byte [] in_value, byte [] out_value)
1209 if (disposed)
1210 throw new ObjectDisposedException (GetType ().ToString ());
1212 int error;
1213 int result = WSAIoctl (socket, ioctl_code, in_value,
1214 out_value, out error);
1216 if (error != 0) {
1217 throw new SocketException (error);
1220 if (result == -1)
1221 throw new InvalidOperationException ("Must use Blocking property instead.");
1223 return result;
1226 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1227 private extern static void Listen_internal(IntPtr sock,
1228 int backlog,
1229 out int error);
1231 public void Listen(int backlog) {
1232 int error;
1234 Listen_internal(socket, backlog, out error);
1236 if (error != 0) {
1237 throw new SocketException (error);
1241 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1242 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
1244 public bool Poll (int time_us, SelectMode mode)
1246 if (mode != SelectMode.SelectRead &&
1247 mode != SelectMode.SelectWrite &&
1248 mode != SelectMode.SelectError)
1249 throw new NotSupportedException ("'mode' parameter is not valid.");
1251 int error;
1252 bool result = Poll_internal (socket, mode, time_us, out error);
1253 if (error != 0)
1254 throw new SocketException (error);
1256 if (result == true) {
1257 /* Update the connected state; for
1258 * non-blocking Connect()s this is
1259 * when we can find out that the
1260 * connect succeeded.
1262 connected = true;
1265 return result;
1268 public int Receive (byte [] buf)
1270 if (buf == null)
1271 throw new ArgumentNullException ("buf");
1273 return Receive_nochecks (buf, 0, buf.Length, SocketFlags.None);
1276 public int Receive (byte [] buf, SocketFlags flags)
1278 if (buf == null)
1279 throw new ArgumentNullException ("buf");
1281 return Receive_nochecks (buf, 0, buf.Length, flags);
1284 public int Receive (byte [] buf, int size, SocketFlags flags)
1286 if (buf == null)
1287 throw new ArgumentNullException ("buf");
1289 if (size < 0 || size > buf.Length)
1290 throw new ArgumentOutOfRangeException ("size");
1292 return Receive_nochecks (buf, 0, size, flags);
1295 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1296 private extern static int Receive_internal(IntPtr sock,
1297 byte[] buffer,
1298 int offset,
1299 int count,
1300 SocketFlags flags,
1301 out int error);
1303 public int Receive (byte [] buf, int offset, int size, SocketFlags flags)
1305 if (buf == null)
1306 throw new ArgumentNullException ("buf");
1308 if (offset < 0 || offset > buf.Length)
1309 throw new ArgumentOutOfRangeException ("offset");
1311 if (size < 0 || offset + size > buf.Length)
1312 throw new ArgumentOutOfRangeException ("size");
1314 return Receive_nochecks (buf, offset, size, flags);
1317 int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags)
1319 int ret, error;
1321 ret = Receive_internal (socket, buf, offset, size, flags, out error);
1323 if (error != 0) {
1324 connected = false;
1325 throw new SocketException (error);
1328 connected = true;
1330 return ret;
1333 public int ReceiveFrom (byte [] buf, ref EndPoint remote_end)
1335 if (buf == null)
1336 throw new ArgumentNullException ("buf");
1338 if (remote_end == null)
1339 throw new ArgumentNullException ("remote_end");
1341 return ReceiveFrom_nochecks (buf, 0, buf.Length, SocketFlags.None, ref remote_end);
1344 public int ReceiveFrom (byte [] buf, SocketFlags flags, ref EndPoint remote_end)
1346 if (buf == null)
1347 throw new ArgumentNullException ("buf");
1349 if (remote_end == null)
1350 throw new ArgumentNullException ("remote_end");
1353 return ReceiveFrom_nochecks (buf, 0, buf.Length, flags, ref remote_end);
1356 public int ReceiveFrom (byte [] buf, int size, SocketFlags flags,
1357 ref EndPoint remote_end)
1359 if (buf == null)
1360 throw new ArgumentNullException ("buf");
1362 if (remote_end == null)
1363 throw new ArgumentNullException ("remote_end");
1365 if (size < 0 || size > buf.Length)
1366 throw new ArgumentOutOfRangeException ("size");
1368 return ReceiveFrom_nochecks (buf, 0, size, flags, ref remote_end);
1372 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1373 private extern static int RecvFrom_internal(IntPtr sock,
1374 byte[] buffer,
1375 int offset,
1376 int count,
1377 SocketFlags flags,
1378 ref SocketAddress sockaddr,
1379 out int error);
1381 public int ReceiveFrom (byte [] buf, int offset, int size, SocketFlags flags,
1382 ref EndPoint remote_end)
1384 if (buf == null)
1385 throw new ArgumentNullException ("buf");
1387 if (remote_end == null)
1388 throw new ArgumentNullException ("remote_end");
1390 if (offset < 0 || offset > buf.Length)
1391 throw new ArgumentOutOfRangeException ("offset");
1393 if (size < 0 || offset + size > buf.Length)
1394 throw new ArgumentOutOfRangeException ("size");
1396 return ReceiveFrom_nochecks (buf, offset, size, flags, ref remote_end);
1399 int ReceiveFrom_nochecks (byte [] buf, int offset, int size, SocketFlags flags,
1400 ref EndPoint remote_end)
1402 SocketAddress sockaddr = remote_end.Serialize();
1403 int cnt, error;
1405 cnt = RecvFrom_internal (socket, buf, offset, size, flags, ref sockaddr, out error);
1407 if (error != 0) {
1408 connected = false;
1409 throw new SocketException (error);
1412 connected = true;
1414 // If sockaddr is null then we're a connection
1415 // oriented protocol and should ignore the
1416 // remote_end parameter (see MSDN
1417 // documentation for Socket.ReceiveFrom(...) )
1419 if ( sockaddr != null ) {
1420 // Stupidly, EndPoint.Create() is an
1421 // instance method
1422 remote_end = remote_end.Create (sockaddr);
1425 return cnt;
1428 public int Send (byte [] buf)
1430 if (buf == null)
1431 throw new ArgumentNullException ("buf");
1433 return Send_nochecks (buf, 0, buf.Length, SocketFlags.None);
1436 public int Send (byte [] buf, SocketFlags flags)
1438 if (buf == null)
1439 throw new ArgumentNullException ("buf");
1441 return Send_nochecks (buf, 0, buf.Length, flags);
1444 public int Send (byte [] buf, int size, SocketFlags flags)
1446 if (buf == null)
1447 throw new ArgumentNullException ("buf");
1449 if (size < 0 || size > buf.Length)
1450 throw new ArgumentOutOfRangeException ("size");
1452 return Send_nochecks (buf, 0, size, flags);
1455 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1456 private extern static int Send_internal(IntPtr sock,
1457 byte[] buf, int offset,
1458 int count,
1459 SocketFlags flags,
1460 out int error);
1462 public int Send (byte [] buf, int offset, int size, SocketFlags flags)
1464 if (buf == null)
1465 throw new ArgumentNullException ("buffer");
1467 if (offset < 0 || offset > buf.Length)
1468 throw new ArgumentOutOfRangeException ("offset");
1470 if (size < 0 || offset + size > buf.Length)
1471 throw new ArgumentOutOfRangeException ("size");
1473 return Send_nochecks (buf, offset, size, flags);
1476 int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags)
1478 if (size == 0)
1479 return 0;
1481 int ret, error;
1483 ret = Send_internal (socket, buf, offset, size, flags, out error);
1485 if (error != 0) {
1486 connected = false;
1487 throw new SocketException (error);
1490 connected = true;
1492 return ret;
1495 public int SendTo (byte [] buffer, EndPoint remote_end)
1497 if (buffer == null)
1498 throw new ArgumentNullException ("buffer");
1500 if (remote_end == null)
1501 throw new ArgumentNullException ("remote_end");
1503 return SendTo_nochecks (buffer, 0, buffer.Length, SocketFlags.None, remote_end);
1506 public int SendTo (byte [] buffer, SocketFlags flags, EndPoint remote_end)
1508 if (buffer == null)
1509 throw new ArgumentNullException ("buffer");
1511 if (remote_end == null)
1512 throw new ArgumentNullException ("remote_end");
1514 return SendTo_nochecks (buffer, 0, buffer.Length, flags, remote_end);
1517 public int SendTo (byte [] buffer, int size, SocketFlags flags, EndPoint remote_end)
1519 if (buffer == null)
1520 throw new ArgumentNullException ("buffer");
1522 if (remote_end == null)
1523 throw new ArgumentNullException ("remote_end");
1525 if (size < 0 || size > buffer.Length)
1526 throw new ArgumentOutOfRangeException ("size");
1528 return SendTo_nochecks (buffer, 0, size, flags, remote_end);
1532 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1533 private extern static int SendTo_internal(IntPtr sock,
1534 byte[] buffer,
1535 int offset,
1536 int count,
1537 SocketFlags flags,
1538 SocketAddress sa,
1539 out int error);
1541 public int SendTo (byte [] buffer, int offset, int size, SocketFlags flags,
1542 EndPoint remote_end)
1544 if (buffer == null)
1545 throw new ArgumentNullException ("buffer");
1547 if (remote_end == null)
1548 throw new ArgumentNullException("remote_end");
1550 if (offset < 0 || offset > buffer.Length)
1551 throw new ArgumentOutOfRangeException ("offset");
1553 if (size < 0 || offset + size > buffer.Length)
1554 throw new ArgumentOutOfRangeException ("size");
1556 return SendTo_nochecks (buffer, offset, size, flags, remote_end);
1559 int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags,
1560 EndPoint remote_end)
1562 SocketAddress sockaddr = remote_end.Serialize ();
1564 int ret, error;
1566 ret = SendTo_internal (socket, buffer, offset, size, flags, sockaddr, out error);
1568 if (error != 0) {
1569 connected = false;
1570 throw new SocketException (error);
1573 connected = true;
1575 return ret;
1578 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1579 private extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level,
1580 SocketOptionName name, object obj_val,
1581 byte [] byte_val, int int_val,
1582 out int error);
1584 public void SetSocketOption(SocketOptionLevel level,
1585 SocketOptionName name,
1586 byte[] opt_value) {
1587 int error;
1589 SetSocketOption_internal(socket, level, name, null,
1590 opt_value, 0, out error);
1592 if (error != 0) {
1593 throw new SocketException (error);
1597 public void SetSocketOption(SocketOptionLevel level,
1598 SocketOptionName name,
1599 int opt_value) {
1600 int error;
1602 SetSocketOption_internal(socket, level, name, null,
1603 null, opt_value, out error);
1605 if (error != 0) {
1606 throw new SocketException (error);
1610 public void SetSocketOption(SocketOptionLevel level,
1611 SocketOptionName name,
1612 object opt_value) {
1613 if(opt_value==null) {
1614 throw new ArgumentNullException();
1617 int error;
1619 /* Passing a bool as the third parameter to
1620 * SetSocketOption causes this overload to be
1621 * used when in fact we want to pass the value
1622 * to the runtime as an int.
1624 if (opt_value is System.Boolean) {
1625 bool bool_val = (bool) opt_value;
1626 int int_val = (bool_val) ? 1 : 0;
1628 SetSocketOption_internal (socket, level, name, null, null, int_val, out error);
1629 } else {
1630 SetSocketOption_internal (socket, level, name, opt_value, null, 0, out error);
1633 if (error != 0) {
1634 throw new SocketException (error);
1638 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1639 private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how, out int error);
1641 public void Shutdown(SocketShutdown how) {
1642 int error;
1644 Shutdown_internal(socket, how, out error);
1646 if (error != 0) {
1647 throw new SocketException (error);
1651 public override int GetHashCode ()
1653 return (int) socket;
1656 private bool disposed;
1658 protected virtual void Dispose(bool explicitDisposing) {
1659 if (!disposed) {
1660 int error;
1662 disposed = true;
1663 connected = false;
1664 if (!explicitDisposing) {
1665 closed = true;
1666 Close_internal (socket, out error);
1668 if (error != 0) {
1669 throw new SocketException (error);
1672 return;
1675 if (Interlocked.CompareExchange (ref pendingEnds, 0, 0) == 0) {
1676 closed = true;
1677 Close_internal (socket, out error);
1679 if (error != 0) {
1680 throw new SocketException (error);
1682 } else {
1683 Interlocked.CompareExchange (ref closeDelayed, 1, 0);
1688 void IDisposable.Dispose ()
1690 Dispose (true);
1691 GC.SuppressFinalize (this);
1694 ~Socket () {
1695 Dispose(false);
1698 static Hashtable asyncObjects;
1700 static void KeepReference (object o)
1702 lock (typeof (Socket)) {
1703 if (asyncObjects == null)
1704 asyncObjects = new Hashtable ();
1706 asyncObjects [o] = o;
1710 static void RemoveReference (object o)
1712 lock (typeof (Socket)) {
1713 if (asyncObjects == null)
1714 return;
1716 asyncObjects.Remove (o);
1720 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1721 extern static bool GetSupportsAsync ();
1723 static bool FakeGetSupportsAsync ()
1725 if (Environment.GetEnvironmentVariable ("MONO_ENABLE_SOCKET_AIO") != null)
1726 return GetSupportsAsync ();
1728 return false;
1731 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1732 extern static void AsyncReceiveInternal (SocketAsyncResult ares, out int error);
1734 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1735 extern static void AsyncSendInternal (SocketAsyncResult ares, out int error);