2009-11-10 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 (!connected || 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                         bool was_connected = connected;
421                         connected = false;
422                         if ((int) socket != -1) {
423                                 int error;
424                                 closed = true;
425                                 IntPtr x = socket;
426                                 socket = (IntPtr) (-1);
427                                 Thread th = blocking_thread;
428                                 if (th != null) {
429                                         th.Abort ();
430                                         blocking_thread = null;
431                                 }
432
433                                 if (was_connected)
434                                         Linger (x);
435                                 //DateTime start = DateTime.UtcNow;
436                                 Close_internal (x, out error);
437                                 //Console.WriteLine ("Time spent in Close_internal: {0}ms", (DateTime.UtcNow - start).TotalMilliseconds);
438                                 if (error != 0)
439                                         throw new SocketException (error);
440                         }
441                 }
442
443 #if NET_2_1
444                 public void Dispose ()
445 #else
446                 void IDisposable.Dispose ()
447 #endif
448                 {
449                         Dispose (true);
450                         GC.SuppressFinalize (this);
451                 }
452
453                 // Closes the socket
454                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
455                 private extern static void Close_internal(IntPtr socket, out int error);
456
457                 public void Close ()
458                 {
459                         linger_timeout = 0;
460                         ((IDisposable) this).Dispose ();
461                 }
462
463 #if NET_2_0
464                 public void Close (int timeout) 
465                 {
466                         linger_timeout = timeout;
467                         ((IDisposable) this).Dispose ();
468                 }
469 #endif
470
471                 // Connects to the remote address
472                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
473                 private extern static void Connect_internal(IntPtr sock,
474                                                             SocketAddress sa,
475                                                             out int error);
476
477                 public void Connect (EndPoint remoteEP)
478                 {
479                         SocketAddress serial = null;
480
481                         if (disposed && closed)
482                                 throw new ObjectDisposedException (GetType ().ToString ());
483
484                         if (remoteEP == null)
485                                 throw new ArgumentNullException ("remoteEP");
486
487                         IPEndPoint ep = remoteEP as IPEndPoint;
488                         if (ep != null)
489                                 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
490                                         throw new SocketException ((int) SocketError.AddressNotAvailable);
491
492 #if NET_2_1 && !MONOTOUCH
493                         if (protocol_type != ProtocolType.Tcp)
494                                 throw new SocketException ((int) SocketError.AccessDenied);
495 #elif NET_2_0
496                         /* TODO: check this for the 1.1 profile too */
497                         if (islistening)
498                                 throw new InvalidOperationException ();
499 #endif
500                         serial = remoteEP.Serialize ();
501
502                         int error = 0;
503
504                         blocking_thread = Thread.CurrentThread;
505                         try {
506                                 Connect_internal (socket, serial, out error);
507                         } catch (ThreadAbortException) {
508                                 if (disposed) {
509                                         Thread.ResetAbort ();
510                                         error = (int) SocketError.Interrupted;
511                                 }
512                         } finally {
513                                 blocking_thread = null;
514                         }
515
516                         if (error != 0)
517                                 throw new SocketException (error);
518
519                         connected=true;
520
521 #if NET_2_0
522                         isbound = true;
523 #endif
524
525                         seed_endpoint = remoteEP;
526                 }
527
528 #if NET_2_0
529                 public bool ReceiveAsync (SocketAsyncEventArgs e)
530                 {
531                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
532                         //
533                         // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
534                         // thrown when e.Buffer and e.BufferList are null (works fine when one is
535                         // set to a valid object)
536                         if (disposed && closed)
537                                 throw new ObjectDisposedException (GetType ().ToString ());
538
539                         // We do not support recv into multiple buffers yet
540                         if (e.BufferList != null)
541                                 throw new NotSupportedException ("Mono doesn't support using BufferList at this point.");
542                         
543                         e.DoOperation (SocketAsyncOperation.Receive, this);
544
545                         // We always return true for now
546                         return true;
547                 }
548
549                 public bool SendAsync (SocketAsyncEventArgs e)
550                 {
551                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
552                         
553                         if (disposed && closed)
554                                 throw new ObjectDisposedException (GetType ().ToString ());
555                         if (e.Buffer == null && e.BufferList == null)
556                                 throw new ArgumentException ("Either e.Buffer or e.BufferList must be valid buffers.");
557
558                         e.DoOperation (SocketAsyncOperation.Send, this);
559
560                         // We always return true for now
561                         return true;
562                 }
563 #endif
564
565                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
566                 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
567
568 #if !NET_2_1 || MONOTOUCH
569                 /* This overload is needed as the async Connect method
570                  * also needs to check the socket error status, but
571                  * getsockopt(..., SO_ERROR) clears the error.
572                  */
573                 internal bool Poll (int time_us, SelectMode mode, out int socket_error)
574                 {
575                         if (disposed && closed)
576                                 throw new ObjectDisposedException (GetType ().ToString ());
577
578                         if (mode != SelectMode.SelectRead &&
579                             mode != SelectMode.SelectWrite &&
580                             mode != SelectMode.SelectError)
581                                 throw new NotSupportedException ("'mode' parameter is not valid.");
582
583                         int error;
584                         bool result = Poll_internal (socket, mode, time_us, out error);
585                         if (error != 0)
586                                 throw new SocketException (error);
587
588                         socket_error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
589                         
590                         if (mode == SelectMode.SelectWrite && result) {
591                                 /* Update the connected state; for
592                                  * non-blocking Connect()s this is
593                                  * when we can find out that the
594                                  * connect succeeded.
595                                  */
596                                 if (socket_error == 0) {
597                                         connected = true;
598                                 }
599                         }
600                         
601                         return result;
602                 }
603 #endif
604                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
605                 private extern static int Receive_internal(IntPtr sock,
606                                                            byte[] buffer,
607                                                            int offset,
608                                                            int count,
609                                                            SocketFlags flags,
610                                                            out int error);
611
612                 internal int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
613                 {
614                         int nativeError;
615                         int ret = Receive_internal (socket, buf, offset, size, flags, out nativeError);
616                         error = (SocketError) nativeError;
617                         if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
618                                 connected = false;
619                         else
620                                 connected = true;
621                         
622                         return ret;
623                 }
624
625                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
626                 private extern static void GetSocketOption_obj_internal(IntPtr socket,
627                         SocketOptionLevel level, SocketOptionName name, out object obj_val,
628                         out int error);
629
630                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
631                 private extern static int Send_internal(IntPtr sock,
632                                                         byte[] buf, int offset,
633                                                         int count,
634                                                         SocketFlags flags,
635                                                         out int error);
636
637                 internal int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
638                 {
639                         if (size == 0) {
640                                 error = SocketError.Success;
641                                 return 0;
642                         }
643
644                         int nativeError;
645
646                         int ret = Send_internal (socket, buf, offset, size, flags, out nativeError);
647
648                         error = (SocketError)nativeError;
649
650                         if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress)
651                                 connected = false;
652                         else
653                                 connected = true;
654
655                         return ret;
656                 }
657
658                 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
659                 {
660                         if (disposed && closed)
661                                 throw new ObjectDisposedException (GetType ().ToString ());
662
663                         object obj_val;
664                         int error;
665
666                         GetSocketOption_obj_internal (socket, optionLevel, optionName, out obj_val,
667                                 out error);
668                         if (error != 0)
669                                 throw new SocketException (error);
670
671                         if (optionName == SocketOptionName.Linger) {
672                                 return((LingerOption)obj_val);
673                         } else if (optionName == SocketOptionName.AddMembership ||
674                                    optionName == SocketOptionName.DropMembership) {
675                                 return((MulticastOption)obj_val);
676                         } else if (obj_val is int) {
677                                 return((int)obj_val);
678                         } else {
679                                 return(obj_val);
680                         }
681                 }
682
683                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
684                 private extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
685                 
686                 public void Shutdown (SocketShutdown how)
687                 {
688                         if (disposed && closed)
689                                 throw new ObjectDisposedException (GetType ().ToString ());
690
691                         if (!connected)
692                                 throw new SocketException (10057); // Not connected
693
694                         int error;
695                         
696                         Shutdown_internal (socket, how, out error);
697                         if (error != 0)
698                                 throw new SocketException (error);
699                 }
700
701                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
702                 private extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level,
703                                                                      SocketOptionName name, object obj_val,
704                                                                      byte [] byte_val, int int_val,
705                                                                      out int error);
706
707                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
708                 {
709                         if (disposed && closed)
710                                 throw new ObjectDisposedException (GetType ().ToString ());
711
712                         int error;
713
714                         SetSocketOption_internal (socket, optionLevel, optionName, null,
715                                                  null, optionValue, out error);
716
717                         if (error != 0)
718                                 throw new SocketException (error);
719                 }
720
721                 private void ThrowIfUpd ()
722                 {
723 #if !NET_2_1
724                         if (protocol_type == ProtocolType.Udp)
725                                 throw new SocketException ((int)SocketError.ProtocolOption);
726 #endif
727                 }
728
729 #if NET_2_1 && !MONOTOUCH
730                 static void CheckConnect (SocketAsyncEventArgs e)
731                 {
732                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
733
734                         if (e.RemoteEndPoint == null)
735                                 throw new ArgumentNullException ("remoteEP");
736                         if (e.BufferList != null)
737                                 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
738                 }
739
740                 public bool ConnectAsync (SocketAsyncEventArgs e)
741                 {
742                         if (disposed && closed)
743                                 throw new ObjectDisposedException (GetType ().ToString ());
744
745                         CheckConnect (e);
746
747                         e.DoOperation (SocketAsyncOperation.Connect, this);
748
749                         // We always return true for now
750                         return true;
751                 }
752
753                 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
754                 {
755                         // exception ordering requires to check before creating the socket (good thing resource wise too)
756                         CheckConnect (e);
757
758                         Socket s = new Socket (AddressFamily.InterNetwork, socketType, protocolType);
759                         e.DoOperation (SocketAsyncOperation.Connect, s);
760
761                         // We always return true for now
762                         return true;
763                 }
764
765                 public static void CancelConnectAsync (SocketAsyncEventArgs e)
766                 {
767                         if (e == null)
768                                 throw new ArgumentNullException ("e");
769
770                         Socket s = e.ConnectSocket;
771                         if ((s != null) && (s.blocking_thread != null))
772                                 s.blocking_thread.Abort ();
773                 }
774 #endif
775         }
776 }
777