[socket] More BeginConnect (IPAddress []) work
authorGonzalo Paniagua Javier <gonzalo.mono@gmail.com>
Thu, 28 Apr 2011 04:01:10 +0000 (00:01 -0400)
committerGonzalo Paniagua Javier <gonzalo.mono@gmail.com>
Thu, 28 Apr 2011 04:03:37 +0000 (00:03 -0400)
When trying multiple addresses, the second and sucessive calls to
BeginConnect(IPAddress) will cause an error which we would have to
ignore and then retry. Since this behavior is not documented, we just
close the socket and open a new one for retries is there is already a
pending connect attempt.

mcs/class/System/System.Net.Sockets/Socket_2_1.cs

index b97a48976e9fb035440a931a683d88c0a8e4760b..69d4b57535322643a05ab51f2f2298136df7edb5 100644 (file)
@@ -588,6 +588,8 @@ namespace System.Net.Sockets {
                                                        result = mconnect;
                                                result.Sock.seed_endpoint = ep;
                                                result.Sock.connected = true;
+                                               result.Sock.isbound = true;
+                                               result.Sock.connect_in_progress = false;
                                                result.error = 0;
                                                result.Complete ();
                                                if (is_mconnect)
@@ -596,6 +598,7 @@ namespace System.Net.Sockets {
                                        }
 
                                        if (!is_mconnect) {
+                                               result.Sock.connect_in_progress = false;
                                                result.Complete (new SocketException (error_code));
                                                return;
                                        }
@@ -606,10 +609,9 @@ namespace System.Net.Sockets {
                                                        mconnect.DoMConnectCallback ();
                                                return;
                                        }
-#if !MOONLIGHT
                                        mconnect.Sock.BeginMConnect (mconnect);
-#endif
                                } catch (Exception e) {
+                                       result.Sock.connect_in_progress = false;
                                        if (is_mconnect)
                                                result = mconnect;
                                        result.Complete (e);
@@ -864,6 +866,7 @@ namespace System.Net.Sockets {
                /* true if we called Close_internal */
                private bool closed;
                internal bool disposed;
+               bool connect_in_progress;
 
                /*
                 * This EndPoint is used when creating new endpoints. Because
@@ -1326,42 +1329,6 @@ namespace System.Net.Sockets {
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                extern static bool Poll_internal (IntPtr socket, SelectMode mode, int timeout, out int error);
 
-               /* This overload is needed as the async Connect method
-                * also needs to check the socket error status, but
-                * getsockopt(..., SO_ERROR) clears the error.
-                */
-               internal bool Poll (int time_us, SelectMode mode, out int socket_error)
-               {
-                       if (disposed && closed)
-                               throw new ObjectDisposedException (GetType ().ToString ());
-
-                       if (mode != SelectMode.SelectRead &&
-                           mode != SelectMode.SelectWrite &&
-                           mode != SelectMode.SelectError)
-                               throw new NotSupportedException ("'mode' parameter is not valid.");
-
-                       int error;
-                       bool result = Poll_internal (socket, mode, time_us, out error);
-                       if (error != 0)
-                               throw new SocketException (error);
-
-                       socket_error = (int)GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
-                       
-                       if (mode == SelectMode.SelectWrite && result) {
-                               /* Update the connected state; for
-                                * non-blocking Connect()s this is
-                                * when we can find out that the
-                                * connect succeeded.
-                                */
-                               if (socket_error == 0) {
-                                       connected = true;
-                                       isbound = true;
-                               }
-                       }
-                       
-                       return result;
-               }
-
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern static int Receive_internal(IntPtr sock,
                                                           byte[] buffer,
@@ -1515,6 +1482,16 @@ namespace System.Net.Sockets {
                        }
 
                        int error = 0;
+                       if (connect_in_progress) {
+                               // This could happen when multiple IPs are used
+                               // Calling connect() again will reset the connection attempt and cause
+                               // an error. Better to just close the socket and move on.
+                               connect_in_progress = false;
+                               Close_internal (socket, out error);
+                               socket = Socket_internal (address_family, socket_type, protocol_type, out error);
+                               if (error != 0)
+                                       throw new SocketException (error);
+                       }
                        bool blk = blocking;
                        if (blk)
                                Blocking = false;
@@ -1525,6 +1502,7 @@ namespace System.Net.Sockets {
                        if (error == 0) {
                                // succeeded synch
                                connected = true;
+                               isbound = true;
                                req.Complete (true);
                                return req;
                        }
@@ -1532,12 +1510,15 @@ namespace System.Net.Sockets {
                        if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
                                // error synch
                                connected = false;
+                               isbound = false;
                                req.Complete (new SocketException (error), true);
                                return req;
                        }
 
                        // continue asynch
                        connected = false;
+                       isbound = false;
+                       connect_in_progress = true;
                        socket_pool_queue (Worker.Dispatcher, req);
                        return req;
                }