2004-05-03 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                         Connect_internal(socket, remote_end.Serialize(), out error);
933
934                         if (error != 0) {
935                                 throw new SocketException (error);
936                         }
937                         
938                         connected=true;
939                 }
940                 
941                 public Socket EndAccept(IAsyncResult result) {
942                         if (disposed && closed)
943                                 throw new ObjectDisposedException (GetType ().ToString ());
944
945                         if (result == null)
946                                 throw new ArgumentNullException ("result");
947
948                         SocketAsyncResult req = result as SocketAsyncResult;
949                         if (req == null)
950                                 throw new ArgumentException ("Invalid IAsyncResult", "result");
951
952                         if (!result.IsCompleted)
953                                 result.AsyncWaitHandle.WaitOne();
954
955                         Interlocked.Decrement (ref pendingEnds);
956                         CheckIfClose ();
957                         req.CheckIfThrowDelayedException();
958                         return req.Socket;
959                 }
960
961                 public void EndConnect(IAsyncResult result) {
962                         if (disposed && closed)
963                                 throw new ObjectDisposedException (GetType ().ToString ());
964
965                         if (result == null)
966                                 throw new ArgumentNullException ("result");
967
968                         SocketAsyncResult req = result as SocketAsyncResult;
969                         if (req == null)
970                                 throw new ArgumentException ("Invalid IAsyncResult", "result");
971
972                         if (!result.IsCompleted)
973                                 result.AsyncWaitHandle.WaitOne();
974
975                         Interlocked.Decrement (ref pendingEnds);
976                         CheckIfClose ();
977                         req.CheckIfThrowDelayedException();
978                 }
979
980                 public int EndReceive(IAsyncResult result) {
981                         if (disposed && closed)
982                                 throw new ObjectDisposedException (GetType ().ToString ());
983
984                         if (result == null)
985                                 throw new ArgumentNullException ("result");
986
987                         SocketAsyncResult req = result as SocketAsyncResult;
988                         if (req == null)
989                                 throw new ArgumentException ("Invalid IAsyncResult", "result");
990
991                         RemoveReference (req);
992                         if (!result.IsCompleted)
993                                 result.AsyncWaitHandle.WaitOne();
994
995                         Interlocked.Decrement (ref pendingEnds);
996                         CheckIfClose ();
997                         req.CheckIfThrowDelayedException();
998                         return req.Total;
999                 }
1000
1001                 public int EndReceiveFrom(IAsyncResult result,
1002                                           ref EndPoint end_point) {
1003                         if (disposed && closed)
1004                                 throw new ObjectDisposedException (GetType ().ToString ());
1005
1006                         if (result == null)
1007                                 throw new ArgumentNullException ("result");
1008
1009                         SocketAsyncResult req = result as SocketAsyncResult;
1010                         if (req == null)
1011                                 throw new ArgumentException ("Invalid IAsyncResult", "result");
1012
1013                         if (!result.IsCompleted)
1014                                 result.AsyncWaitHandle.WaitOne();
1015
1016                         Interlocked.Decrement (ref pendingEnds);
1017                         CheckIfClose ();
1018                         req.CheckIfThrowDelayedException();
1019                         end_point = req.EndPoint;
1020                         return req.Total;
1021                 }
1022
1023                 public int EndSend(IAsyncResult result) {
1024                         if (disposed && closed)
1025                                 throw new ObjectDisposedException (GetType ().ToString ());
1026
1027                         if (result == null)
1028                                 throw new ArgumentNullException ("result");
1029
1030                         SocketAsyncResult req = result as SocketAsyncResult;
1031                         if (req == null)
1032                                 throw new ArgumentException ("Invalid IAsyncResult", "result");
1033
1034                         RemoveReference (req);
1035                         if (!result.IsCompleted)
1036                                 result.AsyncWaitHandle.WaitOne();
1037
1038                         Interlocked.Decrement (ref pendingEnds);
1039                         CheckIfClose ();
1040                         req.CheckIfThrowDelayedException();
1041                         return req.Total;
1042                 }
1043
1044                 public int EndSendTo(IAsyncResult result) {
1045                         if (disposed && closed)
1046                                 throw new ObjectDisposedException (GetType ().ToString ());
1047
1048                         if (result == null)
1049                                 throw new ArgumentNullException ("result");
1050
1051                         SocketAsyncResult req = result as SocketAsyncResult;
1052                         if (req == null)
1053                                 throw new ArgumentException ("Invalid IAsyncResult", "result");
1054
1055                         if (!result.IsCompleted)
1056                                 result.AsyncWaitHandle.WaitOne();
1057
1058                         Interlocked.Decrement (ref pendingEnds);
1059                         CheckIfClose ();
1060                         req.CheckIfThrowDelayedException();
1061                         return req.Total;
1062                 }
1063
1064                 void CheckIfClose ()
1065                 {
1066                         if (Interlocked.CompareExchange (ref closeDelayed, 0, 1) == 1 &&
1067                             Interlocked.CompareExchange (ref pendingEnds, 0, 0) == 0) {
1068                                 closed = true;
1069
1070                                 int error;
1071                                 
1072                                 Close_internal(socket, out error);
1073
1074                                 if (error != 0) {
1075                                         throw new SocketException (error);
1076                                 }
1077                         }
1078                 }
1079
1080                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1081                 private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
1082                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1083                 private extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
1084
1085                 public object GetSocketOption(SocketOptionLevel level,
1086                                               SocketOptionName name) {
1087                         object obj_val;
1088                         int error;
1089                         
1090                         GetSocketOption_obj_internal(socket, level, name,
1091                                                      out obj_val, out error);
1092
1093                         if (error != 0) {
1094                                 throw new SocketException (error);
1095                         }
1096                         
1097                         if(name==SocketOptionName.Linger) {
1098                                 return((LingerOption)obj_val);
1099                         } else if (name==SocketOptionName.AddMembership ||
1100                                    name==SocketOptionName.DropMembership) {
1101                                 return((MulticastOption)obj_val);
1102                         } else {
1103                                 return((int)obj_val);
1104                         }
1105                 }
1106
1107                 public void GetSocketOption(SocketOptionLevel level,
1108                                             SocketOptionName name,
1109                                             byte[] opt_value) {
1110                         int opt_value_len=opt_value.Length;
1111                         int error;
1112                         
1113                         GetSocketOption_arr_internal(socket, level, name,
1114                                                      ref opt_value, out error);
1115
1116                         if (error != 0) {
1117                                 throw new SocketException (error);
1118                         }
1119                 }
1120
1121                 public byte[] GetSocketOption(SocketOptionLevel level,
1122                                               SocketOptionName name,
1123                                               int length) {
1124                         byte[] byte_val=new byte[length];
1125                         int error;
1126                         
1127                         GetSocketOption_arr_internal(socket, level, name,
1128                                                      ref byte_val, out error);
1129
1130                         if (error != 0) {
1131                                 throw new SocketException (error);
1132                         }
1133
1134                         return(byte_val);
1135                 }
1136
1137                 // See Socket.IOControl, WSAIoctl documentation in MSDN. The
1138                 // common options between UNIX and Winsock are FIONREAD,
1139                 // FIONBIO and SIOCATMARK. Anything else will depend on the
1140                 // system.
1141                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1142                 extern static int WSAIoctl (IntPtr sock, int ioctl_code,
1143                                             byte [] input, byte [] output,
1144                                             out int error);
1145
1146                 public int IOControl (int ioctl_code, byte [] in_value, byte [] out_value)
1147                 {
1148                         if (disposed)
1149                                 throw new ObjectDisposedException (GetType ().ToString ());
1150
1151                         int error;
1152                         int result = WSAIoctl (socket, ioctl_code, in_value,
1153                                                out_value, out error);
1154
1155                         if (error != 0) {
1156                                 throw new SocketException (error);
1157                         }
1158                         
1159                         if (result == -1)
1160                                 throw new InvalidOperationException ("Must use Blocking property instead.");
1161
1162                         return result;
1163                 }
1164
1165                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1166                 private extern static void Listen_internal(IntPtr sock,
1167                                                            int backlog,
1168                                                            out int error);
1169
1170                 public void Listen(int backlog) {
1171                         int error;
1172                         
1173                         Listen_internal(socket, backlog, out error);
1174
1175                         if (error != 0) {
1176                                 throw new SocketException (error);
1177                         }
1178                 }
1179
1180                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1181                 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
1182
1183                 public bool Poll (int time_us, SelectMode mode)
1184                 {
1185                         if (mode != SelectMode.SelectRead &&
1186                             mode != SelectMode.SelectWrite &&
1187                             mode != SelectMode.SelectError)
1188                                 throw new NotSupportedException ("'mode' parameter is not valid.");
1189
1190                         int error;
1191                         bool result = Poll_internal (socket, mode, time_us, out error);
1192                         if (error != 0)
1193                                 throw new SocketException (error);
1194
1195                         return result;
1196                 }
1197                 
1198                 public int Receive (byte [] buf)
1199                 {
1200                         if (buf == null)
1201                                 throw new ArgumentNullException ("buf");
1202
1203                         return Receive_nochecks (buf, 0, buf.Length, SocketFlags.None);
1204                 }
1205
1206                 public int Receive (byte [] buf, SocketFlags flags)
1207                 {
1208                         if (buf == null)
1209                                 throw new ArgumentNullException ("buf");
1210
1211                         return Receive_nochecks (buf, 0, buf.Length, flags);
1212                 }
1213
1214                 public int Receive (byte [] buf, int size, SocketFlags flags)
1215                 {
1216                         if (buf == null)
1217                                 throw new ArgumentNullException ("buf");
1218
1219                         if (size < 0 || size > buf.Length)
1220                                 throw new ArgumentOutOfRangeException ("size");
1221
1222                         return Receive_nochecks (buf, 0, size, flags);
1223                 }
1224
1225                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1226                 private extern static int Receive_internal(IntPtr sock,
1227                                                            byte[] buffer,
1228                                                            int offset,
1229                                                            int count,
1230                                                            SocketFlags flags,
1231                                                            out int error);
1232
1233                 public int Receive (byte [] buf, int offset, int size, SocketFlags flags)
1234                 {
1235                         if (buf == null)
1236                                 throw new ArgumentNullException ("buf");
1237
1238                         if (offset < 0 || offset > buf.Length)
1239                                 throw new ArgumentOutOfRangeException ("offset");
1240
1241                         if (size < 0 || offset + size > buf.Length)
1242                                 throw new ArgumentOutOfRangeException ("size");
1243                         
1244                         return Receive_nochecks (buf, offset, size, flags);
1245                 }
1246
1247                 int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags)
1248                 {
1249                         int ret, error;
1250                         
1251                         ret = Receive_internal (socket, buf, offset, size, flags, out error);
1252
1253                         if (error != 0) {
1254                                 connected = false;
1255                                 throw new SocketException (error);
1256                         }
1257                         
1258                         connected = true;
1259
1260                         return ret;
1261                 }
1262                 
1263                 public int ReceiveFrom (byte [] buf, ref EndPoint remote_end)
1264                 {
1265                         if (buf == null)
1266                                 throw new ArgumentNullException ("buf");
1267
1268                         if (remote_end == null)
1269                                 throw new ArgumentNullException ("remote_end");
1270
1271                         return ReceiveFrom_nochecks (buf, 0, buf.Length, SocketFlags.None, ref remote_end);
1272                 }
1273
1274                 public int ReceiveFrom (byte [] buf, SocketFlags flags, ref EndPoint remote_end)
1275                 {
1276                         if (buf == null)
1277                                 throw new ArgumentNullException ("buf");
1278
1279                         if (remote_end == null)
1280                                 throw new ArgumentNullException ("remote_end");
1281
1282
1283                         return ReceiveFrom_nochecks (buf, 0, buf.Length, flags, ref remote_end);
1284                 }
1285
1286                 public int ReceiveFrom (byte [] buf, int size, SocketFlags flags,
1287                                         ref EndPoint remote_end)
1288                 {
1289                         if (buf == null)
1290                                 throw new ArgumentNullException ("buf");
1291
1292                         if (remote_end == null)
1293                                 throw new ArgumentNullException ("remote_end");
1294
1295                         if (size < 0 || size > buf.Length)
1296                                 throw new ArgumentOutOfRangeException ("size");
1297
1298                         return ReceiveFrom_nochecks (buf, 0, size, flags, ref remote_end);
1299                 }
1300
1301
1302                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1303                 private extern static int RecvFrom_internal(IntPtr sock,
1304                                                             byte[] buffer,
1305                                                             int offset,
1306                                                             int count,
1307                                                             SocketFlags flags,
1308                                                             ref SocketAddress sockaddr,
1309                                                             out int error);
1310
1311                 public int ReceiveFrom (byte [] buf, int offset, int size, SocketFlags flags,
1312                                         ref EndPoint remote_end)
1313                 {
1314                         if (buf == null)
1315                                 throw new ArgumentNullException ("buf");
1316
1317                         if (remote_end == null)
1318                                 throw new ArgumentNullException ("remote_end");
1319
1320                         if (offset < 0 || offset > buf.Length)
1321                                 throw new ArgumentOutOfRangeException ("offset");
1322
1323                         if (size < 0 || offset + size > buf.Length)
1324                                 throw new ArgumentOutOfRangeException ("size");
1325
1326                         return ReceiveFrom_nochecks (buf, offset, size, flags, ref remote_end);
1327                 }
1328
1329                 int ReceiveFrom_nochecks (byte [] buf, int offset, int size, SocketFlags flags,
1330                                           ref EndPoint remote_end)
1331                 {
1332                         SocketAddress sockaddr = remote_end.Serialize();
1333                         int cnt, error;
1334
1335                         cnt = RecvFrom_internal (socket, buf, offset, size, flags, ref sockaddr, out error);
1336
1337                         if (error != 0) {
1338                                 connected = false;
1339                                 throw new SocketException (error);
1340                         }
1341
1342                         connected = true;
1343                         
1344                         // Stupidly, EndPoint.Create() is an
1345                         // instance method
1346                         remote_end = remote_end.Create (sockaddr);
1347
1348                         return cnt;
1349                 }
1350
1351                 public int Send (byte [] buf)
1352                 {
1353                         if (buf == null)
1354                                 throw new ArgumentNullException ("buf");
1355
1356                         return Send_nochecks (buf, 0, buf.Length, SocketFlags.None);
1357                 }
1358
1359                 public int Send (byte [] buf, SocketFlags flags)
1360                 {
1361                         if (buf == null)
1362                                 throw new ArgumentNullException ("buf");
1363
1364                         return Send_nochecks (buf, 0, buf.Length, flags);
1365                 }
1366
1367                 public int Send (byte [] buf, int size, SocketFlags flags)
1368                 {
1369                         if (buf == null)
1370                                 throw new ArgumentNullException ("buf");
1371
1372                         if (size < 0 || size > buf.Length)
1373                                 throw new ArgumentOutOfRangeException ("size");
1374
1375                         return Send_nochecks (buf, 0, size, flags);
1376                 }
1377
1378                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1379                 private extern static int Send_internal(IntPtr sock,
1380                                                         byte[] buf, int offset,
1381                                                         int count,
1382                                                         SocketFlags flags,
1383                                                         out int error);
1384
1385                 public int Send (byte [] buf, int offset, int size, SocketFlags flags)
1386                 {
1387                         if (buf == null)
1388                                 throw new ArgumentNullException ("buffer");
1389
1390                         if (offset < 0 || offset > buf.Length)
1391                                 throw new ArgumentOutOfRangeException ("offset");
1392
1393                         if (size < 0 || offset + size > buf.Length)
1394                                 throw new ArgumentOutOfRangeException ("size");
1395
1396                         return Send_nochecks (buf, offset, size, flags);
1397                 }
1398
1399                 int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags)
1400                 {
1401                         if (size == 0)
1402                                 return 0;
1403
1404                         int ret, error;
1405
1406                         ret = Send_internal (socket, buf, offset, size, flags, out error);
1407
1408                         if (error != 0) {
1409                                 connected = false;
1410                                 throw new SocketException (error);
1411                         }
1412
1413                         connected = true;
1414
1415                         return ret;
1416                 }
1417
1418                 public int SendTo (byte [] buffer, EndPoint remote_end)
1419                 {
1420                         if (buffer == null)
1421                                 throw new ArgumentNullException ("buffer");
1422
1423                         if (remote_end == null)
1424                                 throw new ArgumentNullException ("remote_end");
1425
1426                         return SendTo_nochecks (buffer, 0, buffer.Length, SocketFlags.None, remote_end);
1427                 }
1428
1429                 public int SendTo (byte [] buffer, SocketFlags flags, EndPoint remote_end)
1430                 {
1431                         if (buffer == null)
1432                                 throw new ArgumentNullException ("buffer");
1433
1434                         if (remote_end == null)
1435                                 throw new ArgumentNullException ("remote_end");
1436                                 
1437                         return SendTo_nochecks (buffer, 0, buffer.Length, flags, remote_end);
1438                 }
1439
1440                 public int SendTo (byte [] buffer, int size, SocketFlags flags, EndPoint remote_end)
1441                 {
1442                         if (buffer == null)
1443                                 throw new ArgumentNullException ("buffer");
1444
1445                         if (remote_end == null)
1446                                 throw new ArgumentNullException ("remote_end");
1447
1448                         if (size < 0 || size > buffer.Length)
1449                                 throw new ArgumentOutOfRangeException ("size");
1450
1451                         return SendTo_nochecks (buffer, 0, size, flags, remote_end);
1452                 }
1453
1454
1455                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1456                 private extern static int SendTo_internal(IntPtr sock,
1457                                                           byte[] buffer,
1458                                                           int offset,
1459                                                           int count,
1460                                                           SocketFlags flags,
1461                                                           SocketAddress sa,
1462                                                           out int error);
1463
1464                 public int SendTo (byte [] buffer, int offset, int size, SocketFlags flags,
1465                                    EndPoint remote_end)
1466                 {
1467                         if (buffer == null)
1468                                 throw new ArgumentNullException ("buffer");
1469
1470                         if (remote_end == null)
1471                                 throw new ArgumentNullException("remote_end");
1472
1473                         if (offset < 0 || offset > buffer.Length)
1474                                 throw new ArgumentOutOfRangeException ("offset");
1475
1476                         if (size < 0 || offset + size > buffer.Length)
1477                                 throw new ArgumentOutOfRangeException ("size");
1478
1479                         return SendTo_nochecks (buffer, offset, size, flags, remote_end);
1480                 }
1481
1482                 int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags,
1483                                    EndPoint remote_end)
1484                 {
1485                         SocketAddress sockaddr = remote_end.Serialize ();
1486
1487                         int ret, error;
1488
1489                         ret = SendTo_internal (socket, buffer, offset, size, flags, sockaddr, out error);
1490
1491                         if (error != 0) {
1492                                 connected = false;
1493                                 throw new SocketException (error);
1494                         }
1495
1496                         connected = true;
1497
1498                         return ret;
1499                 }
1500
1501                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1502                 private extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level,
1503                                                                      SocketOptionName name, object obj_val,
1504                                                                      byte [] byte_val, int int_val,
1505                                                                      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                                 int int_val = (bool_val) ? 1 : 0;
1550                                 
1551                                 SetSocketOption_internal (socket, level, name, null, null, int_val, out error);
1552                         } else {
1553                                 SetSocketOption_internal (socket, level, name, opt_value, null, 0, out error);
1554                         }
1555
1556                         if (error != 0) {
1557                                 throw new SocketException (error);
1558                         }
1559                 }
1560
1561                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1562                 private extern static void Shutdown_internal(IntPtr socket, SocketShutdown how, out int error);
1563                 
1564                 public void Shutdown(SocketShutdown how) {
1565                         int error;
1566                         
1567                         Shutdown_internal(socket, how, out error);
1568
1569                         if (error != 0) {
1570                                 throw new SocketException (error);
1571                         }
1572                 }
1573
1574                 public override int GetHashCode ()
1575                 { 
1576                         return (int) socket; 
1577                 }
1578
1579                 private bool disposed;
1580                 
1581                 protected virtual void Dispose(bool explicitDisposing) {
1582                         if (!disposed) {
1583                                 int error;
1584                                 
1585                                 disposed = true;
1586                                 connected = false;
1587                                 if (!explicitDisposing) {
1588                                         closed = true;
1589                                         Close_internal (socket, out error);
1590
1591                                         if (error != 0) {
1592                                                 throw new SocketException (error);
1593                                         }
1594                                         
1595                                         return;
1596                                 }
1597                         
1598                                 if (Interlocked.CompareExchange (ref pendingEnds, 0, 0) == 0) {
1599                                         closed = true;
1600                                         Close_internal (socket, out error);
1601
1602                                         if (error != 0) {
1603                                                 throw new SocketException (error);
1604                                         }
1605                                 } else {
1606                                         Interlocked.CompareExchange (ref closeDelayed, 1, 0);
1607                                 }
1608                         }
1609                 }
1610
1611                 void IDisposable.Dispose ()
1612                 {
1613                         Dispose (true);
1614                         GC.SuppressFinalize (this);
1615                 }
1616                 
1617                 ~Socket () {
1618                         Dispose(false);
1619                 }
1620
1621                 static Hashtable asyncObjects;
1622
1623                 static void KeepReference (object o)
1624                 {
1625                         lock (typeof (Socket)) {
1626                                 if (asyncObjects == null)
1627                                         asyncObjects = new Hashtable ();
1628
1629                                 asyncObjects [o] = o;
1630                         }
1631                 }
1632
1633                 static void RemoveReference (object o)
1634                 {
1635                         lock (typeof (Socket)) {
1636                                 if (asyncObjects == null)
1637                                         return;
1638
1639                                 asyncObjects.Remove (o);
1640                         }
1641                 }
1642
1643                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1644                 extern static bool GetSupportsAsync ();
1645
1646                 static bool FakeGetSupportsAsync ()
1647                 {
1648                         if (Environment.GetEnvironmentVariable ("MONO_ENABLE_SOCKET_AIO") != null)
1649                                 return GetSupportsAsync ();
1650                         
1651                         return false;
1652                 }
1653
1654                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1655                 extern static void AsyncReceiveInternal (SocketAsyncResult ares, out int error);
1656
1657                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1658                 extern static void AsyncSendInternal (SocketAsyncResult ares, out int error);
1659         }
1660 }
1661