2004-04-08 Dick Porter <dick@ximian.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                         private Exception delayedException = null;
30
31                         public SocketAsyncResult(object state) {
32                                 this.state=state;
33                                 completed_sync=completed=false;
34                         }
35
36                         public void SetDelayedException (Exception e) {
37                                 delayedException = e;
38                         }
39
40                         public void CheckIfThrowDelayedException () {
41                                 if (delayedException != null)
42                                         throw delayedException;
43                         }
44
45                         public object AsyncState {
46                                 get {
47                                         return(state);
48                                 }
49                         }
50
51                         public WaitHandle AsyncWaitHandle {
52                                 get {
53                                         lock (this) {
54                                                 if (waithandle == null)
55                                                         waithandle = new ManualResetEvent (completed);
56                                         }
57
58                                         return waithandle;
59                                 }
60                                 set {
61                                         waithandle=value;
62                                 }
63                         }
64
65                         public bool CompletedSynchronously {
66                                 get {
67                                         return(completed_sync);
68                                 }
69                         }
70
71                         public bool IsCompleted {
72                                 get {
73                                         return(completed);
74                                 }
75                                 set {
76                                         completed=value;
77                                         lock (this) {
78                                                 if (waithandle != null && value) {
79                                                         ((ManualResetEvent) waithandle).Set ();
80                                                 }
81                                         }
82                                 }
83                         }
84                         
85                         public Worker Worker {
86                                 get {
87                                         return(worker);
88                                 }
89                                 set {
90                                         worker=value;
91                                 }
92                         }
93                 }
94
95                 private sealed class Worker 
96                 {
97                         private AsyncCallback callback;
98                         private SocketAsyncResult result;
99                         private Socket socket;
100
101                         // Parameters
102                         private EndPoint endpoint;      // Connect,ReceiveFrom,SendTo
103                         private byte[] buffer;          // Receive,ReceiveFrom,Send,SendTo
104                         private int offset;             // Receive,ReceiveFrom,Send,SendTo
105                         private int size;               // Receive,ReceiveFrom,Send,SendTo
106                         private SocketFlags sockflags;  // Receive,ReceiveFrom,Send,SendTo
107
108                         // Return values
109                         private Socket acc_socket;
110                         private int total;
111                         
112
113                         // For Accept
114                         public Worker(Socket req_sock,
115                                       AsyncCallback req_callback,
116                                       SocketAsyncResult req_result)
117                                 : this(req_sock, null, 0, 0, SocketFlags.None,
118                                        null, req_callback, req_result) {}
119
120                         // For Connect
121                         public Worker(Socket req_sock, EndPoint req_endpoint,
122                                       AsyncCallback req_callback,
123                                       SocketAsyncResult req_result)
124                                 : this(req_sock, null, 0, 0, SocketFlags.None,
125                                        req_endpoint, req_callback,
126                                        req_result) {}
127
128                         // For Receive and Send
129                         public Worker(Socket req_sock, byte[] req_buffer,
130                                       int req_offset, int req_size,
131                                       SocketFlags req_sockflags,
132                                       AsyncCallback req_callback,
133                                       SocketAsyncResult req_result)
134                                 : this(req_sock, req_buffer, req_offset,
135                                        req_size, req_sockflags, null,
136                                        req_callback, req_result) {}
137
138                         // For ReceiveFrom and SendTo
139                         public Worker(Socket req_sock, byte[] req_buffer,
140                                       int req_offset, int req_size,
141                                       SocketFlags req_sockflags,
142                                       EndPoint req_endpoint,
143                                       AsyncCallback req_callback,
144                                       SocketAsyncResult req_result) {
145                                 socket=req_sock;
146                                 buffer=req_buffer;
147                                 offset=req_offset;
148                                 size=req_size;
149                                 sockflags=req_sockflags;
150                                 endpoint=req_endpoint;
151                                 callback=req_callback;
152                                 result=req_result;
153                         }
154
155                         private void End() {
156                                 result.IsCompleted=true;
157                                 if (callback != null)
158                                         callback(result);
159                         }
160                         
161                         public void Accept() {
162                                 lock(result) {
163                                         try {
164                                                 acc_socket=socket.Accept();
165                                         } catch (Exception e) {
166                                                 result.SetDelayedException(e);
167                                         }
168                                         End();
169                                 }
170                         }
171
172                         public void Connect() {
173                                 lock(result) {
174                                         if (socket.Blocking) {
175                                                 try {
176                                                         socket.Connect(endpoint);
177                                                 } catch (Exception e) {
178                                                         result.SetDelayedException(e);
179                                                 }
180                                                 End ();
181                                                 return;
182                                         }
183
184                                         Exception rethrow = null;
185                                         try {
186                                                 socket.Connect (endpoint);
187                                         } catch (SocketException e) {
188                                                 //WSAEINPROGRESS
189                                                 if (e.NativeErrorCode != 10036) {
190                                                         result.SetDelayedException(e);  
191                                                         End ();
192                                                         return;
193                                                 }
194
195                                                 socket.Poll (-1, SelectMode.SelectWrite);
196                                                 try {
197                                                         socket.Connect (endpoint);
198                                                 } catch (SocketException e2) {
199                                                         rethrow = e2;
200                                                 }
201                                         } catch (Exception e3) {
202                                                 rethrow = e3;
203                                         }
204                                         
205                                         if (rethrow != null)
206                                                 result.SetDelayedException(rethrow);
207                                         End ();
208                                 }
209                         }
210
211                         public void Receive() {
212                                 lock(result) {
213                                         if (socket.Blocking) {
214                                                 try {
215                                                         total=socket.Receive(buffer, offset,
216                                                                              size, sockflags);
217                                                 } catch (Exception e) {
218                                                         result.SetDelayedException(e);
219                                                 }
220                                                 End();
221                                                 return;
222                                         }
223
224                                         Exception rethrow = null;
225                                         try {
226                                                 total = socket.Receive (buffer, offset, size, sockflags);
227                                         } catch (SocketException e) {
228                                                 //WSAEWOULDBLOCK
229                                                 if (e.NativeErrorCode != 10035) {
230                                                         result.SetDelayedException(e);
231                                                         End ();
232                                                         return;
233                                                 }
234
235                                                 socket.Poll (-1, SelectMode.SelectRead);
236                                                 try {
237                                                         total = socket.Receive (buffer, offset, size, sockflags);
238                                                 } catch (SocketException e2) {
239                                                         rethrow = e2;
240                                                 }
241                                         } catch (Exception e3) {
242                                                 rethrow = e3;
243                                         }
244
245                                         if (rethrow != null)
246                                                 result.SetDelayedException(rethrow);
247                                         End ();
248                                 }
249                         }
250
251                         public void ReceiveFrom() {
252                                 lock(result) {
253                                         if (socket.Blocking) {
254                                                 try {
255                                                         total=socket.ReceiveFrom(buffer,
256                                                                                  offset, size,
257                                                                                  sockflags,
258                                                                                  ref endpoint);
259                                                 } catch (Exception e) {
260                                                         result.SetDelayedException(e);
261                                                 }
262                                                 End();
263                                                 return;
264                                         }
265
266                                         Exception rethrow = null;
267                                         try {
268                                                 total = socket.ReceiveFrom (buffer, offset, size,
269                                                                         sockflags, ref endpoint);
270                                         } catch (SocketException e) {
271                                                 //WSAEWOULDBLOCK
272                                                 if (e.NativeErrorCode != 10035) {
273                                                         result.SetDelayedException(e);
274                                                         End ();
275                                                         return;
276                                                 }
277
278                                                 socket.Poll (-1, SelectMode.SelectRead);
279                                                 try {
280                                                         total = socket.ReceiveFrom (buffer, offset, size,
281                                                                                 sockflags, ref endpoint);
282                                                 } catch (SocketException e2) {
283                                                         rethrow = e2;
284                                                 }
285                                         } catch (Exception e3) {
286                                                 rethrow = e3;
287                                         }
288
289                                         if (rethrow != null)
290                                                 result.SetDelayedException(rethrow);
291                                         End ();
292                                 }
293                         }
294
295                         public void Send() {
296                                 lock(result) {
297                                         if (socket.Blocking) {
298                                                 try {
299                                                         total=socket.Send(buffer, offset, size,
300                                                                           sockflags);
301                                                 } catch (Exception e) {
302                                                         result.SetDelayedException(e);
303                                                 }
304                                                 End();
305                                                 return;
306                                         }
307
308                                         Exception rethrow = null;
309                                         try {
310                                                 total = socket.Send (buffer, offset, size, sockflags);
311                                         } catch (SocketException e) {
312                                                 //WSAEWOULDBLOCK
313                                                 if (e.NativeErrorCode != 10035) {
314                                                         result.SetDelayedException(e);
315                                                         End ();
316                                                         return;
317                                                 }
318
319                                                 socket.Poll (-1, SelectMode.SelectWrite);
320                                                 try {
321                                                         total = socket.Send (buffer, offset, size, sockflags);
322                                                 } catch (SocketException e2) {
323                                                         rethrow = e2;
324                                                 }
325                                         } catch (Exception e3) {
326                                                 rethrow = e3;
327                                         }
328
329                                         if (rethrow != null)
330                                                 result.SetDelayedException(rethrow);
331                                         End ();
332                                 }
333                         }
334
335                         public void SendTo() {
336                                 lock(result) {
337                                         if (socket.Blocking) {
338                                                 try {
339                                                         total=socket.SendTo(buffer, offset,
340                                                                             size, sockflags,
341                                                                             endpoint);
342                                                 } catch (Exception e) {
343                                                         result.SetDelayedException(e);
344                                                 }
345                                                 End();
346                                                 return;
347                                         }
348
349                                         Exception rethrow = null;
350                                         try {
351                                                 total = socket.SendTo (buffer, offset, size,
352                                                                         sockflags, endpoint);
353                                         } catch (SocketException e) {
354                                                 //WSAEWOULDBLOCK
355                                                 if (e.NativeErrorCode != 10035) {
356                                                         result.SetDelayedException(e);
357                                                         End ();
358                                                         return;
359                                                 }
360
361                                                 socket.Poll (-1, SelectMode.SelectWrite);
362                                                 try {
363                                                         total = socket.SendTo (buffer, offset, size,
364                                                                                 sockflags, endpoint);
365                                                 } catch (SocketException e2) {
366                                                         rethrow = e2;
367                                                 }
368                                         } catch (Exception e3) {
369                                                 rethrow = e3;
370                                         }
371
372                                         if (rethrow != null)
373                                                 result.SetDelayedException(rethrow);
374                                         End ();
375                                 }
376                         }
377
378                         public EndPoint EndPoint {
379                                 get {
380                                         return(endpoint);
381                                 }
382                         }
383
384                         public Socket Socket {
385                                 get {
386                                         return(acc_socket);
387                                 }
388                         }
389
390                         public int Total {
391                                 get {
392                                         return(total);
393                                 }
394                         }
395                 }
396                         
397                 /* the field "socket" is looked up by name by the runtime */
398                 private IntPtr socket;
399                 private AddressFamily address_family;
400                 private SocketType socket_type;
401                 private ProtocolType protocol_type;
402                 private bool blocking=true;
403                 private int pendingEnds;
404                 private int closeDelayed;
405
406                 delegate void SocketAsyncCall ();
407                 /*\r
408                  *      These two fields are looked up by name by the runtime, don't change\r
409                  *  their name without also updating the runtime code.\r
410                  */
411                 private static int ipv4Supported = -1, ipv6Supported = -1;
412
413                 /* When true, the socket was connected at the time of
414                  * the last IO operation
415                  */
416                 private bool connected=false;
417                 /* true if we called Close_internal */
418                 private bool closed;
419
420                 /* Used in LocalEndPoint and RemoteEndPoint if the
421                  * Mono.Posix assembly is available
422                  */
423                 private static object unixendpoint=null;
424                 private static Type unixendpointtype=null;
425                 
426                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
427                 private extern static void Select_internal(ref Socket[] read,
428                                                            ref Socket[] write,
429                                                            ref Socket[] err,
430                                                            int timeout,
431                                                            out int error);
432
433                 public static void Select(IList read_list, IList write_list,
434                                           IList err_list, int time_us) {
435                         if(read_list==null &&
436                            write_list==null &&
437                            err_list==null) {
438                                 throw new ArgumentNullException();
439                         }
440
441                         int read_count = 0, write_count = 0, err_count = 0;
442                         Socket[] read_arr = null;
443                         Socket[] write_arr = null;
444                         Socket[] err_arr = null;
445
446                         if (read_list!=null)
447                                 read_count=read_list.Count;
448
449                         if (read_count != 0)
450                                 read_arr=new Socket[read_count];
451
452                         if (write_list!=null)
453                                 write_count=write_list.Count;
454
455                         if (write_count != 0)
456                                 write_arr=new Socket[write_count];
457
458                         if (err_list!=null)
459                                 err_count=err_list.Count;
460
461                         if (err_count != 0)
462                                 err_arr=new Socket[err_count];
463                         
464                         int i;
465
466                         if (read_count != 0) {
467                                 i=0;
468                                 
469                                 foreach (Socket s in read_list) {
470                                         read_arr[i]=s;
471                                         i++;
472                                 }
473                         }
474
475                         if (write_count != 0) {
476                                 i=0;
477                                 foreach (Socket s in write_list) {
478                                         write_arr[i]=s;
479                                         i++;
480                                 }
481                         }
482                         
483                         if (err_count != 0) {
484                                 i=0;
485                                 foreach (Socket s in err_list) {
486                                         err_arr[i]=s;
487                                         i++;
488                                 }
489                         }
490
491                         int error;
492                         
493                         Select_internal(ref read_arr, ref write_arr,
494                                         ref err_arr, time_us, out error);
495
496                         if(error != 0) {
497                                 throw new SocketException (error);
498                         }
499
500                         if(read_list!=null) {
501                                 read_list.Clear();
502                                 for(i=0; i<read_arr.Length; i++) {
503                                         read_list.Add(read_arr[i]);
504                                 }
505                         }
506                         
507                         if(write_list!=null) {
508                                 write_list.Clear();
509                                 for(i=0; i<write_arr.Length; i++) {
510                                         write_list.Add(write_arr[i]);
511                                 }
512                         }
513                         
514                         if(err_list!=null) {
515                                 err_list.Clear();
516                                 for(i=0; i<err_arr.Length; i++) {
517                                         err_list.Add(err_arr[i]);
518                                 }
519                         }
520                 }
521
522                 static Socket() {
523                         Assembly ass;
524                         
525                         try {
526                                 ass=Assembly.Load("Mono.Posix");
527                         } catch (FileNotFoundException) {
528                                 return;
529                         }
530                                 
531                         unixendpointtype=ass.GetType("Mono.Posix.UnixEndPoint");
532
533                         /* The endpoint Create() method is an instance
534                          * method :-(
535                          */
536                         Type[] arg_types=new Type[1];
537                         arg_types[0]=typeof(string);
538                         ConstructorInfo cons=unixendpointtype.GetConstructor(arg_types);
539
540                         object[] args=new object[1];
541                         args[0]="";
542
543                         unixendpoint=cons.Invoke(args);
544                 }
545
546                 // private constructor used by Accept, which already
547                 // has a socket handle to use
548                 private Socket(AddressFamily family, SocketType type,
549                                ProtocolType proto, IntPtr sock) {
550                         address_family=family;
551                         socket_type=type;
552                         protocol_type=proto;
553                         
554                         socket=sock;
555                         connected=true;
556                 }
557                 
558                 // Creates a new system socket, returning the handle
559                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
560                 private extern IntPtr Socket_internal(AddressFamily family,
561                                                       SocketType type,
562                                                       ProtocolType proto,
563                                                       out int error);
564                 
565                 public Socket(AddressFamily family, SocketType type,
566                               ProtocolType proto) {
567                         address_family=family;
568                         socket_type=type;
569                         protocol_type=proto;
570                         
571                         int error;
572                         
573                         socket=Socket_internal(family, type, proto, out error);
574                         if (error != 0) {
575                                 throw new SocketException (error);
576                         }
577                 }
578
579                 public AddressFamily AddressFamily {
580                         get {
581                                 return(address_family);
582                         }
583                 }
584
585                 // Returns the amount of data waiting to be read on socket
586                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
587                 private extern static int Available_internal(IntPtr socket,
588                                                              out int error);
589                 
590                 public int Available {
591                         get {
592                                 if (disposed && closed)
593                                         throw new ObjectDisposedException (GetType ().ToString ());
594
595                                 int ret, error;
596                                 
597                                 ret = Available_internal(socket, out error);
598
599                                 if (error != 0) {
600                                         throw new SocketException (error);
601                                 }
602
603                                 return(ret);
604                         }
605                 }
606
607                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
608                 private extern static void Blocking_internal(IntPtr socket,
609                                                              bool block,
610                                                              out int error);
611
612                 public bool Blocking {
613                         get {
614                                 return(blocking);
615                         }
616                         set {
617                                 int error;
618                                 
619                                 Blocking_internal(socket, value, out error);
620
621                                 if (error != 0) {
622                                         throw new SocketException (error);
623                                 }
624                                 
625                                 blocking=value;
626                         }
627                 }
628
629                 public bool Connected {
630                         get {
631                                 return(connected);
632                         }
633                 }
634
635                 public IntPtr Handle {
636                         get {
637                                 return(socket);
638                         }
639                 }
640
641                 // Returns the local endpoint details in addr and port
642                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
643                 private extern static SocketAddress LocalEndPoint_internal(IntPtr socket, out int error);
644
645                 [MonoTODO("Support non-IP endpoints")]
646                 public EndPoint LocalEndPoint {
647                         get {
648                                 if (disposed && closed)
649                                         throw new ObjectDisposedException (GetType ().ToString ());
650
651                                 SocketAddress sa;
652                                 int error;
653                                 
654                                 sa=LocalEndPoint_internal(socket, out error);
655
656                                 if (error != 0) {
657                                         throw new SocketException (error);
658                                 }
659
660                                 if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6) {
661                                         // Stupidly, EndPoint.Create() is an
662                                         // instance method
663                                         return new IPEndPoint(0, 0).Create(sa);
664                                 } else if (sa.Family==AddressFamily.Unix &&
665                                            unixendpoint!=null) {
666                                         return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
667                                 } else {
668                                         throw new NotImplementedException();
669                                 }
670                         }
671                 }
672
673                 public ProtocolType ProtocolType {
674                         get {
675                                 return(protocol_type);
676                         }
677                 }
678
679                 // Returns the remote endpoint details in addr and port
680                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
681                 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket, out int error);
682
683                 [MonoTODO("Support non-IP endpoints")]
684                 public EndPoint RemoteEndPoint {
685                         get {
686                                 if (disposed && closed)
687                                         throw new ObjectDisposedException (GetType ().ToString ());
688
689                                 SocketAddress sa;
690                                 int error;
691                                 
692                                 sa=RemoteEndPoint_internal(socket, out error);
693
694                                 if (error != 0) {
695                                         throw new SocketException (error);
696                                 }
697
698                                 if(sa.Family==AddressFamily.InterNetwork || sa.Family==AddressFamily.InterNetworkV6 ) {
699                                         // Stupidly, EndPoint.Create() is an
700                                         // instance method
701                                         return new IPEndPoint(0, 0).Create(sa);
702                                 } else if (sa.Family==AddressFamily.Unix &&
703                                            unixendpoint!=null) {
704                                         return((EndPoint)unixendpointtype.InvokeMember("Create", BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public, null, unixendpoint, new object[] {sa}));
705                                 } else {
706                                         throw new NotImplementedException();
707                                 }
708                         }
709                 }
710
711                 public SocketType SocketType {
712                         get {
713                                 return(socket_type);
714                         }
715                 }
716
717 #if NET_1_1
718                 public static bool SupportsIPv4 {\r
719                         get {\r
720                                 CheckProtocolSupport();\r
721                                 return ipv4Supported == 1;\r
722                         }\r
723                 }
724
725                 public static bool SupportsIPv6 {\r
726                         get {\r
727                                 CheckProtocolSupport();\r
728                                 return ipv6Supported == 1;\r
729                         }\r
730                 }
731 #else
732                 internal static bool SupportsIPv4 \r
733                 {\r
734                         get \r
735                         {\r
736                                 return true;\r
737                         }\r
738                 }
739
740                 internal static bool SupportsIPv6 \r
741                 {\r
742                         get \r
743                         {\r
744                                 return false;\r
745                         }\r
746                 }\r
747 #endif
748
749                 internal static void CheckProtocolSupport()
750                 {\r
751                         if(ipv4Supported == -1) {\r
752                                 try  {\r
753                                         Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);\r
754                                         tmp.Close();\r
755 \r
756                                         ipv4Supported = 1;\r
757                                 }\r
758                                 catch {\r
759                                         ipv4Supported = 0;\r
760                                 }\r
761                         }\r
762 \r
763                         if(ipv6Supported == -1) {\r
764                                 NetConfig config = (NetConfig)System.Configuration.ConfigurationSettings.GetConfig("system.net/settings");\r
765 \r
766                                 if(config != null)\r
767                                         ipv6Supported = config.ipv6Enabled?-1:0;\r
768 \r
769                                 if(ipv6Supported != 0) {\r
770                                         try {\r
771                                                 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);\r
772                                                 tmp.Close();\r
773 \r
774                                                 ipv6Supported = 1;\r
775                                         }\r
776                                         catch { }\r
777                                 }\r
778                         }\r
779                 }
780
781                 // Creates a new system socket, returning the handle
782                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
783                 private extern static IntPtr Accept_internal(IntPtr sock,
784                                                              out int error);
785                 
786                 public Socket Accept() {
787                         if (disposed && closed)
788                                 throw new ObjectDisposedException (GetType ().ToString ());
789
790                         int error;
791                         IntPtr sock=Accept_internal(socket, out error);
792
793                         if (error != 0) {
794                                 throw new SocketException (error);
795                         }
796                         
797                         return(new Socket(this.AddressFamily, this.SocketType,
798                                           this.ProtocolType, sock));
799                 }
800
801                 public IAsyncResult BeginAccept(AsyncCallback callback,
802                                                 object state) {
803
804                         if (disposed && closed)
805                                 throw new ObjectDisposedException (GetType ().ToString ());
806
807                         Interlocked.Increment (ref pendingEnds);
808                         SocketAsyncResult req=new SocketAsyncResult(state);
809                         Worker worker=new Worker(this, callback, req);
810                         req.Worker=worker;
811                         SocketAsyncCall sac = new SocketAsyncCall (worker.Accept);
812                         sac.BeginInvoke (null, null);
813                         return(req);
814                 }
815
816                 public IAsyncResult BeginConnect(EndPoint end_point,
817                                                  AsyncCallback callback,
818                                                  object state) {
819
820                         if (disposed && closed)
821                                 throw new ObjectDisposedException (GetType ().ToString ());
822
823                         if (end_point == null)
824                                 throw new ArgumentNullException ("end_point");
825
826                         Interlocked.Increment (ref pendingEnds);
827                         SocketAsyncResult req=new SocketAsyncResult(state);
828                         Worker worker=new Worker(this, end_point, callback,
829                                                  req);
830                         req.Worker=worker;
831                         SocketAsyncCall sac = new SocketAsyncCall (worker.Connect);
832                         sac.BeginInvoke (null, null);
833                         return(req);
834                 }
835
836                 public IAsyncResult BeginReceive(byte[] buffer, int offset,
837                                                  int size,
838                                                  SocketFlags socket_flags,
839                                                  AsyncCallback callback,
840                                                  object state) {
841
842                         if (disposed && closed)
843                                 throw new ObjectDisposedException (GetType ().ToString ());
844
845                         if (buffer == null)
846                                 throw new ArgumentNullException ("buffer");
847
848                         if (offset < 0)
849                                 throw new ArgumentOutOfRangeException ("offset must be >= 0");
850
851                         if (size < 0)
852                                 throw new ArgumentOutOfRangeException ("size must be >= 0");
853
854                         if (offset + size > buffer.Length)
855                                 throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length");
856
857                         Interlocked.Increment (ref pendingEnds);
858                         SocketAsyncResult req=new SocketAsyncResult(state);
859                         Worker worker=new Worker(this, buffer, offset, size,
860                                                  socket_flags, callback, req);
861                         req.Worker=worker;
862                         SocketAsyncCall sac = new SocketAsyncCall (worker.Receive);
863                         sac.BeginInvoke (null, null);
864                         return(req);
865                 }
866
867                 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
868                                                      int size,
869                                                      SocketFlags socket_flags,
870                                                      ref EndPoint remote_end,
871                                                      AsyncCallback callback,
872                                                      object state) {
873                         if (disposed && closed)
874                                 throw new ObjectDisposedException (GetType ().ToString ());
875
876                         if (buffer == null)
877                                 throw new ArgumentNullException ("buffer");
878
879                         if (offset < 0)
880                                 throw new ArgumentOutOfRangeException ("offset must be >= 0");
881
882                         if (size < 0)
883                                 throw new ArgumentOutOfRangeException ("size must be >= 0");
884
885                         if (offset + size > buffer.Length)
886                                 throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length");
887
888                         Interlocked.Increment (ref pendingEnds);
889                         SocketAsyncResult req=new SocketAsyncResult(state);
890                         Worker worker=new Worker(this, buffer, offset, size,
891                                                  socket_flags, remote_end,
892                                                  callback, req);
893                         req.Worker=worker;
894                         SocketAsyncCall sac = new SocketAsyncCall (worker.ReceiveFrom);
895                         sac.BeginInvoke (null, null);
896                         return(req);
897                 }
898
899                 public IAsyncResult BeginSend(byte[] buffer, int offset,
900                                               int size,
901                                               SocketFlags socket_flags,
902                                               AsyncCallback callback,
903                                               object state) {
904                         if (disposed && closed)
905                                 throw new ObjectDisposedException (GetType ().ToString ());
906
907                         if (buffer == null)
908                                 throw new ArgumentNullException ("buffer");
909
910                         if (offset < 0)
911                                 throw new ArgumentOutOfRangeException ("offset must be >= 0");
912
913                         if (size < 0)
914                                 throw new ArgumentOutOfRangeException ("size must be >= 0");
915
916                         if (offset + size > buffer.Length)
917                                 throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length");
918
919                         Interlocked.Increment (ref pendingEnds);
920                         SocketAsyncResult req=new SocketAsyncResult(state);
921                         Worker worker=new Worker(this, buffer, offset, size,
922                                                  socket_flags, callback, req);
923                         req.Worker=worker;
924                         SocketAsyncCall sac = new SocketAsyncCall (worker.Send);
925                         sac.BeginInvoke (null, null);
926                         return(req);
927                 }
928
929                 public IAsyncResult BeginSendTo(byte[] buffer, int offset,
930                                                 int size,
931                                                 SocketFlags socket_flags,
932                                                 EndPoint remote_end,
933                                                 AsyncCallback callback,
934                                                 object state) {
935                         if (disposed && closed)
936                                 throw new ObjectDisposedException (GetType ().ToString ());
937
938                         if (buffer == null)
939                                 throw new ArgumentNullException ("buffer");
940
941                         if (offset < 0)
942                                 throw new ArgumentOutOfRangeException ("offset must be >= 0");
943
944                         if (size < 0)
945                                 throw new ArgumentOutOfRangeException ("size must be >= 0");
946
947                         if (offset + size > buffer.Length)
948                                 throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length");
949
950                         Interlocked.Increment (ref pendingEnds);
951                         SocketAsyncResult req=new SocketAsyncResult(state);
952                         Worker worker=new Worker(this, buffer, offset, size,
953                                                  socket_flags, remote_end,
954                                                  callback, req);
955                         req.Worker=worker;
956                         SocketAsyncCall sac = new SocketAsyncCall (worker.SendTo);
957                         sac.BeginInvoke (null, null);
958                         return(req);
959                 }
960
961                 // Creates a new system socket, returning the handle
962                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
963                 private extern static void Bind_internal(IntPtr sock,
964                                                          SocketAddress sa,
965                                                          out int error);
966
967                 public void Bind(EndPoint local_end) {
968                         if (disposed && closed)
969                                 throw new ObjectDisposedException (GetType ().ToString ());
970
971                         if(local_end==null) {
972                                 throw new ArgumentNullException("local_end");
973                         }
974                         
975                         int error;
976                         
977                         Bind_internal(socket, local_end.Serialize(),
978                                       out error);
979
980                         if (error != 0) {
981                                 throw new SocketException (error);
982                         }
983                 }
984
985                 // Closes the socket
986                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
987                 private extern static void Close_internal(IntPtr socket,
988                                                           out int error);
989                 
990                 public void Close() {
991                         ((IDisposable) this).Dispose ();
992                 }
993
994                 // Connects to the remote address
995                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
996                 private extern static void Connect_internal(IntPtr sock,
997                                                             SocketAddress sa,
998                                                             out int error);
999
1000                 public void Connect(EndPoint remote_end) {
1001                         if (disposed && closed)
1002                                 throw new ObjectDisposedException (GetType ().ToString ());
1003
1004                         if(remote_end==null) {
1005                                 throw new ArgumentNullException("remote_end");
1006                         }
1007
1008                         int error;
1009                         
1010                         Connect_internal(socket, remote_end.Serialize(),
1011                                          out error);
1012
1013                         if (error != 0) {
1014                                 throw new SocketException (error);
1015                         }
1016                         
1017                         connected=true;
1018                 }
1019                 
1020                 public Socket EndAccept(IAsyncResult result) {
1021                         if (disposed && closed)
1022                                 throw new ObjectDisposedException (GetType ().ToString ());
1023
1024                         if (result == null)
1025                                 throw new ArgumentNullException ("result");
1026
1027                         SocketAsyncResult req = result as SocketAsyncResult;
1028                         if (req == null)
1029                                 throw new ArgumentException ("Invalid IAsyncResult");
1030
1031                         if (!result.IsCompleted)
1032                                 result.AsyncWaitHandle.WaitOne();
1033
1034                         Interlocked.Decrement (ref pendingEnds);
1035                         CheckIfClose ();
1036                         req.CheckIfThrowDelayedException();
1037                         return(req.Worker.Socket);
1038                 }
1039
1040                 public void EndConnect(IAsyncResult result) {
1041                         if (disposed && closed)
1042                                 throw new ObjectDisposedException (GetType ().ToString ());
1043
1044                         if (result == null)
1045                                 throw new ArgumentNullException ("result");
1046
1047                         SocketAsyncResult req = result as SocketAsyncResult;
1048                         if (req == null)
1049                                 throw new ArgumentException ("Invalid IAsyncResult");
1050
1051                         if (!result.IsCompleted)
1052                                 result.AsyncWaitHandle.WaitOne();
1053
1054                         Interlocked.Decrement (ref pendingEnds);
1055                         CheckIfClose ();
1056                         req.CheckIfThrowDelayedException();
1057                 }
1058
1059                 public int EndReceive(IAsyncResult result) {
1060                         if (disposed && closed)
1061                                 throw new ObjectDisposedException (GetType ().ToString ());
1062
1063                         if (result == null)
1064                                 throw new ArgumentNullException ("result");
1065
1066                         SocketAsyncResult req = result as SocketAsyncResult;
1067                         if (req == null)
1068                                 throw new ArgumentException ("Invalid IAsyncResult");
1069
1070                         if (!result.IsCompleted)
1071                                 result.AsyncWaitHandle.WaitOne();
1072
1073                         Interlocked.Decrement (ref pendingEnds);
1074                         CheckIfClose ();
1075                         req.CheckIfThrowDelayedException();
1076                         return(req.Worker.Total);
1077                 }
1078
1079                 public int EndReceiveFrom(IAsyncResult result,
1080                                           ref EndPoint end_point) {
1081                         if (disposed && closed)
1082                                 throw new ObjectDisposedException (GetType ().ToString ());
1083
1084                         if (result == null)
1085                                 throw new ArgumentNullException ("result");
1086
1087                         SocketAsyncResult req = result as SocketAsyncResult;
1088                         if (req == null)
1089                                 throw new ArgumentException ("Invalid IAsyncResult");
1090
1091                         if (!result.IsCompleted)
1092                                 result.AsyncWaitHandle.WaitOne();
1093
1094                         Interlocked.Decrement (ref pendingEnds);
1095                         CheckIfClose ();
1096                         req.CheckIfThrowDelayedException();
1097                         end_point=req.Worker.EndPoint;
1098                         return(req.Worker.Total);
1099                 }
1100
1101                 public int EndSend(IAsyncResult result) {
1102                         if (disposed && closed)
1103                                 throw new ObjectDisposedException (GetType ().ToString ());
1104
1105                         if (result == null)
1106                                 throw new ArgumentNullException ("result");
1107
1108                         SocketAsyncResult req = result as SocketAsyncResult;
1109                         if (req == null)
1110                                 throw new ArgumentException ("Invalid IAsyncResult");
1111
1112                         if (!result.IsCompleted)
1113                                 result.AsyncWaitHandle.WaitOne();
1114
1115                         Interlocked.Decrement (ref pendingEnds);
1116                         CheckIfClose ();
1117                         req.CheckIfThrowDelayedException();
1118                         return(req.Worker.Total);
1119                 }
1120
1121                 public int EndSendTo(IAsyncResult result) {
1122                         if (disposed && closed)
1123                                 throw new ObjectDisposedException (GetType ().ToString ());
1124
1125                         if (result == null)
1126                                 throw new ArgumentNullException ("result");
1127
1128                         SocketAsyncResult req = result as SocketAsyncResult;
1129                         if (req == null)
1130                                 throw new ArgumentException ("Invalid IAsyncResult");
1131
1132                         if (!result.IsCompleted)
1133                                 result.AsyncWaitHandle.WaitOne();
1134
1135                         Interlocked.Decrement (ref pendingEnds);
1136                         CheckIfClose ();
1137                         req.CheckIfThrowDelayedException();
1138                         return(req.Worker.Total);
1139                 }
1140
1141                 void CheckIfClose ()
1142                 {
1143                         if (Interlocked.CompareExchange (ref closeDelayed, 0, 1) == 1 &&
1144                             Interlocked.CompareExchange (ref pendingEnds, 0, 0) == 0) {
1145                                 closed = true;
1146
1147                                 int error;
1148                                 
1149                                 Close_internal(socket, out error);
1150
1151                                 if (error != 0) {
1152                                         throw new SocketException (error);
1153                                 }
1154                         }
1155                 }
1156
1157                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1158                 private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
1159                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1160                 private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
1161
1162                 public object GetSocketOption(SocketOptionLevel level,
1163                                               SocketOptionName name) {
1164                         object obj_val;
1165                         int error;
1166                         
1167                         GetSocketOption_obj_internal(socket, level, name,
1168                                                      out obj_val, out error);
1169
1170                         if (error != 0) {
1171                                 throw new SocketException (error);
1172                         }
1173                         
1174                         if(name==SocketOptionName.Linger) {
1175                                 return((LingerOption)obj_val);
1176                         } else if (name==SocketOptionName.AddMembership ||
1177                                    name==SocketOptionName.DropMembership) {
1178                                 return((MulticastOption)obj_val);
1179                         } else {
1180                                 return((int)obj_val);
1181                         }
1182                 }
1183
1184                 public void GetSocketOption(SocketOptionLevel level,
1185                                             SocketOptionName name,
1186                                             byte[] opt_value) {
1187                         int opt_value_len=opt_value.Length;
1188                         int error;
1189                         
1190                         GetSocketOption_arr_internal(socket, level, name,
1191                                                      ref opt_value, out error);
1192
1193                         if (error != 0) {
1194                                 throw new SocketException (error);
1195                         }
1196                 }
1197
1198                 public byte[] GetSocketOption(SocketOptionLevel level,
1199                                               SocketOptionName name,
1200                                               int length) {
1201                         byte[] byte_val=new byte[length];
1202                         int error;
1203                         
1204                         GetSocketOption_arr_internal(socket, level, name,
1205                                                      ref byte_val, out error);
1206
1207                         if (error != 0) {
1208                                 throw new SocketException (error);
1209                         }
1210
1211                         return(byte_val);
1212                 }
1213
1214                 // See Socket.IOControl, WSAIoctl documentation in MSDN. The
1215                 // common options between UNIX and Winsock are FIONREAD,
1216                 // FIONBIO and SIOCATMARK. Anything else will depend on the
1217                 // system.
1218                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1219                 extern static int WSAIoctl (IntPtr sock, int ioctl_code,
1220                                             byte [] input, byte [] output,
1221                                             out int error);
1222
1223                 public int IOControl (int ioctl_code, byte [] in_value,
1224                                       byte [] out_value)
1225                 {
1226                         if (disposed)
1227                                 throw new ObjectDisposedException (GetType ().ToString ());
1228
1229                         int error;
1230                         int result = WSAIoctl (socket, ioctl_code, in_value,
1231                                                out_value, out error);
1232
1233                         if (error != 0) {
1234                                 throw new SocketException (error);
1235                         }
1236                         
1237                         if (result == -1)
1238                                 throw new InvalidOperationException ("Must use Blocking property instead.");
1239
1240                         return result;
1241                 }
1242
1243                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1244                 private extern static void Listen_internal(IntPtr sock,
1245                                                            int backlog,
1246                                                            out int error);
1247
1248                 public void Listen(int backlog) {
1249                         int error;
1250                         
1251                         Listen_internal(socket, backlog, out error);
1252
1253                         if (error != 0) {
1254                                 throw new SocketException (error);
1255                         }
1256                 }
1257
1258                 /* The docs for Poll() are a bit lightweight too, but
1259                  * it seems to be just a simple wrapper around Select.
1260                  */
1261                 public bool Poll(int time_us, SelectMode mode) {
1262                         Socket [] socketlist = new Socket []{this};
1263                         Socket [] n = null;
1264                         int error;
1265                         
1266                         switch(mode) {
1267                         case SelectMode.SelectError:
1268                                 Select_internal (ref n, ref n, ref socketlist,
1269                                                  time_us, out error);
1270                                 break;
1271                         case SelectMode.SelectRead:
1272                                 Select_internal (ref socketlist, ref n, ref n,
1273                                                  time_us, out error);
1274                                 break;
1275                         case SelectMode.SelectWrite:
1276                                 Select_internal (ref n, ref socketlist, ref n,
1277                                                  time_us, out error);
1278                                 break;
1279                         default:
1280                                 throw new NotSupportedException();
1281                         }
1282
1283                         if (error != 0) {
1284                                 throw new SocketException (error);
1285                         }
1286
1287                         return (socketlist.Length == 1);
1288                 }
1289                 
1290                 public int Receive(byte[] buf) {
1291                         return(Receive(buf, 0, buf.Length, SocketFlags.None));
1292                 }
1293
1294                 public int Receive(byte[] buf, SocketFlags flags) {
1295                         return(Receive(buf, 0, buf.Length, flags));
1296                 }
1297
1298                 public int Receive(byte[] buf, int size, SocketFlags flags) {
1299                         return(Receive(buf, 0, size, flags));
1300                 }
1301
1302                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1303                 private extern static int Receive_internal(IntPtr sock,
1304                                                            byte[] buffer,
1305                                                            int offset,
1306                                                            int count,
1307                                                            SocketFlags flags,
1308                                                            out int error);
1309
1310                 public int Receive(byte[] buf, int offset, int size,
1311                                    SocketFlags flags) {
1312                         if(buf==null) {
1313                                 throw new ArgumentNullException("buffer is null");
1314                         }
1315                         if(offset<0 || offset > buf.Length) {
1316                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
1317                         }
1318                         if(size<0 || offset+size > buf.Length) {
1319                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
1320                         }
1321                         
1322                         int ret, error;
1323                         
1324                         ret=Receive_internal(socket, buf, offset, size, flags,
1325                                              out error);
1326
1327                         if(error != 0) {
1328                                 connected=false;
1329                                 throw new SocketException (error);
1330                         }
1331                         
1332                         connected=true;
1333
1334                         return(ret);
1335                 }
1336                 
1337                 public int ReceiveFrom(byte[] buf, ref EndPoint remote_end) {
1338                         return(ReceiveFrom(buf, 0, buf.Length,
1339                                            SocketFlags.None, ref remote_end));
1340                 }
1341
1342                 public int ReceiveFrom(byte[] buf, SocketFlags flags,
1343                                        ref EndPoint remote_end) {
1344                         return(ReceiveFrom(buf, 0, buf.Length, flags,
1345                                            ref remote_end));
1346                 }
1347
1348                 public int ReceiveFrom(byte[] buf, int size, SocketFlags flags,
1349                                        ref EndPoint remote_end) {
1350                         return(ReceiveFrom(buf, 0, size, flags,
1351                                            ref remote_end));
1352                 }
1353
1354
1355                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1356                 private extern static int RecvFrom_internal(IntPtr sock,
1357                                                             byte[] buffer,
1358                                                             int offset,
1359                                                             int count,
1360                                                             SocketFlags flags,
1361                                                             ref SocketAddress sockaddr,
1362                                                             out int error);
1363
1364                 public int ReceiveFrom(byte[] buf, int offset, int size,
1365                                        SocketFlags flags,
1366                                        ref EndPoint remote_end) {
1367                         if(buf==null) {
1368                                 throw new ArgumentNullException("buffer is null");
1369                         }
1370                         if(remote_end==null) {
1371                                 throw new ArgumentNullException("remote endpoint is null");
1372                         }
1373                         if(offset<0 || offset>buf.Length) {
1374                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
1375                         }
1376                         if(size<0 || offset+size>buf.Length) {
1377                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
1378                         }
1379
1380                         SocketAddress sockaddr=remote_end.Serialize();
1381                         int count, error;
1382
1383                         count=RecvFrom_internal(socket, buf, offset, size,
1384                                                 flags, ref sockaddr,
1385                                                 out error);
1386
1387                         if (error != 0) {
1388                                 connected=false;
1389                                 throw new SocketException (error);
1390                         }
1391                         connected=true;
1392                         
1393                         // Stupidly, EndPoint.Create() is an
1394                         // instance method
1395                         remote_end=remote_end.Create(sockaddr);
1396
1397                         return(count);
1398                 }
1399
1400                 public int Send(byte[] buf) {
1401                         return(Send(buf, 0, buf.Length, SocketFlags.None));
1402                 }
1403
1404                 public int Send(byte[] buf, SocketFlags flags) {
1405                         return(Send(buf, 0, buf.Length, flags));
1406                 }
1407
1408                 public int Send(byte[] buf, int size, SocketFlags flags) {
1409                         return(Send(buf, 0, size, flags));
1410                 }
1411
1412                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1413                 private extern static int Send_internal(IntPtr sock,
1414                                                         byte[] buf, int offset,
1415                                                         int count,
1416                                                         SocketFlags flags,
1417                                                         out int error);
1418
1419                 public int Send (byte[] buf, int offset, int size, SocketFlags flags)
1420                 {
1421                         if (buf == null)
1422                                 throw new ArgumentNullException ("buffer");
1423
1424                         if (offset < 0 || offset > buf.Length)
1425                                 throw new ArgumentOutOfRangeException ("offset");
1426
1427                         if (size < 0 || offset + size > buf.Length)
1428                                 throw new ArgumentOutOfRangeException ("size");
1429
1430                         if (size == 0)
1431                                 return 0;
1432
1433                         int ret, error;
1434
1435                         ret = Send_internal (socket, buf, offset, size, flags,
1436                                              out error);
1437
1438                         if (error != 0) {
1439                                 connected = false;
1440                                 throw new SocketException (error);
1441                         }
1442                         connected = true;
1443
1444                         return ret;
1445                 }
1446
1447                 public int SendTo(byte[] buffer, EndPoint remote_end) {
1448                         return(SendTo(buffer, 0, buffer.Length,
1449                                       SocketFlags.None, remote_end));
1450                 }
1451
1452                 public int SendTo(byte[] buffer, SocketFlags flags,
1453                                   EndPoint remote_end) {
1454                         return(SendTo(buffer, 0, buffer.Length, flags,
1455                                       remote_end));
1456                 }
1457
1458                 public int SendTo(byte[] buffer, int size, SocketFlags flags,
1459                                   EndPoint remote_end) {
1460                         return(SendTo(buffer, 0, size, flags, remote_end));
1461                 }
1462
1463
1464                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1465                 private extern static int SendTo_internal(IntPtr sock,
1466                                                           byte[] buffer,
1467                                                           int offset,
1468                                                           int count,
1469                                                           SocketFlags flags,
1470                                                           SocketAddress sa,
1471                                                           out int error);
1472
1473                 public int SendTo(byte[] buffer, int offset, int size,
1474                                   SocketFlags flags, EndPoint remote_end) {
1475                         if(buffer==null) {
1476                                 throw new ArgumentNullException("buffer is null");
1477                         }
1478                         if(remote_end==null) {
1479                                 throw new ArgumentNullException("remote endpoint is null");
1480                         }
1481                         if(offset<0 || offset>buffer.Length) {
1482                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
1483                         }
1484                         if(size<0 || offset+size>buffer.Length) {
1485                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
1486                         }
1487
1488                         SocketAddress sockaddr=remote_end.Serialize();
1489
1490                         int ret, error;
1491
1492                         ret=SendTo_internal(socket, buffer, offset, size,
1493                                             flags, sockaddr, out error);
1494
1495                         if (error != 0) {
1496                                 connected=false;
1497                                 throw new SocketException (error);
1498                         }
1499                         connected=true;
1500
1501                         return(ret);
1502                 }
1503
1504                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1505                 private extern static void SetSocketOption_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte[] byte_val, int int_val, out int error);
1506
1507                 public void SetSocketOption(SocketOptionLevel level,
1508                                             SocketOptionName name,
1509                                             byte[] opt_value) {
1510                         int error;
1511                         
1512                         SetSocketOption_internal(socket, level, name, null,
1513                                                  opt_value, 0, out error);
1514
1515                         if (error != 0) {
1516                                 throw new SocketException (error);
1517                         }
1518                 }
1519
1520                 public void SetSocketOption(SocketOptionLevel level,
1521                                             SocketOptionName name,
1522                                             int opt_value) {
1523                         int error;
1524                         
1525                         SetSocketOption_internal(socket, level, name, null,
1526                                                  null, opt_value, out error);
1527
1528                         if (error != 0) {
1529                                 throw new SocketException (error);
1530                         }
1531                 }
1532
1533                 public void SetSocketOption(SocketOptionLevel level,
1534                                             SocketOptionName name,
1535                                             object opt_value) {
1536                         if(opt_value==null) {
1537                                 throw new ArgumentNullException();
1538                         }
1539                         
1540                         int error;
1541                         
1542                         /* Passing a bool as the third parameter to
1543                          * SetSocketOption causes this overload to be
1544                          * used when in fact we want to pass the value
1545                          * to the runtime as an int.
1546                          */
1547                         if(opt_value is System.Boolean) {
1548                                 bool bool_val=(bool)opt_value;
1549                                 
1550                                 /* Stupid casting rules :-( */
1551                                 if(bool_val==true) {
1552                                         SetSocketOption_internal(socket, level,
1553                                                                  name, null,
1554                                                                  null, 1,
1555                                                                  out error);
1556                                 } else {
1557                                         SetSocketOption_internal(socket, level,
1558                                                                  name, null,
1559                                                                  null, 0,
1560                                                                  out error);
1561                                 }
1562                         } else {
1563                                 SetSocketOption_internal(socket, level, name,
1564                                                          opt_value, null, 0,
1565                                                          out error);
1566                         }
1567
1568                         if (error != 0) {
1569                                 throw new SocketException (error);
1570                         }
1571                 }
1572
1573                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1574                 private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how, out int error);
1575                 
1576                 public void Shutdown(SocketShutdown how) {
1577                         int error;
1578                         
1579                         Shutdown_internal(socket, how, out error);
1580
1581                         if (error != 0) {
1582                                 throw new SocketException (error);
1583                         }
1584                 }
1585
1586                 public override int GetHashCode ()
1587                 { 
1588                         return (int) socket; 
1589                 }
1590
1591                 private bool disposed;
1592                 
1593                 protected virtual void Dispose(bool explicitDisposing) {
1594                         if (!disposed) {
1595                                 int error;
1596                                 
1597                                 disposed = true;
1598                                 connected = false;
1599                                 if (!explicitDisposing) {
1600                                         closed = true;
1601                                         Close_internal (socket, out error);
1602
1603                                         if (error != 0) {
1604                                                 throw new SocketException (error);
1605                                         }
1606                                         
1607                                         return;
1608                                 }
1609                         
1610                                 if (Interlocked.CompareExchange (ref pendingEnds, 0, 0) == 0) {
1611                                         closed = true;
1612                                         Close_internal (socket, out error);
1613
1614                                         if (error != 0) {
1615                                                 throw new SocketException (error);
1616                                         }
1617                                 } else {
1618                                         Interlocked.CompareExchange (ref closeDelayed, 1, 0);
1619                                 }
1620                         }
1621                 }
1622
1623                 void IDisposable.Dispose ()
1624                 {
1625                         Dispose (true);
1626                         GC.SuppressFinalize (this);
1627                 }
1628                 
1629                 ~Socket () {
1630                         Dispose(false);
1631                 }
1632         }
1633 }