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