Merge pull request #1304 from slluis/mac-proxy-autoconfig
[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 //      Sridhar Kulkarni (sridharkulkarni@gmail.com)
8 //      Brian Nickel (brian.nickel@gmail.com)
9 //
10 // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
11 //    http://www.myelin.co.nz
12 // (c) 2004-2011 Novell, Inc. (http://www.novell.com)
13 //
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System;
36 using System.Net;
37 using System.Collections;
38 using System.Collections.Generic;
39 using System.Runtime.CompilerServices;
40 using System.Runtime.InteropServices;
41 using System.Threading;
42 using System.Reflection;
43 using System.IO;
44 using System.Net.Configuration;
45 using System.Text;
46 using System.Timers;
47 using System.Net.NetworkInformation;
48
49 namespace System.Net.Sockets 
50 {
51         public partial class Socket : IDisposable
52         {
53                 private bool islistening;
54                 private bool useoverlappedIO;
55                 private const int SOCKET_CLOSED = 10004;
56
57                 private static readonly string timeout_exc_msg = "A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond";
58
59                 static void AddSockets (List<Socket> sockets, IList list, string name)
60                 {
61                         if (list != null) {
62                                 foreach (Socket sock in list) {
63                                         if (sock == null) // MS throws a NullRef
64                                                 throw new ArgumentNullException ("name", "Contains a null element");
65                                         sockets.Add (sock);
66                                 }
67                         }
68
69                         sockets.Add (null);
70                 }
71                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
72                 private extern static void Select_internal (ref Socket [] sockets,
73                                                         int microSeconds,
74                                                         out int error);
75                 public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
76                 {
77                         var list = new List<Socket> ();
78                         AddSockets (list, checkRead, "checkRead");
79                         AddSockets (list, checkWrite, "checkWrite");
80                         AddSockets (list, checkError, "checkError");
81
82                         if (list.Count == 3) {
83                                 throw new ArgumentNullException ("checkRead, checkWrite, checkError",
84                                                                  "All the lists are null or empty.");
85                         }
86
87                         int error;
88                         /*
89                          * The 'sockets' array contains: READ socket 0-n, null,
90                          *                               WRITE socket 0-n, null,
91                          *                               ERROR socket 0-n, null
92                          */
93                         Socket [] sockets = list.ToArray ();
94                         Select_internal (ref sockets, microSeconds, out error);
95
96                         if (error != 0)
97                                 throw new SocketException (error);
98
99                         if (sockets == null) {
100                                 if (checkRead != null)
101                                         checkRead.Clear ();
102                                 if (checkWrite != null)
103                                         checkWrite.Clear ();
104                                 if (checkError != null)
105                                         checkError.Clear ();
106                                 return;
107                         }
108
109                         int mode = 0;
110                         int count = sockets.Length;
111                         IList currentList = checkRead;
112                         int currentIdx = 0;
113                         for (int i = 0; i < count; i++) {
114                                 Socket sock = sockets [i];
115                                 if (sock == null) { // separator
116                                         if (currentList != null) {
117                                                 // Remove non-signaled sockets after the current one
118                                                 int to_remove = currentList.Count - currentIdx;
119                                                 for (int k = 0; k < to_remove; k++)
120                                                         currentList.RemoveAt (currentIdx);
121                                         }
122                                         currentList = (mode == 0) ? checkWrite : checkError;
123                                         currentIdx = 0;
124                                         mode++;
125                                         continue;
126                                 }
127
128                                 if (mode == 1 && currentList == checkWrite && !sock.connected) {
129                                         if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
130                                                 sock.connected = true;
131                                 }
132
133                                 // Remove non-signaled sockets before the current one
134                                 //int max = currentList.Count;
135                                 while (((Socket) currentList [currentIdx]) != sock) {
136                                         currentList.RemoveAt (currentIdx);
137                                 }
138                                 currentIdx++;
139                         }
140                 }
141
142                 // private constructor used by Accept, which already
143                 // has a socket handle to use
144                 internal Socket(AddressFamily family, SocketType type,
145                                ProtocolType proto, IntPtr sock)
146                 {
147                         address_family=family;
148                         socket_type=type;
149                         protocol_type=proto;
150                         
151                         socket=sock;
152                         connected=true;
153                 }
154
155                 private void SocketDefaults ()
156                 {
157                         try {
158                                 if (address_family == AddressFamily.InterNetwork /* Need to test IPv6 further ||
159                                                                                    address_family == AddressFamily.InterNetworkV6 */) {
160                                         /* This is the default, but it
161                                          * probably has nasty side
162                                          * effects on Linux, as the
163                                          * socket option is kludged by
164                                          * turning on or off PMTU
165                                          * discovery...
166                                          */
167                                         this.DontFragment = false;
168                                 }
169
170                                 //
171                                 // Microsoft sets these to 8192, but we are going to keep them
172                                 // both to the OS defaults as these have a big performance impact.
173                                 // on WebClient performance.
174                                 //
175                                 //this.ReceiveBufferSize = 8192;
176                                 //this.SendBufferSize = 8192;
177                         } catch (SocketException) {
178                         }
179                 }
180
181 #if !MOBILE
182                 public Socket (SocketInformation socketInformation)
183                 {
184                         var options = socketInformation.Options;
185                         islistening = (options & SocketInformationOptions.Listening) != 0;
186                         connected   = (options & SocketInformationOptions.Connected) != 0;
187                         blocking    = (options & SocketInformationOptions.NonBlocking) == 0;
188                         useoverlappedIO = (options & SocketInformationOptions.UseOnlyOverlappedIO) != 0;
189
190                         var result = Mono.DataConverter.Unpack ("iiiil", socketInformation.ProtocolInformation, 0);
191                         
192                         address_family = (AddressFamily) (int) result [0];
193                         socket_type = (SocketType) (int) result [1];
194                         protocol_type = (ProtocolType) (int) result [2];
195                         isbound = (ProtocolType) (int) result [3] != 0;
196                         socket = (IntPtr) (long) result [4];
197                         SocketDefaults ();
198                 }
199 #endif
200         
201                 // Returns the amount of data waiting to be read on socket
202                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
203                 private extern static int Available_internal(IntPtr socket, out int error);
204
205                 public int Available {
206                         get {
207                                 if (disposed && closed)
208                                         throw new ObjectDisposedException (GetType ().ToString ());
209
210                                 int ret, error;
211                                 
212                                 ret = Available_internal(socket, out error);
213
214                                 if (error != 0)
215                                         throw new SocketException (error);
216
217                                 return(ret);
218                         }
219                 }
220
221
222                 public bool DontFragment {
223                         get {
224                                 if (disposed && closed) {
225                                         throw new ObjectDisposedException (GetType ().ToString ());
226                                 }
227
228                                 bool dontfragment;
229                                 
230                                 if (address_family == AddressFamily.InterNetwork) {
231                                         dontfragment = (int)(GetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment)) != 0;
232                                 } else if (address_family == AddressFamily.InterNetworkV6) {
233                                         dontfragment = (int)(GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment)) != 0;
234                                 } else {
235                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
236                                 }
237                                 
238                                 return(dontfragment);
239                         }
240                         set {
241                                 if (disposed && closed) {
242                                         throw new ObjectDisposedException (GetType ().ToString ());
243                                 }
244
245                                 if (address_family == AddressFamily.InterNetwork) {
246                                         SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment, value?1:0);
247                                 } else if (address_family == AddressFamily.InterNetworkV6) {
248                                         SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment, value?1:0);
249                                 } else {
250                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
251                                 }
252                         }
253                 }
254
255                 public bool EnableBroadcast {
256                         get {
257                                 if (disposed && closed) {
258                                         throw new ObjectDisposedException (GetType ().ToString ());
259                                 }
260
261                                 if (protocol_type != ProtocolType.Udp) {
262                                         throw new SocketException ((int)SocketError.ProtocolOption);
263                                 }
264                                 
265                                 return((int)(GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0);
266                         }
267                         set {
268                                 if (disposed && closed) {
269                                         throw new ObjectDisposedException (GetType ().ToString ());
270                                 }
271
272                                 if (protocol_type != ProtocolType.Udp) {
273                                         throw new SocketException ((int)SocketError.ProtocolOption);
274                                 }
275
276                                 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value?1:0);
277                         }
278                 }
279                 
280                 public bool ExclusiveAddressUse {
281                         get {
282                                 if (disposed && closed) {
283                                         throw new ObjectDisposedException (GetType ().ToString ());
284                                 }
285
286                                 return((int)(GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse)) != 0);
287                         }
288                         set {
289                                 if (disposed && closed) {
290                                         throw new ObjectDisposedException (GetType ().ToString ());
291                                 }
292                                 if (isbound) {
293                                         throw new InvalidOperationException ("Bind has already been called for this socket");
294                                 }
295                                 
296                                 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value?1:0);
297                         }
298                 }
299                 
300                 public bool IsBound {
301                         get {
302                                 return(isbound);
303                         }
304                 }
305                 
306                 public LingerOption LingerState {
307                         get {
308                                 if (disposed && closed) {
309                                         throw new ObjectDisposedException (GetType ().ToString ());
310                                 }
311
312                                 return((LingerOption)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger));
313                         }
314                         set {
315                                 if (disposed && closed) {
316                                         throw new ObjectDisposedException (GetType ().ToString ());
317                                 }
318                                 
319                                 SetSocketOption (SocketOptionLevel.Socket,
320                                                  SocketOptionName.Linger,
321                                                  value);
322                         }
323                 }
324                 
325                 public bool MulticastLoopback {
326                         get {
327                                 if (disposed && closed) {
328                                         throw new ObjectDisposedException (GetType ().ToString ());
329                                 }
330
331                                 /* Even though this option can be set
332                                  * for TCP sockets on Linux, throw
333                                  * this exception anyway to be
334                                  * compatible (the MSDN docs say
335                                  * "Setting this property on a
336                                  * Transmission Control Protocol (TCP)
337                                  * socket will have no effect." but
338                                  * the MS runtime throws the
339                                  * exception...)
340                                  */
341                                 if (protocol_type == ProtocolType.Tcp) {
342                                         throw new SocketException ((int)SocketError.ProtocolOption);
343                                 }
344                                 
345                                 bool multicastloopback;
346                                 
347                                 if (address_family == AddressFamily.InterNetwork) {
348                                         multicastloopback = (int)(GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
349                                 } else if (address_family == AddressFamily.InterNetworkV6) {
350                                         multicastloopback = (int)(GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
351                                 } else {
352                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
353                                 }
354                                 
355                                 return(multicastloopback);
356                         }
357                         set {
358                                 if (disposed && closed) {
359                                         throw new ObjectDisposedException (GetType ().ToString ());
360                                 }
361
362                                 /* Even though this option can be set
363                                  * for TCP sockets on Linux, throw
364                                  * this exception anyway to be
365                                  * compatible (the MSDN docs say
366                                  * "Setting this property on a
367                                  * Transmission Control Protocol (TCP)
368                                  * socket will have no effect." but
369                                  * the MS runtime throws the
370                                  * exception...)
371                                  */
372                                 if (protocol_type == ProtocolType.Tcp) {
373                                         throw new SocketException ((int)SocketError.ProtocolOption);
374                                 }
375                                 
376                                 if (address_family == AddressFamily.InterNetwork) {
377                                         SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value?1:0);
378                                 } else if (address_family == AddressFamily.InterNetworkV6) {
379                                         SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value?1:0);
380                                 } else {
381                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
382                                 }
383                         }
384                 }
385                 
386                 
387                 [MonoTODO ("This doesn't do anything on Mono yet")]
388                 public bool UseOnlyOverlappedIO {
389                         get {
390                                 return(useoverlappedIO);
391                         }
392                         set {
393                                 useoverlappedIO = value;
394                         }
395                 }
396
397                 public IntPtr Handle {
398                         get {
399                                 return(socket);
400                         }
401                 }
402
403                 // Returns the local endpoint details in addr and port
404                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
405                 private extern static SocketAddress LocalEndPoint_internal(IntPtr socket, int family, out int error);
406
407                 // Wish:  support non-IP endpoints.
408                 public EndPoint LocalEndPoint {
409                         get {
410                                 if (disposed && closed)
411                                         throw new ObjectDisposedException (GetType ().ToString ());
412                                 
413                                 /*
414                                  * If the seed EndPoint is null, Connect, Bind,
415                                  * etc has not yet been called. MS returns null
416                                  * in this case.
417                                  */
418                                 if (seed_endpoint == null)
419                                         return null;
420                                 
421                                 SocketAddress sa;
422                                 int error;
423                                 
424                                 sa=LocalEndPoint_internal(socket, (int) address_family, out error);
425
426                                 if (error != 0)
427                                         throw new SocketException (error);
428
429                                 return seed_endpoint.Create (sa);
430                         }
431                 }
432
433                 public SocketType SocketType {
434                         get {
435                                 return(socket_type);
436                         }
437                 }
438
439                 public int SendTimeout {
440                         get {
441                                 if (disposed && closed)
442                                         throw new ObjectDisposedException (GetType ().ToString ());
443
444                                 return (int)GetSocketOption(
445                                         SocketOptionLevel.Socket,
446                                         SocketOptionName.SendTimeout);
447                         }
448                         set {
449                                 if (disposed && closed)
450                                         throw new ObjectDisposedException (GetType ().ToString ());
451
452                                 if (value < -1)
453                                         throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
454
455                                 /* According to the MSDN docs we
456                                  * should adjust values between 1 and
457                                  * 499 to 500, but the MS runtime
458                                  * doesn't do this.
459                                  */
460                                 if (value == -1)
461                                         value = 0;
462
463                                 SetSocketOption(
464                                         SocketOptionLevel.Socket,
465                                         SocketOptionName.SendTimeout, value);
466                         }
467                 }
468
469                 public int ReceiveTimeout {
470                         get {
471                                 if (disposed && closed)
472                                         throw new ObjectDisposedException (GetType ().ToString ());
473
474                                 return (int)GetSocketOption(
475                                         SocketOptionLevel.Socket,
476                                         SocketOptionName.ReceiveTimeout);
477                         }
478                         set {
479                                 if (disposed && closed)
480                                         throw new ObjectDisposedException (GetType ().ToString ());
481
482                                 if (value < -1)
483                                         throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
484
485                                 if (value == -1) {
486                                         value = 0;
487                                 }
488                                 
489                                 SetSocketOption(
490                                         SocketOptionLevel.Socket,
491                                         SocketOptionName.ReceiveTimeout, value);
492                         }
493                 }
494
495                 public bool AcceptAsync (SocketAsyncEventArgs e)
496                 {
497                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
498                         
499                         if (disposed && closed)
500                                 throw new ObjectDisposedException (GetType ().ToString ());
501                         if (!IsBound)
502                                 throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
503                         if (!islistening)
504                                 throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
505                         if (e.BufferList != null)
506                                 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
507                         if (e.Count < 0)
508                                 throw new ArgumentOutOfRangeException ("e.Count");
509
510                         Socket acceptSocket = e.AcceptSocket;
511                         if (acceptSocket != null) {
512                                 if (acceptSocket.IsBound || acceptSocket.Connected)
513                                         throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
514                         }
515
516                         e.curSocket = this;
517                         Worker w = e.Worker;
518                         w.Init (this, e, SocketOperation.Accept);
519                         int count;
520                         lock (readQ) {
521                                 readQ.Enqueue (e.Worker);
522                                 count = readQ.Count;
523                         }
524                         if (count == 1)
525                                 socket_pool_queue (Worker.Dispatcher, w.result);
526                         return true;
527                 }
528                 // Creates a new system socket, returning the handle
529                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
530                 private extern static IntPtr Accept_internal(IntPtr sock, out int error, bool blocking);
531
532                 public Socket Accept() {
533                         if (disposed && closed)
534                                 throw new ObjectDisposedException (GetType ().ToString ());
535
536                         int error = 0;
537                         IntPtr sock = (IntPtr) (-1);
538                         try {
539                                 RegisterForBlockingSyscall ();
540                                 sock = Accept_internal(socket, out error, blocking);
541                         } finally {
542                                 UnRegisterForBlockingSyscall ();
543                         }
544
545                         if (error != 0) {
546                                 if (closed)
547                                         error = SOCKET_CLOSED;
548                                 throw new SocketException(error);
549                         }
550
551                         Socket accepted = new Socket(this.AddressFamily, this.SocketType,
552                                 this.ProtocolType, sock);
553
554                         accepted.seed_endpoint = this.seed_endpoint;
555                         accepted.Blocking = this.Blocking;
556                         return(accepted);
557                 }
558
559                 internal void Accept (Socket acceptSocket)
560                 {
561                         if (disposed && closed)
562                                 throw new ObjectDisposedException (GetType ().ToString ());
563                         
564                         int error = 0;
565                         IntPtr sock = (IntPtr)(-1);
566                         
567                         try {
568                                 RegisterForBlockingSyscall ();
569                                 sock = Accept_internal (socket, out error, blocking);
570                         } finally {
571                                 UnRegisterForBlockingSyscall ();
572                         }
573                         
574                         if (error != 0) {
575                                 if (closed)
576                                         error = SOCKET_CLOSED;
577                                 throw new SocketException (error);
578                         }
579                         
580                         acceptSocket.address_family = this.AddressFamily;
581                         acceptSocket.socket_type = this.SocketType;
582                         acceptSocket.protocol_type = this.ProtocolType;
583                         acceptSocket.socket = sock;
584                         acceptSocket.connected = true;
585                         acceptSocket.seed_endpoint = this.seed_endpoint;
586                         acceptSocket.Blocking = this.Blocking;
587
588                         /* FIXME: figure out what if anything else
589                          * needs to be reset
590                          */
591                 }
592
593                 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
594                 {
595                         if (disposed && closed)
596                                 throw new ObjectDisposedException (GetType ().ToString ());
597
598                         if (!isbound || !islistening)
599                                 throw new InvalidOperationException ();
600
601                         SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Accept);
602                         int count;
603                         lock (readQ) {
604                                 readQ.Enqueue (req.Worker);
605                                 count = readQ.Count;
606                         }
607                         if (count == 1)
608                                 socket_pool_queue (Worker.Dispatcher, req);
609                         return req;
610                 }
611
612                 public IAsyncResult BeginAccept (int receiveSize,
613                                                  AsyncCallback callback,
614                                                  object state)
615                 {
616                         if (disposed && closed)
617                                 throw new ObjectDisposedException (GetType ().ToString ());
618
619                         if (receiveSize < 0)
620                                 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
621
622                         SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive);
623                         req.Buffer = new byte[receiveSize];
624                         req.Offset = 0;
625                         req.Size = receiveSize;
626                         req.SockFlags = SocketFlags.None;
627                         int count;
628                         lock (readQ) {
629                                 readQ.Enqueue (req.Worker);
630                                 count = readQ.Count;
631                         }
632                         if (count == 1)
633                                 socket_pool_queue (Worker.Dispatcher, req);
634                         return req;
635                 }
636
637                 public IAsyncResult BeginAccept (Socket acceptSocket,
638                                                  int receiveSize,
639                                                  AsyncCallback callback,
640                                                  object state)
641                 {
642                         if (disposed && closed)
643                                 throw new ObjectDisposedException (GetType ().ToString ());
644
645                         if (receiveSize < 0)
646                                 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
647
648                         if (acceptSocket != null) {
649                                 if (acceptSocket.disposed && acceptSocket.closed)
650                                         throw new ObjectDisposedException (acceptSocket.GetType ().ToString ());
651
652                                 if (acceptSocket.IsBound)
653                                         throw new InvalidOperationException ();
654
655                                 /* For some reason the MS runtime
656                                  * barfs if the new socket is not TCP,
657                                  * even though it's just about to blow
658                                  * away all those parameters
659                                  */
660                                 if (acceptSocket.ProtocolType != ProtocolType.Tcp)
661                                         throw new SocketException ((int)SocketError.InvalidArgument);
662                         }
663                         
664                         SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.AcceptReceive);
665                         req.Buffer = new byte[receiveSize];
666                         req.Offset = 0;
667                         req.Size = receiveSize;
668                         req.SockFlags = SocketFlags.None;
669                         req.AcceptSocket = acceptSocket;
670                         int count;
671                         lock (readQ) {
672                                 readQ.Enqueue (req.Worker);
673                                 count = readQ.Count;
674                         }
675                         if (count == 1)
676                                 socket_pool_queue (Worker.Dispatcher, req);
677                         return(req);
678                 }
679
680                 public IAsyncResult BeginConnect (IPAddress address, int port,
681                                                   AsyncCallback callback,
682                                                   object state)
683                 {
684                         if (disposed && closed)
685                                 throw new ObjectDisposedException (GetType ().ToString ());
686
687                         if (address == null)
688                                 throw new ArgumentNullException ("address");
689
690                         if (address.ToString ().Length == 0)
691                                 throw new ArgumentException ("The length of the IP address is zero");
692
693                         if (port <= 0 || port > 65535)
694                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
695
696                         if (islistening)
697                                 throw new InvalidOperationException ();
698
699                         IPEndPoint iep = new IPEndPoint (address, port);
700                         return(BeginConnect (iep, callback, state));
701                 }
702
703                 public IAsyncResult BeginConnect (string host, int port,
704                                                   AsyncCallback callback,
705                                                   object state)
706                 {
707                         if (disposed && closed)
708                                 throw new ObjectDisposedException (GetType ().ToString ());
709
710                         if (host == null)
711                                 throw new ArgumentNullException ("host");
712
713                         if (address_family != AddressFamily.InterNetwork &&
714                                 address_family != AddressFamily.InterNetworkV6)
715                                 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
716
717                         if (port <= 0 || port > 65535)
718                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
719
720                         if (islistening)
721                                 throw new InvalidOperationException ();
722
723                         return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
724                 }
725
726                 public IAsyncResult BeginDisconnect (bool reuseSocket,
727                                                      AsyncCallback callback,
728                                                      object state)
729                 {
730                         if (disposed && closed)
731                                 throw new ObjectDisposedException (GetType ().ToString ());
732
733                         SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Disconnect);
734                         req.ReuseSocket = reuseSocket;
735                         socket_pool_queue (Worker.Dispatcher, req);
736                         return(req);
737                 }
738
739                 void CheckRange (byte[] buffer, int offset, int size)
740                 {
741                         if (offset < 0)
742                                 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
743                                 
744                         if (offset > buffer.Length)
745                                 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
746
747                         if (size < 0)                          
748                                 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
749                                 
750                         if (size > buffer.Length - offset)
751                                 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
752                 }
753                 
754                 public IAsyncResult BeginReceive(byte[] buffer, int offset,
755                                                  int size,
756                                                  SocketFlags socket_flags,
757                                                  AsyncCallback callback,
758                                                  object state) {
759
760                         if (disposed && closed)
761                                 throw new ObjectDisposedException (GetType ().ToString ());
762
763                         if (buffer == null)
764                                 throw new ArgumentNullException ("buffer");
765
766                         CheckRange (buffer, offset, size);
767
768                         SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Receive);
769                         req.Buffer = buffer;
770                         req.Offset = offset;
771                         req.Size = size;
772                         req.SockFlags = socket_flags;
773                         int count;
774                         lock (readQ) {
775                                 readQ.Enqueue (req.Worker);
776                                 count = readQ.Count;
777                         }
778                         if (count == 1)
779                                 socket_pool_queue (Worker.Dispatcher, req);
780                         return req;
781                 }
782
783                 public IAsyncResult BeginReceive (byte[] buffer, int offset,
784                                                   int size, SocketFlags flags,
785                                                   out SocketError error,
786                                                   AsyncCallback callback,
787                                                   object state)
788                 {
789                         /* As far as I can tell from the docs and from
790                          * experimentation, a pointer to the
791                          * SocketError parameter is not supposed to be
792                          * saved for the async parts.  And as we don't
793                          * set any socket errors in the setup code, we
794                          * just have to set it to Success.
795                          */
796                         error = SocketError.Success;
797                         return (BeginReceive (buffer, offset, size, flags, callback, state));
798                 }
799
800                 [CLSCompliant (false)]
801                 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers,
802                                                   SocketFlags socketFlags,
803                                                   AsyncCallback callback,
804                                                   object state)
805                 {
806                         if (disposed && closed)
807                                 throw new ObjectDisposedException (GetType ().ToString ());
808
809                         if (buffers == null)
810                                 throw new ArgumentNullException ("buffers");
811
812                         SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveGeneric);
813                         req.Buffers = buffers;
814                         req.SockFlags = socketFlags;
815                         int count;
816                         lock(readQ) {
817                                 readQ.Enqueue (req.Worker);
818                                 count = readQ.Count;
819                         }
820                         if (count == 1)
821                                 socket_pool_queue (Worker.Dispatcher, req);
822                         return req;
823                 }
824                 
825                 [CLSCompliant (false)]
826                 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers,
827                                                   SocketFlags socketFlags,
828                                                   out SocketError errorCode,
829                                                   AsyncCallback callback,
830                                                   object state)
831                 {
832                         /* I assume the same SocketError semantics as
833                          * above
834                          */
835                         errorCode = SocketError.Success;
836                         return (BeginReceive (buffers, socketFlags, callback, state));
837                 }
838
839                 public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset,
840                                                      int size,
841                                                      SocketFlags socket_flags,
842                                                      ref 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 (remote_end == null)
852                                 throw new ArgumentNullException ("remote_end");
853
854                         CheckRange (buffer, offset, size);
855
856                         SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.ReceiveFrom);
857                         req.Buffer = buffer;
858                         req.Offset = offset;
859                         req.Size = size;
860                         req.SockFlags = socket_flags;
861                         req.EndPoint = remote_end;
862                         int count;
863                         lock (readQ) {
864                                 readQ.Enqueue (req.Worker);
865                                 count = readQ.Count;
866                         }
867                         if (count == 1)
868                                 socket_pool_queue (Worker.Dispatcher, req);
869                         return req;
870                 }
871
872                 [MonoTODO]
873                 public IAsyncResult BeginReceiveMessageFrom (
874                         byte[] buffer, int offset, int size,
875                         SocketFlags socketFlags, ref EndPoint remoteEP,
876                         AsyncCallback callback, object state)
877                 {
878                         if (disposed && closed)
879                                 throw new ObjectDisposedException (GetType ().ToString ());
880
881                         if (buffer == null)
882                                 throw new ArgumentNullException ("buffer");
883
884                         if (remoteEP == null)
885                                 throw new ArgumentNullException ("remoteEP");
886
887                         CheckRange (buffer, offset, size);
888
889                         throw new NotImplementedException ();
890                 }
891
892                 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags,
893                                                AsyncCallback callback, object state)
894                 {
895                         if (disposed && closed)
896                                 throw new ObjectDisposedException (GetType ().ToString ());
897
898                         if (buffer == null)
899                                 throw new ArgumentNullException ("buffer");
900
901                         CheckRange (buffer, offset, size);
902
903                         if (!connected)
904                                 throw new SocketException ((int)SocketError.NotConnected);
905
906                         SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Send);
907                         req.Buffer = buffer;
908                         req.Offset = offset;
909                         req.Size = size;
910                         req.SockFlags = socket_flags;
911                         int count;
912                         lock (writeQ) {
913                                 writeQ.Enqueue (req.Worker);
914                                 count = writeQ.Count;
915                         }
916                         if (count == 1)
917                                 socket_pool_queue (Worker.Dispatcher, req);
918                         return req;
919                 }
920
921                 public IAsyncResult BeginSend (byte[] buffer, int offset,
922                                                int size,
923                                                SocketFlags socketFlags,
924                                                out SocketError errorCode,
925                                                AsyncCallback callback,
926                                                object state)
927                 {
928                         if (!connected) {
929                                 errorCode = SocketError.NotConnected;
930                                 throw new SocketException ((int)errorCode);
931                         }
932                         
933                         errorCode = SocketError.Success;
934                         
935                         return (BeginSend (buffer, offset, size, socketFlags, callback,
936                                 state));
937                 }
938
939                 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers,
940                                                SocketFlags socketFlags,
941                                                AsyncCallback callback,
942                                                object state)
943                 {
944                         if (disposed && closed)
945                                 throw new ObjectDisposedException (GetType ().ToString ());
946
947                         if (buffers == null)
948                                 throw new ArgumentNullException ("buffers");
949
950                         if (!connected)
951                                 throw new SocketException ((int)SocketError.NotConnected);
952
953                         SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.SendGeneric);
954                         req.Buffers = buffers;
955                         req.SockFlags = socketFlags;
956                         int count;
957                         lock (writeQ) {
958                                 writeQ.Enqueue (req.Worker);
959                                 count = writeQ.Count;
960                         }
961                         if (count == 1)
962                                 socket_pool_queue (Worker.Dispatcher, req);
963                         return req;
964                 }
965
966                 [CLSCompliant (false)]
967                 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers,
968                                                SocketFlags socketFlags,
969                                                out SocketError errorCode,
970                                                AsyncCallback callback,
971                                                object state)
972                 {
973                         if (!connected) {
974                                 errorCode = SocketError.NotConnected;
975                                 throw new SocketException ((int)errorCode);
976                         }
977                         
978                         errorCode = SocketError.Success;
979                         return (BeginSend (buffers, socketFlags, callback, state));
980                 }
981
982                 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
983
984                 sealed class SendFileAsyncResult : IAsyncResult {
985                         IAsyncResult ares;
986                         SendFileHandler d;
987
988                         public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
989                         {
990                                 this.d = d;
991                                 this.ares = ares;
992                         }
993
994                         public object AsyncState {
995                                 get { return ares.AsyncState; }
996                         }
997
998                         public WaitHandle AsyncWaitHandle {
999                                 get { return ares.AsyncWaitHandle; }
1000                         }
1001
1002                         public bool CompletedSynchronously {
1003                                 get { return ares.CompletedSynchronously; }
1004                         }
1005
1006                         public bool IsCompleted {
1007                                 get { return ares.IsCompleted; }
1008                         }
1009
1010                         public SendFileHandler Delegate {
1011                                 get { return d; }
1012                         }
1013
1014                         public IAsyncResult Original {
1015                                 get { return ares; }
1016                         }
1017                 }
1018
1019                 public IAsyncResult BeginSendFile (string fileName,
1020                                                    AsyncCallback callback,
1021                                                    object state)
1022                 {
1023                         if (disposed && closed)
1024                                 throw new ObjectDisposedException (GetType ().ToString ());
1025
1026                         if (!connected)
1027                                 throw new NotSupportedException ();
1028
1029                         if (!File.Exists (fileName))
1030                                 throw new FileNotFoundException ();
1031
1032                         return BeginSendFile (fileName, null, null, 0, callback, state);
1033                 }
1034
1035                 public IAsyncResult BeginSendFile (string fileName,
1036                                                    byte[] preBuffer,
1037                                                    byte[] postBuffer,
1038                                                    TransmitFileOptions flags,
1039                                                    AsyncCallback callback,
1040                                                    object state)
1041                 {
1042                         if (disposed && closed)
1043                                 throw new ObjectDisposedException (GetType ().ToString ());
1044
1045                         if (!connected)
1046                                 throw new NotSupportedException ();
1047
1048                         if (!File.Exists (fileName))
1049                                 throw new FileNotFoundException ();
1050
1051                         SendFileHandler d = new SendFileHandler (SendFile);
1052                         return new SendFileAsyncResult (d, d.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => {
1053                                 SendFileAsyncResult sfar = new SendFileAsyncResult (d, ar);
1054                                 callback (sfar);
1055                         }, state));
1056                 }
1057
1058                 public IAsyncResult BeginSendTo(byte[] buffer, int offset,
1059                                                 int size,
1060                                                 SocketFlags socket_flags,
1061                                                 EndPoint remote_end,
1062                                                 AsyncCallback callback,
1063                                                 object state) {
1064                         if (disposed && closed)
1065                                 throw new ObjectDisposedException (GetType ().ToString ());
1066
1067                         if (buffer == null)
1068                                 throw new ArgumentNullException ("buffer");
1069
1070                         CheckRange (buffer, offset, size);
1071
1072                         SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.SendTo);
1073                         req.Buffer = buffer;
1074                         req.Offset = offset;
1075                         req.Size = size;
1076                         req.SockFlags = socket_flags;
1077                         req.EndPoint = remote_end;
1078                         int count;
1079                         lock (writeQ) {
1080                                 writeQ.Enqueue (req.Worker);
1081                                 count = writeQ.Count;
1082                         }
1083                         if (count == 1)
1084                                 socket_pool_queue (Worker.Dispatcher, req);
1085                         return req;
1086                 }
1087
1088                 // Creates a new system socket, returning the handle
1089                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1090                 private extern static void Bind_internal(IntPtr sock,
1091                                                          SocketAddress sa,
1092                                                          out int error);
1093
1094                 public void Bind(EndPoint local_end) {
1095                         if (disposed && closed)
1096                                 throw new ObjectDisposedException (GetType ().ToString ());
1097
1098                         if (local_end == null)
1099                                 throw new ArgumentNullException("local_end");
1100                         
1101                         int error;
1102                         
1103                         Bind_internal(socket, local_end.Serialize(), out error);
1104                         if (error != 0)
1105                                 throw new SocketException (error);
1106                         if (error == 0)
1107                                 isbound = true;
1108                         
1109                         seed_endpoint = local_end;
1110                 }
1111
1112                 public void Connect (IPAddress address, int port)
1113                 {
1114                         Connect (new IPEndPoint (address, port));
1115                 }
1116                 
1117                 public void Connect (IPAddress[] addresses, int port)
1118                 {
1119                         if (disposed && closed)
1120                                 throw new ObjectDisposedException (GetType ().ToString ());
1121
1122                         if (addresses == null)
1123                                 throw new ArgumentNullException ("addresses");
1124
1125                         if (this.AddressFamily != AddressFamily.InterNetwork &&
1126                                 this.AddressFamily != AddressFamily.InterNetworkV6)
1127                                 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1128
1129                         if (islistening)
1130                                 throw new InvalidOperationException ();
1131
1132                         /* FIXME: do non-blocking sockets Poll here? */
1133                         int error = 0;
1134                         foreach (IPAddress address in addresses) {
1135                                 IPEndPoint iep = new IPEndPoint (address, port);
1136                                 SocketAddress serial = iep.Serialize ();
1137                                 
1138                                 Connect_internal (socket, serial, out error);
1139                                 if (error == 0) {
1140                                         connected = true;
1141                                         isbound = true;
1142                                         seed_endpoint = iep;
1143                                         return;
1144                                 } else if (error != (int)SocketError.InProgress &&
1145                                            error != (int)SocketError.WouldBlock) {
1146                                         continue;
1147                                 }
1148                                 
1149                                 if (!blocking) {
1150                                         Poll (-1, SelectMode.SelectWrite);
1151                                         error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1152                                         if (error == 0) {
1153                                                 connected = true;
1154                                                 isbound = true;
1155                                                 seed_endpoint = iep;
1156                                                 return;
1157                                         }
1158                                 }
1159                         }
1160                         if (error != 0)
1161                                 throw new SocketException (error);
1162                 }
1163
1164                 public void Connect (string host, int port)
1165                 {
1166                         IPAddress [] addresses = Dns.GetHostAddresses (host);
1167                         Connect (addresses, port);
1168                 }
1169
1170                 public bool DisconnectAsync (SocketAsyncEventArgs e)
1171                 {
1172                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1173                         if (disposed && closed)
1174                                 throw new ObjectDisposedException (GetType ().ToString ());
1175
1176                         e.curSocket = this;
1177                         e.Worker.Init (this, e, SocketOperation.Disconnect);
1178                         socket_pool_queue (Worker.Dispatcher, e.Worker.result);
1179                         return true;
1180                 }
1181
1182                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1183                 extern static void Disconnect_internal(IntPtr sock, bool reuse, out int error);
1184
1185                 /* According to the docs, the MS runtime will throw
1186                  * PlatformNotSupportedException if the platform is
1187                  * newer than w2k.  We should be able to cope...
1188                  */
1189                 public void Disconnect (bool reuseSocket)
1190                 {
1191                         if (disposed && closed)
1192                                 throw new ObjectDisposedException (GetType ().ToString ());
1193
1194                         int error = 0;
1195                         
1196                         Disconnect_internal (socket, reuseSocket, out error);
1197
1198                         if (error != 0) {
1199                                 if (error == 50) {
1200                                         /* ERROR_NOT_SUPPORTED */
1201                                         throw new PlatformNotSupportedException ();
1202                                 } else {
1203                                         throw new SocketException (error);
1204                                 }
1205                         }
1206
1207                         connected = false;
1208                         
1209                         if (reuseSocket) {
1210                                 /* Do managed housekeeping here... */
1211                         }
1212                 }
1213
1214 #if !MOBILE
1215                 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
1216                 public SocketInformation DuplicateAndClose (int targetProcessId)
1217                 {
1218                         var si = new SocketInformation ();
1219                         si.Options =
1220                                 (islistening ? SocketInformationOptions.Listening : 0) |
1221                                 (connected ? SocketInformationOptions.Connected : 0) |
1222                                 (blocking ? 0 : SocketInformationOptions.NonBlocking) |
1223                                 (useoverlappedIO ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
1224
1225                         si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, isbound ? 1 : 0, (long)socket);
1226                         socket = (IntPtr) (-1);
1227
1228                         return si;
1229                 }
1230 #endif
1231         
1232                 public Socket EndAccept (IAsyncResult result)
1233                 {
1234                         int bytes;
1235                         byte[] buffer;
1236                         
1237                         return(EndAccept (out buffer, out bytes, result));
1238                 }
1239
1240                 public Socket EndAccept (out byte[] buffer, IAsyncResult asyncResult)
1241                 {
1242                         int bytes;
1243                         return(EndAccept (out buffer, out bytes, asyncResult));
1244                 }
1245
1246                 public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
1247                 {
1248                         if (disposed && closed)
1249                                 throw new ObjectDisposedException (GetType ().ToString ());
1250
1251                         if (asyncResult == null)
1252                                 throw new ArgumentNullException ("asyncResult");
1253                         
1254                         SocketAsyncResult req = asyncResult as SocketAsyncResult;
1255                         if (req == null)
1256                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
1257
1258                         if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1259                                 throw InvalidAsyncOp ("EndAccept");
1260                         if (!asyncResult.IsCompleted)
1261                                 asyncResult.AsyncWaitHandle.WaitOne ();
1262
1263                         req.CheckIfThrowDelayedException ();
1264                         
1265                         buffer = req.Buffer;
1266                         bytesTransferred = req.Total;
1267                         
1268                         return(req.Socket);
1269                 }
1270
1271                 public void EndConnect (IAsyncResult result)
1272                 {
1273                         if (disposed && closed)
1274                                 throw new ObjectDisposedException (GetType ().ToString ());
1275
1276                         if (result == null)
1277                                 throw new ArgumentNullException ("result");
1278
1279                         SocketAsyncResult req = result as SocketAsyncResult;
1280                         if (req == null)
1281                                 throw new ArgumentException ("Invalid IAsyncResult", "result");
1282
1283                         if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1284                                 throw InvalidAsyncOp ("EndConnect");
1285                         if (!result.IsCompleted)
1286                                 result.AsyncWaitHandle.WaitOne();
1287
1288                         req.CheckIfThrowDelayedException();
1289                 }
1290
1291                 public void EndDisconnect (IAsyncResult asyncResult)
1292                 {
1293                         if (disposed && closed)
1294                                 throw new ObjectDisposedException (GetType ().ToString ());
1295
1296                         if (asyncResult == null)
1297                                 throw new ArgumentNullException ("asyncResult");
1298
1299                         SocketAsyncResult req = asyncResult as SocketAsyncResult;
1300                         if (req == null)
1301                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
1302
1303                         if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1304                                 throw InvalidAsyncOp ("EndDisconnect");
1305                         if (!asyncResult.IsCompleted)
1306                                 asyncResult.AsyncWaitHandle.WaitOne ();
1307
1308                         req.CheckIfThrowDelayedException ();
1309                 }
1310
1311                 [MonoTODO]
1312                 public int EndReceiveMessageFrom (IAsyncResult asyncResult,
1313                                                   ref SocketFlags socketFlags,
1314                                                   ref EndPoint endPoint,
1315                                                   out IPPacketInformation ipPacketInformation)
1316                 {
1317                         if (disposed && closed)
1318                                 throw new ObjectDisposedException (GetType ().ToString ());
1319
1320                         if (asyncResult == null)
1321                                 throw new ArgumentNullException ("asyncResult");
1322
1323                         if (endPoint == null)
1324                                 throw new ArgumentNullException ("endPoint");
1325
1326                         SocketAsyncResult req = asyncResult as SocketAsyncResult;
1327                         if (req == null)
1328                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
1329
1330                         if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1331                                 throw InvalidAsyncOp ("EndReceiveMessageFrom");
1332                         throw new NotImplementedException ();
1333                 }
1334
1335                 public void EndSendFile (IAsyncResult asyncResult)
1336                 {
1337                         if (disposed && closed)
1338                                 throw new ObjectDisposedException (GetType ().ToString ());
1339
1340                         if (asyncResult == null)
1341                                 throw new ArgumentNullException ("asyncResult");
1342
1343                         SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
1344                         if (ares == null)
1345                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
1346
1347                         ares.Delegate.EndInvoke (ares.Original);
1348                 }
1349
1350                 public int EndSendTo (IAsyncResult result)
1351                 {
1352                         if (disposed && closed)
1353                                 throw new ObjectDisposedException (GetType ().ToString ());
1354
1355                         if (result == null)
1356                                 throw new ArgumentNullException ("result");
1357
1358                         SocketAsyncResult req = result as SocketAsyncResult;
1359                         if (req == null)
1360                                 throw new ArgumentException ("Invalid IAsyncResult", "result");
1361
1362                         if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1363                                 throw InvalidAsyncOp ("EndSendTo");
1364                         if (!result.IsCompleted)
1365                                 result.AsyncWaitHandle.WaitOne();
1366
1367                         req.CheckIfThrowDelayedException();
1368                         return req.Total;
1369                 }
1370
1371                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1372                 private extern static void GetSocketOption_arr_internal(IntPtr socket,
1373                         SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val,
1374                         out int error);
1375
1376                 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
1377                 {
1378                         if (disposed && closed)
1379                                 throw new ObjectDisposedException (GetType ().ToString ());
1380
1381                         if (optionValue == null)
1382                                 throw new SocketException ((int) SocketError.Fault,
1383                                         "Error trying to dereference an invalid pointer");
1384
1385                         int error;
1386
1387                         GetSocketOption_arr_internal (socket, optionLevel, optionName, ref optionValue,
1388                                 out error);
1389                         if (error != 0)
1390                                 throw new SocketException (error);
1391                 }
1392
1393                 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int length)
1394                 {
1395                         if (disposed && closed)
1396                                 throw new ObjectDisposedException (GetType ().ToString ());
1397
1398                         byte[] byte_val=new byte[length];
1399                         int error;
1400
1401                         GetSocketOption_arr_internal (socket, optionLevel, optionName, ref byte_val,
1402                                 out error);
1403                         if (error != 0)
1404                                 throw new SocketException (error);
1405
1406                         return(byte_val);
1407                 }
1408
1409                 // See Socket.IOControl, WSAIoctl documentation in MSDN. The
1410                 // common options between UNIX and Winsock are FIONREAD,
1411                 // FIONBIO and SIOCATMARK. Anything else will depend on the
1412                 // system except SIO_KEEPALIVE_VALS which is properly handled
1413                 // on both windows and linux.
1414                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1415                 extern static int WSAIoctl (IntPtr sock, int ioctl_code, byte [] input,
1416                         byte [] output, out int error);
1417
1418                 public int IOControl (int ioctl_code, byte [] in_value, byte [] out_value)
1419                 {
1420                         if (disposed)
1421                                 throw new ObjectDisposedException (GetType ().ToString ());
1422
1423                         int error;
1424                         int result = WSAIoctl (socket, ioctl_code, in_value, out_value,
1425                                 out error);
1426
1427                         if (error != 0)
1428                                 throw new SocketException (error);
1429                         
1430                         if (result == -1)
1431                                 throw new InvalidOperationException ("Must use Blocking property instead.");
1432
1433                         return result;
1434                 }
1435
1436                 public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
1437                 {
1438                         return IOControl ((int) ioControlCode, optionInValue, optionOutValue);
1439                 }
1440
1441                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1442                 private extern static void Listen_internal(IntPtr sock, int backlog, out int error);
1443
1444                 public void Listen (int backlog)
1445                 {
1446                         if (disposed && closed)
1447                                 throw new ObjectDisposedException (GetType ().ToString ());
1448
1449                         if (!isbound)
1450                                 throw new SocketException ((int)SocketError.InvalidArgument);
1451
1452                         int error;
1453                         Listen_internal(socket, backlog, out error);
1454
1455                         if (error != 0)
1456                                 throw new SocketException (error);
1457
1458                         islistening = true;
1459                 }
1460
1461                 public bool Poll (int time_us, SelectMode mode)
1462                 {
1463                         if (disposed && closed)
1464                                 throw new ObjectDisposedException (GetType ().ToString ());
1465
1466                         if (mode != SelectMode.SelectRead &&
1467                             mode != SelectMode.SelectWrite &&
1468                             mode != SelectMode.SelectError)
1469                                 throw new NotSupportedException ("'mode' parameter is not valid.");
1470
1471                         int error;
1472                         bool result = Poll_internal (socket, mode, time_us, out error);
1473                         if (error != 0)
1474                                 throw new SocketException (error);
1475
1476                         if (mode == SelectMode.SelectWrite && result && !connected) {
1477                                 /* Update the connected state; for
1478                                  * non-blocking Connect()s this is
1479                                  * when we can find out that the
1480                                  * connect succeeded.
1481                                  */
1482                                 if ((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0) {
1483                                         connected = true;
1484                                 }
1485                         }
1486                         
1487                         return result;
1488                 }
1489
1490                 public int Receive (byte [] buffer)
1491                 {
1492                         return Receive (buffer, SocketFlags.None);
1493                 }
1494
1495                 public int Receive (byte [] buffer, SocketFlags flags)
1496                 {
1497                         if (disposed && closed)
1498                                 throw new ObjectDisposedException (GetType ().ToString ());
1499
1500                         if (buffer == null)
1501                                 throw new ArgumentNullException ("buffer");
1502
1503                         SocketError error;
1504
1505                         int ret = Receive_nochecks (buffer, 0, buffer.Length, flags, out error);
1506                         
1507                         if (error != SocketError.Success) {
1508                                 if (error == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set
1509                                         throw new SocketException ((int) error, timeout_exc_msg);
1510                                 throw new SocketException ((int) error);
1511                         }
1512
1513                         return ret;
1514                 }
1515
1516                 public int Receive (byte [] buffer, int size, SocketFlags flags)
1517                 {
1518                         if (disposed && closed)
1519                                 throw new ObjectDisposedException (GetType ().ToString ());
1520
1521                         if (buffer == null)
1522                                 throw new ArgumentNullException ("buffer");
1523
1524                         CheckRange (buffer, 0, size);
1525
1526                         SocketError error;
1527
1528                         int ret = Receive_nochecks (buffer, 0, size, flags, out error);
1529                         
1530                         if (error != SocketError.Success) {
1531                                 if (error == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set
1532                                         throw new SocketException ((int) error, timeout_exc_msg);
1533                                 throw new SocketException ((int) error);
1534                         }
1535
1536                         return ret;
1537                 }
1538
1539                 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags)
1540                 {
1541                         if (disposed && closed)
1542                                 throw new ObjectDisposedException (GetType ().ToString ());
1543
1544                         if (buffer == null)
1545                                 throw new ArgumentNullException ("buffer");
1546
1547                         CheckRange (buffer, offset, size);
1548                         
1549                         SocketError error;
1550
1551                         int ret = Receive_nochecks (buffer, offset, size, flags, out error);
1552                         
1553                         if (error != SocketError.Success) {
1554                                 if (error == SocketError.WouldBlock && blocking) // This might happen when ReceiveTimeout is set
1555                                         throw new SocketException ((int) error, timeout_exc_msg);
1556                                 throw new SocketException ((int) error);
1557                         }
1558
1559                         return ret;
1560                 }
1561
1562                 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
1563                 {
1564                         if (disposed && closed)
1565                                 throw new ObjectDisposedException (GetType ().ToString ());
1566
1567                         if (buffer == null)
1568                                 throw new ArgumentNullException ("buffer");
1569
1570                         CheckRange (buffer, offset, size);
1571                         
1572                         return Receive_nochecks (buffer, offset, size, flags, out error);
1573                 }
1574
1575                 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
1576                 {
1577                         if (disposed && closed)
1578                                 throw new ObjectDisposedException (GetType ().ToString ());
1579
1580                         // We do not support recv into multiple buffers yet
1581                         if (e.BufferList != null)
1582                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
1583                         if (e.RemoteEndPoint == null)
1584                                 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
1585
1586                         e.curSocket = this;
1587                         e.Worker.Init (this, e, SocketOperation.ReceiveFrom);
1588                         SocketAsyncResult res = e.Worker.result;
1589                         res.Buffer = e.Buffer;
1590                         res.Offset = e.Offset;
1591                         res.Size = e.Count;
1592                         res.EndPoint = e.RemoteEndPoint;
1593                         res.SockFlags = e.SocketFlags;
1594                         int count;
1595                         lock (readQ) {
1596                                 readQ.Enqueue (e.Worker);
1597                                 count = readQ.Count;
1598                         }
1599                         if (count == 1)
1600                                 socket_pool_queue (Worker.Dispatcher, res);
1601                         return true;
1602                 }
1603
1604                 public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
1605                 {
1606                         if (disposed && closed)
1607                                 throw new ObjectDisposedException (GetType ().ToString ());
1608
1609                         if (buffer == null)
1610                                 throw new ArgumentNullException ("buffer");
1611
1612                         if (remoteEP == null)
1613                                 throw new ArgumentNullException ("remoteEP");
1614
1615                         return ReceiveFrom_nochecks (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
1616                 }
1617
1618                 public int ReceiveFrom (byte [] buffer, SocketFlags flags, ref EndPoint remoteEP)
1619                 {
1620                         if (disposed && closed)
1621                                 throw new ObjectDisposedException (GetType ().ToString ());
1622
1623                         if (buffer == null)
1624                                 throw new ArgumentNullException ("buffer");
1625
1626                         if (remoteEP == null)
1627                                 throw new ArgumentNullException ("remoteEP");
1628
1629                         return ReceiveFrom_nochecks (buffer, 0, buffer.Length, flags, ref remoteEP);
1630                 }
1631
1632                 public int ReceiveFrom (byte [] buffer, int size, SocketFlags flags,
1633                                         ref EndPoint remoteEP)
1634                 {
1635                         if (disposed && closed)
1636                                 throw new ObjectDisposedException (GetType ().ToString ());
1637
1638                         if (buffer == null)
1639                                 throw new ArgumentNullException ("buffer");
1640
1641                         if (remoteEP == null)
1642                                 throw new ArgumentNullException ("remoteEP");
1643
1644                         if (size < 0 || size > buffer.Length)
1645                                 throw new ArgumentOutOfRangeException ("size");
1646
1647                         return ReceiveFrom_nochecks (buffer, 0, size, flags, ref remoteEP);
1648                 }
1649
1650                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1651                 private extern static int RecvFrom_internal(IntPtr sock,
1652                                                             byte[] buffer,
1653                                                             int offset,
1654                                                             int count,
1655                                                             SocketFlags flags,
1656                                                             ref SocketAddress sockaddr,
1657                                                             out int error);
1658
1659                 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags flags,
1660                                         ref EndPoint remoteEP)
1661                 {
1662                         if (disposed && closed)
1663                                 throw new ObjectDisposedException (GetType ().ToString ());
1664
1665                         if (buffer == null)
1666                                 throw new ArgumentNullException ("buffer");
1667
1668                         if (remoteEP == null)
1669                                 throw new ArgumentNullException ("remoteEP");
1670
1671                         CheckRange (buffer, offset, size);
1672
1673                         return ReceiveFrom_nochecks (buffer, offset, size, flags, ref remoteEP);
1674                 }
1675
1676                 internal int ReceiveFrom_nochecks (byte [] buf, int offset, int size, SocketFlags flags,
1677                                                    ref EndPoint remote_end)
1678                 {
1679                         int error;
1680                         return ReceiveFrom_nochecks_exc (buf, offset, size, flags, ref remote_end, true, out error);
1681                 }
1682
1683                 internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags,
1684                                                    ref EndPoint remote_end, bool throwOnError, out int error)
1685                 {
1686                         SocketAddress sockaddr = remote_end.Serialize();
1687                         int cnt = RecvFrom_internal (socket, buf, offset, size, flags, ref sockaddr, out error);
1688                         SocketError err = (SocketError) error;
1689                         if (err != 0) {
1690                                 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
1691                                         connected = false;
1692                                 else if (err == SocketError.WouldBlock && blocking) { // This might happen when ReceiveTimeout is set
1693                                         if (throwOnError)       
1694                                                 throw new SocketException ((int) SocketError.TimedOut, timeout_exc_msg);
1695                                         error = (int) SocketError.TimedOut;
1696                                         return 0;
1697                                 }
1698
1699                                 if (throwOnError)
1700                                         throw new SocketException (error);
1701                                 return 0;
1702                         }
1703
1704                         connected = true;
1705                         isbound = true;
1706
1707                         // If sockaddr is null then we're a connection
1708                         // oriented protocol and should ignore the
1709                         // remote_end parameter (see MSDN
1710                         // documentation for Socket.ReceiveFrom(...) )
1711                         
1712                         if ( sockaddr != null ) {
1713                                 // Stupidly, EndPoint.Create() is an
1714                                 // instance method
1715                                 remote_end = remote_end.Create (sockaddr);
1716                         }
1717                         
1718                         seed_endpoint = remote_end;
1719                         
1720                         return cnt;
1721                 }
1722
1723                 [MonoTODO ("Not implemented")]
1724                 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
1725                 {
1726                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1727                         if (disposed && closed)
1728                                 throw new ObjectDisposedException (GetType ().ToString ());
1729                         
1730                         throw new NotImplementedException ();
1731                 }
1732                 
1733                 [MonoTODO ("Not implemented")]
1734                 public int ReceiveMessageFrom (byte[] buffer, int offset,
1735                                                int size,
1736                                                ref SocketFlags socketFlags,
1737                                                ref EndPoint remoteEP,
1738                                                out IPPacketInformation ipPacketInformation)
1739                 {
1740                         if (disposed && closed)
1741                                 throw new ObjectDisposedException (GetType ().ToString ());
1742
1743                         if (buffer == null)
1744                                 throw new ArgumentNullException ("buffer");
1745
1746                         if (remoteEP == null)
1747                                 throw new ArgumentNullException ("remoteEP");
1748
1749                         CheckRange (buffer, offset, size);
1750
1751                         /* FIXME: figure out how we get hold of the
1752                          * IPPacketInformation
1753                          */
1754                         throw new NotImplementedException ();
1755                 }
1756
1757                 [MonoTODO ("Not implemented")]
1758                 public bool SendPacketsAsync (SocketAsyncEventArgs e)
1759                 {
1760                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1761                         
1762                         if (disposed && closed)
1763                                 throw new ObjectDisposedException (GetType ().ToString ());
1764                         
1765                         throw new NotImplementedException ();
1766                 }
1767
1768                 public int Send (byte [] buf)
1769                 {
1770                         if (disposed && closed)
1771                                 throw new ObjectDisposedException (GetType ().ToString ());
1772
1773                         if (buf == null)
1774                                 throw new ArgumentNullException ("buf");
1775
1776                         SocketError error;
1777
1778                         int ret = Send_nochecks (buf, 0, buf.Length, SocketFlags.None, out error);
1779
1780                         if (error != SocketError.Success)
1781                                 throw new SocketException ((int) error);
1782
1783                         return ret;
1784                 }
1785
1786                 public int Send (byte [] buf, SocketFlags flags)
1787                 {
1788                         if (disposed && closed)
1789                                 throw new ObjectDisposedException (GetType ().ToString ());
1790
1791                         if (buf == null)
1792                                 throw new ArgumentNullException ("buf");
1793
1794                         SocketError error;
1795
1796                         int ret = Send_nochecks (buf, 0, buf.Length, flags, out error);
1797
1798                         if (error != SocketError.Success)
1799                                 throw new SocketException ((int) error);
1800
1801                         return ret;
1802                 }
1803
1804                 public int Send (byte [] buf, int size, SocketFlags flags)
1805                 {
1806                         if (disposed && closed)
1807                                 throw new ObjectDisposedException (GetType ().ToString ());
1808
1809                         if (buf == null)
1810                                 throw new ArgumentNullException ("buf");
1811
1812                         CheckRange (buf, 0, size);
1813
1814                         SocketError error;
1815
1816                         int ret = Send_nochecks (buf, 0, size, flags, out error);
1817
1818                         if (error != SocketError.Success)
1819                                 throw new SocketException ((int) error);
1820
1821                         return ret;
1822                 }
1823
1824                 public int Send (byte [] buf, int offset, int size, SocketFlags flags)
1825                 {
1826                         if (disposed && closed)
1827                                 throw new ObjectDisposedException (GetType ().ToString ());
1828
1829                         if (buf == null)
1830                                 throw new ArgumentNullException ("buffer");
1831
1832                         CheckRange (buf, offset, size);
1833
1834                         SocketError error;
1835
1836                         int ret = Send_nochecks (buf, offset, size, flags, out error);
1837
1838                         if (error != SocketError.Success)
1839                                 throw new SocketException ((int) error);
1840
1841                         return ret;
1842                 }
1843
1844                 public int Send (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
1845                 {
1846                         if (disposed && closed)
1847                                 throw new ObjectDisposedException (GetType ().ToString ());
1848
1849                         if (buf == null)
1850                                 throw new ArgumentNullException ("buffer");
1851
1852                         CheckRange (buf, offset, size);
1853
1854                         return Send_nochecks (buf, offset, size, flags, out error);
1855                 }
1856
1857                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1858                 private extern static bool SendFile (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
1859
1860                 public void SendFile (string fileName)
1861                 {
1862                         if (disposed && closed)
1863                                 throw new ObjectDisposedException (GetType ().ToString ());
1864
1865                         if (!connected)
1866                                 throw new NotSupportedException ();
1867
1868                         if (!blocking)
1869                                 throw new InvalidOperationException ();
1870
1871                         SendFile (fileName, null, null, 0);
1872                 }
1873
1874                 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
1875                 {
1876                         if (disposed && closed)
1877                                 throw new ObjectDisposedException (GetType ().ToString ());
1878
1879                         if (!connected)
1880                                 throw new NotSupportedException ();
1881
1882                         if (!blocking)
1883                                 throw new InvalidOperationException ();
1884
1885                         if (!SendFile (socket, fileName, preBuffer, postBuffer, flags)) {
1886                                 SocketException exc = new SocketException ();
1887                                 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
1888                                         throw new FileNotFoundException ();
1889                                 throw exc;
1890                         }
1891                 }
1892
1893                 public bool SendToAsync (SocketAsyncEventArgs e)
1894                 {
1895                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1896                         
1897                         if (disposed && closed)
1898                                 throw new ObjectDisposedException (GetType ().ToString ());
1899                         if (e.BufferList != null)
1900                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
1901                         if (e.RemoteEndPoint == null)
1902                                 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
1903
1904                         e.curSocket = this;
1905                         e.Worker.Init (this, e, SocketOperation.SendTo);
1906                         SocketAsyncResult res = e.Worker.result;
1907                         res.Buffer = e.Buffer;
1908                         res.Offset = e.Offset;
1909                         res.Size = e.Count;
1910                         res.SockFlags = e.SocketFlags;
1911                         res.EndPoint = e.RemoteEndPoint;
1912                         int count;
1913                         lock (writeQ) {
1914                                 writeQ.Enqueue (e.Worker);
1915                                 count = writeQ.Count;
1916                         }
1917                         if (count == 1)
1918                                 socket_pool_queue (Worker.Dispatcher, res);
1919                         return true;
1920                 }
1921                 
1922                 public int SendTo (byte [] buffer, EndPoint remote_end)
1923                 {
1924                         if (disposed && closed)
1925                                 throw new ObjectDisposedException (GetType ().ToString ());
1926
1927                         if (buffer == null)
1928                                 throw new ArgumentNullException ("buffer");
1929
1930                         if (remote_end == null)
1931                                 throw new ArgumentNullException ("remote_end");
1932
1933                         return SendTo_nochecks (buffer, 0, buffer.Length, SocketFlags.None, remote_end);
1934                 }
1935
1936                 public int SendTo (byte [] buffer, SocketFlags flags, EndPoint remote_end)
1937                 {
1938                         if (disposed && closed)
1939                                 throw new ObjectDisposedException (GetType ().ToString ());
1940
1941                         if (buffer == null)
1942                                 throw new ArgumentNullException ("buffer");
1943
1944                         if (remote_end == null)
1945                                 throw new ArgumentNullException ("remote_end");
1946                                 
1947                         return SendTo_nochecks (buffer, 0, buffer.Length, flags, remote_end);
1948                 }
1949
1950                 public int SendTo (byte [] buffer, int size, SocketFlags flags, EndPoint remote_end)
1951                 {
1952                         if (disposed && closed)
1953                                 throw new ObjectDisposedException (GetType ().ToString ());
1954
1955                         if (buffer == null)
1956                                 throw new ArgumentNullException ("buffer");
1957
1958                         if (remote_end == null)
1959                                 throw new ArgumentNullException ("remote_end");
1960
1961                         CheckRange (buffer, 0, size);
1962
1963                         return SendTo_nochecks (buffer, 0, size, flags, remote_end);
1964                 }
1965
1966                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1967                 private extern static int SendTo_internal(IntPtr sock,
1968                                                           byte[] buffer,
1969                                                           int offset,
1970                                                           int count,
1971                                                           SocketFlags flags,
1972                                                           SocketAddress sa,
1973                                                           out int error);
1974
1975                 public int SendTo (byte [] buffer, int offset, int size, SocketFlags flags,
1976                                    EndPoint remote_end)
1977                 {
1978                         if (disposed && closed)
1979                                 throw new ObjectDisposedException (GetType ().ToString ());
1980
1981                         if (buffer == null)
1982                                 throw new ArgumentNullException ("buffer");
1983
1984                         if (remote_end == null)
1985                                 throw new ArgumentNullException("remote_end");
1986
1987                         CheckRange (buffer, offset, size);
1988
1989                         return SendTo_nochecks (buffer, offset, size, flags, remote_end);
1990                 }
1991
1992                 internal int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags,
1993                                               EndPoint remote_end)
1994                 {
1995                         SocketAddress sockaddr = remote_end.Serialize ();
1996
1997                         int ret, error;
1998
1999                         ret = SendTo_internal (socket, buffer, offset, size, flags, sockaddr, out error);
2000
2001                         SocketError err = (SocketError) error;
2002                         if (err != 0) {
2003                                 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2004                                         connected = false;
2005
2006                                 throw new SocketException (error);
2007                         }
2008
2009                         connected = true;
2010                         isbound = true;
2011                         seed_endpoint = remote_end;
2012                         
2013                         return ret;
2014                 }
2015
2016                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2017                 {
2018                         if (disposed && closed)
2019                                 throw new ObjectDisposedException (GetType ().ToString ());
2020
2021                         // I'd throw an ArgumentNullException, but this is what MS does.
2022                         if (optionValue == null)
2023                                 throw new SocketException ((int) SocketError.Fault,
2024                                         "Error trying to dereference an invalid pointer");
2025                         
2026                         int error;
2027
2028                         SetSocketOption_internal (socket, optionLevel, optionName, null,
2029                                                  optionValue, 0, out error);
2030
2031                         if (error != 0) {
2032                                 if (error == (int) SocketError.InvalidArgument)
2033                                         throw new ArgumentException ();
2034                                 throw new SocketException (error);
2035                         }
2036                 }
2037
2038                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
2039                 {
2040                         if (disposed && closed)
2041                                 throw new ObjectDisposedException (GetType ().ToString ());
2042
2043                         // NOTE: if a null is passed, the byte[] overload is used instead...
2044                         if (optionValue == null)
2045                                 throw new ArgumentNullException("optionValue");
2046                         
2047                         int error;
2048
2049                         if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
2050                                 LingerOption linger = optionValue as LingerOption;
2051                                 if (linger == null)
2052                                         throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
2053                                 SetSocketOption_internal (socket, optionLevel, optionName, linger, null, 0, out error);
2054                         } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2055                                 MulticastOption multicast = optionValue as MulticastOption;
2056                                 if (multicast == null)
2057                                         throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
2058                                 SetSocketOption_internal (socket, optionLevel, optionName, multicast, null, 0, out error);
2059                         } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2060                                 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
2061                                 if (multicast == null)
2062                                         throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
2063                                 SetSocketOption_internal (socket, optionLevel, optionName, multicast, null, 0, out error);
2064                         } else {
2065                                 throw new ArgumentException ("Invalid value specified.", "optionValue");
2066                         }
2067
2068                         if (error != 0) {
2069                                 if (error == (int) SocketError.InvalidArgument)
2070                                         throw new ArgumentException ();
2071                                 throw new SocketException (error);
2072                         }
2073                 }
2074
2075                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
2076                 {
2077                         if (disposed && closed)
2078                                 throw new ObjectDisposedException (GetType ().ToString ());
2079
2080                         int error;
2081                         int int_val = (optionValue) ? 1 : 0;
2082                         SetSocketOption_internal (socket, optionLevel, optionName, null, null, int_val, out error);
2083                         if (error != 0) {
2084                                 if (error == (int) SocketError.InvalidArgument)
2085                                         throw new ArgumentException ();
2086                                 throw new SocketException (error);
2087                         }
2088                 }
2089         }
2090 }
2091