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