Merge pull request #2408 from tastywheattasteslikechicken/MoreInterfaceSupport
[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 result)
713                 {
714                         int bytes;
715                         byte[] buffer;
716                         return EndAccept (out buffer, out bytes, result);
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                                         e.socket_async_result.EndPoint = e.RemoteEndPoint;
905                                         ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
906                                 } else {
907                                         DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
908                                         e.socket_async_result.Addresses = addresses;
909                                         e.socket_async_result.Port = dep.Port;
910                                         ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
911                                 }
912
913                                 if (ares.IsCompleted && ares.CompletedSynchronously) {
914                                         ares.CheckIfThrowDelayedException ();
915                                         return false;
916                                 }
917                         } catch (Exception exc) {
918                                 e.socket_async_result.Complete (exc, true);
919                                 return false;
920                         }
921
922                         return true;
923                 }
924
925                 public static void CancelConnectAsync (SocketAsyncEventArgs e)
926                 {
927                         if (e == null)
928                                 throw new ArgumentNullException("e");
929
930                         if (e.in_progress != 0 && e.LastOperation == SocketAsyncOperation.Connect)
931                                 e.current_socket.Close();
932                 }
933
934                 static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
935                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
936
937                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
938                                 throw new InvalidOperationException ("No operation in progress");
939
940                         try {
941                                 e.current_socket.EndConnect (ares);
942                         } catch (SocketException se) {
943                                 e.SocketError = se.SocketErrorCode;
944                         } catch (ObjectDisposedException) {
945                                 e.SocketError = SocketError.OperationAborted;
946                         } finally {
947                                 e.Complete ();
948                         }
949                 });
950
951                 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
952                 {
953                         ThrowIfDisposedAndClosed ();
954
955                         if (host == null)
956                                 throw new ArgumentNullException ("host");
957                         if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6)
958                                 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
959                         if (port <= 0 || port > 65535)
960                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
961                         if (is_listening)
962                                 throw new InvalidOperationException ();
963
964                         return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
965                 }
966
967                 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
968                 {
969                         ThrowIfDisposedAndClosed ();
970
971                         if (end_point == null)
972                                 throw new ArgumentNullException ("end_point");
973                         if (is_listening)
974                                 throw new InvalidOperationException ();
975
976                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
977                                 EndPoint = end_point,
978                         };
979
980                         // Bug #75154: Connect() should not succeed for .Any addresses.
981                         if (end_point is IPEndPoint) {
982                                 IPEndPoint ep = (IPEndPoint) end_point;
983                                 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
984                                         sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
985                                         return sockares;
986                                 }
987                                 
988                                 end_point = RemapIPEndPoint (ep);
989                         }
990
991                         int error = 0;
992
993                         if (connect_in_progress) {
994                                 // This could happen when multiple IPs are used
995                                 // Calling connect() again will reset the connection attempt and cause
996                                 // an error. Better to just close the socket and move on.
997                                 connect_in_progress = false;
998                                 m_Handle.Dispose ();
999                                 m_Handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
1000                                 if (error != 0)
1001                                         throw new SocketException (error);
1002                         }
1003
1004                         bool blk = is_blocking;
1005                         if (blk)
1006                                 Blocking = false;
1007                         Connect_internal (m_Handle, end_point.Serialize (), out error, false);
1008                         if (blk)
1009                                 Blocking = true;
1010
1011                         if (error == 0) {
1012                                 // succeeded synch
1013                                 is_connected = true;
1014                                 is_bound = true;
1015                                 sockares.Complete (true);
1016                                 return sockares;
1017                         }
1018
1019                         if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1020                                 // error synch
1021                                 is_connected = false;
1022                                 is_bound = false;
1023                                 sockares.Complete (new SocketException (error), true);
1024                                 return sockares;
1025                         }
1026
1027                         // continue asynch
1028                         is_connected = false;
1029                         is_bound = false;
1030                         connect_in_progress = true;
1031
1032                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
1033
1034                         return sockares;
1035                 }
1036
1037                 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1038                 {
1039                         ThrowIfDisposedAndClosed ();
1040
1041                         if (addresses == null)
1042                                 throw new ArgumentNullException ("addresses");
1043                         if (addresses.Length == 0)
1044                                 throw new ArgumentException ("Empty addresses list");
1045                         if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1046                                 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1047                         if (port <= 0 || port > 65535)
1048                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1049                         if (is_listening)
1050                                 throw new InvalidOperationException ();
1051
1052                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1053                                 Addresses = addresses,
1054                                 Port = port,
1055                         };
1056
1057                         is_connected = false;
1058
1059                         return BeginMConnect (sockares);
1060                 }
1061
1062                 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1063                 {
1064                         SocketAsyncResult ares = null;
1065                         Exception exc = null;
1066                         AsyncCallback callback;
1067
1068                         for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1069                                 try {
1070                                         sockares.CurrentAddress++;
1071
1072                                         ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1073                                         if (ares.IsCompleted && ares.CompletedSynchronously) {
1074                                                 ares.CheckIfThrowDelayedException ();
1075
1076                                                 callback = ares.AsyncCallback;
1077                                                 if (callback != null)
1078                                                         ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
1079                                         }
1080
1081                                         break;
1082                                 } catch (Exception e) {
1083                                         exc = e;
1084                                         ares = null;
1085                                 }
1086                         }
1087
1088                         if (ares == null)
1089                                 throw exc;
1090
1091                         return sockares;
1092                 }
1093
1094                 static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
1095                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1096
1097                         if (sockares.EndPoint == null) {
1098                                 sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
1099                                 return;
1100                         }
1101
1102                         SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
1103                         bool is_mconnect = mconnect != null && mconnect.Addresses != null;
1104
1105                         try {
1106                                 EndPoint ep = sockares.EndPoint;
1107                                 int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1108
1109                                 if (error_code == 0) {
1110                                         if (is_mconnect)
1111                                                 sockares = mconnect;
1112
1113                                         sockares.socket.seed_endpoint = ep;
1114                                         sockares.socket.is_connected = true;
1115                                         sockares.socket.is_bound = true;
1116                                         sockares.socket.connect_in_progress = false;
1117                                         sockares.error = 0;
1118                                         sockares.Complete ();
1119                                         return;
1120                                 }
1121
1122                                 if (!is_mconnect) {
1123                                         sockares.socket.connect_in_progress = false;
1124                                         sockares.Complete (new SocketException (error_code));
1125                                         return;
1126                                 }
1127
1128                                 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
1129                                         mconnect.Complete (new SocketException (error_code));
1130                                         return;
1131                                 }
1132
1133                                 mconnect.socket.BeginMConnect (mconnect);
1134                         } catch (Exception e) {
1135                                 sockares.socket.connect_in_progress = false;
1136
1137                                 if (is_mconnect)
1138                                         sockares = mconnect;
1139
1140                                 sockares.Complete (e);
1141                                 return;
1142                         }
1143                 });
1144
1145                 public void EndConnect (IAsyncResult result)
1146                 {
1147                         ThrowIfDisposedAndClosed ();
1148
1149                         SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1150
1151                         if (!sockares.IsCompleted)
1152                                 sockares.AsyncWaitHandle.WaitOne();
1153
1154                         sockares.CheckIfThrowDelayedException();
1155                 }
1156
1157                 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error, bool blocking)
1158                 {
1159                         try {
1160                                 safeHandle.RegisterForBlockingSyscall ();
1161                                 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error, blocking);
1162                         } finally {
1163                                 safeHandle.UnRegisterForBlockingSyscall ();
1164                         }
1165                 }
1166
1167                 /* Connects to the remote address */
1168                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1169                 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error, bool blocking);
1170
1171                 /* Returns :
1172                  *  - false when it is ok to use RemoteEndPoint
1173                  *  - true when addresses must be used (and addresses could be null/empty) */
1174                 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1175                 {
1176                         addresses = null;
1177
1178                         // Connect to the first address that match the host name, like:
1179                         // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1180                         // while skipping entries that do not match the address family
1181                         DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1182                         if (dep != null) {
1183                                 addresses = Dns.GetHostAddresses (dep.Host);
1184                                 return true;
1185                         } else {
1186                                 e.ConnectByNameError = null;
1187                                 return false;
1188                         }
1189                 }
1190
1191 #endregion
1192
1193 #region Disconnect
1194
1195                 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1196                  * if the platform is newer than w2k.  We should be able to cope... */
1197                 public void Disconnect (bool reuseSocket)
1198                 {
1199                         ThrowIfDisposedAndClosed ();
1200
1201                         int error = 0;
1202                         Disconnect_internal (m_Handle, reuseSocket, out error);
1203
1204                         if (error != 0) {
1205                                 if (error == 50) {
1206                                         /* ERROR_NOT_SUPPORTED */
1207                                         throw new PlatformNotSupportedException ();
1208                                 } else {
1209                                         throw new SocketException (error);
1210                                 }
1211                         }
1212
1213                         is_connected = false;
1214                         if (reuseSocket) {
1215                                 /* Do managed housekeeping here... */
1216                         }
1217                 }
1218
1219                 public bool DisconnectAsync (SocketAsyncEventArgs e)
1220                 {
1221                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1222
1223                         ThrowIfDisposedAndClosed ();
1224
1225                         InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
1226
1227                         IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
1228
1229                         return true;
1230                 }
1231
1232                 static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
1233                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1234
1235                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1236                                 throw new InvalidOperationException ("No operation in progress");
1237
1238                         try {
1239                                 e.current_socket.EndDisconnect (ares);
1240                         } catch (SocketException ex) {
1241                                 e.SocketError = ex.SocketErrorCode;
1242                         } catch (ObjectDisposedException) {
1243                                 e.SocketError = SocketError.OperationAborted;
1244                         } finally {
1245                                 e.Complete ();
1246                         }
1247                 });
1248
1249                 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1250                 {
1251                         ThrowIfDisposedAndClosed ();
1252
1253                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1254                                 ReuseSocket = reuseSocket,
1255                         };
1256
1257                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
1258
1259                         return sockares;
1260                 }
1261
1262                 static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
1263                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1264
1265                         try {
1266                                 sockares.socket.Disconnect (sockares.ReuseSocket);
1267                         } catch (Exception e) {
1268                                 sockares.Complete (e);
1269                                 return;
1270                         }
1271
1272                         sockares.Complete ();
1273                 });
1274
1275                 public void EndDisconnect (IAsyncResult asyncResult)
1276                 {
1277                         ThrowIfDisposedAndClosed ();
1278
1279                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1280
1281                         if (!sockares.IsCompleted)
1282                                 sockares.AsyncWaitHandle.WaitOne ();
1283
1284                         sockares.CheckIfThrowDelayedException ();
1285                 }
1286
1287                 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1288                 {
1289                         bool release = false;
1290                         try {
1291                                 safeHandle.DangerousAddRef (ref release);
1292                                 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1293                         } finally {
1294                                 if (release)
1295                                         safeHandle.DangerousRelease ();
1296                         }
1297                 }
1298
1299                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1300                 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1301
1302 #endregion
1303
1304 #region Receive
1305
1306                 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1307                 {
1308                         ThrowIfDisposedAndClosed ();
1309                         ThrowIfBufferNull (buffer);
1310                         ThrowIfBufferOutOfRange (buffer, offset, size);
1311
1312                         int nativeError;
1313                         int ret = Receive_internal (m_Handle, buffer, offset, size, socketFlags, out nativeError, is_blocking);
1314
1315                         errorCode = (SocketError) nativeError;
1316                         if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1317                                 is_connected = false;
1318                                 is_bound = false;
1319                         } else {
1320                                 is_connected = true;
1321                         }
1322
1323                         return ret;
1324                 }
1325
1326                 [CLSCompliant (false)]
1327                 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1328                 {
1329                         ThrowIfDisposedAndClosed ();
1330
1331                         if (buffers == null || buffers.Count == 0)
1332                                 throw new ArgumentNullException ("buffers");
1333
1334                         int numsegments = buffers.Count;
1335                         int nativeError;
1336                         int ret;
1337
1338                         /* Only example I can find of sending a byte array reference directly into an internal
1339                          * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1340                          * so taking a lead from that... */
1341                         WSABUF[] bufarray = new WSABUF[numsegments];
1342                         GCHandle[] gch = new GCHandle[numsegments];
1343
1344                         for (int i = 0; i < numsegments; i++) {
1345                                 ArraySegment<byte> segment = buffers[i];
1346
1347                                 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1348                                         throw new ArgumentOutOfRangeException ("segment");
1349
1350                                 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1351                                 bufarray[i].len = segment.Count;
1352                                 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1353                         }
1354
1355                         try {
1356                                 ret = Receive_internal (m_Handle, bufarray, socketFlags, out nativeError, is_blocking);
1357                         } finally {
1358                                 for (int i = 0; i < numsegments; i++) {
1359                                         if (gch[i].IsAllocated)
1360                                                 gch[i].Free ();
1361                                 }
1362                         }
1363
1364                         errorCode = (SocketError) nativeError;
1365
1366                         return ret;
1367                 }
1368
1369                 public bool ReceiveAsync (SocketAsyncEventArgs e)
1370                 {
1371                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1372
1373                         ThrowIfDisposedAndClosed ();
1374
1375                         // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1376                         // thrown when e.Buffer and e.BufferList are null (works fine when one is
1377                         // set to a valid object)
1378                         if (e.Buffer == null && e.BufferList == null)
1379                                 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1380
1381                         if (e.Buffer == null) {
1382                                 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
1383
1384                                 e.socket_async_result.Buffers = e.BufferList;
1385
1386                                 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
1387                         } else {
1388                                 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
1389
1390                                 e.socket_async_result.Buffer = e.Buffer;
1391                                 e.socket_async_result.Offset = e.Offset;
1392                                 e.socket_async_result.Size = e.Count;
1393
1394                                 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
1395                         }
1396
1397                         return true;
1398                 }
1399
1400                 static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
1401                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1402
1403                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1404                                 throw new InvalidOperationException ("No operation in progress");
1405
1406                         try {
1407                                 e.BytesTransferred = e.current_socket.EndReceive (ares);
1408                         } catch (SocketException se){
1409                                 e.SocketError = se.SocketErrorCode;
1410                         } catch (ObjectDisposedException) {
1411                                 e.SocketError = SocketError.OperationAborted;
1412                         } finally {
1413                                 e.Complete ();
1414                         }
1415                 });
1416
1417                 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1418                 {
1419                         ThrowIfDisposedAndClosed ();
1420                         ThrowIfBufferNull (buffer);
1421                         ThrowIfBufferOutOfRange (buffer, offset, size);
1422
1423                         /* As far as I can tell from the docs and from experimentation, a pointer to the
1424                          * SocketError parameter is not supposed to be saved for the async parts.  And as we don't
1425                          * set any socket errors in the setup code, we just have to set it to Success. */
1426                         errorCode = SocketError.Success;
1427
1428                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1429                                 Buffer = buffer,
1430                                 Offset = offset,
1431                                 Size = size,
1432                                 SockFlags = socketFlags,
1433                         };
1434
1435                         QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
1436
1437                         return sockares;
1438                 }
1439
1440                 static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
1441                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1442                         int total = 0;
1443
1444                         try {
1445                                 total = Receive_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error, sockares.socket.is_blocking);
1446                         } catch (Exception e) {
1447                                 sockares.Complete (e);
1448                                 return;
1449                         }
1450
1451                         sockares.Complete (total);
1452                 });
1453
1454                 [CLSCompliant (false)]
1455                 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1456                 {
1457                         ThrowIfDisposedAndClosed ();
1458
1459                         if (buffers == null)
1460                                 throw new ArgumentNullException ("buffers");
1461
1462                         /* I assume the same SocketError semantics as above */
1463                         errorCode = SocketError.Success;
1464
1465                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1466                                 Buffers = buffers,
1467                                 SockFlags = socketFlags,
1468                         };
1469
1470                         QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
1471
1472                         return sockares;
1473                 }
1474
1475                 static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
1476                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1477                         int total = 0;
1478
1479                         try {
1480                                 total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
1481                         } catch (Exception e) {
1482                                 sockares.Complete (e);
1483                                 return;
1484                         }
1485
1486                         sockares.Complete (total);
1487                 });
1488
1489                 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
1490                 {
1491                         ThrowIfDisposedAndClosed ();
1492
1493                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
1494
1495                         if (!sockares.IsCompleted)
1496                                 sockares.AsyncWaitHandle.WaitOne ();
1497
1498                         errorCode = sockares.ErrorCode;
1499
1500                         if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress)
1501                                 is_connected = false;
1502
1503                         // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
1504                         // kinds of exceptions that should be thrown.
1505                         if (errorCode == SocketError.Success)
1506                                 sockares.CheckIfThrowDelayedException();
1507
1508                         return sockares.Total;
1509                 }
1510
1511                 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking)
1512                 {
1513                         try {
1514                                 safeHandle.RegisterForBlockingSyscall ();
1515                                 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error, blocking);
1516                         } finally {
1517                                 safeHandle.UnRegisterForBlockingSyscall ();
1518                         }
1519                 }
1520
1521                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1522                 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking);
1523
1524                 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error, bool blocking)
1525                 {
1526                         try {
1527                                 safeHandle.RegisterForBlockingSyscall ();
1528                                 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error, blocking);
1529                         } finally {
1530                                 safeHandle.UnRegisterForBlockingSyscall ();
1531                         }
1532                 }
1533
1534                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1535                 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error, bool blocking);
1536
1537 #endregion
1538
1539 #region ReceiveFrom
1540
1541                 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
1542                 {
1543                         ThrowIfDisposedAndClosed ();
1544                         ThrowIfBufferNull (buffer);
1545                         ThrowIfBufferOutOfRange (buffer, offset, size);
1546
1547                         if (remoteEP == null)
1548                                 throw new ArgumentNullException ("remoteEP");
1549
1550                         SocketError errorCode;
1551                         int ret = ReceiveFrom (buffer, offset, size, socketFlags, ref remoteEP, out errorCode);
1552
1553                         if (errorCode != SocketError.Success)
1554                                 throw new SocketException (errorCode);
1555
1556                         return ret;
1557                 }
1558
1559                 internal int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, out SocketError errorCode)
1560                 {
1561                         SocketAddress sockaddr = remoteEP.Serialize();
1562
1563                         int nativeError;
1564                         int cnt = ReceiveFrom_internal (m_Handle, buffer, offset, size, socketFlags, ref sockaddr, out nativeError, is_blocking);
1565
1566                         errorCode = (SocketError) nativeError;
1567                         if (errorCode != SocketError.Success) {
1568                                 if (errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1569                                         is_connected = false;
1570                                 } else if (errorCode == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
1571                                         errorCode = SocketError.TimedOut;
1572                                 }
1573
1574                                 return 0;
1575                         }
1576
1577                         is_connected = true;
1578                         is_bound = true;
1579
1580                         /* If sockaddr is null then we're a connection oriented protocol and should ignore the
1581                          * remoteEP parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
1582                         if (sockaddr != null) {
1583                                 /* Stupidly, EndPoint.Create() is an instance method */
1584                                 remoteEP = remoteEP.Create (sockaddr);
1585                         }
1586
1587                         seed_endpoint = remoteEP;
1588
1589                         return cnt;
1590                 }
1591
1592                 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
1593                 {
1594                         ThrowIfDisposedAndClosed ();
1595
1596                         // We do not support recv into multiple buffers yet
1597                         if (e.BufferList != null)
1598                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
1599                         if (e.RemoteEndPoint == null)
1600                                 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
1601
1602                         InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
1603
1604                         e.socket_async_result.Buffer = e.Buffer;
1605                         e.socket_async_result.Offset = e.Offset;
1606                         e.socket_async_result.Size = e.Count;
1607                         e.socket_async_result.EndPoint = e.RemoteEndPoint;
1608                         e.socket_async_result.SockFlags = e.SocketFlags;
1609
1610                         QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
1611
1612                         return true;
1613                 }
1614
1615                 static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
1616                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1617
1618                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1619                                 throw new InvalidOperationException ("No operation in progress");
1620
1621                         try {
1622                                 e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
1623                         } catch (SocketException ex) {
1624                                 e.SocketError = ex.SocketErrorCode;
1625                         } catch (ObjectDisposedException) {
1626                                 e.SocketError = SocketError.OperationAborted;
1627                         } finally {
1628                                 e.Complete ();
1629                         }
1630                 });
1631
1632                 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
1633                 {
1634                         ThrowIfDisposedAndClosed ();
1635                         ThrowIfBufferNull (buffer);
1636                         ThrowIfBufferOutOfRange (buffer, offset, size);
1637
1638                         if (remote_end == null)
1639                                 throw new ArgumentNullException ("remote_end");
1640
1641                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
1642                                 Buffer = buffer,
1643                                 Offset = offset,
1644                                 Size = size,
1645                                 SockFlags = socket_flags,
1646                                 EndPoint = remote_end,
1647                         };
1648
1649                         QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
1650
1651                         return sockares;
1652                 }
1653
1654                 static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
1655                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1656                         int total = 0;
1657
1658                         try {
1659                                 SocketError errorCode;
1660                                 total = sockares.socket.ReceiveFrom (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, out errorCode);
1661
1662                                 if (errorCode != SocketError.Success) {
1663                                         sockares.Complete (new SocketException (errorCode));
1664                                         return;
1665                                 }
1666                         } catch (Exception e) {
1667                                 sockares.Complete (e);
1668                                 return;
1669                         }
1670
1671                         sockares.Complete (total);
1672                 });
1673
1674                 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
1675                 {
1676                         ThrowIfDisposedAndClosed ();
1677
1678                         if (end_point == null)
1679                                 throw new ArgumentNullException ("remote_end");
1680
1681                         SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
1682
1683                         if (!sockares.IsCompleted)
1684                                 sockares.AsyncWaitHandle.WaitOne();
1685
1686                         sockares.CheckIfThrowDelayedException();
1687
1688                         end_point = sockares.EndPoint;
1689
1690                         return sockares.Total;
1691                 }
1692
1693
1694
1695                 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking)
1696                 {
1697                         try {
1698                                 safeHandle.RegisterForBlockingSyscall ();
1699                                 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error, blocking);
1700                         } finally {
1701                                 safeHandle.UnRegisterForBlockingSyscall ();
1702                         }
1703                 }
1704
1705                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1706                 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking);
1707
1708 #endregion
1709
1710 #region ReceiveMessageFrom
1711
1712                 [MonoTODO ("Not implemented")]
1713                 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
1714                 {
1715                         ThrowIfDisposedAndClosed ();
1716                         ThrowIfBufferNull (buffer);
1717                         ThrowIfBufferOutOfRange (buffer, offset, size);
1718
1719                         if (remoteEP == null)
1720                                 throw new ArgumentNullException ("remoteEP");
1721
1722                         // FIXME: figure out how we get hold of the IPPacketInformation
1723                         throw new NotImplementedException ();
1724                 }
1725
1726                 [MonoTODO ("Not implemented")]
1727                 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
1728                 {
1729                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1730
1731                         ThrowIfDisposedAndClosed ();
1732
1733                         throw new NotImplementedException ();
1734                 }
1735
1736                 [MonoTODO]
1737                 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
1738                 {
1739                         ThrowIfDisposedAndClosed ();
1740                         ThrowIfBufferNull (buffer);
1741                         ThrowIfBufferOutOfRange (buffer, offset, size);
1742
1743                         if (remoteEP == null)
1744                                 throw new ArgumentNullException ("remoteEP");
1745
1746                         throw new NotImplementedException ();
1747                 }
1748
1749                 [MonoTODO]
1750                 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
1751                 {
1752                         ThrowIfDisposedAndClosed ();
1753
1754                         if (endPoint == null)
1755                                 throw new ArgumentNullException ("endPoint");
1756
1757                         /*SocketAsyncResult sockares =*/ ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
1758
1759                         throw new NotImplementedException ();
1760                 }
1761
1762 #endregion
1763
1764 #region Send
1765
1766                 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1767                 {
1768                         ThrowIfDisposedAndClosed ();
1769                         ThrowIfBufferNull (buffer);
1770                         ThrowIfBufferOutOfRange (buffer, offset, size);
1771
1772                         if (size == 0) {
1773                                 errorCode = SocketError.Success;
1774                                 return 0;
1775                         }
1776
1777                         int nativeError;
1778                         int sent = 0;
1779                         do {
1780                                 sent += Send_internal (
1781 m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_blocking);
1782                                 errorCode = (SocketError)nativeError;
1783                                 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1784                                         is_connected = false;
1785                                         is_bound = false;
1786                                         break;
1787                                 } else {
1788                                         is_connected = true;
1789                                 }
1790                         } while (sent < size);
1791
1792                         return sent;
1793                 }
1794
1795                 [CLSCompliant (false)]
1796                 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1797                 {
1798                         ThrowIfDisposedAndClosed ();
1799
1800                         if (buffers == null)
1801                                 throw new ArgumentNullException ("buffers");
1802                         if (buffers.Count == 0)
1803                                 throw new ArgumentException ("Buffer is empty", "buffers");
1804
1805                         int numsegments = buffers.Count;
1806                         int nativeError;
1807                         int ret;
1808
1809                         WSABUF[] bufarray = new WSABUF[numsegments];
1810                         GCHandle[] gch = new GCHandle[numsegments];
1811
1812                         for(int i = 0; i < numsegments; i++) {
1813                                 ArraySegment<byte> segment = buffers[i];
1814
1815                                 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1816                                         throw new ArgumentOutOfRangeException ("segment");
1817
1818                                 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1819                                 bufarray[i].len = segment.Count;
1820                                 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1821                         }
1822
1823                         try {
1824                                 ret = Send_internal (m_Handle, bufarray, socketFlags, out nativeError, is_blocking);
1825                         } finally {
1826                                 for(int i = 0; i < numsegments; i++) {
1827                                         if (gch[i].IsAllocated) {
1828                                                 gch[i].Free ();
1829                                         }
1830                                 }
1831                         }
1832
1833                         errorCode = (SocketError)nativeError;
1834
1835                         return ret;
1836                 }
1837
1838                 public bool SendAsync (SocketAsyncEventArgs e)
1839                 {
1840                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1841
1842                         ThrowIfDisposedAndClosed ();
1843
1844                         if (e.Buffer == null && e.BufferList == null)
1845                                 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1846
1847                         if (e.Buffer == null) {
1848                                 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
1849
1850                                 e.socket_async_result.Buffers = e.BufferList;
1851
1852                                 QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
1853                         } else {
1854                                 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
1855
1856                                 e.socket_async_result.Buffer = e.Buffer;
1857                                 e.socket_async_result.Offset = e.Offset;
1858                                 e.socket_async_result.Size = e.Count;
1859
1860                                 QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
1861                         }
1862
1863                         return true;
1864                 }
1865
1866                 static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
1867                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1868
1869                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1870                                 throw new InvalidOperationException ("No operation in progress");
1871
1872                         try {
1873                                 e.BytesTransferred = e.current_socket.EndSend (ares);
1874                         } catch (SocketException se){
1875                                 e.SocketError = se.SocketErrorCode;
1876                         } catch (ObjectDisposedException) {
1877                                 e.SocketError = SocketError.OperationAborted;
1878                         } finally {
1879                                 e.Complete ();
1880                         }
1881                 });
1882
1883                 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1884                 {
1885                         ThrowIfDisposedAndClosed ();
1886                         ThrowIfBufferNull (buffer);
1887                         ThrowIfBufferOutOfRange (buffer, offset, size);
1888
1889                         if (!is_connected) {
1890                                 errorCode = SocketError.NotConnected;
1891                                 return null;
1892                         }
1893
1894                         errorCode = SocketError.Success;
1895
1896                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
1897                                 Buffer = buffer,
1898                                 Offset = offset,
1899                                 Size = size,
1900                                 SockFlags = socketFlags,
1901                         };
1902
1903                         QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
1904
1905                         return sockares;
1906                 }
1907
1908                 static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
1909                 {
1910                         int total = 0;
1911
1912                         try {
1913                                 total = Socket.Send_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error, false);
1914                         } catch (Exception e) {
1915                                 sockares.Complete (e);
1916                                 return;
1917                         }
1918
1919                         if (sockares.error == 0) {
1920                                 sent_so_far += total;
1921                                 sockares.Offset += total;
1922                                 sockares.Size -= total;
1923
1924                                 if (sockares.socket.CleanedUp) {
1925                                         sockares.Complete (total);
1926                                         return;
1927                                 }
1928
1929                                 if (sockares.Size > 0) {
1930                                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
1931                                         return; // Have to finish writing everything. See bug #74475.
1932                                 }
1933
1934                                 sockares.Total = sent_so_far;
1935                         }
1936
1937                         sockares.Complete (total);
1938                 }
1939
1940                 [CLSCompliant (false)]
1941                 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1942                 {
1943                         ThrowIfDisposedAndClosed ();
1944
1945                         if (buffers == null)
1946                                 throw new ArgumentNullException ("buffers");
1947
1948                         if (!is_connected) {
1949                                 errorCode = SocketError.NotConnected;
1950                                 return null;
1951                         }
1952
1953                         errorCode = SocketError.Success;
1954
1955                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
1956                                 Buffers = buffers,
1957                                 SockFlags = socketFlags,
1958                         };
1959
1960                         QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
1961
1962                         return sockares;
1963                 }
1964
1965                 static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
1966                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1967                         int total = 0;
1968
1969                         try {
1970                                 total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
1971                         } catch (Exception e) {
1972                                 sockares.Complete (e);
1973                                 return;
1974                         }
1975
1976                         sockares.Complete (total);
1977                 });
1978
1979                 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
1980                 {
1981                         ThrowIfDisposedAndClosed ();
1982
1983                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
1984
1985                         if (!sockares.IsCompleted)
1986                                 sockares.AsyncWaitHandle.WaitOne ();
1987
1988                         errorCode = sockares.ErrorCode;
1989
1990                         if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress)
1991                                 is_connected = false;
1992
1993                         /* If no socket error occurred, call CheckIfThrowDelayedException in
1994                          * case there are other kinds of exceptions that should be thrown.*/
1995                         if (errorCode == SocketError.Success)
1996                                 sockares.CheckIfThrowDelayedException ();
1997
1998                         return sockares.Total;
1999                 }
2000
2001                 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking)
2002                 {
2003                         try {
2004                                 safeHandle.RegisterForBlockingSyscall ();
2005                                 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error, blocking);
2006                         } finally {
2007                                 safeHandle.UnRegisterForBlockingSyscall ();
2008                         }
2009                 }
2010
2011                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2012                 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking);
2013
2014                 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error, bool blocking)
2015                 {
2016                         try {
2017                                 safeHandle.RegisterForBlockingSyscall ();
2018                                 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error, blocking);
2019                         } finally {
2020                                 safeHandle.UnRegisterForBlockingSyscall ();
2021                         }
2022                 }
2023
2024                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2025                 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error, bool blocking);
2026
2027 #endregion
2028
2029 #region SendTo
2030
2031                 public int SendTo (byte [] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP)
2032                 {
2033                         ThrowIfDisposedAndClosed ();
2034                         ThrowIfBufferNull (buffer);
2035                         ThrowIfBufferOutOfRange (buffer, offset, size);
2036
2037                         if (remoteEP == null)
2038                                 throw new ArgumentNullException("remoteEP");
2039
2040                         int error;
2041                         int ret = SendTo_internal (m_Handle, buffer, offset, size, socketFlags, remoteEP.Serialize (), out error, is_blocking);
2042
2043                         SocketError err = (SocketError) error;
2044                         if (err != 0) {
2045                                 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2046                                         is_connected = false;
2047                                 throw new SocketException (error);
2048                         }
2049
2050                         is_connected = true;
2051                         is_bound = true;
2052                         seed_endpoint = remoteEP;
2053
2054                         return ret;
2055                 }
2056
2057                 public bool SendToAsync (SocketAsyncEventArgs e)
2058                 {
2059                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2060
2061                         ThrowIfDisposedAndClosed ();
2062
2063                         if (e.BufferList != null)
2064                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2065                         if (e.RemoteEndPoint == null)
2066                                 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2067
2068                         InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2069
2070                         e.socket_async_result.Buffer = e.Buffer;
2071                         e.socket_async_result.Offset = e.Offset;
2072                         e.socket_async_result.Size = e.Count;
2073                         e.socket_async_result.SockFlags = e.SocketFlags;
2074                         e.socket_async_result.EndPoint = e.RemoteEndPoint;
2075
2076                         QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2077
2078                         return true;
2079                 }
2080
2081                 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2082                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2083
2084                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2085                                 throw new InvalidOperationException ("No operation in progress");
2086
2087                         try {
2088                                 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2089                         } catch (SocketException ex) {
2090                                 e.SocketError = ex.SocketErrorCode;
2091                         } catch (ObjectDisposedException) {
2092                                 e.SocketError = SocketError.OperationAborted;
2093                         } finally {
2094                                 e.Complete ();
2095                         }
2096                 });
2097
2098                 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2099                 {
2100                         ThrowIfDisposedAndClosed ();
2101                         ThrowIfBufferNull (buffer);
2102                         ThrowIfBufferOutOfRange (buffer, offset, size);
2103
2104                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2105                                 Buffer = buffer,
2106                                 Offset = offset,
2107                                 Size = size,
2108                                 SockFlags = socket_flags,
2109                                 EndPoint = remote_end,
2110                         };
2111
2112                         QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2113
2114                         return sockares;
2115                 }
2116
2117                 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2118                 {
2119                         int total = 0;
2120                         try {
2121                                 total = sockares.socket.SendTo (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2122
2123                                 if (sockares.error == 0) {
2124                                         sent_so_far += total;
2125                                         sockares.Offset += total;
2126                                         sockares.Size -= total;
2127                                 }
2128
2129                                 if (sockares.Size > 0) {
2130                                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2131                                         return; // Have to finish writing everything. See bug #74475.
2132                                 }
2133
2134                                 sockares.Total = sent_so_far;
2135                         } catch (Exception e) {
2136                                 sockares.Complete (e);
2137                                 return;
2138                         }
2139
2140                         sockares.Complete ();
2141                 }
2142
2143                 public int EndSendTo (IAsyncResult result)
2144                 {
2145                         ThrowIfDisposedAndClosed ();
2146
2147                         SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2148
2149                         if (!sockares.IsCompleted)
2150                                 sockares.AsyncWaitHandle.WaitOne();
2151
2152                         sockares.CheckIfThrowDelayedException();
2153
2154                         return sockares.Total;
2155                 }
2156
2157                 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking)
2158                 {
2159                         try {
2160                                 safeHandle.RegisterForBlockingSyscall ();
2161                                 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error, blocking);
2162                         } finally {
2163                                 safeHandle.UnRegisterForBlockingSyscall ();
2164                         }
2165                 }
2166
2167                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2168                 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking);
2169
2170 #endregion
2171
2172 #region SendFile
2173
2174                 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2175                 {
2176                         ThrowIfDisposedAndClosed ();
2177
2178                         if (!is_connected)
2179                                 throw new NotSupportedException ();
2180                         if (!is_blocking)
2181                                 throw new InvalidOperationException ();
2182
2183                         int error = 0;
2184                         if (!SendFile_internal (m_Handle, fileName, preBuffer, postBuffer, flags, out error, is_blocking) || error != 0) {
2185                                 SocketException exc = new SocketException (error);
2186                                 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2187                                         throw new FileNotFoundException ();
2188                                 throw exc;
2189                         }
2190                 }
2191
2192                 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2193                 {
2194                         ThrowIfDisposedAndClosed ();
2195
2196                         if (!is_connected)
2197                                 throw new NotSupportedException ();
2198                         if (!File.Exists (fileName))
2199                                 throw new FileNotFoundException ();
2200
2201                         SendFileHandler handler = new SendFileHandler (SendFile);
2202
2203                         return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2204                 }
2205
2206                 public void EndSendFile (IAsyncResult asyncResult)
2207                 {
2208                         ThrowIfDisposedAndClosed ();
2209
2210                         if (asyncResult == null)
2211                                 throw new ArgumentNullException ("asyncResult");
2212
2213                         SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2214                         if (ares == null)
2215                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2216
2217                         ares.Delegate.EndInvoke (ares.Original);
2218                 }
2219
2220                 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags, out int error, bool blocking)
2221                 {
2222                         try {
2223                                 safeHandle.RegisterForBlockingSyscall ();
2224                                 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags, out error, blocking);
2225                         } finally {
2226                                 safeHandle.UnRegisterForBlockingSyscall ();
2227                         }
2228                 }
2229
2230                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2231                 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags, out int error, bool blocking);
2232
2233                 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2234
2235                 sealed class SendFileAsyncResult : IAsyncResult {
2236                         IAsyncResult ares;
2237                         SendFileHandler d;
2238
2239                         public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2240                         {
2241                                 this.d = d;
2242                                 this.ares = ares;
2243                         }
2244
2245                         public object AsyncState {
2246                                 get { return ares.AsyncState; }
2247                         }
2248
2249                         public WaitHandle AsyncWaitHandle {
2250                                 get { return ares.AsyncWaitHandle; }
2251                         }
2252
2253                         public bool CompletedSynchronously {
2254                                 get { return ares.CompletedSynchronously; }
2255                         }
2256
2257                         public bool IsCompleted {
2258                                 get { return ares.IsCompleted; }
2259                         }
2260
2261                         public SendFileHandler Delegate {
2262                                 get { return d; }
2263                         }
2264
2265                         public IAsyncResult Original {
2266                                 get { return ares; }
2267                         }
2268                 }
2269
2270 #endregion
2271
2272 #region SendPackets
2273
2274                 [MonoTODO ("Not implemented")]
2275                 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2276                 {
2277                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2278
2279                         ThrowIfDisposedAndClosed ();
2280
2281                         throw new NotImplementedException ();
2282                 }
2283
2284 #endregion
2285
2286 #region DuplicateAndClose
2287
2288                 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2289                 public SocketInformation DuplicateAndClose (int targetProcessId)
2290                 {
2291                         var si = new SocketInformation ();
2292                         si.Options =
2293                                 (is_listening      ? SocketInformationOptions.Listening : 0) |
2294                                 (is_connected      ? SocketInformationOptions.Connected : 0) |
2295                                 (is_blocking       ? 0 : SocketInformationOptions.NonBlocking) |
2296                                 (useOverlappedIO ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
2297
2298                         si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)addressFamily, (int)socketType, (int)protocolType, is_bound ? 1 : 0, (long)Handle);
2299                         m_Handle = null;
2300
2301                         return si;
2302                 }
2303
2304 #endregion
2305
2306 #region GetSocketOption
2307
2308                 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2309                 {
2310                         ThrowIfDisposedAndClosed ();
2311
2312                         if (optionValue == null)
2313                                 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2314
2315                         int error;
2316                         GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref optionValue, out error);
2317
2318                         if (error != 0)
2319                                 throw new SocketException (error);
2320                 }
2321
2322                 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength)
2323                 {
2324                         ThrowIfDisposedAndClosed ();
2325
2326                         int error;
2327                         byte[] byte_val = new byte [optionLength];
2328                         GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref byte_val, out error);
2329
2330                         if (error != 0)
2331                                 throw new SocketException (error);
2332
2333                         return byte_val;
2334                 }
2335
2336                 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
2337                 {
2338                         ThrowIfDisposedAndClosed ();
2339
2340                         int error;
2341                         object obj_val;
2342                         GetSocketOption_obj_internal (m_Handle, optionLevel, optionName, out obj_val, out error);
2343
2344                         if (error != 0)
2345                                 throw new SocketException (error);
2346
2347                         if (optionName == SocketOptionName.Linger)
2348                                 return (LingerOption) obj_val;
2349                         else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
2350                                 return (MulticastOption) obj_val;
2351                         else if (obj_val is int)
2352                                 return (int) obj_val;
2353                         else
2354                                 return obj_val;
2355                 }
2356
2357                 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
2358                 {
2359                         bool release = false;
2360                         try {
2361                                 safeHandle.DangerousAddRef (ref release);
2362                                 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
2363                         } finally {
2364                                 if (release)
2365                                         safeHandle.DangerousRelease ();
2366                         }
2367                 }
2368
2369                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2370                 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
2371
2372                 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
2373                 {
2374                         bool release = false;
2375                         try {
2376                                 safeHandle.DangerousAddRef (ref release);
2377                                 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
2378                         } finally {
2379                                 if (release)
2380                                         safeHandle.DangerousRelease ();
2381                         }
2382                 }
2383
2384                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2385                 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
2386
2387 #endregion
2388
2389 #region SetSocketOption
2390
2391                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2392                 {
2393                         ThrowIfDisposedAndClosed ();
2394
2395                         // I'd throw an ArgumentNullException, but this is what MS does.
2396                         if (optionValue == null)
2397                                 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2398
2399                         int error;
2400                         SetSocketOption_internal (m_Handle, optionLevel, optionName, null, optionValue, 0, out error);
2401
2402                         if (error != 0) {
2403                                 if (error == (int) SocketError.InvalidArgument)
2404                                         throw new ArgumentException ();
2405                                 throw new SocketException (error);
2406                         }
2407                 }
2408
2409                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
2410                 {
2411                         ThrowIfDisposedAndClosed ();
2412
2413                         // NOTE: if a null is passed, the byte[] overload is used instead...
2414                         if (optionValue == null)
2415                                 throw new ArgumentNullException("optionValue");
2416
2417                         int error;
2418
2419                         if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
2420                                 LingerOption linger = optionValue as LingerOption;
2421                                 if (linger == null)
2422                                         throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
2423                                 SetSocketOption_internal (m_Handle, optionLevel, optionName, linger, null, 0, out error);
2424                         } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2425                                 MulticastOption multicast = optionValue as MulticastOption;
2426                                 if (multicast == null)
2427                                         throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
2428                                 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2429                         } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2430                                 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
2431                                 if (multicast == null)
2432                                         throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
2433                                 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2434                         } else {
2435                                 throw new ArgumentException ("Invalid value specified.", "optionValue");
2436                         }
2437
2438                         if (error != 0) {
2439                                 if (error == (int) SocketError.InvalidArgument)
2440                                         throw new ArgumentException ();
2441                                 throw new SocketException (error);
2442                         }
2443                 }
2444
2445                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
2446                 {
2447                         int int_val = optionValue ? 1 : 0;
2448
2449                         SetSocketOption (optionLevel, optionName, int_val);
2450                 }
2451
2452                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
2453                 {
2454                         ThrowIfDisposedAndClosed ();
2455
2456                         int error;
2457                         SetSocketOption_internal (m_Handle, optionLevel, optionName, null, null, optionValue, out error);
2458
2459                         if (error != 0) {
2460                                 if (error == (int) SocketError.InvalidArgument)
2461                                         throw new ArgumentException ();
2462                                 throw new SocketException (error);
2463                         }
2464                 }
2465
2466                 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
2467                 {
2468                         bool release = false;
2469                         try {
2470                                 safeHandle.DangerousAddRef (ref release);
2471                                 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
2472                         } finally {
2473                                 if (release)
2474                                         safeHandle.DangerousRelease ();
2475                         }
2476                 }
2477
2478                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2479                 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
2480
2481 #endregion
2482
2483 #region IOControl
2484
2485                 public int IOControl (int ioControlCode, byte [] optionInValue, byte [] optionOutValue)
2486                 {
2487                         if (CleanedUp)
2488                                 throw new ObjectDisposedException (GetType ().ToString ());
2489
2490                         int error;
2491                         int result = IOControl_internal (m_Handle, ioControlCode, optionInValue, optionOutValue, out error);
2492
2493                         if (error != 0)
2494                                 throw new SocketException (error);
2495                         if (result == -1)
2496                                 throw new InvalidOperationException ("Must use Blocking property instead.");
2497
2498                         return result;
2499                 }
2500
2501                 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
2502                 {
2503                         bool release = false;
2504                         try {
2505                                 safeHandle.DangerousAddRef (ref release);
2506                                 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
2507                         } finally {
2508                                 if (release)
2509                                         safeHandle.DangerousRelease ();
2510                         }
2511                 }
2512
2513                 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
2514                  * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
2515                  * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
2516                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2517                 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
2518
2519 #endregion
2520
2521 #region Close
2522
2523                 public void Close ()
2524                 {
2525                         linger_timeout = 0;
2526                         Dispose ();
2527                 }
2528
2529                 public void Close (int timeout)
2530                 {
2531                         linger_timeout = timeout;
2532                         Dispose ();
2533                 }
2534
2535                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2536                 internal extern static void Close_internal (IntPtr socket, out int error);
2537
2538 #endregion
2539
2540 #region Shutdown
2541
2542                 public void Shutdown (SocketShutdown how)
2543                 {
2544                         ThrowIfDisposedAndClosed ();
2545
2546                         if (!is_connected)
2547                                 throw new SocketException (10057); // Not connected
2548
2549                         int error;
2550                         Shutdown_internal (m_Handle, how, out error);
2551
2552                         if (error != 0)
2553                                 throw new SocketException (error);
2554                 }
2555
2556                 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
2557                 {
2558                         bool release = false;
2559                         try {
2560                                 safeHandle.DangerousAddRef (ref release);
2561                                 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
2562                         } finally {
2563                                 if (release)
2564                                         safeHandle.DangerousRelease ();
2565                         }
2566                 }
2567
2568                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2569                 internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
2570
2571 #endregion
2572
2573 #region Dispose
2574
2575                 protected virtual void Dispose (bool disposing)
2576                 {
2577                         if (CleanedUp)
2578                                 return;
2579
2580                         m_IntCleanedUp = 1;
2581                         bool was_connected = is_connected;
2582                         is_connected = false;
2583
2584                         if (m_Handle != null) {
2585                                 is_closed = true;
2586                                 IntPtr x = Handle;
2587
2588                                 if (was_connected)
2589                                         Linger (x);
2590
2591                                 m_Handle.Dispose ();
2592                         }
2593                 }
2594
2595                 void Linger (IntPtr handle)
2596                 {
2597                         if (!is_connected || linger_timeout <= 0)
2598                                 return;
2599
2600                         /* We don't want to receive any more data */
2601                         int error;
2602                         Shutdown_internal (handle, SocketShutdown.Receive, out error);
2603
2604                         if (error != 0)
2605                                 return;
2606
2607                         int seconds = linger_timeout / 1000;
2608                         int ms = linger_timeout % 1000;
2609                         if (ms > 0) {
2610                                 /* If the other end closes, this will return 'true' with 'Available' == 0 */
2611                                 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
2612                                 if (error != 0)
2613                                         return;
2614                         }
2615
2616                         if (seconds > 0) {
2617                                 LingerOption linger = new LingerOption (true, seconds);
2618                                 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
2619                                 /* Not needed, we're closing upon return */
2620                                 //if (error != 0)
2621                                 //      return;
2622                         }
2623                 }
2624
2625 #endregion
2626
2627                 void ThrowIfDisposedAndClosed (Socket socket)
2628                 {
2629                         if (socket.CleanedUp && socket.is_closed)
2630                                 throw new ObjectDisposedException (socket.GetType ().ToString ());
2631                 }
2632
2633                 void ThrowIfDisposedAndClosed ()
2634                 {
2635                         if (CleanedUp && is_closed)
2636                                 throw new ObjectDisposedException (GetType ().ToString ());
2637                 }
2638
2639                 void ThrowIfBufferNull (byte[] buffer)
2640                 {
2641                         if (buffer == null)
2642                                 throw new ArgumentNullException ("buffer");
2643                 }
2644
2645                 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
2646                 {
2647                         if (offset < 0)
2648                                 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
2649                         if (offset > buffer.Length)
2650                                 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
2651                         if (size < 0)
2652                                 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
2653                         if (size > buffer.Length - offset)
2654                                 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
2655                 }
2656
2657                 void ThrowIfUdp ()
2658                 {
2659                         if (protocolType == ProtocolType.Udp)
2660                                 throw new SocketException ((int)SocketError.ProtocolOption);
2661                 }
2662
2663                 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
2664                 {
2665                         if (ares == null)
2666                                 throw new ArgumentNullException (argName);
2667
2668                         SocketAsyncResult sockares = ares as SocketAsyncResult;
2669                         if (sockares == null)
2670                                 throw new ArgumentException ("Invalid IAsyncResult", argName);
2671                         if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
2672                                 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
2673
2674                         return sockares;
2675                 }
2676
2677                 void QueueIOSelectorJob (SemaphoreSlim sem, IntPtr handle, IOSelectorJob job)
2678                 {
2679                         sem.WaitAsync ().ContinueWith (t => {
2680                                 if (CleanedUp) {
2681                                         job.MarkDisposed ();
2682                                         return;
2683                                 }
2684
2685                                 IOSelector.Add (handle, job);
2686                         });
2687                 }
2688
2689                 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
2690                 {
2691                         e.socket_async_result.Init (this, callback, state, operation);
2692                         if (e.AcceptSocket != null) {
2693                                 e.socket_async_result.AcceptSocket = e.AcceptSocket;
2694                         }
2695                         e.current_socket = this;
2696                         e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
2697                         e.SocketError = SocketError.Success;
2698                         e.BytesTransferred = 0;
2699                 }
2700
2701                 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
2702                 {
2703                         switch (op) {
2704                         case SocketOperation.Connect:
2705                                 return SocketAsyncOperation.Connect;
2706                         case SocketOperation.Accept:
2707                                 return SocketAsyncOperation.Accept;
2708                         case SocketOperation.Disconnect:
2709                                 return SocketAsyncOperation.Disconnect;
2710                         case SocketOperation.Receive:
2711                         case SocketOperation.ReceiveGeneric:
2712                                 return SocketAsyncOperation.Receive;
2713                         case SocketOperation.ReceiveFrom:
2714                                 return SocketAsyncOperation.ReceiveFrom;
2715                         case SocketOperation.Send:
2716                         case SocketOperation.SendGeneric:
2717                                 return SocketAsyncOperation.Send;
2718                         case SocketOperation.SendTo:
2719                                 return SocketAsyncOperation.SendTo;
2720                         default:
2721                                 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
2722                         }
2723                 }
2724                 
2725                 IPEndPoint RemapIPEndPoint (IPEndPoint input) {
2726                         // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
2727                         if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
2728                                 return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
2729                         
2730                         return input;
2731                 }
2732                 
2733                 [StructLayout (LayoutKind.Sequential)]
2734                 struct WSABUF {
2735                         public int len;
2736                         public IntPtr buf;
2737                 }
2738
2739                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2740                 internal static extern void cancel_blocking_socket_operation (Thread thread);
2741
2742                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2743                 internal static extern bool SupportsPortReuse (ProtocolType proto);
2744
2745                 internal static int FamilyHint {
2746                         get {
2747                                 // Returns one of
2748                                 //      MONO_HINT_UNSPECIFIED           = 0,
2749                                 //      MONO_HINT_IPV4                          = 1,
2750                                 //      MONO_HINT_IPV6                          = 2,
2751
2752                                 int hint = 0;
2753                                 if (OSSupportsIPv4) {
2754                                         hint = 1;
2755                                 }
2756
2757                                 if (OSSupportsIPv6) {
2758                                         hint = hint == 0 ? 2 : 0;
2759                                 }
2760
2761                                 return hint;
2762                         }
2763                 }
2764
2765                 static bool IsProtocolSupported (NetworkInterfaceComponent networkInterface)
2766                 {
2767 #if MOBILE
2768                         return true;
2769 #else
2770                         var nics = NetworkInterface.GetAllNetworkInterfaces ();
2771                         foreach (var adapter in nics) {
2772                                 if (adapter.Supports (networkInterface))
2773                                         return true;
2774                         }
2775
2776                         return false;
2777 #endif
2778                 }
2779         }
2780 }
2781