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;
262 /* When true, the socket was connected at the time of
263 * the last IO operation
265 private bool connected=false;
267 /* Used in LocalEndPoint and RemoteEndPoint if the
268 * Mono.Posix assembly is available
270 private static object unixendpoint=null;
271 private static Type unixendpointtype=null;
273 [MethodImplAttribute(MethodImplOptions.InternalCall)]
274 private extern static void Select_internal(ref Socket[] read,
279 public static void Select(IList read_list, IList write_list,
280 IList err_list, int time_us) {
281 if(read_list==null &&
284 throw new ArgumentNullException();
287 int read_count = 0, write_count = 0, err_count = 0;
288 Socket[] read_arr = null;
289 Socket[] write_arr = null;
290 Socket[] err_arr = null;
293 read_count=read_list.Count;
296 read_arr=new Socket[read_count];
298 if (write_list!=null)
299 write_count=write_list.Count;
301 if (write_count != 0)
302 write_arr=new Socket[write_count];
305 err_count=err_list.Count;
308 err_arr=new Socket[err_count];
312 if (read_count != 0) {
315 foreach (Socket s in read_list) {
321 if (write_count != 0) {
323 foreach (Socket s in write_list) {
329 if (err_count != 0) {
331 foreach (Socket s in err_list) {
337 Select_internal(ref read_arr, ref write_arr,
338 ref err_arr, time_us);
340 if(read_list!=null) {
342 for(i=0; i<read_arr.Length; i++) {
343 read_list.Add(read_arr[i]);
347 if(write_list!=null) {
349 for(i=0; i<write_arr.Length; i++) {
350 write_list.Add(write_arr[i]);
356 for(i=0; i<err_arr.Length; i++) {
357 err_list.Add(err_arr[i]);
366 ass=Assembly.Load("Mono.Posix");
367 } catch (FileNotFoundException) {
371 unixendpointtype=ass.GetType("Mono.Posix.UnixEndPoint");
373 /* The endpoint Create() method is an instance
376 Type[] arg_types=new Type[1];
377 arg_types[0]=typeof(string);
378 ConstructorInfo cons=unixendpointtype.GetConstructor(arg_types);
380 object[] args=new object[1];
383 unixendpoint=cons.Invoke(args);
386 // private constructor used by Accept, which already
387 // has a socket handle to use
388 private Socket(AddressFamily family, SocketType type,
389 ProtocolType proto, IntPtr sock) {
390 address_family=family;
398 // Creates a new system socket, returning the handle
399 [MethodImplAttribute(MethodImplOptions.InternalCall)]
400 private extern IntPtr Socket_internal(AddressFamily family,
404 public Socket(AddressFamily family, SocketType type,
405 ProtocolType proto) {
406 address_family=family;
410 socket=Socket_internal(family, type, proto);
413 public AddressFamily AddressFamily {
415 return(address_family);
419 // Returns the amount of data waiting to be read on socket
420 [MethodImplAttribute(MethodImplOptions.InternalCall)]
421 private extern static int Available_internal(IntPtr socket);
423 public int Available {
425 return(Available_internal(socket));
429 [MethodImplAttribute(MethodImplOptions.InternalCall)]
430 private extern static void Blocking_internal(IntPtr socket,
433 public bool Blocking {
438 Blocking_internal(socket, value);
443 public bool Connected {
449 public IntPtr Handle {
455 // Returns the local endpoint details in addr and port
456 [MethodImplAttribute(MethodImplOptions.InternalCall)]
457 private extern static SocketAddress LocalEndPoint_internal(IntPtr socket);
459 [MonoTODO("Support non-IP endpoints")]
460 public EndPoint LocalEndPoint {
464 sa=LocalEndPoint_internal(socket);
466 if(sa.Family==AddressFamily.InterNetwork) {
467 // Stupidly, EndPoint.Create() is an
469 return new IPEndPoint(0, 0).Create(sa);
470 } else if (sa.Family==AddressFamily.Unix &&
471 unixendpoint!=null) {
472 return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
474 throw new NotImplementedException();
479 public ProtocolType ProtocolType {
481 return(protocol_type);
485 // Returns the remote endpoint details in addr and port
486 [MethodImplAttribute(MethodImplOptions.InternalCall)]
487 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket);
489 [MonoTODO("Support non-IP endpoints")]
490 public EndPoint RemoteEndPoint {
494 sa=RemoteEndPoint_internal(socket);
496 if(sa.Family==AddressFamily.InterNetwork) {
497 // Stupidly, EndPoint.Create() is an
499 return new IPEndPoint(0, 0).Create(sa);
500 } else if (sa.Family==AddressFamily.Unix &&
501 unixendpoint!=null) {
502 return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
504 throw new NotImplementedException();
509 public SocketType SocketType {
515 // Creates a new system socket, returning the handle
516 [MethodImplAttribute(MethodImplOptions.InternalCall)]
517 private extern static IntPtr Accept_internal(IntPtr sock);
519 public Socket Accept() {
520 IntPtr sock=Accept_internal(socket);
522 return(new Socket(this.AddressFamily, this.SocketType,
523 this.ProtocolType, sock));
526 public IAsyncResult BeginAccept(AsyncCallback callback,
528 SocketAsyncResult req=new SocketAsyncResult(state);
529 Worker worker=new Worker(this, callback, req);
531 Thread child=new Thread(new ThreadStart(worker.Accept));
536 public IAsyncResult BeginConnect(EndPoint end_point,
537 AsyncCallback callback,
539 SocketAsyncResult req=new SocketAsyncResult(state);
540 Worker worker=new Worker(this, end_point, callback,
543 Thread child=new Thread(new ThreadStart(worker.Connect));
548 public IAsyncResult BeginReceive(byte[] buffer, int offset,
550 SocketFlags socket_flags,
551 AsyncCallback callback,
553 SocketAsyncResult req=new SocketAsyncResult(state);
554 Worker worker=new Worker(this, buffer, offset, size,
555 socket_flags, callback, req);
557 Thread child=new Thread(new ThreadStart(worker.Receive));
562 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
564 SocketFlags socket_flags,
565 ref EndPoint remote_end,
566 AsyncCallback callback,
568 SocketAsyncResult req=new SocketAsyncResult(state);
569 Worker worker=new Worker(this, buffer, offset, size,
570 socket_flags, remote_end,
573 Thread child=new Thread(new ThreadStart(worker.ReceiveFrom));
578 public IAsyncResult BeginSend(byte[] buffer, int offset,
580 SocketFlags socket_flags,
581 AsyncCallback callback,
583 SocketAsyncResult req=new SocketAsyncResult(state);
584 Worker worker=new Worker(this, buffer, offset, size,
585 socket_flags, callback, req);
587 Thread child=new Thread(new ThreadStart(worker.Send));
592 public IAsyncResult BeginSendTo(byte[] buffer, int offset,
594 SocketFlags socket_flags,
596 AsyncCallback callback,
598 SocketAsyncResult req=new SocketAsyncResult(state);
599 Worker worker=new Worker(this, buffer, offset, size,
600 socket_flags, remote_end,
603 Thread child=new Thread(new ThreadStart(worker.SendTo));
608 // Creates a new system socket, returning the handle
609 [MethodImplAttribute(MethodImplOptions.InternalCall)]
610 private extern static void Bind_internal(IntPtr sock,
613 public void Bind(EndPoint local_end) {
614 if(local_end==null) {
615 throw new ArgumentNullException();
618 Bind_internal(socket, local_end.Serialize());
622 [MethodImplAttribute(MethodImplOptions.InternalCall)]
623 private extern static void Close_internal(IntPtr socket);
625 public void Close() {
629 // Connects to the remote address
630 [MethodImplAttribute(MethodImplOptions.InternalCall)]
631 private extern static void Connect_internal(IntPtr sock,
634 public void Connect(EndPoint remote_end) {
635 if(remote_end==null) {
636 throw new ArgumentNullException();
639 Connect_internal(socket, remote_end.Serialize());
643 public Socket EndAccept(IAsyncResult result) {
644 SocketAsyncResult req=(SocketAsyncResult)result;
646 result.AsyncWaitHandle.WaitOne();
647 return(req.Worker.Socket);
650 public void EndConnect(IAsyncResult result) {
651 SocketAsyncResult req=(SocketAsyncResult)result;
653 result.AsyncWaitHandle.WaitOne();
656 public int EndReceive(IAsyncResult result) {
657 SocketAsyncResult req=(SocketAsyncResult)result;
659 result.AsyncWaitHandle.WaitOne();
660 return(req.Worker.Total);
663 public int EndReceiveFrom(IAsyncResult result,
664 ref EndPoint end_point) {
665 SocketAsyncResult req=(SocketAsyncResult)result;
667 result.AsyncWaitHandle.WaitOne();
668 end_point=req.Worker.EndPoint;
669 return(req.Worker.Total);
672 public int EndSend(IAsyncResult result) {
673 SocketAsyncResult req=(SocketAsyncResult)result;
675 result.AsyncWaitHandle.WaitOne();
676 return(req.Worker.Total);
679 public int EndSendTo(IAsyncResult result) {
680 SocketAsyncResult req=(SocketAsyncResult)result;
682 result.AsyncWaitHandle.WaitOne();
683 return(req.Worker.Total);
686 [MethodImplAttribute(MethodImplOptions.InternalCall)]
687 private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val);
688 [MethodImplAttribute(MethodImplOptions.InternalCall)]
689 private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val);
691 public object GetSocketOption(SocketOptionLevel level,
692 SocketOptionName name) {
695 GetSocketOption_obj_internal(socket, level, name,
698 if(name==SocketOptionName.Linger) {
699 return((LingerOption)obj_val);
700 } else if (name==SocketOptionName.AddMembership ||
701 name==SocketOptionName.DropMembership) {
702 return((MulticastOption)obj_val);
704 return((int)obj_val);
708 public void GetSocketOption(SocketOptionLevel level,
709 SocketOptionName name,
711 int opt_value_len=opt_value.Length;
713 GetSocketOption_arr_internal(socket, level, name,
717 public byte[] GetSocketOption(SocketOptionLevel level,
718 SocketOptionName name,
720 byte[] byte_val=new byte[length];
722 GetSocketOption_arr_internal(socket, level, name,
728 [MonoTODO("Totally undocumented")]
729 public int IOControl(int ioctl_code, byte[] in_value,
731 throw new NotImplementedException();
734 [MethodImplAttribute(MethodImplOptions.InternalCall)]
735 private extern static void Listen_internal(IntPtr sock,
738 public void Listen(int backlog) {
739 Listen_internal(socket, backlog);
742 /* The docs for Poll() are a bit lightweight too, but
743 * it seems to be just a simple wrapper around Select.
745 public bool Poll(int time_us, SelectMode mode) {
746 Socket [] socketlist = new Socket []{this};
750 case SelectMode.SelectError:
751 Select_internal (ref n, ref n, ref socketlist, time_us);
753 case SelectMode.SelectRead:
754 Select_internal (ref socketlist, ref n, ref n, time_us);
756 case SelectMode.SelectWrite:
757 Select_internal (ref n, ref socketlist, ref n, time_us);
760 throw new NotSupportedException();
763 return (socketlist.Length == 1);
766 public int Receive(byte[] buf) {
767 return(Receive(buf, 0, buf.Length, SocketFlags.None));
770 public int Receive(byte[] buf, SocketFlags flags) {
771 return(Receive(buf, 0, buf.Length, flags));
774 public int Receive(byte[] buf, int size, SocketFlags flags) {
775 return(Receive(buf, 0, size, flags));
778 [MethodImplAttribute(MethodImplOptions.InternalCall)]
779 private extern static int Receive_internal(IntPtr sock,
785 public int Receive(byte[] buf, int offset, int size,
788 throw new ArgumentNullException("buffer is null");
790 if(offset<0 || offset >= buf.Length) {
791 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
793 if(offset+size<0 || offset+size > buf.Length) {
794 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
800 ret=Receive_internal(socket, buf, offset,
802 } catch(SocketException) {
811 public int ReceiveFrom(byte[] buf, ref EndPoint remote_end) {
812 return(ReceiveFrom(buf, 0, buf.Length,
813 SocketFlags.None, ref remote_end));
816 public int ReceiveFrom(byte[] buf, SocketFlags flags,
817 ref EndPoint remote_end) {
818 return(ReceiveFrom(buf, 0, buf.Length, flags,
822 public int ReceiveFrom(byte[] buf, int size, SocketFlags flags,
823 ref EndPoint remote_end) {
824 return(ReceiveFrom(buf, 0, size, flags,
829 [MethodImplAttribute(MethodImplOptions.InternalCall)]
830 private extern static int RecvFrom_internal(IntPtr sock,
835 ref SocketAddress sockaddr);
837 public int ReceiveFrom(byte[] buf, int offset, int size,
839 ref EndPoint remote_end) {
841 throw new ArgumentNullException("buffer is null");
843 if(remote_end==null) {
844 throw new ArgumentNullException("remote endpoint is null");
846 if(offset<0 || offset>=buf.Length) {
847 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
849 if(offset+size<0 || offset+size>buf.Length) {
850 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
853 SocketAddress sockaddr=remote_end.Serialize();
857 count=RecvFrom_internal(socket, buf, offset,
860 } catch(SocketException) {
866 // Stupidly, EndPoint.Create() is an
868 remote_end=remote_end.Create(sockaddr);
873 public int Send(byte[] buf) {
874 return(Send(buf, 0, buf.Length, SocketFlags.None));
877 public int Send(byte[] buf, SocketFlags flags) {
878 return(Send(buf, 0, buf.Length, flags));
881 public int Send(byte[] buf, int size, SocketFlags flags) {
882 return(Send(buf, 0, size, flags));
885 [MethodImplAttribute(MethodImplOptions.InternalCall)]
886 private extern static int Send_internal(IntPtr sock,
887 byte[] buf, int offset,
891 public int Send (byte[] buf, int offset, int size, SocketFlags flags)
894 throw new ArgumentNullException ("buffer");
896 if (offset < 0 || offset > buf.Length)
897 throw new ArgumentOutOfRangeException ("offset");
899 if (size < 0 || offset + size > buf.Length)
900 throw new ArgumentOutOfRangeException ("size");
908 ret = Send_internal (socket, buf, offset, size, flags);
909 } catch (SocketException) {
918 public int SendTo(byte[] buffer, EndPoint remote_end) {
919 return(SendTo(buffer, 0, buffer.Length,
920 SocketFlags.None, remote_end));
923 public int SendTo(byte[] buffer, SocketFlags flags,
924 EndPoint remote_end) {
925 return(SendTo(buffer, 0, buffer.Length, flags,
929 public int SendTo(byte[] buffer, int size, SocketFlags flags,
930 EndPoint remote_end) {
931 return(SendTo(buffer, 0, size, flags, remote_end));
935 [MethodImplAttribute(MethodImplOptions.InternalCall)]
936 private extern static int SendTo_internal(IntPtr sock,
943 public int SendTo(byte[] buffer, int offset, int size,
944 SocketFlags flags, EndPoint remote_end) {
946 throw new ArgumentNullException("buffer is null");
948 if(remote_end==null) {
949 throw new ArgumentNullException("remote endpoint is null");
951 if(offset<0 || offset>=buffer.Length) {
952 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
954 if(offset+size<0 || offset+size>buffer.Length) {
955 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
958 SocketAddress sockaddr=remote_end.Serialize();
963 ret=SendTo_internal(socket, buffer, offset,
964 size, flags, sockaddr);
966 catch(SocketException) {
975 [MethodImplAttribute(MethodImplOptions.InternalCall)]
976 private extern static void SetSocketOption_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte[] byte_val, int int_val);
978 public void SetSocketOption(SocketOptionLevel level,
979 SocketOptionName name,
981 SetSocketOption_internal(socket, level, name, null,
985 public void SetSocketOption(SocketOptionLevel level,
986 SocketOptionName name,
988 SetSocketOption_internal(socket, level, name, null,
992 public void SetSocketOption(SocketOptionLevel level,
993 SocketOptionName name,
995 if(opt_value==null) {
996 throw new ArgumentNullException();
999 /* Passing a bool as the third parameter to
1000 * SetSocketOption causes this overload to be
1001 * used when in fact we want to pass the value
1002 * to the runtime as an int.
1004 if(opt_value is System.Boolean) {
1005 bool bool_val=(bool)opt_value;
1007 /* Stupid casting rules :-( */
1008 if(bool_val==true) {
1009 SetSocketOption_internal(socket, level,
1013 SetSocketOption_internal(socket, level,
1018 SetSocketOption_internal(socket, level, name,
1019 opt_value, null, 0);
1023 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1024 private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how);
1026 public void Shutdown(SocketShutdown how) {
1027 Shutdown_internal(socket, how);
1030 private bool disposed = false;
1032 protected virtual void Dispose(bool explicitDisposing) {
1033 // Check to see if Dispose has already been called
1034 if(!this.disposed) {
1035 // If this is a call to Dispose,
1036 // dispose all managed resources.
1037 if(explicitDisposing) {
1038 // Free up stuff here
1041 // Release unmanaged resources
1045 Close_internal(socket);
1049 public void Dispose() {
1051 // Take yourself off the Finalization queue
1052 GC.SuppressFinalize(this);