2009-11-03 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mcs / class / System / System.Net.Sockets / Socket_2_1.cs
1 // System.Net.Sockets.Socket.cs
2 //
3 // Authors:
4 //      Phillip Pearson (pp@myelin.co.nz)
5 //      Dick Porter <dick@ximian.com>
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //      Sridhar Kulkarni (sridharkulkarni@gmail.com)
8 //      Brian Nickel (brian.nickel@gmail.com)
9 //
10 // Copyright (C) 2001, 2002 Phillip Pearson and Ximian, Inc.
11 //    http://www.myelin.co.nz
12 // (c) 2004-2006 Novell, Inc. (http://www.novell.com)
13 //
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.Runtime.CompilerServices;
40 using System.Runtime.InteropServices;
41 using System.Threading;
42 using System.IO;
43 using System.Security;
44 using System.Text;
45
46 #if !NET_2_1
47 using System.Net.Configuration;
48 #endif
49
50 #if NET_2_0
51 using System.Collections.Generic;
52 #if !NET_2_1
53 using System.Net.NetworkInformation;
54 #endif
55 #endif
56
57 namespace System.Net.Sockets {
58
59         public partial class Socket : IDisposable {
60
61                 /*
62                  *      These two fields are looked up by name by the runtime, don't change
63                  *  their name without also updating the runtime code.
64                  */
65                 private static int ipv4Supported = -1, ipv6Supported = -1;
66                 int linger_timeout;
67
68                 static Socket ()
69                 {
70                         // initialize ipv4Supported and ipv6Supported
71                         CheckProtocolSupport ();
72                 }
73
74                 internal static void CheckProtocolSupport ()
75                 {
76                         if(ipv4Supported == -1) {
77                                 try {
78                                         Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
79                                         tmp.Close();
80
81                                         ipv4Supported = 1;
82                                 } catch {
83                                         ipv4Supported = 0;
84                                 }
85                         }
86
87                         if (ipv6Supported == -1) {
88 #if !NET_2_1
89 #if NET_2_0 && CONFIGURATION_DEP
90                                 SettingsSection config;
91                                 config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
92                                 if (config != null)
93                                         ipv6Supported = config.Ipv6.Enabled ? -1 : 0;
94 #else
95                                 NetConfig config = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig;
96                                 if (config != null)
97                                         ipv6Supported = config.ipv6Enabled ? -1 : 0;
98 #endif
99 #endif
100                                 if (ipv6Supported != 0) {
101                                         try {
102                                                 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
103                                                 tmp.Close();
104
105                                                 ipv6Supported = 1;
106                                         } catch {
107                                                 ipv6Supported = 0;
108                                         }
109                                 }
110                         }
111                 }
112
113                 public static bool SupportsIPv4 {
114                         get {
115                                 CheckProtocolSupport();
116                                 return ipv4Supported == 1;
117                         }
118                 }
119
120 #if NET_2_0
121                 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
122 #endif
123                 public static bool SupportsIPv6 {
124                         get {
125                                 CheckProtocolSupport();
126                                 return ipv6Supported == 1;
127                         }
128                 }
129 #if NET_2_1
130                 public static bool OSSupportsIPv4 {
131                         get {
132                                 CheckProtocolSupport();
133                                 return ipv4Supported == 1;
134                         }
135                 }
136 #endif
137 #if NET_2_1
138                 public static bool OSSupportsIPv6 {
139                         get {
140                                 CheckProtocolSupport();
141                                 return ipv6Supported == 1;
142                         }
143                 }
144 #elif NET_2_0
145                 public static bool OSSupportsIPv6 {
146                         get {
147                                 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
148                                 
149                                 foreach (NetworkInterface adapter in nics) {
150                                         if (adapter.Supports (NetworkInterfaceComponent.IPv6))
151                                                 return true;
152                                 }
153                                 return false;
154                         }
155                 }
156 #endif
157
158                 /* the field "socket" is looked up by name by the runtime */
159                 private IntPtr socket;
160                 private AddressFamily address_family;
161                 private SocketType socket_type;
162                 private ProtocolType protocol_type;
163                 internal bool blocking=true;
164                 Thread blocking_thread;
165 #if NET_2_0
166                 private bool isbound;
167 #endif
168                 /* When true, the socket was connected at the time of
169                  * the last IO operation
170                  */
171                 private bool connected;
172                 /* true if we called Close_internal */
173                 private bool closed;
174                 internal bool disposed;
175
176                 /*
177                  * This EndPoint is used when creating new endpoints. Because
178                  * there are many types of EndPoints possible,
179                  * seed_endpoint.Create(addr) is used for creating new ones.
180                  * As such, this value is set on Bind, SentTo, ReceiveFrom,
181                  * Connect, etc.
182                  */
183                 internal EndPoint seed_endpoint = null;
184
185 #if !TARGET_JVM
186                 // Creates a new system socket, returning the handle
187                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
188                 private extern IntPtr Socket_internal(AddressFamily family,
189                                                       SocketType type,
190                                                       ProtocolType proto,
191                                                       out int error);
192 #endif          
193                 
194                 public Socket(AddressFamily family, SocketType type, ProtocolType proto)
195                 {
196 #if NET_2_1
197                         if (family == AddressFamily.Unspecified)
198                                 throw new ArgumentException ("family");
199 #endif
200                         address_family=family;
201                         socket_type=type;
202                         protocol_type=proto;
203                         
204                         int error;
205                         
206                         socket = Socket_internal (family, type, proto, out error);
207                         if (error != 0)
208                                 throw new SocketException (error);
209 #if !NET_2_1
210                         SocketDefaults ();
211 #endif
212                 }
213
214                 ~Socket ()
215                 {
216                         Dispose (false);
217                 }
218
219
220                 public AddressFamily AddressFamily {
221                         get { return address_family; }
222                 }
223
224 #if !TARGET_JVM
225                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
226                 private extern static void Blocking_internal(IntPtr socket,
227                                                              bool block,
228                                                              out int error);
229 #endif
230 #if !NET_2_1 || MONOTOUCH
231                 public bool Blocking {
232                         get {
233                                 return(blocking);
234                         }
235                         set {
236                                 if (disposed && closed)
237                                         throw new ObjectDisposedException (GetType ().ToString ());
238
239                                 int error;
240                                 
241                                 Blocking_internal (socket, value, out error);
242
243                                 if (error != 0)
244                                         throw new SocketException (error);
245                                 
246                                 blocking=value;
247                         }
248                 }
249 #endif
250                 public bool Connected {
251                         get { return connected; }
252                         internal set { connected = value; }
253                 }
254
255                 public ProtocolType ProtocolType {
256                         get { return protocol_type; }
257                 }
258 #if NET_2_0
259                 public bool NoDelay {
260                         get {
261                                 if (disposed && closed)
262                                         throw new ObjectDisposedException (GetType ().ToString ());
263
264                                 ThrowIfUpd ();
265
266                                 return (int)(GetSocketOption (
267                                         SocketOptionLevel.Tcp,
268                                         SocketOptionName.NoDelay)) != 0;
269                         }
270
271                         set {
272                                 if (disposed && closed)
273                                         throw new ObjectDisposedException (GetType ().ToString ());
274
275                                 ThrowIfUpd ();
276
277                                 SetSocketOption (
278                                         SocketOptionLevel.Tcp,
279                                         SocketOptionName.NoDelay, value ? 1 : 0);
280                         }
281                 }
282
283                 public int ReceiveBufferSize {
284                         get {
285                                 if (disposed && closed) {
286                                         throw new ObjectDisposedException (GetType ().ToString ());
287                                 }
288                                 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer));
289                         }
290                         set {
291                                 if (disposed && closed) {
292                                         throw new ObjectDisposedException (GetType ().ToString ());
293                                 }
294                                 if (value < 0) {
295                                         throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
296                                 }
297                                 
298                                 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
299                         }
300                 }
301
302                 public int SendBufferSize {
303                         get {
304                                 if (disposed && closed) {
305                                         throw new ObjectDisposedException (GetType ().ToString ());
306                                 }
307                                 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer));
308                         }
309                         set {
310                                 if (disposed && closed) {
311                                         throw new ObjectDisposedException (GetType ().ToString ());
312                                 }
313                                 if (value < 0) {
314                                         throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
315                                 }
316                                 
317                                 SetSocketOption (SocketOptionLevel.Socket,
318                                                  SocketOptionName.SendBuffer,
319                                                  value);
320                         }
321                 }
322
323                 public short Ttl {
324                         get {
325                                 if (disposed && closed) {
326                                         throw new ObjectDisposedException (GetType ().ToString ());
327                                 }
328                                 
329                                 short ttl_val;
330                                 
331                                 if (address_family == AddressFamily.InterNetwork) {
332                                         ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive));
333                                 } else if (address_family == AddressFamily.InterNetworkV6) {
334                                         ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit));
335                                 } else {
336                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
337                                 }
338                                 
339                                 return(ttl_val);
340                         }
341                         set {
342                                 if (disposed && closed) {
343                                         throw new ObjectDisposedException (GetType ().ToString ());
344                                 }
345                                 
346                                 if (address_family == AddressFamily.InterNetwork) {
347                                         SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
348                                 } else if (address_family == AddressFamily.InterNetworkV6) {
349                                         SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
350                                 } else {
351                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
352                                 }
353                         }
354                 }
355 #endif
356                 // Returns the remote endpoint details in addr and port
357                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
358                 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket, out int error);
359
360                 public EndPoint RemoteEndPoint {
361                         get {
362                                 if (disposed && closed)
363                                         throw new ObjectDisposedException (GetType ().ToString ());
364                                 
365                                 /*
366                                  * If the seed EndPoint is null, Connect, Bind,
367                                  * etc has not yet been called. MS returns null
368                                  * in this case.
369                                  */
370                                 if (seed_endpoint == null)
371                                         return null;
372                                 
373                                 SocketAddress sa;
374                                 int error;
375                                 
376                                 sa=RemoteEndPoint_internal(socket, out error);
377
378                                 if (error != 0)
379                                         throw new SocketException (error);
380
381                                 return seed_endpoint.Create (sa);
382                         }
383                 }
384
385                 void Linger (IntPtr handle)
386                 {
387                         if (linger_timeout <= 0)
388                                 return;
389
390                         // We don't want to receive any more data
391                         int error;
392                         Shutdown_internal (handle, SocketShutdown.Receive, out error);
393                         if (error != 0)
394                                 return;
395
396                         int seconds = linger_timeout / 1000;
397                         int ms = linger_timeout % 1000;
398                         if (ms > 0) {
399                                 // If the other end closes, this will return 'true' with 'Available' == 0
400                                 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
401                                 if (error != 0)
402                                         return;
403
404                         }
405                         if (seconds > 0) {
406                                 LingerOption linger = new LingerOption (true, seconds);
407                                 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
408                                 /* Not needed, we're closing upon return */
409                                 /*if (error != 0)
410                                         return; */
411                         }
412                 }
413
414                 protected virtual void Dispose (bool explicitDisposing)
415                 {
416                         if (disposed)
417                                 return;
418
419                         disposed = true;
420                         connected = false;
421                         if ((int) socket != -1) {
422                                 int error;
423                                 closed = true;
424                                 IntPtr x = socket;
425                                 socket = (IntPtr) (-1);
426                                 Thread th = blocking_thread;
427                                 if (th != null) {
428                                         th.Abort ();
429                                         blocking_thread = null;
430                                 }
431
432                                 Linger (x);
433                                 //DateTime start = DateTime.UtcNow;
434                                 Close_internal (x, out error);
435                                 //Console.WriteLine ("Time spent in Close_internal: {0}ms", (DateTime.UtcNow - start).TotalMilliseconds);
436                                 if (error != 0)
437                                         throw new SocketException (error);
438                         }
439                 }
440
441 #if NET_2_1
442                 public void Dispose ()
443 #else
444                 void IDisposable.Dispose ()
445 #endif
446                 {
447                         Dispose (true);
448                         GC.SuppressFinalize (this);
449                 }
450
451                 // Closes the socket
452                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
453                 private extern static void Close_internal(IntPtr socket, out int error);
454
455                 public void Close ()
456                 {
457                         linger_timeout = 0;
458                         ((IDisposable) this).Dispose ();
459                 }
460
461 #if NET_2_0
462                 public void Close (int timeout) 
463                 {
464                         linger_timeout = timeout;
465                         ((IDisposable) this).Dispose ();
466                 }
467 #endif
468
469                 // Connects to the remote address
470                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
471                 private extern static void Connect_internal(IntPtr sock,
472                                                             SocketAddress sa,
473                                                             out int error);
474
475                 public void Connect (EndPoint remoteEP)
476                 {
477                         SocketAddress serial = null;
478
479                         if (disposed && closed)
480                                 throw new ObjectDisposedException (GetType ().ToString ());
481
482                         if (remoteEP == null)
483                                 throw new ArgumentNullException ("remoteEP");
484
485                         IPEndPoint ep = remoteEP as IPEndPoint;
486                         if (ep != null)
487                                 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
488                                         throw new SocketException ((int) SocketError.AddressNotAvailable);
489
490 #if NET_2_1 && !MONOTOUCH
491                         if (protocol_type != ProtocolType.Tcp)
492                                 throw new SocketException ((int) SocketError.AccessDenied);
493 #elif NET_2_0
494                         /* TODO: check this for the 1.1 profile too */
495                         if (islistening)
496                                 throw new InvalidOperationException ();
497 #endif
498                         serial = remoteEP.Serialize ();
499
500                         int error = 0;
501
502                         blocking_thread = Thread.CurrentThread;
503                         try {
504                                 Connect_internal (socket, serial, out error);
505                         } catch (ThreadAbortException) {
506                                 if (disposed) {
507                                         Thread.ResetAbort ();
508                                         error = (int) SocketError.Interrupted;
509                                 }
510                         } finally {
511                                 blocking_thread = null;
512                         }
513
514                         if (error != 0)
515                                 throw new SocketException (error);
516
517                         connected=true;
518
519 #if NET_2_0
520                         isbound = true;
521 #endif
522
523                         seed_endpoint = remoteEP;
524                 }
525
526 #if NET_2_0
527                 public bool ReceiveAsync (SocketAsyncEventArgs e)
528                 {
529                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
530                         //
531                         // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
532                         // thrown when e.Buffer and e.BufferList are null (works fine when one is
533                         // set to a valid object)
534                         if (disposed && closed)
535                                 throw new ObjectDisposedException (GetType ().ToString ());
536
537                         // We do not support recv into multiple buffers yet
538                         if (e.BufferList != null)
539                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
540                         
541                         e.DoOperation (SocketAsyncOperation.Receive, this);
542
543                         // We always return true for now
544                         return true;
545                 }
546
547                 public bool SendAsync (SocketAsyncEventArgs e)
548                 {
549                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
550                         
551                         if (disposed && closed)
552                                 throw new ObjectDisposedException (GetType ().ToString ());
553                         if (e.Buffer == null && e.BufferList == null)
554                                 throw new ArgumentException ("Either e.Buffer or e.BufferList must be valid buffers.");
555
556                         e.DoOperation (SocketAsyncOperation.Send, this);
557
558                         // We always return true for now
559                         return true;
560                 }
561 #endif
562
563                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
564                 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
565
566 #if !NET_2_1 || MONOTOUCH
567                 /* This overload is needed as the async Connect method
568                  * also needs to check the socket error status, but
569                  * getsockopt(..., SO_ERROR) clears the error.
570                  */
571                 internal bool Poll (int time_us, SelectMode mode, out int socket_error)
572                 {
573                         if (disposed && closed)
574                                 throw new ObjectDisposedException (GetType ().ToString ());
575
576                         if (mode != SelectMode.SelectRead &&
577                             mode != SelectMode.SelectWrite &&
578                             mode != SelectMode.SelectError)
579                                 throw new NotSupportedException ("'mode' parameter is not valid.");
580
581                         int error;
582                         bool result = Poll_internal (socket, mode, time_us, out error);
583                         if (error != 0)
584                                 throw new SocketException (error);
585
586                         socket_error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
587                         
588                         if (mode == SelectMode.SelectWrite && result) {
589                                 /* Update the connected state; for
590                                  * non-blocking Connect()s this is
591                                  * when we can find out that the
592                                  * connect succeeded.
593                                  */
594                                 if (socket_error == 0) {
595                                         connected = true;
596                                 }
597                         }
598                         
599                         return result;
600                 }
601 #endif
602                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
603                 private extern static int Receive_internal(IntPtr sock,
604                                                            byte[] buffer,
605                                                            int offset,
606                                                            int count,
607                                                            SocketFlags flags,
608                                                            out int error);
609
610                 internal int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
611                 {
612                         int nativeError;
613                         int ret = Receive_internal (socket, buf, offset, size, flags, out nativeError);
614                         error = (SocketError) nativeError;
615                         if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
616                                 connected = false;
617                         else
618                                 connected = true;
619                         
620                         return ret;
621                 }
622
623                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
624                 private extern static void GetSocketOption_obj_internal(IntPtr socket,
625                         SocketOptionLevel level, SocketOptionName name, out object obj_val,
626                         out int error);
627
628                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
629                 private extern static int Send_internal(IntPtr sock,
630                                                         byte[] buf, int offset,
631                                                         int count,
632                                                         SocketFlags flags,
633                                                         out int error);
634
635                 internal int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
636                 {
637                         if (size == 0) {
638                                 error = SocketError.Success;
639                                 return 0;
640                         }
641
642                         int nativeError;
643
644                         int ret = Send_internal (socket, buf, offset, size, flags, out nativeError);
645
646                         error = (SocketError)nativeError;
647
648                         if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
649                                 connected = false;
650                         else
651                                 connected = true;
652
653                         return ret;
654                 }
655
656                 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
657                 {
658                         if (disposed && closed)
659                                 throw new ObjectDisposedException (GetType ().ToString ());
660
661                         object obj_val;
662                         int error;
663
664                         GetSocketOption_obj_internal (socket, optionLevel, optionName, out obj_val,
665                                 out error);
666                         if (error != 0)
667                                 throw new SocketException (error);
668
669                         if (optionName == SocketOptionName.Linger) {
670                                 return((LingerOption)obj_val);
671                         } else if (optionName == SocketOptionName.AddMembership ||
672                                    optionName == SocketOptionName.DropMembership) {
673                                 return((MulticastOption)obj_val);
674                         } else if (obj_val is int) {
675                                 return((int)obj_val);
676                         } else {
677                                 return(obj_val);
678                         }
679                 }
680
681                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
682                 private extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
683                 
684                 public void Shutdown (SocketShutdown how)
685                 {
686                         if (disposed && closed)
687                                 throw new ObjectDisposedException (GetType ().ToString ());
688
689                         int error;
690                         
691                         Shutdown_internal (socket, how, out error);
692
693                         if (error != 0)
694                                 throw new SocketException (error);
695                 }
696
697                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
698                 private extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level,
699                                                                      SocketOptionName name, object obj_val,
700                                                                      byte [] byte_val, int int_val,
701                                                                      out int error);
702
703                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
704                 {
705                         if (disposed && closed)
706                                 throw new ObjectDisposedException (GetType ().ToString ());
707
708                         int error;
709
710                         SetSocketOption_internal (socket, optionLevel, optionName, null,
711                                                  null, optionValue, out error);
712
713                         if (error != 0)
714                                 throw new SocketException (error);
715                 }
716
717                 private void ThrowIfUpd ()
718                 {
719 #if !NET_2_1
720                         if (protocol_type == ProtocolType.Udp)
721                                 throw new SocketException ((int)SocketError.ProtocolOption);
722 #endif
723                 }
724
725 #if NET_2_1 && !MONOTOUCH
726                 static void CheckConnect (SocketAsyncEventArgs e)
727                 {
728                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
729
730                         if (e.RemoteEndPoint == null)
731                                 throw new ArgumentNullException ("remoteEP");
732                         if (e.BufferList != null)
733                                 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
734                 }
735
736                 public bool ConnectAsync (SocketAsyncEventArgs e)
737                 {
738                         if (disposed && closed)
739                                 throw new ObjectDisposedException (GetType ().ToString ());
740
741                         CheckConnect (e);
742
743                         e.DoOperation (SocketAsyncOperation.Connect, this);
744
745                         // We always return true for now
746                         return true;
747                 }
748
749                 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
750                 {
751                         // exception ordering requires to check before creating the socket (good thing resource wise too)
752                         CheckConnect (e);
753
754                         Socket s = new Socket (AddressFamily.InterNetwork, socketType, protocolType);
755                         e.DoOperation (SocketAsyncOperation.Connect, s);
756
757                         // We always return true for now
758                         return true;
759                 }
760
761                 public static void CancelConnectAsync (SocketAsyncEventArgs e)
762                 {
763                         if (e == null)
764                                 throw new ArgumentNullException ("e");
765
766                         Socket s = e.ConnectSocket;
767                         if ((s != null) && (s.blocking_thread != null))
768                                 s.blocking_thread.Abort ();
769                 }
770 #endif
771         }
772 }
773