Revert "[w32handle] Remove use of w32handle for File, Console, Pipe and Socket (...
[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 //      Ludovic Henry (ludovic@xamarin.com)
10 //
11 // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
12 //    http://www.myelin.co.nz
13 // (c) 2004-2011 Novell, Inc. (http://www.novell.com)
14 //
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35
36 using System;
37 using System.Net;
38 using System.Collections;
39 using System.Collections.Generic;
40 using System.Runtime.CompilerServices;
41 using System.Runtime.InteropServices;
42 using System.Threading;
43 using System.Reflection;
44 using System.IO;
45 using System.Net.Configuration;
46 using System.Text;
47 using System.Timers;
48 using System.Net.NetworkInformation;
49
50 namespace System.Net.Sockets 
51 {
52         public partial class Socket : IDisposable
53         {
54                 const int SOCKET_CLOSED_CODE = 10004;
55                 const string TIMEOUT_EXCEPTION_MSG = "A connection attempt failed because the connected party did not properly respond" +
56                         "after a period of time, or established connection failed because connected host has failed to respond";
57
58                 /* true if we called Close_internal */
59                 bool is_closed;
60
61                 bool is_listening;
62                 bool useOverlappedIO;
63
64                 int linger_timeout;
65
66                 AddressFamily addressFamily;
67                 SocketType socketType;
68                 ProtocolType protocolType;
69
70                 /* the field "m_Handle" is looked up by name by the runtime */
71                 internal SafeSocketHandle m_Handle;
72
73                 /*
74                  * This EndPoint is used when creating new endpoints. Because
75                  * there are many types of EndPoints possible,
76                  * seed_endpoint.Create(addr) is used for creating new ones.
77                  * As such, this value is set on Bind, SentTo, ReceiveFrom,
78                  * Connect, etc.
79                  */
80                 internal EndPoint seed_endpoint = null;
81
82                 internal SemaphoreSlim ReadSem = new SemaphoreSlim (1, 1);
83                 internal SemaphoreSlim WriteSem = new SemaphoreSlim (1, 1);
84
85                 internal bool is_blocking = true;
86                 internal bool is_bound;
87
88                 /* When true, the socket was connected at the time of the last IO operation */
89                 internal bool is_connected;
90
91                 int m_IntCleanedUp;
92                 internal bool connect_in_progress;
93
94 #region Constructors
95
96
97                 public Socket (SocketInformation socketInformation)
98                 {
99                         this.is_listening      = (socketInformation.Options & SocketInformationOptions.Listening) != 0;
100                         this.is_connected      = (socketInformation.Options & SocketInformationOptions.Connected) != 0;
101                         this.is_blocking       = (socketInformation.Options & SocketInformationOptions.NonBlocking) == 0;
102                         this.useOverlappedIO = (socketInformation.Options & SocketInformationOptions.UseOnlyOverlappedIO) != 0;
103
104                         var result = Mono.DataConverter.Unpack ("iiiil", socketInformation.ProtocolInformation, 0);
105
106                         this.addressFamily = (AddressFamily) (int) result [0];
107                         this.socketType = (SocketType) (int) result [1];
108                         this.protocolType = (ProtocolType) (int) result [2];
109                         this.is_bound = (ProtocolType) (int) result [3] != 0;
110                         this.m_Handle = new SafeSocketHandle ((IntPtr) (long) result [4], true);
111
112                         InitializeSockets ();
113
114                         SocketDefaults ();
115                 }
116
117                 /* private constructor used by Accept, which already has a socket handle to use */
118                 internal Socket(AddressFamily family, SocketType type, ProtocolType proto, SafeSocketHandle safe_handle)
119                 {
120                         this.addressFamily = family;
121                         this.socketType = type;
122                         this.protocolType = proto;
123                         
124                         this.m_Handle = safe_handle;
125                         this.is_connected = true;
126
127                         InitializeSockets ();   
128                 }
129
130                 void SocketDefaults ()
131                 {
132                         try {
133                                 /* Need to test IPv6 further */
134                                 if (addressFamily == AddressFamily.InterNetwork
135                                         // || addressFamily == AddressFamily.InterNetworkV6
136                                 ) {
137                                         /* This is the default, but it probably has nasty side
138                                          * effects on Linux, as the socket option is kludged by
139                                          * turning on or off PMTU discovery... */
140                                         this.DontFragment = false;
141                                         if (protocolType == ProtocolType.Tcp)
142                                                 this.NoDelay = false;
143                                 } else if (addressFamily == AddressFamily.InterNetworkV6) {
144                                         this.DualMode = true;
145                                 }
146
147                                 /* Microsoft sets these to 8192, but we are going to keep them
148                                  * both to the OS defaults as these have a big performance impact.
149                                  * on WebClient performance. */
150                                 // this.ReceiveBufferSize = 8192;
151                                 // this.SendBufferSize = 8192;
152                         } catch (SocketException) {
153                         }
154                 }
155
156                 /* Creates a new system socket, returning the handle */
157                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
158                 extern IntPtr Socket_internal (AddressFamily family, SocketType type, ProtocolType proto, out int error);
159
160 #endregion
161
162 #region Properties
163
164                 public int Available {
165                         get {
166                                 ThrowIfDisposedAndClosed ();
167
168                                 int ret, error;
169                                 ret = Available_internal (m_Handle, out error);
170
171                                 if (error != 0)
172                                         throw new SocketException (error);
173
174                                 return ret;
175                         }
176                 }
177
178                 static int Available_internal (SafeSocketHandle safeHandle, out int error)
179                 {
180                         bool release = false;
181                         try {
182                                 safeHandle.DangerousAddRef (ref release);
183                                 return Available_internal (safeHandle.DangerousGetHandle (), out error);
184                         } finally {
185                                 if (release)
186                                         safeHandle.DangerousRelease ();
187                         }
188                 }
189
190                 /* Returns the amount of data waiting to be read on socket */
191                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
192                 extern static int Available_internal (IntPtr socket, out int error);
193
194                 // FIXME: import from referencesource
195                 public bool EnableBroadcast {
196                         get {
197                                 ThrowIfDisposedAndClosed ();
198
199                                 if (protocolType != ProtocolType.Udp)
200                                         throw new SocketException ((int) SocketError.ProtocolOption);
201
202                                 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0;
203                         }
204                         set {
205                                 ThrowIfDisposedAndClosed ();
206
207                                 if (protocolType != ProtocolType.Udp)
208                                         throw new SocketException ((int) SocketError.ProtocolOption);
209
210                                 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
211                         }
212                 }
213
214                 public bool IsBound {
215                         get {
216                                 return is_bound;
217                         }
218                 }
219
220                 // FIXME: import from referencesource
221                 public bool MulticastLoopback {
222                         get {
223                                 ThrowIfDisposedAndClosed ();
224
225                                 /* Even though this option can be set for TCP sockets on Linux, throw
226                                  * this exception anyway to be compatible (the MSDN docs say
227                                  * "Setting this property on a Transmission Control Protocol (TCP)
228                                  * socket will have no effect." but the MS runtime throws the
229                                  * exception...) */
230                                 if (protocolType == ProtocolType.Tcp)
231                                         throw new SocketException ((int)SocketError.ProtocolOption);
232
233                                 switch (addressFamily) {
234                                 case AddressFamily.InterNetwork:
235                                         return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
236                                 case AddressFamily.InterNetworkV6:
237                                         return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
238                                 default:
239                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
240                                 }
241                         }
242                         set {
243                                 ThrowIfDisposedAndClosed ();
244
245                                 /* Even though this option can be set for TCP sockets on Linux, throw
246                                  * this exception anyway to be compatible (the MSDN docs say
247                                  * "Setting this property on a Transmission Control Protocol (TCP)
248                                  * socket will have no effect." but the MS runtime throws the
249                                  * exception...) */
250                                 if (protocolType == ProtocolType.Tcp)
251                                         throw new SocketException ((int)SocketError.ProtocolOption);
252
253                                 switch (addressFamily) {
254                                 case AddressFamily.InterNetwork:
255                                         SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
256                                         break;
257                                 case AddressFamily.InterNetworkV6:
258                                         SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
259                                         break;
260                                 default:
261                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
262                                 }
263                         }
264                 }
265
266                 // Wish:  support non-IP endpoints.
267                 public EndPoint LocalEndPoint {
268                         get {
269                                 ThrowIfDisposedAndClosed ();
270
271                                 /* If the seed EndPoint is null, Connect, Bind, etc has not yet
272                                  * been called. MS returns null in this case. */
273                                 if (seed_endpoint == null)
274                                         return null;
275
276                                 int error;
277                                 SocketAddress sa = LocalEndPoint_internal (m_Handle, (int) addressFamily, out error);
278
279                                 if (error != 0)
280                                         throw new SocketException (error);
281
282                                 return seed_endpoint.Create (sa);
283                         }
284                 }
285
286                 static SocketAddress LocalEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
287                 {
288                         bool release = false;
289                         try {
290                                 safeHandle.DangerousAddRef (ref release);
291                                 return LocalEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
292                         } finally {
293                                 if (release)
294                                         safeHandle.DangerousRelease ();
295                         }
296                 }
297
298                 /* Returns the local endpoint details in addr and port */
299                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
300                 extern static SocketAddress LocalEndPoint_internal (IntPtr socket, int family, out int error);
301
302                 public bool Blocking {
303                         get { return is_blocking; }
304                         set {
305                                 ThrowIfDisposedAndClosed ();
306
307                                 int error;
308                                 Blocking_internal (m_Handle, value, out error);
309
310                                 if (error != 0)
311                                         throw new SocketException (error);
312
313                                 is_blocking = value;
314                         }
315                 }
316
317                 static void Blocking_internal (SafeSocketHandle safeHandle, bool block, out int error)
318                 {
319                         bool release = false;
320                         try {
321                                 safeHandle.DangerousAddRef (ref release);
322                                 Blocking_internal (safeHandle.DangerousGetHandle (), block, out error);
323                         } finally {
324                                 if (release)
325                                         safeHandle.DangerousRelease ();
326                         }
327                 }
328
329                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
330                 internal extern static void Blocking_internal(IntPtr socket, bool block, out int error);
331
332                 public bool Connected {
333                         get { return is_connected; }
334                         internal set { is_connected = value; }
335                 }
336
337                 // FIXME: import from referencesource
338                 public bool NoDelay {
339                         get {
340                                 ThrowIfDisposedAndClosed ();
341                                 ThrowIfUdp ();
342
343                                 return ((int) GetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay)) != 0;
344                         }
345
346                         set {
347                                 ThrowIfDisposedAndClosed ();
348                                 ThrowIfUdp ();
349                                 SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
350                         }
351                 }
352
353                 public EndPoint RemoteEndPoint {
354                         get {
355                                 ThrowIfDisposedAndClosed ();
356
357                                 /* If the seed EndPoint is null, Connect, Bind, etc has
358                                  * not yet been called. MS returns null in this case. */
359                                 if (!is_connected || seed_endpoint == null)
360                                         return null;
361
362                                 int error;
363                                 SocketAddress sa = RemoteEndPoint_internal (m_Handle, (int) addressFamily, out error);
364
365                                 if (error != 0)
366                                         throw new SocketException (error);
367
368                                 return seed_endpoint.Create (sa);
369                         }
370                 }
371
372                 static SocketAddress RemoteEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
373                 {
374                         bool release = false;
375                         try {
376                                 safeHandle.DangerousAddRef (ref release);
377                                 return RemoteEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
378                         } finally {
379                                 if (release)
380                                         safeHandle.DangerousRelease ();
381                         }
382                 }
383
384                 /* Returns the remote endpoint details in addr and port */
385                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
386                 extern static SocketAddress RemoteEndPoint_internal (IntPtr socket, int family, out int error);
387
388 #endregion
389
390 #region Select
391
392                 public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
393                 {
394                         var list = new List<Socket> ();
395                         AddSockets (list, checkRead, "checkRead");
396                         AddSockets (list, checkWrite, "checkWrite");
397                         AddSockets (list, checkError, "checkError");
398
399                         if (list.Count == 3)
400                                 throw new ArgumentNullException ("checkRead, checkWrite, checkError", "All the lists are null or empty.");
401
402                         /* The 'sockets' array contains:
403                          *  - READ socket 0-n, null,
404                          *  - WRITE socket 0-n, null,
405                          *  - ERROR socket 0-n, null */
406                         Socket [] sockets = list.ToArray ();
407
408                         int error;
409                         Select_internal (ref sockets, microSeconds, out error);
410
411                         if (error != 0)
412                                 throw new SocketException (error);
413
414                         if (sockets == null) {
415                                 if (checkRead != null)
416                                         checkRead.Clear ();
417                                 if (checkWrite != null)
418                                         checkWrite.Clear ();
419                                 if (checkError != null)
420                                         checkError.Clear ();
421                                 return;
422                         }
423
424                         int mode = 0;
425                         int count = sockets.Length;
426                         IList currentList = checkRead;
427                         int currentIdx = 0;
428                         for (int i = 0; i < count; i++) {
429                                 Socket sock = sockets [i];
430                                 if (sock == null) { // separator
431                                         if (currentList != null) {
432                                                 // Remove non-signaled sockets after the current one
433                                                 int to_remove = currentList.Count - currentIdx;
434                                                 for (int k = 0; k < to_remove; k++)
435                                                         currentList.RemoveAt (currentIdx);
436                                         }
437                                         currentList = (mode == 0) ? checkWrite : checkError;
438                                         currentIdx = 0;
439                                         mode++;
440                                         continue;
441                                 }
442
443                                 if (mode == 1 && currentList == checkWrite && !sock.is_connected) {
444                                         if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
445                                                 sock.is_connected = true;
446                                 }
447
448                                 /* Remove non-signaled sockets before the current one */
449                                 while (((Socket) currentList [currentIdx]) != sock)
450                                         currentList.RemoveAt (currentIdx);
451
452                                 currentIdx++;
453                         }
454                 }
455
456                 static void AddSockets (List<Socket> sockets, IList list, string name)
457                 {
458                         if (list != null) {
459                                 foreach (Socket sock in list) {
460                                         if (sock == null) // MS throws a NullRef
461                                                 throw new ArgumentNullException (name, "Contains a null element");
462                                         sockets.Add (sock);
463                                 }
464                         }
465
466                         sockets.Add (null);
467                 }
468
469                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
470                 extern static void Select_internal (ref Socket [] sockets, int microSeconds, out int error);
471
472 #endregion
473
474 #region Poll
475
476                 public bool Poll (int microSeconds, SelectMode mode)
477                 {
478                         ThrowIfDisposedAndClosed ();
479
480                         if (mode != SelectMode.SelectRead && mode != SelectMode.SelectWrite && mode != SelectMode.SelectError)
481                                 throw new NotSupportedException ("'mode' parameter is not valid.");
482
483                         int error;
484                         bool result = Poll_internal (m_Handle, mode, microSeconds, out error);
485
486                         if (error != 0)
487                                 throw new SocketException (error);
488
489                         if (mode == SelectMode.SelectWrite && result && !is_connected) {
490                                 /* Update the is_connected state; for non-blocking Connect()
491                                  * this is when we can find out that the connect succeeded. */
492                                 if ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
493                                         is_connected = true;
494                         }
495
496                         return result;
497                 }
498
499                 static bool Poll_internal (SafeSocketHandle safeHandle, SelectMode mode, int timeout, out int error)
500                 {
501                         bool release = false;
502                         try {
503                                 safeHandle.DangerousAddRef (ref release);
504                                 return Poll_internal (safeHandle.DangerousGetHandle (), mode, timeout, out error);
505                         } finally {
506                                 if (release)
507                                         safeHandle.DangerousRelease ();
508                         }
509                 }
510
511                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
512                 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
513
514 #endregion
515
516 #region Accept
517
518                 public Socket Accept()
519                 {
520                         ThrowIfDisposedAndClosed ();
521
522                         int error = 0;
523                         SafeSocketHandle safe_handle = Accept_internal (this.m_Handle, out error, is_blocking);
524
525                         if (error != 0) {
526                                 if (is_closed)
527                                         error = SOCKET_CLOSED_CODE;
528                                 throw new SocketException(error);
529                         }
530
531                         Socket accepted = new Socket (this.AddressFamily, this.SocketType, this.ProtocolType, safe_handle) {
532                                 seed_endpoint = this.seed_endpoint,
533                                 Blocking = this.Blocking,
534                         };
535
536                         return accepted;
537                 }
538
539                 internal void Accept (Socket acceptSocket)
540                 {
541                         ThrowIfDisposedAndClosed ();
542
543                         int error = 0;
544                         SafeSocketHandle safe_handle = Accept_internal (this.m_Handle, out error, is_blocking);
545
546                         if (error != 0) {
547                                 if (is_closed)
548                                         error = SOCKET_CLOSED_CODE;
549                                 throw new SocketException (error);
550                         }
551
552                         acceptSocket.addressFamily = this.AddressFamily;
553                         acceptSocket.socketType = this.SocketType;
554                         acceptSocket.protocolType = this.ProtocolType;
555                         acceptSocket.m_Handle = safe_handle;
556                         acceptSocket.is_connected = true;
557                         acceptSocket.seed_endpoint = this.seed_endpoint;
558                         acceptSocket.Blocking = this.Blocking;
559
560                         // FIXME: figure out what if anything else needs to be reset
561                 }
562
563                 public bool AcceptAsync (SocketAsyncEventArgs e)
564                 {
565                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
566
567                         ThrowIfDisposedAndClosed ();
568
569                         if (!is_bound)
570                                 throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
571                         if (!is_listening)
572                                 throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
573                         if (e.BufferList != null)
574                                 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
575                         if (e.Count < 0)
576                                 throw new ArgumentOutOfRangeException ("e.Count");
577
578                         Socket acceptSocket = e.AcceptSocket;
579                         if (acceptSocket != null) {
580                                 if (acceptSocket.is_bound || acceptSocket.is_connected)
581                                         throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
582                         }
583
584                         InitSocketAsyncEventArgs (e, AcceptAsyncCallback, e, SocketOperation.Accept);
585
586                         QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, e.socket_async_result));
587
588                         return true;
589                 }
590
591                 static AsyncCallback AcceptAsyncCallback = new AsyncCallback (ares => {
592                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
593
594                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
595                                 throw new InvalidOperationException ("No operation in progress");
596
597                         try {
598                                 e.AcceptSocket = e.current_socket.EndAccept (ares);
599                         } catch (SocketException ex) {
600                                 e.SocketError = ex.SocketErrorCode;
601                         } catch (ObjectDisposedException) {
602                                 e.SocketError = SocketError.OperationAborted;
603                         } finally {
604                                 if (e.AcceptSocket == null)
605                                         e.AcceptSocket = new Socket (e.current_socket.AddressFamily, e.current_socket.SocketType, e.current_socket.ProtocolType, null);
606                                 e.Complete ();
607                         }
608                 });
609
610                 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
611                 {
612                         ThrowIfDisposedAndClosed ();
613
614                         if (!is_bound || !is_listening)
615                                 throw new InvalidOperationException ();
616
617                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Accept);
618
619                         QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, sockares));
620
621                         return sockares;
622                 }
623
624                 static IOAsyncCallback BeginAcceptCallback = new IOAsyncCallback (ares => {
625                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
626                         Socket acc_socket = null;
627                         try {
628                                 if (sockares.AcceptSocket == null) {
629                                         acc_socket = sockares.socket.Accept ();
630                                 } else {
631                                         acc_socket = sockares.AcceptSocket;
632                                         sockares.socket.Accept (acc_socket);
633                                 }
634
635                         } catch (Exception e) {
636                                 sockares.Complete (e);
637                                 return;
638                         }
639                         sockares.Complete (acc_socket);
640                 });
641
642                 public IAsyncResult BeginAccept (Socket acceptSocket, int receiveSize, AsyncCallback callback, object state)
643                 {
644                         ThrowIfDisposedAndClosed ();
645
646                         if (receiveSize < 0)
647                                 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
648
649                         if (acceptSocket != null) {
650                                 ThrowIfDisposedAndClosed (acceptSocket);
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 sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
665                                 Buffer = new byte [receiveSize],
666                                 Offset = 0,
667                                 Size = receiveSize,
668                                 SockFlags = SocketFlags.None,
669                                 AcceptSocket = acceptSocket,
670                         };
671
672                         QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
673
674                         return sockares;
675                 }
676
677                 static IOAsyncCallback BeginAcceptReceiveCallback = new IOAsyncCallback (ares => {
678                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
679                         Socket acc_socket = null;
680
681                         try {
682                                 if (sockares.AcceptSocket == null) {
683                                         acc_socket = sockares.socket.Accept ();
684                                 } else {
685                                         acc_socket = sockares.AcceptSocket;
686                                         sockares.socket.Accept (acc_socket);
687                                 }
688                         } catch (Exception e) {
689                                 sockares.Complete (e);
690                                 return;
691                         }
692
693                         /* It seems the MS runtime special-cases 0-length requested receive data.  See bug 464201. */
694                         int total = 0;
695                         if (sockares.Size > 0) {
696                                 try {
697                                         SocketError error;
698                                         total = acc_socket.Receive (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out error);
699                                         if (error != 0) {
700                                                 sockares.Complete (new SocketException ((int) error));
701                                                 return;
702                                         }
703                                 } catch (Exception e) {
704                                         sockares.Complete (e);
705                                         return;
706                                 }
707                         }
708
709                         sockares.Complete (acc_socket, total);
710                 });
711
712                 public Socket EndAccept (IAsyncResult asyncResult)
713                 {
714                         int bytes;
715                         byte[] buffer;
716                         return EndAccept (out buffer, out bytes, asyncResult);
717                 }
718
719                 public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
720                 {
721                         ThrowIfDisposedAndClosed ();
722
723                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndAccept", "asyncResult");
724
725                         if (!sockares.IsCompleted)
726                                 sockares.AsyncWaitHandle.WaitOne ();
727
728                         sockares.CheckIfThrowDelayedException ();
729
730                         buffer = sockares.Buffer;
731                         bytesTransferred = sockares.Total;
732
733                         return sockares.AcceptedSocket;
734                 }
735
736                 static SafeSocketHandle Accept_internal (SafeSocketHandle safeHandle, out int error, bool blocking)
737                 {
738                         try {
739                                 safeHandle.RegisterForBlockingSyscall ();
740                                 var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
741                                 return new SafeSocketHandle (ret, true);
742                         } finally {
743                                 safeHandle.UnRegisterForBlockingSyscall ();
744                         }
745                 }
746
747                 /* Creates a new system socket, returning the handle */
748                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
749                 extern static IntPtr Accept_internal (IntPtr sock, out int error, bool blocking);
750
751 #endregion
752
753 #region Bind
754
755                 public void Bind (EndPoint localEP)
756                 {
757 #if FEATURE_NO_BSD_SOCKETS
758                         throw new PlatformNotSupportedException ("System.Net.Sockets.Socket:Bind is not supported on this platform.");
759 #else
760                         ThrowIfDisposedAndClosed ();
761
762                         if (localEP == null)
763                                 throw new ArgumentNullException("localEP");
764                                 
765                         var ipEndPoint = localEP as IPEndPoint;
766                         if (ipEndPoint != null) {
767                                 localEP = RemapIPEndPoint (ipEndPoint); 
768                         }
769                         
770                         int error;
771                         Bind_internal (m_Handle, localEP.Serialize(), out error);
772
773                         if (error != 0)
774                                 throw new SocketException (error);
775                         if (error == 0)
776                                 is_bound = true;
777
778                         seed_endpoint = localEP;
779 #endif // FEATURE_NO_BSD_SOCKETS
780                 }
781
782                 private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
783                 {
784                         bool release = false;
785                         try {
786                                 safeHandle.DangerousAddRef (ref release);
787                                 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
788                         } finally {
789                                 if (release)
790                                         safeHandle.DangerousRelease ();
791                         }
792                 }
793
794                 // Creates a new system socket, returning the handle
795                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
796                 private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
797
798 #endregion
799
800 #region Listen
801
802                 public void Listen (int backlog)
803                 {
804                         ThrowIfDisposedAndClosed ();
805
806                         if (!is_bound)
807                                 throw new SocketException ((int) SocketError.InvalidArgument);
808
809                         int error;
810                         Listen_internal(m_Handle, backlog, out error);
811
812                         if (error != 0)
813                                 throw new SocketException (error);
814
815                         is_listening = true;
816                 }
817
818                 static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
819                 {
820                         bool release = false;
821                         try {
822                                 safeHandle.DangerousAddRef (ref release);
823                                 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
824                         } finally {
825                                 if (release)
826                                         safeHandle.DangerousRelease ();
827                         }
828                 }
829
830                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
831                 extern static void Listen_internal (IntPtr sock, int backlog, out int error);
832
833 #endregion
834
835 #region Connect
836
837                 public void Connect (IPAddress address, int port)
838                 {
839                         Connect (new IPEndPoint (address, port));
840                 }
841
842                 public void Connect (string host, int port)
843                 {
844                         Connect (Dns.GetHostAddresses (host), port);
845                 }
846
847                 public void Connect (EndPoint remoteEP)
848                 {
849                         ThrowIfDisposedAndClosed ();
850
851                         if (remoteEP == null)
852                                 throw new ArgumentNullException ("remoteEP");
853
854                         IPEndPoint ep = remoteEP as IPEndPoint;
855                         /* Dgram uses Any to 'disconnect' */
856                         if (ep != null && socketType != SocketType.Dgram) {
857                                 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
858                                         throw new SocketException ((int) SocketError.AddressNotAvailable);
859                         }
860
861                         if (is_listening)
862                                 throw new InvalidOperationException ();
863                                 
864                         if (ep != null) {
865                                 remoteEP = RemapIPEndPoint (ep);
866                         }
867
868                         SocketAddress serial = remoteEP.Serialize ();
869
870                         int error = 0;
871                         Connect_internal (m_Handle, serial, out error, is_blocking);
872
873                         if (error == 0 || error == 10035)
874                                 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
875
876                         if (error != 0) {
877                                 if (is_closed)
878                                         error = SOCKET_CLOSED_CODE;
879                                 throw new SocketException (error);
880                         }
881
882                         is_connected = !(socketType == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
883                         is_bound = true;
884                 }
885
886                 public bool ConnectAsync (SocketAsyncEventArgs e)
887                 {
888                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
889
890                         ThrowIfDisposedAndClosed ();
891
892                         if (is_listening)
893                                 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
894                         if (e.RemoteEndPoint == null)
895                                 throw new ArgumentNullException ("remoteEP");
896
897                         InitSocketAsyncEventArgs (e, null, e, SocketOperation.Connect);
898
899                         try {
900                                 IPAddress [] addresses;
901                                 SocketAsyncResult ares;
902
903                                 if (!GetCheckedIPs (e, out addresses)) {
904                                         //NOTE: DualMode may cause Socket's RemoteEndpoint to differ in AddressFamily from the
905                                         // SocketAsyncEventArgs, but the SocketAsyncEventArgs itself is not changed
906                                         ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
907                                 } else {
908                                         DnsEndPoint dep = (DnsEndPoint)e.RemoteEndPoint;
909                                         ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
910                                 }
911
912                                 if (ares.IsCompleted && ares.CompletedSynchronously) {
913                                         ares.CheckIfThrowDelayedException ();
914                                         return false;
915                                 }
916                         } catch (Exception exc) {
917                                 e.socket_async_result.Complete (exc, true);
918                                 return false;
919                         }
920
921                         return true;
922                 }
923
924                 public static void CancelConnectAsync (SocketAsyncEventArgs e)
925                 {
926                         if (e == null)
927                                 throw new ArgumentNullException("e");
928
929                         if (e.in_progress != 0 && e.LastOperation == SocketAsyncOperation.Connect)
930                                 e.current_socket.Close();
931                 }
932
933                 static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
934                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
935
936                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
937                                 throw new InvalidOperationException ("No operation in progress");
938
939                         try {
940                                 e.current_socket.EndConnect (ares);
941                         } catch (SocketException se) {
942                                 e.SocketError = se.SocketErrorCode;
943                         } catch (ObjectDisposedException) {
944                                 e.SocketError = SocketError.OperationAborted;
945                         } finally {
946                                 e.Complete ();
947                         }
948                 });
949
950                 public IAsyncResult BeginConnect (string host, int port, AsyncCallback requestCallback, object state)
951                 {
952                         ThrowIfDisposedAndClosed ();
953
954                         if (host == null)
955                                 throw new ArgumentNullException ("host");
956                         if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6)
957                                 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
958                         if (port <= 0 || port > 65535)
959                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
960                         if (is_listening)
961                                 throw new InvalidOperationException ();
962
963                         return BeginConnect (Dns.GetHostAddresses (host), port, requestCallback, state);
964                 }
965
966                 public IAsyncResult BeginConnect (EndPoint remoteEP, AsyncCallback callback, object state)
967                 {
968                         ThrowIfDisposedAndClosed ();
969
970                         if (remoteEP == null)
971                                 throw new ArgumentNullException ("remoteEP");
972                         if (is_listening)
973                                 throw new InvalidOperationException ();
974
975                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
976                                 EndPoint = remoteEP,
977                         };
978
979                         BeginSConnect (sockares);
980                         return sockares;
981                 }
982
983                 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback requestCallback, object state)
984                 {
985                         ThrowIfDisposedAndClosed ();
986
987                         if (addresses == null)
988                                 throw new ArgumentNullException ("addresses");
989                         if (addresses.Length == 0)
990                                 throw new ArgumentException ("Empty addresses list");
991                         if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
992                                 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
993                         if (port <= 0 || port > 65535)
994                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
995                         if (is_listening)
996                                 throw new InvalidOperationException ();
997
998                         SocketAsyncResult sockares = new SocketAsyncResult (this, requestCallback, state, SocketOperation.Connect) {
999                                 Addresses = addresses,
1000                                 Port = port,
1001                         };
1002
1003                         is_connected = false;
1004
1005                         BeginMConnect (sockares);
1006                         return sockares;
1007                 }
1008
1009                 static void BeginMConnect (SocketAsyncResult sockares)
1010                 {
1011                         Exception exc = null;
1012
1013                         for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1014                                 try {
1015                                         sockares.CurrentAddress++;
1016                                         sockares.EndPoint = new IPEndPoint (sockares.Addresses [i], sockares.Port);
1017
1018                                         BeginSConnect (sockares);
1019                                         return;
1020                                 } catch (Exception e) {
1021                                         exc = e;
1022                                 }
1023                         }
1024
1025                         throw exc;
1026                 }
1027
1028                 static void BeginSConnect (SocketAsyncResult sockares)
1029                 {
1030                         EndPoint remoteEP = sockares.EndPoint;
1031                         // Bug #75154: Connect() should not succeed for .Any addresses.
1032                         if (remoteEP is IPEndPoint) {
1033                                 IPEndPoint ep = (IPEndPoint) remoteEP;
1034                                 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1035                                         sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1036                                         return;
1037                                 }
1038
1039                                 sockares.EndPoint = remoteEP = sockares.socket.RemapIPEndPoint (ep);
1040                         }
1041
1042                         int error = 0;
1043
1044                         if (sockares.socket.connect_in_progress) {
1045                                 // This could happen when multiple IPs are used
1046                                 // Calling connect() again will reset the connection attempt and cause
1047                                 // an error. Better to just close the socket and move on.
1048                                 sockares.socket.connect_in_progress = false;
1049                                 sockares.socket.m_Handle.Dispose ();
1050                                 sockares.socket.m_Handle = new SafeSocketHandle (sockares.socket.Socket_internal (sockares.socket.addressFamily, sockares.socket.socketType, sockares.socket.protocolType, out error), true);
1051                                 if (error != 0)
1052                                         throw new SocketException (error);
1053                         }
1054
1055                         bool blk = sockares.socket.is_blocking;
1056                         if (blk)
1057                                 sockares.socket.Blocking = false;
1058                         Connect_internal (sockares.socket.m_Handle, remoteEP.Serialize (), out error, false);
1059                         if (blk)
1060                                 sockares.socket.Blocking = true;
1061
1062                         if (error == 0) {
1063                                 // succeeded synch
1064                                 sockares.socket.is_connected = true;
1065                                 sockares.socket.is_bound = true;
1066                                 sockares.Complete (true);
1067                                 return;
1068                         }
1069
1070                         if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1071                                 // error synch
1072                                 sockares.socket.is_connected = false;
1073                                 sockares.socket.is_bound = false;
1074                                 sockares.Complete (new SocketException (error), true);
1075                                 return;
1076                         }
1077
1078                         // continue asynch
1079                         sockares.socket.is_connected = false;
1080                         sockares.socket.is_bound = false;
1081                         sockares.socket.connect_in_progress = true;
1082
1083                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
1084                 }
1085
1086                 static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
1087                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1088
1089                         if (sockares.EndPoint == null) {
1090                                 sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
1091                                 return;
1092                         }
1093
1094                         try {
1095                                 int error = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1096
1097                                 if (error == 0) {
1098                                         sockares.socket.seed_endpoint = sockares.EndPoint;
1099                                         sockares.socket.is_connected = true;
1100                                         sockares.socket.is_bound = true;
1101                                         sockares.socket.connect_in_progress = false;
1102                                         sockares.error = 0;
1103                                         sockares.Complete ();
1104                                         return;
1105                                 }
1106
1107                                 if (sockares.Addresses == null) {
1108                                         sockares.socket.connect_in_progress = false;
1109                                         sockares.Complete (new SocketException (error));
1110                                         return;
1111                                 }
1112
1113                                 if (sockares.CurrentAddress >= sockares.Addresses.Length) {
1114                                         sockares.Complete (new SocketException (error));
1115                                         return;
1116                                 }
1117
1118                                 BeginMConnect (sockares);
1119                         } catch (Exception e) {
1120                                 sockares.socket.connect_in_progress = false;
1121                                 sockares.Complete (e);
1122                         }
1123                 });
1124
1125                 public void EndConnect (IAsyncResult asyncResult)
1126                 {
1127                         ThrowIfDisposedAndClosed ();
1128
1129                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndConnect", "asyncResult");
1130
1131                         if (!sockares.IsCompleted)
1132                                 sockares.AsyncWaitHandle.WaitOne();
1133
1134                         sockares.CheckIfThrowDelayedException();
1135                 }
1136
1137                 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error, bool blocking)
1138                 {
1139                         try {
1140                                 safeHandle.RegisterForBlockingSyscall ();
1141                                 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error, blocking);
1142                         } finally {
1143                                 safeHandle.UnRegisterForBlockingSyscall ();
1144                         }
1145                 }
1146
1147                 /* Connects to the remote address */
1148                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1149                 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error, bool blocking);
1150
1151                 /* Returns :
1152                  *  - false when it is ok to use RemoteEndPoint
1153                  *  - true when addresses must be used (and addresses could be null/empty) */
1154                 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1155                 {
1156                         addresses = null;
1157
1158                         // Connect to the first address that match the host name, like:
1159                         // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1160                         // while skipping entries that do not match the address family
1161                         DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1162                         if (dep != null) {
1163                                 addresses = Dns.GetHostAddresses (dep.Host);
1164                                 return true;
1165                         } else {
1166                                 e.ConnectByNameError = null;
1167                                 return false;
1168                         }
1169                 }
1170
1171 #endregion
1172
1173 #region Disconnect
1174
1175                 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1176                  * if the platform is newer than w2k.  We should be able to cope... */
1177                 public void Disconnect (bool reuseSocket)
1178                 {
1179                         ThrowIfDisposedAndClosed ();
1180
1181                         int error = 0;
1182                         Disconnect_internal (m_Handle, reuseSocket, out error);
1183
1184                         if (error != 0) {
1185                                 if (error == 50) {
1186                                         /* ERROR_NOT_SUPPORTED */
1187                                         throw new PlatformNotSupportedException ();
1188                                 } else {
1189                                         throw new SocketException (error);
1190                                 }
1191                         }
1192
1193                         is_connected = false;
1194                         if (reuseSocket) {
1195                                 /* Do managed housekeeping here... */
1196                         }
1197                 }
1198
1199                 public bool DisconnectAsync (SocketAsyncEventArgs e)
1200                 {
1201                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1202
1203                         ThrowIfDisposedAndClosed ();
1204
1205                         InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
1206
1207                         IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
1208
1209                         return true;
1210                 }
1211
1212                 static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
1213                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1214
1215                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1216                                 throw new InvalidOperationException ("No operation in progress");
1217
1218                         try {
1219                                 e.current_socket.EndDisconnect (ares);
1220                         } catch (SocketException ex) {
1221                                 e.SocketError = ex.SocketErrorCode;
1222                         } catch (ObjectDisposedException) {
1223                                 e.SocketError = SocketError.OperationAborted;
1224                         } finally {
1225                                 e.Complete ();
1226                         }
1227                 });
1228
1229                 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1230                 {
1231                         ThrowIfDisposedAndClosed ();
1232
1233                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1234                                 ReuseSocket = reuseSocket,
1235                         };
1236
1237                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
1238
1239                         return sockares;
1240                 }
1241
1242                 static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
1243                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1244
1245                         try {
1246                                 sockares.socket.Disconnect (sockares.ReuseSocket);
1247                         } catch (Exception e) {
1248                                 sockares.Complete (e);
1249                                 return;
1250                         }
1251
1252                         sockares.Complete ();
1253                 });
1254
1255                 public void EndDisconnect (IAsyncResult asyncResult)
1256                 {
1257                         ThrowIfDisposedAndClosed ();
1258
1259                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1260
1261                         if (!sockares.IsCompleted)
1262                                 sockares.AsyncWaitHandle.WaitOne ();
1263
1264                         sockares.CheckIfThrowDelayedException ();
1265                 }
1266
1267                 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1268                 {
1269                         bool release = false;
1270                         try {
1271                                 safeHandle.DangerousAddRef (ref release);
1272                                 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1273                         } finally {
1274                                 if (release)
1275                                         safeHandle.DangerousRelease ();
1276                         }
1277                 }
1278
1279                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1280                 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1281
1282 #endregion
1283
1284 #region Receive
1285
1286                 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1287                 {
1288                         ThrowIfDisposedAndClosed ();
1289                         ThrowIfBufferNull (buffer);
1290                         ThrowIfBufferOutOfRange (buffer, offset, size);
1291
1292                         int nativeError;
1293                         int ret = Receive_internal (m_Handle, buffer, offset, size, socketFlags, out nativeError, is_blocking);
1294
1295                         errorCode = (SocketError) nativeError;
1296                         if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1297                                 is_connected = false;
1298                                 is_bound = false;
1299                         } else {
1300                                 is_connected = true;
1301                         }
1302
1303                         return ret;
1304                 }
1305
1306                 [CLSCompliant (false)]
1307                 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1308                 {
1309                         ThrowIfDisposedAndClosed ();
1310
1311                         if (buffers == null || buffers.Count == 0)
1312                                 throw new ArgumentNullException ("buffers");
1313
1314                         int numsegments = buffers.Count;
1315                         int nativeError;
1316                         int ret;
1317
1318                         /* Only example I can find of sending a byte array reference directly into an internal
1319                          * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1320                          * so taking a lead from that... */
1321                         WSABUF[] bufarray = new WSABUF[numsegments];
1322                         GCHandle[] gch = new GCHandle[numsegments];
1323
1324                         for (int i = 0; i < numsegments; i++) {
1325                                 ArraySegment<byte> segment = buffers[i];
1326
1327                                 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1328                                         throw new ArgumentOutOfRangeException ("segment");
1329
1330                                 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1331                                 bufarray[i].len = segment.Count;
1332                                 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1333                         }
1334
1335                         try {
1336                                 ret = Receive_internal (m_Handle, bufarray, socketFlags, out nativeError, is_blocking);
1337                         } finally {
1338                                 for (int i = 0; i < numsegments; i++) {
1339                                         if (gch[i].IsAllocated)
1340                                                 gch[i].Free ();
1341                                 }
1342                         }
1343
1344                         errorCode = (SocketError) nativeError;
1345
1346                         return ret;
1347                 }
1348
1349                 public bool ReceiveAsync (SocketAsyncEventArgs e)
1350                 {
1351                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1352
1353                         ThrowIfDisposedAndClosed ();
1354
1355                         // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1356                         // thrown when e.Buffer and e.BufferList are null (works fine when one is
1357                         // set to a valid object)
1358                         if (e.Buffer == null && e.BufferList == null)
1359                                 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1360
1361                         if (e.Buffer == null) {
1362                                 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
1363
1364                                 e.socket_async_result.Buffers = e.BufferList;
1365
1366                                 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
1367                         } else {
1368                                 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
1369
1370                                 e.socket_async_result.Buffer = e.Buffer;
1371                                 e.socket_async_result.Offset = e.Offset;
1372                                 e.socket_async_result.Size = e.Count;
1373
1374                                 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
1375                         }
1376
1377                         return true;
1378                 }
1379
1380                 static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
1381                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1382
1383                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1384                                 throw new InvalidOperationException ("No operation in progress");
1385
1386                         try {
1387                                 e.BytesTransferred = e.current_socket.EndReceive (ares);
1388                         } catch (SocketException se){
1389                                 e.SocketError = se.SocketErrorCode;
1390                         } catch (ObjectDisposedException) {
1391                                 e.SocketError = SocketError.OperationAborted;
1392                         } finally {
1393                                 e.Complete ();
1394                         }
1395                 });
1396
1397                 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1398                 {
1399                         ThrowIfDisposedAndClosed ();
1400                         ThrowIfBufferNull (buffer);
1401                         ThrowIfBufferOutOfRange (buffer, offset, size);
1402
1403                         /* As far as I can tell from the docs and from experimentation, a pointer to the
1404                          * SocketError parameter is not supposed to be saved for the async parts.  And as we don't
1405                          * set any socket errors in the setup code, we just have to set it to Success. */
1406                         errorCode = SocketError.Success;
1407
1408                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1409                                 Buffer = buffer,
1410                                 Offset = offset,
1411                                 Size = size,
1412                                 SockFlags = socketFlags,
1413                         };
1414
1415                         QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
1416
1417                         return sockares;
1418                 }
1419
1420                 static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
1421                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1422                         int total = 0;
1423
1424                         try {
1425                                 total = Receive_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error, sockares.socket.is_blocking);
1426                         } catch (Exception e) {
1427                                 sockares.Complete (e);
1428                                 return;
1429                         }
1430
1431                         sockares.Complete (total);
1432                 });
1433
1434                 [CLSCompliant (false)]
1435                 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1436                 {
1437                         ThrowIfDisposedAndClosed ();
1438
1439                         if (buffers == null)
1440                                 throw new ArgumentNullException ("buffers");
1441
1442                         /* I assume the same SocketError semantics as above */
1443                         errorCode = SocketError.Success;
1444
1445                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1446                                 Buffers = buffers,
1447                                 SockFlags = socketFlags,
1448                         };
1449
1450                         QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
1451
1452                         return sockares;
1453                 }
1454
1455                 static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
1456                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1457                         int total = 0;
1458
1459                         try {
1460                                 total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
1461                         } catch (Exception e) {
1462                                 sockares.Complete (e);
1463                                 return;
1464                         }
1465
1466                         sockares.Complete (total);
1467                 });
1468
1469                 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
1470                 {
1471                         ThrowIfDisposedAndClosed ();
1472
1473                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
1474
1475                         if (!sockares.IsCompleted)
1476                                 sockares.AsyncWaitHandle.WaitOne ();
1477
1478                         errorCode = sockares.ErrorCode;
1479
1480                         if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress)
1481                                 is_connected = false;
1482
1483                         // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
1484                         // kinds of exceptions that should be thrown.
1485                         if (errorCode == SocketError.Success)
1486                                 sockares.CheckIfThrowDelayedException();
1487
1488                         return sockares.Total;
1489                 }
1490
1491                 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking)
1492                 {
1493                         try {
1494                                 safeHandle.RegisterForBlockingSyscall ();
1495                                 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error, blocking);
1496                         } finally {
1497                                 safeHandle.UnRegisterForBlockingSyscall ();
1498                         }
1499                 }
1500
1501                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1502                 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking);
1503
1504                 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error, bool blocking)
1505                 {
1506                         try {
1507                                 safeHandle.RegisterForBlockingSyscall ();
1508                                 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error, blocking);
1509                         } finally {
1510                                 safeHandle.UnRegisterForBlockingSyscall ();
1511                         }
1512                 }
1513
1514                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1515                 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error, bool blocking);
1516
1517 #endregion
1518
1519 #region ReceiveFrom
1520
1521                 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
1522                 {
1523                         ThrowIfDisposedAndClosed ();
1524                         ThrowIfBufferNull (buffer);
1525                         ThrowIfBufferOutOfRange (buffer, offset, size);
1526
1527                         if (remoteEP == null)
1528                                 throw new ArgumentNullException ("remoteEP");
1529
1530                         SocketError errorCode;
1531                         int ret = ReceiveFrom (buffer, offset, size, socketFlags, ref remoteEP, out errorCode);
1532
1533                         if (errorCode != SocketError.Success)
1534                                 throw new SocketException (errorCode);
1535
1536                         return ret;
1537                 }
1538
1539                 internal int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, out SocketError errorCode)
1540                 {
1541                         SocketAddress sockaddr = remoteEP.Serialize();
1542
1543                         int nativeError;
1544                         int cnt = ReceiveFrom_internal (m_Handle, buffer, offset, size, socketFlags, ref sockaddr, out nativeError, is_blocking);
1545
1546                         errorCode = (SocketError) nativeError;
1547                         if (errorCode != SocketError.Success) {
1548                                 if (errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1549                                         is_connected = false;
1550                                 } else if (errorCode == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
1551                                         errorCode = SocketError.TimedOut;
1552                                 }
1553
1554                                 return 0;
1555                         }
1556
1557                         is_connected = true;
1558                         is_bound = true;
1559
1560                         /* If sockaddr is null then we're a connection oriented protocol and should ignore the
1561                          * remoteEP parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
1562                         if (sockaddr != null) {
1563                                 /* Stupidly, EndPoint.Create() is an instance method */
1564                                 remoteEP = remoteEP.Create (sockaddr);
1565                         }
1566
1567                         seed_endpoint = remoteEP;
1568
1569                         return cnt;
1570                 }
1571
1572                 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
1573                 {
1574                         ThrowIfDisposedAndClosed ();
1575
1576                         // We do not support recv into multiple buffers yet
1577                         if (e.BufferList != null)
1578                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
1579                         if (e.RemoteEndPoint == null)
1580                                 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
1581
1582                         InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
1583
1584                         e.socket_async_result.Buffer = e.Buffer;
1585                         e.socket_async_result.Offset = e.Offset;
1586                         e.socket_async_result.Size = e.Count;
1587                         e.socket_async_result.EndPoint = e.RemoteEndPoint;
1588                         e.socket_async_result.SockFlags = e.SocketFlags;
1589
1590                         QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
1591
1592                         return true;
1593                 }
1594
1595                 static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
1596                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1597
1598                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1599                                 throw new InvalidOperationException ("No operation in progress");
1600
1601                         try {
1602                                 e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
1603                         } catch (SocketException ex) {
1604                                 e.SocketError = ex.SocketErrorCode;
1605                         } catch (ObjectDisposedException) {
1606                                 e.SocketError = SocketError.OperationAborted;
1607                         } finally {
1608                                 e.Complete ();
1609                         }
1610                 });
1611
1612                 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
1613                 {
1614                         ThrowIfDisposedAndClosed ();
1615                         ThrowIfBufferNull (buffer);
1616                         ThrowIfBufferOutOfRange (buffer, offset, size);
1617
1618                         if (remoteEP == null)
1619                                 throw new ArgumentNullException ("remoteEP");
1620
1621                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
1622                                 Buffer = buffer,
1623                                 Offset = offset,
1624                                 Size = size,
1625                                 SockFlags = socketFlags,
1626                                 EndPoint = remoteEP,
1627                         };
1628
1629                         QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
1630
1631                         return sockares;
1632                 }
1633
1634                 static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
1635                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1636                         int total = 0;
1637
1638                         try {
1639                                 SocketError errorCode;
1640                                 total = sockares.socket.ReceiveFrom (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, out errorCode);
1641
1642                                 if (errorCode != SocketError.Success) {
1643                                         sockares.Complete (new SocketException (errorCode));
1644                                         return;
1645                                 }
1646                         } catch (Exception e) {
1647                                 sockares.Complete (e);
1648                                 return;
1649                         }
1650
1651                         sockares.Complete (total);
1652                 });
1653
1654                 public int EndReceiveFrom(IAsyncResult asyncResult, ref EndPoint endPoint)
1655                 {
1656                         ThrowIfDisposedAndClosed ();
1657
1658                         if (endPoint == null)
1659                                 throw new ArgumentNullException ("endPoint");
1660
1661                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveFrom", "asyncResult");
1662
1663                         if (!sockares.IsCompleted)
1664                                 sockares.AsyncWaitHandle.WaitOne();
1665
1666                         sockares.CheckIfThrowDelayedException();
1667
1668                         endPoint = sockares.EndPoint;
1669
1670                         return sockares.Total;
1671                 }
1672
1673
1674
1675                 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking)
1676                 {
1677                         try {
1678                                 safeHandle.RegisterForBlockingSyscall ();
1679                                 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error, blocking);
1680                         } finally {
1681                                 safeHandle.UnRegisterForBlockingSyscall ();
1682                         }
1683                 }
1684
1685                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1686                 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking);
1687
1688 #endregion
1689
1690 #region ReceiveMessageFrom
1691
1692                 [MonoTODO ("Not implemented")]
1693                 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
1694                 {
1695                         ThrowIfDisposedAndClosed ();
1696                         ThrowIfBufferNull (buffer);
1697                         ThrowIfBufferOutOfRange (buffer, offset, size);
1698
1699                         if (remoteEP == null)
1700                                 throw new ArgumentNullException ("remoteEP");
1701
1702                         // FIXME: figure out how we get hold of the IPPacketInformation
1703                         throw new NotImplementedException ();
1704                 }
1705
1706                 [MonoTODO ("Not implemented")]
1707                 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
1708                 {
1709                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1710
1711                         ThrowIfDisposedAndClosed ();
1712
1713                         throw new NotImplementedException ();
1714                 }
1715
1716                 [MonoTODO]
1717                 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
1718                 {
1719                         ThrowIfDisposedAndClosed ();
1720                         ThrowIfBufferNull (buffer);
1721                         ThrowIfBufferOutOfRange (buffer, offset, size);
1722
1723                         if (remoteEP == null)
1724                                 throw new ArgumentNullException ("remoteEP");
1725
1726                         throw new NotImplementedException ();
1727                 }
1728
1729                 [MonoTODO]
1730                 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
1731                 {
1732                         ThrowIfDisposedAndClosed ();
1733
1734                         if (endPoint == null)
1735                                 throw new ArgumentNullException ("endPoint");
1736
1737                         /*SocketAsyncResult sockares =*/ ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
1738
1739                         throw new NotImplementedException ();
1740                 }
1741
1742 #endregion
1743
1744 #region Send
1745
1746                 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1747                 {
1748                         ThrowIfDisposedAndClosed ();
1749                         ThrowIfBufferNull (buffer);
1750                         ThrowIfBufferOutOfRange (buffer, offset, size);
1751
1752                         if (size == 0) {
1753                                 errorCode = SocketError.Success;
1754                                 return 0;
1755                         }
1756
1757                         int nativeError;
1758                         int sent = 0;
1759                         do {
1760                                 sent += Send_internal (
1761 m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_blocking);
1762                                 errorCode = (SocketError)nativeError;
1763                                 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1764                                         is_connected = false;
1765                                         is_bound = false;
1766                                         break;
1767                                 } else {
1768                                         is_connected = true;
1769                                 }
1770                         } while (sent < size);
1771
1772                         return sent;
1773                 }
1774
1775                 [CLSCompliant (false)]
1776                 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1777                 {
1778                         ThrowIfDisposedAndClosed ();
1779
1780                         if (buffers == null)
1781                                 throw new ArgumentNullException ("buffers");
1782                         if (buffers.Count == 0)
1783                                 throw new ArgumentException ("Buffer is empty", "buffers");
1784
1785                         int numsegments = buffers.Count;
1786                         int nativeError;
1787                         int ret;
1788
1789                         WSABUF[] bufarray = new WSABUF[numsegments];
1790                         GCHandle[] gch = new GCHandle[numsegments];
1791
1792                         for(int i = 0; i < numsegments; i++) {
1793                                 ArraySegment<byte> segment = buffers[i];
1794
1795                                 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1796                                         throw new ArgumentOutOfRangeException ("segment");
1797
1798                                 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1799                                 bufarray[i].len = segment.Count;
1800                                 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1801                         }
1802
1803                         try {
1804                                 ret = Send_internal (m_Handle, bufarray, socketFlags, out nativeError, is_blocking);
1805                         } finally {
1806                                 for(int i = 0; i < numsegments; i++) {
1807                                         if (gch[i].IsAllocated) {
1808                                                 gch[i].Free ();
1809                                         }
1810                                 }
1811                         }
1812
1813                         errorCode = (SocketError)nativeError;
1814
1815                         return ret;
1816                 }
1817
1818                 public bool SendAsync (SocketAsyncEventArgs e)
1819                 {
1820                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1821
1822                         ThrowIfDisposedAndClosed ();
1823
1824                         if (e.Buffer == null && e.BufferList == null)
1825                                 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1826
1827                         if (e.Buffer == null) {
1828                                 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
1829
1830                                 e.socket_async_result.Buffers = e.BufferList;
1831
1832                                 QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
1833                         } else {
1834                                 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
1835
1836                                 e.socket_async_result.Buffer = e.Buffer;
1837                                 e.socket_async_result.Offset = e.Offset;
1838                                 e.socket_async_result.Size = e.Count;
1839
1840                                 QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
1841                         }
1842
1843                         return true;
1844                 }
1845
1846                 static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
1847                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1848
1849                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1850                                 throw new InvalidOperationException ("No operation in progress");
1851
1852                         try {
1853                                 e.BytesTransferred = e.current_socket.EndSend (ares);
1854                         } catch (SocketException se){
1855                                 e.SocketError = se.SocketErrorCode;
1856                         } catch (ObjectDisposedException) {
1857                                 e.SocketError = SocketError.OperationAborted;
1858                         } finally {
1859                                 e.Complete ();
1860                         }
1861                 });
1862
1863                 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1864                 {
1865                         ThrowIfDisposedAndClosed ();
1866                         ThrowIfBufferNull (buffer);
1867                         ThrowIfBufferOutOfRange (buffer, offset, size);
1868
1869                         if (!is_connected) {
1870                                 errorCode = SocketError.NotConnected;
1871                                 return null;
1872                         }
1873
1874                         errorCode = SocketError.Success;
1875
1876                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
1877                                 Buffer = buffer,
1878                                 Offset = offset,
1879                                 Size = size,
1880                                 SockFlags = socketFlags,
1881                         };
1882
1883                         QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
1884
1885                         return sockares;
1886                 }
1887
1888                 static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
1889                 {
1890                         int total = 0;
1891
1892                         try {
1893                                 total = Socket.Send_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error, false);
1894                         } catch (Exception e) {
1895                                 sockares.Complete (e);
1896                                 return;
1897                         }
1898
1899                         if (sockares.error == 0) {
1900                                 sent_so_far += total;
1901                                 sockares.Offset += total;
1902                                 sockares.Size -= total;
1903
1904                                 if (sockares.socket.CleanedUp) {
1905                                         sockares.Complete (total);
1906                                         return;
1907                                 }
1908
1909                                 if (sockares.Size > 0) {
1910                                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
1911                                         return; // Have to finish writing everything. See bug #74475.
1912                                 }
1913
1914                                 sockares.Total = sent_so_far;
1915                         }
1916
1917                         sockares.Complete (total);
1918                 }
1919
1920                 [CLSCompliant (false)]
1921                 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1922                 {
1923                         ThrowIfDisposedAndClosed ();
1924
1925                         if (buffers == null)
1926                                 throw new ArgumentNullException ("buffers");
1927
1928                         if (!is_connected) {
1929                                 errorCode = SocketError.NotConnected;
1930                                 return null;
1931                         }
1932
1933                         errorCode = SocketError.Success;
1934
1935                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
1936                                 Buffers = buffers,
1937                                 SockFlags = socketFlags,
1938                         };
1939
1940                         QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
1941
1942                         return sockares;
1943                 }
1944
1945                 static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
1946                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1947                         int total = 0;
1948
1949                         try {
1950                                 total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
1951                         } catch (Exception e) {
1952                                 sockares.Complete (e);
1953                                 return;
1954                         }
1955
1956                         sockares.Complete (total);
1957                 });
1958
1959                 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
1960                 {
1961                         ThrowIfDisposedAndClosed ();
1962
1963                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
1964
1965                         if (!sockares.IsCompleted)
1966                                 sockares.AsyncWaitHandle.WaitOne ();
1967
1968                         errorCode = sockares.ErrorCode;
1969
1970                         if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress)
1971                                 is_connected = false;
1972
1973                         /* If no socket error occurred, call CheckIfThrowDelayedException in
1974                          * case there are other kinds of exceptions that should be thrown.*/
1975                         if (errorCode == SocketError.Success)
1976                                 sockares.CheckIfThrowDelayedException ();
1977
1978                         return sockares.Total;
1979                 }
1980
1981                 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking)
1982                 {
1983                         try {
1984                                 safeHandle.RegisterForBlockingSyscall ();
1985                                 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error, blocking);
1986                         } finally {
1987                                 safeHandle.UnRegisterForBlockingSyscall ();
1988                         }
1989                 }
1990
1991                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1992                 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking);
1993
1994                 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error, bool blocking)
1995                 {
1996                         try {
1997                                 safeHandle.RegisterForBlockingSyscall ();
1998                                 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error, blocking);
1999                         } finally {
2000                                 safeHandle.UnRegisterForBlockingSyscall ();
2001                         }
2002                 }
2003
2004                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2005                 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error, bool blocking);
2006
2007 #endregion
2008
2009 #region SendTo
2010
2011                 public int SendTo (byte [] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP)
2012                 {
2013                         ThrowIfDisposedAndClosed ();
2014                         ThrowIfBufferNull (buffer);
2015                         ThrowIfBufferOutOfRange (buffer, offset, size);
2016
2017                         if (remoteEP == null)
2018                                 throw new ArgumentNullException("remoteEP");
2019
2020                         int error;
2021                         int ret = SendTo_internal (m_Handle, buffer, offset, size, socketFlags, remoteEP.Serialize (), out error, is_blocking);
2022
2023                         SocketError err = (SocketError) error;
2024                         if (err != 0) {
2025                                 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2026                                         is_connected = false;
2027                                 throw new SocketException (error);
2028                         }
2029
2030                         is_connected = true;
2031                         is_bound = true;
2032                         seed_endpoint = remoteEP;
2033
2034                         return ret;
2035                 }
2036
2037                 public bool SendToAsync (SocketAsyncEventArgs e)
2038                 {
2039                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2040
2041                         ThrowIfDisposedAndClosed ();
2042
2043                         if (e.BufferList != null)
2044                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2045                         if (e.RemoteEndPoint == null)
2046                                 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2047
2048                         InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2049
2050                         e.socket_async_result.Buffer = e.Buffer;
2051                         e.socket_async_result.Offset = e.Offset;
2052                         e.socket_async_result.Size = e.Count;
2053                         e.socket_async_result.SockFlags = e.SocketFlags;
2054                         e.socket_async_result.EndPoint = e.RemoteEndPoint;
2055
2056                         QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2057
2058                         return true;
2059                 }
2060
2061                 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2062                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2063
2064                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2065                                 throw new InvalidOperationException ("No operation in progress");
2066
2067                         try {
2068                                 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2069                         } catch (SocketException ex) {
2070                                 e.SocketError = ex.SocketErrorCode;
2071                         } catch (ObjectDisposedException) {
2072                                 e.SocketError = SocketError.OperationAborted;
2073                         } finally {
2074                                 e.Complete ();
2075                         }
2076                 });
2077
2078                 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP, AsyncCallback callback, object state)
2079                 {
2080                         ThrowIfDisposedAndClosed ();
2081                         ThrowIfBufferNull (buffer);
2082                         ThrowIfBufferOutOfRange (buffer, offset, size);
2083
2084                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2085                                 Buffer = buffer,
2086                                 Offset = offset,
2087                                 Size = size,
2088                                 SockFlags = socketFlags,
2089                                 EndPoint = remoteEP,
2090                         };
2091
2092                         QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2093
2094                         return sockares;
2095                 }
2096
2097                 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2098                 {
2099                         int total = 0;
2100                         try {
2101                                 total = sockares.socket.SendTo (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2102
2103                                 if (sockares.error == 0) {
2104                                         sent_so_far += total;
2105                                         sockares.Offset += total;
2106                                         sockares.Size -= total;
2107                                 }
2108
2109                                 if (sockares.Size > 0) {
2110                                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2111                                         return; // Have to finish writing everything. See bug #74475.
2112                                 }
2113
2114                                 sockares.Total = sent_so_far;
2115                         } catch (Exception e) {
2116                                 sockares.Complete (e);
2117                                 return;
2118                         }
2119
2120                         sockares.Complete ();
2121                 }
2122
2123                 public int EndSendTo (IAsyncResult asyncResult)
2124                 {
2125                         ThrowIfDisposedAndClosed ();
2126
2127                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSendTo", "result");
2128
2129                         if (!sockares.IsCompleted)
2130                                 sockares.AsyncWaitHandle.WaitOne();
2131
2132                         sockares.CheckIfThrowDelayedException();
2133
2134                         return sockares.Total;
2135                 }
2136
2137                 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking)
2138                 {
2139                         try {
2140                                 safeHandle.RegisterForBlockingSyscall ();
2141                                 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error, blocking);
2142                         } finally {
2143                                 safeHandle.UnRegisterForBlockingSyscall ();
2144                         }
2145                 }
2146
2147                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2148                 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking);
2149
2150 #endregion
2151
2152 #region SendFile
2153
2154                 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2155                 {
2156                         ThrowIfDisposedAndClosed ();
2157
2158                         if (!is_connected)
2159                                 throw new NotSupportedException ();
2160                         if (!is_blocking)
2161                                 throw new InvalidOperationException ();
2162
2163                         int error = 0;
2164                         if (!SendFile_internal (m_Handle, fileName, preBuffer, postBuffer, flags, out error, is_blocking) || error != 0) {
2165                                 SocketException exc = new SocketException (error);
2166                                 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2167                                         throw new FileNotFoundException ();
2168                                 throw exc;
2169                         }
2170                 }
2171
2172                 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2173                 {
2174                         ThrowIfDisposedAndClosed ();
2175
2176                         if (!is_connected)
2177                                 throw new NotSupportedException ();
2178                         if (!File.Exists (fileName))
2179                                 throw new FileNotFoundException ();
2180
2181                         SendFileHandler handler = new SendFileHandler (SendFile);
2182
2183                         return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2184                 }
2185
2186                 public void EndSendFile (IAsyncResult asyncResult)
2187                 {
2188                         ThrowIfDisposedAndClosed ();
2189
2190                         if (asyncResult == null)
2191                                 throw new ArgumentNullException ("asyncResult");
2192
2193                         SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2194                         if (ares == null)
2195                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2196
2197                         ares.Delegate.EndInvoke (ares.Original);
2198                 }
2199
2200                 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags, out int error, bool blocking)
2201                 {
2202                         try {
2203                                 safeHandle.RegisterForBlockingSyscall ();
2204                                 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags, out error, blocking);
2205                         } finally {
2206                                 safeHandle.UnRegisterForBlockingSyscall ();
2207                         }
2208                 }
2209
2210                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2211                 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags, out int error, bool blocking);
2212
2213                 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2214
2215                 sealed class SendFileAsyncResult : IAsyncResult {
2216                         IAsyncResult ares;
2217                         SendFileHandler d;
2218
2219                         public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2220                         {
2221                                 this.d = d;
2222                                 this.ares = ares;
2223                         }
2224
2225                         public object AsyncState {
2226                                 get { return ares.AsyncState; }
2227                         }
2228
2229                         public WaitHandle AsyncWaitHandle {
2230                                 get { return ares.AsyncWaitHandle; }
2231                         }
2232
2233                         public bool CompletedSynchronously {
2234                                 get { return ares.CompletedSynchronously; }
2235                         }
2236
2237                         public bool IsCompleted {
2238                                 get { return ares.IsCompleted; }
2239                         }
2240
2241                         public SendFileHandler Delegate {
2242                                 get { return d; }
2243                         }
2244
2245                         public IAsyncResult Original {
2246                                 get { return ares; }
2247                         }
2248                 }
2249
2250 #endregion
2251
2252 #region SendPackets
2253
2254                 [MonoTODO ("Not implemented")]
2255                 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2256                 {
2257                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2258
2259                         ThrowIfDisposedAndClosed ();
2260
2261                         throw new NotImplementedException ();
2262                 }
2263
2264 #endregion
2265
2266 #region DuplicateAndClose
2267
2268                 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2269                 public SocketInformation DuplicateAndClose (int targetProcessId)
2270                 {
2271                         var si = new SocketInformation ();
2272                         si.Options =
2273                                 (is_listening      ? SocketInformationOptions.Listening : 0) |
2274                                 (is_connected      ? SocketInformationOptions.Connected : 0) |
2275                                 (is_blocking       ? 0 : SocketInformationOptions.NonBlocking) |
2276                                 (useOverlappedIO ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
2277
2278                         MonoIOError error;
2279                         IntPtr duplicateHandle;
2280                         if (!MonoIO.DuplicateHandle (System.Diagnostics.Process.GetCurrentProcess ().Handle, Handle, new IntPtr (targetProcessId), out duplicateHandle, 0, 0, 0x00000002 /* DUPLICATE_SAME_ACCESS */, out error))
2281                                 throw MonoIO.GetException (error);
2282
2283                         si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)addressFamily, (int)socketType, (int)protocolType, is_bound ? 1 : 0, (long)duplicateHandle);
2284                         m_Handle = null;
2285  
2286                         return si;
2287                 }
2288
2289 #endregion
2290
2291 #region GetSocketOption
2292
2293                 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2294                 {
2295                         ThrowIfDisposedAndClosed ();
2296
2297                         if (optionValue == null)
2298                                 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2299
2300                         int error;
2301                         GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref optionValue, out error);
2302
2303                         if (error != 0)
2304                                 throw new SocketException (error);
2305                 }
2306
2307                 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength)
2308                 {
2309                         ThrowIfDisposedAndClosed ();
2310
2311                         int error;
2312                         byte[] byte_val = new byte [optionLength];
2313                         GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref byte_val, out error);
2314
2315                         if (error != 0)
2316                                 throw new SocketException (error);
2317
2318                         return byte_val;
2319                 }
2320
2321                 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
2322                 {
2323                         ThrowIfDisposedAndClosed ();
2324
2325                         int error;
2326                         object obj_val;
2327                         GetSocketOption_obj_internal (m_Handle, optionLevel, optionName, out obj_val, out error);
2328
2329                         if (error != 0)
2330                                 throw new SocketException (error);
2331
2332                         if (optionName == SocketOptionName.Linger)
2333                                 return (LingerOption) obj_val;
2334                         else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
2335                                 return (MulticastOption) obj_val;
2336                         else if (obj_val is int)
2337                                 return (int) obj_val;
2338                         else
2339                                 return obj_val;
2340                 }
2341
2342                 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
2343                 {
2344                         bool release = false;
2345                         try {
2346                                 safeHandle.DangerousAddRef (ref release);
2347                                 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
2348                         } finally {
2349                                 if (release)
2350                                         safeHandle.DangerousRelease ();
2351                         }
2352                 }
2353
2354                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2355                 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
2356
2357                 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
2358                 {
2359                         bool release = false;
2360                         try {
2361                                 safeHandle.DangerousAddRef (ref release);
2362                                 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
2363                         } finally {
2364                                 if (release)
2365                                         safeHandle.DangerousRelease ();
2366                         }
2367                 }
2368
2369                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2370                 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
2371
2372 #endregion
2373
2374 #region SetSocketOption
2375
2376                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2377                 {
2378                         ThrowIfDisposedAndClosed ();
2379
2380                         // I'd throw an ArgumentNullException, but this is what MS does.
2381                         if (optionValue == null)
2382                                 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2383
2384                         int error;
2385                         SetSocketOption_internal (m_Handle, optionLevel, optionName, null, optionValue, 0, out error);
2386
2387                         if (error != 0) {
2388                                 if (error == (int) SocketError.InvalidArgument)
2389                                         throw new ArgumentException ();
2390                                 throw new SocketException (error);
2391                         }
2392                 }
2393
2394                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
2395                 {
2396                         ThrowIfDisposedAndClosed ();
2397
2398                         // NOTE: if a null is passed, the byte[] overload is used instead...
2399                         if (optionValue == null)
2400                                 throw new ArgumentNullException("optionValue");
2401
2402                         int error;
2403
2404                         if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
2405                                 LingerOption linger = optionValue as LingerOption;
2406                                 if (linger == null)
2407                                         throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
2408                                 SetSocketOption_internal (m_Handle, optionLevel, optionName, linger, null, 0, out error);
2409                         } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2410                                 MulticastOption multicast = optionValue as MulticastOption;
2411                                 if (multicast == null)
2412                                         throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
2413                                 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2414                         } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2415                                 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
2416                                 if (multicast == null)
2417                                         throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
2418                                 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2419                         } else {
2420                                 throw new ArgumentException ("Invalid value specified.", "optionValue");
2421                         }
2422
2423                         if (error != 0) {
2424                                 if (error == (int) SocketError.InvalidArgument)
2425                                         throw new ArgumentException ();
2426                                 throw new SocketException (error);
2427                         }
2428                 }
2429
2430                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
2431                 {
2432                         int int_val = optionValue ? 1 : 0;
2433
2434                         SetSocketOption (optionLevel, optionName, int_val);
2435                 }
2436
2437                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
2438                 {
2439                         ThrowIfDisposedAndClosed ();
2440
2441                         int error;
2442                         SetSocketOption_internal (m_Handle, optionLevel, optionName, null, null, optionValue, out error);
2443
2444                         if (error != 0) {
2445                                 if (error == (int) SocketError.InvalidArgument)
2446                                         throw new ArgumentException ();
2447                                 throw new SocketException (error);
2448                         }
2449                 }
2450
2451                 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
2452                 {
2453                         bool release = false;
2454                         try {
2455                                 safeHandle.DangerousAddRef (ref release);
2456                                 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
2457                         } finally {
2458                                 if (release)
2459                                         safeHandle.DangerousRelease ();
2460                         }
2461                 }
2462
2463                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2464                 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
2465
2466 #endregion
2467
2468 #region IOControl
2469
2470                 public int IOControl (int ioControlCode, byte [] optionInValue, byte [] optionOutValue)
2471                 {
2472                         if (CleanedUp)
2473                                 throw new ObjectDisposedException (GetType ().ToString ());
2474
2475                         int error;
2476                         int result = IOControl_internal (m_Handle, ioControlCode, optionInValue, optionOutValue, out error);
2477
2478                         if (error != 0)
2479                                 throw new SocketException (error);
2480                         if (result == -1)
2481                                 throw new InvalidOperationException ("Must use Blocking property instead.");
2482
2483                         return result;
2484                 }
2485
2486                 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
2487                 {
2488                         bool release = false;
2489                         try {
2490                                 safeHandle.DangerousAddRef (ref release);
2491                                 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
2492                         } finally {
2493                                 if (release)
2494                                         safeHandle.DangerousRelease ();
2495                         }
2496                 }
2497
2498                 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
2499                  * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
2500                  * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
2501                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2502                 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
2503
2504 #endregion
2505
2506 #region Close
2507
2508                 public void Close ()
2509                 {
2510                         linger_timeout = 0;
2511                         Dispose ();
2512                 }
2513
2514                 public void Close (int timeout)
2515                 {
2516                         linger_timeout = timeout;
2517                         Dispose ();
2518                 }
2519
2520                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2521                 internal extern static void Close_internal (IntPtr socket, out int error);
2522
2523 #endregion
2524
2525 #region Shutdown
2526
2527                 public void Shutdown (SocketShutdown how)
2528                 {
2529                         ThrowIfDisposedAndClosed ();
2530
2531                         if (!is_connected)
2532                                 throw new SocketException (10057); // Not connected
2533
2534                         int error;
2535                         Shutdown_internal (m_Handle, how, out error);
2536
2537                         if (error != 0)
2538                                 throw new SocketException (error);
2539                 }
2540
2541                 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
2542                 {
2543                         bool release = false;
2544                         try {
2545                                 safeHandle.DangerousAddRef (ref release);
2546                                 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
2547                         } finally {
2548                                 if (release)
2549                                         safeHandle.DangerousRelease ();
2550                         }
2551                 }
2552
2553                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2554                 internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
2555
2556 #endregion
2557
2558 #region Dispose
2559
2560                 protected virtual void Dispose (bool disposing)
2561                 {
2562                         if (CleanedUp)
2563                                 return;
2564
2565                         m_IntCleanedUp = 1;
2566                         bool was_connected = is_connected;
2567                         is_connected = false;
2568
2569                         if (m_Handle != null) {
2570                                 is_closed = true;
2571                                 IntPtr x = Handle;
2572
2573                                 if (was_connected)
2574                                         Linger (x);
2575
2576                                 m_Handle.Dispose ();
2577                         }
2578                 }
2579
2580                 void Linger (IntPtr handle)
2581                 {
2582                         if (!is_connected || linger_timeout <= 0)
2583                                 return;
2584
2585                         /* We don't want to receive any more data */
2586                         int error;
2587                         Shutdown_internal (handle, SocketShutdown.Receive, out error);
2588
2589                         if (error != 0)
2590                                 return;
2591
2592                         int seconds = linger_timeout / 1000;
2593                         int ms = linger_timeout % 1000;
2594                         if (ms > 0) {
2595                                 /* If the other end closes, this will return 'true' with 'Available' == 0 */
2596                                 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
2597                                 if (error != 0)
2598                                         return;
2599                         }
2600
2601                         if (seconds > 0) {
2602                                 LingerOption linger = new LingerOption (true, seconds);
2603                                 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
2604                                 /* Not needed, we're closing upon return */
2605                                 //if (error != 0)
2606                                 //      return;
2607                         }
2608                 }
2609
2610 #endregion
2611
2612                 void ThrowIfDisposedAndClosed (Socket socket)
2613                 {
2614                         if (socket.CleanedUp && socket.is_closed)
2615                                 throw new ObjectDisposedException (socket.GetType ().ToString ());
2616                 }
2617
2618                 void ThrowIfDisposedAndClosed ()
2619                 {
2620                         if (CleanedUp && is_closed)
2621                                 throw new ObjectDisposedException (GetType ().ToString ());
2622                 }
2623
2624                 void ThrowIfBufferNull (byte[] buffer)
2625                 {
2626                         if (buffer == null)
2627                                 throw new ArgumentNullException ("buffer");
2628                 }
2629
2630                 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
2631                 {
2632                         if (offset < 0)
2633                                 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
2634                         if (offset > buffer.Length)
2635                                 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
2636                         if (size < 0)
2637                                 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
2638                         if (size > buffer.Length - offset)
2639                                 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
2640                 }
2641
2642                 void ThrowIfUdp ()
2643                 {
2644                         if (protocolType == ProtocolType.Udp)
2645                                 throw new SocketException ((int)SocketError.ProtocolOption);
2646                 }
2647
2648                 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
2649                 {
2650                         if (ares == null)
2651                                 throw new ArgumentNullException (argName);
2652
2653                         SocketAsyncResult sockares = ares as SocketAsyncResult;
2654                         if (sockares == null)
2655                                 throw new ArgumentException ("Invalid IAsyncResult", argName);
2656                         if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
2657                                 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
2658
2659                         return sockares;
2660                 }
2661
2662                 void QueueIOSelectorJob (SemaphoreSlim sem, IntPtr handle, IOSelectorJob job)
2663                 {
2664                         var task = sem.WaitAsync();
2665                         // fast path without Task<Action> allocation.
2666                         if (task.IsCompleted) {
2667                                 if (CleanedUp) {
2668                                         job.MarkDisposed ();
2669                                         return;
2670                                 }
2671                                 IOSelector.Add (handle, job);
2672                         }
2673                         else
2674                         {
2675                                 task.ContinueWith( t => {
2676                                         if (CleanedUp) {
2677                                                 job.MarkDisposed ();
2678                                                 return;
2679                                         }
2680                                         IOSelector.Add(handle, job);
2681                                 });
2682                         }
2683                 }
2684
2685                 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
2686                 {
2687                         e.socket_async_result.Init (this, callback, state, operation);
2688                         if (e.AcceptSocket != null) {
2689                                 e.socket_async_result.AcceptSocket = e.AcceptSocket;
2690                         }
2691                         e.current_socket = this;
2692                         e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
2693                         e.SocketError = SocketError.Success;
2694                         e.BytesTransferred = 0;
2695                 }
2696
2697                 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
2698                 {
2699                         switch (op) {
2700                         case SocketOperation.Connect:
2701                                 return SocketAsyncOperation.Connect;
2702                         case SocketOperation.Accept:
2703                                 return SocketAsyncOperation.Accept;
2704                         case SocketOperation.Disconnect:
2705                                 return SocketAsyncOperation.Disconnect;
2706                         case SocketOperation.Receive:
2707                         case SocketOperation.ReceiveGeneric:
2708                                 return SocketAsyncOperation.Receive;
2709                         case SocketOperation.ReceiveFrom:
2710                                 return SocketAsyncOperation.ReceiveFrom;
2711                         case SocketOperation.Send:
2712                         case SocketOperation.SendGeneric:
2713                                 return SocketAsyncOperation.Send;
2714                         case SocketOperation.SendTo:
2715                                 return SocketAsyncOperation.SendTo;
2716                         default:
2717                                 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
2718                         }
2719                 }
2720                 
2721                 IPEndPoint RemapIPEndPoint (IPEndPoint input) {
2722                         // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
2723                         if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
2724                                 return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
2725                         
2726                         return input;
2727                 }
2728                 
2729                 [StructLayout (LayoutKind.Sequential)]
2730                 struct WSABUF {
2731                         public int len;
2732                         public IntPtr buf;
2733                 }
2734
2735                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2736                 internal static extern void cancel_blocking_socket_operation (Thread thread);
2737
2738                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2739                 internal static extern bool SupportsPortReuse (ProtocolType proto);
2740
2741                 internal static int FamilyHint {
2742                         get {
2743                                 // Returns one of
2744                                 //      MONO_HINT_UNSPECIFIED           = 0,
2745                                 //      MONO_HINT_IPV4                          = 1,
2746                                 //      MONO_HINT_IPV6                          = 2,
2747
2748                                 int hint = 0;
2749                                 if (OSSupportsIPv4) {
2750                                         hint = 1;
2751                                 }
2752
2753                                 if (OSSupportsIPv6) {
2754                                         hint = hint == 0 ? 2 : 0;
2755                                 }
2756
2757                                 return hint;
2758                         }
2759                 }
2760
2761                 static bool IsProtocolSupported (NetworkInterfaceComponent networkInterface)
2762                 {
2763 #if MOBILE
2764                         return true;
2765 #else
2766                         var nics = NetworkInterface.GetAllNetworkInterfaces ();
2767                         foreach (var adapter in nics) {
2768                                 if (adapter.Supports (networkInterface))
2769                                         return true;
2770                         }
2771
2772                         return false;
2773 #endif
2774                 }
2775         }
2776 }
2777