From 059dba14b774083ae63cde9ad41b00308f001ce7 Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Wed, 20 May 2009 16:17:47 +0200 Subject: Recommit of bug 43560 after merge with mysql-5.1-bugteam --- sql-common/client.c | 68 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 24 deletions(-) (limited to 'sql-common') diff --git a/sql-common/client.c b/sql-common/client.c index d2c7e02551d..9ba7f13e6b6 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -924,6 +924,7 @@ void end_server(MYSQL *mysql) vio_delete(mysql->net.vio); reset_sigpipe(mysql); mysql->net.vio= 0; /* Marker */ + mysql_prune_stmt_list(mysql); } net_end(&mysql->net); free_old_query(mysql); @@ -2526,30 +2527,9 @@ my_bool mysql_reconnect(MYSQL *mysql) tmp_mysql.reconnect= 1; tmp_mysql.free_me= mysql->free_me; - /* - For each stmt in mysql->stmts, move it to tmp_mysql if it is - in state MYSQL_STMT_INIT_DONE, otherwise close it. - */ - { - LIST *element= mysql->stmts; - for (; element; element= element->next) - { - MYSQL_STMT *stmt= (MYSQL_STMT *) element->data; - if (stmt->state != MYSQL_STMT_INIT_DONE) - { - stmt->mysql= 0; - stmt->last_errno= CR_SERVER_LOST; - strmov(stmt->last_error, ER(CR_SERVER_LOST)); - strmov(stmt->sqlstate, unknown_sqlstate); - } - else - { - tmp_mysql.stmts= list_add(tmp_mysql.stmts, &stmt->list); - } - /* No need to call list_delete for statement here */ - } - mysql->stmts= NULL; - } + /* Move prepared statements (if any) over to the new mysql object */ + tmp_mysql.stmts= mysql->stmts; + mysql->stmts= 0; /* Don't free options as these are now used in tmp_mysql */ bzero((char*) &mysql->options,sizeof(mysql->options)); @@ -2639,6 +2619,46 @@ static void mysql_close_free(MYSQL *mysql) } +/** + For use when the connection to the server has been lost (in which case + the server has discarded all information about prepared statements + associated with the connection). + + Mark all statements in mysql->stmts by setting stmt->mysql= 0 if the + statement has transitioned beyond the MYSQL_STMT_INIT_DONE state, and + unlink the statement from the mysql->stmts list. + + The remaining pruned list of statements (if any) is kept in mysql->stmts. + + @param mysql pointer to the MYSQL object + + @return none +*/ +void mysql_prune_stmt_list(MYSQL *mysql) +{ + LIST *element= mysql->stmts; + LIST *pruned_list= 0; + + for (; element; element= element->next) + { + MYSQL_STMT *stmt= (MYSQL_STMT *) element->data; + if (stmt->state != MYSQL_STMT_INIT_DONE) + { + stmt->mysql= 0; + stmt->last_errno= CR_SERVER_LOST; + strmov(stmt->last_error, ER(CR_SERVER_LOST)); + strmov(stmt->sqlstate, unknown_sqlstate); + } + else + { + pruned_list= list_add(pruned_list, element); + } + } + + mysql->stmts= pruned_list; +} + + /* Clear connection pointer of every statement: this is necessary to give error on attempt to use a prepared statement of closed -- cgit v1.2.1 From aede9b7d1328657ba454d5d0f88825f9e0c616c0 Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Wed, 20 May 2009 19:34:37 +0200 Subject: Adding missing forward declaration for bug 43560 --- sql-common/client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql-common') diff --git a/sql-common/client.c b/sql-common/client.c index 9ba7f13e6b6..a6a2be1086f 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -120,6 +120,7 @@ const char *def_shared_memory_base_name= default_shared_memory_base_name; static void mysql_close_free_options(MYSQL *mysql); static void mysql_close_free(MYSQL *mysql); +static void mysql_prune_stmt_list(MYSQL *mysql); #if !(defined(__WIN__) || defined(__NETWARE__)) static int wait_for_data(my_socket fd, uint timeout); @@ -2634,7 +2635,7 @@ static void mysql_close_free(MYSQL *mysql) @return none */ -void mysql_prune_stmt_list(MYSQL *mysql) +static void mysql_prune_stmt_list(MYSQL *mysql) { LIST *element= mysql->stmts; LIST *pruned_list= 0; -- cgit v1.2.1 From afacea4d602bd2230791bd7a91f51e380e00f5d0 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Wed, 10 Jun 2009 10:59:59 -0300 Subject: Bug#41190: shared memory connections do not work in Vista, if server started from cmdline Backport to MySQL 5.0/1 fix by Vladislav Vaintroub: In Vista and later and also in when using terminal services, when server is started from command line, client cannot connect to it via shared memory protocol. This is a regression introduced when Bug#24731 was fixed. The reason is that client is trying to attach to shared memory using global kernel object namespace (all kernel objects are prefixed with Global\). However, server started from the command line in Vista and later will create shared memory and events using current session namespace. Thus, client is unable to find the server and connection fails. The fix for the client is to first try to find server using "local" names (omitting Global\ prefix) and only if server is not found, trying global namespace. --- sql-common/client.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'sql-common') diff --git a/sql-common/client.c b/sql-common/client.c index 27cc110401c..5475d5d5160 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -412,6 +412,9 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout) DWORD error_code = 0; DWORD event_access_rights= SYNCHRONIZE | EVENT_MODIFY_STATE; char *shared_memory_base_name = mysql->options.shared_memory_base_name; + static const char *name_prefixes[] = {"","Global\\"}; + const char *prefix; + int i; /* get enough space base-name + '_' + longest suffix we might ever send @@ -426,9 +429,18 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout) shared_memory_base_name is unique value for each server unique_part is uniquel value for each object (events and file-mapping) */ - suffix_pos = strxmov(tmp, "Global\\", shared_memory_base_name, "_", NullS); - strmov(suffix_pos, "CONNECT_REQUEST"); - if (!(event_connect_request= OpenEvent(event_access_rights, FALSE, tmp))) + for (i = 0; i< array_elements(name_prefixes); i++) + { + prefix= name_prefixes[i]; + suffix_pos = strxmov(tmp, prefix , shared_memory_base_name, "_", NullS); + strmov(suffix_pos, "CONNECT_REQUEST"); + event_connect_request= OpenEvent(event_access_rights, FALSE, tmp); + if (event_connect_request) + { + break; + } + } + if (!event_connect_request) { error_allow = CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR; goto err; @@ -480,7 +492,7 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout) unique_part is uniquel value for each object (events and file-mapping) number_of_connection is number of connection between server and client */ - suffix_pos = strxmov(tmp, "Global\\", shared_memory_base_name, "_", connect_number_char, + suffix_pos = strxmov(tmp, prefix , shared_memory_base_name, "_", connect_number_char, "_", NullS); strmov(suffix_pos, "DATA"); if ((handle_file_map = OpenFileMapping(FILE_MAP_WRITE,FALSE,tmp)) == NULL) -- cgit v1.2.1 From 543e86728f02da79bb9fec4de35aae3d8759c88a Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Thu, 30 Jul 2009 21:28:43 -0300 Subject: 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 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 IPv4 address from the list of addresses that hostname maps to until a successful connection is established or there are no more address. --- sql-common/client.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'sql-common') diff --git a/sql-common/client.c b/sql-common/client.c index 2cbc15ad746..06ab3e0b632 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -2027,6 +2027,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, (!mysql->options.protocol || mysql->options.protocol == MYSQL_PROTOCOL_TCP)) { + int status= -1; unix_socket=0; /* This is not used */ if (!port) port=mysql_port; @@ -2052,6 +2053,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, 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 @@ -2060,28 +2062,46 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, 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 { - int tmp_errno; + 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); - if (!hp) + + /* + 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. + */ + 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; } - memcpy(&sock_addr.sin_addr, hp->h_addr, - min(sizeof(sock_addr.sin_addr), (size_t) hp->h_length)); + + for (i= 0; status && hp->h_addr_list[i]; i++) + { + IF_DBUG(char ipaddr[18];) + 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))); + status= my_connect(sock, (struct sockaddr *) &sock_addr, + sizeof(sock_addr), mysql->options.connect_timeout); + } + my_gethostbyname_r_free(); } - sock_addr.sin_port = (ushort) htons((ushort) port); - if (my_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr), - mysql->options.connect_timeout)) + + if (status) { DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno, host)); -- cgit v1.2.1