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