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