Merge pull request #2250 from esdrubal/master
[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)
706                                         throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
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, ConnectAsyncCallback, 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                 static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
1360                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1361
1362                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1363                                 throw new InvalidOperationException ("No operation in progress");
1364
1365                         try {
1366                                 e.current_socket.EndConnect (ares);
1367                         } catch (SocketException se) {
1368                                 e.SocketError = se.SocketErrorCode;
1369                         } catch (ObjectDisposedException) {
1370                                 e.SocketError = SocketError.OperationAborted;
1371                         } finally {
1372                                 e.Complete ();
1373                         }
1374                 });
1375
1376                 public IAsyncResult BeginConnect (IPAddress address, int port, AsyncCallback callback, object state)
1377                 {
1378                         ThrowIfDisposedAndClosed ();
1379
1380                         if (address == null)
1381                                 throw new ArgumentNullException ("address");
1382                         if (address.ToString ().Length == 0)
1383                                 throw new ArgumentException ("The length of the IP address is zero");
1384                         if (port <= 0 || port > 65535)
1385                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1386                         if (is_listening)
1387                                 throw new InvalidOperationException ();
1388
1389                         return BeginConnect (new IPEndPoint (address, port), callback, state);
1390                 }
1391
1392                 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
1393                 {
1394                         ThrowIfDisposedAndClosed ();
1395
1396                         if (host == null)
1397                                 throw new ArgumentNullException ("host");
1398                         if (address_family != AddressFamily.InterNetwork && address_family != AddressFamily.InterNetworkV6)
1399                                 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1400                         if (port <= 0 || port > 65535)
1401                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1402                         if (is_listening)
1403                                 throw new InvalidOperationException ();
1404
1405                         return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1406                 }
1407
1408                 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
1409                 {
1410                         ThrowIfDisposedAndClosed ();
1411
1412                         if (end_point == null)
1413                                 throw new ArgumentNullException ("end_point");
1414
1415                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1416                                 EndPoint = end_point,
1417                         };
1418
1419                         // Bug #75154: Connect() should not succeed for .Any addresses.
1420                         if (end_point is IPEndPoint) {
1421                                 IPEndPoint ep = (IPEndPoint) end_point;
1422                                 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1423                                         sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1424                                         return sockares;
1425                                 }
1426                                 
1427                                 end_point = RemapIPEndPoint (ep);
1428                         }
1429
1430                         int error = 0;
1431
1432                         if (connect_in_progress) {
1433                                 // This could happen when multiple IPs are used
1434                                 // Calling connect() again will reset the connection attempt and cause
1435                                 // an error. Better to just close the socket and move on.
1436                                 connect_in_progress = false;
1437                                 safe_handle.Dispose ();
1438                                 safe_handle = new SafeSocketHandle (Socket_internal (address_family, socket_type, protocol_type, out error), true);
1439                                 if (error != 0)
1440                                         throw new SocketException (error);
1441                         }
1442
1443                         bool blk = is_blocking;
1444                         if (blk)
1445                                 Blocking = false;
1446                         Connect_internal (safe_handle, end_point.Serialize (), out error);
1447                         if (blk)
1448                                 Blocking = true;
1449
1450                         if (error == 0) {
1451                                 // succeeded synch
1452                                 is_connected = true;
1453                                 is_bound = true;
1454                                 sockares.Complete (true);
1455                                 return sockares;
1456                         }
1457
1458                         if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1459                                 // error synch
1460                                 is_connected = false;
1461                                 is_bound = false;
1462                                 sockares.Complete (new SocketException (error), true);
1463                                 return sockares;
1464                         }
1465
1466                         // continue asynch
1467                         is_connected = false;
1468                         is_bound = false;
1469                         connect_in_progress = true;
1470
1471                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
1472
1473                         return sockares;
1474                 }
1475
1476                 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1477                 {
1478                         ThrowIfDisposedAndClosed ();
1479
1480                         if (addresses == null)
1481                                 throw new ArgumentNullException ("addresses");
1482                         if (addresses.Length == 0)
1483                                 throw new ArgumentException ("Empty addresses list");
1484                         if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1485                                 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1486                         if (port <= 0 || port > 65535)
1487                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1488                         if (is_listening)
1489                                 throw new InvalidOperationException ();
1490
1491                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1492                                 Addresses = addresses,
1493                                 Port = port,
1494                         };
1495
1496                         is_connected = false;
1497
1498                         return BeginMConnect (sockares);
1499                 }
1500
1501                 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1502                 {
1503                         SocketAsyncResult ares = null;
1504                         Exception exc = null;
1505                         AsyncCallback callback;
1506
1507                         for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1508                                 try {
1509                                         sockares.CurrentAddress++;
1510
1511                                         ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1512                                         if (ares.IsCompleted && ares.CompletedSynchronously) {
1513                                                 ares.CheckIfThrowDelayedException ();
1514
1515                                                 callback = ares.AsyncCallback;
1516                                                 if (callback != null)
1517                                                         ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
1518                                         }
1519
1520                                         break;
1521                                 } catch (Exception e) {
1522                                         exc = e;
1523                                         ares = null;
1524                                 }
1525                         }
1526
1527                         if (ares == null)
1528                                 throw exc;
1529
1530                         return sockares;
1531                 }
1532
1533                 static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
1534                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1535
1536                         if (sockares.EndPoint == null) {
1537                                 sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
1538                                 return;
1539                         }
1540
1541                         SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
1542                         bool is_mconnect = mconnect != null && mconnect.Addresses != null;
1543
1544                         try {
1545                                 EndPoint ep = sockares.EndPoint;
1546                                 int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1547
1548                                 if (error_code == 0) {
1549                                         if (is_mconnect)
1550                                                 sockares = mconnect;
1551
1552                                         sockares.socket.seed_endpoint = ep;
1553                                         sockares.socket.is_connected = true;
1554                                         sockares.socket.is_bound = true;
1555                                         sockares.socket.connect_in_progress = false;
1556                                         sockares.error = 0;
1557                                         sockares.Complete ();
1558                                         return;
1559                                 }
1560
1561                                 if (!is_mconnect) {
1562                                         sockares.socket.connect_in_progress = false;
1563                                         sockares.Complete (new SocketException (error_code));
1564                                         return;
1565                                 }
1566
1567                                 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
1568                                         mconnect.Complete (new SocketException (error_code));
1569                                         return;
1570                                 }
1571
1572                                 mconnect.socket.BeginMConnect (mconnect);
1573                         } catch (Exception e) {
1574                                 sockares.socket.connect_in_progress = false;
1575
1576                                 if (is_mconnect)
1577                                         sockares = mconnect;
1578
1579                                 sockares.Complete (e);
1580                                 return;
1581                         }
1582                 });
1583
1584                 public void EndConnect (IAsyncResult result)
1585                 {
1586                         ThrowIfDisposedAndClosed ();
1587
1588                         SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1589
1590                         if (!sockares.IsCompleted)
1591                                 sockares.AsyncWaitHandle.WaitOne();
1592
1593                         sockares.CheckIfThrowDelayedException();
1594                 }
1595
1596                 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1597                 {
1598                         try {
1599                                 safeHandle.RegisterForBlockingSyscall ();
1600                                 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
1601                         } finally {
1602                                 safeHandle.UnRegisterForBlockingSyscall ();
1603                         }
1604                 }
1605
1606                 /* Connects to the remote address */
1607                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1608                 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error);
1609
1610                 /* Returns :
1611                  *  - false when it is ok to use RemoteEndPoint
1612                  *  - true when addresses must be used (and addresses could be null/empty) */
1613                 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1614                 {
1615                         addresses = null;
1616
1617                         // Connect to the first address that match the host name, like:
1618                         // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1619                         // while skipping entries that do not match the address family
1620                         DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1621                         if (dep != null) {
1622                                 addresses = Dns.GetHostAddresses (dep.Host);
1623                                 return true;
1624                         } else {
1625                                 e.ConnectByNameError = null;
1626                                 return false;
1627                         }
1628                 }
1629
1630 #endregion
1631
1632 #region Disconnect
1633
1634                 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1635                  * if the platform is newer than w2k.  We should be able to cope... */
1636                 public void Disconnect (bool reuseSocket)
1637                 {
1638                         ThrowIfDisposedAndClosed ();
1639
1640                         int error = 0;
1641                         Disconnect_internal (safe_handle, reuseSocket, out error);
1642
1643                         if (error != 0) {
1644                                 if (error == 50) {
1645                                         /* ERROR_NOT_SUPPORTED */
1646                                         throw new PlatformNotSupportedException ();
1647                                 } else {
1648                                         throw new SocketException (error);
1649                                 }
1650                         }
1651
1652                         is_connected = false;
1653                         if (reuseSocket) {
1654                                 /* Do managed housekeeping here... */
1655                         }
1656                 }
1657
1658                 public bool DisconnectAsync (SocketAsyncEventArgs e)
1659                 {
1660                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1661
1662                         ThrowIfDisposedAndClosed ();
1663
1664                         InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
1665
1666                         IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
1667
1668                         return true;
1669                 }
1670
1671                 static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
1672                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1673
1674                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1675                                 throw new InvalidOperationException ("No operation in progress");
1676
1677                         try {
1678                                 e.current_socket.EndDisconnect (ares);
1679                         } catch (SocketException ex) {
1680                                 e.SocketError = ex.SocketErrorCode;
1681                         } catch (ObjectDisposedException) {
1682                                 e.SocketError = SocketError.OperationAborted;
1683                         } finally {
1684                                 e.Complete ();
1685                         }
1686                 });
1687
1688                 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1689                 {
1690                         ThrowIfDisposedAndClosed ();
1691
1692                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1693                                 ReuseSocket = reuseSocket,
1694                         };
1695
1696                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
1697
1698                         return sockares;
1699                 }
1700
1701                 static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
1702                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1703
1704                         try {
1705                                 sockares.socket.Disconnect (sockares.ReuseSocket);
1706                         } catch (Exception e) {
1707                                 sockares.Complete (e);
1708                                 return;
1709                         }
1710
1711                         sockares.Complete ();
1712                 });
1713
1714                 public void EndDisconnect (IAsyncResult asyncResult)
1715                 {
1716                         ThrowIfDisposedAndClosed ();
1717
1718                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1719
1720                         if (!sockares.IsCompleted)
1721                                 sockares.AsyncWaitHandle.WaitOne ();
1722
1723                         sockares.CheckIfThrowDelayedException ();
1724                 }
1725
1726                 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1727                 {
1728                         bool release = false;
1729                         try {
1730                                 safeHandle.DangerousAddRef (ref release);
1731                                 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1732                         } finally {
1733                                 if (release)
1734                                         safeHandle.DangerousRelease ();
1735                         }
1736                 }
1737
1738                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1739                 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1740
1741 #endregion
1742
1743 #region Receive
1744
1745                 public int Receive (byte [] buffer)
1746                 {
1747                         return Receive (buffer, SocketFlags.None);
1748                 }
1749
1750                 public int Receive (byte [] buffer, SocketFlags flags)
1751                 {
1752                         ThrowIfDisposedAndClosed ();
1753                         ThrowIfBufferNull (buffer);
1754                         ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
1755
1756                         SocketError error;
1757                         int ret = Receive_nochecks (buffer, 0, buffer.Length, flags, out error);
1758
1759                         if (error != SocketError.Success) {
1760                                 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1761                                         throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1762                                 throw new SocketException ((int) error);
1763                         }
1764
1765                         return ret;
1766                 }
1767
1768                 public int Receive (byte [] buffer, int size, SocketFlags flags)
1769                 {
1770                         ThrowIfDisposedAndClosed ();
1771                         ThrowIfBufferNull (buffer);
1772                         ThrowIfBufferOutOfRange (buffer, 0, size);
1773
1774                         SocketError error;
1775                         int ret = Receive_nochecks (buffer, 0, size, flags, out error);
1776
1777                         if (error != SocketError.Success) {
1778                                 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1779                                         throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1780                                 throw new SocketException ((int) error);
1781                         }
1782
1783                         return ret;
1784                 }
1785
1786                 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags)
1787                 {
1788                         ThrowIfDisposedAndClosed ();
1789                         ThrowIfBufferNull (buffer);
1790                         ThrowIfBufferOutOfRange (buffer, offset, size);
1791
1792                         SocketError error;
1793                         int ret = Receive_nochecks (buffer, offset, size, flags, out error);
1794
1795                         if (error != SocketError.Success) {
1796                                 if (error == SocketError.WouldBlock && is_blocking) // This might happen when ReceiveTimeout is set
1797                                         throw new SocketException ((int) error, TIMEOUT_EXCEPTION_MSG);
1798                                 throw new SocketException ((int) error);
1799                         }
1800
1801                         return ret;
1802                 }
1803
1804                 public int Receive (byte [] buffer, int offset, int size, SocketFlags flags, out SocketError error)
1805                 {
1806                         ThrowIfDisposedAndClosed ();
1807                         ThrowIfBufferNull (buffer);
1808                         ThrowIfBufferOutOfRange (buffer, offset, size);
1809
1810                         return Receive_nochecks (buffer, offset, size, flags, out error);
1811                 }
1812
1813                 public int Receive (IList<ArraySegment<byte>> buffers)
1814                 {
1815                         SocketError error;
1816                         int ret = Receive (buffers, SocketFlags.None, out error);
1817
1818                         if (error != SocketError.Success)
1819                                 throw new SocketException ((int) error);
1820
1821                         return ret;
1822                 }
1823
1824                 [CLSCompliant (false)]
1825                 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1826                 {
1827                         SocketError error;
1828                         int ret = Receive (buffers, socketFlags, out error);
1829
1830                         if (error != SocketError.Success)
1831                                 throw new SocketException ((int) error);
1832
1833                         return(ret);
1834                 }
1835
1836                 [CLSCompliant (false)]
1837                 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1838                 {
1839                         ThrowIfDisposedAndClosed ();
1840
1841                         if (buffers == null || buffers.Count == 0)
1842                                 throw new ArgumentNullException ("buffers");
1843
1844                         int numsegments = buffers.Count;
1845                         int nativeError;
1846                         int ret;
1847
1848                         /* Only example I can find of sending a byte array reference directly into an internal
1849                          * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1850                          * so taking a lead from that... */
1851                         WSABUF[] bufarray = new WSABUF[numsegments];
1852                         GCHandle[] gch = new GCHandle[numsegments];
1853
1854                         for (int i = 0; i < numsegments; i++) {
1855                                 ArraySegment<byte> segment = buffers[i];
1856
1857                                 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1858                                         throw new ArgumentOutOfRangeException ("segment");
1859
1860                                 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1861                                 bufarray[i].len = segment.Count;
1862                                 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1863                         }
1864
1865                         try {
1866                                 ret = Receive_internal (safe_handle, bufarray, socketFlags, out nativeError);
1867                         } finally {
1868                                 for (int i = 0; i < numsegments; i++) {
1869                                         if (gch[i].IsAllocated)
1870                                                 gch[i].Free ();
1871                                 }
1872                         }
1873
1874                         errorCode = (SocketError) nativeError;
1875
1876                         return ret;
1877                 }
1878
1879                 public bool ReceiveAsync (SocketAsyncEventArgs e)
1880                 {
1881                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1882
1883                         ThrowIfDisposedAndClosed ();
1884
1885                         // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1886                         // thrown when e.Buffer and e.BufferList are null (works fine when one is
1887                         // set to a valid object)
1888                         if (e.Buffer == null && e.BufferList == null)
1889                                 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1890
1891                         if (e.Buffer == null) {
1892                                 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
1893
1894                                 e.socket_async_result.Buffers = e.BufferList;
1895
1896                                 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
1897                         } else {
1898                                 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
1899
1900                                 e.socket_async_result.Buffer = e.Buffer;
1901                                 e.socket_async_result.Offset = e.Offset;
1902                                 e.socket_async_result.Size = e.Count;
1903
1904                                 QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
1905                         }
1906
1907                         return true;
1908                 }
1909
1910                 static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
1911                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1912
1913                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1914                                 throw new InvalidOperationException ("No operation in progress");
1915
1916                         try {
1917                                 e.BytesTransferred = e.current_socket.EndReceive (ares);
1918                         } catch (SocketException se){
1919                                 e.SocketError = se.SocketErrorCode;
1920                         } catch (ObjectDisposedException) {
1921                                 e.SocketError = SocketError.OperationAborted;
1922                         } finally {
1923                                 e.Complete ();
1924                         }
1925                 });
1926
1927                 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
1928                 {
1929                         ThrowIfDisposedAndClosed ();
1930                         ThrowIfBufferNull (buffer);
1931                         ThrowIfBufferOutOfRange (buffer, offset, size);
1932
1933                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1934                                 Buffer = buffer,
1935                                 Offset = offset,
1936                                 Size = size,
1937                                 SockFlags = socket_flags,
1938                         };
1939
1940                         QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
1941
1942                         return sockares;
1943                 }
1944
1945                 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags flags, out SocketError error, AsyncCallback callback, object state)
1946                 {
1947                         /* As far as I can tell from the docs and from experimentation, a pointer to the
1948                          * SocketError parameter is not supposed to be saved for the async parts.  And as we don't
1949                          * set any socket errors in the setup code, we just have to set it to Success. */
1950                         error = SocketError.Success;
1951                         return BeginReceive (buffer, offset, size, flags, callback, state);
1952                 }
1953
1954                 static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
1955                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1956                         int total = 0;
1957
1958                         try {
1959                                 total = Receive_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
1960                         } catch (Exception e) {
1961                                 sockares.Complete (e);
1962                                 return;
1963                         }
1964
1965                         sockares.Complete (total);
1966                 });
1967
1968                 [CLSCompliant (false)]
1969                 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
1970                 {
1971                         ThrowIfDisposedAndClosed ();
1972
1973                         if (buffers == null)
1974                                 throw new ArgumentNullException ("buffers");
1975
1976                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1977                                 Buffers = buffers,
1978                                 SockFlags = socketFlags,
1979                         };
1980
1981                         QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
1982
1983                         return sockares;
1984                 }
1985
1986                 [CLSCompliant (false)]
1987                 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1988                 {
1989                         /* I assume the same SocketError semantics as above */
1990                         errorCode = SocketError.Success;
1991                         return BeginReceive (buffers, socketFlags, callback, state);
1992                 }
1993
1994                 static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
1995                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1996                         int total = 0;
1997
1998                         try {
1999                                 total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
2000                         } catch (Exception e) {
2001                                 sockares.Complete (e);
2002                                 return;
2003                         }
2004
2005                         sockares.Complete (total);
2006                 });
2007
2008                 public int EndReceive (IAsyncResult result)
2009                 {
2010                         SocketError error;
2011                         int bytesReceived = EndReceive (result, out error);
2012
2013                         if (error != SocketError.Success) {
2014                                 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2015                                         is_connected = false;
2016                                 throw new SocketException ((int)error);
2017                         }
2018
2019                         return bytesReceived;
2020                 }
2021
2022                 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
2023                 {
2024                         ThrowIfDisposedAndClosed ();
2025
2026                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
2027
2028                         if (!sockares.IsCompleted)
2029                                 sockares.AsyncWaitHandle.WaitOne ();
2030
2031                         // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
2032                         // kinds of exceptions that should be thrown.
2033                         if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2034                                 sockares.CheckIfThrowDelayedException();
2035
2036                         return sockares.Total;
2037                 }
2038
2039                 int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2040                 {
2041                         int nativeError;
2042                         int ret = Receive_internal (safe_handle, buf, offset, size, flags, out nativeError);
2043
2044                         error = (SocketError) nativeError;
2045                         if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2046                                 is_connected = false;
2047                                 is_bound = false;
2048                         } else {
2049                                 is_connected = true;
2050                         }
2051
2052                         return ret;
2053                 }
2054
2055                 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2056                 {
2057                         try {
2058                                 safeHandle.RegisterForBlockingSyscall ();
2059                                 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2060                         } finally {
2061                                 safeHandle.UnRegisterForBlockingSyscall ();
2062                         }
2063                 }
2064
2065                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2066                 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2067
2068                 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
2069                 {
2070                         try {
2071                                 safeHandle.RegisterForBlockingSyscall ();
2072                                 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
2073                         } finally {
2074                                 safeHandle.UnRegisterForBlockingSyscall ();
2075                         }
2076                 }
2077
2078                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2079                 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error);
2080
2081 #endregion
2082
2083 #region ReceiveFrom
2084
2085                 public int ReceiveFrom (byte [] buffer, ref EndPoint remoteEP)
2086                 {
2087                         ThrowIfDisposedAndClosed ();
2088                         ThrowIfBufferNull (buffer);
2089
2090                         return ReceiveFrom (buffer, 0, buffer.Length, SocketFlags.None, ref remoteEP);
2091                 }
2092
2093                 public int ReceiveFrom (byte [] buffer, SocketFlags flags, ref EndPoint remoteEP)
2094                 {
2095                         ThrowIfDisposedAndClosed ();
2096                         ThrowIfBufferNull (buffer);
2097
2098                         return ReceiveFrom (buffer, 0, buffer.Length, flags, ref remoteEP);
2099                 }
2100
2101                 public int ReceiveFrom (byte [] buffer, int size, SocketFlags flags, ref EndPoint remoteEP)
2102                 {
2103                         ThrowIfDisposedAndClosed ();
2104                         ThrowIfBufferNull (buffer);
2105                         ThrowIfBufferOutOfRange (buffer, 0, size);
2106
2107                         return ReceiveFrom (buffer, 0, size, flags, ref remoteEP);
2108                 }
2109
2110                 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags flags, ref EndPoint remoteEP)
2111                 {
2112                         ThrowIfDisposedAndClosed ();
2113                         ThrowIfBufferNull (buffer);
2114                         ThrowIfBufferOutOfRange (buffer, offset, size);
2115
2116                         if (remoteEP == null)
2117                                 throw new ArgumentNullException ("remoteEP");
2118
2119                         int error;
2120                         return ReceiveFrom_nochecks_exc (buffer, offset, size, flags, ref remoteEP, true, out error);
2121                 }
2122
2123                 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
2124                 {
2125                         ThrowIfDisposedAndClosed ();
2126
2127                         // We do not support recv into multiple buffers yet
2128                         if (e.BufferList != null)
2129                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2130                         if (e.RemoteEndPoint == null)
2131                                 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2132
2133                         InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
2134
2135                         e.socket_async_result.Buffer = e.Buffer;
2136                         e.socket_async_result.Offset = e.Offset;
2137                         e.socket_async_result.Size = e.Count;
2138                         e.socket_async_result.EndPoint = e.RemoteEndPoint;
2139                         e.socket_async_result.SockFlags = e.SocketFlags;
2140
2141                         QueueIOSelectorJob (readQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
2142
2143                         return true;
2144                 }
2145
2146                 static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
2147                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2148
2149                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2150                                 throw new InvalidOperationException ("No operation in progress");
2151
2152                         try {
2153                                 e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
2154                         } catch (SocketException ex) {
2155                                 e.SocketError = ex.SocketErrorCode;
2156                         } catch (ObjectDisposedException) {
2157                                 e.SocketError = SocketError.OperationAborted;
2158                         } finally {
2159                                 e.Complete ();
2160                         }
2161                 });
2162
2163                 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
2164                 {
2165                         ThrowIfDisposedAndClosed ();
2166                         ThrowIfBufferNull (buffer);
2167                         ThrowIfBufferOutOfRange (buffer, offset, size);
2168
2169                         if (remote_end == null)
2170                                 throw new ArgumentNullException ("remote_end");
2171
2172                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
2173                                 Buffer = buffer,
2174                                 Offset = offset,
2175                                 Size = size,
2176                                 SockFlags = socket_flags,
2177                                 EndPoint = remote_end,
2178                         };
2179
2180                         QueueIOSelectorJob (readQ, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
2181
2182                         return sockares;
2183                 }
2184
2185                 static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
2186                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
2187                         int total = 0;
2188
2189                         try {
2190                                 int error;
2191                                 total = sockares.socket.ReceiveFrom_nochecks_exc (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, true, out error);
2192                         } catch (Exception e) {
2193                                 sockares.Complete (e);
2194                                 return;
2195                         }
2196
2197                         sockares.Complete (total);
2198                 });
2199
2200                 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
2201                 {
2202                         ThrowIfDisposedAndClosed ();
2203
2204                         if (end_point == null)
2205                                 throw new ArgumentNullException ("remote_end");
2206
2207                         SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
2208
2209                         if (!sockares.IsCompleted)
2210                                 sockares.AsyncWaitHandle.WaitOne();
2211
2212                         sockares.CheckIfThrowDelayedException();
2213
2214                         end_point = sockares.EndPoint;
2215
2216                         return sockares.Total;
2217                 }
2218
2219                 internal int ReceiveFrom_nochecks_exc (byte [] buf, int offset, int size, SocketFlags flags, ref EndPoint remote_end, bool throwOnError, out int error)
2220                 {
2221                         SocketAddress sockaddr = remote_end.Serialize();
2222
2223                         int cnt = ReceiveFrom_internal (safe_handle, buf, offset, size, flags, ref sockaddr, out error);
2224
2225                         SocketError err = (SocketError) error;
2226                         if (err != 0) {
2227                                 if (err != SocketError.WouldBlock && err != SocketError.InProgress) {
2228                                         is_connected = false;
2229                                 } else if (err == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
2230                                         if (throwOnError)       
2231                                                 throw new SocketException ((int) SocketError.TimedOut, TIMEOUT_EXCEPTION_MSG);
2232                                         error = (int) SocketError.TimedOut;
2233                                         return 0;
2234                                 }
2235
2236                                 if (throwOnError)
2237                                         throw new SocketException (error);
2238
2239                                 return 0;
2240                         }
2241
2242                         is_connected = true;
2243                         is_bound = true;
2244
2245                         /* If sockaddr is null then we're a connection oriented protocol and should ignore the
2246                          * remote_end parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
2247                         if (sockaddr != null) {
2248                                 /* Stupidly, EndPoint.Create() is an instance method */
2249                                 remote_end = remote_end.Create (sockaddr);
2250                         }
2251
2252                         seed_endpoint = remote_end;
2253
2254                         return cnt;
2255                 }
2256
2257                 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error)
2258                 {
2259                         try {
2260                                 safeHandle.RegisterForBlockingSyscall ();
2261                                 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
2262                         } finally {
2263                                 safeHandle.UnRegisterForBlockingSyscall ();
2264                         }
2265                 }
2266
2267                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2268                 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error);
2269
2270 #endregion
2271
2272 #region ReceiveMessageFrom
2273
2274                 [MonoTODO ("Not implemented")]
2275                 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
2276                 {
2277                         ThrowIfDisposedAndClosed ();
2278                         ThrowIfBufferNull (buffer);
2279                         ThrowIfBufferOutOfRange (buffer, offset, size);
2280
2281                         if (remoteEP == null)
2282                                 throw new ArgumentNullException ("remoteEP");
2283
2284                         // FIXME: figure out how we get hold of the IPPacketInformation
2285                         throw new NotImplementedException ();
2286                 }
2287
2288                 [MonoTODO ("Not implemented")]
2289                 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
2290                 {
2291                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2292
2293                         ThrowIfDisposedAndClosed ();
2294
2295                         throw new NotImplementedException ();
2296                 }
2297
2298                 [MonoTODO]
2299                 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
2300                 {
2301                         ThrowIfDisposedAndClosed ();
2302                         ThrowIfBufferNull (buffer);
2303                         ThrowIfBufferOutOfRange (buffer, offset, size);
2304
2305                         if (remoteEP == null)
2306                                 throw new ArgumentNullException ("remoteEP");
2307
2308                         throw new NotImplementedException ();
2309                 }
2310
2311                 [MonoTODO]
2312                 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
2313                 {
2314                         ThrowIfDisposedAndClosed ();
2315
2316                         if (endPoint == null)
2317                                 throw new ArgumentNullException ("endPoint");
2318
2319                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
2320
2321                         throw new NotImplementedException ();
2322                 }
2323
2324 #endregion
2325
2326 #region Send
2327
2328                 public int Send (byte [] buffer)
2329                 {
2330                         ThrowIfDisposedAndClosed ();
2331                         ThrowIfBufferNull (buffer);
2332                         ThrowIfBufferOutOfRange (buffer, 0, buffer.Length);
2333
2334                         SocketError error;
2335                         int ret = Send_nochecks (buffer, 0, buffer.Length, SocketFlags.None, out error);
2336
2337                         if (error != SocketError.Success)
2338                                 throw new SocketException ((int) error);
2339
2340                         return ret;
2341                 }
2342
2343                 public int Send (byte [] buffer, SocketFlags flags)
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, flags, out error);
2351
2352                         if (error != SocketError.Success)
2353                                 throw new SocketException ((int) error);
2354
2355                         return ret;
2356                 }
2357
2358                 public int Send (byte [] buffer, int size, SocketFlags flags)
2359                 {
2360                         ThrowIfDisposedAndClosed ();
2361                         ThrowIfBufferNull (buffer);
2362                         ThrowIfBufferOutOfRange (buffer, 0, size);
2363
2364                         SocketError error;
2365                         int ret = Send_nochecks (buffer, 0, size, 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 offset, int size, SocketFlags flags)
2374                 {
2375                         ThrowIfDisposedAndClosed ();
2376                         ThrowIfBufferNull (buffer);
2377                         ThrowIfBufferOutOfRange (buffer, offset, size);
2378
2379                         SocketError error;
2380                         int ret = Send_nochecks (buffer, offset, 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, out SocketError error)
2389                 {
2390                         ThrowIfDisposedAndClosed ();
2391                         ThrowIfBufferNull (buffer);
2392                         ThrowIfBufferOutOfRange (buffer, offset, size);
2393
2394                         return Send_nochecks (buffer, offset, size, flags, out error);
2395                 }
2396
2397                 public
2398                 int Send (IList<ArraySegment<byte>> buffers)
2399                 {
2400                         SocketError error;
2401                         int ret = Send (buffers, SocketFlags.None, out error);
2402
2403                         if (error != SocketError.Success)
2404                                 throw new SocketException ((int) error);
2405
2406                         return ret;
2407                 }
2408
2409                 public
2410                 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
2411                 {
2412                         SocketError error;
2413                         int ret = Send (buffers, socketFlags, out error);
2414
2415                         if (error != SocketError.Success)
2416                                 throw new SocketException ((int) error);
2417
2418                         return ret;
2419                 }
2420
2421                 [CLSCompliant (false)]
2422                 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
2423                 {
2424                         ThrowIfDisposedAndClosed ();
2425
2426                         if (buffers == null)
2427                                 throw new ArgumentNullException ("buffers");
2428                         if (buffers.Count == 0)
2429                                 throw new ArgumentException ("Buffer is empty", "buffers");
2430
2431                         int numsegments = buffers.Count;
2432                         int nativeError;
2433                         int ret;
2434
2435                         WSABUF[] bufarray = new WSABUF[numsegments];
2436                         GCHandle[] gch = new GCHandle[numsegments];
2437
2438                         for(int i = 0; i < numsegments; i++) {
2439                                 ArraySegment<byte> segment = buffers[i];
2440
2441                                 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
2442                                         throw new ArgumentOutOfRangeException ("segment");
2443
2444                                 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
2445                                 bufarray[i].len = segment.Count;
2446                                 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
2447                         }
2448
2449                         try {
2450                                 ret = Send_internal (safe_handle, bufarray, socketFlags, out nativeError);
2451                         } finally {
2452                                 for(int i = 0; i < numsegments; i++) {
2453                                         if (gch[i].IsAllocated) {
2454                                                 gch[i].Free ();
2455                                         }
2456                                 }
2457                         }
2458
2459                         errorCode = (SocketError)nativeError;
2460
2461                         return ret;
2462                 }
2463
2464                 int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
2465                 {
2466                         if (size == 0) {
2467                                 error = SocketError.Success;
2468                                 return 0;
2469                         }
2470
2471                         int nativeError;
2472                         int ret = Send_internal (safe_handle, buf, offset, size, flags, out nativeError);
2473
2474                         error = (SocketError)nativeError;
2475
2476                         if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
2477                                 is_connected = false;
2478                                 is_bound = false;
2479                         } else {
2480                                 is_connected = true;
2481                         }
2482
2483                         return ret;
2484                 }
2485
2486                 public bool SendAsync (SocketAsyncEventArgs e)
2487                 {
2488                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2489
2490                         ThrowIfDisposedAndClosed ();
2491
2492                         if (e.Buffer == null && e.BufferList == null)
2493                                 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
2494
2495                         if (e.Buffer == null) {
2496                                 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
2497
2498                                 e.socket_async_result.Buffers = e.BufferList;
2499
2500                                 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
2501                         } else {
2502                                 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
2503
2504                                 e.socket_async_result.Buffer = e.Buffer;
2505                                 e.socket_async_result.Offset = e.Offset;
2506                                 e.socket_async_result.Size = e.Count;
2507
2508                                 QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2509                         }
2510
2511                         return true;
2512                 }
2513
2514                 static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
2515                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2516
2517                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2518                                 throw new InvalidOperationException ("No operation in progress");
2519
2520                         try {
2521                                 e.BytesTransferred = e.current_socket.EndSend (ares);
2522                         } catch (SocketException se){
2523                                 e.SocketError = se.SocketErrorCode;
2524                         } catch (ObjectDisposedException) {
2525                                 e.SocketError = SocketError.OperationAborted;
2526                         } finally {
2527                                 e.Complete ();
2528                         }
2529                 });
2530
2531                 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2532                 {
2533                         if (!is_connected) {
2534                                 errorCode = SocketError.NotConnected;
2535                                 throw new SocketException ((int) errorCode);
2536                         }
2537
2538                         errorCode = SocketError.Success;
2539                         return BeginSend (buffer, offset, size, socketFlags, callback, state);
2540                 }
2541
2542                 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socket_flags, AsyncCallback callback, object state)
2543                 {
2544                         ThrowIfDisposedAndClosed ();
2545                         ThrowIfBufferNull (buffer);
2546                         ThrowIfBufferOutOfRange (buffer, offset, size);
2547
2548                         if (!is_connected)
2549                                 throw new SocketException ((int)SocketError.NotConnected);
2550
2551                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
2552                                 Buffer = buffer,
2553                                 Offset = offset,
2554                                 Size = size,
2555                                 SockFlags = socket_flags,
2556                         };
2557
2558                         QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
2559
2560                         return sockares;
2561                 }
2562
2563                 static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
2564                 {
2565                         int total = 0;
2566
2567                         try {
2568                                 total = Socket.Send_internal (sockares.socket.safe_handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
2569                         } catch (Exception e) {
2570                                 sockares.Complete (e);
2571                                 return;
2572                         }
2573
2574                         if (sockares.error == 0) {
2575                                 sent_so_far += total;
2576                                 sockares.Offset += total;
2577                                 sockares.Size -= total;
2578
2579                                 if (sockares.socket.is_disposed) {
2580                                         sockares.Complete (total);
2581                                         return;
2582                                 }
2583
2584                                 if (sockares.Size > 0) {
2585                                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2586                                         return; // Have to finish writing everything. See bug #74475.
2587                                 }
2588
2589                                 sockares.Total = sent_so_far;
2590                         }
2591
2592                         sockares.Complete (total);
2593                 }
2594
2595                 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
2596                 {
2597                         ThrowIfDisposedAndClosed ();
2598
2599                         if (buffers == null)
2600                                 throw new ArgumentNullException ("buffers");
2601                         if (!is_connected)
2602                                 throw new SocketException ((int)SocketError.NotConnected);
2603
2604                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
2605                                 Buffers = buffers,
2606                                 SockFlags = socketFlags,
2607                         };
2608
2609                         QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
2610
2611                         return sockares;
2612                 }
2613
2614                 [CLSCompliant (false)]
2615                 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2616                 {
2617                         if (!is_connected) {
2618                                 errorCode = SocketError.NotConnected;
2619                                 throw new SocketException ((int)errorCode);
2620                         }
2621
2622                         errorCode = SocketError.Success;
2623                         return BeginSend (buffers, socketFlags, callback, state);
2624                 }
2625
2626                 static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
2627                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
2628                         int total = 0;
2629
2630                         try {
2631                                 total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
2632                         } catch (Exception e) {
2633                                 sockares.Complete (e);
2634                                 return;
2635                         }
2636
2637                         sockares.Complete (total);
2638                 });
2639
2640                 public int EndSend (IAsyncResult result)
2641                 {
2642                         SocketError error;
2643                         int bytesSent = EndSend (result, out error);
2644
2645                         if (error != SocketError.Success) {
2646                                 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
2647                                         is_connected = false;
2648                                 throw new SocketException ((int)error);
2649                         }
2650
2651                         return bytesSent;
2652                 }
2653
2654                 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
2655                 {
2656                         ThrowIfDisposedAndClosed ();
2657
2658                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
2659
2660                         if (!sockares.IsCompleted)
2661                                 sockares.AsyncWaitHandle.WaitOne ();
2662
2663                         /* If no socket error occurred, call CheckIfThrowDelayedException in
2664                          * case there are other kinds of exceptions that should be thrown.*/
2665                         if ((errorCode = sockares.ErrorCode) == SocketError.Success)
2666                                 sockares.CheckIfThrowDelayedException ();
2667
2668                         return sockares.Total;
2669                 }
2670
2671                 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2672                 {
2673                         bool release = false;
2674                         try {
2675                                 safeHandle.DangerousAddRef (ref release);
2676                                 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2677                         } finally {
2678                                 if (release)
2679                                         safeHandle.DangerousRelease ();
2680                         }
2681                 }
2682
2683                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2684                 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2685
2686                 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
2687                 {
2688                         try {
2689                                 safeHandle.RegisterForBlockingSyscall ();
2690                                 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
2691                         } finally {
2692                                 safeHandle.UnRegisterForBlockingSyscall ();
2693                         }
2694                 }
2695
2696                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2697                 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
2698
2699 #endregion
2700
2701 #region SendTo
2702
2703                 public int SendTo (byte [] buffer, EndPoint remote_end)
2704                 {
2705                         ThrowIfDisposedAndClosed ();
2706                         ThrowIfBufferNull (buffer);
2707
2708                         return SendTo (buffer, 0, buffer.Length, SocketFlags.None, remote_end);
2709                 }
2710
2711                 public int SendTo (byte [] buffer, SocketFlags flags, EndPoint remote_end)
2712                 {
2713                         ThrowIfDisposedAndClosed ();
2714                         ThrowIfBufferNull (buffer);
2715
2716                         return SendTo (buffer, 0, buffer.Length, flags, remote_end);
2717                 }
2718
2719                 public int SendTo (byte [] buffer, int size, SocketFlags flags, EndPoint remote_end)
2720                 {
2721                         return SendTo (buffer, 0, size, flags, remote_end);
2722                 }
2723
2724                 public int SendTo (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2725                 {
2726                         ThrowIfDisposedAndClosed ();
2727                         ThrowIfBufferNull (buffer);
2728                         ThrowIfBufferOutOfRange (buffer, offset, size);
2729
2730                         if (remote_end == null)
2731                                 throw new ArgumentNullException("remote_end");
2732
2733                         return SendTo_nochecks (buffer, offset, size, flags, remote_end);
2734                 }
2735
2736                 public bool SendToAsync (SocketAsyncEventArgs e)
2737                 {
2738                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2739
2740                         ThrowIfDisposedAndClosed ();
2741
2742                         if (e.BufferList != null)
2743                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2744                         if (e.RemoteEndPoint == null)
2745                                 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2746
2747                         InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2748
2749                         e.socket_async_result.Buffer = e.Buffer;
2750                         e.socket_async_result.Offset = e.Offset;
2751                         e.socket_async_result.Size = e.Count;
2752                         e.socket_async_result.SockFlags = e.SocketFlags;
2753                         e.socket_async_result.EndPoint = e.RemoteEndPoint;
2754
2755                         QueueIOSelectorJob (writeQ, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2756
2757                         return true;
2758                 }
2759
2760                 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2761                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2762
2763                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2764                                 throw new InvalidOperationException ("No operation in progress");
2765
2766                         try {
2767                                 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2768                         } catch (SocketException ex) {
2769                                 e.SocketError = ex.SocketErrorCode;
2770                         } catch (ObjectDisposedException) {
2771                                 e.SocketError = SocketError.OperationAborted;
2772                         } finally {
2773                                 e.Complete ();
2774                         }
2775                 });
2776
2777                 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2778                 {
2779                         ThrowIfDisposedAndClosed ();
2780                         ThrowIfBufferNull (buffer);
2781                         ThrowIfBufferOutOfRange (buffer, offset, size);
2782
2783                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2784                                 Buffer = buffer,
2785                                 Offset = offset,
2786                                 Size = size,
2787                                 SockFlags = socket_flags,
2788                                 EndPoint = remote_end,
2789                         };
2790
2791                         QueueIOSelectorJob (writeQ, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2792
2793                         return sockares;
2794                 }
2795
2796                 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2797                 {
2798                         int total = 0;
2799                         try {
2800                                 total = sockares.socket.SendTo_nochecks (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2801
2802                                 if (sockares.error == 0) {
2803                                         sent_so_far += total;
2804                                         sockares.Offset += total;
2805                                         sockares.Size -= total;
2806                                 }
2807
2808                                 if (sockares.Size > 0) {
2809                                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2810                                         return; // Have to finish writing everything. See bug #74475.
2811                                 }
2812
2813                                 sockares.Total = sent_so_far;
2814                         } catch (Exception e) {
2815                                 sockares.Complete (e);
2816                                 return;
2817                         }
2818
2819                         sockares.Complete ();
2820                 }
2821
2822                 public int EndSendTo (IAsyncResult result)
2823                 {
2824                         ThrowIfDisposedAndClosed ();
2825
2826                         SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2827
2828                         if (!sockares.IsCompleted)
2829                                 sockares.AsyncWaitHandle.WaitOne();
2830
2831                         sockares.CheckIfThrowDelayedException();
2832
2833                         return sockares.Total;
2834                 }
2835
2836                 int SendTo_nochecks (byte [] buffer, int offset, int size, SocketFlags flags, EndPoint remote_end)
2837                 {
2838                         int error;
2839                         int ret = SendTo_internal (safe_handle, buffer, offset, size, flags, remote_end.Serialize (), out error);
2840
2841                         SocketError err = (SocketError) error;
2842                         if (err != 0) {
2843                                 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2844                                         is_connected = false;
2845                                 throw new SocketException (error);
2846                         }
2847
2848                         is_connected = true;
2849                         is_bound = true;
2850                         seed_endpoint = remote_end;
2851
2852                         return ret;
2853                 }
2854
2855                 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
2856                 {
2857                         try {
2858                                 safeHandle.RegisterForBlockingSyscall ();
2859                                 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
2860                         } finally {
2861                                 safeHandle.UnRegisterForBlockingSyscall ();
2862                         }
2863                 }
2864
2865                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2866                 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
2867
2868 #endregion
2869
2870 #region SendFile
2871
2872                 public void SendFile (string fileName)
2873                 {
2874                         ThrowIfDisposedAndClosed ();
2875
2876                         if (!is_connected)
2877                                 throw new NotSupportedException ();
2878                         if (!is_blocking)
2879                                 throw new InvalidOperationException ();
2880
2881                         SendFile (fileName, null, null, 0);
2882                 }
2883
2884                 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2885                 {
2886                         ThrowIfDisposedAndClosed ();
2887
2888                         if (!is_connected)
2889                                 throw new NotSupportedException ();
2890                         if (!is_blocking)
2891                                 throw new InvalidOperationException ();
2892
2893                         if (!SendFile_internal (safe_handle, fileName, preBuffer, postBuffer, flags)) {
2894                                 SocketException exc = new SocketException ();
2895                                 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2896                                         throw new FileNotFoundException ();
2897                                 throw exc;
2898                         }
2899                 }
2900
2901                 public IAsyncResult BeginSendFile (string fileName, AsyncCallback callback, object state)
2902                 {
2903                         ThrowIfDisposedAndClosed ();
2904
2905                         if (!is_connected)
2906                                 throw new NotSupportedException ();
2907                         if (!File.Exists (fileName))
2908                                 throw new FileNotFoundException ();
2909
2910                         return BeginSendFile (fileName, null, null, 0, callback, state);
2911                 }
2912
2913                 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2914                 {
2915                         ThrowIfDisposedAndClosed ();
2916
2917                         if (!is_connected)
2918                                 throw new NotSupportedException ();
2919                         if (!File.Exists (fileName))
2920                                 throw new FileNotFoundException ();
2921
2922                         SendFileHandler handler = new SendFileHandler (SendFile);
2923
2924                         return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2925                 }
2926
2927                 public void EndSendFile (IAsyncResult asyncResult)
2928                 {
2929                         ThrowIfDisposedAndClosed ();
2930
2931                         if (asyncResult == null)
2932                                 throw new ArgumentNullException ("asyncResult");
2933
2934                         SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2935                         if (ares == null)
2936                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2937
2938                         ares.Delegate.EndInvoke (ares.Original);
2939                 }
2940
2941                 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
2942                 {
2943                         try {
2944                                 safeHandle.RegisterForBlockingSyscall ();
2945                                 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
2946                         } finally {
2947                                 safeHandle.UnRegisterForBlockingSyscall ();
2948                         }
2949                 }
2950
2951                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2952                 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
2953
2954                 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2955
2956                 sealed class SendFileAsyncResult : IAsyncResult {
2957                         IAsyncResult ares;
2958                         SendFileHandler d;
2959
2960                         public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2961                         {
2962                                 this.d = d;
2963                                 this.ares = ares;
2964                         }
2965
2966                         public object AsyncState {
2967                                 get { return ares.AsyncState; }
2968                         }
2969
2970                         public WaitHandle AsyncWaitHandle {
2971                                 get { return ares.AsyncWaitHandle; }
2972                         }
2973
2974                         public bool CompletedSynchronously {
2975                                 get { return ares.CompletedSynchronously; }
2976                         }
2977
2978                         public bool IsCompleted {
2979                                 get { return ares.IsCompleted; }
2980                         }
2981
2982                         public SendFileHandler Delegate {
2983                                 get { return d; }
2984                         }
2985
2986                         public IAsyncResult Original {
2987                                 get { return ares; }
2988                         }
2989                 }
2990
2991 #endregion
2992
2993 #region SendPackets
2994
2995                 [MonoTODO ("Not implemented")]
2996                 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2997                 {
2998                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2999
3000                         ThrowIfDisposedAndClosed ();
3001
3002                         throw new NotImplementedException ();
3003                 }
3004
3005 #endregion
3006
3007 #region DuplicateAndClose
3008
3009 #if !MOBILE
3010                 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
3011                 public SocketInformation DuplicateAndClose (int targetProcessId)
3012                 {
3013                         var si = new SocketInformation ();
3014                         si.Options =
3015                                 (is_listening      ? SocketInformationOptions.Listening : 0) |
3016                                 (is_connected      ? SocketInformationOptions.Connected : 0) |
3017                                 (is_blocking       ? 0 : SocketInformationOptions.NonBlocking) |
3018                                 (use_overlapped_io ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
3019
3020                         si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, is_bound ? 1 : 0, (long)Handle);
3021                         safe_handle = null;
3022
3023                         return si;
3024                 }
3025 #endif
3026
3027 #endregion
3028
3029 #region GetSocketOption
3030
3031                 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3032                 {
3033                         ThrowIfDisposedAndClosed ();
3034
3035                         if (optionValue == null)
3036                                 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3037
3038                         int error;
3039                         GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref optionValue, out error);
3040
3041                         if (error != 0)
3042                                 throw new SocketException (error);
3043                 }
3044
3045                 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int length)
3046                 {
3047                         ThrowIfDisposedAndClosed ();
3048
3049                         int error;
3050                         byte[] byte_val = new byte [length];
3051                         GetSocketOption_arr_internal (safe_handle, optionLevel, optionName, ref byte_val, out error);
3052
3053                         if (error != 0)
3054                                 throw new SocketException (error);
3055
3056                         return byte_val;
3057                 }
3058
3059                 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
3060                 {
3061                         ThrowIfDisposedAndClosed ();
3062
3063                         int error;
3064                         object obj_val;
3065                         GetSocketOption_obj_internal (safe_handle, optionLevel, optionName, out obj_val, out error);
3066
3067                         if (error != 0)
3068                                 throw new SocketException (error);
3069
3070                         if (optionName == SocketOptionName.Linger)
3071                                 return (LingerOption) obj_val;
3072                         else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
3073                                 return (MulticastOption) obj_val;
3074                         else if (obj_val is int)
3075                                 return (int) obj_val;
3076                         else
3077                                 return obj_val;
3078                 }
3079
3080                 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
3081                 {
3082                         bool release = false;
3083                         try {
3084                                 safeHandle.DangerousAddRef (ref release);
3085                                 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
3086                         } finally {
3087                                 if (release)
3088                                         safeHandle.DangerousRelease ();
3089                         }
3090                 }
3091
3092                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3093                 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
3094
3095                 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
3096                 {
3097                         bool release = false;
3098                         try {
3099                                 safeHandle.DangerousAddRef (ref release);
3100                                 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
3101                         } finally {
3102                                 if (release)
3103                                         safeHandle.DangerousRelease ();
3104                         }
3105                 }
3106
3107                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3108                 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
3109
3110 #endregion
3111
3112 #region SetSocketOption
3113
3114                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
3115                 {
3116                         ThrowIfDisposedAndClosed ();
3117
3118                         // I'd throw an ArgumentNullException, but this is what MS does.
3119                         if (optionValue == null)
3120                                 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
3121
3122                         int error;
3123                         SetSocketOption_internal (safe_handle, optionLevel, optionName, null, optionValue, 0, out error);
3124
3125                         if (error != 0) {
3126                                 if (error == (int) SocketError.InvalidArgument)
3127                                         throw new ArgumentException ();
3128                                 throw new SocketException (error);
3129                         }
3130                 }
3131
3132                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
3133                 {
3134                         ThrowIfDisposedAndClosed ();
3135
3136                         // NOTE: if a null is passed, the byte[] overload is used instead...
3137                         if (optionValue == null)
3138                                 throw new ArgumentNullException("optionValue");
3139
3140                         int error;
3141
3142                         if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
3143                                 LingerOption linger = optionValue as LingerOption;
3144                                 if (linger == null)
3145                                         throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
3146                                 SetSocketOption_internal (safe_handle, optionLevel, optionName, linger, null, 0, out error);
3147                         } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3148                                 MulticastOption multicast = optionValue as MulticastOption;
3149                                 if (multicast == null)
3150                                         throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
3151                                 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3152                         } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
3153                                 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
3154                                 if (multicast == null)
3155                                         throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
3156                                 SetSocketOption_internal (safe_handle, optionLevel, optionName, multicast, null, 0, out error);
3157                         } else {
3158                                 throw new ArgumentException ("Invalid value specified.", "optionValue");
3159                         }
3160
3161                         if (error != 0) {
3162                                 if (error == (int) SocketError.InvalidArgument)
3163                                         throw new ArgumentException ();
3164                                 throw new SocketException (error);
3165                         }
3166                 }
3167
3168                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
3169                 {
3170                         int int_val = optionValue ? 1 : 0;
3171
3172                         SetSocketOption (optionLevel, optionName, int_val);
3173                 }
3174
3175                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
3176                 {
3177                         ThrowIfDisposedAndClosed ();
3178
3179                         if (optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse ())
3180                                 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.");
3181
3182                         int error;
3183                         SetSocketOption_internal (safe_handle, optionLevel, optionName, null, null, optionValue, out error);
3184
3185                         if (error != 0) {
3186                                 if (error == (int) SocketError.InvalidArgument)
3187                                         throw new ArgumentException ();
3188                                 throw new SocketException (error);
3189                         }
3190                 }
3191
3192                 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
3193                 {
3194                         bool release = false;
3195                         try {
3196                                 safeHandle.DangerousAddRef (ref release);
3197                                 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
3198                         } finally {
3199                                 if (release)
3200                                         safeHandle.DangerousRelease ();
3201                         }
3202                 }
3203
3204                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3205                 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
3206
3207 #endregion
3208
3209 #region IOControl
3210
3211                 public int IOControl (int ioctl_code, byte [] in_value, byte [] out_value)
3212                 {
3213                         if (is_disposed)
3214                                 throw new ObjectDisposedException (GetType ().ToString ());
3215
3216                         int error;
3217                         int result = IOControl_internal (safe_handle, ioctl_code, in_value, out_value, out error);
3218
3219                         if (error != 0)
3220                                 throw new SocketException (error);
3221                         if (result == -1)
3222                                 throw new InvalidOperationException ("Must use Blocking property instead.");
3223
3224                         return result;
3225                 }
3226
3227                 public int IOControl (IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
3228                 {
3229                         return IOControl ((int) ioControlCode, optionInValue, optionOutValue);
3230                 }
3231
3232                 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
3233                 {
3234                         bool release = false;
3235                         try {
3236                                 safeHandle.DangerousAddRef (ref release);
3237                                 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
3238                         } finally {
3239                                 if (release)
3240                                         safeHandle.DangerousRelease ();
3241                         }
3242                 }
3243
3244                 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
3245                  * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
3246                  * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
3247                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3248                 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
3249
3250 #endregion
3251
3252 #region Close
3253
3254                 public void Close ()
3255                 {
3256                         linger_timeout = 0;
3257                         Dispose ();
3258                 }
3259
3260                 public void Close (int timeout)
3261                 {
3262                         linger_timeout = timeout;
3263                         Dispose ();
3264                 }
3265
3266                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3267                 internal extern static void Close_internal (IntPtr socket, out int error);
3268
3269 #endregion
3270
3271 #region Shutdown
3272
3273                 public void Shutdown (SocketShutdown how)
3274                 {
3275                         ThrowIfDisposedAndClosed ();
3276
3277                         if (!is_connected)
3278                                 throw new SocketException (10057); // Not connected
3279
3280                         int error;
3281                         Shutdown_internal (safe_handle, how, out error);
3282
3283                         if (error != 0)
3284                                 throw new SocketException (error);
3285                 }
3286
3287                 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
3288                 {
3289                         bool release = false;
3290                         try {
3291                                 safeHandle.DangerousAddRef (ref release);
3292                                 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
3293                         } finally {
3294                                 if (release)
3295                                         safeHandle.DangerousRelease ();
3296                         }
3297                 }
3298
3299                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
3300                 internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
3301
3302 #endregion
3303
3304 #region Dispose
3305
3306                 protected virtual void Dispose (bool disposing)
3307                 {
3308                         if (is_disposed)
3309                                 return;
3310
3311                         is_disposed = true;
3312                         bool was_connected = is_connected;
3313                         is_connected = false;
3314
3315                         if (safe_handle != null) {
3316                                 is_closed = true;
3317                                 IntPtr x = Handle;
3318
3319                                 if (was_connected)
3320                                         Linger (x);
3321
3322                                 safe_handle.Dispose ();
3323                         }
3324                 }
3325
3326                 public void Dispose ()
3327                 {
3328                         Dispose (true);
3329                         GC.SuppressFinalize (this);
3330                 }
3331
3332                 void Linger (IntPtr handle)
3333                 {
3334                         if (!is_connected || linger_timeout <= 0)
3335                                 return;
3336
3337                         /* We don't want to receive any more data */
3338                         int error;
3339                         Shutdown_internal (handle, SocketShutdown.Receive, out error);
3340
3341                         if (error != 0)
3342                                 return;
3343
3344                         int seconds = linger_timeout / 1000;
3345                         int ms = linger_timeout % 1000;
3346                         if (ms > 0) {
3347                                 /* If the other end closes, this will return 'true' with 'Available' == 0 */
3348                                 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
3349                                 if (error != 0)
3350                                         return;
3351                         }
3352
3353                         if (seconds > 0) {
3354                                 LingerOption linger = new LingerOption (true, seconds);
3355                                 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
3356                                 /* Not needed, we're closing upon return */
3357                                 //if (error != 0)
3358                                 //      return;
3359                         }
3360                 }
3361
3362 #endregion
3363
3364                 void ThrowIfDisposedAndClosed (Socket socket)
3365                 {
3366                         if (socket.is_disposed && socket.is_closed)
3367                                 throw new ObjectDisposedException (socket.GetType ().ToString ());
3368                 }
3369
3370                 void ThrowIfDisposedAndClosed ()
3371                 {
3372                         if (is_disposed && is_closed)
3373                                 throw new ObjectDisposedException (GetType ().ToString ());
3374                 }
3375
3376                 void ThrowIfBufferNull (byte[] buffer)
3377                 {
3378                         if (buffer == null)
3379                                 throw new ArgumentNullException ("buffer");
3380                 }
3381
3382                 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
3383                 {
3384                         if (offset < 0)
3385                                 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
3386                         if (offset > buffer.Length)
3387                                 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
3388                         if (size < 0)
3389                                 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
3390                         if (size > buffer.Length - offset)
3391                                 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
3392                 }
3393
3394                 void ThrowIfUdp ()
3395                 {
3396 #if !NET_2_1 || MOBILE
3397                         if (protocol_type == ProtocolType.Udp)
3398                                 throw new SocketException ((int)SocketError.ProtocolOption);
3399 #endif
3400                 }
3401
3402                 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
3403                 {
3404                         if (ares == null)
3405                                 throw new ArgumentNullException (argName);
3406
3407                         SocketAsyncResult sockares = ares as SocketAsyncResult;
3408                         if (sockares == null)
3409                                 throw new ArgumentException ("Invalid IAsyncResult", argName);
3410                         if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
3411                                 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
3412
3413                         return sockares;
3414                 }
3415
3416                 void QueueIOSelectorJob (Queue<KeyValuePair<IntPtr, IOSelectorJob>> queue, IntPtr handle, IOSelectorJob job)
3417                 {
3418                         int count;
3419                         lock (queue) {
3420                                 queue.Enqueue (new KeyValuePair<IntPtr, IOSelectorJob> (handle, job));
3421                                 count = queue.Count;
3422                         }
3423
3424                         if (count == 1)
3425                                 IOSelector.Add (handle, job);
3426                 }
3427
3428                 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
3429                 {
3430                         e.socket_async_result.Init (this, callback, state, operation);
3431                         if (e.AcceptSocket != null) {
3432                                 e.socket_async_result.AcceptSocket = e.AcceptSocket;
3433                         }
3434                         e.current_socket = this;
3435                         e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
3436                         e.SocketError = SocketError.Success;
3437                         e.BytesTransferred = 0;
3438                 }
3439
3440                 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
3441                 {
3442                         switch (op) {
3443                         case SocketOperation.Connect:
3444                                 return SocketAsyncOperation.Connect;
3445                         case SocketOperation.Accept:
3446                                 return SocketAsyncOperation.Accept;
3447                         case SocketOperation.Disconnect:
3448                                 return SocketAsyncOperation.Disconnect;
3449                         case SocketOperation.Receive:
3450                         case SocketOperation.ReceiveGeneric:
3451                                 return SocketAsyncOperation.Receive;
3452                         case SocketOperation.ReceiveFrom:
3453                                 return SocketAsyncOperation.ReceiveFrom;
3454                         case SocketOperation.Send:
3455                         case SocketOperation.SendGeneric:
3456                                 return SocketAsyncOperation.Send;
3457                         case SocketOperation.SendTo:
3458                                 return SocketAsyncOperation.SendTo;
3459                         default:
3460                                 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
3461                         }
3462                 }
3463                 
3464                 IPEndPoint RemapIPEndPoint (IPEndPoint input) {
3465                         // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
3466                         if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
3467                                 return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
3468                         
3469                         return input;
3470                 }
3471                 
3472                 [StructLayout (LayoutKind.Sequential)]
3473                 struct WSABUF {
3474                         public int len;
3475                         public IntPtr buf;
3476                 }
3477
3478                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3479                 internal static extern void cancel_blocking_socket_operation (Thread thread);
3480
3481                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3482                 internal static extern bool SupportsPortReuse ();
3483         }
3484 }
3485