# 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#45017 | Davi Arnaut | 3 Aug |