summaryrefslogtreecommitdiff
path: root/sql-common
diff options
context:
space:
mode:
authorAlexander Nozdrin <alik@sun.com>2009-11-25 13:53:23 +0300
committerAlexander Nozdrin <alik@sun.com>2009-11-25 13:53:23 +0300
commit7eb84da890698c3109795742c6f34d4580567b17 (patch)
treee44eeb900770af5a8a6c8712d985329fd1d7ba44 /sql-common
parent027a2fff1573550baae84ff97b962169a4961518 (diff)
downloadmariadb-git-7eb84da890698c3109795742c6f34d4580567b17.tar.gz
Backport of WL#798 (MySQL IPv6 support) from 6.0.
The following 6.0 revisions were analyzed: - sp1r-brian@zim.(none)-20071228102738-21894 - sp1r-brian@zim.(none)-20071228121841-56447 - sp1r-brian@zim.(none)-20071228205403-56423 - sp1r-brian@zim.(none)-20071228221139-55341 - sp1r-brian@zim.(none)-20071228233443-55352 - sp1r-brian@zim.(none)-20071229094527-61763 - sp1r-brian@zim.(none)-20071230203739-61746 - sp1r-brian@zim.(none)-20080102213805-61741 - sp1r-brian@zim.(none)-20080103201041-61746 - sp1r-brian@zim.(none)-20080104234927-59875 - sp1r-brian@zim.(none)-20080105005827-59874 - sp1r-brian@zim.(none)-20080105012020-59865 - sp1r-brian@zim.(none)-20080106003858-59857 - sp1r-brian@zim.(none)-20080123195552-31680 - sp1r-brian@zim.(none)-20080124201848-29999 - sp1r-brian@zim.(none)-20080129075144-36991 - sp1r-cbell/Chuck@mysql_cab_desk.-20080215041806-21954 - sp1r-vvaintroub@wva.-20080212124547-06272 - sp1r-dfischer/mysqldev@mysql.com/production.mysql.com-20071223184258-15140 - sp1r-brian@zim.(none)-20080206122216-35774 - sp1r-baker@bk-internal.mysql.com-20080209005622-35947 - sp1r-baker@bk-internal.mysql.com-20080224215608-24613 - sp1r-baker@bk-internal.mysql.com-20080307170710-63543 - sp1r-baker@bk-internal.mysql.com-20080312233205-13069 - sp1r-Reggie@core.-20080402175211-28643 - kpettersson@mysql.com-20080901101150-4ne74r8v0492vv42 - alik@sun.com-20090805173811-9fzt0ymcp9tsvn7k - alik@sun.com-20090805173937-fcv1fdveodq5x9gb - alik@sun.com-20090805175009-g1od16i3t1xkw2qr - kostja@sun.com-20090805200643-j9i4fy7ii8ijho5c - alik@sun.com-20090807195303-j4fb5m4l1dgdahwo - alik@sun.com-20090808114848-3rkzr9kifrijzaqy - alik@sun.com-20090810041739-ugmx34h34uid8mox - alik@sun.com-20090810105306-rf43rfyzzblsy5e7 - alik@sun.com-20090810123113-ccdjwai68b5woqdm - alik@sun.com-20090811080423-gb7pibec1znaydzy - alik@sun.com-20090811082130-5uckar1vx3kdsw7g - alik@sun.com-20090812202051-uqkfwwxxcjvo5ean The following bugfixes are also backported within this patch: - Bug#34292: netdb.h missing in hostname.cc - Bug#39153: Failing to lookup a host name can lead to crash in current IPv6 implementation - Bug#38247: Server does not resolve connecting ip's - Bug#43006: main.skip_name_resolve fails on Windows in PB2 - Bug#45606: ACL requires IPv4-mapped addresses to be used - Bug#45584: Host name cache does not work as a cache
Diffstat (limited to 'sql-common')
-rw-r--r--sql-common/client.c198
1 files changed, 121 insertions, 77 deletions
diff --git a/sql-common/client.c b/sql-common/client.c
index 5114b645818..1f9c00f93be 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -38,6 +38,10 @@
#include "mysql.h"
+#ifndef __WIN__
+#include <netdb.h>
+#endif
+
/* Remove client convenience wrappers */
#undef max_allowed_packet
#undef net_buffer_length
@@ -2227,9 +2231,6 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
{
char buff[NAME_LEN+USERNAME_LENGTH+100];
char *end,*host_info= NULL;
- my_socket sock;
- in_addr_t ip_addr;
- struct sockaddr_in sock_addr;
ulong pkt_length;
NET *net= &mysql->net;
#ifdef MYSQL_SERVER
@@ -2335,7 +2336,6 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
else
{
mysql->options.protocol=MYSQL_PROTOCOL_MEMORY;
- sock=0;
unix_socket = 0;
host=mysql->options.shared_memory_base_name;
my_snprintf(host_info=buff, sizeof(buff)-1,
@@ -2350,12 +2350,9 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
(unix_socket || mysql_unix_port) &&
(!host || !strcmp(host,LOCAL_HOST)))
{
- host=LOCAL_HOST;
- if (!unix_socket)
- unix_socket=mysql_unix_port;
- host_info=(char*) ER(CR_LOCALHOST_CONNECTION);
- DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket));
- if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR)
+ DBUG_PRINT("info", ("Using socket"));
+ my_socket sock= socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock == SOCKET_ERROR)
{
set_mysql_extended_error(mysql, CR_SOCKET_CREATE_ERROR,
unknown_sqlstate,
@@ -2363,12 +2360,28 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
socket_errno);
goto error;
}
+
net->vio= vio_new(sock, VIO_TYPE_SOCKET,
VIO_LOCALHOST | VIO_BUFFERED_READ);
- bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
- UNIXaddr.sun_family = AF_UNIX;
+ 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;
+ }
+
+ host= LOCAL_HOST;
+ if (!unix_socket)
+ unix_socket= mysql_unix_port;
+ host_info= (char*) ER(CR_LOCALHOST_CONNECTION);
+ DBUG_PRINT("info", ("Using UNIX sock '%s'", unix_socket));
+
+ bzero((char*) &UNIXaddr, sizeof(UNIXaddr));
+ UNIXaddr.sun_family= AF_UNIX;
strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path)-1);
- if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
+
+ if (my_connect(sock, (struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
mysql->options.connect_timeout))
{
DBUG_PRINT("error",("Got error %d on connect to local server",
@@ -2377,6 +2390,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
unknown_sqlstate,
ER(CR_CONNECTION_ERROR),
unix_socket, socket_errno);
+ vio_delete(net->vio);
+ net->vio= 0;
goto error;
}
mysql->options.protocol=MYSQL_PROTOCOL_SOCKET;
@@ -2387,7 +2402,6 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
(host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
(! have_tcpip && (unix_socket || !host && is_NT()))))
{
- sock=0;
if ((hPipe= create_named_pipe(mysql, mysql->options.connect_timeout,
(char**) &host, (char**) &unix_socket)) ==
INVALID_HANDLE_VALUE)
@@ -2417,94 +2431,124 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
(!mysql->options.protocol ||
mysql->options.protocol == MYSQL_PROTOCOL_TCP))
{
- int status= -1;
+ struct addrinfo *res_lst, hints, *t_res;
+ int gai_errno;
+ char port_buf[NI_MAXSERV];
+ my_socket sock= SOCKET_ERROR;
+ int UNINIT_VAR(saved_error), status= -1;
+
unix_socket=0; /* This is not used */
+
if (!port)
- port=mysql_port;
+ port= mysql_port;
+
if (!host)
- host=LOCAL_HOST;
- my_snprintf(host_info=buff,sizeof(buff)-1,ER(CR_TCP_CONNECTION),host);
- DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
+ host= LOCAL_HOST;
+
+ my_snprintf(host_info=buff, sizeof(buff)-1, ER(CR_TCP_CONNECTION), host);
+ DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host, port));
#ifdef MYSQL_SERVER
thr_alarm_init(&alarmed);
thr_alarm(&alarmed, mysql->options.connect_timeout, &alarm_buff);
#endif
- /* _WIN64 ; Assume that the (int) range is enough for socket() */
- sock = (my_socket) socket(AF_INET,SOCK_STREAM,0);
+
+ DBUG_PRINT("info",("IP '%s'", "client"));
+
#ifdef MYSQL_SERVER
thr_end_alarm(&alarmed);
#endif
- if (sock == SOCKET_ERROR)
- {
- set_mysql_extended_error(mysql, CR_IPSOCK_ERROR, unknown_sqlstate,
- ER(CR_IPSOCK_ERROR), socket_errno);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype= SOCK_STREAM;
+ hints.ai_protocol= IPPROTO_TCP;
+ hints.ai_family= AF_UNSPEC;
+
+ DBUG_PRINT("info",("IPV6 getaddrinfo %s", host));
+ my_snprintf(port_buf, NI_MAXSERV, "%d", port);
+ gai_errno= getaddrinfo(host, port_buf, &hints, &res_lst);
+
+ if (gai_errno != 0)
+ {
+ /*
+ For DBUG we are keeping the right message but for client we default to
+ historical error message.
+ */
+ DBUG_PRINT("info",("IPV6 getaddrinfo error %d", gai_errno));
+ set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
+ ER(CR_UNKNOWN_HOST), host, errno);
+
goto error;
}
- net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
- bzero((char*) &sock_addr,sizeof(sock_addr));
- sock_addr.sin_family = AF_INET;
- sock_addr.sin_port = (ushort) htons((ushort) port);
/*
- The server name may be a host name or IP address
+ A hostname might map to multiple IP addresses (IPv4/IPv6). Go over the
+ list of IP addresses until a successful connection can be established.
*/
-
- if ((int) (ip_addr = inet_addr(host)) != (int) INADDR_NONE)
- {
- memcpy_fixed(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr));
- status= my_connect(sock, (struct sockaddr *) &sock_addr,
- sizeof(sock_addr), mysql->options.connect_timeout);
- }
- else
+ DBUG_PRINT("info", ("Try connect on all addresses for host."));
+ for (t_res= res_lst; t_res; t_res= t_res->ai_next)
{
- int i, tmp_errno;
- struct hostent tmp_hostent,*hp;
- char buff2[GETHOSTBYNAME_BUFF_SIZE];
- hp = my_gethostbyname_r(host,&tmp_hostent,buff2,sizeof(buff2),
- &tmp_errno);
+ DBUG_PRINT("info", ("Create socket, family: %d type: %d proto: %d",
+ 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)
+ {
+ saved_error= socket_errno;
+ continue;
+ }
+ DBUG_PRINT("info", ("Connect socket"));
+ status= my_connect(sock, t_res->ai_addr, t_res->ai_addrlen,
+ mysql->options.connect_timeout);
/*
- Don't attempt to connect to non IPv4 addresses as the client could
- end up sending information to a unknown server. For example, a IPv6
- address might be returned from gethostbyname depending on options
- set via the RES_OPTIONS environment variable.
+ Here we rely on my_connect() to return success only if the
+ connect attempt was really successful. Otherwise we would stop
+ trying another address, believing we were successful.
*/
- if (!hp || (hp->h_addrtype != AF_INET))
- {
- my_gethostbyname_r_free();
- set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
- ER(CR_UNKNOWN_HOST), host, tmp_errno);
- goto error;
- }
+ if (!status)
+ break;
- for (i= 0; status && hp->h_addr_list[i]; i++)
- {
- char ipaddr[18] __attribute__((unused));
- memcpy(&sock_addr.sin_addr, hp->h_addr_list[i],
- min(sizeof(sock_addr.sin_addr), (size_t) hp->h_length));
- DBUG_PRINT("info",("Trying %s...",
- (my_inet_ntoa(sock_addr.sin_addr, ipaddr), ipaddr)));
- /*
- Here we rely on my_connect() to return success only if the
- connect attempt was really successful. Otherwise we would stop
- trying another address, believing we were successful.
- */
- status= my_connect(sock, (struct sockaddr *) &sock_addr,
- sizeof(sock_addr), mysql->options.connect_timeout);
- }
+ /*
+ Save value as socket errno might be overwritten due to
+ calling a socket function below.
+ */
+ saved_error= socket_errno;
- my_gethostbyname_r_free();
+ DBUG_PRINT("info", ("No success, close socket, try next address."));
+ closesocket(sock);
+ }
+ DBUG_PRINT("info",
+ ("End of connect attempts, sock: %d status: %d error: %d",
+ sock, status, saved_error));
+
+ 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'",socket_errno,
- host));
+ 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, socket_errno);
+ 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;
}
}
+
+ DBUG_PRINT("info", ("net->vio: %p", net->vio));
if (!net->vio)
{
DBUG_PRINT("error",("Unknow protocol %d ",mysql->options.protocol));
@@ -2640,14 +2684,14 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
if (client_flag & CLIENT_MULTI_STATEMENTS)
client_flag|= CLIENT_MULTI_RESULTS;
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
if (mysql->options.ssl_key || mysql->options.ssl_cert ||
mysql->options.ssl_ca || mysql->options.ssl_capath ||
mysql->options.ssl_cipher)
mysql->options.use_ssl= 1;
if (mysql->options.use_ssl)
client_flag|=CLIENT_SSL;
-#endif /* HAVE_OPENSSL */
+#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY*/
if (db)
client_flag|=CLIENT_CONNECT_WITH_DB;
@@ -2676,7 +2720,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
}
mysql->client_flag=client_flag;
-#ifdef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
if (client_flag & CLIENT_SSL)
{
/* Do the SSL layering. */
@@ -2727,7 +2771,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
}
}
-#endif /* HAVE_OPENSSL */
+#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
DBUG_PRINT("info",("Server version = '%s' capabilites: %lu status: %u client_flag: %lu",
mysql->server_version,mysql->server_capabilities,