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();
137 result.IsCompleted=true;
140 public void Accept() {
142 acc_socket=socket.Accept();
147 public void Connect() {
149 socket.Connect(endpoint);
154 public void Receive() {
156 total=socket.Receive(buffer, offset,
162 public void ReceiveFrom() {
164 total=socket.ReceiveFrom(buffer,
174 total=socket.Send(buffer, offset, size,
180 public void SendTo() {
182 total=socket.SendTo(buffer, offset,
189 public EndPoint EndPoint {
195 public Socket Socket {
208 /* the field "socket" is looked up by name by the runtime */
209 private IntPtr socket;
210 private AddressFamily address_family;
211 private SocketType socket_type;
212 private ProtocolType protocol_type;
213 private bool blocking=true;
215 /* When true, the socket was connected at the time of
216 * the last IO operation
218 private bool connected=false;
220 [MethodImplAttribute(MethodImplOptions.InternalCall)]
221 private extern static void Select_internal(ref Socket[] read,
226 public static void Select(IList read_list, IList write_list,
227 IList err_list, int time_us) {
228 if(read_list==null &&
231 throw new ArgumentNullException();
234 int read_count, write_count, err_count;
236 if(read_list!=null) {
237 read_count=read_list.Count;
242 if(write_list!=null) {
243 write_count=write_list.Count;
249 err_count=err_list.Count;
254 Socket[] read_arr=new Socket[read_count];
255 Socket[] write_arr=new Socket[write_count];
256 Socket[] err_arr=new Socket[err_count];
260 if(read_list!=null) {
263 foreach (Socket s in read_list) {
269 if(write_list!=null) {
271 foreach (Socket s in write_list) {
279 foreach (Socket s in err_list) {
285 Select_internal(ref read_arr, ref write_arr,
286 ref err_arr, time_us);
288 if(read_list!=null) {
290 for(i=0; i<read_arr.Length; i++) {
291 read_list.Add(read_arr[i]);
295 if(write_list!=null) {
297 for(i=0; i<write_arr.Length; i++) {
298 write_list.Add(write_arr[i]);
304 for(i=0; i<err_arr.Length; i++) {
305 err_list.Add(err_arr[i]);
310 // private constructor used by Accept, which already
311 // has a socket handle to use
312 private Socket(AddressFamily family, SocketType type,
313 ProtocolType proto, IntPtr sock) {
314 address_family=family;
322 // Creates a new system socket, returning the handle
323 [MethodImplAttribute(MethodImplOptions.InternalCall)]
324 private extern IntPtr Socket_internal(AddressFamily family,
328 public Socket(AddressFamily family, SocketType type,
329 ProtocolType proto) {
330 address_family=family;
334 socket=Socket_internal(family, type, proto);
337 public AddressFamily AddressFamily {
339 return(address_family);
343 // Returns the amount of data waiting to be read on socket
344 [MethodImplAttribute(MethodImplOptions.InternalCall)]
345 private extern static int Available_internal(IntPtr socket);
347 public int Available {
349 return(Available_internal(socket));
353 [MethodImplAttribute(MethodImplOptions.InternalCall)]
354 private extern static void Blocking_internal(IntPtr socket,
357 public bool Blocking {
362 Blocking_internal(socket, value);
367 public bool Connected {
373 public IntPtr Handle {
379 // Returns the local endpoint details in addr and port
380 [MethodImplAttribute(MethodImplOptions.InternalCall)]
381 private extern static SocketAddress LocalEndPoint_internal(IntPtr socket);
383 [MonoTODO("Support non-IP endpoints")]
384 public EndPoint LocalEndPoint {
388 sa=LocalEndPoint_internal(socket);
390 if(sa.Family==AddressFamily.InterNetwork) {
391 // Stupidly, EndPoint.Create() is an
393 return new IPEndPoint(0, 0).Create(sa);
395 throw new NotImplementedException();
400 public ProtocolType ProtocolType {
402 return(protocol_type);
406 // Returns the remote endpoint details in addr and port
407 [MethodImplAttribute(MethodImplOptions.InternalCall)]
408 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket);
410 [MonoTODO("Support non-IP endpoints")]
411 public EndPoint RemoteEndPoint {
415 sa=RemoteEndPoint_internal(socket);
417 if(sa.Family==AddressFamily.InterNetwork) {
418 // Stupidly, EndPoint.Create() is an
420 return new IPEndPoint(0, 0).Create(sa);
422 throw new NotImplementedException();
427 public SocketType SocketType {
433 // Creates a new system socket, returning the handle
434 [MethodImplAttribute(MethodImplOptions.InternalCall)]
435 private extern static IntPtr Accept_internal(IntPtr sock);
437 public Socket Accept() {
438 IntPtr sock=Accept_internal(socket);
440 return(new Socket(this.AddressFamily, this.SocketType,
441 this.ProtocolType, sock));
444 public IAsyncResult BeginAccept(AsyncCallback callback,
446 SocketAsyncResult req=new SocketAsyncResult(state);
447 Worker worker=new Worker(this, callback, req);
449 Thread child=new Thread(new ThreadStart(worker.Accept));
454 public IAsyncResult BeginConnect(EndPoint end_point,
455 AsyncCallback callback,
457 SocketAsyncResult req=new SocketAsyncResult(state);
458 Worker worker=new Worker(this, end_point, callback,
461 Thread child=new Thread(new ThreadStart(worker.Connect));
466 public IAsyncResult BeginReceive(byte[] buffer, int offset,
468 SocketFlags socket_flags,
469 AsyncCallback callback,
471 SocketAsyncResult req=new SocketAsyncResult(state);
472 Worker worker=new Worker(this, buffer, offset, size,
473 socket_flags, callback, req);
475 Thread child=new Thread(new ThreadStart(worker.Receive));
480 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
482 SocketFlags socket_flags,
483 ref EndPoint remote_end,
484 AsyncCallback callback,
486 SocketAsyncResult req=new SocketAsyncResult(state);
487 Worker worker=new Worker(this, buffer, offset, size,
488 socket_flags, remote_end,
491 Thread child=new Thread(new ThreadStart(worker.ReceiveFrom));
496 public IAsyncResult BeginSend(byte[] buffer, int offset,
498 SocketFlags socket_flags,
499 AsyncCallback callback,
501 SocketAsyncResult req=new SocketAsyncResult(state);
502 Worker worker=new Worker(this, buffer, offset, size,
503 socket_flags, callback, req);
505 Thread child=new Thread(new ThreadStart(worker.Send));
510 public IAsyncResult BeginSendTo(byte[] buffer, int offset,
512 SocketFlags socket_flags,
514 AsyncCallback callback,
516 SocketAsyncResult req=new SocketAsyncResult(state);
517 Worker worker=new Worker(this, buffer, offset, size,
518 socket_flags, remote_end,
521 Thread child=new Thread(new ThreadStart(worker.SendTo));
526 // Creates a new system socket, returning the handle
527 [MethodImplAttribute(MethodImplOptions.InternalCall)]
528 private extern static void Bind_internal(IntPtr sock,
531 public void Bind(EndPoint local_end) {
532 if(local_end==null) {
533 throw new ArgumentNullException();
536 Bind_internal(socket, local_end.Serialize());
540 [MethodImplAttribute(MethodImplOptions.InternalCall)]
541 private extern static void Close_internal(IntPtr socket);
543 public void Close() {
545 Close_internal(socket);
548 // Connects to the remote address
549 [MethodImplAttribute(MethodImplOptions.InternalCall)]
550 private extern static void Connect_internal(IntPtr sock,
553 public void Connect(EndPoint remote_end) {
554 if(remote_end==null) {
555 throw new ArgumentNullException();
558 Connect_internal(socket, remote_end.Serialize());
562 public Socket EndAccept(IAsyncResult result) {
563 SocketAsyncResult req=(SocketAsyncResult)result;
565 result.AsyncWaitHandle.WaitOne();
566 return(req.Worker.Socket);
569 public void EndConnect(IAsyncResult result) {
570 SocketAsyncResult req=(SocketAsyncResult)result;
572 result.AsyncWaitHandle.WaitOne();
575 public int EndReceive(IAsyncResult result) {
576 SocketAsyncResult req=(SocketAsyncResult)result;
578 result.AsyncWaitHandle.WaitOne();
579 return(req.Worker.Total);
582 public int EndReceiveFrom(IAsyncResult result,
583 ref EndPoint end_point) {
584 SocketAsyncResult req=(SocketAsyncResult)result;
586 result.AsyncWaitHandle.WaitOne();
587 end_point=req.Worker.EndPoint;
588 return(req.Worker.Total);
591 public int EndSend(IAsyncResult result) {
592 SocketAsyncResult req=(SocketAsyncResult)result;
594 result.AsyncWaitHandle.WaitOne();
595 return(req.Worker.Total);
598 public int EndSendTo(IAsyncResult result) {
599 SocketAsyncResult req=(SocketAsyncResult)result;
601 result.AsyncWaitHandle.WaitOne();
602 return(req.Worker.Total);
605 [MethodImplAttribute(MethodImplOptions.InternalCall)]
606 private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val);
607 [MethodImplAttribute(MethodImplOptions.InternalCall)]
608 private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val);
610 public object GetSocketOption(SocketOptionLevel level,
611 SocketOptionName name) {
614 GetSocketOption_obj_internal(socket, level, name,
617 if(name==SocketOptionName.Linger) {
618 return((LingerOption)obj_val);
619 } else if (name==SocketOptionName.AddMembership ||
620 name==SocketOptionName.DropMembership) {
621 return((MulticastOption)obj_val);
623 return((int)obj_val);
627 public void GetSocketOption(SocketOptionLevel level,
628 SocketOptionName name,
630 int opt_value_len=opt_value.Length;
632 GetSocketOption_arr_internal(socket, level, name,
636 public byte[] GetSocketOption(SocketOptionLevel level,
637 SocketOptionName name,
639 byte[] byte_val=new byte[length];
641 GetSocketOption_arr_internal(socket, level, name,
647 [MonoTODO("Totally undocumented")]
648 public int IOControl(int ioctl_code, byte[] in_value,
650 throw new NotImplementedException();
653 [MethodImplAttribute(MethodImplOptions.InternalCall)]
654 private extern static void Listen_internal(IntPtr sock,
657 public void Listen(int backlog) {
658 Listen_internal(socket, backlog);
661 /* The docs for Poll() are a bit lightweight too, but
662 * it seems to be just a simple wrapper around Select.
664 public bool Poll(int time_us, SelectMode mode) {
665 ArrayList socketlist=new ArrayList(1);
667 socketlist.Add(this);
670 case SelectMode.SelectError:
671 Select(null, null, socketlist, time_us);
673 case SelectMode.SelectRead:
674 Select(socketlist, null, null, time_us);
676 case SelectMode.SelectWrite:
677 Select(null, socketlist, null, time_us);
680 throw new NotSupportedException();
683 if(socketlist.Contains(this)) {
690 public int Receive(byte[] buf) {
691 return(Receive(buf, 0, buf.Length, SocketFlags.None));
694 public int Receive(byte[] buf, SocketFlags flags) {
695 return(Receive(buf, 0, buf.Length, flags));
698 public int Receive(byte[] buf, int size, SocketFlags flags) {
699 return(Receive(buf, 0, size, flags));
702 [MethodImplAttribute(MethodImplOptions.InternalCall)]
703 private extern static int Receive_internal(IntPtr sock,
709 public int Receive(byte[] buf, int offset, int size,
712 throw new ArgumentNullException();
714 if(offset+size>buf.Length) {
715 throw new ArgumentException();
721 ret=Receive_internal(socket, buf, offset,
723 } catch(SocketException) {
732 public int ReceiveFrom(byte[] buf, ref EndPoint remote_end) {
733 return(ReceiveFrom(buf, 0, buf.Length,
734 SocketFlags.None, ref remote_end));
737 public int ReceiveFrom(byte[] buf, SocketFlags flags,
738 ref EndPoint remote_end) {
739 return(ReceiveFrom(buf, 0, buf.Length, flags,
743 public int ReceiveFrom(byte[] buf, int size, SocketFlags flags,
744 ref EndPoint remote_end) {
745 return(ReceiveFrom(buf, 0, size, flags,
750 [MethodImplAttribute(MethodImplOptions.InternalCall)]
751 private extern static int RecvFrom_internal(IntPtr sock,
756 ref SocketAddress sockaddr);
758 public int ReceiveFrom(byte[] buf, int offset, int size,
760 ref EndPoint remote_end) {
761 if(buf==null || remote_end==null) {
762 throw new ArgumentNullException();
764 if(offset+size>buf.Length) {
765 throw new ArgumentException();
768 SocketAddress sockaddr=remote_end.Serialize();
772 count=RecvFrom_internal(socket, buf, offset,
775 } catch(SocketException) {
781 // Stupidly, EndPoint.Create() is an
783 remote_end=remote_end.Create(sockaddr);
788 public int Send(byte[] buf) {
789 return(Send(buf, 0, buf.Length, SocketFlags.None));
792 public int Send(byte[] buf, SocketFlags flags) {
793 return(Send(buf, 0, buf.Length, flags));
796 public int Send(byte[] buf, int size, SocketFlags flags) {
797 return(Send(buf, 0, size, flags));
800 [MethodImplAttribute(MethodImplOptions.InternalCall)]
801 private extern static int Send_internal(IntPtr sock,
802 byte[] buf, int offset,
806 public int Send(byte[] buf, int offset, int size,
809 throw new ArgumentNullException();
811 if(offset+size>buf.Length) {
812 throw new ArgumentException();
818 ret=Send_internal(socket, buf, offset, size,
820 } catch(SocketException) {
829 public int SendTo(byte[] buffer, EndPoint remote_end) {
830 return(SendTo(buffer, 0, buffer.Length,
831 SocketFlags.None, remote_end));
834 public int SendTo(byte[] buffer, SocketFlags flags,
835 EndPoint remote_end) {
836 return(SendTo(buffer, 0, buffer.Length, flags,
840 public int SendTo(byte[] buffer, int size, SocketFlags flags,
841 EndPoint remote_end) {
842 return(SendTo(buffer, size, buffer.Length, flags,
847 [MethodImplAttribute(MethodImplOptions.InternalCall)]
848 private extern static int SendTo_internal(IntPtr sock,
855 public int SendTo(byte[] buffer, int offset, int size,
856 SocketFlags flags, EndPoint remote_end) {
857 if(buffer==null || remote_end==null) {
858 throw new ArgumentNullException();
860 if(offset+size>buffer.Length) {
861 throw new ArgumentException();
864 SocketAddress sockaddr=remote_end.Serialize();
869 ret=SendTo_internal(socket, buffer, offset,
870 size, flags, sockaddr);
872 catch(SocketException) {
881 [MethodImplAttribute(MethodImplOptions.InternalCall)]
882 private extern static void SetSocketOption_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte[] byte_val, int int_val);
884 public void SetSocketOption(SocketOptionLevel level,
885 SocketOptionName name,
887 SetSocketOption_internal(socket, level, name, null,
891 public void SetSocketOption(SocketOptionLevel level,
892 SocketOptionName name,
894 SetSocketOption_internal(socket, level, name, null,
898 public void SetSocketOption(SocketOptionLevel level,
899 SocketOptionName name,
901 if(opt_value==null) {
902 throw new ArgumentNullException();
905 /* Passing a bool as the third parameter to
906 * SetSocketOption causes this overload to be
907 * used when in fact we want to pass the value
908 * to the runtime as an int.
910 if(opt_value is System.Boolean) {
911 bool bool_val=(bool)opt_value;
913 /* Stupid casting rules :-( */
915 SetSocketOption_internal(socket, level,
919 SetSocketOption_internal(socket, level,
924 SetSocketOption_internal(socket, level, name,
929 [MethodImplAttribute(MethodImplOptions.InternalCall)]
930 private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how);
932 public void Shutdown(SocketShutdown how) {
933 Shutdown_internal(socket, how);
936 private bool disposed = false;
938 protected virtual void Dispose(bool explicitDisposing) {
939 // Check to see if Dispose has already been called
941 // If this is a call to Dispose,
942 // dispose all managed resources.
943 if(explicitDisposing) {
944 // Free up stuff here
947 // Release unmanaged resources
953 public void Dispose() {
955 // Take yourself off the Finalization queue
956 GC.SuppressFinalize(this);