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