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