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;
136 ((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);
448 Thread child=new Thread(new ThreadStart(worker.Accept));
453 public IAsyncResult BeginConnect(EndPoint end_point,
454 AsyncCallback callback,
456 SocketAsyncResult req=new SocketAsyncResult(state);
457 Worker worker=new Worker(this, end_point, callback,
459 Thread child=new Thread(new ThreadStart(worker.Connect));
464 public IAsyncResult BeginReceive(byte[] buffer, int offset,
466 SocketFlags socket_flags,
467 AsyncCallback callback,
469 SocketAsyncResult req=new SocketAsyncResult(state);
470 Worker worker=new Worker(this, buffer, offset, size,
471 socket_flags, callback, req);
472 Thread child=new Thread(new ThreadStart(worker.Receive));
477 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
479 SocketFlags socket_flags,
480 ref EndPoint remote_end,
481 AsyncCallback callback,
483 SocketAsyncResult req=new SocketAsyncResult(state);
484 Worker worker=new Worker(this, buffer, offset, size,
485 socket_flags, remote_end,
487 Thread child=new Thread(new ThreadStart(worker.ReceiveFrom));
492 public IAsyncResult BeginSend(byte[] buffer, int offset,
494 SocketFlags socket_flags,
495 AsyncCallback callback,
497 SocketAsyncResult req=new SocketAsyncResult(state);
498 Worker worker=new Worker(this, buffer, offset, size,
499 socket_flags, callback, req);
500 Thread child=new Thread(new ThreadStart(worker.Send));
505 public IAsyncResult BeginSendTo(byte[] buffer, int offset,
507 SocketFlags socket_flags,
509 AsyncCallback callback,
511 SocketAsyncResult req=new SocketAsyncResult(state);
512 Worker worker=new Worker(this, buffer, offset, size,
513 socket_flags, remote_end,
515 Thread child=new Thread(new ThreadStart(worker.SendTo));
520 // Creates a new system socket, returning the handle
521 [MethodImplAttribute(MethodImplOptions.InternalCall)]
522 private extern static void Bind_internal(IntPtr sock,
525 public void Bind(EndPoint local_end) {
526 if(local_end==null) {
527 throw new ArgumentNullException();
530 Bind_internal(socket, local_end.Serialize());
534 [MethodImplAttribute(MethodImplOptions.InternalCall)]
535 private extern static void Close_internal(IntPtr socket);
537 public void Close() {
539 Close_internal(socket);
542 // Connects to the remote address
543 [MethodImplAttribute(MethodImplOptions.InternalCall)]
544 private extern static void Connect_internal(IntPtr sock,
547 public void Connect(EndPoint remote_end) {
548 if(remote_end==null) {
549 throw new ArgumentNullException();
552 Connect_internal(socket, remote_end.Serialize());
556 public Socket EndAccept(IAsyncResult result) {
557 SocketAsyncResult req=(SocketAsyncResult)result;
559 result.AsyncWaitHandle.WaitOne();
560 return(req.Worker.Socket);
563 public void EndConnect(IAsyncResult result) {
564 SocketAsyncResult req=(SocketAsyncResult)result;
566 result.AsyncWaitHandle.WaitOne();
569 public int EndReceive(IAsyncResult result) {
570 SocketAsyncResult req=(SocketAsyncResult)result;
572 result.AsyncWaitHandle.WaitOne();
573 return(req.Worker.Total);
576 public int EndReceiveFrom(IAsyncResult result,
577 ref EndPoint end_point) {
578 SocketAsyncResult req=(SocketAsyncResult)result;
580 result.AsyncWaitHandle.WaitOne();
581 end_point=req.Worker.EndPoint;
582 return(req.Worker.Total);
585 public int EndSend(IAsyncResult result) {
586 SocketAsyncResult req=(SocketAsyncResult)result;
588 result.AsyncWaitHandle.WaitOne();
589 return(req.Worker.Total);
592 public int EndSendTo(IAsyncResult result) {
593 SocketAsyncResult req=(SocketAsyncResult)result;
595 result.AsyncWaitHandle.WaitOne();
596 return(req.Worker.Total);
599 [MethodImplAttribute(MethodImplOptions.InternalCall)]
600 private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val);
601 [MethodImplAttribute(MethodImplOptions.InternalCall)]
602 private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val);
604 public object GetSocketOption(SocketOptionLevel level,
605 SocketOptionName name) {
608 GetSocketOption_obj_internal(socket, level, name,
611 if(name==SocketOptionName.Linger) {
612 return((LingerOption)obj_val);
613 } else if (name==SocketOptionName.AddMembership ||
614 name==SocketOptionName.DropMembership) {
615 return((MulticastOption)obj_val);
617 return((int)obj_val);
621 public void GetSocketOption(SocketOptionLevel level,
622 SocketOptionName name,
624 int opt_value_len=opt_value.Length;
626 GetSocketOption_arr_internal(socket, level, name,
630 public byte[] GetSocketOption(SocketOptionLevel level,
631 SocketOptionName name,
633 byte[] byte_val=new byte[length];
635 GetSocketOption_arr_internal(socket, level, name,
641 [MonoTODO("Totally undocumented")]
642 public int IOControl(int ioctl_code, byte[] in_value,
644 throw new NotImplementedException();
647 [MethodImplAttribute(MethodImplOptions.InternalCall)]
648 private extern static void Listen_internal(IntPtr sock,
651 public void Listen(int backlog) {
652 Listen_internal(socket, backlog);
655 /* The docs for Poll() are a bit lightweight too, but
656 * it seems to be just a simple wrapper around Select.
658 public bool Poll(int time_us, SelectMode mode) {
659 ArrayList socketlist=new ArrayList(1);
661 socketlist.Add(socket);
664 case SelectMode.SelectError:
665 Select(null, null, socketlist, time_us);
667 case SelectMode.SelectRead:
668 Select(socketlist, null, null, time_us);
670 case SelectMode.SelectWrite:
671 Select(null, socketlist, null, time_us);
674 throw new NotSupportedException();
677 if(socketlist.Contains(socket)) {
684 public int Receive(byte[] buf) {
685 return(Receive(buf, 0, buf.Length, SocketFlags.None));
688 public int Receive(byte[] buf, SocketFlags flags) {
689 return(Receive(buf, 0, buf.Length, flags));
692 public int Receive(byte[] buf, int size, SocketFlags flags) {
693 return(Receive(buf, 0, size, flags));
696 [MethodImplAttribute(MethodImplOptions.InternalCall)]
697 private extern static int Receive_internal(IntPtr sock,
703 public int Receive(byte[] buf, int offset, int size,
706 throw new ArgumentNullException();
708 if(offset+size>buf.Length) {
709 throw new ArgumentException();
715 ret=Receive_internal(socket, buf, offset,
717 } catch(SocketException) {
726 public int ReceiveFrom(byte[] buf, ref EndPoint remote_end) {
727 return(ReceiveFrom(buf, 0, buf.Length,
728 SocketFlags.None, ref remote_end));
731 public int ReceiveFrom(byte[] buf, SocketFlags flags,
732 ref EndPoint remote_end) {
733 return(ReceiveFrom(buf, 0, buf.Length, flags,
737 public int ReceiveFrom(byte[] buf, int size, SocketFlags flags,
738 ref EndPoint remote_end) {
739 return(ReceiveFrom(buf, 0, size, flags,
744 [MethodImplAttribute(MethodImplOptions.InternalCall)]
745 private extern static int RecvFrom_internal(IntPtr sock,
750 ref SocketAddress sockaddr);
752 public int ReceiveFrom(byte[] buf, int offset, int size,
754 ref EndPoint remote_end) {
755 if(buf==null || remote_end==null) {
756 throw new ArgumentNullException();
758 if(offset+size>buf.Length) {
759 throw new ArgumentException();
762 SocketAddress sockaddr=remote_end.Serialize();
766 count=RecvFrom_internal(socket, buf, offset,
769 } catch(SocketException) {
775 // Stupidly, EndPoint.Create() is an
777 remote_end=remote_end.Create(sockaddr);
782 public int Send(byte[] buf) {
783 return(Send(buf, 0, buf.Length, SocketFlags.None));
786 public int Send(byte[] buf, SocketFlags flags) {
787 return(Send(buf, 0, buf.Length, flags));
790 public int Send(byte[] buf, int size, SocketFlags flags) {
791 return(Send(buf, 0, size, flags));
794 [MethodImplAttribute(MethodImplOptions.InternalCall)]
795 private extern static int Send_internal(IntPtr sock,
796 byte[] buf, int offset,
800 public int Send(byte[] buf, int offset, int size,
803 throw new ArgumentNullException();
805 if(offset+size>buf.Length) {
806 throw new ArgumentException();
812 ret=Send_internal(socket, buf, offset, size,
814 } catch(SocketException) {
823 public int SendTo(byte[] buffer, EndPoint remote_end) {
824 return(SendTo(buffer, 0, buffer.Length,
825 SocketFlags.None, remote_end));
828 public int SendTo(byte[] buffer, SocketFlags flags,
829 EndPoint remote_end) {
830 return(SendTo(buffer, 0, buffer.Length, flags,
834 public int SendTo(byte[] buffer, int size, SocketFlags flags,
835 EndPoint remote_end) {
836 return(SendTo(buffer, size, buffer.Length, flags,
841 [MethodImplAttribute(MethodImplOptions.InternalCall)]
842 private extern static int SendTo_internal(IntPtr sock,
849 public int SendTo(byte[] buffer, int offset, int size,
850 SocketFlags flags, EndPoint remote_end) {
851 if(buffer==null || remote_end==null) {
852 throw new ArgumentNullException();
854 if(offset+size>buffer.Length) {
855 throw new ArgumentException();
858 SocketAddress sockaddr=remote_end.Serialize();
863 ret=SendTo_internal(socket, buffer, offset,
864 size, flags, sockaddr);
866 catch(SocketException) {
875 [MethodImplAttribute(MethodImplOptions.InternalCall)]
876 private extern static void SetSocketOption_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte[] byte_val, int int_val);
878 public void SetSocketOption(SocketOptionLevel level,
879 SocketOptionName name,
881 SetSocketOption_internal(socket, level, name, null,
885 public void SetSocketOption(SocketOptionLevel level,
886 SocketOptionName name,
888 SetSocketOption_internal(socket, level, name, null,
892 public void SetSocketOption(SocketOptionLevel level,
893 SocketOptionName name,
895 if(opt_value==null) {
896 throw new ArgumentNullException();
899 SetSocketOption_internal(socket, level, name,
903 [MethodImplAttribute(MethodImplOptions.InternalCall)]
904 private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how);
906 public void Shutdown(SocketShutdown how) {
907 Shutdown_internal(socket, how);
910 private bool disposed = false;
912 protected virtual void Dispose(bool explicitDisposing) {
913 // Check to see if Dispose has already been called
915 // If this is a call to Dispose,
916 // dispose all managed resources.
917 if(explicitDisposing) {
918 // Free up stuff here
921 // Release unmanaged resources
927 public void Dispose() {
929 // Take yourself off the Finalization queue
930 GC.SuppressFinalize(this);