Merge pull request #3600 from henricm/fix-win-network-info-tests
[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                 /*
59                  *      These two fields are looked up by name by the runtime, don't change
60                  *  their name without also updating the runtime code.
61                  */
62                 static int ipv4_supported = -1;
63                 static int ipv6_supported = -1;
64
65                 /* true if we called Close_internal */
66                 bool is_closed;
67
68                 bool is_listening;
69                 bool use_overlapped_io;
70
71                 int linger_timeout;
72
73                 AddressFamily address_family;
74                 SocketType socket_type;
75                 ProtocolType protocol_type;
76
77                 /* the field "safe_handle" is looked up by name by the runtime */
78                 internal SafeSocketHandle safe_handle;
79
80                 /*
81                  * This EndPoint is used when creating new endpoints. Because
82                  * there are many types of EndPoints possible,
83                  * seed_endpoint.Create(addr) is used for creating new ones.
84                  * As such, this value is set on Bind, SentTo, ReceiveFrom,
85                  * Connect, etc.
86                  */
87                 internal EndPoint seed_endpoint = null;
88
89                 internal Queue<KeyValuePair<IntPtr, IOSelectorJob>> readQ = new Queue<KeyValuePair<IntPtr, IOSelectorJob>> (2);
90                 internal Queue<KeyValuePair<IntPtr, IOSelectorJob>> writeQ = new Queue<KeyValuePair<IntPtr, IOSelectorJob>> (2);
91
92                 internal bool is_blocking = true;
93                 internal bool is_bound;
94
95                 /* When true, the socket was connected at the time of the last IO operation */
96                 internal bool is_connected;
97
98                 internal bool is_disposed;
99                 internal bool connect_in_progress;
100
101 #region Constructors
102
103                 static Socket ()
104                 {
105                         if (ipv4_supported == -1) {
106                                 try {
107                                         Socket tmp = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
108                                         tmp.Close();
109
110                                         ipv4_supported = 1;
111                                 } catch {
112                                         ipv4_supported = 0;
113                                 }
114                         }
115
116                         if (ipv6_supported == -1) {
117                                 // We need to put a try/catch around ConfigurationManager methods as will always throw an exception 
118                                 // when run in a mono embedded application.  This occurs as embedded applications do not have a setup
119                                 // for application config.  The exception is not thrown when called from a normal .NET application. 
120                                 //
121                                 // We, then, need to guard calls to the ConfigurationManager.  If the config is not found or throws an
122                                 // exception, will fall through to the existing Socket / API directly below in the code.
123                                 //
124                                 // Also note that catching ConfigurationErrorsException specifically would require library dependency
125                                 // System.Configuration, and wanted to avoid that.
126 #if !MOBILE
127 #if CONFIGURATION_DEP
128                                 try {
129                                         SettingsSection config;
130                                         config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
131                                         if (config != null)
132                                                 ipv6_supported = config.Ipv6.Enabled ? -1 : 0;
133                                 } catch {
134                                         ipv6_supported = -1;
135                                 }
136 #else
137                                 try {
138                                         NetConfig config = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig;
139                                         if (config != null)
140                                                 ipv6_supported = config.ipv6Enabled ? -1 : 0;
141                                 } catch {
142                                         ipv6_supported = -1;
143                                 }
144 #endif
145 #endif
146                                 if (ipv6_supported != 0) {
147                                         try {
148                                                 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
149                                                 tmp.Close();
150
151                                                 ipv6_supported = 1;
152                                         } catch {
153                                                 ipv6_supported = 0;
154                                         }
155                                 }
156                         }
157                 }
158
159                 //
160                 // This constructor is used by servers that want to listen for instance on both
161                 // ipv4 and ipv6.   Mono has historically done that if you use InterNetworkV6 (at
162                 // least on Unix), because that is the default behavior unless the IPV6_V6ONLY
163                 // option is explicitly set by using setsockopt (sock, IPPROTO_IPV6, IPV6_ONLY)
164                 //
165                 public Socket (SocketType socketType, ProtocolType protocolType)
166                         : this (AddressFamily.InterNetworkV6, socketType, protocolType)
167                 {
168                         DualMode = true;
169                 }
170                 
171                 public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
172                 {
173                         this.address_family = addressFamily;
174                         this.socket_type = socketType;
175                         this.protocol_type = protocolType;
176
177                         int error;
178                         this.safe_handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
179
180                         if (error != 0)
181                                 throw new SocketException (error);
182
183                         SocketDefaults ();
184                 }
185
186 #if !MOBILE
187                 public Socket (SocketInformation socketInformation)
188                 {
189                         this.is_listening      = (socketInformation.Options & SocketInformationOptions.Listening) != 0;
190                         this.is_connected      = (socketInformation.Options & SocketInformationOptions.Connected) != 0;
191                         this.is_blocking       = (socketInformation.Options & SocketInformationOptions.NonBlocking) == 0;
192                         this.use_overlapped_io = (socketInformation.Options & SocketInformationOptions.UseOnlyOverlappedIO) != 0;
193
194                         var result = Mono.DataConverter.Unpack ("iiiil", socketInformation.ProtocolInformation, 0);
195
196                         this.address_family = (AddressFamily) (int) result [0];
197                         this.socket_type = (SocketType) (int) result [1];
198                         this.protocol_type = (ProtocolType) (int) result [2];
199                         this.is_bound = (ProtocolType) (int) result [3] != 0;
200                         this.safe_handle = new SafeSocketHandle ((IntPtr) (long) result [4], true);
201
202                         SocketDefaults ();
203                 }
204 #endif
205
206                 /* private constructor used by Accept, which already has a socket handle to use */
207                 internal Socket(AddressFamily family, SocketType type, ProtocolType proto, SafeSocketHandle safe_handle)
208                 {
209                         this.address_family = family;
210                         this.socket_type = type;
211                         this.protocol_type = proto;
212                         
213                         this.safe_handle = safe_handle;
214                         this.is_connected = true;
215                 }
216
217                 ~Socket ()
218                 {
219                         Dispose (false);
220                 }
221
222                 void SocketDefaults ()
223                 {
224                         try {
225                                 /* Need to test IPv6 further */
226                                 if (address_family == AddressFamily.InterNetwork
227                                         // || address_family == AddressFamily.InterNetworkV6
228                                 ) {
229                                         /* This is the default, but it probably has nasty side
230                                          * effects on Linux, as the socket option is kludged by
231                                          * turning on or off PMTU discovery... */
232                                         this.DontFragment = false;
233                                         if (protocol_type == ProtocolType.Tcp)
234                                                 this.NoDelay = false;
235                                 } else if (address_family == AddressFamily.InterNetworkV6) {
236                                         this.DualMode = true;
237                                 }
238
239                                 /* Microsoft sets these to 8192, but we are going to keep them
240                                  * both to the OS defaults as these have a big performance impact.
241                                  * on WebClient performance. */
242                                 // this.ReceiveBufferSize = 8192;
243                                 // this.SendBufferSize = 8192;
244                         } catch (SocketException) {
245                         }
246                 }
247
248                 /* Creates a new system socket, returning the handle */
249                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
250                 extern IntPtr Socket_internal (AddressFamily family, SocketType type, ProtocolType proto, out int error);
251
252 #endregion
253
254 #region Properties
255
256                 [ObsoleteAttribute ("Use OSSupportsIPv4 instead")]
257                 public static bool SupportsIPv4 {
258                         get { return ipv4_supported == 1; }
259                 }
260
261                 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
262                 public static bool SupportsIPv6 {
263                         get { return ipv6_supported == 1; }
264                 }
265
266 #if MOBILE
267                 public static bool OSSupportsIPv4 {
268                         get { return ipv4_supported == 1; }
269                 }
270 #else
271                 public static bool OSSupportsIPv4 {
272                         get {
273                                 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
274
275                                 foreach (NetworkInterface adapter in nics) {
276                                         if (adapter.Supports (NetworkInterfaceComponent.IPv4))
277                                                 return true;
278                                 }
279
280                                 return false;
281                         }
282                 }
283 #endif
284
285 #if MOBILE
286                 public static bool OSSupportsIPv6 {
287                         get { return ipv6_supported == 1; }
288                 }
289 #else
290                 public static bool OSSupportsIPv6 {
291                         get {
292                                 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
293
294                                 foreach (NetworkInterface adapter in nics) {
295                                         if (adapter.Supports (NetworkInterfaceComponent.IPv6))
296                                                 return true;
297                                 }
298
299                                 return false;
300                         }
301                 }
302 #endif
303
304                 public int Available {
305                         get {
306                                 ThrowIfDisposedAndClosed ();
307
308                                 int ret, error;
309                                 ret = Available_internal (safe_handle, out error);
310
311                                 if (error != 0)
312                                         throw new SocketException (error);
313
314                                 return ret;
315                         }
316                 }
317
318                 static int Available_internal (SafeSocketHandle safeHandle, out int error)
319                 {
320                         bool release = false;
321                         try {
322                                 safeHandle.DangerousAddRef (ref release);
323                                 return Available_internal (safeHandle.DangerousGetHandle (), out error);
324                         } finally {
325                                 if (release)
326                                         safeHandle.DangerousRelease ();
327                         }
328                 }
329
330                 /* Returns the amount of data waiting to be read on socket */
331                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
332                 extern static int Available_internal (IntPtr socket, out int error);
333
334                 public bool DontFragment {
335                         get {
336                                 ThrowIfDisposedAndClosed ();
337
338                                 switch (address_family) {
339                                 case AddressFamily.InterNetwork:
340                                         return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment)) != 0;
341                                 case AddressFamily.InterNetworkV6:
342                                         return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment)) != 0;
343                                 default:
344                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
345                                 }
346                         }
347                         set {
348                                 ThrowIfDisposedAndClosed ();
349
350                                 switch (address_family) {
351                                 case AddressFamily.InterNetwork:
352                                         SetSocketOption (SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
353                                         break;
354                                 case AddressFamily.InterNetworkV6:
355                                         SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.DontFragment, value ? 1 : 0);
356                                         break;
357                                 default:
358                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
359                                 }
360                         }
361                 }
362
363                 public bool EnableBroadcast {
364                         get {
365                                 ThrowIfDisposedAndClosed ();
366
367                                 if (protocol_type != ProtocolType.Udp)
368                                         throw new SocketException ((int) SocketError.ProtocolOption);
369
370                                 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast)) != 0;
371                         }
372                         set {
373                                 ThrowIfDisposedAndClosed ();
374
375                                 if (protocol_type != ProtocolType.Udp)
376                                         throw new SocketException ((int) SocketError.ProtocolOption);
377
378                                 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
379                         }
380                 }
381
382                 public bool ExclusiveAddressUse {
383                         get {
384                                 ThrowIfDisposedAndClosed ();
385
386                                 return ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse)) != 0;
387                         }
388                         set {
389                                 ThrowIfDisposedAndClosed ();
390
391                                 if (is_bound)
392                                         throw new InvalidOperationException ("Bind has already been called for this socket");
393
394                                 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
395                         }
396                 }
397
398                 public bool IsBound {
399                         get {
400                                 return is_bound;
401                         }
402                 }
403
404                 public LingerOption LingerState {
405                         get {
406                                 ThrowIfDisposedAndClosed ();
407
408                                 return (LingerOption) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger);
409                         }
410                         set {
411                                 ThrowIfDisposedAndClosed ();
412                                 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Linger, value);
413                         }
414                 }
415
416                 public bool MulticastLoopback {
417                         get {
418                                 ThrowIfDisposedAndClosed ();
419
420                                 /* Even though this option can be set for TCP sockets on Linux, throw
421                                  * this exception anyway to be compatible (the MSDN docs say
422                                  * "Setting this property on a Transmission Control Protocol (TCP)
423                                  * socket will have no effect." but the MS runtime throws the
424                                  * exception...) */
425                                 if (protocol_type == ProtocolType.Tcp)
426                                         throw new SocketException ((int)SocketError.ProtocolOption);
427
428                                 switch (address_family) {
429                                 case AddressFamily.InterNetwork:
430                                         return ((int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)) != 0;
431                                 case AddressFamily.InterNetworkV6:
432                                         return ((int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback)) != 0;
433                                 default:
434                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
435                                 }
436                         }
437                         set {
438                                 ThrowIfDisposedAndClosed ();
439
440                                 /* Even though this option can be set for TCP sockets on Linux, throw
441                                  * this exception anyway to be compatible (the MSDN docs say
442                                  * "Setting this property on a Transmission Control Protocol (TCP)
443                                  * socket will have no effect." but the MS runtime throws the
444                                  * exception...) */
445                                 if (protocol_type == ProtocolType.Tcp)
446                                         throw new SocketException ((int)SocketError.ProtocolOption);
447
448                                 switch (address_family) {
449                                 case AddressFamily.InterNetwork:
450                                         SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
451                                         break;
452                                 case AddressFamily.InterNetworkV6:
453                                         SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
454                                         break;
455                                 default:
456                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
457                                 }
458                         }
459                 }
460
461                 public bool DualMode {
462                         get {
463                                 if (AddressFamily != AddressFamily.InterNetworkV6) 
464                                         throw new NotSupportedException("This protocol version is not supported");
465
466                                 return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only) == 0);
467                         }
468                         set {
469                                 if (AddressFamily != AddressFamily.InterNetworkV6) 
470                                         throw new NotSupportedException("This protocol version is not supported");
471
472                                 SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1);
473                         }
474                 }
475
476                 private bool IsDualMode {
477                         get {
478                                 return AddressFamily == AddressFamily.InterNetworkV6 && DualMode;
479                         }
480                 }
481
482                 [MonoTODO ("This doesn't do anything on Mono yet")]
483                 public bool UseOnlyOverlappedIO {
484                         get { return use_overlapped_io; }
485                         set { use_overlapped_io = value; }
486                 }
487
488                 public IntPtr Handle {
489                         get { return safe_handle.DangerousGetHandle (); }
490                 }
491
492                 // Wish:  support non-IP endpoints.
493                 public EndPoint LocalEndPoint {
494                         get {
495                                 ThrowIfDisposedAndClosed ();
496
497                                 /* If the seed EndPoint is null, Connect, Bind, etc has not yet
498                                  * been called. MS returns null in this case. */
499                                 if (seed_endpoint == null)
500                                         return null;
501
502                                 int error;
503                                 SocketAddress sa = LocalEndPoint_internal (safe_handle, (int) address_family, out error);
504
505                                 if (error != 0)
506                                         throw new SocketException (error);
507
508                                 return seed_endpoint.Create (sa);
509                         }
510                 }
511
512                 static SocketAddress LocalEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
513                 {
514                         bool release = false;
515                         try {
516                                 safeHandle.DangerousAddRef (ref release);
517                                 return LocalEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
518                         } finally {
519                                 if (release)
520                                         safeHandle.DangerousRelease ();
521                         }
522                 }
523
524                 /* Returns the local endpoint details in addr and port */
525                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
526                 extern static SocketAddress LocalEndPoint_internal (IntPtr socket, int family, out int error);
527
528                 public SocketType SocketType {
529                         get { return socket_type; }
530                 }
531
532                 public int SendTimeout {
533                         get {
534                                 ThrowIfDisposedAndClosed ();
535
536                                 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
537                         }
538                         set {
539                                 ThrowIfDisposedAndClosed ();
540
541                                 if (value < -1)
542                                         throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
543
544                                 /* According to the MSDN docs we should adjust values between 1 and
545                                  * 499 to 500, but the MS runtime doesn't do this. */
546                                 if (value == -1)
547                                         value = 0;
548
549                                 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
550                         }
551                 }
552
553                 public int ReceiveTimeout {
554                         get {
555                                 ThrowIfDisposedAndClosed ();
556
557                                 return (int) GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
558                         }
559                         set {
560                                 ThrowIfDisposedAndClosed ();
561
562                                 if (value < -1)
563                                         throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than -1");
564
565                                 if (value == -1)
566                                         value = 0;
567
568                                 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, value);
569                         }
570                 }
571
572                 public AddressFamily AddressFamily {
573                         get { return address_family; }
574                 }
575
576                 public bool Blocking {
577                         get { return is_blocking; }
578                         set {
579                                 ThrowIfDisposedAndClosed ();
580
581                                 int error;
582                                 Blocking_internal (safe_handle, value, out error);
583
584                                 if (error != 0)
585                                         throw new SocketException (error);
586
587                                 is_blocking = value;
588                         }
589                 }
590
591                 static void Blocking_internal (SafeSocketHandle safeHandle, bool block, out int error)
592                 {
593                         bool release = false;
594                         try {
595                                 safeHandle.DangerousAddRef (ref release);
596                                 Blocking_internal (safeHandle.DangerousGetHandle (), block, out error);
597                         } finally {
598                                 if (release)
599                                         safeHandle.DangerousRelease ();
600                         }
601                 }
602
603                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
604                 internal extern static void Blocking_internal(IntPtr socket, bool block, out int error);
605
606                 public bool Connected {
607                         get { return is_connected; }
608                         internal set { is_connected = value; }
609                 }
610
611                 public ProtocolType ProtocolType {
612                         get { return protocol_type; }
613                 }
614
615                 public bool NoDelay {
616                         get {
617                                 ThrowIfDisposedAndClosed ();
618                                 ThrowIfUdp ();
619
620                                 return ((int) GetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay)) != 0;
621                         }
622
623                         set {
624                                 ThrowIfDisposedAndClosed ();
625                                 ThrowIfUdp ();
626                                 SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
627                         }
628                 }
629
630                 public int ReceiveBufferSize {
631                         get {
632                                 ThrowIfDisposedAndClosed ();
633
634                                 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer);
635                         }
636                         set {
637                                 ThrowIfDisposedAndClosed ();
638
639                                 if (value < 0)
640                                         throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
641
642                                 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
643                         }
644                 }
645
646                 public int SendBufferSize {
647                         get {
648                                 ThrowIfDisposedAndClosed ();
649
650                                 return (int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer);
651                         }
652                         set {
653                                 ThrowIfDisposedAndClosed ();
654
655                                 if (value < 0)
656                                         throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
657
658                                 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer, value);
659                         }
660                 }
661
662                 public short Ttl {
663                         get {
664                                 ThrowIfDisposedAndClosed ();
665
666                                 switch (address_family) {
667                                 case AddressFamily.InterNetwork:
668                                         return (short) (int) GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
669                                 case AddressFamily.InterNetworkV6:
670                                         return (short) (int) GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit);
671                                 default:
672                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
673                                 }
674                         }
675                         set {
676                                 ThrowIfDisposedAndClosed ();
677
678                                 if (value < 0 || value > 255)
679                                         throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero or greater than 255.");
680
681                                 switch (address_family) {
682                                 case AddressFamily.InterNetwork:
683                                         SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
684                                         break;
685                                 case AddressFamily.InterNetworkV6:
686                                         SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
687                                         break;
688                                 default:
689                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
690                                 }
691                         }
692                 }
693
694                 public EndPoint RemoteEndPoint {
695                         get {
696                                 ThrowIfDisposedAndClosed ();
697
698                                 /* If the seed EndPoint is null, Connect, Bind, etc has
699                                  * not yet been called. MS returns null in this case. */
700                                 if (!is_connected || seed_endpoint == null)
701                                         return null;
702
703                                 int error;
704                                 SocketAddress sa = RemoteEndPoint_internal (safe_handle, (int) address_family, out error);
705
706                                 if (error != 0)
707                                         throw new SocketException (error);
708
709                                 return seed_endpoint.Create (sa);
710                         }
711                 }
712
713                 static SocketAddress RemoteEndPoint_internal (SafeSocketHandle safeHandle, int family, out int error)
714                 {
715                         bool release = false;
716                         try {
717                                 safeHandle.DangerousAddRef (ref release);
718                                 return RemoteEndPoint_internal (safeHandle.DangerousGetHandle (), family, out error);
719                         } finally {
720                                 if (release)
721                                         safeHandle.DangerousRelease ();
722                         }
723                 }
724
725                 /* Returns the remote endpoint details in addr and port */
726                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
727                 extern static SocketAddress RemoteEndPoint_internal (IntPtr socket, int family, out int error);
728
729 #endregion
730
731 #region Select
732
733                 public static void Select (IList checkRead, IList checkWrite, IList checkError, int microSeconds)
734                 {
735                         var list = new List<Socket> ();
736                         AddSockets (list, checkRead, "checkRead");
737                         AddSockets (list, checkWrite, "checkWrite");
738                         AddSockets (list, checkError, "checkError");
739
740                         if (list.Count == 3)
741                                 throw new ArgumentNullException ("checkRead, checkWrite, checkError", "All the lists are null or empty.");
742
743                         /* The 'sockets' array contains:
744                          *  - READ socket 0-n, null,
745                          *  - WRITE socket 0-n, null,
746                          *  - ERROR socket 0-n, null */
747                         Socket [] sockets = list.ToArray ();
748
749                         int error;
750                         Select_internal (ref sockets, microSeconds, out error);
751
752                         if (error != 0)
753                                 throw new SocketException (error);
754
755                         if (sockets == null) {
756                                 if (checkRead != null)
757                                         checkRead.Clear ();
758                                 if (checkWrite != null)
759                                         checkWrite.Clear ();
760                                 if (checkError != null)
761                                         checkError.Clear ();
762                                 return;
763                         }
764
765                         int mode = 0;
766                         int count = sockets.Length;
767                         IList currentList = checkRead;
768                         int currentIdx = 0;
769                         for (int i = 0; i < count; i++) {
770                                 Socket sock = sockets [i];
771                                 if (sock == null) { // separator
772                                         if (currentList != null) {
773                                                 // Remove non-signaled sockets after the current one
774                                                 int to_remove = currentList.Count - currentIdx;
775                                                 for (int k = 0; k < to_remove; k++)
776                                                         currentList.RemoveAt (currentIdx);
777                                         }
778                                         currentList = (mode == 0) ? checkWrite : checkError;
779                                         currentIdx = 0;
780                                         mode++;
781                                         continue;
782                                 }
783
784                                 if (mode == 1 && currentList == checkWrite && !sock.is_connected) {
785                                         if ((int) sock.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
786                                                 sock.is_connected = true;
787                                 }
788
789                                 /* Remove non-signaled sockets before the current one */
790                                 while (((Socket) currentList [currentIdx]) != sock)
791                                         currentList.RemoveAt (currentIdx);
792
793                                 currentIdx++;
794                         }
795                 }
796
797                 static void AddSockets (List<Socket> sockets, IList list, string name)
798                 {
799                         if (list != null) {
800                                 foreach (Socket sock in list) {
801                                         if (sock == null) // MS throws a NullRef
802                                                 throw new ArgumentNullException ("name", "Contains a null element");
803                                         sockets.Add (sock);
804                                 }
805                         }
806
807                         sockets.Add (null);
808                 }
809
810                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
811                 extern static void Select_internal (ref Socket [] sockets, int microSeconds, out int error);
812
813 #endregion
814
815 #region Poll
816
817                 public bool Poll (int microSeconds, SelectMode mode)
818                 {
819                         ThrowIfDisposedAndClosed ();
820
821                         if (mode != SelectMode.SelectRead && mode != SelectMode.SelectWrite && mode != SelectMode.SelectError)
822                                 throw new NotSupportedException ("'mode' parameter is not valid.");
823
824                         int error;
825                         bool result = Poll_internal (safe_handle, mode, microSeconds, out error);
826
827                         if (error != 0)
828                                 throw new SocketException (error);
829
830                         if (mode == SelectMode.SelectWrite && result && !is_connected) {
831                                 /* Update the is_connected state; for non-blocking Connect()
832                                  * this is when we can find out that the connect succeeded. */
833                                 if ((int) GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error) == 0)
834                                         is_connected = true;
835                         }
836
837                         return result;
838                 }
839
840                 static bool Poll_internal (SafeSocketHandle safeHandle, SelectMode mode, int timeout, out int error)
841                 {
842                         bool release = false;
843                         try {
844                                 safeHandle.DangerousAddRef (ref release);
845                                 return Poll_internal (safeHandle.DangerousGetHandle (), mode, timeout, out error);
846                         } finally {
847                                 if (release)
848                                         safeHandle.DangerousRelease ();
849                         }
850                 }
851
852                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
853                 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
854
855 #endregion
856
857 #region Accept
858
859                 public Socket Accept()
860                 {
861                         ThrowIfDisposedAndClosed ();
862
863                         int error = 0;
864                         SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
865
866                         if (error != 0) {
867                                 if (is_closed)
868                                         error = SOCKET_CLOSED_CODE;
869                                 throw new SocketException(error);
870                         }
871
872                         Socket accepted = new Socket (this.AddressFamily, this.SocketType, this.ProtocolType, safe_handle) {
873                                 seed_endpoint = this.seed_endpoint,
874                                 Blocking = this.Blocking,
875                         };
876
877                         return accepted;
878                 }
879
880                 internal void Accept (Socket acceptSocket)
881                 {
882                         ThrowIfDisposedAndClosed ();
883
884                         int error = 0;
885                         SafeSocketHandle safe_handle = Accept_internal (this.safe_handle, out error, is_blocking);
886
887                         if (error != 0) {
888                                 if (is_closed)
889                                         error = SOCKET_CLOSED_CODE;
890                                 throw new SocketException (error);
891                         }
892
893                         acceptSocket.address_family = this.AddressFamily;
894                         acceptSocket.socket_type = this.SocketType;
895                         acceptSocket.protocol_type = this.ProtocolType;
896                         acceptSocket.safe_handle = safe_handle;
897                         acceptSocket.is_connected = true;
898                         acceptSocket.seed_endpoint = this.seed_endpoint;
899                         acceptSocket.Blocking = this.Blocking;
900
901                         // FIXME: figure out what if anything else needs to be reset
902                 }
903
904                 public bool AcceptAsync (SocketAsyncEventArgs e)
905                 {
906                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
907
908                         ThrowIfDisposedAndClosed ();
909
910                         if (!is_bound)
911                                 throw new InvalidOperationException ("You must call the Bind method before performing this operation.");
912                         if (!is_listening)
913                                 throw new InvalidOperationException ("You must call the Listen method before performing this operation.");
914                         if (e.BufferList != null)
915                                 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
916                         if (e.Count < 0)
917                                 throw new ArgumentOutOfRangeException ("e.Count");
918
919                         Socket acceptSocket = e.AcceptSocket;
920                         if (acceptSocket != null) {
921                                 if (acceptSocket.is_bound || acceptSocket.is_connected)
922                                         throw new InvalidOperationException ("AcceptSocket: The socket must not be bound or connected.");
923                         }
924
925                         InitSocketAsyncEventArgs (e, AcceptAsyncCallback, e, SocketOperation.Accept);
926
927                         QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, e.socket_async_result));
928
929                         return true;
930                 }
931
932                 static AsyncCallback AcceptAsyncCallback = new AsyncCallback (ares => {
933                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
934
935                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
936                                 throw new InvalidOperationException ("No operation in progress");
937
938                         try {
939                                 e.AcceptSocket = e.current_socket.EndAccept (ares);
940                         } catch (SocketException ex) {
941                                 e.SocketError = ex.SocketErrorCode;
942                         } catch (ObjectDisposedException) {
943                                 e.SocketError = SocketError.OperationAborted;
944                         } finally {
945                                 if (e.AcceptSocket == null)
946                                         e.AcceptSocket = new Socket (e.current_socket.AddressFamily, e.current_socket.SocketType, e.current_socket.ProtocolType, null);
947                                 e.Complete ();
948                         }
949                 });
950
951                 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
952                 {
953                         ThrowIfDisposedAndClosed ();
954
955                         if (!is_bound || !is_listening)
956                                 throw new InvalidOperationException ();
957
958                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Accept);
959
960                         QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptCallback, sockares));
961
962                         return sockares;
963                 }
964
965                 static IOAsyncCallback BeginAcceptCallback = new IOAsyncCallback (ares => {
966                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
967                         Socket acc_socket = null;
968                         try {
969                                 if (sockares.AcceptSocket == null) {
970                                         acc_socket = sockares.socket.Accept ();
971                                 } else {
972                                         acc_socket = sockares.AcceptSocket;
973                                         sockares.socket.Accept (acc_socket);
974                                 }
975
976                         } catch (Exception e) {
977                                 sockares.Complete (e);
978                                 return;
979                         }
980                         sockares.Complete (acc_socket);
981                 });
982
983                 public IAsyncResult BeginAccept (int receiveSize, AsyncCallback callback, object state)
984                 {
985                         ThrowIfDisposedAndClosed ();
986
987                         if (receiveSize < 0)
988                                 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
989
990                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
991                                 Buffer = new byte [receiveSize],
992                                 Offset = 0,
993                                 Size = receiveSize,
994                                 SockFlags = SocketFlags.None,
995                         };
996
997                         QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
998
999                         return sockares;
1000                 }
1001
1002                 public IAsyncResult BeginAccept (Socket acceptSocket, int receiveSize, AsyncCallback callback, object state)
1003                 {
1004                         ThrowIfDisposedAndClosed ();
1005
1006                         if (receiveSize < 0)
1007                                 throw new ArgumentOutOfRangeException ("receiveSize", "receiveSize is less than zero");
1008
1009                         if (acceptSocket != null) {
1010                                 ThrowIfDisposedAndClosed (acceptSocket);
1011
1012                                 if (acceptSocket.IsBound)
1013                                         throw new InvalidOperationException ();
1014
1015                                 /* For some reason the MS runtime
1016                                  * barfs if the new socket is not TCP,
1017                                  * even though it's just about to blow
1018                                  * away all those parameters
1019                                  */
1020                                 if (acceptSocket.ProtocolType != ProtocolType.Tcp)
1021                                         throw new SocketException ((int)SocketError.InvalidArgument);
1022                         }
1023
1024                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.AcceptReceive) {
1025                                 Buffer = new byte [receiveSize],
1026                                 Offset = 0,
1027                                 Size = receiveSize,
1028                                 SockFlags = SocketFlags.None,
1029                                 AcceptSocket = acceptSocket,
1030                         };
1031
1032                         QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginAcceptReceiveCallback, sockares));
1033
1034                         return sockares;
1035                 }
1036
1037                 static IOAsyncCallback BeginAcceptReceiveCallback = new IOAsyncCallback (ares => {
1038                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1039                         Socket acc_socket = null;
1040
1041                         try {
1042                                 if (sockares.AcceptSocket == null) {
1043                                         acc_socket = sockares.socket.Accept ();
1044                                 } else {
1045                                         acc_socket = sockares.AcceptSocket;
1046                                         sockares.socket.Accept (acc_socket);
1047                                 }
1048                         } catch (Exception e) {
1049                                 sockares.Complete (e);
1050                                 return;
1051                         }
1052
1053                         /* It seems the MS runtime special-cases 0-length requested receive data.  See bug 464201. */
1054                         int total = 0;
1055                         if (sockares.Size > 0) {
1056                                 try {
1057                                         SocketError error;
1058                                         total = acc_socket.Receive_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out error);
1059                                         if (error != 0) {
1060                                                 sockares.Complete (new SocketException ((int) error));
1061                                                 return;
1062                                         }
1063                                 } catch (Exception e) {
1064                                         sockares.Complete (e);
1065                                         return;
1066                                 }
1067                         }
1068
1069                         sockares.Complete (acc_socket, total);
1070                 });
1071
1072                 public Socket EndAccept (IAsyncResult result)
1073                 {
1074                         int bytes;
1075                         byte[] buffer;
1076                         return EndAccept (out buffer, out bytes, result);
1077                 }
1078
1079                 public Socket EndAccept (out byte[] buffer, IAsyncResult asyncResult)
1080                 {
1081                         int bytes;
1082                         return EndAccept (out buffer, out bytes, asyncResult);
1083                 }
1084
1085                 public Socket EndAccept (out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult)
1086                 {
1087                         ThrowIfDisposedAndClosed ();
1088
1089                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndAccept", "asyncResult");
1090
1091                         if (!sockares.IsCompleted)
1092                                 sockares.AsyncWaitHandle.WaitOne ();
1093
1094                         sockares.CheckIfThrowDelayedException ();
1095
1096                         buffer = sockares.Buffer;
1097                         bytesTransferred = sockares.Total;
1098
1099                         return sockares.AcceptedSocket;
1100                 }
1101
1102                 static SafeSocketHandle Accept_internal (SafeSocketHandle safeHandle, out int error, bool blocking)
1103                 {
1104                         try {
1105                                 safeHandle.RegisterForBlockingSyscall ();
1106                                 var ret = Accept_internal (safeHandle.DangerousGetHandle (), out error, blocking);
1107                                 return new SafeSocketHandle (ret, true);
1108                         } finally {
1109                                 safeHandle.UnRegisterForBlockingSyscall ();
1110                         }
1111                 }
1112
1113                 /* Creates a new system socket, returning the handle */
1114                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1115                 extern static IntPtr Accept_internal (IntPtr sock, out int error, bool blocking);
1116
1117 #endregion
1118
1119 #region Bind
1120
1121                 public void Bind (EndPoint localEP)
1122                 {
1123                         ThrowIfDisposedAndClosed ();
1124
1125                         if (localEP == null)
1126                                 throw new ArgumentNullException("localEP");
1127                                 
1128                         var ipEndPoint = localEP as IPEndPoint;
1129                         if (ipEndPoint != null) {
1130                                 localEP = RemapIPEndPoint (ipEndPoint); 
1131                         }
1132                         
1133                         int error;
1134                         Bind_internal (safe_handle, localEP.Serialize(), out error);
1135
1136                         if (error != 0)
1137                                 throw new SocketException (error);
1138                         if (error == 0)
1139                                 is_bound = true;
1140
1141                         seed_endpoint = localEP;
1142                 }
1143
1144                 private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1145                 {
1146                         bool release = false;
1147                         try {
1148                                 safeHandle.DangerousAddRef (ref release);
1149                                 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
1150                         } finally {
1151                                 if (release)
1152                                         safeHandle.DangerousRelease ();
1153                         }
1154                 }
1155
1156                 // Creates a new system socket, returning the handle
1157                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1158                 private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
1159
1160 #endregion
1161
1162 #region Listen
1163
1164                 public void Listen (int backlog)
1165                 {
1166                         ThrowIfDisposedAndClosed ();
1167
1168                         if (!is_bound)
1169                                 throw new SocketException ((int) SocketError.InvalidArgument);
1170
1171                         int error;
1172                         Listen_internal(safe_handle, backlog, out error);
1173
1174                         if (error != 0)
1175                                 throw new SocketException (error);
1176
1177                         is_listening = true;
1178                 }
1179
1180                 static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
1181                 {
1182                         bool release = false;
1183                         try {
1184                                 safeHandle.DangerousAddRef (ref release);
1185                                 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
1186                         } finally {
1187                                 if (release)
1188                                         safeHandle.DangerousRelease ();
1189                         }
1190                 }
1191
1192                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1193                 extern static void Listen_internal (IntPtr sock, int backlog, out int error);
1194
1195 #endregion
1196
1197 #region Connect
1198
1199                 public void Connect (IPAddress address, int port)
1200                 {
1201                         Connect (new IPEndPoint (address, port));
1202                 }
1203
1204                 public void Connect (string host, int port)
1205                 {
1206                         Connect (Dns.GetHostAddresses (host), port);
1207                 }
1208
1209                 public void Connect (IPAddress[] addresses, int port)
1210                 {
1211                         ThrowIfDisposedAndClosed ();
1212
1213                         if (addresses == null)
1214                                 throw new ArgumentNullException ("addresses");
1215                         if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1216                                 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1217                         if (is_listening)
1218                                 throw new InvalidOperationException ();
1219
1220                         // FIXME: do non-blocking sockets Poll here?
1221                         int error = 0;
1222                         foreach (IPAddress address in addresses) {
1223                                 IPEndPoint iep = new IPEndPoint (address, port);
1224                                 
1225                                 iep = RemapIPEndPoint (iep);
1226
1227                                 Connect_internal (safe_handle, iep.Serialize (), out error);
1228                                 if (error == 0) {
1229                                         is_connected = true;
1230                                         is_bound = true;
1231                                         seed_endpoint = iep;
1232                                         return;
1233                                 }
1234                                 if (error != (int)SocketError.InProgress && error != (int)SocketError.WouldBlock)
1235                                         continue;
1236
1237                                 if (!is_blocking) {
1238                                         Poll (-1, SelectMode.SelectWrite);
1239                                         error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1240                                         if (error == 0) {
1241                                                 is_connected = true;
1242                                                 is_bound = true;
1243                                                 seed_endpoint = iep;
1244                                                 return;
1245                                         }
1246                                 }
1247                         }
1248
1249                         if (error != 0)
1250                                 throw new SocketException (error);
1251                 }
1252
1253
1254                 public void Connect (EndPoint remoteEP)
1255                 {
1256                         ThrowIfDisposedAndClosed ();
1257
1258                         if (remoteEP == null)
1259                                 throw new ArgumentNullException ("remoteEP");
1260
1261                         IPEndPoint ep = remoteEP as IPEndPoint;
1262                         /* Dgram uses Any to 'disconnect' */
1263                         if (ep != null && socket_type != SocketType.Dgram) {
1264                                 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1265                                         throw new SocketException ((int) SocketError.AddressNotAvailable);
1266                         }
1267
1268                         if (is_listening)
1269                                 throw new InvalidOperationException ();
1270                                 
1271                         if (ep != null) {
1272                                 remoteEP = RemapIPEndPoint (ep);
1273                         }
1274
1275                         SocketAddress serial = remoteEP.Serialize ();
1276
1277                         int error = 0;
1278                         Connect_internal (safe_handle, serial, out error);
1279
1280                         if (error == 0 || error == 10035)
1281                                 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1282
1283                         if (error != 0) {
1284                                 if (is_closed)
1285                                         error = SOCKET_CLOSED_CODE;
1286                                 throw new SocketException (error);
1287                         }
1288
1289                         is_connected = !(socket_type == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
1290                         is_bound = true;
1291                 }
1292
1293                 public bool ConnectAsync (SocketAsyncEventArgs e)
1294                 {
1295                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1296
1297                         ThrowIfDisposedAndClosed ();
1298
1299                         if (is_listening)
1300                                 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1301                         if (e.RemoteEndPoint == null)
1302                                 throw new ArgumentNullException ("remoteEP");
1303
1304                         InitSocketAsyncEventArgs (e, null, e, SocketOperation.Connect);
1305
1306                         try {
1307                                 IPAddress [] addresses;
1308                                 SocketAsyncResult ares;
1309
1310                                 if (!GetCheckedIPs (e, out addresses)) {
1311                                         e.socket_async_result.EndPoint = e.RemoteEndPoint;
1312                                         ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
1313                                 } else {
1314                                         DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1315                                         e.socket_async_result.Addresses = addresses;
1316                                         e.socket_async_result.Port = dep.Port;
1317                                         ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
1318                                 }
1319
1320                                 if (ares.IsCompleted && ares.CompletedSynchronously) {
1321                                         ares.CheckIfThrowDelayedException ();
1322                                         return false;
1323                                 }
1324                         } catch (Exception exc) {
1325                                 e.socket_async_result.Complete (exc, true);
1326                                 return false;
1327                         }
1328
1329                         return true;
1330                 }
1331
1332                 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
1333                 {
1334                         var sock = new Socket (e.RemoteEndPoint.AddressFamily, socketType, protocolType);
1335                         return sock.ConnectAsync (e);
1336                 }
1337
1338                 public static void CancelConnectAsync (SocketAsyncEventArgs e)
1339                 {
1340                         if (e == null)
1341                                 throw new ArgumentNullException("e");
1342
1343                         if (e.in_progress != 0 && e.LastOperation == SocketAsyncOperation.Connect)
1344                                 e.current_socket.Close();
1345                 }
1346
1347                 static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
1348                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1349
1350                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1351                                 throw new InvalidOperationException ("No operation in progress");
1352
1353                         try {
1354                                 e.current_socket.EndConnect (ares);
1355                         } catch (SocketException se) {
1356                                 e.SocketError = se.SocketErrorCode;
1357                         } catch (ObjectDisposedException) {
1358                                 e.SocketError = SocketError.OperationAborted;
1359                         } finally {
1360                                 e.Complete ();
1361                         }
1362                 });
1363
1364                 public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback callback, object state)
1365                 {
1366                         ThrowIfDisposedAndClosed ();
1367
1368                         if (address == null)
1369                                 throw new ArgumentNullException ("address");
1370                         if (address.ToString ().Length == 0)
1371                                 throw new ArgumentException ("The length of the IP address is zero");
1372                         if (port <= 0 || port > 65535)
1373                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1374                         if (is_listening)
1375                                 throw new InvalidOperationException ();
1376
1377                         return BeginConnect (new IPEndPoint (address, port), callback, state);
1378                 }
1379
1380                 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
1381                 {
1382                         ThrowIfDisposedAndClosed ();
1383
1384                         if (host == null)
1385                                 throw new ArgumentNullException ("host");
1386                         if (address_family != AddressFamily.InterNetwork && address_family != AddressFamily.InterNetworkV6)
1387                                 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1388                         if (port <= 0 || port > 65535)
1389                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1390                         if (is_listening)
1391                                 throw new InvalidOperationException ();
1392
1393                         return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1394                 }
1395
1396                 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
1397                 {
1398                         ThrowIfDisposedAndClosed ();
1399
1400                         if (end_point == null)
1401                                 throw new ArgumentNullException ("end_point");
1402
1403                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1404                                 EndPoint = end_point,
1405                         };
1406
1407                         // Bug #75154: Connect() should not succeed for .Any addresses.
1408                         if (end_point is IPEndPoint) {
1409                                 IPEndPoint ep = (IPEndPoint) end_point;
1410                                 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1411                                         sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1412                                         return sockares;
1413                                 }
1414                                 
1415                                 end_point = RemapIPEndPoint (ep);
1416                         }
1417
1418                         int error = 0;
1419
1420                         if (connect_in_progress) {
1421                                 // This could happen when multiple IPs are used
1422                                 // Calling connect() again will reset the connection attempt and cause
1423                                 // an error. Better to just close the socket and move on.
1424                                 connect_in_progress = false;
1425                                 safe_handle.Dispose ();
1426                                 safe_handle = new SafeSocketHandle (Socket_internal (address_family, socket_type, protocol_type, out error), true);
1427                                 if (error != 0)
1428                                         throw new SocketException (error);
1429                         }
1430
1431                         bool blk = is_blocking;
1432                         if (blk)
1433                                 Blocking = false;
1434                         Connect_internal (safe_handle, end_point.Serialize (), out error);
1435                         if (blk)
1436                                 Blocking = true;
1437
1438                         if (error == 0) {
1439                                 // succeeded synch
1440                                 is_connected = true;
1441                                 is_bound = true;
1442                                 sockares.Complete (true);
1443                                 return sockares;
1444                         }
1445
1446                         if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1447                                 // error synch
1448                                 is_connected = false;
1449                                 is_bound = false;
1450                                 sockares.Complete (new SocketException (error), true);
1451                                 return sockares;
1452                         }
1453
1454                         // continue asynch
1455                         is_connected = false;
1456                         is_bound = false;
1457                         connect_in_progress = true;
1458
1459                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
1460
1461                         return sockares;
1462                 }
1463
1464                 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1465                 {
1466                         ThrowIfDisposedAndClosed ();
1467
1468                         if (addresses == null)
1469                                 throw new ArgumentNullException ("addresses");
1470                         if (addresses.Length == 0)
1471                                 throw new ArgumentException ("Empty addresses list");
1472                         if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1473                                 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1474                         if (port <= 0 || port > 65535)
1475                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1476                         if (is_listening)
1477                                 throw new InvalidOperationException ();
1478
1479                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1480                                 Addresses = addresses,
1481                                 Port = port,
1482                         };
1483
1484                         is_connected = false;
1485
1486                         return BeginMConnect (sockares);
1487                 }
1488
1489                 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1490                 {
1491                         SocketAsyncResult ares = null;
1492                         Exception exc = null;
1493                         AsyncCallback callback;
1494
1495                         for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1496                                 try {
1497                                         sockares.CurrentAddress++;
1498
1499                                         ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1500                                         if (ares.IsCompleted && ares.CompletedSynchronously) {
1501                                                 ares.CheckIfThrowDelayedException ();
1502
1503                                                 callback = ares.AsyncCallback;
1504                                                 if (callback != null)
1505                                                         ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
1506                                         }
1507
1508                                         break;
1509                                 } catch (Exception e) {
1510                                         exc = e;
1511                                         ares = null;
1512                                 }
1513                         }
1514
1515                         if (ares == null)
1516                                 throw exc;
1517
1518                         return sockares;
1519                 }
1520
1521                 static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
1522                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1523
1524                         if (sockares.EndPoint == null) {
1525                                 sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
1526                                 return;
1527                         }
1528
1529                         SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
1530                         bool is_mconnect = mconnect != null && mconnect.Addresses != null;
1531
1532                         try {
1533                                 EndPoint ep = sockares.EndPoint;
1534                                 int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1535
1536                                 if (error_code == 0) {
1537                                         if (is_mconnect)
1538                                                 sockares = mconnect;
1539
1540                                         sockares.socket.seed_endpoint = ep;
1541                                         sockares.socket.is_connected = true;
1542                                         sockares.socket.is_bound = true;
1543                                         sockares.socket.connect_in_progress = false;
1544                                         sockares.error = 0;
1545                                         sockares.Complete ();
1546                                         return;
1547                                 }
1548
1549                                 if (!is_mconnect) {
1550                                         sockares.socket.connect_in_progress = false;
1551                                         sockares.Complete (new SocketException (error_code));
1552                                         return;
1553                                 }
1554
1555                                 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
1556                                         mconnect.Complete (new SocketException (error_code));
1557                                         return;
1558                                 }
1559
1560                                 mconnect.socket.BeginMConnect (mconnect);
1561                         } catch (Exception e) {
1562                                 sockares.socket.connect_in_progress = false;
1563
1564                                 if (is_mconnect)
1565                                         sockares = mconnect;
1566
1567                                 sockares.Complete (e);
1568                                 return;
1569                         }
1570                 });
1571
1572                 public void EndConnect (IAsyncResult result)
1573                 {
1574                         ThrowIfDisposedAndClosed ();
1575
1576                         SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1577
1578                         if (!sockares.IsCompleted)
1579                                 sockares.AsyncWaitHandle.WaitOne();
1580
1581                         sockares.CheckIfThrowDelayedException();
1582                 }
1583
1584                 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1585                 {
1586                         try {
1587                                 safeHandle.RegisterForBlockingSyscall ();
1588                                 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
1589                         } finally {
1590                                 safeHandle.UnRegisterForBlockingSyscall ();
1591                         }
1592                 }
1593
1594                 /* Connects to the remote address */
1595                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1596                 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error);
1597
1598                 /* Returns :
1599                  *  - false when it is ok to use RemoteEndPoint
1600                  *  - true when addresses must be used (and addresses could be null/empty) */
1601                 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1602                 {
1603                         addresses = null;
1604
1605                         // Connect to the first address that match the host name, like:
1606                         // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1607                         // while skipping entries that do not match the address family
1608                         DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1609                         if (dep != null) {
1610                                 addresses = Dns.GetHostAddresses (dep.Host);
1611                                 return true;
1612                         } else {
1613                                 e.ConnectByNameError = null;
1614                                 return false;
1615                         }
1616                 }
1617
1618 #endregion
1619
1620 #region Disconnect
1621
1622                 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1623                  * if the platform is newer than w2k.  We should be able to cope... */
1624                 public void Disconnect (bool reuseSocket)
1625                 {
1626                         ThrowIfDisposedAndClosed ();
1627
1628                         int error = 0;
1629                         Disconnect_internal (safe_handle, reuseSocket, out error);
1630
1631                         if (error != 0) {
1632                                 if (error == 50) {
1633                                         /* ERROR_NOT_SUPPORTED */
1634                                         throw new PlatformNotSupportedException ();
1635                                 } else {
1636                                         throw new SocketException (error);
1637                                 }
1638                         }
1639
1640                         is_connected = false;
1641                         if (reuseSocket) {
1642                                 /* Do managed housekeeping here... */
1643                         }
1644                 }
1645
1646                 public bool DisconnectAsync (SocketAsyncEventArgs e)
1647                 {
1648                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1649
1650                         ThrowIfDisposedAndClosed ();
1651
1652                         InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
1653
1654                         IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
1655
1656                         return true;
1657                 }
1658
1659                 static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
1660                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1661
1662                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1663                                 throw new InvalidOperationException ("No operation in progress");
1664
1665                         try {
1666                                 e.current_socket.EndDisconnect (ares);
1667                         } catch (SocketException ex) {
1668                                 e.SocketError = ex.SocketErrorCode;
1669                         } catch (ObjectDisposedException) {
1670                                 e.SocketError = SocketError.OperationAborted;
1671                         } finally {
1672                                 e.Complete ();
1673                         }
1674                 });
1675
1676                 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1677                 {
1678                         ThrowIfDisposedAndClosed ();
1679
1680                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1681                                 ReuseSocket = reuseSocket,
1682                         };
1683
1684                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
1685
1686                         return sockares;
1687                 }
1688
1689                 static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
1690                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1691
1692                         try {
1693                                 sockares.socket.Disconnect (sockares.ReuseSocket);
1694                         } catch (Exception e) {
1695                                 sockares.Complete (e);
1696                                 return;
1697                         }
1698
1699                         sockares.Complete ();
1700                 });
1701
1702                 public void EndDisconnect (IAsyncResult asyncResult)
1703                 {
1704                         ThrowIfDisposedAndClosed ();
1705
1706                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1707
1708                         if (!sockares.IsCompleted)
1709                                 sockares.AsyncWaitHandle.WaitOne ();
1710
1711                         sockares.CheckIfThrowDelayedException ();
1712                 }
1713
1714                 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1715                 {
1716                         bool release = false;
1717                         try {
1718                                 safeHandle.DangerousAddRef (ref release);
1719                                 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1720                         } finally {
1721                                 if (release)
1722                                         safeHandle.DangerousRelease ();
1723                         }
1724                 }
1725
1726                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1727                 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1728
1729 #endregion
1730
1731 #region Receive
1732
1733                 public int Receive (byte [] buffer)
1734                 {
1735                         return Receive (buffer, SocketFlags.None);
1736                 }
1737
1738                 public int Receive (byte [] buffer, SocketFlags socketFlags)
1739                 {
1740                         ThrowIfDisposedAndClosed ();
1741                         ThrowIfBufferNull (buffer);
1742                         ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
1743
1744                         SocketError error;
1745                         int ret = Receive_nochecks (buffer, 0, buffer.Length, socketFlags, out error);
1746
1747                         if (error != SocketError.Success) {
1748                                 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1749                                         throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1750                                 throw new SocketException ((int) error);
1751                         }
1752
1753                         return ret;
1754                 }
1755
1756                 public int Receive (byte [] buffer, int size, SocketFlags socketFlags)
1757                 {
1758                         ThrowIfDisposedAndClosed ();
1759                         ThrowIfBufferNull (buffer);
1760                         ThrowIfBufferOutOfRange (buffer, 0, size);
1761
1762                         SocketError error;
1763                         int ret = Receive_nochecks (buffer, 0, size, socketFlags, out error);
1764
1765                         if (error != SocketError.Success) {
1766                                 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1767                                         throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1768                                 throw new SocketException ((int) error);
1769                         }
1770
1771                         return ret;
1772                 }
1773
1774                 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags)
1775                 {
1776                         ThrowIfDisposedAndClosed ();
1777                         ThrowIfBufferNull (buffer);
1778                         ThrowIfBufferOutOfRange (buffer, offset, size);
1779
1780                         SocketError error;
1781                         int ret = Receive_nochecks (buffer, offset, size, socketFlags, out error);
1782
1783                         if (error != SocketError.Success) {
1784                                 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1785                                         throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1786                                 throw new SocketException ((int) error);
1787                         }
1788
1789                         return ret;
1790                 }
1791
1792                 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1793                 {
1794                         ThrowIfDisposedAndClosed ();
1795                         ThrowIfBufferNull (buffer);
1796                         ThrowIfBufferOutOfRange (buffer, offset, size);
1797
1798                         return Receive_nochecks (buffer, offset, size, socketFlags, out errorCode);
1799                 }
1800
1801                 public int Receive (IList<ArraySegment<byte>> buffers)
1802                 {
1803                         SocketError error;
1804                         int ret = Receive (buffers, SocketFlags.None, out error);
1805
1806                         if (error != SocketError.Success)
1807                                 throw new SocketException ((int) error);
1808
1809                         return ret;
1810                 }
1811
1812                 [CLSCompliant (false)]
1813                 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1814                 {
1815                         SocketError error;
1816                         int ret = Receive (buffers, socketFlags, out error);
1817
1818                         if (error != SocketError.Success)
1819                                 throw new SocketException ((int) error);
1820
1821                         return(ret);
1822                 }
1823
1824                 [CLSCompliant (false)]
1825                 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1826                 {
1827                         ThrowIfDisposedAndClosed ();
1828
1829                         if (buffers == null || buffers.Count == 0)
1830                                 throw new ArgumentNullException ("buffers");
1831
1832                         int numsegments = buffers.Count;
1833                         int nativeError;
1834                         int ret;
1835
1836                         /* Only example I can find of sending a byte array reference directly into an internal
1837                          * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1838                          * so taking a lead from that... */
1839                         WSABUF[] bufarray = new WSABUF[numsegments];
1840                         GCHandle[] gch = new GCHandle[numsegments];
1841
1842                         for (int i = 0; i < numsegments; i++) {
1843                                 ArraySegment<byte> segment = buffers[i];
1844
1845                                 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1846                                         throw new ArgumentOutOfRangeException ("segment");
1847
1848                                 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1849                                 bufarray[i].len = segment.Count;
1850                                 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1851                         }
1852
1853                         try {
1854                                 ret = Receive_internal (safe_handle, bufarray, socketFlags, out nativeError);
1855                         } finally {
1856                                 for (int i = 0; i < numsegments; i++) {
1857                                         if (gch[i].IsAllocated)
1858                                                 gch[i].Free ();
1859                                 }
1860                         }
1861
1862                         errorCode = (SocketError) nativeError;
1863
1864                         return ret;
1865                 }
1866
1867                 public bool ReceiveAsync (SocketAsyncEventArgs e)
1868                 {
1869                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1870
1871                         ThrowIfDisposedAndClosed ();
1872
1873                         // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1874                         // thrown when e.Buffer and e.BufferList are null (works fine when one is
1875                         // set to a valid object)
1876                         if (e.Buffer == null && e.BufferList == null)
1877                                 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1878
1879                         if (e.Buffer == null) {
1880                                 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
1881
1882                                 e.socket_async_result.Buffers = e.BufferList;
1883
1884                                 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
1885                         } else {
1886                                 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
1887
1888                                 e.socket_async_result.Buffer = e.Buffer;
1889                                 e.socket_async_result.Offset = e.Offset;
1890                                 e.socket_async_result.Size = e.Count;
1891
1892                                 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
1893                         }
1894
1895                         return true;
1896                 }
1897
1898                 static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
1899                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1900
1901                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1902                                 throw new InvalidOperationException ("No operation in progress");
1903
1904                         try {
1905                                 e.BytesTransferred = e.current_socket.EndReceive (ares);
1906                         } catch (SocketException se){
1907                                 e.SocketError = se.SocketErrorCode;
1908                         } catch (ObjectDisposedException) {
1909                                 e.SocketError = SocketError.OperationAborted;
1910                         } finally {
1911                                 e.Complete ();
1912                         }
1913                 });
1914
1915                 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
1916                 {
1917                         ThrowIfDisposedAndClosed ();
1918                         ThrowIfBufferNull (buffer);
1919                         ThrowIfBufferOutOfRange (buffer, offset, size);
1920
1921                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1922                                 Buffer = buffer,
1923                                 Offset = offset,
1924                                 Size = size,
1925                                 SockFlags = socket_flags,
1926                         };
1927
1928                         QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
1929
1930                         return sockares;
1931                 }
1932
1933                 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags flags, out SocketError error, AsyncCallback callback, object state)
1934                 {
1935                         /* As far as I can tell from the docs and from experimentation, a pointer to the
1936                          * SocketError parameter is not supposed to be saved for the async parts.  And as we don't
1937                          * set any socket errors in the setup code, we just have to set it to Success. */
1938                         error = SocketError.Success;
1939                         return BeginReceive (buffer, offset, size, flags, callback, state);
1940                 }
1941
1942                 static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
1943                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1944                         int total = 0;
1945
1946                         try {
1947                                 total = Receive_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
1948                         } catch (Exception e) {
1949                                 sockares.Complete (e);
1950                                 return;
1951                         }
1952
1953                         sockares.Complete (total);
1954                 });
1955
1956                 [CLSCompliant (false)]
1957                 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
1958                 {
1959                         ThrowIfDisposedAndClosed ();
1960
1961                         if (buffers == null)
1962                                 throw new ArgumentNullException ("buffers");
1963
1964                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1965                                 Buffers = buffers,
1966                                 SockFlags = socketFlags,
1967                         };
1968
1969                         QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
1970
1971                         return sockares;
1972                 }
1973
1974                 [CLSCompliant (false)]
1975                 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1976                 {
1977                         /* I assume the same SocketError semantics as above */
1978                         errorCode = SocketError.Success;
1979                         return BeginReceive (buffers, socketFlags, callback, state);
1980                 }
1981
1982                 static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
1983                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1984                         int total = 0;
1985
1986                         try {
1987                                 total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
1988                         } catch (Exception e) {
1989                                 sockares.Complete (e);
1990                                 return;
1991                         }
1992
1993                         sockares.Complete (total);
1994                 });
1995
1996                 public int EndReceive (IAsyncResult result)
1997                 {
1998                         SocketError error;
1999                         int bytesReceived = EndReceive (result, out error);
2000
2001                         if (error != SocketError.Success) {
2002                                 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2003                                         is_connected = false;
2004                                 throw new SocketException ((int)error);
2005                         }
2006
2007                         return bytesReceived;
2008                 }
2009
2010                 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
2011                 {
2012                         ThrowIfDisposedAndClosed ();
2013
2014                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
2015
2016                         if (!sockares.IsCompleted)
2017                                 sockares.AsyncWaitHandle.WaitOne ();
2018
2019                         // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
2020                         // kinds of exceptions that should be thrown.
2021                         if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2022                                 sockares.CheckIfThrowDelayedException();
2023
2024                         return sockares.Total;
2025                 }
2026
2027                 int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2028                 {
2029                         int nativeError;
2030                         int ret = Receive_internal (safe_handle, buf, offset, size, flags, out nativeError);
2031
2032                         error = (SocketError) nativeError;
2033                         if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2034                                 is_connected = false;
2035                                 is_bound = false;
2036                         } else {
2037                                 is_connected = true;
2038                         }
2039
2040                         return ret;
2041                 }
2042
2043                 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2044                 {
2045                         try {
2046                                 safeHandle.RegisterForBlockingSyscall ();
2047                                 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2048                         } finally {
2049                                 safeHandle.UnRegisterForBlockingSyscall ();
2050                         }
2051                 }
2052
2053                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2054                 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2055
2056                 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
2057                 {
2058                         try {
2059                                 safeHandle.RegisterForBlockingSyscall ();
2060                                 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
2061                         } finally {
2062                                 safeHandle.UnRegisterForBlockingSyscall ();
2063                         }
2064                 }
2065
2066                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2067                 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error);
2068
2069 #endregion
2070
2071 #region ReceiveFrom
2072
2073                 public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
2074                 {
2075                         ThrowIfDisposedAndClosed ();
2076                         ThrowIfBufferNull (buffer);
2077
2078                         return ReceiveFrom (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
2079                 }
2080
2081                 public int ReceiveFrom (byte [] buffer, SocketFlags socketFlags, ref EndPoint remoteEP)
2082                 {
2083                         ThrowIfDisposedAndClosed ();
2084                         ThrowIfBufferNull (buffer);
2085
2086                         return ReceiveFrom (buffer, 0, buffer.Length, socketFlags, ref remoteEP);
2087                 }
2088
2089                 public int ReceiveFrom (byte [] buffer, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
2090                 {
2091                         ThrowIfDisposedAndClosed ();
2092                         ThrowIfBufferNull (buffer);
2093                         ThrowIfBufferOutOfRange (buffer, 0, size);
2094
2095                         return ReceiveFrom (buffer, 0, size, socketFlags, ref remoteEP);
2096                 }
2097
2098                 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
2099                 {
2100                         ThrowIfDisposedAndClosed ();
2101                         ThrowIfBufferNull (buffer);
2102                         ThrowIfBufferOutOfRange (buffer, offset, size);
2103
2104                         if (remoteEP == null)
2105                                 throw new ArgumentNullException ("remoteEP");
2106
2107                         int error;
2108                         return ReceiveFrom_nochecks_exc (buffer, offset, size, socketFlags, ref remoteEP, true, out error);
2109                 }
2110
2111                 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
2112                 {
2113                         ThrowIfDisposedAndClosed ();
2114
2115                         // We do not support recv into multiple buffers yet
2116                         if (e.BufferList != null)
2117                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2118                         if (e.RemoteEndPoint == null)
2119                                 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2120
2121                         InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
2122
2123                         e.socket_async_result.Buffer = e.Buffer;
2124                         e.socket_async_result.Offset = e.Offset;
2125                         e.socket_async_result.Size = e.Count;
2126                         e.socket_async_result.EndPoint = e.RemoteEndPoint;
2127                         e.socket_async_result.SockFlags = e.SocketFlags;
2128
2129                         QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
2130
2131                         return true;
2132                 }
2133
2134                 static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
2135                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2136
2137                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2138                                 throw new InvalidOperationException ("No operation in progress");
2139
2140                         try {
2141                                 e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
2142                         } catch (SocketException ex) {
2143                                 e.SocketError = ex.SocketErrorCode;
2144                         } catch (ObjectDisposedException) {
2145                                 e.SocketError = SocketError.OperationAborted;
2146                         } finally {
2147                                 e.Complete ();
2148                         }
2149                 });
2150
2151                 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
2152                 {
2153                         ThrowIfDisposedAndClosed ();
2154                         ThrowIfBufferNull (buffer);
2155                         ThrowIfBufferOutOfRange (buffer, offset, size);
2156
2157                         if (remote_end == null)
2158                                 throw new ArgumentNullException ("remote_end");
2159
2160                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
2161                                 Buffer = buffer,
2162                                 Offset = offset,
2163                                 Size = size,
2164                                 SockFlags = socket_flags,
2165                                 EndPoint = remote_end,
2166                         };
2167
2168                         QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
2169
2170                         return sockares;
2171                 }
2172
2173                 static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
2174                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
2175                         int total = 0;
2176
2177                         try {
2178                                 int error;
2179                                 total = sockares.socket.ReceiveFrom_nochecks_exc (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, true, out error);
2180                         } catch (Exception e) {
2181                                 sockares.Complete (e);
2182                                 return;
2183                         }
2184
2185                         sockares.Complete (total);
2186                 });
2187
2188                 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
2189                 {
2190                         ThrowIfDisposedAndClosed ();
2191
2192                         if (end_point == null)
2193                                 throw new ArgumentNullException ("remote_end");
2194
2195                         SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
2196
2197                         if (!sockares.IsCompleted)
2198                                 sockares.AsyncWaitHandle.WaitOne();
2199
2200                         sockares.CheckIfThrowDelayedException();
2201
2202                         end_point = sockares.EndPoint;
2203
2204                         return sockares.Total;
2205                 }
2206
2207                 internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end, bool throwOnError, out int error)
2208                 {
2209                         SocketAddress sockaddr = remote_end.Serialize();
2210
2211                         int cnt = ReceiveFrom_internal (safe_handle, buf, offset, size, flags, ref sockaddr, out error);
2212
2213                         SocketError err = (SocketError) error;
2214                         if (err != 0) {
2215                                 if (err != SocketError.WouldBlock && err != SocketError.InProgress) {
2216                                         is_connected = false;
2217                                 } else if (err == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
2218                                         if (throwOnError)       
2219                                                 throw new SocketException ((int) SocketError.TimedOut, TIMEOUT_EXCEPTION_MSG);
2220                                         error = (int) SocketError.TimedOut;
2221                                         return 0;
2222                                 }
2223
2224                                 if (throwOnError)
2225                                         throw new SocketException (error);
2226
2227                                 return 0;
2228                         }
2229
2230                         is_connected = true;
2231                         is_bound = true;
2232
2233                         /* If sockaddr is null then we're a connection oriented protocol and should ignore the
2234                          * remote_end parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
2235                         if (sockaddr != null) {
2236                                 /* Stupidly, EndPoint.Create() is an instance method */
2237                                 remote_end = remote_end.Create (sockaddr);
2238                         }
2239
2240                         seed_endpoint = remote_end;
2241
2242                         return cnt;
2243                 }
2244
2245                 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error)
2246                 {
2247                         try {
2248                                 safeHandle.RegisterForBlockingSyscall ();
2249                                 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
2250                         } finally {
2251                                 safeHandle.UnRegisterForBlockingSyscall ();
2252                         }
2253                 }
2254
2255                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2256                 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error);
2257
2258 #endregion
2259
2260 #region ReceiveMessageFrom
2261
2262                 [MonoTODO ("Not implemented")]
2263                 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
2264                 {
2265                         ThrowIfDisposedAndClosed ();
2266                         ThrowIfBufferNull (buffer);
2267                         ThrowIfBufferOutOfRange (buffer, offset, size);
2268
2269                         if (remoteEP == null)
2270                                 throw new ArgumentNullException ("remoteEP");
2271
2272                         // FIXME: figure out how we get hold of the IPPacketInformation
2273                         throw new NotImplementedException ();
2274                 }
2275
2276                 [MonoTODO ("Not implemented")]
2277                 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
2278                 {
2279                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2280
2281                         ThrowIfDisposedAndClosed ();
2282
2283                         throw new NotImplementedException ();
2284                 }
2285
2286                 [MonoTODO]
2287                 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
2288                 {
2289                         ThrowIfDisposedAndClosed ();
2290                         ThrowIfBufferNull (buffer);
2291                         ThrowIfBufferOutOfRange (buffer, offset, size);
2292
2293                         if (remoteEP == null)
2294                                 throw new ArgumentNullException ("remoteEP");
2295
2296                         throw new NotImplementedException ();
2297                 }
2298
2299                 [MonoTODO]
2300                 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
2301                 {
2302                         ThrowIfDisposedAndClosed ();
2303
2304                         if (endPoint == null)
2305                                 throw new ArgumentNullException ("endPoint");
2306
2307                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
2308
2309                         throw new NotImplementedException ();
2310                 }
2311
2312 #endregion
2313
2314 #region Send
2315
2316                 public int Send (byte [] buffer)
2317                 {
2318                         ThrowIfDisposedAndClosed ();
2319                         ThrowIfBufferNull (buffer);
2320                         ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2321
2322                         SocketError error;
2323                         int ret = Send_nochecks (buffer, 0, buffer.Length, SocketFlags.None, out error);
2324
2325                         if (error != SocketError.Success)
2326                                 throw new SocketException ((int) error);
2327
2328                         return ret;
2329                 }
2330
2331                 public int Send (byte [] buffer, SocketFlags socketFlags)
2332                 {
2333                         ThrowIfDisposedAndClosed ();
2334                         ThrowIfBufferNull (buffer);
2335                         ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2336
2337                         SocketError error;
2338                         int ret = Send_nochecks (buffer, 0, buffer.Length, socketFlags, out error);
2339
2340                         if (error != SocketError.Success)
2341                                 throw new SocketException ((int) error);
2342
2343                         return ret;
2344                 }
2345
2346                 public int Send (byte [] buffer, int size, SocketFlags socketFlags)
2347                 {
2348                         ThrowIfDisposedAndClosed ();
2349                         ThrowIfBufferNull (buffer);
2350                         ThrowIfBufferOutOfRange (buffer, 0, size);
2351
2352                         SocketError error;
2353                         int ret = Send_nochecks (buffer, 0, size, socketFlags, out error);
2354
2355                         if (error != SocketError.Success)
2356                                 throw new SocketException ((int) error);
2357
2358                         return ret;
2359                 }
2360
2361                 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags)
2362                 {
2363                         ThrowIfDisposedAndClosed ();
2364                         ThrowIfBufferNull (buffer);
2365                         ThrowIfBufferOutOfRange (buffer, offset, size);
2366
2367                         SocketError error;
2368                         int ret = Send_nochecks (buffer, offset, size, socketFlags, out error);
2369
2370                         if (error != SocketError.Success)
2371                                 throw new SocketException ((int) error);
2372
2373                         return ret;
2374                 }
2375
2376                 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
2377                 {
2378                         ThrowIfDisposedAndClosed ();
2379                         ThrowIfBufferNull (buffer);
2380                         ThrowIfBufferOutOfRange (buffer, offset, size);
2381
2382                         return Send_nochecks (buffer, offset, size, socketFlags, out errorCode);
2383                 }
2384
2385                 public
2386                 int Send (IList<ArraySegment<byte>> buffers)
2387                 {
2388                         SocketError error;
2389                         int ret = Send (buffers, SocketFlags.None, out error);
2390
2391                         if (error != SocketError.Success)
2392                                 throw new SocketException ((int) error);
2393
2394                         return ret;
2395                 }
2396
2397                 public
2398                 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
2399                 {
2400                         SocketError error;
2401                         int ret = Send (buffers, socketFlags, out error);
2402
2403                         if (error != SocketError.Success)
2404                                 throw new SocketException ((int) error);
2405
2406                         return ret;
2407                 }
2408
2409                 [CLSCompliant (false)]
2410                 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
2411                 {
2412                         ThrowIfDisposedAndClosed ();
2413
2414                         if (buffers == null)
2415                                 throw new ArgumentNullException ("buffers");
2416                         if (buffers.Count == 0)
2417                                 throw new ArgumentException ("Buffer is empty", "buffers");
2418
2419                         int numsegments = buffers.Count;
2420                         int nativeError;
2421                         int ret;
2422
2423                         WSABUF[] bufarray = new WSABUF[numsegments];
2424                         GCHandle[] gch = new GCHandle[numsegments];
2425
2426                         for(int i = 0; i < numsegments; i++) {
2427                                 ArraySegment<byte> segment = buffers[i];
2428
2429                                 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
2430                                         throw new ArgumentOutOfRangeException ("segment");
2431
2432                                 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
2433                                 bufarray[i].len = segment.Count;
2434                                 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
2435                         }
2436
2437                         try {
2438                                 ret = Send_internal (safe_handle, bufarray, socketFlags, out nativeError);
2439                         } finally {
2440                                 for(int i = 0; i < numsegments; i++) {
2441                                         if (gch[i].IsAllocated) {
2442                                                 gch[i].Free ();
2443                                         }
2444                                 }
2445                         }
2446
2447                         errorCode = (SocketError)nativeError;
2448
2449                         return ret;
2450                 }
2451
2452                 int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2453                 {
2454                         if (size == 0) {
2455                                 error = SocketError.Success;
2456                                 return 0;
2457                         }
2458
2459                         int nativeError;
2460                         int ret = Send_internal (safe_handle, buf, offset, size, flags, out nativeError);
2461
2462                         error = (SocketError)nativeError;
2463
2464                         if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2465                                 is_connected = false;
2466                                 is_bound = false;
2467                         } else {
2468                                 is_connected = true;
2469                         }
2470
2471                         return ret;
2472                 }
2473
2474                 public bool SendAsync (SocketAsyncEventArgs e)
2475                 {
2476                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2477
2478                         ThrowIfDisposedAndClosed ();
2479
2480                         if (e.Buffer == null && e.BufferList == null)
2481                                 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
2482
2483                         if (e.Buffer == null) {
2484                                 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
2485
2486                                 e.socket_async_result.Buffers = e.BufferList;
2487
2488                                 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
2489                         } else {
2490                                 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
2491
2492                                 e.socket_async_result.Buffer = e.Buffer;
2493                                 e.socket_async_result.Offset = e.Offset;
2494                                 e.socket_async_result.Size = e.Count;
2495
2496                                 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2497                         }
2498
2499                         return true;
2500                 }
2501
2502                 static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
2503                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2504
2505                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2506                                 throw new InvalidOperationException ("No operation in progress");
2507
2508                         try {
2509                                 e.BytesTransferred = e.current_socket.EndSend (ares);
2510                         } catch (SocketException se){
2511                                 e.SocketError = se.SocketErrorCode;
2512                         } catch (ObjectDisposedException) {
2513                                 e.SocketError = SocketError.OperationAborted;
2514                         } finally {
2515                                 e.Complete ();
2516                         }
2517                 });
2518
2519                 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2520                 {
2521                         if (!is_connected) {
2522                                 errorCode = SocketError.NotConnected;
2523                                 throw new SocketException ((int) errorCode);
2524                         }
2525
2526                         errorCode = SocketError.Success;
2527                         return BeginSend (buffer, offset, size, socketFlags, callback, state);
2528                 }
2529
2530                 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
2531                 {
2532                         ThrowIfDisposedAndClosed ();
2533                         ThrowIfBufferNull (buffer);
2534                         ThrowIfBufferOutOfRange (buffer, offset, size);
2535
2536                         if (!is_connected)
2537                                 throw new SocketException ((int)SocketError.NotConnected);
2538
2539                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
2540                                 Buffer = buffer,
2541                                 Offset = offset,
2542                                 Size = size,
2543                                 SockFlags = socket_flags,
2544                         };
2545
2546                         QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
2547
2548                         return sockares;
2549                 }
2550
2551                 static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
2552                 {
2553                         int total = 0;
2554
2555                         try {
2556                                 total = Socket.Send_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
2557                         } catch (Exception e) {
2558                                 sockares.Complete (e);
2559                                 return;
2560                         }
2561
2562                         if (sockares.error == 0) {
2563                                 sent_so_far += total;
2564                                 sockares.Offset += total;
2565                                 sockares.Size -= total;
2566
2567                                 if (sockares.socket.is_disposed) {
2568                                         sockares.Complete (total);
2569                                         return;
2570                                 }
2571
2572                                 if (sockares.Size > 0) {
2573                                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2574                                         return; // Have to finish writing everything. See bug #74475.
2575                                 }
2576
2577                                 sockares.Total = sent_so_far;
2578                         }
2579
2580                         sockares.Complete (total);
2581                 }
2582
2583                 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
2584                 {
2585                         ThrowIfDisposedAndClosed ();
2586
2587                         if (buffers == null)
2588                                 throw new ArgumentNullException ("buffers");
2589                         if (!is_connected)
2590                                 throw new SocketException ((int)SocketError.NotConnected);
2591
2592                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
2593                                 Buffers = buffers,
2594                                 SockFlags = socketFlags,
2595                         };
2596
2597                         QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
2598
2599                         return sockares;
2600                 }
2601
2602                 [CLSCompliant (false)]
2603                 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2604                 {
2605                         if (!is_connected) {
2606                                 errorCode = SocketError.NotConnected;
2607                                 throw new SocketException ((int)errorCode);
2608                         }
2609
2610                         errorCode = SocketError.Success;
2611                         return BeginSend (buffers, socketFlags, callback, state);
2612                 }
2613
2614                 static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
2615                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
2616                         int total = 0;
2617
2618                         try {
2619                                 total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
2620                         } catch (Exception e) {
2621                                 sockares.Complete (e);
2622                                 return;
2623                         }
2624
2625                         sockares.Complete (total);
2626                 });
2627
2628                 public int EndSend (IAsyncResult result)
2629                 {
2630                         SocketError error;
2631                         int bytesSent = EndSend (result, out error);
2632
2633                         if (error != SocketError.Success) {
2634                                 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2635                                         is_connected = false;
2636                                 throw new SocketException ((int)error);
2637                         }
2638
2639                         return bytesSent;
2640                 }
2641
2642                 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
2643                 {
2644                         ThrowIfDisposedAndClosed ();
2645
2646                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
2647
2648                         if (!sockares.IsCompleted)
2649                                 sockares.AsyncWaitHandle.WaitOne ();
2650
2651                         /* If no socket error occurred, call CheckIfThrowDelayedException in
2652                          * case there are other kinds of exceptions that should be thrown.*/
2653                         if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2654                                 sockares.CheckIfThrowDelayedException ();
2655
2656                         return sockares.Total;
2657                 }
2658
2659                 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2660                 {
2661                         bool release = false;
2662                         try {
2663                                 safeHandle.DangerousAddRef (ref release);
2664                                 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2665                         } finally {
2666                                 if (release)
2667                                         safeHandle.DangerousRelease ();
2668                         }
2669                 }
2670
2671                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2672                 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2673
2674                 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
2675                 {
2676                         try {
2677                                 safeHandle.RegisterForBlockingSyscall ();
2678                                 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
2679                         } finally {
2680                                 safeHandle.UnRegisterForBlockingSyscall ();
2681                         }
2682                 }
2683
2684                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2685                 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
2686
2687 #endregion
2688
2689 #region SendTo
2690
2691                 public int SendTo (byte [] buffer, EndPoint remoteEP)
2692                 {
2693                         ThrowIfDisposedAndClosed ();
2694                         ThrowIfBufferNull (buffer);
2695
2696                         return SendTo (buffer, 0, buffer.Length, SocketFlags.None, remoteEP);
2697                 }
2698
2699                 public int SendTo (byte [] buffer, SocketFlags socketFlags, EndPoint remoteEP)
2700                 {
2701                         ThrowIfDisposedAndClosed ();
2702                         ThrowIfBufferNull (buffer);
2703
2704                         return SendTo (buffer, 0, buffer.Length, socketFlags, remoteEP);
2705                 }
2706
2707                 public int SendTo (byte [] buffer, int size, SocketFlags socketFlags, EndPoint remoteEP)
2708                 {
2709                         return SendTo (buffer, 0, size, socketFlags, remoteEP);
2710                 }
2711
2712                 public int SendTo (byte [] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP)
2713                 {
2714                         ThrowIfDisposedAndClosed ();
2715                         ThrowIfBufferNull (buffer);
2716                         ThrowIfBufferOutOfRange (buffer, offset, size);
2717
2718                         if (remoteEP == null)
2719                                 throw new ArgumentNullException("remoteEP");
2720
2721                         return SendTo_nochecks (buffer, offset, size, socketFlags, remoteEP);
2722                 }
2723
2724                 public bool SendToAsync (SocketAsyncEventArgs e)
2725                 {
2726                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2727
2728                         ThrowIfDisposedAndClosed ();
2729
2730                         if (e.BufferList != null)
2731                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2732                         if (e.RemoteEndPoint == null)
2733                                 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2734
2735                         InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2736
2737                         e.socket_async_result.Buffer = e.Buffer;
2738                         e.socket_async_result.Offset = e.Offset;
2739                         e.socket_async_result.Size = e.Count;
2740                         e.socket_async_result.SockFlags = e.SocketFlags;
2741                         e.socket_async_result.EndPoint = e.RemoteEndPoint;
2742
2743                         QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2744
2745                         return true;
2746                 }
2747
2748                 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2749                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2750
2751                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2752                                 throw new InvalidOperationException ("No operation in progress");
2753
2754                         try {
2755                                 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2756                         } catch (SocketException ex) {
2757                                 e.SocketError = ex.SocketErrorCode;
2758                         } catch (ObjectDisposedException) {
2759                                 e.SocketError = SocketError.OperationAborted;
2760                         } finally {
2761                                 e.Complete ();
2762                         }
2763                 });
2764
2765                 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2766                 {
2767                         ThrowIfDisposedAndClosed ();
2768                         ThrowIfBufferNull (buffer);
2769                         ThrowIfBufferOutOfRange (buffer, offset, size);
2770
2771                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2772                                 Buffer = buffer,
2773                                 Offset = offset,
2774                                 Size = size,
2775                                 SockFlags = socket_flags,
2776                                 EndPoint = remote_end,
2777                         };
2778
2779                         QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2780
2781                         return sockares;
2782                 }
2783
2784                 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2785                 {
2786                         int total = 0;
2787                         try {
2788                                 total = sockares.socket.SendTo_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2789
2790                                 if (sockares.error == 0) {
2791                                         sent_so_far += total;
2792                                         sockares.Offset += total;
2793                                         sockares.Size -= total;
2794                                 }
2795
2796                                 if (sockares.Size > 0) {
2797                                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2798                                         return; // Have to finish writing everything. See bug #74475.
2799                                 }
2800
2801                                 sockares.Total = sent_so_far;
2802                         } catch (Exception e) {
2803                                 sockares.Complete (e);
2804                                 return;
2805                         }
2806
2807                         sockares.Complete ();
2808                 }
2809
2810                 public int EndSendTo (IAsyncResult result)
2811                 {
2812                         ThrowIfDisposedAndClosed ();
2813
2814                         SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2815
2816                         if (!sockares.IsCompleted)
2817                                 sockares.AsyncWaitHandle.WaitOne();
2818
2819                         sockares.CheckIfThrowDelayedException();
2820
2821                         return sockares.Total;
2822                 }
2823
2824                 int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2825                 {
2826                         int error;
2827                         int ret = SendTo_internal (safe_handle, buffer, offset, size, flags, remote_end.Serialize (), out error);
2828
2829                         SocketError err = (SocketError) error;
2830                         if (err != 0) {
2831                                 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2832                                         is_connected = false;
2833                                 throw new SocketException (error);
2834                         }
2835
2836                         is_connected = true;
2837                         is_bound = true;
2838                         seed_endpoint = remote_end;
2839
2840                         return ret;
2841                 }
2842
2843                 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
2844                 {
2845                         try {
2846                                 safeHandle.RegisterForBlockingSyscall ();
2847                                 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
2848                         } finally {
2849                                 safeHandle.UnRegisterForBlockingSyscall ();
2850                         }
2851                 }
2852
2853                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2854                 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
2855
2856 #endregion
2857
2858 #region SendFile
2859
2860                 public void SendFile (string fileName)
2861                 {
2862                         ThrowIfDisposedAndClosed ();
2863
2864                         if (!is_connected)
2865                                 throw new NotSupportedException ();
2866                         if (!is_blocking)
2867                                 throw new InvalidOperationException ();
2868
2869                         SendFile (fileName, null, null, 0);
2870                 }
2871
2872                 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2873                 {
2874                         ThrowIfDisposedAndClosed ();
2875
2876                         if (!is_connected)
2877                                 throw new NotSupportedException ();
2878                         if (!is_blocking)
2879                                 throw new InvalidOperationException ();
2880
2881                         if (!SendFile_internal (safe_handle, fileName, preBuffer, postBuffer, flags)) {
2882                                 SocketException exc = new SocketException ();
2883                                 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2884                                         throw new FileNotFoundException ();
2885                                 throw exc;
2886                         }
2887                 }
2888
2889                 public IAsyncResult BeginSendFile (string fileName, AsyncCallback callback, object state)
2890                 {
2891                         ThrowIfDisposedAndClosed ();
2892
2893                         if (!is_connected)
2894                                 throw new NotSupportedException ();
2895                         if (!File.Exists (fileName))
2896                                 throw new FileNotFoundException ();
2897
2898                         return BeginSendFile (fileName, null, null, 0, callback, state);
2899                 }
2900
2901                 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2902                 {
2903                         ThrowIfDisposedAndClosed ();
2904
2905                         if (!is_connected)
2906                                 throw new NotSupportedException ();
2907                         if (!File.Exists (fileName))
2908                                 throw new FileNotFoundException ();
2909
2910                         SendFileHandler handler = new SendFileHandler (SendFile);
2911
2912                         return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2913                 }
2914
2915                 public void EndSendFile (IAsyncResult asyncResult)
2916                 {
2917                         ThrowIfDisposedAndClosed ();
2918
2919                         if (asyncResult == null)
2920                                 throw new ArgumentNullException ("asyncResult");
2921
2922                         SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2923                         if (ares == null)
2924                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2925
2926                         ares.Delegate.EndInvoke (ares.Original);
2927                 }
2928
2929                 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
2930                 {
2931                         try {
2932                                 safeHandle.RegisterForBlockingSyscall ();
2933                                 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
2934                         } finally {
2935                                 safeHandle.UnRegisterForBlockingSyscall ();
2936                         }
2937                 }
2938
2939                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2940                 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
2941
2942                 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2943
2944                 sealed class SendFileAsyncResult : IAsyncResult {
2945                         IAsyncResult ares;
2946                         SendFileHandler d;
2947
2948                         public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2949                         {
2950                                 this.d = d;
2951                                 this.ares = ares;
2952                         }
2953
2954                         public object AsyncState {
2955                                 get { return ares.AsyncState; }
2956                         }
2957
2958                         public WaitHandle AsyncWaitHandle {
2959                                 get { return ares.AsyncWaitHandle; }
2960                         }
2961
2962                         public bool CompletedSynchronously {
2963                                 get { return ares.CompletedSynchronously; }
2964                         }
2965
2966                         public bool IsCompleted {
2967                                 get { return ares.IsCompleted; }
2968                         }
2969
2970                         public SendFileHandler Delegate {
2971                                 get { return d; }
2972                         }
2973
2974                         public IAsyncResult Original {
2975                                 get { return ares; }
2976                         }
2977                 }
2978
2979 #endregion
2980
2981 #region SendPackets
2982
2983                 [MonoTODO ("Not implemented")]
2984                 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2985                 {
2986                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2987
2988                         ThrowIfDisposedAndClosed ();
2989
2990                         throw new NotImplementedException ();
2991                 }
2992
2993 #endregion
2994
2995 #region DuplicateAndClose
2996
2997 #if !MOBILE
2998                 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2999                 public SocketInformation DuplicateAndClose (int targetProcessId)
3000                 {
3001                         var si = new SocketInformation ();
3002                         si.Options =
3003                                 (is_listening      ? SocketInformationOptions.Listening : 0) |
3004                                 (is_connected      ? SocketInformationOptions.Connected : 0) |
3005                                 (is_blocking       ? 0 : SocketInformationOptions.NonBlocking) |
3006                                 (use_overlapped_io ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
3007
3008                         si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, is_bound ? 1 : 0, (long)Handle);
3009                         safe_handle = null;
3010
3011                         return si;
3012                 }
3013 #endif
3014
3015 #endregion
3016
3017 #region GetSocketOption
3018
3019                 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3020                 {
3021                         ThrowIfDisposedAndClosed ();
3022
3023                         if (optionValue == null)
3024                                 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3025
3026                         int error;
3027                         GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref optionValue, out error);
3028
3029                         if (error != 0)
3030                                 throw new SocketException (error);
3031                 }
3032
3033                 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength)
3034                 {
3035                         ThrowIfDisposedAndClosed ();
3036
3037                         int error;
3038                         byte[] byte_val = new byte [optionLength];
3039                         GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref byte_val, out error);
3040
3041                         if (error != 0)
3042                                 throw new SocketException (error);
3043
3044                         return byte_val;
3045                 }
3046
3047                 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
3048                 {
3049                         ThrowIfDisposedAndClosed ();
3050
3051                         int error;
3052                         object obj_val;
3053                         GetSocketOption_obj_internal (safe_handle, optionLevel, optionName, out obj_val, out error);
3054
3055                         if (error != 0)
3056                                 throw new SocketException (error);
3057
3058                         if (optionName == SocketOptionName.Linger)
3059                                 return (LingerOption) obj_val;
3060                         else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
3061                                 return (MulticastOption) obj_val;
3062                         else if (obj_val is int)
3063                                 return (int) obj_val;
3064                         else
3065                                 return obj_val;
3066                 }
3067
3068                 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
3069                 {
3070                         bool release = false;
3071                         try {
3072                                 safeHandle.DangerousAddRef (ref release);
3073                                 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
3074                         } finally {
3075                                 if (release)
3076                                         safeHandle.DangerousRelease ();
3077                         }
3078                 }
3079
3080                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3081                 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
3082
3083                 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
3084                 {
3085                         bool release = false;
3086                         try {
3087                                 safeHandle.DangerousAddRef (ref release);
3088                                 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
3089                         } finally {
3090                                 if (release)
3091                                         safeHandle.DangerousRelease ();
3092                         }
3093                 }
3094
3095                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3096                 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
3097
3098 #endregion
3099
3100 #region SetSocketOption
3101
3102                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3103                 {
3104                         ThrowIfDisposedAndClosed ();
3105
3106                         // I'd throw an ArgumentNullException, but this is what MS does.
3107                         if (optionValue == null)
3108                                 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3109
3110                         int error;
3111                         SetSocketOption_internal (safe_handle, optionLevel, optionName, null, optionValue, 0, out error);
3112
3113                         if (error != 0) {
3114                                 if (error == (int) SocketError.InvalidArgument)
3115                                         throw new ArgumentException ();
3116                                 throw new SocketException (error);
3117                         }
3118                 }
3119
3120                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
3121                 {
3122                         ThrowIfDisposedAndClosed ();
3123
3124                         // NOTE: if a null is passed, the byte[] overload is used instead...
3125                         if (optionValue == null)
3126                                 throw new ArgumentNullException("optionValue");
3127
3128                         int error;
3129
3130                         if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
3131                                 LingerOption linger = optionValue as LingerOption;
3132                                 if (linger == null)
3133                                         throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
3134                                 SetSocketOption_internal (safe_handle, optionLevel, optionName, linger, null, 0, out error);
3135                         } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3136                                 MulticastOption multicast = optionValue as MulticastOption;
3137                                 if (multicast == null)
3138                                         throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
3139                                 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3140                         } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3141                                 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
3142                                 if (multicast == null)
3143                                         throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
3144                                 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3145                         } else {
3146                                 throw new ArgumentException ("Invalid value specified.", "optionValue");
3147                         }
3148
3149                         if (error != 0) {
3150                                 if (error == (int) SocketError.InvalidArgument)
3151                                         throw new ArgumentException ();
3152                                 throw new SocketException (error);
3153                         }
3154                 }
3155
3156                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
3157                 {
3158                         int int_val = optionValue ? 1 : 0;
3159
3160                         SetSocketOption (optionLevel, optionName, int_val);
3161                 }
3162
3163                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
3164                 {
3165                         ThrowIfDisposedAndClosed ();
3166
3167                         if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse (protocol_type))
3168                                 throw new SocketException ((int) SocketError.OperationNotSupported, "Operating system sockets do not support ReuseAddress.\nIf your socket is not intended to bind to the same address and port multiple times remove this option, otherwise you should ignore this exception inside a try catch and check that ReuseAddress is true before binding to the same address and port multiple times.");
3169
3170                         int error;
3171                         SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, optionValue, out error);
3172
3173                         if (error != 0) {
3174                                 if (error == (int) SocketError.InvalidArgument)
3175                                         throw new ArgumentException ();
3176                                 throw new SocketException (error);
3177                         }
3178                 }
3179
3180                 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
3181                 {
3182                         bool release = false;
3183                         try {
3184                                 safeHandle.DangerousAddRef (ref release);
3185                                 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
3186                         } finally {
3187                                 if (release)
3188                                         safeHandle.DangerousRelease ();
3189                         }
3190                 }
3191
3192                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3193                 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
3194
3195 #endregion
3196
3197 #region IOControl
3198
3199                 public int IOControl (int ioControlCode, byte [] optionInValue, byte [] optionOutValue)
3200                 {
3201                         if (is_disposed)
3202                                 throw new ObjectDisposedException (GetType ().ToString ());
3203
3204                         int error;
3205                         int result = IOControl_internal (safe_handle, ioControlCode, optionInValue, optionOutValue, out error);
3206
3207                         if (error != 0)
3208                                 throw new SocketException (error);
3209                         if (result == -1)
3210                                 throw new InvalidOperationException ("Must use Blocking property instead.");
3211
3212                         return result;
3213                 }
3214
3215                 public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
3216                 {
3217                         return IOControl ((int) ioControlCode, optionInValue, optionOutValue);
3218                 }
3219
3220                 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
3221                 {
3222                         bool release = false;
3223                         try {
3224                                 safeHandle.DangerousAddRef (ref release);
3225                                 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
3226                         } finally {
3227                                 if (release)
3228                                         safeHandle.DangerousRelease ();
3229                         }
3230                 }
3231
3232                 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
3233                  * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
3234                  * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
3235                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3236                 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
3237
3238 #endregion
3239
3240 #region Close
3241
3242                 public void Close ()
3243                 {
3244                         linger_timeout = 0;
3245                         Dispose ();
3246                 }
3247
3248                 public void Close (int timeout)
3249                 {
3250                         linger_timeout = timeout;
3251                         Dispose ();
3252                 }
3253
3254                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3255                 internal extern static void Close_internal (IntPtr socket, out int error);
3256
3257 #endregion
3258
3259 #region Shutdown
3260
3261                 public void Shutdown (SocketShutdown how)
3262                 {
3263                         ThrowIfDisposedAndClosed ();
3264
3265                         if (!is_connected)
3266                                 throw new SocketException (10057); // Not connected
3267
3268                         int error;
3269                         Shutdown_internal (safe_handle, how, out error);
3270
3271                         if (error != 0)
3272                                 throw new SocketException (error);
3273                 }
3274
3275                 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
3276                 {
3277                         bool release = false;
3278                         try {
3279                                 safeHandle.DangerousAddRef (ref release);
3280                                 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
3281                         } finally {
3282                                 if (release)
3283                                         safeHandle.DangerousRelease ();
3284                         }
3285                 }
3286
3287                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
3288                 internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
3289
3290 #endregion
3291
3292 #region Dispose
3293
3294                 protected virtual void Dispose (bool disposing)
3295                 {
3296                         if (is_disposed)
3297                                 return;
3298
3299                         is_disposed = true;
3300                         bool was_connected = is_connected;
3301                         is_connected = false;
3302
3303                         if (safe_handle != null) {
3304                                 is_closed = true;
3305                                 IntPtr x = Handle;
3306
3307                                 if (was_connected)
3308                                         Linger (x);
3309
3310                                 safe_handle.Dispose ();
3311                         }
3312                 }
3313
3314                 public void Dispose ()
3315                 {
3316                         Dispose (true);
3317                         GC.SuppressFinalize (this);
3318                 }
3319
3320                 void Linger (IntPtr handle)
3321                 {
3322                         if (!is_connected || linger_timeout <= 0)
3323                                 return;
3324
3325                         /* We don't want to receive any more data */
3326                         int error;
3327                         Shutdown_internal (handle, SocketShutdown.Receive, out error);
3328
3329                         if (error != 0)
3330                                 return;
3331
3332                         int seconds = linger_timeout / 1000;
3333                         int ms = linger_timeout % 1000;
3334                         if (ms > 0) {
3335                                 /* If the other end closes, this will return 'true' with 'Available' == 0 */
3336                                 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
3337                                 if (error != 0)
3338                                         return;
3339                         }
3340
3341                         if (seconds > 0) {
3342                                 LingerOption linger = new LingerOption (true, seconds);
3343                                 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
3344                                 /* Not needed, we're closing upon return */
3345                                 //if (error != 0)
3346                                 //      return;
3347                         }
3348                 }
3349
3350 #endregion
3351
3352                 void ThrowIfDisposedAndClosed (Socket socket)
3353                 {
3354                         if (socket.is_disposed && socket.is_closed)
3355                                 throw new ObjectDisposedException (socket.GetType ().ToString ());
3356                 }
3357
3358                 void ThrowIfDisposedAndClosed ()
3359                 {
3360                         if (is_disposed && is_closed)
3361                                 throw new ObjectDisposedException (GetType ().ToString ());
3362                 }
3363
3364                 void ThrowIfBufferNull (byte[] buffer)
3365                 {
3366                         if (buffer == null)
3367                                 throw new ArgumentNullException ("buffer");
3368                 }
3369
3370                 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
3371                 {
3372                         if (offset < 0)
3373                                 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
3374                         if (offset > buffer.Length)
3375                                 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
3376                         if (size < 0)
3377                                 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
3378                         if (size > buffer.Length - offset)
3379                                 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
3380                 }
3381
3382                 void ThrowIfUdp ()
3383                 {
3384                         if (protocol_type == ProtocolType.Udp)
3385                                 throw new SocketException ((int)SocketError.ProtocolOption);
3386                 }
3387
3388                 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
3389                 {
3390                         if (ares == null)
3391                                 throw new ArgumentNullException (argName);
3392
3393                         SocketAsyncResult sockares = ares as SocketAsyncResult;
3394                         if (sockares == null)
3395                                 throw new ArgumentException ("Invalid IAsyncResult", argName);
3396                         if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
3397                                 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
3398
3399                         return sockares;
3400                 }
3401
3402                 void QueueIOSelectorJob (Queue<KeyValuePair<IntPtr, IOSelectorJob>> queue, IntPtr handle, IOSelectorJob job)
3403                 {
3404                         int count;
3405                         lock (queue) {
3406                                 queue.Enqueue (new KeyValuePair<IntPtr, IOSelectorJob> (handle, job));
3407                                 count = queue.Count;
3408                         }
3409
3410                         if (count == 1)
3411                                 IOSelector.Add (handle, job);
3412                 }
3413
3414                 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
3415                 {
3416                         e.socket_async_result.Init (this, callback, state, operation);
3417                         if (e.AcceptSocket != null) {
3418                                 e.socket_async_result.AcceptSocket = e.AcceptSocket;
3419                         }
3420                         e.current_socket = this;
3421                         e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
3422                         e.SocketError = SocketError.Success;
3423                         e.BytesTransferred = 0;
3424                 }
3425
3426                 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
3427                 {
3428                         switch (op) {
3429                         case SocketOperation.Connect:
3430                                 return SocketAsyncOperation.Connect;
3431                         case SocketOperation.Accept:
3432                                 return SocketAsyncOperation.Accept;
3433                         case SocketOperation.Disconnect:
3434                                 return SocketAsyncOperation.Disconnect;
3435                         case SocketOperation.Receive:
3436                         case SocketOperation.ReceiveGeneric:
3437                                 return SocketAsyncOperation.Receive;
3438                         case SocketOperation.ReceiveFrom:
3439                                 return SocketAsyncOperation.ReceiveFrom;
3440                         case SocketOperation.Send:
3441                         case SocketOperation.SendGeneric:
3442                                 return SocketAsyncOperation.Send;
3443                         case SocketOperation.SendTo:
3444                                 return SocketAsyncOperation.SendTo;
3445                         default:
3446                                 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
3447                         }
3448                 }
3449                 
3450                 IPEndPoint RemapIPEndPoint (IPEndPoint input) {
3451                         // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
3452                         if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
3453                                 return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
3454                         
3455                         return input;
3456                 }
3457                 
3458                 [StructLayout (LayoutKind.Sequential)]
3459                 struct WSABUF {
3460                         public int len;
3461                         public IntPtr buf;
3462                 }
3463
3464                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3465                 internal static extern void cancel_blocking_socket_operation (Thread thread);
3466
3467                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3468                 internal static extern bool SupportsPortReuse (ProtocolType proto);
3469         }
3470 }
3471