[System*] Throw a PlatformNotSupported exception when using the networking stack...
[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 #if FEATURE_NO_BSD_SOCKETS
881                         throw new PlatformNotSupportedException ("System.Net.Sockets.Socket:Bind is not supported on this platform.");
882 #else
883                         ThrowIfDisposedAndClosed ();
884
885                         if (localEP == null)
886                                 throw new ArgumentNullException("localEP");
887                                 
888                         var ipEndPoint = localEP as IPEndPoint;
889                         if (ipEndPoint != null) {
890                                 localEP = RemapIPEndPoint (ipEndPoint); 
891                         }
892                         
893                         int error;
894                         Bind_internal (m_Handle, localEP.Serialize(), out error);
895
896                         if (error != 0)
897                                 throw new SocketException (error);
898                         if (error == 0)
899                                 is_bound = true;
900
901                         seed_endpoint = localEP;
902 #endif // FEATURE_NO_BSD_SOCKETS
903                 }
904
905                 private static void Bind_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
906                 {
907                         bool release = false;
908                         try {
909                                 safeHandle.DangerousAddRef (ref release);
910                                 Bind_internal (safeHandle.DangerousGetHandle (), sa, out error);
911                         } finally {
912                                 if (release)
913                                         safeHandle.DangerousRelease ();
914                         }
915                 }
916
917                 // Creates a new system socket, returning the handle
918                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
919                 private extern static void Bind_internal(IntPtr sock, SocketAddress sa, out int error);
920
921 #endregion
922
923 #region Listen
924
925                 public void Listen (int backlog)
926                 {
927                         ThrowIfDisposedAndClosed ();
928
929                         if (!is_bound)
930                                 throw new SocketException ((int) SocketError.InvalidArgument);
931
932                         int error;
933                         Listen_internal(m_Handle, backlog, out error);
934
935                         if (error != 0)
936                                 throw new SocketException (error);
937
938                         is_listening = true;
939                 }
940
941                 static void Listen_internal (SafeSocketHandle safeHandle, int backlog, out int error)
942                 {
943                         bool release = false;
944                         try {
945                                 safeHandle.DangerousAddRef (ref release);
946                                 Listen_internal (safeHandle.DangerousGetHandle (), backlog, out error);
947                         } finally {
948                                 if (release)
949                                         safeHandle.DangerousRelease ();
950                         }
951                 }
952
953                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
954                 extern static void Listen_internal (IntPtr sock, int backlog, out int error);
955
956 #endregion
957
958 #region Connect
959
960                 public void Connect (IPAddress address, int port)
961                 {
962                         Connect (new IPEndPoint (address, port));
963                 }
964
965                 public void Connect (string host, int port)
966                 {
967                         Connect (Dns.GetHostAddresses (host), port);
968                 }
969
970                 public void Connect (IPAddress[] addresses, int port)
971                 {
972                         ThrowIfDisposedAndClosed ();
973
974                         if (addresses == null)
975                                 throw new ArgumentNullException ("addresses");
976                         if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
977                                 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
978                         if (is_listening)
979                                 throw new InvalidOperationException ();
980
981                         // FIXME: do non-blocking sockets Poll here?
982                         int error = 0;
983                         foreach (IPAddress address in addresses) {
984                                 IPEndPoint iep = new IPEndPoint (address, port);
985                                 
986                                 iep = RemapIPEndPoint (iep);
987
988                                 Connect_internal (m_Handle, iep.Serialize (), out error);
989                                 if (error == 0) {
990                                         is_connected = true;
991                                         is_bound = true;
992                                         seed_endpoint = iep;
993                                         return;
994                                 }
995                                 if (error != (int)SocketError.InProgress && error != (int)SocketError.WouldBlock)
996                                         continue;
997
998                                 if (!is_blocking) {
999                                         Poll (-1, SelectMode.SelectWrite);
1000                                         error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1001                                         if (error == 0) {
1002                                                 is_connected = true;
1003                                                 is_bound = true;
1004                                                 seed_endpoint = iep;
1005                                                 return;
1006                                         }
1007                                 }
1008                         }
1009
1010                         if (error != 0)
1011                                 throw new SocketException (error);
1012                 }
1013
1014
1015                 public void Connect (EndPoint remoteEP)
1016                 {
1017                         ThrowIfDisposedAndClosed ();
1018
1019                         if (remoteEP == null)
1020                                 throw new ArgumentNullException ("remoteEP");
1021
1022                         IPEndPoint ep = remoteEP as IPEndPoint;
1023                         /* Dgram uses Any to 'disconnect' */
1024                         if (ep != null && socketType != SocketType.Dgram) {
1025                                 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1026                                         throw new SocketException ((int) SocketError.AddressNotAvailable);
1027                         }
1028
1029                         if (is_listening)
1030                                 throw new InvalidOperationException ();
1031                                 
1032                         if (ep != null) {
1033                                 remoteEP = RemapIPEndPoint (ep);
1034                         }
1035
1036                         SocketAddress serial = remoteEP.Serialize ();
1037
1038                         int error = 0;
1039                         Connect_internal (m_Handle, serial, out error);
1040
1041                         if (error == 0 || error == 10035)
1042                                 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1043
1044                         if (error != 0) {
1045                                 if (is_closed)
1046                                         error = SOCKET_CLOSED_CODE;
1047                                 throw new SocketException (error);
1048                         }
1049
1050                         is_connected = !(socketType == SocketType.Dgram && ep != null && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)));
1051                         is_bound = true;
1052                 }
1053
1054                 public bool ConnectAsync (SocketAsyncEventArgs e)
1055                 {
1056                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1057
1058                         ThrowIfDisposedAndClosed ();
1059
1060                         if (is_listening)
1061                                 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1062                         if (e.RemoteEndPoint == null)
1063                                 throw new ArgumentNullException ("remoteEP");
1064
1065                         InitSocketAsyncEventArgs (e, null, e, SocketOperation.Connect);
1066
1067                         try {
1068                                 IPAddress [] addresses;
1069                                 SocketAsyncResult ares;
1070
1071                                 if (!GetCheckedIPs (e, out addresses)) {
1072                                         e.socket_async_result.EndPoint = e.RemoteEndPoint;
1073                                         ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
1074                                 } else {
1075                                         DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1076                                         e.socket_async_result.Addresses = addresses;
1077                                         e.socket_async_result.Port = dep.Port;
1078                                         ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
1079                                 }
1080
1081                                 if (ares.IsCompleted && ares.CompletedSynchronously) {
1082                                         ares.CheckIfThrowDelayedException ();
1083                                         return false;
1084                                 }
1085                         } catch (Exception exc) {
1086                                 e.socket_async_result.Complete (exc, true);
1087                                 return false;
1088                         }
1089
1090                         return true;
1091                 }
1092
1093                 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
1094                 {
1095                         var sock = new Socket (e.RemoteEndPoint.AddressFamily, socketType, protocolType);
1096                         return sock.ConnectAsync (e);
1097                 }
1098
1099                 public static void CancelConnectAsync (SocketAsyncEventArgs e)
1100                 {
1101                         if (e == null)
1102                                 throw new ArgumentNullException("e");
1103
1104                         if (e.in_progress != 0 && e.LastOperation == SocketAsyncOperation.Connect)
1105                                 e.current_socket.Close();
1106                 }
1107
1108                 static AsyncCallback ConnectAsyncCallback = new AsyncCallback (ares => {
1109                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1110
1111                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1112                                 throw new InvalidOperationException ("No operation in progress");
1113
1114                         try {
1115                                 e.current_socket.EndConnect (ares);
1116                         } catch (SocketException se) {
1117                                 e.SocketError = se.SocketErrorCode;
1118                         } catch (ObjectDisposedException) {
1119                                 e.SocketError = SocketError.OperationAborted;
1120                         } finally {
1121                                 e.Complete ();
1122                         }
1123                 });
1124
1125                 public IAsyncResult BeginConnect (string host, int port, AsyncCallback callback, object state)
1126                 {
1127                         ThrowIfDisposedAndClosed ();
1128
1129                         if (host == null)
1130                                 throw new ArgumentNullException ("host");
1131                         if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6)
1132                                 throw new NotSupportedException ("This method is valid only for sockets in the InterNetwork and InterNetworkV6 families");
1133                         if (port <= 0 || port > 65535)
1134                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1135                         if (is_listening)
1136                                 throw new InvalidOperationException ();
1137
1138                         return BeginConnect (Dns.GetHostAddresses (host), port, callback, state);
1139                 }
1140
1141                 public IAsyncResult BeginConnect (EndPoint end_point, AsyncCallback callback, object state)
1142                 {
1143                         ThrowIfDisposedAndClosed ();
1144
1145                         if (end_point == null)
1146                                 throw new ArgumentNullException ("end_point");
1147                         if (is_listening)
1148                                 throw new InvalidOperationException ();
1149
1150                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1151                                 EndPoint = end_point,
1152                         };
1153
1154                         // Bug #75154: Connect() should not succeed for .Any addresses.
1155                         if (end_point is IPEndPoint) {
1156                                 IPEndPoint ep = (IPEndPoint) end_point;
1157                                 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1158                                         sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1159                                         return sockares;
1160                                 }
1161                                 
1162                                 end_point = RemapIPEndPoint (ep);
1163                         }
1164
1165                         int error = 0;
1166
1167                         if (connect_in_progress) {
1168                                 // This could happen when multiple IPs are used
1169                                 // Calling connect() again will reset the connection attempt and cause
1170                                 // an error. Better to just close the socket and move on.
1171                                 connect_in_progress = false;
1172                                 m_Handle.Dispose ();
1173                                 m_Handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
1174                                 if (error != 0)
1175                                         throw new SocketException (error);
1176                         }
1177
1178                         bool blk = is_blocking;
1179                         if (blk)
1180                                 Blocking = false;
1181                         Connect_internal (m_Handle, end_point.Serialize (), out error);
1182                         if (blk)
1183                                 Blocking = true;
1184
1185                         if (error == 0) {
1186                                 // succeeded synch
1187                                 is_connected = true;
1188                                 is_bound = true;
1189                                 sockares.Complete (true);
1190                                 return sockares;
1191                         }
1192
1193                         if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1194                                 // error synch
1195                                 is_connected = false;
1196                                 is_bound = false;
1197                                 sockares.Complete (new SocketException (error), true);
1198                                 return sockares;
1199                         }
1200
1201                         // continue asynch
1202                         is_connected = false;
1203                         is_bound = false;
1204                         connect_in_progress = true;
1205
1206                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
1207
1208                         return sockares;
1209                 }
1210
1211                 public IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1212                 {
1213                         ThrowIfDisposedAndClosed ();
1214
1215                         if (addresses == null)
1216                                 throw new ArgumentNullException ("addresses");
1217                         if (addresses.Length == 0)
1218                                 throw new ArgumentException ("Empty addresses list");
1219                         if (this.AddressFamily != AddressFamily.InterNetwork && this.AddressFamily != AddressFamily.InterNetworkV6)
1220                                 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1221                         if (port <= 0 || port > 65535)
1222                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1223                         if (is_listening)
1224                                 throw new InvalidOperationException ();
1225
1226                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Connect) {
1227                                 Addresses = addresses,
1228                                 Port = port,
1229                         };
1230
1231                         is_connected = false;
1232
1233                         return BeginMConnect (sockares);
1234                 }
1235
1236                 internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
1237                 {
1238                         SocketAsyncResult ares = null;
1239                         Exception exc = null;
1240                         AsyncCallback callback;
1241
1242                         for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
1243                                 try {
1244                                         sockares.CurrentAddress++;
1245
1246                                         ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
1247                                         if (ares.IsCompleted && ares.CompletedSynchronously) {
1248                                                 ares.CheckIfThrowDelayedException ();
1249
1250                                                 callback = ares.AsyncCallback;
1251                                                 if (callback != null)
1252                                                         ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
1253                                         }
1254
1255                                         break;
1256                                 } catch (Exception e) {
1257                                         exc = e;
1258                                         ares = null;
1259                                 }
1260                         }
1261
1262                         if (ares == null)
1263                                 throw exc;
1264
1265                         return sockares;
1266                 }
1267
1268                 static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
1269                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1270
1271                         if (sockares.EndPoint == null) {
1272                                 sockares.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
1273                                 return;
1274                         }
1275
1276                         SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
1277                         bool is_mconnect = mconnect != null && mconnect.Addresses != null;
1278
1279                         try {
1280                                 EndPoint ep = sockares.EndPoint;
1281                                 int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1282
1283                                 if (error_code == 0) {
1284                                         if (is_mconnect)
1285                                                 sockares = mconnect;
1286
1287                                         sockares.socket.seed_endpoint = ep;
1288                                         sockares.socket.is_connected = true;
1289                                         sockares.socket.is_bound = true;
1290                                         sockares.socket.connect_in_progress = false;
1291                                         sockares.error = 0;
1292                                         sockares.Complete ();
1293                                         return;
1294                                 }
1295
1296                                 if (!is_mconnect) {
1297                                         sockares.socket.connect_in_progress = false;
1298                                         sockares.Complete (new SocketException (error_code));
1299                                         return;
1300                                 }
1301
1302                                 if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
1303                                         mconnect.Complete (new SocketException (error_code));
1304                                         return;
1305                                 }
1306
1307                                 mconnect.socket.BeginMConnect (mconnect);
1308                         } catch (Exception e) {
1309                                 sockares.socket.connect_in_progress = false;
1310
1311                                 if (is_mconnect)
1312                                         sockares = mconnect;
1313
1314                                 sockares.Complete (e);
1315                                 return;
1316                         }
1317                 });
1318
1319                 public void EndConnect (IAsyncResult result)
1320                 {
1321                         ThrowIfDisposedAndClosed ();
1322
1323                         SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndConnect", "result");
1324
1325                         if (!sockares.IsCompleted)
1326                                 sockares.AsyncWaitHandle.WaitOne();
1327
1328                         sockares.CheckIfThrowDelayedException();
1329                 }
1330
1331                 static void Connect_internal (SafeSocketHandle safeHandle, SocketAddress sa, out int error)
1332                 {
1333                         try {
1334                                 safeHandle.RegisterForBlockingSyscall ();
1335                                 Connect_internal (safeHandle.DangerousGetHandle (), sa, out error);
1336                         } finally {
1337                                 safeHandle.UnRegisterForBlockingSyscall ();
1338                         }
1339                 }
1340
1341                 /* Connects to the remote address */
1342                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1343                 extern static void Connect_internal(IntPtr sock, SocketAddress sa, out int error);
1344
1345                 /* Returns :
1346                  *  - false when it is ok to use RemoteEndPoint
1347                  *  - true when addresses must be used (and addresses could be null/empty) */
1348                 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1349                 {
1350                         addresses = null;
1351
1352                         // Connect to the first address that match the host name, like:
1353                         // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1354                         // while skipping entries that do not match the address family
1355                         DnsEndPoint dep = e.RemoteEndPoint as DnsEndPoint;
1356                         if (dep != null) {
1357                                 addresses = Dns.GetHostAddresses (dep.Host);
1358                                 return true;
1359                         } else {
1360                                 e.ConnectByNameError = null;
1361                                 return false;
1362                         }
1363                 }
1364
1365 #endregion
1366
1367 #region Disconnect
1368
1369                 /* According to the docs, the MS runtime will throw PlatformNotSupportedException
1370                  * if the platform is newer than w2k.  We should be able to cope... */
1371                 public void Disconnect (bool reuseSocket)
1372                 {
1373                         ThrowIfDisposedAndClosed ();
1374
1375                         int error = 0;
1376                         Disconnect_internal (m_Handle, reuseSocket, out error);
1377
1378                         if (error != 0) {
1379                                 if (error == 50) {
1380                                         /* ERROR_NOT_SUPPORTED */
1381                                         throw new PlatformNotSupportedException ();
1382                                 } else {
1383                                         throw new SocketException (error);
1384                                 }
1385                         }
1386
1387                         is_connected = false;
1388                         if (reuseSocket) {
1389                                 /* Do managed housekeeping here... */
1390                         }
1391                 }
1392
1393                 public bool DisconnectAsync (SocketAsyncEventArgs e)
1394                 {
1395                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1396
1397                         ThrowIfDisposedAndClosed ();
1398
1399                         InitSocketAsyncEventArgs (e, DisconnectAsyncCallback, e, SocketOperation.Disconnect);
1400
1401                         IOSelector.Add (e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, e.socket_async_result));
1402
1403                         return true;
1404                 }
1405
1406                 static AsyncCallback DisconnectAsyncCallback = new AsyncCallback (ares => {
1407                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1408
1409                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1410                                 throw new InvalidOperationException ("No operation in progress");
1411
1412                         try {
1413                                 e.current_socket.EndDisconnect (ares);
1414                         } catch (SocketException ex) {
1415                                 e.SocketError = ex.SocketErrorCode;
1416                         } catch (ObjectDisposedException) {
1417                                 e.SocketError = SocketError.OperationAborted;
1418                         } finally {
1419                                 e.Complete ();
1420                         }
1421                 });
1422
1423                 public IAsyncResult BeginDisconnect (bool reuseSocket, AsyncCallback callback, object state)
1424                 {
1425                         ThrowIfDisposedAndClosed ();
1426
1427                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Disconnect) {
1428                                 ReuseSocket = reuseSocket,
1429                         };
1430
1431                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginDisconnectCallback, sockares));
1432
1433                         return sockares;
1434                 }
1435
1436                 static IOAsyncCallback BeginDisconnectCallback = new IOAsyncCallback (ares => {
1437                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1438
1439                         try {
1440                                 sockares.socket.Disconnect (sockares.ReuseSocket);
1441                         } catch (Exception e) {
1442                                 sockares.Complete (e);
1443                                 return;
1444                         }
1445
1446                         sockares.Complete ();
1447                 });
1448
1449                 public void EndDisconnect (IAsyncResult asyncResult)
1450                 {
1451                         ThrowIfDisposedAndClosed ();
1452
1453                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndDisconnect", "asyncResult");
1454
1455                         if (!sockares.IsCompleted)
1456                                 sockares.AsyncWaitHandle.WaitOne ();
1457
1458                         sockares.CheckIfThrowDelayedException ();
1459                 }
1460
1461                 static void Disconnect_internal (SafeSocketHandle safeHandle, bool reuse, out int error)
1462                 {
1463                         bool release = false;
1464                         try {
1465                                 safeHandle.DangerousAddRef (ref release);
1466                                 Disconnect_internal (safeHandle.DangerousGetHandle (), reuse, out error);
1467                         } finally {
1468                                 if (release)
1469                                         safeHandle.DangerousRelease ();
1470                         }
1471                 }
1472
1473                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1474                 extern static void Disconnect_internal (IntPtr sock, bool reuse, out int error);
1475
1476 #endregion
1477
1478 #region Receive
1479
1480                 public int Receive (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1481                 {
1482                         ThrowIfDisposedAndClosed ();
1483                         ThrowIfBufferNull (buffer);
1484                         ThrowIfBufferOutOfRange (buffer, offset, size);
1485
1486                         int nativeError;
1487                         int ret = Receive_internal (m_Handle, buffer, offset, size, socketFlags, out nativeError);
1488
1489                         errorCode = (SocketError) nativeError;
1490                         if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1491                                 is_connected = false;
1492                                 is_bound = false;
1493                         } else {
1494                                 is_connected = true;
1495                         }
1496
1497                         return ret;
1498                 }
1499
1500                 [CLSCompliant (false)]
1501                 public int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1502                 {
1503                         ThrowIfDisposedAndClosed ();
1504
1505                         if (buffers == null || buffers.Count == 0)
1506                                 throw new ArgumentNullException ("buffers");
1507
1508                         int numsegments = buffers.Count;
1509                         int nativeError;
1510                         int ret;
1511
1512                         /* Only example I can find of sending a byte array reference directly into an internal
1513                          * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1514                          * so taking a lead from that... */
1515                         WSABUF[] bufarray = new WSABUF[numsegments];
1516                         GCHandle[] gch = new GCHandle[numsegments];
1517
1518                         for (int i = 0; i < numsegments; i++) {
1519                                 ArraySegment<byte> segment = buffers[i];
1520
1521                                 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1522                                         throw new ArgumentOutOfRangeException ("segment");
1523
1524                                 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1525                                 bufarray[i].len = segment.Count;
1526                                 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1527                         }
1528
1529                         try {
1530                                 ret = Receive_internal (m_Handle, bufarray, socketFlags, out nativeError);
1531                         } finally {
1532                                 for (int i = 0; i < numsegments; i++) {
1533                                         if (gch[i].IsAllocated)
1534                                                 gch[i].Free ();
1535                                 }
1536                         }
1537
1538                         errorCode = (SocketError) nativeError;
1539
1540                         return ret;
1541                 }
1542
1543                 public bool ReceiveAsync (SocketAsyncEventArgs e)
1544                 {
1545                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1546
1547                         ThrowIfDisposedAndClosed ();
1548
1549                         // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1550                         // thrown when e.Buffer and e.BufferList are null (works fine when one is
1551                         // set to a valid object)
1552                         if (e.Buffer == null && e.BufferList == null)
1553                                 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1554
1555                         if (e.Buffer == null) {
1556                                 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.ReceiveGeneric);
1557
1558                                 e.socket_async_result.Buffers = e.BufferList;
1559
1560                                 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, e.socket_async_result));
1561                         } else {
1562                                 InitSocketAsyncEventArgs (e, ReceiveAsyncCallback, e, SocketOperation.Receive);
1563
1564                                 e.socket_async_result.Buffer = e.Buffer;
1565                                 e.socket_async_result.Offset = e.Offset;
1566                                 e.socket_async_result.Size = e.Count;
1567
1568                                 QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, e.socket_async_result));
1569                         }
1570
1571                         return true;
1572                 }
1573
1574                 static AsyncCallback ReceiveAsyncCallback = new AsyncCallback (ares => {
1575                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1576
1577                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1578                                 throw new InvalidOperationException ("No operation in progress");
1579
1580                         try {
1581                                 e.BytesTransferred = e.current_socket.EndReceive (ares);
1582                         } catch (SocketException se){
1583                                 e.SocketError = se.SocketErrorCode;
1584                         } catch (ObjectDisposedException) {
1585                                 e.SocketError = SocketError.OperationAborted;
1586                         } finally {
1587                                 e.Complete ();
1588                         }
1589                 });
1590
1591                 public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1592                 {
1593                         ThrowIfDisposedAndClosed ();
1594                         ThrowIfBufferNull (buffer);
1595                         ThrowIfBufferOutOfRange (buffer, offset, size);
1596
1597                         /* As far as I can tell from the docs and from experimentation, a pointer to the
1598                          * SocketError parameter is not supposed to be saved for the async parts.  And as we don't
1599                          * set any socket errors in the setup code, we just have to set it to Success. */
1600                         errorCode = SocketError.Success;
1601
1602                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Receive) {
1603                                 Buffer = buffer,
1604                                 Offset = offset,
1605                                 Size = size,
1606                                 SockFlags = socketFlags,
1607                         };
1608
1609                         QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveCallback, sockares));
1610
1611                         return sockares;
1612                 }
1613
1614                 static IOAsyncCallback BeginReceiveCallback = new IOAsyncCallback (ares => {
1615                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1616                         int total = 0;
1617
1618                         try {
1619                                 total = Receive_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
1620                         } catch (Exception e) {
1621                                 sockares.Complete (e);
1622                                 return;
1623                         }
1624
1625                         sockares.Complete (total);
1626                 });
1627
1628                 [CLSCompliant (false)]
1629                 public IAsyncResult BeginReceive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
1630                 {
1631                         ThrowIfDisposedAndClosed ();
1632
1633                         if (buffers == null)
1634                                 throw new ArgumentNullException ("buffers");
1635
1636                         /* I assume the same SocketError semantics as above */
1637                         errorCode = SocketError.Success;
1638
1639                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveGeneric) {
1640                                 Buffers = buffers,
1641                                 SockFlags = socketFlags,
1642                         };
1643
1644                         QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveGenericCallback, sockares));
1645
1646                         return sockares;
1647                 }
1648
1649                 static IOAsyncCallback BeginReceiveGenericCallback = new IOAsyncCallback (ares => {
1650                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1651                         int total = 0;
1652
1653                         try {
1654                                 total = sockares.socket.Receive (sockares.Buffers, sockares.SockFlags);
1655                         } catch (Exception e) {
1656                                 sockares.Complete (e);
1657                                 return;
1658                         }
1659
1660                         sockares.Complete (total);
1661                 });
1662
1663                 public int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
1664                 {
1665                         ThrowIfDisposedAndClosed ();
1666
1667                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceive", "asyncResult");
1668
1669                         if (!sockares.IsCompleted)
1670                                 sockares.AsyncWaitHandle.WaitOne ();
1671
1672                         errorCode = sockares.ErrorCode;
1673
1674                         if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress)
1675                                 is_connected = false;
1676
1677                         // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
1678                         // kinds of exceptions that should be thrown.
1679                         if (errorCode == SocketError.Success)
1680                                 sockares.CheckIfThrowDelayedException();
1681
1682                         return sockares.Total;
1683                 }
1684
1685                 static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
1686                 {
1687                         try {
1688                                 safeHandle.RegisterForBlockingSyscall ();
1689                                 return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
1690                         } finally {
1691                                 safeHandle.UnRegisterForBlockingSyscall ();
1692                         }
1693                 }
1694
1695                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1696                 extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
1697
1698                 static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error)
1699                 {
1700                         try {
1701                                 safeHandle.RegisterForBlockingSyscall ();
1702                                 return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error);
1703                         } finally {
1704                                 safeHandle.UnRegisterForBlockingSyscall ();
1705                         }
1706                 }
1707
1708                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1709                 extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error);
1710
1711 #endregion
1712
1713 #region ReceiveFrom
1714
1715                 public int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP)
1716                 {
1717                         ThrowIfDisposedAndClosed ();
1718                         ThrowIfBufferNull (buffer);
1719                         ThrowIfBufferOutOfRange (buffer, offset, size);
1720
1721                         if (remoteEP == null)
1722                                 throw new ArgumentNullException ("remoteEP");
1723
1724                         SocketError errorCode;
1725                         int ret = ReceiveFrom (buffer, offset, size, socketFlags, ref remoteEP, out errorCode);
1726
1727                         if (errorCode != SocketError.Success)
1728                                 throw new SocketException (errorCode);
1729
1730                         return ret;
1731                 }
1732
1733                 internal int ReceiveFrom (byte [] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, out SocketError errorCode)
1734                 {
1735                         SocketAddress sockaddr = remoteEP.Serialize();
1736
1737                         int nativeError;
1738                         int cnt = ReceiveFrom_internal (m_Handle, buffer, offset, size, socketFlags, ref sockaddr, out nativeError);
1739
1740                         errorCode = (SocketError) nativeError;
1741                         if (errorCode != SocketError.Success) {
1742                                 if (errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1743                                         is_connected = false;
1744                                 } else if (errorCode == SocketError.WouldBlock && is_blocking) { // This might happen when ReceiveTimeout is set
1745                                         errorCode = SocketError.TimedOut;
1746                                 }
1747
1748                                 return 0;
1749                         }
1750
1751                         is_connected = true;
1752                         is_bound = true;
1753
1754                         /* If sockaddr is null then we're a connection oriented protocol and should ignore the
1755                          * remoteEP parameter (see MSDN documentation for Socket.ReceiveFrom(...) ) */
1756                         if (sockaddr != null) {
1757                                 /* Stupidly, EndPoint.Create() is an instance method */
1758                                 remoteEP = remoteEP.Create (sockaddr);
1759                         }
1760
1761                         seed_endpoint = remoteEP;
1762
1763                         return cnt;
1764                 }
1765
1766                 public bool ReceiveFromAsync (SocketAsyncEventArgs e)
1767                 {
1768                         ThrowIfDisposedAndClosed ();
1769
1770                         // We do not support recv into multiple buffers yet
1771                         if (e.BufferList != null)
1772                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
1773                         if (e.RemoteEndPoint == null)
1774                                 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
1775
1776                         InitSocketAsyncEventArgs (e, ReceiveFromAsyncCallback, e, SocketOperation.ReceiveFrom);
1777
1778                         e.socket_async_result.Buffer = e.Buffer;
1779                         e.socket_async_result.Offset = e.Offset;
1780                         e.socket_async_result.Size = e.Count;
1781                         e.socket_async_result.EndPoint = e.RemoteEndPoint;
1782                         e.socket_async_result.SockFlags = e.SocketFlags;
1783
1784                         QueueIOSelectorJob (ReadSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, e.socket_async_result));
1785
1786                         return true;
1787                 }
1788
1789                 static AsyncCallback ReceiveFromAsyncCallback = new AsyncCallback (ares => {
1790                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
1791
1792                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
1793                                 throw new InvalidOperationException ("No operation in progress");
1794
1795                         try {
1796                                 e.BytesTransferred = e.current_socket.EndReceiveFrom (ares, ref e.remote_ep);
1797                         } catch (SocketException ex) {
1798                                 e.SocketError = ex.SocketErrorCode;
1799                         } catch (ObjectDisposedException) {
1800                                 e.SocketError = SocketError.OperationAborted;
1801                         } finally {
1802                                 e.Complete ();
1803                         }
1804                 });
1805
1806                 public IAsyncResult BeginReceiveFrom (byte[] buffer, int offset, int size, SocketFlags socket_flags, ref EndPoint remote_end, AsyncCallback callback, object state)
1807                 {
1808                         ThrowIfDisposedAndClosed ();
1809                         ThrowIfBufferNull (buffer);
1810                         ThrowIfBufferOutOfRange (buffer, offset, size);
1811
1812                         if (remote_end == null)
1813                                 throw new ArgumentNullException ("remote_end");
1814
1815                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.ReceiveFrom) {
1816                                 Buffer = buffer,
1817                                 Offset = offset,
1818                                 Size = size,
1819                                 SockFlags = socket_flags,
1820                                 EndPoint = remote_end,
1821                         };
1822
1823                         QueueIOSelectorJob (ReadSem, sockares.Handle, new IOSelectorJob (IOOperation.Read, BeginReceiveFromCallback, sockares));
1824
1825                         return sockares;
1826                 }
1827
1828                 static IOAsyncCallback BeginReceiveFromCallback = new IOAsyncCallback (ares => {
1829                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
1830                         int total = 0;
1831
1832                         try {
1833                                 SocketError errorCode;
1834                                 total = sockares.socket.ReceiveFrom (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, ref sockares.EndPoint, out errorCode);
1835
1836                                 if (errorCode != SocketError.Success) {
1837                                         sockares.Complete (new SocketException (errorCode));
1838                                         return;
1839                                 }
1840                         } catch (Exception e) {
1841                                 sockares.Complete (e);
1842                                 return;
1843                         }
1844
1845                         sockares.Complete (total);
1846                 });
1847
1848                 public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
1849                 {
1850                         ThrowIfDisposedAndClosed ();
1851
1852                         if (end_point == null)
1853                                 throw new ArgumentNullException ("remote_end");
1854
1855                         SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndReceiveFrom", "result");
1856
1857                         if (!sockares.IsCompleted)
1858                                 sockares.AsyncWaitHandle.WaitOne();
1859
1860                         sockares.CheckIfThrowDelayedException();
1861
1862                         end_point = sockares.EndPoint;
1863
1864                         return sockares.Total;
1865                 }
1866
1867
1868
1869                 static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error)
1870                 {
1871                         try {
1872                                 safeHandle.RegisterForBlockingSyscall ();
1873                                 return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error);
1874                         } finally {
1875                                 safeHandle.UnRegisterForBlockingSyscall ();
1876                         }
1877                 }
1878
1879                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1880                 extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error);
1881
1882 #endregion
1883
1884 #region ReceiveMessageFrom
1885
1886                 [MonoTODO ("Not implemented")]
1887                 public int ReceiveMessageFrom (byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
1888                 {
1889                         ThrowIfDisposedAndClosed ();
1890                         ThrowIfBufferNull (buffer);
1891                         ThrowIfBufferOutOfRange (buffer, offset, size);
1892
1893                         if (remoteEP == null)
1894                                 throw new ArgumentNullException ("remoteEP");
1895
1896                         // FIXME: figure out how we get hold of the IPPacketInformation
1897                         throw new NotImplementedException ();
1898                 }
1899
1900                 [MonoTODO ("Not implemented")]
1901                 public bool ReceiveMessageFromAsync (SocketAsyncEventArgs e)
1902                 {
1903                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1904
1905                         ThrowIfDisposedAndClosed ();
1906
1907                         throw new NotImplementedException ();
1908                 }
1909
1910                 [MonoTODO]
1911                 public IAsyncResult BeginReceiveMessageFrom (byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, object state)
1912                 {
1913                         ThrowIfDisposedAndClosed ();
1914                         ThrowIfBufferNull (buffer);
1915                         ThrowIfBufferOutOfRange (buffer, offset, size);
1916
1917                         if (remoteEP == null)
1918                                 throw new ArgumentNullException ("remoteEP");
1919
1920                         throw new NotImplementedException ();
1921                 }
1922
1923                 [MonoTODO]
1924                 public int EndReceiveMessageFrom (IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation)
1925                 {
1926                         ThrowIfDisposedAndClosed ();
1927
1928                         if (endPoint == null)
1929                                 throw new ArgumentNullException ("endPoint");
1930
1931                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndReceiveMessageFrom", "asyncResult");
1932
1933                         throw new NotImplementedException ();
1934                 }
1935
1936 #endregion
1937
1938 #region Send
1939
1940                 public int Send (byte [] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode)
1941                 {
1942                         ThrowIfDisposedAndClosed ();
1943                         ThrowIfBufferNull (buffer);
1944                         ThrowIfBufferOutOfRange (buffer, offset, size);
1945
1946                         if (size == 0) {
1947                                 errorCode = SocketError.Success;
1948                                 return 0;
1949                         }
1950
1951                         int nativeError;
1952                         int sent = 0;
1953                         do {
1954                                 sent += Send_internal (
1955 m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError);
1956                                 errorCode = (SocketError)nativeError;
1957                                 if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
1958                                         is_connected = false;
1959                                         is_bound = false;
1960                                         break;
1961                                 } else {
1962                                         is_connected = true;
1963                                 }
1964                         } while (sent < size);
1965
1966                         return sent;
1967                 }
1968
1969                 [CLSCompliant (false)]
1970                 public int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1971                 {
1972                         ThrowIfDisposedAndClosed ();
1973
1974                         if (buffers == null)
1975                                 throw new ArgumentNullException ("buffers");
1976                         if (buffers.Count == 0)
1977                                 throw new ArgumentException ("Buffer is empty", "buffers");
1978
1979                         int numsegments = buffers.Count;
1980                         int nativeError;
1981                         int ret;
1982
1983                         WSABUF[] bufarray = new WSABUF[numsegments];
1984                         GCHandle[] gch = new GCHandle[numsegments];
1985
1986                         for(int i = 0; i < numsegments; i++) {
1987                                 ArraySegment<byte> segment = buffers[i];
1988
1989                                 if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
1990                                         throw new ArgumentOutOfRangeException ("segment");
1991
1992                                 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1993                                 bufarray[i].len = segment.Count;
1994                                 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1995                         }
1996
1997                         try {
1998                                 ret = Send_internal (m_Handle, bufarray, socketFlags, out nativeError);
1999                         } finally {
2000                                 for(int i = 0; i < numsegments; i++) {
2001                                         if (gch[i].IsAllocated) {
2002                                                 gch[i].Free ();
2003                                         }
2004                                 }
2005                         }
2006
2007                         errorCode = (SocketError)nativeError;
2008
2009                         return ret;
2010                 }
2011
2012                 public bool SendAsync (SocketAsyncEventArgs e)
2013                 {
2014                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2015
2016                         ThrowIfDisposedAndClosed ();
2017
2018                         if (e.Buffer == null && e.BufferList == null)
2019                                 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
2020
2021                         if (e.Buffer == null) {
2022                                 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.SendGeneric);
2023
2024                                 e.socket_async_result.Buffers = e.BufferList;
2025
2026                                 QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, e.socket_async_result));
2027                         } else {
2028                                 InitSocketAsyncEventArgs (e, SendAsyncCallback, e, SocketOperation.Send);
2029
2030                                 e.socket_async_result.Buffer = e.Buffer;
2031                                 e.socket_async_result.Offset = e.Offset;
2032                                 e.socket_async_result.Size = e.Count;
2033
2034                                 QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2035                         }
2036
2037                         return true;
2038                 }
2039
2040                 static AsyncCallback SendAsyncCallback = new AsyncCallback (ares => {
2041                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2042
2043                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2044                                 throw new InvalidOperationException ("No operation in progress");
2045
2046                         try {
2047                                 e.BytesTransferred = e.current_socket.EndSend (ares);
2048                         } catch (SocketException se){
2049                                 e.SocketError = se.SocketErrorCode;
2050                         } catch (ObjectDisposedException) {
2051                                 e.SocketError = SocketError.OperationAborted;
2052                         } finally {
2053                                 e.Complete ();
2054                         }
2055                 });
2056
2057                 public IAsyncResult BeginSend (byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2058                 {
2059                         ThrowIfDisposedAndClosed ();
2060                         ThrowIfBufferNull (buffer);
2061                         ThrowIfBufferOutOfRange (buffer, offset, size);
2062
2063                         if (!is_connected) {
2064                                 errorCode = SocketError.NotConnected;
2065                                 return null;
2066                         }
2067
2068                         errorCode = SocketError.Success;
2069
2070                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.Send) {
2071                                 Buffer = buffer,
2072                                 Offset = offset,
2073                                 Size = size,
2074                                 SockFlags = socketFlags,
2075                         };
2076
2077                         QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, 0), sockares));
2078
2079                         return sockares;
2080                 }
2081
2082                 static void BeginSendCallback (SocketAsyncResult sockares, int sent_so_far)
2083                 {
2084                         int total = 0;
2085
2086                         try {
2087                                 total = Socket.Send_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error);
2088                         } catch (Exception e) {
2089                                 sockares.Complete (e);
2090                                 return;
2091                         }
2092
2093                         if (sockares.error == 0) {
2094                                 sent_so_far += total;
2095                                 sockares.Offset += total;
2096                                 sockares.Size -= total;
2097
2098                                 if (sockares.socket.CleanedUp) {
2099                                         sockares.Complete (total);
2100                                         return;
2101                                 }
2102
2103                                 if (sockares.Size > 0) {
2104                                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2105                                         return; // Have to finish writing everything. See bug #74475.
2106                                 }
2107
2108                                 sockares.Total = sent_so_far;
2109                         }
2110
2111                         sockares.Complete (total);
2112                 }
2113
2114                 [CLSCompliant (false)]
2115                 public IAsyncResult BeginSend (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state)
2116                 {
2117                         ThrowIfDisposedAndClosed ();
2118
2119                         if (buffers == null)
2120                                 throw new ArgumentNullException ("buffers");
2121
2122                         if (!is_connected) {
2123                                 errorCode = SocketError.NotConnected;
2124                                 return null;
2125                         }
2126
2127                         errorCode = SocketError.Success;
2128
2129                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendGeneric) {
2130                                 Buffers = buffers,
2131                                 SockFlags = socketFlags,
2132                         };
2133
2134                         QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginSendGenericCallback, sockares));
2135
2136                         return sockares;
2137                 }
2138
2139                 static IOAsyncCallback BeginSendGenericCallback = new IOAsyncCallback (ares => {
2140                         SocketAsyncResult sockares = (SocketAsyncResult) ares;
2141                         int total = 0;
2142
2143                         try {
2144                                 total = sockares.socket.Send (sockares.Buffers, sockares.SockFlags);
2145                         } catch (Exception e) {
2146                                 sockares.Complete (e);
2147                                 return;
2148                         }
2149
2150                         sockares.Complete (total);
2151                 });
2152
2153                 public int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
2154                 {
2155                         ThrowIfDisposedAndClosed ();
2156
2157                         SocketAsyncResult sockares = ValidateEndIAsyncResult (asyncResult, "EndSend", "asyncResult");
2158
2159                         if (!sockares.IsCompleted)
2160                                 sockares.AsyncWaitHandle.WaitOne ();
2161
2162                         errorCode = sockares.ErrorCode;
2163
2164                         if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress)
2165                                 is_connected = false;
2166
2167                         /* If no socket error occurred, call CheckIfThrowDelayedException in
2168                          * case there are other kinds of exceptions that should be thrown.*/
2169                         if (errorCode == SocketError.Success)
2170                                 sockares.CheckIfThrowDelayedException ();
2171
2172                         return sockares.Total;
2173                 }
2174
2175                 static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error)
2176                 {
2177                         bool release = false;
2178                         try {
2179                                 safeHandle.DangerousAddRef (ref release);
2180                                 return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error);
2181                         } finally {
2182                                 if (release)
2183                                         safeHandle.DangerousRelease ();
2184                         }
2185                 }
2186
2187                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2188                 extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
2189
2190                 static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error)
2191                 {
2192                         try {
2193                                 safeHandle.RegisterForBlockingSyscall ();
2194                                 return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error);
2195                         } finally {
2196                                 safeHandle.UnRegisterForBlockingSyscall ();
2197                         }
2198                 }
2199
2200                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2201                 extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error);
2202
2203 #endregion
2204
2205 #region SendTo
2206
2207                 public int SendTo (byte [] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP)
2208                 {
2209                         ThrowIfDisposedAndClosed ();
2210                         ThrowIfBufferNull (buffer);
2211                         ThrowIfBufferOutOfRange (buffer, offset, size);
2212
2213                         if (remoteEP == null)
2214                                 throw new ArgumentNullException("remoteEP");
2215
2216                         int error;
2217                         int ret = SendTo_internal (m_Handle, buffer, offset, size, socketFlags, remoteEP.Serialize (), out error);
2218
2219                         SocketError err = (SocketError) error;
2220                         if (err != 0) {
2221                                 if (err != SocketError.WouldBlock && err != SocketError.InProgress)
2222                                         is_connected = false;
2223                                 throw new SocketException (error);
2224                         }
2225
2226                         is_connected = true;
2227                         is_bound = true;
2228                         seed_endpoint = remoteEP;
2229
2230                         return ret;
2231                 }
2232
2233                 public bool SendToAsync (SocketAsyncEventArgs e)
2234                 {
2235                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2236
2237                         ThrowIfDisposedAndClosed ();
2238
2239                         if (e.BufferList != null)
2240                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
2241                         if (e.RemoteEndPoint == null)
2242                                 throw new ArgumentNullException ("remoteEP", "Value cannot be null.");
2243
2244                         InitSocketAsyncEventArgs (e, SendToAsyncCallback, e, SocketOperation.SendTo);
2245
2246                         e.socket_async_result.Buffer = e.Buffer;
2247                         e.socket_async_result.Offset = e.Offset;
2248                         e.socket_async_result.Size = e.Count;
2249                         e.socket_async_result.SockFlags = e.SocketFlags;
2250                         e.socket_async_result.EndPoint = e.RemoteEndPoint;
2251
2252                         QueueIOSelectorJob (WriteSem, e.socket_async_result.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), e.socket_async_result));
2253
2254                         return true;
2255                 }
2256
2257                 static AsyncCallback SendToAsyncCallback = new AsyncCallback (ares => {
2258                         SocketAsyncEventArgs e = (SocketAsyncEventArgs) ((SocketAsyncResult) ares).AsyncState;
2259
2260                         if (Interlocked.Exchange (ref e.in_progress, 0) != 1)
2261                                 throw new InvalidOperationException ("No operation in progress");
2262
2263                         try {
2264                                 e.BytesTransferred = e.current_socket.EndSendTo (ares);
2265                         } catch (SocketException ex) {
2266                                 e.SocketError = ex.SocketErrorCode;
2267                         } catch (ObjectDisposedException) {
2268                                 e.SocketError = SocketError.OperationAborted;
2269                         } finally {
2270                                 e.Complete ();
2271                         }
2272                 });
2273
2274                 public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socket_flags, EndPoint remote_end, AsyncCallback callback, object state)
2275                 {
2276                         ThrowIfDisposedAndClosed ();
2277                         ThrowIfBufferNull (buffer);
2278                         ThrowIfBufferOutOfRange (buffer, offset, size);
2279
2280                         SocketAsyncResult sockares = new SocketAsyncResult (this, callback, state, SocketOperation.SendTo) {
2281                                 Buffer = buffer,
2282                                 Offset = offset,
2283                                 Size = size,
2284                                 SockFlags = socket_flags,
2285                                 EndPoint = remote_end,
2286                         };
2287
2288                         QueueIOSelectorJob (WriteSem, sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, 0), sockares));
2289
2290                         return sockares;
2291                 }
2292
2293                 static void BeginSendToCallback (SocketAsyncResult sockares, int sent_so_far)
2294                 {
2295                         int total = 0;
2296                         try {
2297                                 total = sockares.socket.SendTo (sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, sockares.EndPoint);
2298
2299                                 if (sockares.error == 0) {
2300                                         sent_so_far += total;
2301                                         sockares.Offset += total;
2302                                         sockares.Size -= total;
2303                                 }
2304
2305                                 if (sockares.Size > 0) {
2306                                         IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, s => BeginSendToCallback ((SocketAsyncResult) s, sent_so_far), sockares));
2307                                         return; // Have to finish writing everything. See bug #74475.
2308                                 }
2309
2310                                 sockares.Total = sent_so_far;
2311                         } catch (Exception e) {
2312                                 sockares.Complete (e);
2313                                 return;
2314                         }
2315
2316                         sockares.Complete ();
2317                 }
2318
2319                 public int EndSendTo (IAsyncResult result)
2320                 {
2321                         ThrowIfDisposedAndClosed ();
2322
2323                         SocketAsyncResult sockares = ValidateEndIAsyncResult (result, "EndSendTo", "result");
2324
2325                         if (!sockares.IsCompleted)
2326                                 sockares.AsyncWaitHandle.WaitOne();
2327
2328                         sockares.CheckIfThrowDelayedException();
2329
2330                         return sockares.Total;
2331                 }
2332
2333                 static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error)
2334                 {
2335                         try {
2336                                 safeHandle.RegisterForBlockingSyscall ();
2337                                 return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error);
2338                         } finally {
2339                                 safeHandle.UnRegisterForBlockingSyscall ();
2340                         }
2341                 }
2342
2343                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2344                 extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error);
2345
2346 #endregion
2347
2348 #region SendFile
2349
2350                 public void SendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags)
2351                 {
2352                         ThrowIfDisposedAndClosed ();
2353
2354                         if (!is_connected)
2355                                 throw new NotSupportedException ();
2356                         if (!is_blocking)
2357                                 throw new InvalidOperationException ();
2358
2359                         if (!SendFile_internal (m_Handle, fileName, preBuffer, postBuffer, flags)) {
2360                                 SocketException exc = new SocketException ();
2361                                 if (exc.ErrorCode == 2 || exc.ErrorCode == 3)
2362                                         throw new FileNotFoundException ();
2363                                 throw exc;
2364                         }
2365                 }
2366
2367                 public IAsyncResult BeginSendFile (string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state)
2368                 {
2369                         ThrowIfDisposedAndClosed ();
2370
2371                         if (!is_connected)
2372                                 throw new NotSupportedException ();
2373                         if (!File.Exists (fileName))
2374                                 throw new FileNotFoundException ();
2375
2376                         SendFileHandler handler = new SendFileHandler (SendFile);
2377
2378                         return new SendFileAsyncResult (handler, handler.BeginInvoke (fileName, preBuffer, postBuffer, flags, ar => callback (new SendFileAsyncResult (handler, ar)), state));
2379                 }
2380
2381                 public void EndSendFile (IAsyncResult asyncResult)
2382                 {
2383                         ThrowIfDisposedAndClosed ();
2384
2385                         if (asyncResult == null)
2386                                 throw new ArgumentNullException ("asyncResult");
2387
2388                         SendFileAsyncResult ares = asyncResult as SendFileAsyncResult;
2389                         if (ares == null)
2390                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
2391
2392                         ares.Delegate.EndInvoke (ares.Original);
2393                 }
2394
2395                 static bool SendFile_internal (SafeSocketHandle safeHandle, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags)
2396                 {
2397                         try {
2398                                 safeHandle.RegisterForBlockingSyscall ();
2399                                 return SendFile_internal (safeHandle.DangerousGetHandle (), filename, pre_buffer, post_buffer, flags);
2400                         } finally {
2401                                 safeHandle.UnRegisterForBlockingSyscall ();
2402                         }
2403                 }
2404
2405                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2406                 extern static bool SendFile_internal (IntPtr sock, string filename, byte [] pre_buffer, byte [] post_buffer, TransmitFileOptions flags);
2407
2408                 delegate void SendFileHandler (string fileName, byte [] preBuffer, byte [] postBuffer, TransmitFileOptions flags);
2409
2410                 sealed class SendFileAsyncResult : IAsyncResult {
2411                         IAsyncResult ares;
2412                         SendFileHandler d;
2413
2414                         public SendFileAsyncResult (SendFileHandler d, IAsyncResult ares)
2415                         {
2416                                 this.d = d;
2417                                 this.ares = ares;
2418                         }
2419
2420                         public object AsyncState {
2421                                 get { return ares.AsyncState; }
2422                         }
2423
2424                         public WaitHandle AsyncWaitHandle {
2425                                 get { return ares.AsyncWaitHandle; }
2426                         }
2427
2428                         public bool CompletedSynchronously {
2429                                 get { return ares.CompletedSynchronously; }
2430                         }
2431
2432                         public bool IsCompleted {
2433                                 get { return ares.IsCompleted; }
2434                         }
2435
2436                         public SendFileHandler Delegate {
2437                                 get { return d; }
2438                         }
2439
2440                         public IAsyncResult Original {
2441                                 get { return ares; }
2442                         }
2443                 }
2444
2445 #endregion
2446
2447 #region SendPackets
2448
2449                 [MonoTODO ("Not implemented")]
2450                 public bool SendPacketsAsync (SocketAsyncEventArgs e)
2451                 {
2452                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
2453
2454                         ThrowIfDisposedAndClosed ();
2455
2456                         throw new NotImplementedException ();
2457                 }
2458
2459 #endregion
2460
2461 #region DuplicateAndClose
2462
2463                 [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
2464                 public SocketInformation DuplicateAndClose (int targetProcessId)
2465                 {
2466                         var si = new SocketInformation ();
2467                         si.Options =
2468                                 (is_listening      ? SocketInformationOptions.Listening : 0) |
2469                                 (is_connected      ? SocketInformationOptions.Connected : 0) |
2470                                 (is_blocking       ? 0 : SocketInformationOptions.NonBlocking) |
2471                                 (useOverlappedIO ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
2472
2473                         si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)addressFamily, (int)socketType, (int)protocolType, is_bound ? 1 : 0, (long)Handle);
2474                         m_Handle = null;
2475
2476                         return si;
2477                 }
2478
2479 #endregion
2480
2481 #region GetSocketOption
2482
2483                 public void GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2484                 {
2485                         ThrowIfDisposedAndClosed ();
2486
2487                         if (optionValue == null)
2488                                 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2489
2490                         int error;
2491                         GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref optionValue, out error);
2492
2493                         if (error != 0)
2494                                 throw new SocketException (error);
2495                 }
2496
2497                 public byte [] GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength)
2498                 {
2499                         ThrowIfDisposedAndClosed ();
2500
2501                         int error;
2502                         byte[] byte_val = new byte [optionLength];
2503                         GetSocketOption_arr_internal (m_Handle, optionLevel, optionName, ref byte_val, out error);
2504
2505                         if (error != 0)
2506                                 throw new SocketException (error);
2507
2508                         return byte_val;
2509                 }
2510
2511                 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
2512                 {
2513                         ThrowIfDisposedAndClosed ();
2514
2515                         int error;
2516                         object obj_val;
2517                         GetSocketOption_obj_internal (m_Handle, optionLevel, optionName, out obj_val, out error);
2518
2519                         if (error != 0)
2520                                 throw new SocketException (error);
2521
2522                         if (optionName == SocketOptionName.Linger)
2523                                 return (LingerOption) obj_val;
2524                         else if (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)
2525                                 return (MulticastOption) obj_val;
2526                         else if (obj_val is int)
2527                                 return (int) obj_val;
2528                         else
2529                                 return obj_val;
2530                 }
2531
2532                 static void GetSocketOption_arr_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error)
2533                 {
2534                         bool release = false;
2535                         try {
2536                                 safeHandle.DangerousAddRef (ref release);
2537                                 GetSocketOption_arr_internal (safeHandle.DangerousGetHandle (), level, name, ref byte_val, out error);
2538                         } finally {
2539                                 if (release)
2540                                         safeHandle.DangerousRelease ();
2541                         }
2542                 }
2543
2544                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2545                 extern static void GetSocketOption_arr_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, ref byte[] byte_val, out int error);
2546
2547                 static void GetSocketOption_obj_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error)
2548                 {
2549                         bool release = false;
2550                         try {
2551                                 safeHandle.DangerousAddRef (ref release);
2552                                 GetSocketOption_obj_internal (safeHandle.DangerousGetHandle (), level, name, out obj_val, out error);
2553                         } finally {
2554                                 if (release)
2555                                         safeHandle.DangerousRelease ();
2556                         }
2557                 }
2558
2559                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2560                 extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val, out int error);
2561
2562 #endregion
2563
2564 #region SetSocketOption
2565
2566                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, byte [] optionValue)
2567                 {
2568                         ThrowIfDisposedAndClosed ();
2569
2570                         // I'd throw an ArgumentNullException, but this is what MS does.
2571                         if (optionValue == null)
2572                                 throw new SocketException ((int) SocketError.Fault, "Error trying to dereference an invalid pointer");
2573
2574                         int error;
2575                         SetSocketOption_internal (m_Handle, optionLevel, optionName, null, optionValue, 0, out error);
2576
2577                         if (error != 0) {
2578                                 if (error == (int) SocketError.InvalidArgument)
2579                                         throw new ArgumentException ();
2580                                 throw new SocketException (error);
2581                         }
2582                 }
2583
2584                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
2585                 {
2586                         ThrowIfDisposedAndClosed ();
2587
2588                         // NOTE: if a null is passed, the byte[] overload is used instead...
2589                         if (optionValue == null)
2590                                 throw new ArgumentNullException("optionValue");
2591
2592                         int error;
2593
2594                         if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger) {
2595                                 LingerOption linger = optionValue as LingerOption;
2596                                 if (linger == null)
2597                                         throw new ArgumentException ("A 'LingerOption' value must be specified.", "optionValue");
2598                                 SetSocketOption_internal (m_Handle, optionLevel, optionName, linger, null, 0, out error);
2599                         } else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2600                                 MulticastOption multicast = optionValue as MulticastOption;
2601                                 if (multicast == null)
2602                                         throw new ArgumentException ("A 'MulticastOption' value must be specified.", "optionValue");
2603                                 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2604                         } else if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership)) {
2605                                 IPv6MulticastOption multicast = optionValue as IPv6MulticastOption;
2606                                 if (multicast == null)
2607                                         throw new ArgumentException ("A 'IPv6MulticastOption' value must be specified.", "optionValue");
2608                                 SetSocketOption_internal (m_Handle, optionLevel, optionName, multicast, null, 0, out error);
2609                         } else {
2610                                 throw new ArgumentException ("Invalid value specified.", "optionValue");
2611                         }
2612
2613                         if (error != 0) {
2614                                 if (error == (int) SocketError.InvalidArgument)
2615                                         throw new ArgumentException ();
2616                                 throw new SocketException (error);
2617                         }
2618                 }
2619
2620                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
2621                 {
2622                         int int_val = optionValue ? 1 : 0;
2623
2624                         SetSocketOption (optionLevel, optionName, int_val);
2625                 }
2626
2627                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
2628                 {
2629                         ThrowIfDisposedAndClosed ();
2630
2631                         if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse (protocolType))
2632                                 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.");
2633
2634                         int error;
2635                         SetSocketOption_internal (m_Handle, optionLevel, optionName, null, null, optionValue, out error);
2636
2637                         if (error != 0) {
2638                                 if (error == (int) SocketError.InvalidArgument)
2639                                         throw new ArgumentException ();
2640                                 throw new SocketException (error);
2641                         }
2642                 }
2643
2644                 static void SetSocketOption_internal (SafeSocketHandle safeHandle, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error)
2645                 {
2646                         bool release = false;
2647                         try {
2648                                 safeHandle.DangerousAddRef (ref release);
2649                                 SetSocketOption_internal (safeHandle.DangerousGetHandle (), level, name, obj_val, byte_val, int_val, out error);
2650                         } finally {
2651                                 if (release)
2652                                         safeHandle.DangerousRelease ();
2653                         }
2654                 }
2655
2656                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2657                 extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level, SocketOptionName name, object obj_val, byte [] byte_val, int int_val, out int error);
2658
2659 #endregion
2660
2661 #region IOControl
2662
2663                 public int IOControl (int ioControlCode, byte [] optionInValue, byte [] optionOutValue)
2664                 {
2665                         if (CleanedUp)
2666                                 throw new ObjectDisposedException (GetType ().ToString ());
2667
2668                         int error;
2669                         int result = IOControl_internal (m_Handle, ioControlCode, optionInValue, optionOutValue, out error);
2670
2671                         if (error != 0)
2672                                 throw new SocketException (error);
2673                         if (result == -1)
2674                                 throw new InvalidOperationException ("Must use Blocking property instead.");
2675
2676                         return result;
2677                 }
2678
2679                 static int IOControl_internal (SafeSocketHandle safeHandle, int ioctl_code, byte [] input, byte [] output, out int error)
2680                 {
2681                         bool release = false;
2682                         try {
2683                                 safeHandle.DangerousAddRef (ref release);
2684                                 return IOControl_internal (safeHandle.DangerousGetHandle (), ioctl_code, input, output, out error);
2685                         } finally {
2686                                 if (release)
2687                                         safeHandle.DangerousRelease ();
2688                         }
2689                 }
2690
2691                 /* See Socket.IOControl, WSAIoctl documentation in MSDN. The common options between UNIX
2692                  * and Winsock are FIONREAD, FIONBIO and SIOCATMARK. Anything else will depend on the system
2693                  * except SIO_KEEPALIVE_VALS which is properly handled on both windows and linux. */
2694                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2695                 extern static int IOControl_internal (IntPtr sock, int ioctl_code, byte [] input, byte [] output, out int error);
2696
2697 #endregion
2698
2699 #region Close
2700
2701                 public void Close ()
2702                 {
2703                         linger_timeout = 0;
2704                         Dispose ();
2705                 }
2706
2707                 public void Close (int timeout)
2708                 {
2709                         linger_timeout = timeout;
2710                         Dispose ();
2711                 }
2712
2713                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2714                 internal extern static void Close_internal (IntPtr socket, out int error);
2715
2716 #endregion
2717
2718 #region Shutdown
2719
2720                 public void Shutdown (SocketShutdown how)
2721                 {
2722                         ThrowIfDisposedAndClosed ();
2723
2724                         if (!is_connected)
2725                                 throw new SocketException (10057); // Not connected
2726
2727                         int error;
2728                         Shutdown_internal (m_Handle, how, out error);
2729
2730                         if (error != 0)
2731                                 throw new SocketException (error);
2732                 }
2733
2734                 static void Shutdown_internal (SafeSocketHandle safeHandle, SocketShutdown how, out int error)
2735                 {
2736                         bool release = false;
2737                         try {
2738                                 safeHandle.DangerousAddRef (ref release);
2739                                 Shutdown_internal (safeHandle.DangerousGetHandle (), how, out error);
2740                         } finally {
2741                                 if (release)
2742                                         safeHandle.DangerousRelease ();
2743                         }
2744                 }
2745
2746                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
2747                 internal extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
2748
2749 #endregion
2750
2751 #region Dispose
2752
2753                 protected virtual void Dispose (bool disposing)
2754                 {
2755                         if (CleanedUp)
2756                                 return;
2757
2758                         m_IntCleanedUp = 1;
2759                         bool was_connected = is_connected;
2760                         is_connected = false;
2761
2762                         if (m_Handle != null) {
2763                                 is_closed = true;
2764                                 IntPtr x = Handle;
2765
2766                                 if (was_connected)
2767                                         Linger (x);
2768
2769                                 m_Handle.Dispose ();
2770                         }
2771                 }
2772
2773                 void Linger (IntPtr handle)
2774                 {
2775                         if (!is_connected || linger_timeout <= 0)
2776                                 return;
2777
2778                         /* We don't want to receive any more data */
2779                         int error;
2780                         Shutdown_internal (handle, SocketShutdown.Receive, out error);
2781
2782                         if (error != 0)
2783                                 return;
2784
2785                         int seconds = linger_timeout / 1000;
2786                         int ms = linger_timeout % 1000;
2787                         if (ms > 0) {
2788                                 /* If the other end closes, this will return 'true' with 'Available' == 0 */
2789                                 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
2790                                 if (error != 0)
2791                                         return;
2792                         }
2793
2794                         if (seconds > 0) {
2795                                 LingerOption linger = new LingerOption (true, seconds);
2796                                 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
2797                                 /* Not needed, we're closing upon return */
2798                                 //if (error != 0)
2799                                 //      return;
2800                         }
2801                 }
2802
2803 #endregion
2804
2805                 void ThrowIfDisposedAndClosed (Socket socket)
2806                 {
2807                         if (socket.CleanedUp && socket.is_closed)
2808                                 throw new ObjectDisposedException (socket.GetType ().ToString ());
2809                 }
2810
2811                 void ThrowIfDisposedAndClosed ()
2812                 {
2813                         if (CleanedUp && is_closed)
2814                                 throw new ObjectDisposedException (GetType ().ToString ());
2815                 }
2816
2817                 void ThrowIfBufferNull (byte[] buffer)
2818                 {
2819                         if (buffer == null)
2820                                 throw new ArgumentNullException ("buffer");
2821                 }
2822
2823                 void ThrowIfBufferOutOfRange (byte[] buffer, int offset, int size)
2824                 {
2825                         if (offset < 0)
2826                                 throw new ArgumentOutOfRangeException ("offset", "offset must be >= 0");
2827                         if (offset > buffer.Length)
2828                                 throw new ArgumentOutOfRangeException ("offset", "offset must be <= buffer.Length");
2829                         if (size < 0)
2830                                 throw new ArgumentOutOfRangeException ("size", "size must be >= 0");
2831                         if (size > buffer.Length - offset)
2832                                 throw new ArgumentOutOfRangeException ("size", "size must be <= buffer.Length - offset");
2833                 }
2834
2835                 void ThrowIfUdp ()
2836                 {
2837                         if (protocolType == ProtocolType.Udp)
2838                                 throw new SocketException ((int)SocketError.ProtocolOption);
2839                 }
2840
2841                 SocketAsyncResult ValidateEndIAsyncResult (IAsyncResult ares, string methodName, string argName)
2842                 {
2843                         if (ares == null)
2844                                 throw new ArgumentNullException (argName);
2845
2846                         SocketAsyncResult sockares = ares as SocketAsyncResult;
2847                         if (sockares == null)
2848                                 throw new ArgumentException ("Invalid IAsyncResult", argName);
2849                         if (Interlocked.CompareExchange (ref sockares.EndCalled, 1, 0) == 1)
2850                                 throw new InvalidOperationException (methodName + " can only be called once per asynchronous operation");
2851
2852                         return sockares;
2853                 }
2854
2855                 void QueueIOSelectorJob (SemaphoreSlim sem, IntPtr handle, IOSelectorJob job)
2856                 {
2857                         sem.WaitAsync ().ContinueWith (t => {
2858                                 if (CleanedUp) {
2859                                         job.MarkDisposed ();
2860                                         return;
2861                                 }
2862
2863                                 IOSelector.Add (handle, job);
2864                         });
2865                 }
2866
2867                 void InitSocketAsyncEventArgs (SocketAsyncEventArgs e, AsyncCallback callback, object state, SocketOperation operation)
2868                 {
2869                         e.socket_async_result.Init (this, callback, state, operation);
2870                         if (e.AcceptSocket != null) {
2871                                 e.socket_async_result.AcceptSocket = e.AcceptSocket;
2872                         }
2873                         e.current_socket = this;
2874                         e.SetLastOperation (SocketOperationToSocketAsyncOperation (operation));
2875                         e.SocketError = SocketError.Success;
2876                         e.BytesTransferred = 0;
2877                 }
2878
2879                 SocketAsyncOperation SocketOperationToSocketAsyncOperation (SocketOperation op)
2880                 {
2881                         switch (op) {
2882                         case SocketOperation.Connect:
2883                                 return SocketAsyncOperation.Connect;
2884                         case SocketOperation.Accept:
2885                                 return SocketAsyncOperation.Accept;
2886                         case SocketOperation.Disconnect:
2887                                 return SocketAsyncOperation.Disconnect;
2888                         case SocketOperation.Receive:
2889                         case SocketOperation.ReceiveGeneric:
2890                                 return SocketAsyncOperation.Receive;
2891                         case SocketOperation.ReceiveFrom:
2892                                 return SocketAsyncOperation.ReceiveFrom;
2893                         case SocketOperation.Send:
2894                         case SocketOperation.SendGeneric:
2895                                 return SocketAsyncOperation.Send;
2896                         case SocketOperation.SendTo:
2897                                 return SocketAsyncOperation.SendTo;
2898                         default:
2899                                 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
2900                         }
2901                 }
2902                 
2903                 IPEndPoint RemapIPEndPoint (IPEndPoint input) {
2904                         // If socket is DualMode ensure we automatically handle mapping IPv4 addresses to IPv6.
2905                         if (IsDualMode && input.AddressFamily == AddressFamily.InterNetwork)
2906                                 return new IPEndPoint (input.Address.MapToIPv6 (), input.Port);
2907                         
2908                         return input;
2909                 }
2910                 
2911                 [StructLayout (LayoutKind.Sequential)]
2912                 struct WSABUF {
2913                         public int len;
2914                         public IntPtr buf;
2915                 }
2916
2917                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2918                 internal static extern void cancel_blocking_socket_operation (Thread thread);
2919
2920                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2921                 internal static extern bool SupportsPortReuse (ProtocolType proto);
2922         }
2923 }
2924