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;
140 public void Accept() {
142 acc_socket=socket.Accept();
147 public void Connect() {
149 if (socket.Blocking) {
150 socket.Connect(endpoint);
155 SocketException rethrow = null;
157 socket.Connect (endpoint);
158 } catch (SocketException e) {
160 if (e.NativeErrorCode != 10036)
163 socket.Poll (-1, SelectMode.SelectWrite);
165 socket.Connect (endpoint);
166 } catch (SocketException e2) {
176 public void Receive() {
178 if (socket.Blocking) {
179 total=socket.Receive(buffer, offset,
185 SocketException rethrow = null;
187 total = socket.Receive (buffer, offset, size, sockflags);
188 } catch (SocketException e) {
190 if (e.NativeErrorCode != 10035)
193 socket.Poll (-1, SelectMode.SelectRead);
195 total = socket.Receive (buffer, offset, size, sockflags);
196 } catch (SocketException e2) {
206 public void ReceiveFrom() {
208 total=socket.ReceiveFrom(buffer,
218 total=socket.Send(buffer, offset, size,
224 public void SendTo() {
226 total=socket.SendTo(buffer, offset,
233 public EndPoint EndPoint {
239 public Socket Socket {
252 /* the field "socket" is looked up by name by the runtime */
253 private IntPtr socket;
254 private AddressFamily address_family;
255 private SocketType socket_type;
256 private ProtocolType protocol_type;
257 private bool blocking=true;
259 /* When true, the socket was connected at the time of
260 * the last IO operation
262 private bool connected=false;
264 [MethodImplAttribute(MethodImplOptions.InternalCall)]
265 private extern static void Select_internal(ref Socket[] read,
270 public static void Select(IList read_list, IList write_list,
271 IList err_list, int time_us) {
272 if(read_list==null &&
275 throw new ArgumentNullException();
278 int read_count, write_count, err_count;
280 if(read_list!=null) {
281 read_count=read_list.Count;
286 if(write_list!=null) {
287 write_count=write_list.Count;
293 err_count=err_list.Count;
298 Socket[] read_arr=new Socket[read_count];
299 Socket[] write_arr=new Socket[write_count];
300 Socket[] err_arr=new Socket[err_count];
304 if(read_list!=null) {
307 foreach (Socket s in read_list) {
313 if(write_list!=null) {
315 foreach (Socket s in write_list) {
323 foreach (Socket s in err_list) {
329 Select_internal(ref read_arr, ref write_arr,
330 ref err_arr, time_us);
332 if(read_list!=null) {
334 for(i=0; i<read_arr.Length; i++) {
335 read_list.Add(read_arr[i]);
339 if(write_list!=null) {
341 for(i=0; i<write_arr.Length; i++) {
342 write_list.Add(write_arr[i]);
348 for(i=0; i<err_arr.Length; i++) {
349 err_list.Add(err_arr[i]);
354 // private constructor used by Accept, which already
355 // has a socket handle to use
356 private Socket(AddressFamily family, SocketType type,
357 ProtocolType proto, IntPtr sock) {
358 address_family=family;
366 // Creates a new system socket, returning the handle
367 [MethodImplAttribute(MethodImplOptions.InternalCall)]
368 private extern IntPtr Socket_internal(AddressFamily family,
372 public Socket(AddressFamily family, SocketType type,
373 ProtocolType proto) {
374 address_family=family;
378 socket=Socket_internal(family, type, proto);
381 public AddressFamily AddressFamily {
383 return(address_family);
387 // Returns the amount of data waiting to be read on socket
388 [MethodImplAttribute(MethodImplOptions.InternalCall)]
389 private extern static int Available_internal(IntPtr socket);
391 public int Available {
393 return(Available_internal(socket));
397 [MethodImplAttribute(MethodImplOptions.InternalCall)]
398 private extern static void Blocking_internal(IntPtr socket,
401 public bool Blocking {
406 Blocking_internal(socket, value);
411 public bool Connected {
417 public IntPtr Handle {
423 // Returns the local endpoint details in addr and port
424 [MethodImplAttribute(MethodImplOptions.InternalCall)]
425 private extern static SocketAddress LocalEndPoint_internal(IntPtr socket);
427 [MonoTODO("Support non-IP endpoints")]
428 public EndPoint LocalEndPoint {
432 sa=LocalEndPoint_internal(socket);
434 if(sa.Family==AddressFamily.InterNetwork) {
435 // Stupidly, EndPoint.Create() is an
437 return new IPEndPoint(0, 0).Create(sa);
439 throw new NotImplementedException();
444 public ProtocolType ProtocolType {
446 return(protocol_type);
450 // Returns the remote endpoint details in addr and port
451 [MethodImplAttribute(MethodImplOptions.InternalCall)]
452 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket);
454 [MonoTODO("Support non-IP endpoints")]
455 public EndPoint RemoteEndPoint {
459 sa=RemoteEndPoint_internal(socket);
461 if(sa.Family==AddressFamily.InterNetwork) {
462 // Stupidly, EndPoint.Create() is an
464 return new IPEndPoint(0, 0).Create(sa);
466 throw new NotImplementedException();
471 public SocketType SocketType {
477 // Creates a new system socket, returning the handle
478 [MethodImplAttribute(MethodImplOptions.InternalCall)]
479 private extern static IntPtr Accept_internal(IntPtr sock);
481 public Socket Accept() {
482 IntPtr sock=Accept_internal(socket);
484 return(new Socket(this.AddressFamily, this.SocketType,
485 this.ProtocolType, sock));
488 public IAsyncResult BeginAccept(AsyncCallback callback,
490 SocketAsyncResult req=new SocketAsyncResult(state);
491 Worker worker=new Worker(this, callback, req);
493 Thread child=new Thread(new ThreadStart(worker.Accept));
498 public IAsyncResult BeginConnect(EndPoint end_point,
499 AsyncCallback callback,
501 SocketAsyncResult req=new SocketAsyncResult(state);
502 Worker worker=new Worker(this, end_point, callback,
505 Thread child=new Thread(new ThreadStart(worker.Connect));
510 public IAsyncResult BeginReceive(byte[] buffer, int offset,
512 SocketFlags socket_flags,
513 AsyncCallback callback,
515 SocketAsyncResult req=new SocketAsyncResult(state);
516 Worker worker=new Worker(this, buffer, offset, size,
517 socket_flags, callback, req);
519 Thread child=new Thread(new ThreadStart(worker.Receive));
524 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
526 SocketFlags socket_flags,
527 ref EndPoint remote_end,
528 AsyncCallback callback,
530 SocketAsyncResult req=new SocketAsyncResult(state);
531 Worker worker=new Worker(this, buffer, offset, size,
532 socket_flags, remote_end,
535 Thread child=new Thread(new ThreadStart(worker.ReceiveFrom));
540 public IAsyncResult BeginSend(byte[] buffer, int offset,
542 SocketFlags socket_flags,
543 AsyncCallback callback,
545 SocketAsyncResult req=new SocketAsyncResult(state);
546 Worker worker=new Worker(this, buffer, offset, size,
547 socket_flags, callback, req);
549 Thread child=new Thread(new ThreadStart(worker.Send));
554 public IAsyncResult BeginSendTo(byte[] buffer, int offset,
556 SocketFlags socket_flags,
558 AsyncCallback callback,
560 SocketAsyncResult req=new SocketAsyncResult(state);
561 Worker worker=new Worker(this, buffer, offset, size,
562 socket_flags, remote_end,
565 Thread child=new Thread(new ThreadStart(worker.SendTo));
570 // Creates a new system socket, returning the handle
571 [MethodImplAttribute(MethodImplOptions.InternalCall)]
572 private extern static void Bind_internal(IntPtr sock,
575 public void Bind(EndPoint local_end) {
576 if(local_end==null) {
577 throw new ArgumentNullException();
580 Bind_internal(socket, local_end.Serialize());
584 [MethodImplAttribute(MethodImplOptions.InternalCall)]
585 private extern static void Close_internal(IntPtr socket);
587 public void Close() {
591 // Connects to the remote address
592 [MethodImplAttribute(MethodImplOptions.InternalCall)]
593 private extern static void Connect_internal(IntPtr sock,
596 public void Connect(EndPoint remote_end) {
597 if(remote_end==null) {
598 throw new ArgumentNullException();
601 Connect_internal(socket, remote_end.Serialize());
605 public Socket EndAccept(IAsyncResult result) {
606 SocketAsyncResult req=(SocketAsyncResult)result;
608 result.AsyncWaitHandle.WaitOne();
609 return(req.Worker.Socket);
612 public void EndConnect(IAsyncResult result) {
613 SocketAsyncResult req=(SocketAsyncResult)result;
615 result.AsyncWaitHandle.WaitOne();
618 public int EndReceive(IAsyncResult result) {
619 SocketAsyncResult req=(SocketAsyncResult)result;
621 result.AsyncWaitHandle.WaitOne();
622 return(req.Worker.Total);
625 public int EndReceiveFrom(IAsyncResult result,
626 ref EndPoint end_point) {
627 SocketAsyncResult req=(SocketAsyncResult)result;
629 result.AsyncWaitHandle.WaitOne();
630 end_point=req.Worker.EndPoint;
631 return(req.Worker.Total);
634 public int EndSend(IAsyncResult result) {
635 SocketAsyncResult req=(SocketAsyncResult)result;
637 result.AsyncWaitHandle.WaitOne();
638 return(req.Worker.Total);
641 public int EndSendTo(IAsyncResult result) {
642 SocketAsyncResult req=(SocketAsyncResult)result;
644 result.AsyncWaitHandle.WaitOne();
645 return(req.Worker.Total);
648 [MethodImplAttribute(MethodImplOptions.InternalCall)]
649 private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val);
650 [MethodImplAttribute(MethodImplOptions.InternalCall)]
651 private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val);
653 public object GetSocketOption(SocketOptionLevel level,
654 SocketOptionName name) {
657 GetSocketOption_obj_internal(socket, level, name,
660 if(name==SocketOptionName.Linger) {
661 return((LingerOption)obj_val);
662 } else if (name==SocketOptionName.AddMembership ||
663 name==SocketOptionName.DropMembership) {
664 return((MulticastOption)obj_val);
666 return((int)obj_val);
670 public void GetSocketOption(SocketOptionLevel level,
671 SocketOptionName name,
673 int opt_value_len=opt_value.Length;
675 GetSocketOption_arr_internal(socket, level, name,
679 public byte[] GetSocketOption(SocketOptionLevel level,
680 SocketOptionName name,
682 byte[] byte_val=new byte[length];
684 GetSocketOption_arr_internal(socket, level, name,
690 [MonoTODO("Totally undocumented")]
691 public int IOControl(int ioctl_code, byte[] in_value,
693 throw new NotImplementedException();
696 [MethodImplAttribute(MethodImplOptions.InternalCall)]
697 private extern static void Listen_internal(IntPtr sock,
700 public void Listen(int backlog) {
701 Listen_internal(socket, backlog);
704 /* The docs for Poll() are a bit lightweight too, but
705 * it seems to be just a simple wrapper around Select.
707 public bool Poll(int time_us, SelectMode mode) {
708 ArrayList socketlist=new ArrayList(1);
710 socketlist.Add(this);
713 case SelectMode.SelectError:
714 Select(null, null, socketlist, time_us);
716 case SelectMode.SelectRead:
717 Select(socketlist, null, null, time_us);
719 case SelectMode.SelectWrite:
720 Select(null, socketlist, null, time_us);
723 throw new NotSupportedException();
726 if(socketlist.Contains(this)) {
733 public int Receive(byte[] buf) {
734 return(Receive(buf, 0, buf.Length, SocketFlags.None));
737 public int Receive(byte[] buf, SocketFlags flags) {
738 return(Receive(buf, 0, buf.Length, flags));
741 public int Receive(byte[] buf, int size, SocketFlags flags) {
742 return(Receive(buf, 0, size, flags));
745 [MethodImplAttribute(MethodImplOptions.InternalCall)]
746 private extern static int Receive_internal(IntPtr sock,
752 public int Receive(byte[] buf, int offset, int size,
755 throw new ArgumentNullException("buffer is null");
757 if(offset<0 || offset >= buf.Length) {
758 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
760 if(offset+size<0 || offset+size > buf.Length) {
761 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
767 ret=Receive_internal(socket, buf, offset,
769 } catch(SocketException) {
778 public int ReceiveFrom(byte[] buf, ref EndPoint remote_end) {
779 return(ReceiveFrom(buf, 0, buf.Length,
780 SocketFlags.None, ref remote_end));
783 public int ReceiveFrom(byte[] buf, SocketFlags flags,
784 ref EndPoint remote_end) {
785 return(ReceiveFrom(buf, 0, buf.Length, flags,
789 public int ReceiveFrom(byte[] buf, int size, SocketFlags flags,
790 ref EndPoint remote_end) {
791 return(ReceiveFrom(buf, 0, size, flags,
796 [MethodImplAttribute(MethodImplOptions.InternalCall)]
797 private extern static int RecvFrom_internal(IntPtr sock,
802 ref SocketAddress sockaddr);
804 public int ReceiveFrom(byte[] buf, int offset, int size,
806 ref EndPoint remote_end) {
808 throw new ArgumentNullException("buffer is null");
810 if(remote_end==null) {
811 throw new ArgumentNullException("remote endpoint is null");
813 if(offset<0 || offset>=buf.Length) {
814 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
816 if(offset+size<0 || offset+size>buf.Length) {
817 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
820 SocketAddress sockaddr=remote_end.Serialize();
824 count=RecvFrom_internal(socket, buf, offset,
827 } catch(SocketException) {
833 // Stupidly, EndPoint.Create() is an
835 remote_end=remote_end.Create(sockaddr);
840 public int Send(byte[] buf) {
841 return(Send(buf, 0, buf.Length, SocketFlags.None));
844 public int Send(byte[] buf, SocketFlags flags) {
845 return(Send(buf, 0, buf.Length, flags));
848 public int Send(byte[] buf, int size, SocketFlags flags) {
849 return(Send(buf, 0, size, flags));
852 [MethodImplAttribute(MethodImplOptions.InternalCall)]
853 private extern static int Send_internal(IntPtr sock,
854 byte[] buf, int offset,
858 public int Send (byte[] buf, int offset, int size, SocketFlags flags)
861 throw new ArgumentNullException ("buffer");
863 if (offset < 0 || offset > buf.Length)
864 throw new ArgumentOutOfRangeException ("offset");
866 if (size < 0 || offset + size > buf.Length)
867 throw new ArgumentOutOfRangeException ("size");
875 ret = Send_internal (socket, buf, offset, size, flags);
876 } catch (SocketException) {
885 public int SendTo(byte[] buffer, EndPoint remote_end) {
886 return(SendTo(buffer, 0, buffer.Length,
887 SocketFlags.None, remote_end));
890 public int SendTo(byte[] buffer, SocketFlags flags,
891 EndPoint remote_end) {
892 return(SendTo(buffer, 0, buffer.Length, flags,
896 public int SendTo(byte[] buffer, int size, SocketFlags flags,
897 EndPoint remote_end) {
898 return(SendTo(buffer, size, buffer.Length, flags,
903 [MethodImplAttribute(MethodImplOptions.InternalCall)]
904 private extern static int SendTo_internal(IntPtr sock,
911 public int SendTo(byte[] buffer, int offset, int size,
912 SocketFlags flags, EndPoint remote_end) {
914 throw new ArgumentNullException("buffer is null");
916 if(remote_end==null) {
917 throw new ArgumentNullException("remote endpoint is null");
919 if(offset<0 || offset>=buffer.Length) {
920 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
922 if(offset+size<0 || offset+size>buffer.Length) {
923 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
926 SocketAddress sockaddr=remote_end.Serialize();
931 ret=SendTo_internal(socket, buffer, offset,
932 size, flags, sockaddr);
934 catch(SocketException) {
943 [MethodImplAttribute(MethodImplOptions.InternalCall)]
944 private extern static void SetSocketOption_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte[] byte_val, int int_val);
946 public void SetSocketOption(SocketOptionLevel level,
947 SocketOptionName name,
949 SetSocketOption_internal(socket, level, name, null,
953 public void SetSocketOption(SocketOptionLevel level,
954 SocketOptionName name,
956 SetSocketOption_internal(socket, level, name, null,
960 public void SetSocketOption(SocketOptionLevel level,
961 SocketOptionName name,
963 if(opt_value==null) {
964 throw new ArgumentNullException();
967 /* Passing a bool as the third parameter to
968 * SetSocketOption causes this overload to be
969 * used when in fact we want to pass the value
970 * to the runtime as an int.
972 if(opt_value is System.Boolean) {
973 bool bool_val=(bool)opt_value;
975 /* Stupid casting rules :-( */
977 SetSocketOption_internal(socket, level,
981 SetSocketOption_internal(socket, level,
986 SetSocketOption_internal(socket, level, name,
991 [MethodImplAttribute(MethodImplOptions.InternalCall)]
992 private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how);
994 public void Shutdown(SocketShutdown how) {
995 Shutdown_internal(socket, how);
998 private bool disposed = false;
1000 protected virtual void Dispose(bool explicitDisposing) {
1001 // Check to see if Dispose has already been called
1002 if(!this.disposed) {
1003 // If this is a call to Dispose,
1004 // dispose all managed resources.
1005 if(explicitDisposing) {
1006 // Free up stuff here
1009 // Release unmanaged resources
1013 Close_internal(socket);
1017 public void Dispose() {
1019 // Take yourself off the Finalization queue
1020 GC.SuppressFinalize(this);