2003-07-18 Andreas Nahr <ClassDevelopment@A-SoftTech.com>
[mono.git] / mcs / class / System / System.Net.Sockets / Socket.cs
1 // System.Net.Sockets.Socket.cs
2 //
3 // Authors:
4 //    Phillip Pearson (pp@myelin.co.nz)
5 //    Dick Porter <dick@ximian.com>
6 //
7 // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
8 //    http://www.myelin.co.nz
9 //
10
11 using System;
12 using System.Net;
13 using System.Collections;
14 using System.Runtime.CompilerServices;
15 using System.Threading;
16 using System.Reflection;
17 using System.IO;
18
19 namespace System.Net.Sockets 
20 {
21         public class Socket : IDisposable 
22         {
23                 private sealed class SocketAsyncResult: IAsyncResult 
24                 {
25                         private object state;
26                         private WaitHandle waithandle;
27                         private bool completed_sync, completed;
28                         private Worker worker;
29
30                         public SocketAsyncResult(object state) {
31                                 this.state=state;
32                                 waithandle=new ManualResetEvent(false);
33                                 completed_sync=completed=false;
34                         }
35
36                         public object AsyncState {
37                                 get {
38                                         return(state);
39                                 }
40                         }
41
42                         public WaitHandle AsyncWaitHandle {
43                                 get {
44                                         return(waithandle);
45                                 }
46                                 set {
47                                         waithandle=value;
48                                 }
49                         }
50
51                         public bool CompletedSynchronously {
52                                 get {
53                                         return(completed_sync);
54                                 }
55                         }
56
57                         public bool IsCompleted {
58                                 get {
59                                         return(completed);
60                                 }
61                                 set {
62                                         completed=value;
63                                 }
64                         }
65                         
66                         public Worker Worker {
67                                 get {
68                                         return(worker);
69                                 }
70                                 set {
71                                         worker=value;
72                                 }
73                         }
74                 }
75
76                 private sealed class Worker 
77                 {
78                         private AsyncCallback callback;
79                         private SocketAsyncResult result;
80                         private Socket socket;
81
82                         // Parameters
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
88
89                         // Return values
90                         private Socket acc_socket;
91                         private int total;
92                         
93
94                         // For Accept
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) {}
100
101                         // For Connect
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,
107                                        req_result) {}
108
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) {}
118
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) {
126                                 socket=req_sock;
127                                 buffer=req_buffer;
128                                 offset=req_offset;
129                                 size=req_size;
130                                 sockflags=req_sockflags;
131                                 endpoint=req_endpoint;
132                                 callback=req_callback;
133                                 result=req_result;
134                         }
135
136                         private void End() {
137                                 ((ManualResetEvent)result.AsyncWaitHandle).Set();
138                                 result.IsCompleted=true;
139                                 if (callback != null)
140                                         callback(result);
141                         }
142                         
143                         public void Accept() {
144                                 lock(result) {
145                                         acc_socket=socket.Accept();
146                                         End();
147                                 }
148                         }
149
150                         public void Connect() {
151                                 lock(result) {
152                                         if (socket.Blocking) {
153                                                 socket.Connect(endpoint);
154                                                 End ();
155                                                 return;
156                                         }
157
158                                         SocketException rethrow = null;
159                                         try {
160                                                 socket.Connect (endpoint);
161                                         } catch (SocketException e) {
162                                                 //WSAEINPROGRESS
163                                                 if (e.NativeErrorCode != 10036)
164                                                         throw;
165
166                                                 socket.Poll (-1, SelectMode.SelectWrite);
167                                                 try {
168                                                         socket.Connect (endpoint);
169                                                 } catch (SocketException e2) {
170                                                         rethrow = e2;
171                                                 }
172                                         }
173                                         End ();
174                                         if (rethrow != null)
175                                                 throw rethrow;
176                                 }
177                         }
178
179                         public void Receive() {
180                                 lock(result) {
181                                         if (socket.Blocking) {
182                                                 total=socket.Receive(buffer, offset,
183                                                                      size, sockflags);
184                                                 End();
185                                                 return;
186                                         }
187
188                                         SocketException rethrow = null;
189                                         try {
190                                                 total = socket.Receive (buffer, offset, size, sockflags);
191                                         } catch (SocketException e) {
192                                                 //WSAEWOULDBLOCK
193                                                 if (e.NativeErrorCode != 10035)
194                                                         throw;
195
196                                                 socket.Poll (-1, SelectMode.SelectRead);
197                                                 try {
198                                                         total = socket.Receive (buffer, offset, size, sockflags);
199                                                 } catch (SocketException e2) {
200                                                         rethrow = e2;
201                                                 }
202                                         }
203                                         End ();
204                                         if (rethrow != null)
205                                                 throw rethrow;
206                                 }
207                         }
208
209                         public void ReceiveFrom() {
210                                 lock(result) {
211                                         total=socket.ReceiveFrom(buffer,
212                                                                  offset, size,
213                                                                  sockflags,
214                                                                  ref endpoint);
215                                         End();
216                                 }
217                         }
218
219                         public void Send() {
220                                 lock(result) {
221                                         total=socket.Send(buffer, offset, size,
222                                                           sockflags);
223                                         End();
224                                 }
225                         }
226
227                         public void SendTo() {
228                                 lock(result) {
229                                         total=socket.SendTo(buffer, offset,
230                                                             size, sockflags,
231                                                             endpoint);
232                                         End();
233                                 }
234                         }
235
236                         public EndPoint EndPoint {
237                                 get {
238                                         return(endpoint);
239                                 }
240                         }
241
242                         public Socket Socket {
243                                 get {
244                                         return(acc_socket);
245                                 }
246                         }
247
248                         public int Total {
249                                 get {
250                                         return(total);
251                                 }
252                         }
253                 }
254                         
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;
261 \r
262                 /*\r
263                  *      These two fields are looked up by name by the runtime, don't change\r
264                  *  their name without also updating the runtime code.\r
265                  */
266                 private static int ipv4Supported = -1, ipv6Supported = -1;
267
268                 /* When true, the socket was connected at the time of
269                  * the last IO operation
270                  */
271                 private bool connected=false;
272
273                 /* Used in LocalEndPoint and RemoteEndPoint if the
274                  * Mono.Posix assembly is available
275                  */
276                 private static object unixendpoint=null;
277                 private static Type unixendpointtype=null;
278                 
279                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
280                 private extern static void Select_internal(ref Socket[] read,
281                                                            ref Socket[] write,
282                                                            ref Socket[] err,
283                                                            int timeout);
284
285                 public static void Select(IList read_list, IList write_list,
286                                           IList err_list, int time_us) {
287                         if(read_list==null &&
288                            write_list==null &&
289                            err_list==null) {
290                                 throw new ArgumentNullException();
291                         }
292
293                         int read_count = 0, write_count = 0, err_count = 0;
294                         Socket[] read_arr = null;
295                         Socket[] write_arr = null;
296                         Socket[] err_arr = null;
297
298                         if (read_list!=null)
299                                 read_count=read_list.Count;
300
301                         if (read_count != 0)
302                                 read_arr=new Socket[read_count];
303
304                         if (write_list!=null)
305                                 write_count=write_list.Count;
306
307                         if (write_count != 0)
308                                 write_arr=new Socket[write_count];
309
310                         if (err_list!=null)
311                                 err_count=err_list.Count;
312
313                         if (err_count != 0)
314                                 err_arr=new Socket[err_count];
315                         
316                         int i;
317
318                         if (read_count != 0) {
319                                 i=0;
320                                 
321                                 foreach (Socket s in read_list) {
322                                         read_arr[i]=s;
323                                         i++;
324                                 }
325                         }
326
327                         if (write_count != 0) {
328                                 i=0;
329                                 foreach (Socket s in write_list) {
330                                         write_arr[i]=s;
331                                         i++;
332                                 }
333                         }
334                         
335                         if (err_count != 0) {
336                                 i=0;
337                                 foreach (Socket s in err_list) {
338                                         err_arr[i]=s;
339                                         i++;
340                                 }
341                         }
342
343                         Select_internal(ref read_arr, ref write_arr,
344                                         ref err_arr, time_us);
345
346                         if(read_list!=null) {
347                                 read_list.Clear();
348                                 for(i=0; i<read_arr.Length; i++) {
349                                         read_list.Add(read_arr[i]);
350                                 }
351                         }
352                         
353                         if(write_list!=null) {
354                                 write_list.Clear();
355                                 for(i=0; i<write_arr.Length; i++) {
356                                         write_list.Add(write_arr[i]);
357                                 }
358                         }
359                         
360                         if(err_list!=null) {
361                                 err_list.Clear();
362                                 for(i=0; i<err_arr.Length; i++) {
363                                         err_list.Add(err_arr[i]);
364                                 }
365                         }
366                 }
367
368                 static Socket() {
369                         Assembly ass;
370                         
371                         try {
372                                 ass=Assembly.Load("Mono.Posix");
373                         } catch (FileNotFoundException) {
374                                 return;
375                         }
376                                 
377                         unixendpointtype=ass.GetType("Mono.Posix.UnixEndPoint");
378
379                         /* The endpoint Create() method is an instance
380                          * method :-(
381                          */
382                         Type[] arg_types=new Type[1];
383                         arg_types[0]=typeof(string);
384                         ConstructorInfo cons=unixendpointtype.GetConstructor(arg_types);
385
386                         object[] args=new object[1];
387                         args[0]="";
388
389                         unixendpoint=cons.Invoke(args);
390                 }
391
392                 // private constructor used by Accept, which already
393                 // has a socket handle to use
394                 private Socket(AddressFamily family, SocketType type,
395                                ProtocolType proto, IntPtr sock) {
396                         address_family=family;
397                         socket_type=type;
398                         protocol_type=proto;
399                         
400                         socket=sock;
401                         connected=true;
402                 }
403                 
404                 // Creates a new system socket, returning the handle
405                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
406                 private extern IntPtr Socket_internal(AddressFamily family,
407                                                       SocketType type,
408                                                       ProtocolType proto);
409                 
410                 public Socket(AddressFamily family, SocketType type,
411                               ProtocolType proto) {
412                         address_family=family;
413                         socket_type=type;
414                         protocol_type=proto;
415                         
416                         socket=Socket_internal(family, type, proto);
417                 }
418
419                 public AddressFamily AddressFamily {
420                         get {
421                                 return(address_family);
422                         }
423                 }
424
425                 // Returns the amount of data waiting to be read on socket
426                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
427                 private extern static int Available_internal(IntPtr socket);
428                 
429                 public int Available {
430                         get {
431                                 return(Available_internal(socket));
432                         }
433                 }
434
435                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
436                 private extern static void Blocking_internal(IntPtr socket,
437                                                             bool block);
438
439                 public bool Blocking {
440                         get {
441                                 return(blocking);
442                         }
443                         set {
444                                 Blocking_internal(socket, value);
445                                 blocking=value;
446                         }
447                 }
448
449                 public bool Connected {
450                         get {
451                                 return(connected);
452                         }
453                 }
454
455                 public IntPtr Handle {
456                         get {
457                                 return(socket);
458                         }
459                 }
460
461                 // Returns the local endpoint details in addr and port
462                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
463                 private extern static SocketAddress LocalEndPoint_internal(IntPtr socket);
464
465                 [MonoTODO("Support non-IP endpoints")]
466                 public EndPoint LocalEndPoint {
467                         get {
468                                 SocketAddress sa;
469                                 
470                                 sa=LocalEndPoint_internal(socket);
471
472                                 if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6) {
473                                         // Stupidly, EndPoint.Create() is an
474                                         // instance method
475                                         return new IPEndPoint(0, 0).Create(sa);
476                                 } else if (sa.Family==AddressFamily.Unix &&
477                                            unixendpoint!=null) {
478                                         return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
479                                 } else {
480                                         throw new NotImplementedException();
481                                 }
482                         }
483                 }
484
485                 public ProtocolType ProtocolType {
486                         get {
487                                 return(protocol_type);
488                         }
489                 }
490
491                 // Returns the remote endpoint details in addr and port
492                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
493                 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket);
494
495                 [MonoTODO("Support non-IP endpoints")]
496                 public EndPoint RemoteEndPoint {
497                         get {
498                                 SocketAddress sa;
499                                 
500                                 sa=RemoteEndPoint_internal(socket);
501
502                                 if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6 ) {
503                                         // Stupidly, EndPoint.Create() is an
504                                         // instance method
505                                         return new IPEndPoint(0, 0).Create(sa);
506                                 } else if (sa.Family==AddressFamily.Unix &&
507                                            unixendpoint!=null) {
508                                         return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
509                                 } else {
510                                         throw new NotImplementedException();
511                                 }
512                         }
513                 }
514
515                 public SocketType SocketType {
516                         get {
517                                 return(socket_type);
518                         }
519                 }
520
521 #if NET_1_1
522                 public static bool SupportsIPv4 {\r
523                         get {\r
524                                 CheckProtocolSupport();\r
525                                 return ipv4Supported == 1;\r
526                         }\r
527                 }
528
529                 public static bool SupportsIPv6 {\r
530                         get {\r
531                                 CheckProtocolSupport();\r
532                                 return ipv6Supported == 1;\r
533                         }\r
534                 }
535 #else
536                 internal static bool SupportsIPv4 \r
537                 {\r
538                         get \r
539                         {\r
540                                 return true;\r
541                         }\r
542                 }
543
544                 internal static bool SupportsIPv6 \r
545                 {\r
546                         get \r
547                         {\r
548                                 return false;\r
549                         }\r
550                 }\r
551 #endif
552
553                 internal static void CheckProtocolSupport()
554                 {\r
555                         if(ipv4Supported == -1) {\r
556                                 try  {\r
557                                         Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);\r
558                                         tmp.Close();\r
559 \r
560                                         ipv4Supported = 1;\r
561                                 }\r
562                                 catch {\r
563                                         ipv4Supported = 0;\r
564                                 }\r
565                         }\r
566 \r
567                         if(ipv6Supported == -1) {\r
568                                 NetConfig config = (NetConfig)System.Configuration.ConfigurationSettings.GetConfig("system.net/settings");\r
569 \r
570                                 if(config != null)\r
571                                         ipv6Supported = config.ipv6Enabled?-1:0;\r
572 \r
573                                 if(ipv6Supported != 0) {\r
574                                         try {\r
575                                                 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);\r
576                                                 tmp.Close();\r
577 \r
578                                                 ipv6Supported = 1;\r
579                                         }\r
580                                         catch { }\r
581                                 }\r
582                         }\r
583                 }
584
585                 // Creates a new system socket, returning the handle
586                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
587                 private extern static IntPtr Accept_internal(IntPtr sock);
588                 
589                 public Socket Accept() {
590                         IntPtr sock=Accept_internal(socket);
591                         
592                         return(new Socket(this.AddressFamily, this.SocketType,
593                                           this.ProtocolType, sock));
594                 }
595
596                 public IAsyncResult BeginAccept(AsyncCallback callback,
597                                                 object state) {
598                         SocketAsyncResult req=new SocketAsyncResult(state);
599                         Worker worker=new Worker(this, callback, req);
600                         req.Worker=worker;
601                         Thread child=new Thread(new ThreadStart(worker.Accept));
602                         child.Start();
603                         return(req);
604                 }
605
606                 public IAsyncResult BeginConnect(EndPoint end_point,
607                                                  AsyncCallback callback,
608                                                  object state) {
609                         SocketAsyncResult req=new SocketAsyncResult(state);
610                         Worker worker=new Worker(this, end_point, callback,
611                                                  req);
612                         req.Worker=worker;
613                         Thread child=new Thread(new ThreadStart(worker.Connect));
614                         child.Start();
615                         return(req);
616                 }
617
618                 public IAsyncResult BeginReceive(byte[] buffer, int offset,
619                                                  int size,
620                                                  SocketFlags socket_flags,
621                                                  AsyncCallback callback,
622                                                  object state) {
623                         SocketAsyncResult req=new SocketAsyncResult(state);
624                         Worker worker=new Worker(this, buffer, offset, size,
625                                                  socket_flags, callback, req);
626                         req.Worker=worker;
627                         Thread child=new Thread(new ThreadStart(worker.Receive));
628                         child.Start();
629                         return(req);
630                 }
631
632                 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
633                                                      int size,
634                                                      SocketFlags socket_flags,
635                                                      ref EndPoint remote_end,
636                                                      AsyncCallback callback,
637                                                      object state) {
638                         SocketAsyncResult req=new SocketAsyncResult(state);
639                         Worker worker=new Worker(this, buffer, offset, size,
640                                                  socket_flags, remote_end,
641                                                  callback, req);
642                         req.Worker=worker;
643                         Thread child=new Thread(new ThreadStart(worker.ReceiveFrom));
644                         child.Start();
645                         return(req);
646                 }
647
648                 public IAsyncResult BeginSend(byte[] buffer, int offset,
649                                               int size,
650                                               SocketFlags socket_flags,
651                                               AsyncCallback callback,
652                                               object state) {
653                         SocketAsyncResult req=new SocketAsyncResult(state);
654                         Worker worker=new Worker(this, buffer, offset, size,
655                                                  socket_flags, callback, req);
656                         req.Worker=worker;
657                         Thread child=new Thread(new ThreadStart(worker.Send));
658                         child.Start();
659                         return(req);
660                 }
661
662                 public IAsyncResult BeginSendTo(byte[] buffer, int offset,
663                                                 int size,
664                                                 SocketFlags socket_flags,
665                                                 EndPoint remote_end,
666                                                 AsyncCallback callback,
667                                                 object state) {
668                         SocketAsyncResult req=new SocketAsyncResult(state);
669                         Worker worker=new Worker(this, buffer, offset, size,
670                                                  socket_flags, remote_end,
671                                                  callback, req);
672                         req.Worker=worker;
673                         Thread child=new Thread(new ThreadStart(worker.SendTo));
674                         child.Start();
675                         return(req);
676                 }
677
678                 // Creates a new system socket, returning the handle
679                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
680                 private extern static void Bind_internal(IntPtr sock,
681                                                          SocketAddress sa);
682
683                 public void Bind(EndPoint local_end) {
684                         if(local_end==null) {
685                                 throw new ArgumentNullException();
686                         }
687                         
688                         Bind_internal(socket, local_end.Serialize());
689                 }
690
691                 // Closes the socket
692                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
693                 private extern static void Close_internal(IntPtr socket);
694                 
695                 public void Close() {
696                         this.Dispose();
697                 }
698
699                 // Connects to the remote address
700                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
701                 private extern static void Connect_internal(IntPtr sock,
702                                                             SocketAddress sa);
703
704                 public void Connect(EndPoint remote_end) {
705                         if(remote_end==null) {
706                                 throw new ArgumentNullException();
707                         }
708
709                         Connect_internal(socket, remote_end.Serialize());
710                         connected=true;
711                 }
712                 
713                 public Socket EndAccept(IAsyncResult result) {
714                         SocketAsyncResult req=(SocketAsyncResult)result;
715
716                         result.AsyncWaitHandle.WaitOne();
717                         return(req.Worker.Socket);
718                 }
719
720                 public void EndConnect(IAsyncResult result) {
721                         SocketAsyncResult req=(SocketAsyncResult)result;
722
723                         result.AsyncWaitHandle.WaitOne();
724                 }
725
726                 public int EndReceive(IAsyncResult result) {
727                         SocketAsyncResult req=(SocketAsyncResult)result;
728
729                         result.AsyncWaitHandle.WaitOne();
730                         return(req.Worker.Total);
731                 }
732
733                 public int EndReceiveFrom(IAsyncResult result,
734                                           ref EndPoint end_point) {
735                         SocketAsyncResult req=(SocketAsyncResult)result;
736
737                         result.AsyncWaitHandle.WaitOne();
738                         end_point=req.Worker.EndPoint;
739                         return(req.Worker.Total);
740                 }
741
742                 public int EndSend(IAsyncResult result) {
743                         SocketAsyncResult req=(SocketAsyncResult)result;
744
745                         result.AsyncWaitHandle.WaitOne();
746                         return(req.Worker.Total);
747                 }
748
749                 public int EndSendTo(IAsyncResult result) {
750                         SocketAsyncResult req=(SocketAsyncResult)result;
751
752                         result.AsyncWaitHandle.WaitOne();
753                         return(req.Worker.Total);
754                 }
755
756                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
757                 private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val);
758                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
759                 private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val);
760
761                 public object GetSocketOption(SocketOptionLevel level,
762                                               SocketOptionName name) {
763                         object obj_val;
764                         
765                         GetSocketOption_obj_internal(socket, level, name,
766                                                      out obj_val);
767                         
768                         if(name==SocketOptionName.Linger) {
769                                 return((LingerOption)obj_val);
770                         } else if (name==SocketOptionName.AddMembership ||
771                                    name==SocketOptionName.DropMembership) {
772                                 return((MulticastOption)obj_val);
773                         } else {
774                                 return((int)obj_val);
775                         }
776                 }
777
778                 public void GetSocketOption(SocketOptionLevel level,
779                                             SocketOptionName name,
780                                             byte[] opt_value) {
781                         int opt_value_len=opt_value.Length;
782                         
783                         GetSocketOption_arr_internal(socket, level, name,
784                                                      ref opt_value);
785                 }
786
787                 public byte[] GetSocketOption(SocketOptionLevel level,
788                                               SocketOptionName name,
789                                               int length) {
790                         byte[] byte_val=new byte[length];
791                         
792                         GetSocketOption_arr_internal(socket, level, name,
793                                                      ref byte_val);
794
795                         return(byte_val);
796                 }
797
798                 [MonoTODO("Totally undocumented")]
799                 public int IOControl(int ioctl_code, byte[] in_value,
800                                      byte[] out_value) {
801                         throw new NotImplementedException();
802                 }
803
804                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
805                 private extern static void Listen_internal(IntPtr sock,
806                                                            int backlog);
807
808                 public void Listen(int backlog) {
809                         Listen_internal(socket, backlog);
810                 }
811
812                 /* The docs for Poll() are a bit lightweight too, but
813                  * it seems to be just a simple wrapper around Select.
814                  */
815                 public bool Poll(int time_us, SelectMode mode) {
816                         Socket [] socketlist = new Socket []{this};
817                         Socket [] n = null;
818
819                         switch(mode) {
820                         case SelectMode.SelectError:
821                                 Select_internal (ref n, ref n, ref socketlist, time_us);
822                                 break;
823                         case SelectMode.SelectRead:
824                                 Select_internal (ref socketlist, ref n, ref n, time_us);
825                                 break;
826                         case SelectMode.SelectWrite:
827                                 Select_internal (ref n, ref socketlist, ref n, time_us);
828                                 break;
829                         default:
830                                 throw new NotSupportedException();
831                         }
832
833                         return (socketlist.Length == 1);
834                 }
835                 
836                 public int Receive(byte[] buf) {
837                         return(Receive(buf, 0, buf.Length, SocketFlags.None));
838                 }
839
840                 public int Receive(byte[] buf, SocketFlags flags) {
841                         return(Receive(buf, 0, buf.Length, flags));
842                 }
843
844                 public int Receive(byte[] buf, int size, SocketFlags flags) {
845                         return(Receive(buf, 0, size, flags));
846                 }
847
848                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
849                 private extern static int Receive_internal(IntPtr sock,
850                                                            byte[] buffer,
851                                                            int offset,
852                                                            int count,
853                                                            SocketFlags flags);
854
855                 public int Receive(byte[] buf, int offset, int size,
856                                    SocketFlags flags) {
857                         if(buf==null) {
858                                 throw new ArgumentNullException("buffer is null");
859                         }
860                         if(offset<0 || offset >= buf.Length) {
861                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
862                         }
863                         if(offset+size<0 || offset+size > buf.Length) {
864                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
865                         }
866                         
867                         int ret;
868                         
869                         try {
870                                 ret=Receive_internal(socket, buf, offset,
871                                                      size, flags);
872                         } catch(SocketException) {
873                                 connected=false;
874                                 throw;
875                         }
876                         connected=true;
877
878                         return(ret);
879                 }
880                 
881                 public int ReceiveFrom(byte[] buf, ref EndPoint remote_end) {
882                         return(ReceiveFrom(buf, 0, buf.Length,
883                                            SocketFlags.None, ref remote_end));
884                 }
885
886                 public int ReceiveFrom(byte[] buf, SocketFlags flags,
887                                        ref EndPoint remote_end) {
888                         return(ReceiveFrom(buf, 0, buf.Length, flags,
889                                            ref remote_end));
890                 }
891
892                 public int ReceiveFrom(byte[] buf, int size, SocketFlags flags,
893                                        ref EndPoint remote_end) {
894                         return(ReceiveFrom(buf, 0, size, flags,
895                                            ref remote_end));
896                 }
897
898
899                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
900                 private extern static int RecvFrom_internal(IntPtr sock,
901                                                             byte[] buffer,
902                                                             int offset,
903                                                             int count,
904                                                             SocketFlags flags,
905                                                             ref SocketAddress sockaddr);
906
907                 public int ReceiveFrom(byte[] buf, int offset, int size,
908                                        SocketFlags flags,
909                                        ref EndPoint remote_end) {
910                         if(buf==null) {
911                                 throw new ArgumentNullException("buffer is null");
912                         }
913                         if(remote_end==null) {
914                                 throw new ArgumentNullException("remote endpoint is null");
915                         }
916                         if(offset<0 || offset>=buf.Length) {
917                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
918                         }
919                         if(offset+size<0 || offset+size>buf.Length) {
920                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
921                         }
922
923                         SocketAddress sockaddr=remote_end.Serialize();
924                         int count;
925
926                         try {
927                                 count=RecvFrom_internal(socket, buf, offset,
928                                                         size, flags,
929                                                         ref sockaddr);
930                         } catch(SocketException) {
931                                 connected=false;
932                                 throw;
933                         }
934                         connected=true;
935                         
936                         // Stupidly, EndPoint.Create() is an
937                         // instance method
938                         remote_end=remote_end.Create(sockaddr);
939
940                         return(count);
941                 }
942
943                 public int Send(byte[] buf) {
944                         return(Send(buf, 0, buf.Length, SocketFlags.None));
945                 }
946
947                 public int Send(byte[] buf, SocketFlags flags) {
948                         return(Send(buf, 0, buf.Length, flags));
949                 }
950
951                 public int Send(byte[] buf, int size, SocketFlags flags) {
952                         return(Send(buf, 0, size, flags));
953                 }
954
955                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
956                 private extern static int Send_internal(IntPtr sock,
957                                                         byte[] buf, int offset,
958                                                         int count,
959                                                         SocketFlags flags);
960
961                 public int Send (byte[] buf, int offset, int size, SocketFlags flags)
962                 {
963                         if (buf == null)
964                                 throw new ArgumentNullException ("buffer");
965
966                         if (offset < 0 || offset > buf.Length)
967                                 throw new ArgumentOutOfRangeException ("offset");
968
969                         if (size < 0 || offset + size > buf.Length)
970                                 throw new ArgumentOutOfRangeException ("size");
971
972                         if (size == 0)
973                                 return 0;
974
975                         int ret;
976
977                         try {
978                                 ret = Send_internal (socket, buf, offset, size, flags);
979                         } catch (SocketException) {
980                                 connected = false;
981                                 throw;
982                         }
983                         connected = true;
984
985                         return ret;
986                 }
987
988                 public int SendTo(byte[] buffer, EndPoint remote_end) {
989                         return(SendTo(buffer, 0, buffer.Length,
990                                       SocketFlags.None, remote_end));
991                 }
992
993                 public int SendTo(byte[] buffer, SocketFlags flags,
994                                   EndPoint remote_end) {
995                         return(SendTo(buffer, 0, buffer.Length, flags,
996                                       remote_end));
997                 }
998
999                 public int SendTo(byte[] buffer, int size, SocketFlags flags,
1000                                   EndPoint remote_end) {
1001                         return(SendTo(buffer, 0, size, flags, remote_end));
1002                 }
1003
1004
1005                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1006                 private extern static int SendTo_internal(IntPtr sock,
1007                                                           byte[] buffer,
1008                                                           int offset,
1009                                                           int count,
1010                                                           SocketFlags flags,
1011                                                           SocketAddress sa);
1012
1013                 public int SendTo(byte[] buffer, int offset, int size,
1014                                   SocketFlags flags, EndPoint remote_end) {
1015                         if(buffer==null) {
1016                                 throw new ArgumentNullException("buffer is null");
1017                         }
1018                         if(remote_end==null) {
1019                                 throw new ArgumentNullException("remote endpoint is null");
1020                         }
1021                         if(offset<0 || offset>=buffer.Length) {
1022                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
1023                         }
1024                         if(offset+size<0 || offset+size>buffer.Length) {
1025                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
1026                         }
1027
1028                         SocketAddress sockaddr=remote_end.Serialize();
1029
1030                         int ret;
1031
1032                         try {
1033                                 ret=SendTo_internal(socket, buffer, offset,
1034                                                     size, flags, sockaddr);
1035                         }
1036                         catch(SocketException) {
1037                                 connected=false;
1038                                 throw;
1039                         }
1040                         connected=true;
1041
1042                         return(ret);
1043                 }
1044
1045                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1046                 private extern static void SetSocketOption_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte[] byte_val, int int_val);
1047
1048                 public void SetSocketOption(SocketOptionLevel level,
1049                                             SocketOptionName name,
1050                                             byte[] opt_value) {
1051                         SetSocketOption_internal(socket, level, name, null,
1052                                                  opt_value, 0);
1053                 }
1054
1055                 public void SetSocketOption(SocketOptionLevel level,
1056                                             SocketOptionName name,
1057                                             int opt_value) {
1058                         SetSocketOption_internal(socket, level, name, null,
1059                                                  null, opt_value);
1060                 }
1061
1062                 public void SetSocketOption(SocketOptionLevel level,
1063                                             SocketOptionName name,
1064                                             object opt_value) {
1065                         if(opt_value==null) {
1066                                 throw new ArgumentNullException();
1067                         }
1068                         
1069                         /* Passing a bool as the third parameter to
1070                          * SetSocketOption causes this overload to be
1071                          * used when in fact we want to pass the value
1072                          * to the runtime as an int.
1073                          */
1074                         if(opt_value is System.Boolean) {
1075                                 bool bool_val=(bool)opt_value;
1076                                 
1077                                 /* Stupid casting rules :-( */
1078                                 if(bool_val==true) {
1079                                         SetSocketOption_internal(socket, level,
1080                                                                  name, null,
1081                                                                  null, 1);
1082                                 } else {
1083                                         SetSocketOption_internal(socket, level,
1084                                                                  name, null,
1085                                                                  null, 0);
1086                                 }
1087                         } else {
1088                                 SetSocketOption_internal(socket, level, name,
1089                                                          opt_value, null, 0);
1090                         }
1091                 }
1092
1093                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1094                 private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how);
1095                 
1096                 public void Shutdown(SocketShutdown how) {
1097                         Shutdown_internal(socket, how);
1098                 }
1099
1100                 public override int GetHashCode ()
1101                 { 
1102                         return (int) socket; 
1103                 }
1104
1105                 private bool disposed = false;
1106                 
1107                 protected virtual void Dispose(bool explicitDisposing) {
1108                         // Check to see if Dispose has already been called
1109                         if(!this.disposed) {
1110                                 // If this is a call to Dispose,
1111                                 // dispose all managed resources.
1112                                 if(explicitDisposing) {
1113                                         // Free up stuff here
1114                                 }
1115
1116                                 // Release unmanaged resources
1117                                 this.disposed=true;
1118                         
1119                                 connected=false;
1120                                 Close_internal(socket);
1121                         }
1122                 }
1123
1124                 public void Dispose() {
1125                         Dispose(true);
1126                         // Take yourself off the Finalization queue
1127                         GC.SuppressFinalize(this);
1128                 }
1129
1130                 ~Socket () {
1131                         Dispose(false);
1132                 }
1133         }
1134 }