List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:August 3 2009 8:43pm
Subject:bzr commit into mysql-pe branch (davi:3507) Bug#45017
View as plain text  
# At a local mysql-pe repository of davi

 3507 Davi Arnaut	2009-08-03
      Bug#45017: Failure to connect if hostname maps to multiple addresses
      
      The problem is that the C API function mysql_real_connect
      only attempts to connect to the first IP address returned
      for a hostname. This can be a problem if a hostname maps
      to multiple IP address and the server is not bound to the
      first one that is returned.
      
      The solution is to augment mysql_real_connect so that it
      attempts to connect to all IPv4/6 addresses that a domain
      name maps to. The function goes over the list of address
      until a successful connection is established.
      
      No test case is provided as its not possible to test this
      automatically with the current testing infrastructure.
     @ sql-common/client.c
        The client will try to connect to each address from the
        list of addresses that hostname maps to until a successful
        connection is established or there are no more address.

    modified:
      sql-common/client.c
=== modified file 'sql-common/client.c'
--- a/sql-common/client.c	2009-07-08 07:30:40 +0000
+++ b/sql-common/client.c	2009-08-03 20:43:21 +0000
@@ -2378,6 +2378,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
     struct addrinfo *res_lst, hints, *t_res;
     int gai_errno;
     char port_buf[NI_MAXSERV];
+    my_socket sock= SOCKET_ERROR;
+    int saved_error, status= -1;
 
     unix_socket=0;				/* This is not used */
 
@@ -2422,44 +2424,58 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
       goto error;
     }
 
-    /* We only look at the first item (something to think about changing in the future) */
-    t_res= res_lst; 
+    /*
+      A hostname might map to multiple addresses (either IPv4 or IPv6).
+      Go over the list of address until a successful connection is established
+    */
+    for (t_res= res_lst; t_res; t_res= t_res->ai_next)
     {
-      my_socket sock= socket(t_res->ai_family, t_res->ai_socktype,
-                             t_res->ai_protocol);
+      sock= socket(t_res->ai_family, t_res->ai_socktype, t_res->ai_protocol);
       if (sock == SOCKET_ERROR)
       {
-        set_mysql_extended_error(mysql, CR_IPSOCK_ERROR, unknown_sqlstate,
-                                 ER(CR_IPSOCK_ERROR), socket_errno);
-        freeaddrinfo(res_lst);
-        goto error;
+        saved_error= socket_errno;
+        continue;
       }
 
-      net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
-      if (! net->vio )
-      {
-        DBUG_PRINT("error",("Unknow protocol %d ", mysql->options.protocol));
-        set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
-        closesocket(sock);
-        freeaddrinfo(res_lst);
-        goto error;
-      }
+      status= my_connect(sock, t_res->ai_addr, t_res->ai_addrlen,
+                         mysql->options.connect_timeout);
+      if (!status)
+        break;
 
-      if (my_connect(sock, t_res->ai_addr, t_res->ai_addrlen,
-                     mysql->options.connect_timeout))
-      {
-        DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno,
-                            host));
-        set_mysql_extended_error(mysql, CR_CONN_HOST_ERROR, unknown_sqlstate,
-                                 ER(CR_CONN_HOST_ERROR), host, socket_errno);
-        vio_delete(net->vio);
-        net->vio= 0;
-        freeaddrinfo(res_lst);
-        goto error;
-      }
+      /*
+        Save errno value as socket errno might be overwritten due to
+        calling a socket function.
+      */
+      saved_error= socket_errno;
+
+      closesocket(sock);
     }
 
     freeaddrinfo(res_lst);
+
+    if (sock == SOCKET_ERROR)
+    {
+      set_mysql_extended_error(mysql, CR_IPSOCK_ERROR, unknown_sqlstate,
+                                ER(CR_IPSOCK_ERROR), saved_error);
+      goto error;
+    }
+
+    if (status)
+    {
+      DBUG_PRINT("error",("Got error %d on connect to '%s'", saved_error, host));
+      set_mysql_extended_error(mysql, CR_CONN_HOST_ERROR, unknown_sqlstate,
+                                ER(CR_CONN_HOST_ERROR), host, saved_error);
+      goto error;
+    }
+
+    net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
+    if (! net->vio )
+    {
+      DBUG_PRINT("error",("Unknow protocol %d ", mysql->options.protocol));
+      set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
+      closesocket(sock);
+      goto error;
+    }
   }
 
   if (!net->vio)


Attachment: [text/bzr-bundle] bzr/davi.arnaut@sun.com-20090803204321-mmjwo8ix7s7f70g7.bundle
Thread
bzr commit into mysql-pe branch (davi:3507) Bug#45017Davi Arnaut3 Aug