1 // System.Net.Sockets.Socket.cs
4 // Phillip Pearson (pp@myelin.co.nz)
5 // Dick Porter <dick@ximian.com>
7 // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
8 // http://www.myelin.co.nz
13 using System.Collections;
14 using System.Runtime.CompilerServices;
15 using System.Threading;
16 using System.Reflection;
19 namespace System.Net.Sockets
21 public class Socket : IDisposable
23 private sealed class SocketAsyncResult: IAsyncResult
26 private WaitHandle waithandle;
27 private bool completed_sync, completed;
28 private Worker worker;
30 public SocketAsyncResult(object state) {
32 waithandle=new ManualResetEvent(false);
33 completed_sync=completed=false;
36 public object AsyncState {
42 public WaitHandle AsyncWaitHandle {
51 public bool CompletedSynchronously {
53 return(completed_sync);
57 public bool IsCompleted {
66 public Worker Worker {
76 private sealed class Worker
78 private AsyncCallback callback;
79 private SocketAsyncResult result;
80 private Socket socket;
83 private EndPoint endpoint; // Connect,ReceiveFrom,SendTo
84 private byte[] buffer; // Receive,ReceiveFrom,Send,SendTo
85 private int offset; // Receive,ReceiveFrom,Send,SendTo
86 private int size; // Receive,ReceiveFrom,Send,SendTo
87 private SocketFlags sockflags; // Receive,ReceiveFrom,Send,SendTo
90 private Socket acc_socket;
95 public Worker(Socket req_sock,
96 AsyncCallback req_callback,
97 SocketAsyncResult req_result)
98 : this(req_sock, null, 0, 0, SocketFlags.None,
99 null, req_callback, req_result) {}
102 public Worker(Socket req_sock, EndPoint req_endpoint,
103 AsyncCallback req_callback,
104 SocketAsyncResult req_result)
105 : this(req_sock, null, 0, 0, SocketFlags.None,
106 req_endpoint, req_callback,
109 // For Receive and Send
110 public Worker(Socket req_sock, byte[] req_buffer,
111 int req_offset, int req_size,
112 SocketFlags req_sockflags,
113 AsyncCallback req_callback,
114 SocketAsyncResult req_result)
115 : this(req_sock, req_buffer, req_offset,
116 req_size, req_sockflags, null,
117 req_callback, req_result) {}
119 // For ReceiveFrom and SendTo
120 public Worker(Socket req_sock, byte[] req_buffer,
121 int req_offset, int req_size,
122 SocketFlags req_sockflags,
123 EndPoint req_endpoint,
124 AsyncCallback req_callback,
125 SocketAsyncResult req_result) {
130 sockflags=req_sockflags;
131 endpoint=req_endpoint;
132 callback=req_callback;
137 ((ManualResetEvent)result.AsyncWaitHandle).Set();
138 result.IsCompleted=true;
139 if (callback != null)
143 public void Accept() {
145 acc_socket=socket.Accept();
150 public void Connect() {
152 if (socket.Blocking) {
153 socket.Connect(endpoint);
158 SocketException rethrow = null;
160 socket.Connect (endpoint);
161 } catch (SocketException e) {
163 if (e.NativeErrorCode != 10036)
166 socket.Poll (-1, SelectMode.SelectWrite);
168 socket.Connect (endpoint);
169 } catch (SocketException e2) {
179 public void Receive() {
181 if (socket.Blocking) {
182 total=socket.Receive(buffer, offset,
188 SocketException rethrow = null;
190 total = socket.Receive (buffer, offset, size, sockflags);
191 } catch (SocketException e) {
193 if (e.NativeErrorCode != 10035)
196 socket.Poll (-1, SelectMode.SelectRead);
198 total = socket.Receive (buffer, offset, size, sockflags);
199 } catch (SocketException e2) {
209 public void ReceiveFrom() {
211 total=socket.ReceiveFrom(buffer,
221 total=socket.Send(buffer, offset, size,
227 public void SendTo() {
229 total=socket.SendTo(buffer, offset,
236 public EndPoint EndPoint {
242 public Socket Socket {
255 /* the field "socket" is looked up by name by the runtime */
256 private IntPtr socket;
257 private AddressFamily address_family;
258 private SocketType socket_type;
259 private ProtocolType protocol_type;
260 private bool blocking=true;
263 * These two fields are looked up by name by the runtime, don't change
\r
264 * their name without also updating the runtime code.
\r
266 private static int ipv4Supported = -1, ipv6Supported = -1;
268 /* When true, the socket was connected at the time of
269 * the last IO operation
271 private bool connected=false;
273 /* Used in LocalEndPoint and RemoteEndPoint if the
274 * Mono.Posix assembly is available
276 private static object unixendpoint=null;
277 private static Type unixendpointtype=null;
279 [MethodImplAttribute(MethodImplOptions.InternalCall)]
280 private extern static void Select_internal(ref Socket[] read,
285 public static void Select(IList read_list, IList write_list,
286 IList err_list, int time_us) {
287 if(read_list==null &&
290 throw new ArgumentNullException();
293 int read_count = 0, write_count = 0, err_count = 0;
294 Socket[] read_arr = null;
295 Socket[] write_arr = null;
296 Socket[] err_arr = null;
299 read_count=read_list.Count;
302 read_arr=new Socket[read_count];
304 if (write_list!=null)
305 write_count=write_list.Count;
307 if (write_count != 0)
308 write_arr=new Socket[write_count];
311 err_count=err_list.Count;
314 err_arr=new Socket[err_count];
318 if (read_count != 0) {
321 foreach (Socket s in read_list) {
327 if (write_count != 0) {
329 foreach (Socket s in write_list) {
335 if (err_count != 0) {
337 foreach (Socket s in err_list) {
343 Select_internal(ref read_arr, ref write_arr,
344 ref err_arr, time_us);
346 if(read_list!=null) {
348 for(i=0; i<read_arr.Length; i++) {
349 read_list.Add(read_arr[i]);
353 if(write_list!=null) {
355 for(i=0; i<write_arr.Length; i++) {
356 write_list.Add(write_arr[i]);
362 for(i=0; i<err_arr.Length; i++) {
363 err_list.Add(err_arr[i]);
372 ass=Assembly.Load("Mono.Posix");
373 } catch (FileNotFoundException) {
377 unixendpointtype=ass.GetType("Mono.Posix.UnixEndPoint");
379 /* The endpoint Create() method is an instance
382 Type[] arg_types=new Type[1];
383 arg_types[0]=typeof(string);
384 ConstructorInfo cons=unixendpointtype.GetConstructor(arg_types);
386 object[] args=new object[1];
389 unixendpoint=cons.Invoke(args);
392 // private constructor used by Accept, which already
393 // has a socket handle to use
394 private Socket(AddressFamily family, SocketType type,
395 ProtocolType proto, IntPtr sock) {
396 address_family=family;
404 // Creates a new system socket, returning the handle
405 [MethodImplAttribute(MethodImplOptions.InternalCall)]
406 private extern IntPtr Socket_internal(AddressFamily family,
410 public Socket(AddressFamily family, SocketType type,
411 ProtocolType proto) {
412 address_family=family;
416 socket=Socket_internal(family, type, proto);
419 public AddressFamily AddressFamily {
421 return(address_family);
425 // Returns the amount of data waiting to be read on socket
426 [MethodImplAttribute(MethodImplOptions.InternalCall)]
427 private extern static int Available_internal(IntPtr socket);
429 public int Available {
431 return(Available_internal(socket));
435 [MethodImplAttribute(MethodImplOptions.InternalCall)]
436 private extern static void Blocking_internal(IntPtr socket,
439 public bool Blocking {
444 Blocking_internal(socket, value);
449 public bool Connected {
455 public IntPtr Handle {
461 // Returns the local endpoint details in addr and port
462 [MethodImplAttribute(MethodImplOptions.InternalCall)]
463 private extern static SocketAddress LocalEndPoint_internal(IntPtr socket);
465 [MonoTODO("Support non-IP endpoints")]
466 public EndPoint LocalEndPoint {
470 sa=LocalEndPoint_internal(socket);
472 if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6) {
473 // Stupidly, EndPoint.Create() is an
475 return new IPEndPoint(0, 0).Create(sa);
476 } else if (sa.Family==AddressFamily.Unix &&
477 unixendpoint!=null) {
478 return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
480 throw new NotImplementedException();
485 public ProtocolType ProtocolType {
487 return(protocol_type);
491 // Returns the remote endpoint details in addr and port
492 [MethodImplAttribute(MethodImplOptions.InternalCall)]
493 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket);
495 [MonoTODO("Support non-IP endpoints")]
496 public EndPoint RemoteEndPoint {
500 sa=RemoteEndPoint_internal(socket);
502 if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6 ) {
503 // Stupidly, EndPoint.Create() is an
505 return new IPEndPoint(0, 0).Create(sa);
506 } else if (sa.Family==AddressFamily.Unix &&
507 unixendpoint!=null) {
508 return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
510 throw new NotImplementedException();
515 public SocketType SocketType {
522 public static bool SupportsIPv4 {
\r
524 CheckProtocolSupport();
\r
525 return ipv4Supported == 1;
\r
529 public static bool SupportsIPv6 {
\r
531 CheckProtocolSupport();
\r
532 return ipv6Supported == 1;
\r
536 internal static bool SupportsIPv4
\r
544 internal static bool SupportsIPv6
\r
553 internal static void CheckProtocolSupport()
555 if(ipv4Supported == -1) {
\r
557 Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
\r
567 if(ipv6Supported == -1) {
\r
568 NetConfig config = (NetConfig)System.Configuration.ConfigurationSettings.GetConfig("system.net/settings");
\r
571 ipv6Supported = config.ipv6Enabled?-1:0;
\r
573 if(ipv6Supported != 0) {
\r
575 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
\r
585 // Creates a new system socket, returning the handle
586 [MethodImplAttribute(MethodImplOptions.InternalCall)]
587 private extern static IntPtr Accept_internal(IntPtr sock);
589 public Socket Accept() {
590 IntPtr sock=Accept_internal(socket);
592 return(new Socket(this.AddressFamily, this.SocketType,
593 this.ProtocolType, sock));
596 public IAsyncResult BeginAccept(AsyncCallback callback,
598 SocketAsyncResult req=new SocketAsyncResult(state);
599 Worker worker=new Worker(this, callback, req);
601 Thread child=new Thread(new ThreadStart(worker.Accept));
606 public IAsyncResult BeginConnect(EndPoint end_point,
607 AsyncCallback callback,
609 SocketAsyncResult req=new SocketAsyncResult(state);
610 Worker worker=new Worker(this, end_point, callback,
613 Thread child=new Thread(new ThreadStart(worker.Connect));
618 public IAsyncResult BeginReceive(byte[] buffer, int offset,
620 SocketFlags socket_flags,
621 AsyncCallback callback,
623 SocketAsyncResult req=new SocketAsyncResult(state);
624 Worker worker=new Worker(this, buffer, offset, size,
625 socket_flags, callback, req);
627 Thread child=new Thread(new ThreadStart(worker.Receive));
632 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
634 SocketFlags socket_flags,
635 ref EndPoint remote_end,
636 AsyncCallback callback,
638 SocketAsyncResult req=new SocketAsyncResult(state);
639 Worker worker=new Worker(this, buffer, offset, size,
640 socket_flags, remote_end,
643 Thread child=new Thread(new ThreadStart(worker.ReceiveFrom));
648 public IAsyncResult BeginSend(byte[] buffer, int offset,
650 SocketFlags socket_flags,
651 AsyncCallback callback,
653 SocketAsyncResult req=new SocketAsyncResult(state);
654 Worker worker=new Worker(this, buffer, offset, size,
655 socket_flags, callback, req);
657 Thread child=new Thread(new ThreadStart(worker.Send));
662 public IAsyncResult BeginSendTo(byte[] buffer, int offset,
664 SocketFlags socket_flags,
666 AsyncCallback callback,
668 SocketAsyncResult req=new SocketAsyncResult(state);
669 Worker worker=new Worker(this, buffer, offset, size,
670 socket_flags, remote_end,
673 Thread child=new Thread(new ThreadStart(worker.SendTo));
678 // Creates a new system socket, returning the handle
679 [MethodImplAttribute(MethodImplOptions.InternalCall)]
680 private extern static void Bind_internal(IntPtr sock,
683 public void Bind(EndPoint local_end) {
684 if(local_end==null) {
685 throw new ArgumentNullException();
688 Bind_internal(socket, local_end.Serialize());
692 [MethodImplAttribute(MethodImplOptions.InternalCall)]
693 private extern static void Close_internal(IntPtr socket);
695 public void Close() {
699 // Connects to the remote address
700 [MethodImplAttribute(MethodImplOptions.InternalCall)]
701 private extern static void Connect_internal(IntPtr sock,
704 public void Connect(EndPoint remote_end) {
705 if(remote_end==null) {
706 throw new ArgumentNullException();
709 Connect_internal(socket, remote_end.Serialize());
713 public Socket EndAccept(IAsyncResult result) {
714 SocketAsyncResult req=(SocketAsyncResult)result;
716 result.AsyncWaitHandle.WaitOne();
717 return(req.Worker.Socket);
720 public void EndConnect(IAsyncResult result) {
721 SocketAsyncResult req=(SocketAsyncResult)result;
723 result.AsyncWaitHandle.WaitOne();
726 public int EndReceive(IAsyncResult result) {
727 SocketAsyncResult req=(SocketAsyncResult)result;
729 result.AsyncWaitHandle.WaitOne();
730 return(req.Worker.Total);
733 public int EndReceiveFrom(IAsyncResult result,
734 ref EndPoint end_point) {
735 SocketAsyncResult req=(SocketAsyncResult)result;
737 result.AsyncWaitHandle.WaitOne();
738 end_point=req.Worker.EndPoint;
739 return(req.Worker.Total);
742 public int EndSend(IAsyncResult result) {
743 SocketAsyncResult req=(SocketAsyncResult)result;
745 result.AsyncWaitHandle.WaitOne();
746 return(req.Worker.Total);
749 public int EndSendTo(IAsyncResult result) {
750 SocketAsyncResult req=(SocketAsyncResult)result;
752 result.AsyncWaitHandle.WaitOne();
753 return(req.Worker.Total);
756 [MethodImplAttribute(MethodImplOptions.InternalCall)]
757 private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val);
758 [MethodImplAttribute(MethodImplOptions.InternalCall)]
759 private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val);
761 public object GetSocketOption(SocketOptionLevel level,
762 SocketOptionName name) {
765 GetSocketOption_obj_internal(socket, level, name,
768 if(name==SocketOptionName.Linger) {
769 return((LingerOption)obj_val);
770 } else if (name==SocketOptionName.AddMembership ||
771 name==SocketOptionName.DropMembership) {
772 return((MulticastOption)obj_val);
774 return((int)obj_val);
778 public void GetSocketOption(SocketOptionLevel level,
779 SocketOptionName name,
781 int opt_value_len=opt_value.Length;
783 GetSocketOption_arr_internal(socket, level, name,
787 public byte[] GetSocketOption(SocketOptionLevel level,
788 SocketOptionName name,
790 byte[] byte_val=new byte[length];
792 GetSocketOption_arr_internal(socket, level, name,
798 [MonoTODO("Totally undocumented")]
799 public int IOControl(int ioctl_code, byte[] in_value,
801 throw new NotImplementedException();
804 [MethodImplAttribute(MethodImplOptions.InternalCall)]
805 private extern static void Listen_internal(IntPtr sock,
808 public void Listen(int backlog) {
809 Listen_internal(socket, backlog);
812 /* The docs for Poll() are a bit lightweight too, but
813 * it seems to be just a simple wrapper around Select.
815 public bool Poll(int time_us, SelectMode mode) {
816 Socket [] socketlist = new Socket []{this};
820 case SelectMode.SelectError:
821 Select_internal (ref n, ref n, ref socketlist, time_us);
823 case SelectMode.SelectRead:
824 Select_internal (ref socketlist, ref n, ref n, time_us);
826 case SelectMode.SelectWrite:
827 Select_internal (ref n, ref socketlist, ref n, time_us);
830 throw new NotSupportedException();
833 return (socketlist.Length == 1);
836 public int Receive(byte[] buf) {
837 return(Receive(buf, 0, buf.Length, SocketFlags.None));
840 public int Receive(byte[] buf, SocketFlags flags) {
841 return(Receive(buf, 0, buf.Length, flags));
844 public int Receive(byte[] buf, int size, SocketFlags flags) {
845 return(Receive(buf, 0, size, flags));
848 [MethodImplAttribute(MethodImplOptions.InternalCall)]
849 private extern static int Receive_internal(IntPtr sock,
855 public int Receive(byte[] buf, int offset, int size,
858 throw new ArgumentNullException("buffer is null");
860 if(offset<0 || offset >= buf.Length) {
861 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
863 if(offset+size<0 || offset+size > buf.Length) {
864 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
870 ret=Receive_internal(socket, buf, offset,
872 } catch(SocketException) {
881 public int ReceiveFrom(byte[] buf, ref EndPoint remote_end) {
882 return(ReceiveFrom(buf, 0, buf.Length,
883 SocketFlags.None, ref remote_end));
886 public int ReceiveFrom(byte[] buf, SocketFlags flags,
887 ref EndPoint remote_end) {
888 return(ReceiveFrom(buf, 0, buf.Length, flags,
892 public int ReceiveFrom(byte[] buf, int size, SocketFlags flags,
893 ref EndPoint remote_end) {
894 return(ReceiveFrom(buf, 0, size, flags,
899 [MethodImplAttribute(MethodImplOptions.InternalCall)]
900 private extern static int RecvFrom_internal(IntPtr sock,
905 ref SocketAddress sockaddr);
907 public int ReceiveFrom(byte[] buf, int offset, int size,
909 ref EndPoint remote_end) {
911 throw new ArgumentNullException("buffer is null");
913 if(remote_end==null) {
914 throw new ArgumentNullException("remote endpoint is null");
916 if(offset<0 || offset>=buf.Length) {
917 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
919 if(offset+size<0 || offset+size>buf.Length) {
920 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
923 SocketAddress sockaddr=remote_end.Serialize();
927 count=RecvFrom_internal(socket, buf, offset,
930 } catch(SocketException) {
936 // Stupidly, EndPoint.Create() is an
938 remote_end=remote_end.Create(sockaddr);
943 public int Send(byte[] buf) {
944 return(Send(buf, 0, buf.Length, SocketFlags.None));
947 public int Send(byte[] buf, SocketFlags flags) {
948 return(Send(buf, 0, buf.Length, flags));
951 public int Send(byte[] buf, int size, SocketFlags flags) {
952 return(Send(buf, 0, size, flags));
955 [MethodImplAttribute(MethodImplOptions.InternalCall)]
956 private extern static int Send_internal(IntPtr sock,
957 byte[] buf, int offset,
961 public int Send (byte[] buf, int offset, int size, SocketFlags flags)
964 throw new ArgumentNullException ("buffer");
966 if (offset < 0 || offset > buf.Length)
967 throw new ArgumentOutOfRangeException ("offset");
969 if (size < 0 || offset + size > buf.Length)
970 throw new ArgumentOutOfRangeException ("size");
978 ret = Send_internal (socket, buf, offset, size, flags);
979 } catch (SocketException) {
988 public int SendTo(byte[] buffer, EndPoint remote_end) {
989 return(SendTo(buffer, 0, buffer.Length,
990 SocketFlags.None, remote_end));
993 public int SendTo(byte[] buffer, SocketFlags flags,
994 EndPoint remote_end) {
995 return(SendTo(buffer, 0, buffer.Length, flags,
999 public int SendTo(byte[] buffer, int size, SocketFlags flags,
1000 EndPoint remote_end) {
1001 return(SendTo(buffer, 0, size, flags, remote_end));
1005 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1006 private extern static int SendTo_internal(IntPtr sock,
1013 public int SendTo(byte[] buffer, int offset, int size,
1014 SocketFlags flags, EndPoint remote_end) {
1016 throw new ArgumentNullException("buffer is null");
1018 if(remote_end==null) {
1019 throw new ArgumentNullException("remote endpoint is null");
1021 if(offset<0 || offset>=buffer.Length) {
1022 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
1024 if(offset+size<0 || offset+size>buffer.Length) {
1025 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
1028 SocketAddress sockaddr=remote_end.Serialize();
1033 ret=SendTo_internal(socket, buffer, offset,
1034 size, flags, sockaddr);
1036 catch(SocketException) {
1045 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1046 private extern static void SetSocketOption_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte[] byte_val, int int_val);
1048 public void SetSocketOption(SocketOptionLevel level,
1049 SocketOptionName name,
1051 SetSocketOption_internal(socket, level, name, null,
1055 public void SetSocketOption(SocketOptionLevel level,
1056 SocketOptionName name,
1058 SetSocketOption_internal(socket, level, name, null,
1062 public void SetSocketOption(SocketOptionLevel level,
1063 SocketOptionName name,
1065 if(opt_value==null) {
1066 throw new ArgumentNullException();
1069 /* Passing a bool as the third parameter to
1070 * SetSocketOption causes this overload to be
1071 * used when in fact we want to pass the value
1072 * to the runtime as an int.
1074 if(opt_value is System.Boolean) {
1075 bool bool_val=(bool)opt_value;
1077 /* Stupid casting rules :-( */
1078 if(bool_val==true) {
1079 SetSocketOption_internal(socket, level,
1083 SetSocketOption_internal(socket, level,
1088 SetSocketOption_internal(socket, level, name,
1089 opt_value, null, 0);
1093 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1094 private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how);
1096 public void Shutdown(SocketShutdown how) {
1097 Shutdown_internal(socket, how);
1100 private bool disposed = false;
1102 protected virtual void Dispose(bool explicitDisposing) {
1103 // Check to see if Dispose has already been called
1104 if(!this.disposed) {
1105 // If this is a call to Dispose,
1106 // dispose all managed resources.
1107 if(explicitDisposing) {
1108 // Free up stuff here
1111 // Release unmanaged resources
1115 Close_internal(socket);
1119 public void Dispose() {
1121 // Take yourself off the Finalization queue
1122 GC.SuppressFinalize(this);