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