[Socket] Improved ConnectAsync
[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-2011 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.Collections.Generic;
40 using System.Runtime.CompilerServices;
41 using System.Runtime.InteropServices;
42 using System.Threading;
43 using System.IO;
44 using System.Security;
45 using System.Text;
46
47 #if !NET_2_1
48 using System.Net.Configuration;
49 using System.Net.NetworkInformation;
50 #endif
51 #if MOONLIGHT && !INSIDE_SYSTEM
52 using System.Net.Policy;
53 #endif
54
55 namespace System.Net.Sockets {
56
57         public partial class Socket : IDisposable {
58                 [StructLayout (LayoutKind.Sequential)]
59                 struct WSABUF {
60                         public int len;
61                         public IntPtr buf;
62                 }
63
64                 // Used by the runtime
65                 internal enum SocketOperation {
66                         Accept,
67                         Connect,
68                         Receive,
69                         ReceiveFrom,
70                         Send,
71                         SendTo,
72                         RecvJustCallback,
73                         SendJustCallback,
74                         UsedInProcess,
75                         UsedInConsole2,
76                         Disconnect,
77                         AcceptReceive,
78                         ReceiveGeneric,
79                         SendGeneric
80                 }
81
82                 [StructLayout (LayoutKind.Sequential)]
83                 internal sealed class SocketAsyncResult: IAsyncResult
84                 {
85                         /* Same structure in the runtime */
86                         /*
87                           Keep this in sync with MonoSocketAsyncResult in
88                           metadata/socket-io.h and ProcessAsyncReader
89                           in System.Diagnostics/Process.cs.
90                         */
91
92                         public Socket Sock;
93                         public IntPtr handle;
94                         object state;
95                         AsyncCallback callback; // used from the runtime
96                         WaitHandle waithandle;
97
98                         Exception delayedException;
99
100                         public EndPoint EndPoint;       // Connect,ReceiveFrom,SendTo
101                         public byte [] Buffer;          // Receive,ReceiveFrom,Send,SendTo
102                         public int Offset;              // Receive,ReceiveFrom,Send,SendTo
103                         public int Size;                // Receive,ReceiveFrom,Send,SendTo
104                         public SocketFlags SockFlags;   // Receive,ReceiveFrom,Send,SendTo
105                         public Socket AcceptSocket;     // AcceptReceive
106                         public IPAddress[] Addresses;   // Connect
107                         public int Port;                // Connect
108                         public IList<ArraySegment<byte>> Buffers;       // Receive, Send
109                         public bool ReuseSocket;        // Disconnect
110
111                         // Return values
112                         Socket acc_socket;
113                         int total;
114
115                         bool completed_sync;
116                         bool completed;
117                         public bool blocking;
118                         internal int error;
119                         public SocketOperation operation;
120                         public object ares;
121                         public int EndCalled;
122
123                         // These fields are not in MonoSocketAsyncResult
124                         public Worker Worker;
125                         public int CurrentAddress; // Connect
126
127                         public SocketAsyncResult ()
128                         {
129                         }
130
131                         public void Init (Socket sock, object state, AsyncCallback callback, SocketOperation operation)
132                         {
133                                 this.Sock = sock;
134                                 if (sock != null) {
135                                         this.blocking = sock.blocking;
136                                         this.handle = sock.socket;
137                                 } else {
138                                         this.blocking = true;
139                                         this.handle = IntPtr.Zero;
140                                 }
141                                 this.state = state;
142                                 this.callback = callback;
143                                 GC.KeepAlive (this.callback);
144                                 this.operation = operation;
145                                 SockFlags = SocketFlags.None;
146                                 if (waithandle != null)
147                                         ((ManualResetEvent) waithandle).Reset ();
148
149                                 delayedException = null;
150
151                                 EndPoint = null;
152                                 Buffer = null;
153                                 Offset = 0;
154                                 Size = 0;
155                                 SockFlags = 0;
156                                 AcceptSocket = null;
157                                 Addresses = null;
158                                 Port = 0;
159                                 Buffers = null;
160                                 ReuseSocket = false;
161                                 acc_socket = null;
162                                 total = 0;
163
164                                 completed_sync = false;
165                                 completed = false;
166                                 blocking = false;
167                                 error = 0;
168                                 ares = null;
169                                 EndCalled = 0;
170                                 Worker = null;
171                         }
172
173                         public void DoMConnectCallback ()
174                         {
175                                 if (callback == null)
176                                         return;
177 #if MOONLIGHT
178                                 ThreadPool.QueueUserWorkItem (_ => { callback (this); }, null);
179 #else
180                                 ThreadPool.UnsafeQueueUserWorkItem (_ => { callback (this); }, null);
181 #endif
182                         }
183
184                         public void Dispose ()
185                         {
186                                 Init (null, null, null, 0);
187                                 if (waithandle != null) {
188                                         waithandle.Close ();
189                                         waithandle = null;
190                                 }
191                         }
192
193                         public SocketAsyncResult (Socket sock, object state, AsyncCallback callback, SocketOperation operation)
194                         {
195                                 this.Sock = sock;
196                                 this.blocking = sock.blocking;
197                                 this.handle = sock.socket;
198                                 this.state = state;
199                                 this.callback = callback;
200                                 GC.KeepAlive (this.callback);
201                                 this.operation = operation;
202                                 SockFlags = SocketFlags.None;
203                                 Worker = new Worker (this);
204                         }
205
206                         public void CheckIfThrowDelayedException ()
207                         {
208                                 if (delayedException != null) {
209                                         Sock.connected = false;
210                                         throw delayedException;
211                                 }
212
213                                 if (error != 0) {
214                                         Sock.connected = false;
215                                         throw new SocketException (error);
216                                 }
217                         }
218
219                         void CompleteAllOnDispose (Queue queue)
220                         {
221                                 object [] pending = queue.ToArray ();
222                                 queue.Clear ();
223
224                                 WaitCallback cb;
225                                 for (int i = 0; i < pending.Length; i++) {
226                                         Worker worker = (Worker) pending [i];
227                                         SocketAsyncResult ares = worker.result;
228                                         cb = new WaitCallback (ares.CompleteDisposed);
229 #if MOONLIGHT
230                                         ThreadPool.QueueUserWorkItem (cb, null);
231 #else
232                                         ThreadPool.UnsafeQueueUserWorkItem (cb, null);
233 #endif
234                                 }
235                         }
236
237                         void CompleteDisposed (object unused)
238                         {
239                                 Complete ();
240                         }
241
242                         public void Complete ()
243                         {
244                                 if (operation != SocketOperation.Receive && Sock.disposed)
245                                         delayedException = new ObjectDisposedException (Sock.GetType ().ToString ());
246
247                                 IsCompleted = true;
248
249                                 Queue queue = null;
250                                 if (operation == SocketOperation.Receive ||
251                                     operation == SocketOperation.ReceiveFrom ||
252                                     operation == SocketOperation.ReceiveGeneric) {
253                                         queue = Sock.readQ;
254                                 } else if (operation == SocketOperation.Send ||
255                                            operation == SocketOperation.SendTo ||
256                                            operation == SocketOperation.SendGeneric) {
257
258                                         queue = Sock.writeQ;
259                                 }
260
261                                 if (queue != null) {
262                                         Worker worker = null;
263                                         SocketAsyncCall sac = null;
264                                         lock (queue) {
265                                                 // queue.Count will only be 0 if the socket is closed while receive/send
266                                                 // operation(s) are pending and at least one call to this method is
267                                                 // waiting on the lock while another one calls CompleteAllOnDispose()
268                                                 if (queue.Count > 0)
269                                                         queue.Dequeue (); // remove ourselves
270                                                 if (queue.Count > 0) {
271                                                         worker = (Worker) queue.Peek ();
272                                                         if (!Sock.disposed) {
273                                                                 sac = Worker.Dispatcher;
274                                                         } else {
275                                                                 CompleteAllOnDispose (queue);
276                                                         }
277                                                 }
278                                         }
279
280                                         if (sac != null)
281                                                 Socket.socket_pool_queue (sac, worker.result);
282                                 }
283                                 // IMPORTANT: 'callback', if any is scheduled from unmanaged code
284                         }
285
286                         public void Complete (bool synch)
287                         {
288                                 completed_sync = synch;
289                                 Complete ();
290                         }
291
292                         public void Complete (int total)
293                         {
294                                 this.total = total;
295                                 Complete ();
296                         }
297
298                         public void Complete (Exception e, bool synch)
299                         {
300                                 completed_sync = synch;
301                                 delayedException = e;
302                                 Complete ();
303                         }
304
305                         public void Complete (Exception e)
306                         {
307                                 delayedException = e;
308                                 Complete ();
309                         }
310
311                         public void Complete (Socket s)
312                         {
313                                 acc_socket = s;
314                                 Complete ();
315                         }
316
317                         public void Complete (Socket s, int total)
318                         {
319                                 acc_socket = s;
320                                 this.total = total;
321                                 Complete ();
322                         }
323
324                         public object AsyncState {
325                                 get {
326                                         return state;
327                                 }
328                         }
329
330                         public WaitHandle AsyncWaitHandle {
331                                 get {
332                                         lock (this) {
333                                                 if (waithandle == null)
334                                                         waithandle = new ManualResetEvent (completed);
335                                         }
336
337                                         return waithandle;
338                                 }
339                                 set {
340                                         waithandle=value;
341                                 }
342                         }
343
344                         public bool CompletedSynchronously {
345                                 get {
346                                         return(completed_sync);
347                                 }
348                         }
349
350                         public bool IsCompleted {
351                                 get {
352                                         return(completed);
353                                 }
354                                 set {
355                                         completed=value;
356                                         lock (this) {
357                                                 if (waithandle != null && value) {
358                                                         ((ManualResetEvent) waithandle).Set ();
359                                                 }
360                                         }
361                                 }
362                         }
363
364                         public Socket Socket {
365                                 get {
366                                         return acc_socket;
367                                 }
368                         }
369
370                         public int Total {
371                                 get { return total; }
372                                 set { total = value; }
373                         }
374
375                         public SocketError ErrorCode {
376                                 get {
377                                         SocketException ex = delayedException as SocketException;
378                                         if (ex != null)
379                                                 return(ex.SocketErrorCode);
380
381                                         if (error != 0)
382                                                 return((SocketError)error);
383
384                                         return(SocketError.Success);
385                                 }
386                         }
387                 }
388
389                 internal sealed class Worker
390                 {
391                         public SocketAsyncResult result;
392                         SocketAsyncEventArgs args;
393
394                         public Worker (SocketAsyncEventArgs args)
395                         {
396                                 this.args = args;
397                                 result = new SocketAsyncResult ();
398                                 result.Worker = this;
399                         }
400
401                         public Worker (SocketAsyncResult ares)
402                         {
403                                 this.result = ares;
404                         }
405
406                         public void Dispose ()
407                         {
408                                 if (result != null) {
409                                         result.Dispose ();
410                                         result = null;
411                                         args = null;
412                                 }
413                         }
414
415                         public static SocketAsyncCall Dispatcher = new SocketAsyncCall (DispatcherCB);
416
417                         static void DispatcherCB (SocketAsyncResult sar)
418                         {
419                                 SocketOperation op = sar.operation;
420                                 if (op == Socket.SocketOperation.Receive || op == Socket.SocketOperation.ReceiveGeneric ||
421                                         op == Socket.SocketOperation.RecvJustCallback)
422                                         sar.Worker.Receive ();
423                                 else if (op == Socket.SocketOperation.Send || op == Socket.SocketOperation.SendGeneric ||
424                                         op == Socket.SocketOperation.SendJustCallback)
425                                         sar.Worker.Send ();
426 #if !MOONLIGHT
427                                 else if (op == Socket.SocketOperation.ReceiveFrom)
428                                         sar.Worker.ReceiveFrom ();
429                                 else if (op == Socket.SocketOperation.SendTo)
430                                         sar.Worker.SendTo ();
431 #endif
432                                 else if (op == Socket.SocketOperation.Connect)
433                                         sar.Worker.Connect ();
434 #if !MOONLIGHT
435                                 else if (op == Socket.SocketOperation.Accept)
436                                         sar.Worker.Accept ();
437                                 else if (op == Socket.SocketOperation.AcceptReceive)
438                                         sar.Worker.AcceptReceive ();
439                                 else if (op == Socket.SocketOperation.Disconnect)
440                                         sar.Worker.Disconnect ();
441
442                                 // SendPackets and ReceiveMessageFrom are not implemented yet
443                                 /*
444                                 else if (op == Socket.SocketOperation.ReceiveMessageFrom)
445                                         async_op = SocketAsyncOperation.ReceiveMessageFrom;
446                                 else if (op == Socket.SocketOperation.SendPackets)
447                                         async_op = SocketAsyncOperation.SendPackets;
448                                 */
449 #endif
450                                 else
451                                         throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
452                         }
453
454                         /* This is called when reusing a SocketAsyncEventArgs */
455                         public void Init (Socket sock, SocketAsyncEventArgs args, SocketOperation op)
456                         {
457                                 result.Init (sock, args, SocketAsyncEventArgs.Dispatcher, op);
458                                 result.Worker = this;
459                                 SocketAsyncOperation async_op;
460
461                                 // Notes;
462                                 //      -SocketOperation.AcceptReceive not used in SocketAsyncEventArgs
463                                 //      -SendPackets and ReceiveMessageFrom are not implemented yet
464                                 if (op == Socket.SocketOperation.Connect)
465                                         async_op = SocketAsyncOperation.Connect;
466 #if !MOONLIGHT
467                                 else if (op == Socket.SocketOperation.Accept)
468                                         async_op = SocketAsyncOperation.Accept;
469                                 else if (op == Socket.SocketOperation.Disconnect)
470                                         async_op = SocketAsyncOperation.Disconnect;
471 #endif
472                                 else if (op == Socket.SocketOperation.Receive || op == Socket.SocketOperation.ReceiveGeneric)
473                                         async_op = SocketAsyncOperation.Receive;
474 #if !MOONLIGHT
475                                 else if (op == Socket.SocketOperation.ReceiveFrom)
476                                         async_op = SocketAsyncOperation.ReceiveFrom;
477 #endif
478                                 /*
479                                 else if (op == Socket.SocketOperation.ReceiveMessageFrom)
480                                         async_op = SocketAsyncOperation.ReceiveMessageFrom;
481                                 */
482                                 else if (op == Socket.SocketOperation.Send || op == Socket.SocketOperation.SendGeneric)
483                                         async_op = SocketAsyncOperation.Send;
484 #if !MOONLIGHT
485                                 /*
486                                 else if (op == Socket.SocketOperation.SendPackets)
487                                         async_op = SocketAsyncOperation.SendPackets;
488                                 */
489                                 else if (op == Socket.SocketOperation.SendTo)
490                                         async_op = SocketAsyncOperation.SendTo;
491 #endif
492                                 else
493                                         throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
494
495                                 args.SetLastOperation (async_op);
496                                 args.SocketError = SocketError.Success;
497                                 args.BytesTransferred = 0;
498                         }
499
500                         public void Accept ()
501                         {
502 #if !MOONLIGHT
503                                 Socket acc_socket = null;
504                                 try {
505                                         if (args != null && args.AcceptSocket != null) {
506                                                 result.Sock.Accept (args.AcceptSocket);
507                                                 acc_socket = args.AcceptSocket;
508                                         } else {
509                                                 acc_socket = result.Sock.Accept ();
510                                                 if (args != null)
511                                                         args.AcceptSocket = acc_socket;
512                                         }
513                                 } catch (Exception e) {
514                                         result.Complete (e);
515                                         return;
516                                 }
517
518                                 result.Complete (acc_socket);
519 #endif
520                         }
521
522                         /* only used in 2.0 profile and newer, but
523                          * leave in older profiles to keep interface
524                          * to runtime consistent
525                          */
526                         public void AcceptReceive ()
527                         {
528 #if !MOONLIGHT
529                                 Socket acc_socket = null;
530                                 try {
531                                         if (result.AcceptSocket == null) {
532                                                 acc_socket = result.Sock.Accept ();
533                                         } else {
534                                                 acc_socket = result.AcceptSocket;
535                                                 result.Sock.Accept (acc_socket);
536                                         }
537                                 } catch (Exception e) {
538                                         result.Complete (e);
539                                         return;
540                                 }
541
542                                 /* It seems the MS runtime
543                                  * special-cases 0-length requested
544                                  * receive data.  See bug 464201.
545                                  */
546                                 int total = 0;
547                                 if (result.Size > 0) {
548                                         try {
549                                                 SocketError error;
550                                                 total = acc_socket.Receive_nochecks (result.Buffer,
551                                                                                      result.Offset,
552                                                                                      result.Size,
553                                                                                      result.SockFlags,
554                                                                                      out error);
555                                                 if (error != 0) {
556                                                         result.Complete (new SocketException ((int) error));
557                                                         return;
558                                                 }
559                                         } catch (Exception e) {
560                                                 result.Complete (e);
561                                                 return;
562                                         }
563                                 }
564
565                                 result.Complete (acc_socket, total);
566 #endif
567                         }
568
569                         public void Connect ()
570                         {
571                                 if (result.EndPoint == null) {
572                                         result.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
573                                         return;
574                                 }
575
576                                 SocketAsyncResult mconnect = result.AsyncState as SocketAsyncResult;
577 #if !MOONLIGHT
578                                 bool is_mconnect = (mconnect != null && mconnect.Addresses != null);
579 #else
580                                 bool is_mconnect = false;
581 #endif
582                                 try {
583                                         int error_code;
584                                         EndPoint ep = result.EndPoint;
585                                         SocketAddress serial = ep.Serialize ();
586                                         Connect_internal (result.Sock.socket, serial, out error_code);
587                                         if (error_code == 0) {
588                                                 if (is_mconnect)
589                                                         result = mconnect;
590                                                 result.Sock.seed_endpoint = ep;
591                                                 result.Sock.connected = true;
592                                                 result.error = 0;
593                                                 result.Complete ();
594                                                 if (is_mconnect)
595                                                         result.DoMConnectCallback ();
596                                                 return;
597                                         }
598
599                                         if (!is_mconnect) {
600                                                 result.Complete (new SocketException (error_code));
601                                                 return;
602                                         }
603
604                                         if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
605                                                 mconnect.Complete (new SocketException (error_code));
606                                                 if (is_mconnect)
607                                                         mconnect.DoMConnectCallback ();
608                                                 return;
609                                         }
610 #if !MOONLIGHT
611                                         mconnect.Sock.BeginMConnect (mconnect);
612 #endif
613                                 } catch (Exception e) {
614                                         if (is_mconnect)
615                                                 result = mconnect;
616                                         result.Complete (e);
617                                         if (is_mconnect)
618                                                 result.DoMConnectCallback ();
619                                         return;
620                                 }
621                         }
622
623                         /* Also only used in 2.0 profile and newer */
624                         public void Disconnect ()
625                         {
626 #if !MOONLIGHT
627                                 try {
628                                         if (args != null)
629                                                 result.ReuseSocket = args.DisconnectReuseSocket;
630                                         result.Sock.Disconnect (result.ReuseSocket);
631                                 } catch (Exception e) {
632                                         result.Complete (e);
633                                         return;
634                                 }
635                                 result.Complete ();
636 #endif
637                         }
638
639                         public void Receive ()
640                         {
641                                 if (result.operation == SocketOperation.ReceiveGeneric) {
642                                         ReceiveGeneric ();
643                                         return;
644                                 }
645                                 // Actual recv() done in the runtime
646                                 result.Complete ();
647                         }
648
649                         public void ReceiveFrom ()
650                         {
651 #if !MOONLIGHT
652                                 int total = 0;
653                                 try {
654                                         total = result.Sock.ReceiveFrom_nochecks (result.Buffer,
655                                                                          result.Offset,
656                                                                          result.Size,
657                                                                          result.SockFlags,
658                                                                          ref result.EndPoint);
659                                 } catch (Exception e) {
660                                         result.Complete (e);
661                                         return;
662                                 }
663
664                                 result.Complete (total);
665 #endif
666                         }
667
668                         public void ReceiveGeneric ()
669                         {
670                                 int total = 0;
671                                 try {
672                                         total = result.Sock.Receive (result.Buffers, result.SockFlags);
673                                 } catch (Exception e) {
674                                         result.Complete (e);
675                                         return;
676                                 }
677                                 result.Complete (total);
678                         }
679
680                         int send_so_far;
681
682                         void UpdateSendValues (int last_sent)
683                         {
684                                 if (result.error == 0) {
685                                         send_so_far += last_sent;
686                                         result.Offset += last_sent;
687                                         result.Size -= last_sent;
688                                 }
689                         }
690
691                         public void Send ()
692                         {
693                                 if (result.operation == SocketOperation.SendGeneric) {
694                                         SendGeneric ();
695                                         return;
696                                 }
697                                 // Actual send() done in the runtime
698                                 if (result.error == 0) {
699                                         UpdateSendValues (result.Total);
700                                         if (result.Sock.disposed) {
701                                                 result.Complete ();
702                                                 return;
703                                         }
704
705                                         if (result.Size > 0) {
706                                                 Socket.socket_pool_queue (Worker.Dispatcher, result);
707                                                 return; // Have to finish writing everything. See bug #74475.
708                                         }
709                                         result.Total = send_so_far;
710                                 }
711                                 result.Complete ();
712                         }
713
714                         public void SendTo ()
715                         {
716 #if !MOONLIGHT
717                                 int total = 0;
718                                 try {
719                                         total = result.Sock.SendTo_nochecks (result.Buffer,
720                                                                     result.Offset,
721                                                                     result.Size,
722                                                                     result.SockFlags,
723                                                                     result.EndPoint);
724
725                                         UpdateSendValues (total);
726                                         if (result.Size > 0) {
727                                                 Socket.socket_pool_queue (Worker.Dispatcher, result);
728                                                 return; // Have to finish writing everything. See bug #74475.
729                                         }
730                                         result.Total = send_so_far;
731                                 } catch (Exception e) {
732                                         result.Complete (e);
733                                         return;
734                                 }
735
736                                 result.Complete ();
737 #endif
738                         }
739
740                         public void SendGeneric ()
741                         {
742                                 int total = 0;
743                                 try {
744                                         total = result.Sock.Send (result.Buffers, result.SockFlags);
745                                 } catch (Exception e) {
746                                         result.Complete (e);
747                                         return;
748                                 }
749                                 result.Complete (total);
750                         }
751                 }
752
753                 private Queue readQ = new Queue (2);
754                 private Queue writeQ = new Queue (2);
755
756                 internal delegate void SocketAsyncCall (SocketAsyncResult sar);
757
758                 /*
759                  *      These two fields are looked up by name by the runtime, don't change
760                  *  their name without also updating the runtime code.
761                  */
762                 private static int ipv4Supported = -1, ipv6Supported = -1;
763                 int linger_timeout;
764
765                 static Socket ()
766                 {
767                         // initialize ipv4Supported and ipv6Supported
768                         CheckProtocolSupport ();
769                 }
770
771                 internal static void CheckProtocolSupport ()
772                 {
773                         if(ipv4Supported == -1) {
774                                 try {
775                                         Socket tmp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
776                                         tmp.Close();
777
778                                         ipv4Supported = 1;
779                                 } catch {
780                                         ipv4Supported = 0;
781                                 }
782                         }
783
784                         if (ipv6Supported == -1) {
785 #if !NET_2_1
786 #if CONFIGURATION_DEP
787                                 SettingsSection config;
788                                 config = (SettingsSection) System.Configuration.ConfigurationManager.GetSection ("system.net/settings");
789                                 if (config != null)
790                                         ipv6Supported = config.Ipv6.Enabled ? -1 : 0;
791 #else
792                                 NetConfig config = System.Configuration.ConfigurationSettings.GetConfig("system.net/settings") as NetConfig;
793                                 if (config != null)
794                                         ipv6Supported = config.ipv6Enabled ? -1 : 0;
795 #endif
796 #endif
797                                 if (ipv6Supported != 0) {
798                                         try {
799                                                 Socket tmp = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
800                                                 tmp.Close();
801
802                                                 ipv6Supported = 1;
803                                         } catch {
804                                                 ipv6Supported = 0;
805                                         }
806                                 }
807                         }
808                 }
809
810                 public static bool SupportsIPv4 {
811                         get {
812                                 CheckProtocolSupport();
813                                 return ipv4Supported == 1;
814                         }
815                 }
816
817                 [ObsoleteAttribute ("Use OSSupportsIPv6 instead")]
818                 public static bool SupportsIPv6 {
819                         get {
820                                 CheckProtocolSupport();
821                                 return ipv6Supported == 1;
822                         }
823                 }
824 #if NET_2_1
825                 public static bool OSSupportsIPv4 {
826                         get {
827                                 CheckProtocolSupport();
828                                 return ipv4Supported == 1;
829                         }
830                 }
831 #endif
832 #if NET_2_1
833                 public static bool OSSupportsIPv6 {
834                         get {
835                                 CheckProtocolSupport();
836                                 return ipv6Supported == 1;
837                         }
838                 }
839 #else
840                 public static bool OSSupportsIPv6 {
841                         get {
842                                 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces ();
843                                 
844                                 foreach (NetworkInterface adapter in nics) {
845                                         if (adapter.Supports (NetworkInterfaceComponent.IPv6))
846                                                 return true;
847                                 }
848                                 return false;
849                         }
850                 }
851 #endif
852
853                 /* the field "socket" is looked up by name by the runtime */
854                 private IntPtr socket;
855                 private AddressFamily address_family;
856                 private SocketType socket_type;
857                 private ProtocolType protocol_type;
858                 internal bool blocking=true;
859                 Thread blocking_thread;
860                 private bool isbound;
861                 /* When true, the socket was connected at the time of
862                  * the last IO operation
863                  */
864                 private bool connected;
865                 /* true if we called Close_internal */
866                 private bool closed;
867                 internal bool disposed;
868
869                 /*
870                  * This EndPoint is used when creating new endpoints. Because
871                  * there are many types of EndPoints possible,
872                  * seed_endpoint.Create(addr) is used for creating new ones.
873                  * As such, this value is set on Bind, SentTo, ReceiveFrom,
874                  * Connect, etc.
875                  */
876                 internal EndPoint seed_endpoint = null;
877
878 #if !TARGET_JVM
879                 // Creates a new system socket, returning the handle
880                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
881                 private extern IntPtr Socket_internal(AddressFamily family,
882                                                       SocketType type,
883                                                       ProtocolType proto,
884                                                       out int error);
885 #endif          
886                 
887                 public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
888                 {
889 #if NET_2_1 && !MOBILE
890                         switch (addressFamily) {
891                         case AddressFamily.InterNetwork:        // ok
892                         case AddressFamily.InterNetworkV6:      // ok
893                         case AddressFamily.Unknown:             // SocketException will be thrown later (with right error #)
894                                 break;
895                         // case AddressFamily.Unspecified:
896                         default:
897                                 throw new ArgumentException ("addressFamily");
898                         }
899
900                         switch (socketType) {
901                         case SocketType.Stream:                 // ok
902                         case SocketType.Unknown:                // SocketException will be thrown later (with right error #)
903                                 break;
904                         default:
905                                 throw new ArgumentException ("socketType");
906                         }
907
908                         switch (protocolType) {
909                         case ProtocolType.Tcp:                  // ok
910                         case ProtocolType.Unspecified:          // ok
911                         case ProtocolType.Unknown:              // SocketException will be thrown later (with right error #)
912                                 break;
913                         default:
914                                 throw new ArgumentException ("protocolType");
915                         }
916 #endif
917                         address_family = addressFamily;
918                         socket_type = socketType;
919                         protocol_type = protocolType;
920                         
921                         int error;
922                         
923                         socket = Socket_internal (addressFamily, socketType, protocolType, out error);
924                         if (error != 0)
925                                 throw new SocketException (error);
926 #if !NET_2_1 || MOBILE
927                         SocketDefaults ();
928 #endif
929                 }
930
931                 ~Socket ()
932                 {
933                         Dispose (false);
934                 }
935
936
937                 public AddressFamily AddressFamily {
938                         get { return address_family; }
939                 }
940
941 #if !TARGET_JVM
942                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
943                 private extern static void Blocking_internal(IntPtr socket,
944                                                              bool block,
945                                                              out int error);
946 #endif
947
948                 public bool Blocking {
949                         get {
950                                 return(blocking);
951                         }
952                         set {
953                                 if (disposed && closed)
954                                         throw new ObjectDisposedException (GetType ().ToString ());
955
956                                 int error;
957                                 
958                                 Blocking_internal (socket, value, out error);
959
960                                 if (error != 0)
961                                         throw new SocketException (error);
962                                 
963                                 blocking=value;
964                         }
965                 }
966
967                 public bool Connected {
968                         get { return connected; }
969                         internal set { connected = value; }
970                 }
971
972                 public ProtocolType ProtocolType {
973                         get { return protocol_type; }
974                 }
975
976                 public bool NoDelay {
977                         get {
978                                 if (disposed && closed)
979                                         throw new ObjectDisposedException (GetType ().ToString ());
980
981                                 ThrowIfUpd ();
982
983                                 return (int)(GetSocketOption (
984                                         SocketOptionLevel.Tcp,
985                                         SocketOptionName.NoDelay)) != 0;
986                         }
987
988                         set {
989                                 if (disposed && closed)
990                                         throw new ObjectDisposedException (GetType ().ToString ());
991
992                                 ThrowIfUpd ();
993
994                                 SetSocketOption (
995                                         SocketOptionLevel.Tcp,
996                                         SocketOptionName.NoDelay, value ? 1 : 0);
997                         }
998                 }
999
1000                 public int ReceiveBufferSize {
1001                         get {
1002                                 if (disposed && closed) {
1003                                         throw new ObjectDisposedException (GetType ().ToString ());
1004                                 }
1005                                 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer));
1006                         }
1007                         set {
1008                                 if (disposed && closed) {
1009                                         throw new ObjectDisposedException (GetType ().ToString ());
1010                                 }
1011                                 if (value < 0) {
1012                                         throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
1013                                 }
1014                                 
1015                                 SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
1016                         }
1017                 }
1018
1019                 public int SendBufferSize {
1020                         get {
1021                                 if (disposed && closed) {
1022                                         throw new ObjectDisposedException (GetType ().ToString ());
1023                                 }
1024                                 return((int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendBuffer));
1025                         }
1026                         set {
1027                                 if (disposed && closed) {
1028                                         throw new ObjectDisposedException (GetType ().ToString ());
1029                                 }
1030                                 if (value < 0) {
1031                                         throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
1032                                 }
1033                                 
1034                                 SetSocketOption (SocketOptionLevel.Socket,
1035                                                  SocketOptionName.SendBuffer,
1036                                                  value);
1037                         }
1038                 }
1039
1040                 public short Ttl {
1041                         get {
1042                                 if (disposed && closed) {
1043                                         throw new ObjectDisposedException (GetType ().ToString ());
1044                                 }
1045                                 
1046                                 short ttl_val;
1047                                 
1048                                 if (address_family == AddressFamily.InterNetwork) {
1049                                         ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive));
1050                                 } else if (address_family == AddressFamily.InterNetworkV6) {
1051                                         ttl_val = (short)((int)GetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit));
1052                                 } else {
1053                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
1054                                 }
1055                                 
1056                                 return(ttl_val);
1057                         }
1058                         set {
1059                                 if (disposed && closed) {
1060                                         throw new ObjectDisposedException (GetType ().ToString ());
1061                                 }
1062                                 if (value < 0) {
1063                                         throw new ArgumentOutOfRangeException ("value", "The value specified for a set operation is less than zero");
1064                                 }
1065                                 
1066                                 if (address_family == AddressFamily.InterNetwork) {
1067                                         SetSocketOption (SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
1068                                 } else if (address_family == AddressFamily.InterNetworkV6) {
1069                                         SetSocketOption (SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
1070                                 } else {
1071                                         throw new NotSupportedException ("This property is only valid for InterNetwork and InterNetworkV6 sockets");
1072                                 }
1073                         }
1074                 }
1075
1076                 // Returns the remote endpoint details in addr and port
1077                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1078                 private extern static SocketAddress RemoteEndPoint_internal(IntPtr socket, int family, out int error);
1079
1080                 public EndPoint RemoteEndPoint {
1081                         get {
1082                                 if (disposed && closed)
1083                                         throw new ObjectDisposedException (GetType ().ToString ());
1084                                 
1085 #if MOONLIGHT
1086                                 if (!connected)
1087                                         return seed_endpoint;
1088 #else
1089                                 /*
1090                                  * If the seed EndPoint is null, Connect, Bind,
1091                                  * etc has not yet been called. MS returns null
1092                                  * in this case.
1093                                  */
1094                                 if (!connected || seed_endpoint == null)
1095                                         return null;
1096 #endif                  
1097                                 SocketAddress sa;
1098                                 int error;
1099                                 
1100                                 sa=RemoteEndPoint_internal(socket, (int) address_family, out error);
1101
1102                                 if (error != 0)
1103                                         throw new SocketException (error);
1104
1105                                 return seed_endpoint.Create (sa);
1106                         }
1107                 }
1108
1109                 void Linger (IntPtr handle)
1110                 {
1111                         if (!connected || linger_timeout <= 0)
1112                                 return;
1113
1114                         // We don't want to receive any more data
1115                         int error;
1116                         Shutdown_internal (handle, SocketShutdown.Receive, out error);
1117                         if (error != 0)
1118                                 return;
1119
1120                         int seconds = linger_timeout / 1000;
1121                         int ms = linger_timeout % 1000;
1122                         if (ms > 0) {
1123                                 // If the other end closes, this will return 'true' with 'Available' == 0
1124                                 Poll_internal (handle, SelectMode.SelectRead, ms * 1000, out error);
1125                                 if (error != 0)
1126                                         return;
1127
1128                         }
1129                         if (seconds > 0) {
1130                                 LingerOption linger = new LingerOption (true, seconds);
1131                                 SetSocketOption_internal (handle, SocketOptionLevel.Socket, SocketOptionName.Linger, linger, null, 0, out error);
1132                                 /* Not needed, we're closing upon return */
1133                                 /*if (error != 0)
1134                                         return; */
1135                         }
1136                 }
1137
1138                 protected virtual void Dispose (bool disposing)
1139                 {
1140                         if (disposed)
1141                                 return;
1142
1143                         disposed = true;
1144                         bool was_connected = connected;
1145                         connected = false;
1146                         if ((int) socket != -1) {
1147                                 int error;
1148                                 closed = true;
1149                                 IntPtr x = socket;
1150                                 socket = (IntPtr) (-1);
1151                                 Thread th = blocking_thread;
1152                                 if (th != null) {
1153                                         th.Abort ();
1154                                         blocking_thread = null;
1155                                 }
1156
1157                                 if (was_connected)
1158                                         Linger (x);
1159                                 //DateTime start = DateTime.UtcNow;
1160                                 Close_internal (x, out error);
1161                                 //Console.WriteLine ("Time spent in Close_internal: {0}ms", (DateTime.UtcNow - start).TotalMilliseconds);
1162                                 if (error != 0)
1163                                         throw new SocketException (error);
1164                         }
1165                 }
1166
1167 #if NET_2_1 || NET_4_0
1168                 public void Dispose ()
1169 #else
1170                 void IDisposable.Dispose ()
1171 #endif
1172                 {
1173                         Dispose (true);
1174                         GC.SuppressFinalize (this);
1175                 }
1176
1177                 // Closes the socket
1178                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1179                 private extern static void Close_internal(IntPtr socket, out int error);
1180
1181                 public void Close ()
1182                 {
1183                         linger_timeout = 0;
1184                         ((IDisposable) this).Dispose ();
1185                 }
1186
1187                 public void Close (int timeout) 
1188                 {
1189                         linger_timeout = timeout;
1190                         ((IDisposable) this).Dispose ();
1191                 }
1192
1193                 // Connects to the remote address
1194                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1195                 private extern static void Connect_internal(IntPtr sock,
1196                                                             SocketAddress sa,
1197                                                             out int error);
1198
1199                 public void Connect (EndPoint remoteEP)
1200                 {
1201                         SocketAddress serial = null;
1202
1203                         if (disposed && closed)
1204                                 throw new ObjectDisposedException (GetType ().ToString ());
1205
1206                         if (remoteEP == null)
1207                                 throw new ArgumentNullException ("remoteEP");
1208
1209                         IPEndPoint ep = remoteEP as IPEndPoint;
1210 #if !MOONLIGHT
1211                         if (ep != null && socket_type != SocketType.Dgram) /* Dgram uses Any to 'disconnect' */
1212 #else
1213                         if (ep != null)
1214 #endif
1215                                 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any))
1216                                         throw new SocketException ((int) SocketError.AddressNotAvailable);
1217
1218 #if MOONLIGHT
1219                         if (protocol_type != ProtocolType.Tcp)
1220                                 throw new SocketException ((int) SocketError.AccessDenied);
1221 #else
1222                         if (islistening)
1223                                 throw new InvalidOperationException ();
1224 #endif
1225                         serial = remoteEP.Serialize ();
1226
1227                         int error = 0;
1228
1229                         blocking_thread = Thread.CurrentThread;
1230                         try {
1231                                 Connect_internal (socket, serial, out error);
1232                         } catch (ThreadAbortException) {
1233                                 if (disposed) {
1234                                         Thread.ResetAbort ();
1235                                         error = (int) SocketError.Interrupted;
1236                                 }
1237                         } finally {
1238                                 blocking_thread = null;
1239                         }
1240
1241                         if (error == 0 || error == 10035)
1242                                 seed_endpoint = remoteEP; // Keep the ep around for non-blocking sockets
1243
1244                         if (error != 0)
1245                                 throw new SocketException (error);
1246
1247 #if !MOONLIGHT
1248                         if (socket_type == SocketType.Dgram && (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)))
1249                                 connected = false;
1250                         else
1251                                 connected = true;
1252 #else
1253                         connected = true;
1254 #endif
1255                         isbound = true;
1256                 }
1257
1258                 public bool ReceiveAsync (SocketAsyncEventArgs e)
1259                 {
1260                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1261                         if (disposed && closed)
1262                                 throw new ObjectDisposedException (GetType ().ToString ());
1263
1264                         // LAME SPEC: the ArgumentException is never thrown, instead an NRE is
1265                         // thrown when e.Buffer and e.BufferList are null (works fine when one is
1266                         // set to a valid object)
1267                         if (e.Buffer == null && e.BufferList == null)
1268                                 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1269
1270                         e.curSocket = this;
1271                         SocketOperation op = (e.Buffer != null) ? SocketOperation.Receive : SocketOperation.ReceiveGeneric;
1272                         e.Worker.Init (this, e, op);
1273                         SocketAsyncResult res = e.Worker.result;
1274                         if (e.Buffer != null) {
1275                                 res.Buffer = e.Buffer;
1276                                 res.Offset = e.Offset;
1277                                 res.Size = e.Count;
1278                         } else {
1279                                 res.Buffers = e.BufferList;
1280                         }
1281                         res.SockFlags = e.SocketFlags;
1282                         int count;
1283                         lock (readQ) {
1284                                 readQ.Enqueue (e.Worker);
1285                                 count = readQ.Count;
1286                         }
1287                         if (count == 1) {
1288                                 // Receive takes care of ReceiveGeneric
1289                                 socket_pool_queue (Worker.Dispatcher, res);
1290                         }
1291
1292                         return true;
1293                 }
1294
1295                 public bool SendAsync (SocketAsyncEventArgs e)
1296                 {
1297                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1298                         if (disposed && closed)
1299                                 throw new ObjectDisposedException (GetType ().ToString ());
1300                         if (e.Buffer == null && e.BufferList == null)
1301                                 throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers.");
1302
1303                         e.curSocket = this;
1304                         SocketOperation op = (e.Buffer != null) ? SocketOperation.Send : SocketOperation.SendGeneric;
1305                         e.Worker.Init (this, e, op);
1306                         SocketAsyncResult res = e.Worker.result;
1307                         if (e.Buffer != null) {
1308                                 res.Buffer = e.Buffer;
1309                                 res.Offset = e.Offset;
1310                                 res.Size = e.Count;
1311                         } else {
1312                                 res.Buffers = e.BufferList;
1313                         }
1314                         res.SockFlags = e.SocketFlags;
1315                         int count;
1316                         lock (writeQ) {
1317                                 writeQ.Enqueue (e.Worker);
1318                                 count = writeQ.Count;
1319                         }
1320                         if (count == 1) {
1321                                 // Send takes care of SendGeneric
1322                                 socket_pool_queue (Worker.Dispatcher, res);
1323                         }
1324                         return true;
1325                 }
1326
1327                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1328                 extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
1329
1330                 /* This overload is needed as the async Connect method
1331                  * also needs to check the socket error status, but
1332                  * getsockopt(..., SO_ERROR) clears the error.
1333                  */
1334                 internal bool Poll (int time_us, SelectMode mode, out int socket_error)
1335                 {
1336                         if (disposed && closed)
1337                                 throw new ObjectDisposedException (GetType ().ToString ());
1338
1339                         if (mode != SelectMode.SelectRead &&
1340                             mode != SelectMode.SelectWrite &&
1341                             mode != SelectMode.SelectError)
1342                                 throw new NotSupportedException ("'mode' parameter is not valid.");
1343
1344                         int error;
1345                         bool result = Poll_internal (socket, mode, time_us, out error);
1346                         if (error != 0)
1347                                 throw new SocketException (error);
1348
1349                         socket_error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
1350                         
1351                         if (mode == SelectMode.SelectWrite && result) {
1352                                 /* Update the connected state; for
1353                                  * non-blocking Connect()s this is
1354                                  * when we can find out that the
1355                                  * connect succeeded.
1356                                  */
1357                                 if (socket_error == 0) {
1358                                         connected = true;
1359                                         isbound = true;
1360                                 }
1361                         }
1362                         
1363                         return result;
1364                 }
1365
1366                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1367                 private extern static int Receive_internal(IntPtr sock,
1368                                                            byte[] buffer,
1369                                                            int offset,
1370                                                            int count,
1371                                                            SocketFlags flags,
1372                                                            out int error);
1373
1374                 internal int Receive_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
1375                 {
1376                         int nativeError;
1377                         int ret = Receive_internal (socket, buf, offset, size, flags, out nativeError);
1378                         error = (SocketError) nativeError;
1379                         if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
1380                                 connected = false;
1381                                 isbound = false;
1382                         } else {
1383                                 connected = true;
1384                         }
1385                         
1386                         return ret;
1387                 }
1388
1389                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1390                 private extern static void GetSocketOption_obj_internal(IntPtr socket,
1391                         SocketOptionLevel level, SocketOptionName name, out object obj_val,
1392                         out int error);
1393
1394                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1395                 private extern static int Send_internal(IntPtr sock,
1396                                                         byte[] buf, int offset,
1397                                                         int count,
1398                                                         SocketFlags flags,
1399                                                         out int error);
1400
1401                 internal int Send_nochecks (byte [] buf, int offset, int size, SocketFlags flags, out SocketError error)
1402                 {
1403                         if (size == 0) {
1404                                 error = SocketError.Success;
1405                                 return 0;
1406                         }
1407
1408                         int nativeError;
1409
1410                         int ret = Send_internal (socket, buf, offset, size, flags, out nativeError);
1411
1412                         error = (SocketError)nativeError;
1413
1414                         if (error != SocketError.Success && error != SocketError.WouldBlock && error != SocketError.InProgress) {
1415                                 connected = false;
1416                                 isbound = false;
1417                         } else {
1418                                 connected = true;
1419                         }
1420
1421                         return ret;
1422                 }
1423
1424                 public object GetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName)
1425                 {
1426                         if (disposed && closed)
1427                                 throw new ObjectDisposedException (GetType ().ToString ());
1428
1429                         object obj_val;
1430                         int error;
1431
1432                         GetSocketOption_obj_internal (socket, optionLevel, optionName, out obj_val,
1433                                 out error);
1434                         if (error != 0)
1435                                 throw new SocketException (error);
1436
1437                         if (optionName == SocketOptionName.Linger) {
1438                                 return((LingerOption)obj_val);
1439                         } else if (optionName == SocketOptionName.AddMembership ||
1440                                    optionName == SocketOptionName.DropMembership) {
1441                                 return((MulticastOption)obj_val);
1442                         } else if (obj_val is int) {
1443                                 return((int)obj_val);
1444                         } else {
1445                                 return(obj_val);
1446                         }
1447                 }
1448
1449                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1450                 private extern static void Shutdown_internal (IntPtr socket, SocketShutdown how, out int error);
1451                 
1452                 public void Shutdown (SocketShutdown how)
1453                 {
1454                         if (disposed && closed)
1455                                 throw new ObjectDisposedException (GetType ().ToString ());
1456
1457                         if (!connected)
1458                                 throw new SocketException (10057); // Not connected
1459
1460                         int error;
1461                         
1462                         Shutdown_internal (socket, how, out error);
1463                         if (error != 0)
1464                                 throw new SocketException (error);
1465                 }
1466
1467                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1468                 private extern static void SetSocketOption_internal (IntPtr socket, SocketOptionLevel level,
1469                                                                      SocketOptionName name, object obj_val,
1470                                                                      byte [] byte_val, int int_val,
1471                                                                      out int error);
1472
1473                 public void SetSocketOption (SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
1474                 {
1475                         if (disposed && closed)
1476                                 throw new ObjectDisposedException (GetType ().ToString ());
1477
1478                         int error;
1479
1480                         SetSocketOption_internal (socket, optionLevel, optionName, null,
1481                                                  null, optionValue, out error);
1482
1483                         if (error != 0)
1484                                 throw new SocketException (error);
1485                 }
1486
1487                 private void ThrowIfUpd ()
1488                 {
1489 #if !NET_2_1 || MOBILE
1490                         if (protocol_type == ProtocolType.Udp)
1491                                 throw new SocketException ((int)SocketError.ProtocolOption);
1492 #endif
1493                 }
1494
1495 #if !MOONLIGHT
1496                 public
1497 #endif
1498                 IAsyncResult BeginConnect(EndPoint end_point, AsyncCallback callback, object state)
1499                 {
1500                         if (disposed && closed)
1501                                 throw new ObjectDisposedException (GetType ().ToString ());
1502
1503                         if (end_point == null)
1504                                 throw new ArgumentNullException ("end_point");
1505
1506                         SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Connect);
1507                         req.EndPoint = end_point;
1508
1509                         // Bug #75154: Connect() should not succeed for .Any addresses.
1510                         if (end_point is IPEndPoint) {
1511                                 IPEndPoint ep = (IPEndPoint) end_point;
1512                                 if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
1513                                         req.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
1514                                         return req;
1515                                 }
1516                         }
1517
1518                         int error = 0;
1519                         bool blk = blocking;
1520                         if (blk)
1521                                 Blocking = false;
1522                         SocketAddress serial = end_point.Serialize ();
1523                         Connect_internal (socket, serial, out error);
1524                         if (blk)
1525                                 Blocking = true;
1526                         if (error == 0) {
1527                                 // succeeded synch
1528                                 connected = true;
1529                                 req.Complete (true);
1530                                 return req;
1531                         }
1532
1533                         if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
1534                                 // error synch
1535                                 connected = false;
1536                                 req.Complete (new SocketException (error), true);
1537                                 return req;
1538                         }
1539
1540                         // continue asynch
1541                         connected = false;
1542                         socket_pool_queue (Worker.Dispatcher, req);
1543                         return req;
1544                 }
1545
1546 #if !MOONLIGHT
1547                 public
1548 #else
1549                 internal
1550 #endif
1551                 IAsyncResult BeginConnect (IPAddress[] addresses, int port, AsyncCallback callback, object state)
1552
1553                 {
1554                         if (disposed && closed)
1555                                 throw new ObjectDisposedException (GetType ().ToString ());
1556
1557                         if (addresses == null)
1558                                 throw new ArgumentNullException ("addresses");
1559
1560                         if (addresses.Length == 0)
1561                                 throw new ArgumentException ("Empty addresses list");
1562
1563                         if (this.AddressFamily != AddressFamily.InterNetwork &&
1564                                 this.AddressFamily != AddressFamily.InterNetworkV6)
1565                                 throw new NotSupportedException ("This method is only valid for addresses in the InterNetwork or InterNetworkV6 families");
1566
1567                         if (port <= 0 || port > 65535)
1568                                 throw new ArgumentOutOfRangeException ("port", "Must be > 0 and < 65536");
1569 #if !MOONLIGHT
1570                         if (islistening)
1571                                 throw new InvalidOperationException ();
1572 #endif
1573
1574                         SocketAsyncResult req = new SocketAsyncResult (this, state, callback, SocketOperation.Connect);
1575                         req.Addresses = addresses;
1576                         req.Port = port;
1577                         connected = false;
1578                         return BeginMConnect (req);
1579                 }
1580
1581                 IAsyncResult BeginMConnect (SocketAsyncResult req)
1582                 {
1583                         IAsyncResult ares = null;
1584                         Exception exc = null;
1585                         for (int i = req.CurrentAddress; i < req.Addresses.Length; i++) {
1586                                 IPAddress addr = req.Addresses [i];
1587                                 IPEndPoint ep = new IPEndPoint (addr, req.Port);
1588                                 try {
1589                                         req.CurrentAddress++;
1590                                         ares = BeginConnect (ep, null, req);
1591                                         if (ares.IsCompleted && ares.CompletedSynchronously) {
1592                                                 ((SocketAsyncResult) ares).CheckIfThrowDelayedException ();
1593                                                 req.DoMConnectCallback ();
1594                                         }
1595                                         break;
1596                                 } catch (Exception e) {
1597                                         exc = e;
1598                                 }
1599                         }
1600
1601                         if (ares == null)
1602                                 throw exc;
1603
1604                         return req;
1605                 }
1606
1607                 // Returns false when it is ok to use RemoteEndPoint
1608                 //         true when addresses must be used (and addresses could be null/empty)
1609                 bool GetCheckedIPs (SocketAsyncEventArgs e, out IPAddress [] addresses)
1610                 {
1611                         addresses = null;
1612 #if MOONLIGHT || NET_4_0
1613                         // Connect to the first address that match the host name, like:
1614                         // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
1615                         // while skipping entries that do not match the address family
1616                         DnsEndPoint dep = (RemoteEndPoint as DnsEndPoint);
1617                         if (dep != null) {
1618                                 addresses = Dns.GetHostAddresses (dep.Host);
1619                                 IPEndPoint endpoint;
1620 #if MOONLIGHT && !INSIDE_SYSTEM
1621                                 if (!e.PolicyRestricted && !SecurityManager.HasElevatedPermissions) {
1622                                         List<IPAddress> valid = new List<IPAddress> ();
1623                                         foreach (IPAddress a in addresses) {
1624                                                 // if we're not downloading a socket policy then check the policy
1625                                                 // and if we're not running with elevated permissions (SL4 OoB option)
1626                                                 endpoint = new IPEndPoint (a, dep.Port);
1627                                                 if (!CrossDomainPolicyManager.CheckEndPoint (endpoint, e.SocketClientAccessPolicyProtocol))
1628                                                         continue;
1629                                                 valid.Add (a);
1630                                         }
1631                                         addresses = valid.ToArray ();
1632                                 }
1633 #endif
1634                                 return true;
1635                         } else {
1636                                 e.ConnectByNameError = null;
1637 #if MOONLIGHT && !INSIDE_SYSTEM
1638                                 if (!e.PolicyRestricted && !SecurityManager.HasElevatedPermissions) {
1639                                         if (CrossDomainPolicyManager.CheckEndPoint (RemoteEndPoint, e.SocketClientAccessPolicyProtocol))
1640                                                 return false;
1641                                 } else
1642 #endif
1643                                         return false;
1644                         }
1645                         return true; // do not use remote endpoint
1646 #else
1647                         return false; // < NET_4_0 -> use remote endpoint
1648 #endif
1649                 }
1650
1651                 bool ConnectAsyncReal (SocketAsyncEventArgs e)
1652                 {
1653                         IPAddress [] addresses = null;
1654                         bool use_remoteep = true;
1655 #if MOONLIGHT || NET_4_0
1656                         use_remoteep = !GetCheckedIPs (e, out addresses);
1657 #endif
1658                         e.curSocket = this;
1659                         Worker w = e.Worker;
1660                         w.Init (this, e, SocketOperation.Connect);
1661                         SocketAsyncResult result = w.result;
1662                         IAsyncResult ares = null;
1663                         try {
1664                                 if (use_remoteep) {
1665                                         result.EndPoint = e.RemoteEndPoint;
1666                                         ares = BeginConnect (e.RemoteEndPoint, SocketAsyncEventArgs.Dispatcher, e);
1667                                 }
1668 #if MOONLIGHT || NET_4_0
1669                                 else {
1670
1671                                         DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
1672                                         result.Addresses = addresses;
1673                                         result.Port = dep.Port;
1674
1675                                         ares = BeginConnect (addresses, dep.Port, SocketAsyncEventArgs.Dispatcher, e);
1676                                 }
1677 #endif
1678                                 if (ares.IsCompleted && ares.CompletedSynchronously) {
1679                                         ((SocketAsyncResult) ares).CheckIfThrowDelayedException ();
1680                                         return false;
1681                                 }
1682                         } catch (Exception exc) {
1683                                 result.Complete (exc, true);
1684                                 return false;
1685                         }
1686                         return true;
1687                 }
1688
1689 #if !MOONLIGHT
1690                 public bool ConnectAsync (SocketAsyncEventArgs e)
1691                 {
1692                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1693                         if (disposed && closed)
1694                                 throw new ObjectDisposedException (GetType ().ToString ());
1695                         if (islistening)
1696                                 throw new InvalidOperationException ("You may not perform this operation after calling the Listen method.");
1697                         if (e.RemoteEndPoint == null)
1698                                 throw new ArgumentNullException ("remoteEP");
1699
1700                         return ConnectAsyncReal (e);
1701                 }
1702 #endif
1703 #if MOONLIGHT
1704                 static void CheckConnect (SocketAsyncEventArgs e)
1705                 {
1706                         // NO check is made whether e != null in MS.NET (NRE is thrown in such case)
1707
1708                         if (e.RemoteEndPoint == null)
1709                                 throw new ArgumentNullException ("remoteEP");
1710                         if (e.BufferList != null)
1711                                 throw new ArgumentException ("Multiple buffers cannot be used with this method.");
1712                 }
1713
1714                 public bool ConnectAsync (SocketAsyncEventArgs e)
1715                 {
1716                         if (disposed && closed)
1717                                 throw new ObjectDisposedException (GetType ().ToString ());
1718
1719                         CheckConnect (e);
1720                         // if an address family is specified then they must match
1721                         AddressFamily raf = e.RemoteEndPoint.AddressFamily;
1722                         if ((raf != AddressFamily.Unspecified) && (raf != AddressFamily))
1723                                 throw new NotSupportedException ("AddressFamily mismatch between socket and endpoint");
1724
1725                         return ConnectAsyncReal (e);
1726                 }
1727
1728                 public static bool ConnectAsync (SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)
1729                 {
1730                         // exception ordering requires to check before creating the socket (good thing resource wise too)
1731                         CheckConnect (e);
1732
1733                         // create socket based on the endpoint address family (if specified), otherwise default fo IPv4
1734                         AddressFamily raf = e.RemoteEndPoint.AddressFamily;
1735                         if (raf == AddressFamily.Unspecified)
1736                                 raf = AddressFamily.InterNetwork;
1737                         Socket s = new Socket (raf, socketType, protocolType);
1738                         return s.ConnectAsyncReal (e);
1739                 }
1740
1741                 public static void CancelConnectAsync (SocketAsyncEventArgs e)
1742                 {
1743                         if (e == null)
1744                                 throw new ArgumentNullException ("e");
1745
1746                         // FIXME: this is canceling a synchronous connect, not an async one
1747                         Socket s = e.ConnectSocket;
1748                         if ((s != null) && (s.blocking_thread != null))
1749                                 s.blocking_thread.Abort ();
1750                 }
1751 #endif
1752                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1753                 private extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
1754 #if !MOONLIGHT
1755                 public
1756 #else
1757                 internal
1758 #endif
1759                 int Receive (IList<ArraySegment<byte>> buffers)
1760                 {
1761                         int ret;
1762                         SocketError error;
1763                         ret = Receive (buffers, SocketFlags.None, out error);
1764                         if (error != SocketError.Success) {
1765                                 throw new SocketException ((int)error);
1766                         }
1767                         return(ret);
1768                 }
1769
1770                 [CLSCompliant (false)]
1771 #if !MOONLIGHT
1772                 public
1773 #else
1774                 internal
1775 #endif
1776                 int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1777                 {
1778                         int ret;
1779                         SocketError error;
1780                         ret = Receive (buffers, socketFlags, out error);
1781                         if (error != SocketError.Success) {
1782                                 throw new SocketException ((int)error);
1783                         }
1784                         return(ret);
1785                 }
1786
1787                 [CLSCompliant (false)]
1788 #if !MOONLIGHT
1789                 public
1790 #else
1791                 internal
1792 #endif
1793                 int Receive (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1794                 {
1795                         if (disposed && closed)
1796                                 throw new ObjectDisposedException (GetType ().ToString ());
1797
1798                         if (buffers == null ||
1799                             buffers.Count == 0) {
1800                                 throw new ArgumentNullException ("buffers");
1801                         }
1802
1803                         int numsegments = buffers.Count;
1804                         int nativeError;
1805                         int ret;
1806
1807                         /* Only example I can find of sending a byte
1808                          * array reference directly into an internal
1809                          * call is in
1810                          * System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
1811                          * so taking a lead from that...
1812                          */
1813                         WSABUF[] bufarray = new WSABUF[numsegments];
1814                         GCHandle[] gch = new GCHandle[numsegments];
1815
1816                         for(int i = 0; i < numsegments; i++) {
1817                                 ArraySegment<byte> segment = buffers[i];
1818                                 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1819                                 bufarray[i].len = segment.Count;
1820                                 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1821                         }
1822
1823                         try {
1824                                 ret = Receive_internal (socket, bufarray,
1825                                                         socketFlags,
1826                                                         out nativeError);
1827                         } finally {
1828                                 for(int i = 0; i < numsegments; i++) {
1829                                         if (gch[i].IsAllocated) {
1830                                                 gch[i].Free ();
1831                                         }
1832                                 }
1833                         }
1834
1835                         errorCode = (SocketError)nativeError;
1836                         return(ret);
1837                 }
1838
1839                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
1840                 private extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error);
1841 #if !MOONLIGHT
1842                 public
1843 #else
1844                 internal
1845 #endif
1846                 int Send (IList<ArraySegment<byte>> buffers)
1847                 {
1848                         int ret;
1849                         SocketError error;
1850                         ret = Send (buffers, SocketFlags.None, out error);
1851                         if (error != SocketError.Success) {
1852                                 throw new SocketException ((int)error);
1853                         }
1854                         return(ret);
1855                 }
1856
1857 #if !MOONLIGHT
1858                 public
1859 #else
1860                 internal
1861 #endif
1862                 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
1863                 {
1864                         int ret;
1865                         SocketError error;
1866                         ret = Send (buffers, socketFlags, out error);
1867                         if (error != SocketError.Success) {
1868                                 throw new SocketException ((int)error);
1869                         }
1870                         return(ret);
1871                 }
1872
1873                 [CLSCompliant (false)]
1874 #if !MOONLIGHT
1875                 public
1876 #else
1877                 internal
1878 #endif
1879                 int Send (IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode)
1880                 {
1881                         if (disposed && closed)
1882                                 throw new ObjectDisposedException (GetType ().ToString ());
1883                         if (buffers == null)
1884                                 throw new ArgumentNullException ("buffers");
1885                         if (buffers.Count == 0)
1886                                 throw new ArgumentException ("Buffer is empty", "buffers");
1887                         int numsegments = buffers.Count;
1888                         int nativeError;
1889                         int ret;
1890
1891                         WSABUF[] bufarray = new WSABUF[numsegments];
1892                         GCHandle[] gch = new GCHandle[numsegments];
1893                         for(int i = 0; i < numsegments; i++) {
1894                                 ArraySegment<byte> segment = buffers[i];
1895                                 gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
1896                                 bufarray[i].len = segment.Count;
1897                                 bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
1898                         }
1899
1900                         try {
1901                                 ret = Send_internal (socket, bufarray, socketFlags, out nativeError);
1902                         } finally {
1903                                 for(int i = 0; i < numsegments; i++) {
1904                                         if (gch[i].IsAllocated) {
1905                                                 gch[i].Free ();
1906                                         }
1907                                 }
1908                         }
1909                         errorCode = (SocketError)nativeError;
1910                         return(ret);
1911                 }
1912
1913                 Exception InvalidAsyncOp (string method)
1914                 {
1915                         return new InvalidOperationException (method + " can only be called once per asynchronous operation");
1916                 }
1917
1918 #if !MOONLIGHT
1919                 public
1920 #else
1921                 internal
1922 #endif
1923                 int EndReceive (IAsyncResult result)
1924                 {
1925                         SocketError error;
1926                         int bytesReceived = EndReceive (result, out error);
1927                         if (error != SocketError.Success) {
1928                                 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
1929                                         connected = false;
1930                                 throw new SocketException ((int)error);
1931                         }
1932                         return bytesReceived;
1933                 }
1934
1935 #if !MOONLIGHT
1936                 public
1937 #else
1938                 internal
1939 #endif
1940                 int EndReceive (IAsyncResult asyncResult, out SocketError errorCode)
1941                 {
1942                         if (disposed && closed)
1943                                 throw new ObjectDisposedException (GetType ().ToString ());
1944
1945                         if (asyncResult == null)
1946                                 throw new ArgumentNullException ("asyncResult");
1947
1948                         SocketAsyncResult req = asyncResult as SocketAsyncResult;
1949                         if (req == null)
1950                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
1951
1952                         if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
1953                                 throw InvalidAsyncOp ("EndReceive");
1954                         if (!asyncResult.IsCompleted)
1955                                 asyncResult.AsyncWaitHandle.WaitOne ();
1956
1957                         errorCode = req.ErrorCode;
1958                         // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
1959                         // kinds of exceptions that should be thrown.
1960                         if (errorCode == SocketError.Success)
1961                                 req.CheckIfThrowDelayedException();
1962
1963                         return(req.Total);
1964                 }
1965
1966 #if !MOONLIGHT
1967                 public
1968 #else
1969                 internal
1970 #endif
1971                 int EndSend (IAsyncResult result)
1972                 {
1973                         SocketError error;
1974                         int bytesSent = EndSend (result, out error);
1975                         if (error != SocketError.Success) {
1976                                 if (error != SocketError.WouldBlock && error != SocketError.InProgress)
1977                                         connected = false;
1978                                 throw new SocketException ((int)error);
1979                         }
1980                         return bytesSent;
1981                 }
1982
1983 #if !MOONLIGHT
1984                 public
1985 #else
1986                 internal
1987 #endif
1988                 int EndSend (IAsyncResult asyncResult, out SocketError errorCode)
1989                 {
1990                         if (disposed && closed)
1991                                 throw new ObjectDisposedException (GetType ().ToString ());
1992                         if (asyncResult == null)
1993                                 throw new ArgumentNullException ("asyncResult");
1994
1995                         SocketAsyncResult req = asyncResult as SocketAsyncResult;
1996                         if (req == null)
1997                                 throw new ArgumentException ("Invalid IAsyncResult", "result");
1998
1999                         if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
2000                                 throw InvalidAsyncOp ("EndSend");
2001                         if (!asyncResult.IsCompleted)
2002                                 asyncResult.AsyncWaitHandle.WaitOne ();
2003
2004                         errorCode = req.ErrorCode;
2005                         // If no socket error occurred, call CheckIfThrowDelayedException in case there are other
2006                         // kinds of exceptions that should be thrown.
2007                         if (errorCode == SocketError.Success)
2008                                 req.CheckIfThrowDelayedException ();
2009
2010                         return(req.Total);
2011                 }
2012
2013                 // Used by Udpclient
2014 #if !MOONLIGHT
2015                 public
2016 #else
2017                 internal
2018 #endif
2019                 int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point)
2020                 {
2021                         if (disposed && closed)
2022                                 throw new ObjectDisposedException (GetType ().ToString ());
2023
2024                         if (result == null)
2025                                 throw new ArgumentNullException ("result");
2026
2027                         if (end_point == null)
2028                                 throw new ArgumentNullException ("remote_end");
2029
2030                         SocketAsyncResult req = result as SocketAsyncResult;
2031                         if (req == null)
2032                                 throw new ArgumentException ("Invalid IAsyncResult", "result");
2033
2034                         if (Interlocked.CompareExchange (ref req.EndCalled, 1, 0) == 1)
2035                                 throw InvalidAsyncOp ("EndReceiveFrom");
2036                         if (!result.IsCompleted)
2037                                 result.AsyncWaitHandle.WaitOne();
2038
2039                         req.CheckIfThrowDelayedException();
2040                         end_point = req.EndPoint;
2041                         return req.Total;
2042                 }
2043
2044                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2045                 static extern void socket_pool_queue (SocketAsyncCall d, SocketAsyncResult r);
2046         }
2047 }
2048