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;
29 private Exception delayedException = null;
31 public SocketAsyncResult(object state) {
33 waithandle=new ManualResetEvent(false);
34 completed_sync=completed=false;
37 public void SetDelayedException (Exception e) {
41 public void CheckIfThrowDelayedException () {
42 if (delayedException != null)
43 throw delayedException;
46 public object AsyncState {
52 public WaitHandle AsyncWaitHandle {
61 public bool CompletedSynchronously {
63 return(completed_sync);
67 public bool IsCompleted {
76 public Worker Worker {
86 private sealed class Worker
88 private AsyncCallback callback;
89 private SocketAsyncResult result;
90 private Socket socket;
93 private EndPoint endpoint; // Connect,ReceiveFrom,SendTo
94 private byte[] buffer; // Receive,ReceiveFrom,Send,SendTo
95 private int offset; // Receive,ReceiveFrom,Send,SendTo
96 private int size; // Receive,ReceiveFrom,Send,SendTo
97 private SocketFlags sockflags; // Receive,ReceiveFrom,Send,SendTo
100 private Socket acc_socket;
105 public Worker(Socket req_sock,
106 AsyncCallback req_callback,
107 SocketAsyncResult req_result)
108 : this(req_sock, null, 0, 0, SocketFlags.None,
109 null, req_callback, req_result) {}
112 public Worker(Socket req_sock, EndPoint req_endpoint,
113 AsyncCallback req_callback,
114 SocketAsyncResult req_result)
115 : this(req_sock, null, 0, 0, SocketFlags.None,
116 req_endpoint, req_callback,
119 // For Receive and Send
120 public Worker(Socket req_sock, byte[] req_buffer,
121 int req_offset, int req_size,
122 SocketFlags req_sockflags,
123 AsyncCallback req_callback,
124 SocketAsyncResult req_result)
125 : this(req_sock, req_buffer, req_offset,
126 req_size, req_sockflags, null,
127 req_callback, req_result) {}
129 // For ReceiveFrom and SendTo
130 public Worker(Socket req_sock, byte[] req_buffer,
131 int req_offset, int req_size,
132 SocketFlags req_sockflags,
133 EndPoint req_endpoint,
134 AsyncCallback req_callback,
135 SocketAsyncResult req_result) {
140 sockflags=req_sockflags;
141 endpoint=req_endpoint;
142 callback=req_callback;
147 ((ManualResetEvent)result.AsyncWaitHandle).Set();
148 result.IsCompleted=true;
149 if (callback != null)
153 public void Accept() {
155 acc_socket=socket.Accept();
160 public void Connect() {
162 if (socket.Blocking) {
164 socket.Connect(endpoint);
165 } catch (Exception e) {
166 result.SetDelayedException(e);
172 SocketException rethrow = null;
174 socket.Connect (endpoint);
175 } catch (SocketException e) {
177 if (e.NativeErrorCode != 10036)
180 socket.Poll (-1, SelectMode.SelectWrite);
182 socket.Connect (endpoint);
183 } catch (SocketException e2) {
193 public void Receive() {
195 if (socket.Blocking) {
196 total=socket.Receive(buffer, offset,
202 SocketException rethrow = null;
204 total = socket.Receive (buffer, offset, size, sockflags);
205 } catch (SocketException e) {
207 if (e.NativeErrorCode != 10035)
210 socket.Poll (-1, SelectMode.SelectRead);
212 total = socket.Receive (buffer, offset, size, sockflags);
213 } catch (SocketException e2) {
223 public void ReceiveFrom() {
225 total=socket.ReceiveFrom(buffer,
236 total=socket.Send(buffer, offset, size,
238 } catch (Exception e) {
239 result.SetDelayedException(e);
245 public void SendTo() {
248 total=socket.SendTo(buffer, offset,
251 } catch (Exception e) {
252 result.SetDelayedException(e);
258 public EndPoint EndPoint {
264 public Socket Socket {
277 /* the field "socket" is looked up by name by the runtime */
278 private IntPtr socket;
279 private AddressFamily address_family;
280 private SocketType socket_type;
281 private ProtocolType protocol_type;
282 private bool blocking=true;
285 * These two fields are looked up by name by the runtime, don't change
\r
286 * their name without also updating the runtime code.
\r
288 private static int ipv4Supported = -1, ipv6Supported = -1;
290 /* When true, the socket was connected at the time of
291 * the last IO operation
293 private bool connected=false;
295 /* Used in LocalEndPoint and RemoteEndPoint if the
296 * Mono.Posix assembly is available
298 private static object unixendpoint=null;
299 private static Type unixendpointtype=null;
301 [MethodImplAttribute(MethodImplOptions.InternalCall)]
302 private extern static void Select_internal(ref Socket[] read,
307 public static void Select(IList read_list, IList write_list,
308 IList err_list, int time_us) {
309 if(read_list==null &&
312 throw new ArgumentNullException();
315 int read_count = 0, write_count = 0, err_count = 0;
316 Socket[] read_arr = null;
317 Socket[] write_arr = null;
318 Socket[] err_arr = null;
321 read_count=read_list.Count;
324 read_arr=new Socket[read_count];
326 if (write_list!=null)
327 write_count=write_list.Count;
329 if (write_count != 0)
330 write_arr=new Socket[write_count];
333 err_count=err_list.Count;
336 err_arr=new Socket[err_count];
340 if (read_count != 0) {
343 foreach (Socket s in read_list) {
349 if (write_count != 0) {
351 foreach (Socket s in write_list) {
357 if (err_count != 0) {
359 foreach (Socket s in err_list) {
365 Select_internal(ref read_arr, ref write_arr,
366 ref err_arr, time_us);
368 if(read_list!=null) {
370 for(i=0; i<read_arr.Length; i++) {
371 read_list.Add(read_arr[i]);
375 if(write_list!=null) {
377 for(i=0; i<write_arr.Length; i++) {
378 write_list.Add(write_arr[i]);
384 for(i=0; i<err_arr.Length; i++) {
385 err_list.Add(err_arr[i]);
394 ass=Assembly.Load("Mono.Posix");
395 } catch (FileNotFoundException) {
399 unixendpointtype=ass.GetType("Mono.Posix.UnixEndPoint");
401 /* The endpoint Create() method is an instance
404 Type[] arg_types=new Type[1];
405 arg_types[0]=typeof(string);
406 ConstructorInfo cons=unixendpointtype.GetConstructor(arg_types);
408 object[] args=new object[1];
411 unixendpoint=cons.Invoke(args);
414 // private constructor used by Accept, which already
415 // has a socket handle to use
416 private Socket(AddressFamily family, SocketType type,
417 ProtocolType proto, IntPtr sock) {
418 address_family=family;
426 // Creates a new system socket, returning the handle
427 [MethodImplAttribute(MethodImplOptions.InternalCall)]
428 private extern IntPtr Socket_internal(AddressFamily family,
432 public Socket(AddressFamily family, SocketType type,
433 ProtocolType proto) {
434 address_family=family;
438 socket=Socket_internal(family, type, proto);
441 public AddressFamily AddressFamily {
443 return(address_family);
447 // Returns the amount of data waiting to be read on socket
448 [MethodImplAttribute(MethodImplOptions.InternalCall)]
449 private extern static int Available_internal(IntPtr socket);
451 public int Available {
453 return(Available_internal(socket));
457 [MethodImplAttribute(MethodImplOptions.InternalCall)]
458 private extern static void Blocking_internal(IntPtr socket,
461 public bool Blocking {
466 Blocking_internal(socket, value);
471 public bool Connected {
477 public IntPtr Handle {
483 // Returns the local endpoint details in addr and port
484 [MethodImplAttribute(MethodImplOptions.InternalCall)]
485 private extern static SocketAddress LocalEndPoint_internal(IntPtr socket);
487 [MonoTODO("Support non-IP endpoints")]
488 public EndPoint LocalEndPoint {
492 sa=LocalEndPoint_internal(socket);
494 if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6) {
495 // Stupidly, EndPoint.Create() is an
497 return new IPEndPoint(0, 0).Create(sa);
498 } else if (sa.Family==AddressFamily.Unix &&
499 unixendpoint!=null) {
500 return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
502 throw new NotImplementedException();
507 public ProtocolType ProtocolType {
509 return(protocol_type);
513 // Returns the remote endpoint details in addr and port
514 [MethodImplAttribute(MethodImplOptions.InternalCall)]
515 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket);
517 [MonoTODO("Support non-IP endpoints")]
518 public EndPoint RemoteEndPoint {
522 sa=RemoteEndPoint_internal(socket);
524 if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6 ) {
525 // Stupidly, EndPoint.Create() is an
527 return new IPEndPoint(0, 0).Create(sa);
528 } else if (sa.Family==AddressFamily.Unix &&
529 unixendpoint!=null) {
530 return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
532 throw new NotImplementedException();
537 public SocketType SocketType {
544 public static bool SupportsIPv4 {
\r
546 CheckProtocolSupport();
\r
547 return ipv4Supported == 1;
\r
551 public static bool SupportsIPv6 {
\r
553 CheckProtocolSupport();
\r
554 return ipv6Supported == 1;
\r
558 internal static bool SupportsIPv4
\r
566 internal static bool SupportsIPv6
\r
575 internal static void CheckProtocolSupport()
577 if(ipv4Supported == -1) {
\r
579 Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
\r
589 if(ipv6Supported == -1) {
\r
590 NetConfig config = (NetConfig)System.Configuration.ConfigurationSettings.GetConfig("system.net/settings");
\r
593 ipv6Supported = config.ipv6Enabled?-1:0;
\r
595 if(ipv6Supported != 0) {
\r
597 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
\r
607 // Creates a new system socket, returning the handle
608 [MethodImplAttribute(MethodImplOptions.InternalCall)]
609 private extern static IntPtr Accept_internal(IntPtr sock);
611 public Socket Accept() {
612 IntPtr sock=Accept_internal(socket);
614 return(new Socket(this.AddressFamily, this.SocketType,
615 this.ProtocolType, sock));
618 public IAsyncResult BeginAccept(AsyncCallback callback,
620 SocketAsyncResult req=new SocketAsyncResult(state);
621 Worker worker=new Worker(this, callback, req);
623 Thread child=new Thread(new ThreadStart(worker.Accept));
628 public IAsyncResult BeginConnect(EndPoint end_point,
629 AsyncCallback callback,
631 SocketAsyncResult req=new SocketAsyncResult(state);
632 Worker worker=new Worker(this, end_point, callback,
635 Thread child=new Thread(new ThreadStart(worker.Connect));
640 public IAsyncResult BeginReceive(byte[] buffer, int offset,
642 SocketFlags socket_flags,
643 AsyncCallback callback,
645 SocketAsyncResult req=new SocketAsyncResult(state);
646 Worker worker=new Worker(this, buffer, offset, size,
647 socket_flags, callback, req);
649 Thread child=new Thread(new ThreadStart(worker.Receive));
654 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
656 SocketFlags socket_flags,
657 ref EndPoint remote_end,
658 AsyncCallback callback,
660 SocketAsyncResult req=new SocketAsyncResult(state);
661 Worker worker=new Worker(this, buffer, offset, size,
662 socket_flags, remote_end,
665 Thread child=new Thread(new ThreadStart(worker.ReceiveFrom));
670 public IAsyncResult BeginSend(byte[] buffer, int offset,
672 SocketFlags socket_flags,
673 AsyncCallback callback,
675 SocketAsyncResult req=new SocketAsyncResult(state);
676 Worker worker=new Worker(this, buffer, offset, size,
677 socket_flags, callback, req);
679 Thread child=new Thread(new ThreadStart(worker.Send));
684 public IAsyncResult BeginSendTo(byte[] buffer, int offset,
686 SocketFlags socket_flags,
688 AsyncCallback callback,
690 SocketAsyncResult req=new SocketAsyncResult(state);
691 Worker worker=new Worker(this, buffer, offset, size,
692 socket_flags, remote_end,
695 Thread child=new Thread(new ThreadStart(worker.SendTo));
700 // Creates a new system socket, returning the handle
701 [MethodImplAttribute(MethodImplOptions.InternalCall)]
702 private extern static void Bind_internal(IntPtr sock,
705 public void Bind(EndPoint local_end) {
706 if(local_end==null) {
707 throw new ArgumentNullException();
710 Bind_internal(socket, local_end.Serialize());
714 [MethodImplAttribute(MethodImplOptions.InternalCall)]
715 private extern static void Close_internal(IntPtr socket);
717 public void Close() {
721 // Connects to the remote address
722 [MethodImplAttribute(MethodImplOptions.InternalCall)]
723 private extern static void Connect_internal(IntPtr sock,
726 public void Connect(EndPoint remote_end) {
727 if(remote_end==null) {
728 throw new ArgumentNullException();
731 Connect_internal(socket, remote_end.Serialize());
735 public Socket EndAccept(IAsyncResult result) {
736 SocketAsyncResult req=(SocketAsyncResult)result;
738 result.AsyncWaitHandle.WaitOne();
739 return(req.Worker.Socket);
742 public void EndConnect(IAsyncResult result) {
743 SocketAsyncResult req=(SocketAsyncResult)result;
745 result.AsyncWaitHandle.WaitOne();
746 req.CheckIfThrowDelayedException();
749 public int EndReceive(IAsyncResult result) {
750 SocketAsyncResult req=(SocketAsyncResult)result;
752 result.AsyncWaitHandle.WaitOne();
753 return(req.Worker.Total);
756 public int EndReceiveFrom(IAsyncResult result,
757 ref EndPoint end_point) {
758 SocketAsyncResult req=(SocketAsyncResult)result;
760 result.AsyncWaitHandle.WaitOne();
761 end_point=req.Worker.EndPoint;
762 return(req.Worker.Total);
765 public int EndSend(IAsyncResult result) {
766 SocketAsyncResult req=(SocketAsyncResult)result;
768 result.AsyncWaitHandle.WaitOne();
769 req.CheckIfThrowDelayedException();
770 return(req.Worker.Total);
773 public int EndSendTo(IAsyncResult result) {
774 SocketAsyncResult req=(SocketAsyncResult)result;
776 result.AsyncWaitHandle.WaitOne();
777 req.CheckIfThrowDelayedException();
778 return(req.Worker.Total);
781 [MethodImplAttribute(MethodImplOptions.InternalCall)]
782 private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val);
783 [MethodImplAttribute(MethodImplOptions.InternalCall)]
784 private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val);
786 public object GetSocketOption(SocketOptionLevel level,
787 SocketOptionName name) {
790 GetSocketOption_obj_internal(socket, level, name,
793 if(name==SocketOptionName.Linger) {
794 return((LingerOption)obj_val);
795 } else if (name==SocketOptionName.AddMembership ||
796 name==SocketOptionName.DropMembership) {
797 return((MulticastOption)obj_val);
799 return((int)obj_val);
803 public void GetSocketOption(SocketOptionLevel level,
804 SocketOptionName name,
806 int opt_value_len=opt_value.Length;
808 GetSocketOption_arr_internal(socket, level, name,
812 public byte[] GetSocketOption(SocketOptionLevel level,
813 SocketOptionName name,
815 byte[] byte_val=new byte[length];
817 GetSocketOption_arr_internal(socket, level, name,
823 [MonoTODO("Totally undocumented")]
824 public int IOControl(int ioctl_code, byte[] in_value,
826 throw new NotImplementedException();
829 [MethodImplAttribute(MethodImplOptions.InternalCall)]
830 private extern static void Listen_internal(IntPtr sock,
833 public void Listen(int backlog) {
834 Listen_internal(socket, backlog);
837 /* The docs for Poll() are a bit lightweight too, but
838 * it seems to be just a simple wrapper around Select.
840 public bool Poll(int time_us, SelectMode mode) {
841 Socket [] socketlist = new Socket []{this};
845 case SelectMode.SelectError:
846 Select_internal (ref n, ref n, ref socketlist, time_us);
848 case SelectMode.SelectRead:
849 Select_internal (ref socketlist, ref n, ref n, time_us);
851 case SelectMode.SelectWrite:
852 Select_internal (ref n, ref socketlist, ref n, time_us);
855 throw new NotSupportedException();
858 return (socketlist.Length == 1);
861 public int Receive(byte[] buf) {
862 return(Receive(buf, 0, buf.Length, SocketFlags.None));
865 public int Receive(byte[] buf, SocketFlags flags) {
866 return(Receive(buf, 0, buf.Length, flags));
869 public int Receive(byte[] buf, int size, SocketFlags flags) {
870 return(Receive(buf, 0, size, flags));
873 [MethodImplAttribute(MethodImplOptions.InternalCall)]
874 private extern static int Receive_internal(IntPtr sock,
880 public int Receive(byte[] buf, int offset, int size,
883 throw new ArgumentNullException("buffer is null");
885 if(offset<0 || offset > buf.Length) {
886 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
888 if(size<0 || offset+size > buf.Length) {
889 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
895 ret=Receive_internal(socket, buf, offset,
897 } catch(SocketException) {
906 public int ReceiveFrom(byte[] buf, ref EndPoint remote_end) {
907 return(ReceiveFrom(buf, 0, buf.Length,
908 SocketFlags.None, ref remote_end));
911 public int ReceiveFrom(byte[] buf, SocketFlags flags,
912 ref EndPoint remote_end) {
913 return(ReceiveFrom(buf, 0, buf.Length, flags,
917 public int ReceiveFrom(byte[] buf, int size, SocketFlags flags,
918 ref EndPoint remote_end) {
919 return(ReceiveFrom(buf, 0, size, flags,
924 [MethodImplAttribute(MethodImplOptions.InternalCall)]
925 private extern static int RecvFrom_internal(IntPtr sock,
930 ref SocketAddress sockaddr);
932 public int ReceiveFrom(byte[] buf, int offset, int size,
934 ref EndPoint remote_end) {
936 throw new ArgumentNullException("buffer is null");
938 if(remote_end==null) {
939 throw new ArgumentNullException("remote endpoint is null");
941 if(offset<0 || offset>buf.Length) {
942 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
944 if(size<0 || offset+size>buf.Length) {
945 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
948 SocketAddress sockaddr=remote_end.Serialize();
952 count=RecvFrom_internal(socket, buf, offset,
955 } catch(SocketException) {
961 // Stupidly, EndPoint.Create() is an
963 remote_end=remote_end.Create(sockaddr);
968 public int Send(byte[] buf) {
969 return(Send(buf, 0, buf.Length, SocketFlags.None));
972 public int Send(byte[] buf, SocketFlags flags) {
973 return(Send(buf, 0, buf.Length, flags));
976 public int Send(byte[] buf, int size, SocketFlags flags) {
977 return(Send(buf, 0, size, flags));
980 [MethodImplAttribute(MethodImplOptions.InternalCall)]
981 private extern static int Send_internal(IntPtr sock,
982 byte[] buf, int offset,
986 public int Send (byte[] buf, int offset, int size, SocketFlags flags)
989 throw new ArgumentNullException ("buffer");
991 if (offset < 0 || offset > buf.Length)
992 throw new ArgumentOutOfRangeException ("offset");
994 if (size < 0 || offset + size > buf.Length)
995 throw new ArgumentOutOfRangeException ("size");
1003 ret = Send_internal (socket, buf, offset, size, flags);
1004 } catch (SocketException) {
1013 public int SendTo(byte[] buffer, EndPoint remote_end) {
1014 return(SendTo(buffer, 0, buffer.Length,
1015 SocketFlags.None, remote_end));
1018 public int SendTo(byte[] buffer, SocketFlags flags,
1019 EndPoint remote_end) {
1020 return(SendTo(buffer, 0, buffer.Length, flags,
1024 public int SendTo(byte[] buffer, int size, SocketFlags flags,
1025 EndPoint remote_end) {
1026 return(SendTo(buffer, 0, size, flags, remote_end));
1030 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1031 private extern static int SendTo_internal(IntPtr sock,
1038 public int SendTo(byte[] buffer, int offset, int size,
1039 SocketFlags flags, EndPoint remote_end) {
1041 throw new ArgumentNullException("buffer is null");
1043 if(remote_end==null) {
1044 throw new ArgumentNullException("remote endpoint is null");
1046 if(offset<0 || offset>buffer.Length) {
1047 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
1049 if(size<0 || offset+size>buffer.Length) {
1050 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
1053 SocketAddress sockaddr=remote_end.Serialize();
1058 ret=SendTo_internal(socket, buffer, offset,
1059 size, flags, sockaddr);
1061 catch(SocketException) {
1070 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1071 private extern static void SetSocketOption_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte[] byte_val, int int_val);
1073 public void SetSocketOption(SocketOptionLevel level,
1074 SocketOptionName name,
1076 SetSocketOption_internal(socket, level, name, null,
1080 public void SetSocketOption(SocketOptionLevel level,
1081 SocketOptionName name,
1083 SetSocketOption_internal(socket, level, name, null,
1087 public void SetSocketOption(SocketOptionLevel level,
1088 SocketOptionName name,
1090 if(opt_value==null) {
1091 throw new ArgumentNullException();
1094 /* Passing a bool as the third parameter to
1095 * SetSocketOption causes this overload to be
1096 * used when in fact we want to pass the value
1097 * to the runtime as an int.
1099 if(opt_value is System.Boolean) {
1100 bool bool_val=(bool)opt_value;
1102 /* Stupid casting rules :-( */
1103 if(bool_val==true) {
1104 SetSocketOption_internal(socket, level,
1108 SetSocketOption_internal(socket, level,
1113 SetSocketOption_internal(socket, level, name,
1114 opt_value, null, 0);
1118 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1119 private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how);
1121 public void Shutdown(SocketShutdown how) {
1122 Shutdown_internal(socket, how);
1125 public override int GetHashCode ()
1127 return (int) socket;
1130 private bool disposed = false;
1132 protected virtual void Dispose(bool explicitDisposing) {
1133 // Check to see if Dispose has already been called
1134 if(!this.disposed) {
1135 // If this is a call to Dispose,
1136 // dispose all managed resources.
1137 if(explicitDisposing) {
1138 // Free up stuff here
1141 // Release unmanaged resources
1145 Close_internal(socket);
1149 public void Dispose() {
1151 // Take yourself off the Finalization queue
1152 GC.SuppressFinalize(this);