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