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;
17 namespace System.Net.Sockets
19 public class Socket : IDisposable
21 private sealed class SocketAsyncResult: IAsyncResult
24 private WaitHandle waithandle;
25 private bool completed_sync, completed;
26 private Worker worker;
28 public SocketAsyncResult(object state) {
30 waithandle=new ManualResetEvent(false);
31 completed_sync=completed=false;
34 public object AsyncState {
40 public WaitHandle AsyncWaitHandle {
49 public bool CompletedSynchronously {
51 return(completed_sync);
55 public bool IsCompleted {
64 public Worker Worker {
74 private sealed class Worker
76 private AsyncCallback callback;
77 private SocketAsyncResult result;
78 private Socket socket;
81 private EndPoint endpoint; // Connect,ReceiveFrom,SendTo
82 private byte[] buffer; // Receive,ReceiveFrom,Send,SendTo
83 private int offset; // Receive,ReceiveFrom,Send,SendTo
84 private int size; // Receive,ReceiveFrom,Send,SendTo
85 private SocketFlags sockflags; // Receive,ReceiveFrom,Send,SendTo
88 private Socket acc_socket;
93 public Worker(Socket req_sock,
94 AsyncCallback req_callback,
95 SocketAsyncResult req_result)
96 : this(req_sock, null, 0, 0, SocketFlags.None,
97 null, req_callback, req_result) {}
100 public Worker(Socket req_sock, EndPoint req_endpoint,
101 AsyncCallback req_callback,
102 SocketAsyncResult req_result)
103 : this(req_sock, null, 0, 0, SocketFlags.None,
104 req_endpoint, req_callback,
107 // For Receive and Send
108 public Worker(Socket req_sock, byte[] req_buffer,
109 int req_offset, int req_size,
110 SocketFlags req_sockflags,
111 AsyncCallback req_callback,
112 SocketAsyncResult req_result)
113 : this(req_sock, req_buffer, req_offset,
114 req_size, req_sockflags, null,
115 req_callback, req_result) {}
117 // For ReceiveFrom and SendTo
118 public Worker(Socket req_sock, byte[] req_buffer,
119 int req_offset, int req_size,
120 SocketFlags req_sockflags,
121 EndPoint req_endpoint,
122 AsyncCallback req_callback,
123 SocketAsyncResult req_result) {
128 sockflags=req_sockflags;
129 endpoint=req_endpoint;
130 callback=req_callback;
135 ((ManualResetEvent)result.AsyncWaitHandle).Set();
136 result.IsCompleted=true;
137 if (callback != null)
141 public void Accept() {
143 acc_socket=socket.Accept();
148 public void Connect() {
150 if (socket.Blocking) {
151 socket.Connect(endpoint);
156 SocketException rethrow = null;
158 socket.Connect (endpoint);
159 } catch (SocketException e) {
161 if (e.NativeErrorCode != 10036)
164 socket.Poll (-1, SelectMode.SelectWrite);
166 socket.Connect (endpoint);
167 } catch (SocketException e2) {
177 public void Receive() {
179 if (socket.Blocking) {
180 total=socket.Receive(buffer, offset,
186 SocketException rethrow = null;
188 total = socket.Receive (buffer, offset, size, sockflags);
189 } catch (SocketException e) {
191 if (e.NativeErrorCode != 10035)
194 socket.Poll (-1, SelectMode.SelectRead);
196 total = socket.Receive (buffer, offset, size, sockflags);
197 } catch (SocketException e2) {
207 public void ReceiveFrom() {
209 total=socket.ReceiveFrom(buffer,
219 total=socket.Send(buffer, offset, size,
225 public void SendTo() {
227 total=socket.SendTo(buffer, offset,
234 public EndPoint EndPoint {
240 public Socket Socket {
253 /* the field "socket" is looked up by name by the runtime */
254 private IntPtr socket;
255 private AddressFamily address_family;
256 private SocketType socket_type;
257 private ProtocolType protocol_type;
258 private bool blocking=true;
260 /* When true, the socket was connected at the time of
261 * the last IO operation
263 private bool connected=false;
265 [MethodImplAttribute(MethodImplOptions.InternalCall)]
266 private extern static void Select_internal(ref Socket[] read,
271 public static void Select(IList read_list, IList write_list,
272 IList err_list, int time_us) {
273 if(read_list==null &&
276 throw new ArgumentNullException();
279 int read_count, write_count, err_count;
281 if(read_list!=null) {
282 read_count=read_list.Count;
287 if(write_list!=null) {
288 write_count=write_list.Count;
294 err_count=err_list.Count;
299 Socket[] read_arr=new Socket[read_count];
300 Socket[] write_arr=new Socket[write_count];
301 Socket[] err_arr=new Socket[err_count];
305 if(read_list!=null) {
308 foreach (Socket s in read_list) {
314 if(write_list!=null) {
316 foreach (Socket s in write_list) {
324 foreach (Socket s in err_list) {
330 Select_internal(ref read_arr, ref write_arr,
331 ref err_arr, time_us);
333 if(read_list!=null) {
335 for(i=0; i<read_arr.Length; i++) {
336 read_list.Add(read_arr[i]);
340 if(write_list!=null) {
342 for(i=0; i<write_arr.Length; i++) {
343 write_list.Add(write_arr[i]);
349 for(i=0; i<err_arr.Length; i++) {
350 err_list.Add(err_arr[i]);
355 // private constructor used by Accept, which already
356 // has a socket handle to use
357 private Socket(AddressFamily family, SocketType type,
358 ProtocolType proto, IntPtr sock) {
359 address_family=family;
367 // Creates a new system socket, returning the handle
368 [MethodImplAttribute(MethodImplOptions.InternalCall)]
369 private extern IntPtr Socket_internal(AddressFamily family,
373 public Socket(AddressFamily family, SocketType type,
374 ProtocolType proto) {
375 address_family=family;
379 socket=Socket_internal(family, type, proto);
382 public AddressFamily AddressFamily {
384 return(address_family);
388 // Returns the amount of data waiting to be read on socket
389 [MethodImplAttribute(MethodImplOptions.InternalCall)]
390 private extern static int Available_internal(IntPtr socket);
392 public int Available {
394 return(Available_internal(socket));
398 [MethodImplAttribute(MethodImplOptions.InternalCall)]
399 private extern static void Blocking_internal(IntPtr socket,
402 public bool Blocking {
407 Blocking_internal(socket, value);
412 public bool Connected {
418 public IntPtr Handle {
424 // Returns the local endpoint details in addr and port
425 [MethodImplAttribute(MethodImplOptions.InternalCall)]
426 private extern static SocketAddress LocalEndPoint_internal(IntPtr socket);
428 [MonoTODO("Support non-IP endpoints")]
429 public EndPoint LocalEndPoint {
433 sa=LocalEndPoint_internal(socket);
435 if(sa.Family==AddressFamily.InterNetwork) {
436 // Stupidly, EndPoint.Create() is an
438 return new IPEndPoint(0, 0).Create(sa);
440 throw new NotImplementedException();
445 public ProtocolType ProtocolType {
447 return(protocol_type);
451 // Returns the remote endpoint details in addr and port
452 [MethodImplAttribute(MethodImplOptions.InternalCall)]
453 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket);
455 [MonoTODO("Support non-IP endpoints")]
456 public EndPoint RemoteEndPoint {
460 sa=RemoteEndPoint_internal(socket);
462 if(sa.Family==AddressFamily.InterNetwork) {
463 // Stupidly, EndPoint.Create() is an
465 return new IPEndPoint(0, 0).Create(sa);
467 throw new NotImplementedException();
472 public SocketType SocketType {
478 // Creates a new system socket, returning the handle
479 [MethodImplAttribute(MethodImplOptions.InternalCall)]
480 private extern static IntPtr Accept_internal(IntPtr sock);
482 public Socket Accept() {
483 IntPtr sock=Accept_internal(socket);
485 return(new Socket(this.AddressFamily, this.SocketType,
486 this.ProtocolType, sock));
489 public IAsyncResult BeginAccept(AsyncCallback callback,
491 SocketAsyncResult req=new SocketAsyncResult(state);
492 Worker worker=new Worker(this, callback, req);
494 Thread child=new Thread(new ThreadStart(worker.Accept));
499 public IAsyncResult BeginConnect(EndPoint end_point,
500 AsyncCallback callback,
502 SocketAsyncResult req=new SocketAsyncResult(state);
503 Worker worker=new Worker(this, end_point, callback,
506 Thread child=new Thread(new ThreadStart(worker.Connect));
511 public IAsyncResult BeginReceive(byte[] buffer, int offset,
513 SocketFlags socket_flags,
514 AsyncCallback callback,
516 SocketAsyncResult req=new SocketAsyncResult(state);
517 Worker worker=new Worker(this, buffer, offset, size,
518 socket_flags, callback, req);
520 Thread child=new Thread(new ThreadStart(worker.Receive));
525 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
527 SocketFlags socket_flags,
528 ref EndPoint remote_end,
529 AsyncCallback callback,
531 SocketAsyncResult req=new SocketAsyncResult(state);
532 Worker worker=new Worker(this, buffer, offset, size,
533 socket_flags, remote_end,
536 Thread child=new Thread(new ThreadStart(worker.ReceiveFrom));
541 public IAsyncResult BeginSend(byte[] buffer, int offset,
543 SocketFlags socket_flags,
544 AsyncCallback callback,
546 SocketAsyncResult req=new SocketAsyncResult(state);
547 Worker worker=new Worker(this, buffer, offset, size,
548 socket_flags, callback, req);
550 Thread child=new Thread(new ThreadStart(worker.Send));
555 public IAsyncResult BeginSendTo(byte[] buffer, int offset,
557 SocketFlags socket_flags,
559 AsyncCallback callback,
561 SocketAsyncResult req=new SocketAsyncResult(state);
562 Worker worker=new Worker(this, buffer, offset, size,
563 socket_flags, remote_end,
566 Thread child=new Thread(new ThreadStart(worker.SendTo));
571 // Creates a new system socket, returning the handle
572 [MethodImplAttribute(MethodImplOptions.InternalCall)]
573 private extern static void Bind_internal(IntPtr sock,
576 public void Bind(EndPoint local_end) {
577 if(local_end==null) {
578 throw new ArgumentNullException();
581 Bind_internal(socket, local_end.Serialize());
585 [MethodImplAttribute(MethodImplOptions.InternalCall)]
586 private extern static void Close_internal(IntPtr socket);
588 public void Close() {
592 // Connects to the remote address
593 [MethodImplAttribute(MethodImplOptions.InternalCall)]
594 private extern static void Connect_internal(IntPtr sock,
597 public void Connect(EndPoint remote_end) {
598 if(remote_end==null) {
599 throw new ArgumentNullException();
602 Connect_internal(socket, remote_end.Serialize());
606 public Socket EndAccept(IAsyncResult result) {
607 SocketAsyncResult req=(SocketAsyncResult)result;
609 result.AsyncWaitHandle.WaitOne();
610 return(req.Worker.Socket);
613 public void EndConnect(IAsyncResult result) {
614 SocketAsyncResult req=(SocketAsyncResult)result;
616 result.AsyncWaitHandle.WaitOne();
619 public int EndReceive(IAsyncResult result) {
620 SocketAsyncResult req=(SocketAsyncResult)result;
622 result.AsyncWaitHandle.WaitOne();
623 return(req.Worker.Total);
626 public int EndReceiveFrom(IAsyncResult result,
627 ref EndPoint end_point) {
628 SocketAsyncResult req=(SocketAsyncResult)result;
630 result.AsyncWaitHandle.WaitOne();
631 end_point=req.Worker.EndPoint;
632 return(req.Worker.Total);
635 public int EndSend(IAsyncResult result) {
636 SocketAsyncResult req=(SocketAsyncResult)result;
638 result.AsyncWaitHandle.WaitOne();
639 return(req.Worker.Total);
642 public int EndSendTo(IAsyncResult result) {
643 SocketAsyncResult req=(SocketAsyncResult)result;
645 result.AsyncWaitHandle.WaitOne();
646 return(req.Worker.Total);
649 [MethodImplAttribute(MethodImplOptions.InternalCall)]
650 private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val);
651 [MethodImplAttribute(MethodImplOptions.InternalCall)]
652 private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val);
654 public object GetSocketOption(SocketOptionLevel level,
655 SocketOptionName name) {
658 GetSocketOption_obj_internal(socket, level, name,
661 if(name==SocketOptionName.Linger) {
662 return((LingerOption)obj_val);
663 } else if (name==SocketOptionName.AddMembership ||
664 name==SocketOptionName.DropMembership) {
665 return((MulticastOption)obj_val);
667 return((int)obj_val);
671 public void GetSocketOption(SocketOptionLevel level,
672 SocketOptionName name,
674 int opt_value_len=opt_value.Length;
676 GetSocketOption_arr_internal(socket, level, name,
680 public byte[] GetSocketOption(SocketOptionLevel level,
681 SocketOptionName name,
683 byte[] byte_val=new byte[length];
685 GetSocketOption_arr_internal(socket, level, name,
691 [MonoTODO("Totally undocumented")]
692 public int IOControl(int ioctl_code, byte[] in_value,
694 throw new NotImplementedException();
697 [MethodImplAttribute(MethodImplOptions.InternalCall)]
698 private extern static void Listen_internal(IntPtr sock,
701 public void Listen(int backlog) {
702 Listen_internal(socket, backlog);
705 /* The docs for Poll() are a bit lightweight too, but
706 * it seems to be just a simple wrapper around Select.
708 public bool Poll(int time_us, SelectMode mode) {
709 ArrayList socketlist=new ArrayList(1);
711 socketlist.Add(this);
714 case SelectMode.SelectError:
715 Select(null, null, socketlist, time_us);
717 case SelectMode.SelectRead:
718 Select(socketlist, null, null, time_us);
720 case SelectMode.SelectWrite:
721 Select(null, socketlist, null, time_us);
724 throw new NotSupportedException();
727 if(socketlist.Contains(this)) {
734 public int Receive(byte[] buf) {
735 return(Receive(buf, 0, buf.Length, SocketFlags.None));
738 public int Receive(byte[] buf, SocketFlags flags) {
739 return(Receive(buf, 0, buf.Length, flags));
742 public int Receive(byte[] buf, int size, SocketFlags flags) {
743 return(Receive(buf, 0, size, flags));
746 [MethodImplAttribute(MethodImplOptions.InternalCall)]
747 private extern static int Receive_internal(IntPtr sock,
753 public int Receive(byte[] buf, int offset, int size,
756 throw new ArgumentNullException("buffer is null");
758 if(offset<0 || offset >= buf.Length) {
759 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
761 if(offset+size<0 || offset+size > buf.Length) {
762 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
768 ret=Receive_internal(socket, buf, offset,
770 } catch(SocketException) {
779 public int ReceiveFrom(byte[] buf, ref EndPoint remote_end) {
780 return(ReceiveFrom(buf, 0, buf.Length,
781 SocketFlags.None, ref remote_end));
784 public int ReceiveFrom(byte[] buf, SocketFlags flags,
785 ref EndPoint remote_end) {
786 return(ReceiveFrom(buf, 0, buf.Length, flags,
790 public int ReceiveFrom(byte[] buf, int size, SocketFlags flags,
791 ref EndPoint remote_end) {
792 return(ReceiveFrom(buf, 0, size, flags,
797 [MethodImplAttribute(MethodImplOptions.InternalCall)]
798 private extern static int RecvFrom_internal(IntPtr sock,
803 ref SocketAddress sockaddr);
805 public int ReceiveFrom(byte[] buf, int offset, int size,
807 ref EndPoint remote_end) {
809 throw new ArgumentNullException("buffer is null");
811 if(remote_end==null) {
812 throw new ArgumentNullException("remote endpoint is null");
814 if(offset<0 || offset>=buf.Length) {
815 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
817 if(offset+size<0 || offset+size>buf.Length) {
818 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
821 SocketAddress sockaddr=remote_end.Serialize();
825 count=RecvFrom_internal(socket, buf, offset,
828 } catch(SocketException) {
834 // Stupidly, EndPoint.Create() is an
836 remote_end=remote_end.Create(sockaddr);
841 public int Send(byte[] buf) {
842 return(Send(buf, 0, buf.Length, SocketFlags.None));
845 public int Send(byte[] buf, SocketFlags flags) {
846 return(Send(buf, 0, buf.Length, flags));
849 public int Send(byte[] buf, int size, SocketFlags flags) {
850 return(Send(buf, 0, size, flags));
853 [MethodImplAttribute(MethodImplOptions.InternalCall)]
854 private extern static int Send_internal(IntPtr sock,
855 byte[] buf, int offset,
859 public int Send (byte[] buf, int offset, int size, SocketFlags flags)
862 throw new ArgumentNullException ("buffer");
864 if (offset < 0 || offset > buf.Length)
865 throw new ArgumentOutOfRangeException ("offset");
867 if (size < 0 || offset + size > buf.Length)
868 throw new ArgumentOutOfRangeException ("size");
876 ret = Send_internal (socket, buf, offset, size, flags);
877 } catch (SocketException) {
886 public int SendTo(byte[] buffer, EndPoint remote_end) {
887 return(SendTo(buffer, 0, buffer.Length,
888 SocketFlags.None, remote_end));
891 public int SendTo(byte[] buffer, SocketFlags flags,
892 EndPoint remote_end) {
893 return(SendTo(buffer, 0, buffer.Length, flags,
897 public int SendTo(byte[] buffer, int size, SocketFlags flags,
898 EndPoint remote_end) {
899 return(SendTo(buffer, size, buffer.Length, flags,
904 [MethodImplAttribute(MethodImplOptions.InternalCall)]
905 private extern static int SendTo_internal(IntPtr sock,
912 public int SendTo(byte[] buffer, int offset, int size,
913 SocketFlags flags, EndPoint remote_end) {
915 throw new ArgumentNullException("buffer is null");
917 if(remote_end==null) {
918 throw new ArgumentNullException("remote endpoint is null");
920 if(offset<0 || offset>=buffer.Length) {
921 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
923 if(offset+size<0 || offset+size>buffer.Length) {
924 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
927 SocketAddress sockaddr=remote_end.Serialize();
932 ret=SendTo_internal(socket, buffer, offset,
933 size, flags, sockaddr);
935 catch(SocketException) {
944 [MethodImplAttribute(MethodImplOptions.InternalCall)]
945 private extern static void SetSocketOption_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte[] byte_val, int int_val);
947 public void SetSocketOption(SocketOptionLevel level,
948 SocketOptionName name,
950 SetSocketOption_internal(socket, level, name, null,
954 public void SetSocketOption(SocketOptionLevel level,
955 SocketOptionName name,
957 SetSocketOption_internal(socket, level, name, null,
961 public void SetSocketOption(SocketOptionLevel level,
962 SocketOptionName name,
964 if(opt_value==null) {
965 throw new ArgumentNullException();
968 /* Passing a bool as the third parameter to
969 * SetSocketOption causes this overload to be
970 * used when in fact we want to pass the value
971 * to the runtime as an int.
973 if(opt_value is System.Boolean) {
974 bool bool_val=(bool)opt_value;
976 /* Stupid casting rules :-( */
978 SetSocketOption_internal(socket, level,
982 SetSocketOption_internal(socket, level,
987 SetSocketOption_internal(socket, level, name,
992 [MethodImplAttribute(MethodImplOptions.InternalCall)]
993 private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how);
995 public void Shutdown(SocketShutdown how) {
996 Shutdown_internal(socket, how);
999 private bool disposed = false;
1001 protected virtual void Dispose(bool explicitDisposing) {
1002 // Check to see if Dispose has already been called
1003 if(!this.disposed) {
1004 // If this is a call to Dispose,
1005 // dispose all managed resources.
1006 if(explicitDisposing) {
1007 // Free up stuff here
1010 // Release unmanaged resources
1014 Close_internal(socket);
1018 public void Dispose() {
1020 // Take yourself off the Finalization queue
1021 GC.SuppressFinalize(this);