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