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