summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRinat Ibragimov <ri@tempesta-tech.com>2020-09-10 03:39:20 +0300
committerDaniel Black <daniel@mariadb.org>2021-03-04 11:19:59 +1100
commit816b6ea849057dbcafc7660a152cf6f7d70b85ac (patch)
tree5348cdbbfb67bfc97f0ec35e65c421b81f00a6bc
parent80ac9ec1cc10d56b048272642653d5d301394779 (diff)
downloadmariadb-git-816b6ea849057dbcafc7660a152cf6f7d70b85ac.tar.gz
MDEV-6536: make --bind=hostname to listen on both IPv6 and IPv4 addresses
Binding to a hostname now makes MariaDB server to listen on all addresses that hostname resolves to. Rebased to 10.6 by Daniel Black Closes: #1668
-rw-r--r--include/mysql/psi/mysql_socket.h11
-rw-r--r--mysql-test/main/bind_address_resolution.opt1
-rw-r--r--mysql-test/main/bind_address_resolution.result15
-rw-r--r--mysql-test/main/bind_address_resolution.test19
-rw-r--r--mysql-test/suite/perfschema/r/socket_instances_func.result14
-rw-r--r--mysql-test/suite/perfschema/t/socket_instances_func.test17
-rw-r--r--mysql-test/suite/rpl/t/rpl_ipv6.cnf4
-rw-r--r--sql/handle_connections_win.cc87
-rw-r--r--sql/mysqld.cc304
-rw-r--r--sql/mysqld.h1
10 files changed, 262 insertions, 211 deletions
diff --git a/include/mysql/psi/mysql_socket.h b/include/mysql/psi/mysql_socket.h
index aa85daaaab1..59489fabe25 100644
--- a/include/mysql/psi/mysql_socket.h
+++ b/include/mysql/psi/mysql_socket.h
@@ -75,6 +75,15 @@ struct st_mysql_socket
/** The real socket descriptor. */
my_socket fd;
+ /** Is this a Unix-domain socket? */
+ char is_unix_domain_socket;
+
+ /** Is this a socket opened for the extra port? */
+ char is_extra_port;
+
+ /** Address family of the socket. (See sa_family from struct sockaddr). */
+ unsigned short address_family;
+
/**
The instrumentation hook.
Note that this hook is not conditionally defined,
@@ -105,7 +114,7 @@ typedef struct st_mysql_socket MYSQL_SOCKET;
static inline MYSQL_SOCKET
mysql_socket_invalid()
{
- MYSQL_SOCKET mysql_socket= {INVALID_SOCKET, NULL};
+ MYSQL_SOCKET mysql_socket= {INVALID_SOCKET, 0, 0, 0, NULL};
return mysql_socket;
}
diff --git a/mysql-test/main/bind_address_resolution.opt b/mysql-test/main/bind_address_resolution.opt
new file mode 100644
index 00000000000..b0b906a7091
--- /dev/null
+++ b/mysql-test/main/bind_address_resolution.opt
@@ -0,0 +1 @@
+--bind-address=localhost
diff --git a/mysql-test/main/bind_address_resolution.result b/mysql-test/main/bind_address_resolution.result
new file mode 100644
index 00000000000..9dc6c7a1f77
--- /dev/null
+++ b/mysql-test/main/bind_address_resolution.result
@@ -0,0 +1,15 @@
+CREATE TABLE t (a TEXT);
+connect con1,localhost,root,,test;
+SELECT * FROM t;
+a
+connect con2,127.0.0.1,root,,test;
+SELECT * FROM t;
+a
+connect con3,::1,root,,test;
+SELECT * FROM t;
+a
+connection default;
+DROP TABLE t;
+disconnect con1;
+disconnect con2;
+disconnect con3;
diff --git a/mysql-test/main/bind_address_resolution.test b/mysql-test/main/bind_address_resolution.test
new file mode 100644
index 00000000000..9bad9313cf7
--- /dev/null
+++ b/mysql-test/main/bind_address_resolution.test
@@ -0,0 +1,19 @@
+--source include/check_ipv6.inc
+--source include/not_embedded.inc
+
+# The server is started with --bind-address=localhost, and should
+# listen on all addresses 'localhost' resolves to. With at least
+# 127.0.0.1 and ::1 amongst them.
+
+CREATE TABLE t (a TEXT);
+--connect(con1,localhost,root,,test)
+SELECT * FROM t;
+--connect(con2,127.0.0.1,root,,test)
+SELECT * FROM t;
+--connect(con3,::1,root,,test)
+SELECT * FROM t;
+--connection default
+DROP TABLE t;
+--disconnect con1
+--disconnect con2
+--disconnect con3
diff --git a/mysql-test/suite/perfschema/r/socket_instances_func.result b/mysql-test/suite/perfschema/r/socket_instances_func.result
index 8792730fa29..28643ca07e8 100644
--- a/mysql-test/suite/perfschema/r/socket_instances_func.result
+++ b/mysql-test/suite/perfschema/r/socket_instances_func.result
@@ -80,15 +80,16 @@ Expect 1
1
# Characteristics of 'server_tcpip_socket' entry
# Server listening socket, TCP/IP
-# There is only one entry with 'wait/io/socket/sql/server_tcpip_socket'.
-# It shares the same thread id as 'wait/io/socket/sql/server_unix_socket'.
-SELECT COUNT(*) = 1 AS 'Expect 1'
+# There are two entries with 'wait/io/socket/sql/server_tcpip_socket',
+# for [::] and for 0.0.0.0.
+# They share the same thread id with 'wait/io/socket/sql/server_unix_socket'.
+SELECT COUNT(*) = 2 AS 'Expect 1'
FROM performance_schema.socket_instances
WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket';
Expect 1
1
# Get the 'server_tcpip_socket' thread id
-SELECT THREAD_ID INTO @thread_id
+SELECT DISTINCT THREAD_ID INTO @thread_id
FROM performance_schema.socket_instances
WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket';
# Check the content.
@@ -100,6 +101,7 @@ FROM performance_schema.socket_instances
WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket';
Expect 1
1
+1
# Characteristics of 'server_unix_socket' entry
# Server listening socket, unix domain (socket file)
# There is only one entry with 'wait/io/socket/sql/server_unix_socket'.
@@ -123,12 +125,12 @@ WHERE EVENT_NAME = 'wait/io/socket/sql/server_unix_socket';
Expect 1
1
# Server listening sockets (TCP and Unix) are handled on the same thread
-SELECT COUNT(*) = 2 AS 'Expect 1'
+SELECT COUNT(*) = 3 AS 'Expect 1'
FROM performance_schema.socket_instances
WHERE THREAD_ID = @thread_id;
Expect 1
1
-SELECT COUNT(*) = 2 AS 'Expect 1'
+SELECT COUNT(*) = 3 AS 'Expect 1'
FROM performance_schema.socket_instances
WHERE THREAD_ID = @thread_id;
Expect 1
diff --git a/mysql-test/suite/perfschema/t/socket_instances_func.test b/mysql-test/suite/perfschema/t/socket_instances_func.test
index 4cf58d42185..27f0b3983c0 100644
--- a/mysql-test/suite/perfschema/t/socket_instances_func.test
+++ b/mysql-test/suite/perfschema/t/socket_instances_func.test
@@ -38,6 +38,10 @@ if($my_socket_debug)
--echo IPV6=$check_ipv6_supported, IPV4_MAPPED=$check_ipv4_mapped_supported, LOCALHOST=$my_localhost
}
+# This test only runs when IPv6 is supported (see include/check_ipv6.inc), so
+# the server will listen on both IPv4 and IPv6 wildcard addresses. That's why
+# the expected number of TCP/IP listeners is always 2.
+
#
# Preserve the current state of SOCKET_INSTANCES
#
@@ -222,17 +226,18 @@ AND PORT = 0 AND THREAD_ID = @thread_id;
--echo # Characteristics of 'server_tcpip_socket' entry
--echo # Server listening socket, TCP/IP
---echo # There is only one entry with 'wait/io/socket/sql/server_tcpip_socket'.
---echo # It shares the same thread id as 'wait/io/socket/sql/server_unix_socket'.
+--echo # There are two entries with 'wait/io/socket/sql/server_tcpip_socket',
+--echo # for [::] and for 0.0.0.0.
+--echo # They share the same thread id with 'wait/io/socket/sql/server_unix_socket'.
-SELECT COUNT(*) = 1 AS 'Expect 1'
+SELECT COUNT(*) = 2 AS 'Expect 1'
FROM performance_schema.socket_instances
WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket';
# Store the thread id of server_tcpip_socket
--echo # Get the 'server_tcpip_socket' thread id
-SELECT THREAD_ID INTO @thread_id
+SELECT DISTINCT THREAD_ID INTO @thread_id
FROM performance_schema.socket_instances
WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket';
@@ -288,14 +293,14 @@ WHERE EVENT_NAME = 'wait/io/socket/sql/server_unix_socket';
--disable_query_log ONCE
eval SET @thread_id = $server_tcpip_thread_id;
-eval SELECT COUNT(*) = 2 AS 'Expect 1'
+eval SELECT COUNT(*) = 3 AS 'Expect 1'
FROM performance_schema.socket_instances
WHERE THREAD_ID = @thread_id;
--disable_query_log ONCE
eval SET @thread_id = $server_unix_thread_id;
-eval SELECT COUNT(*) = 2 AS 'Expect 1'
+eval SELECT COUNT(*) = 3 AS 'Expect 1'
FROM performance_schema.socket_instances
WHERE THREAD_ID = @thread_id;
diff --git a/mysql-test/suite/rpl/t/rpl_ipv6.cnf b/mysql-test/suite/rpl/t/rpl_ipv6.cnf
index c657e7c5115..6bf97a94a4e 100644
--- a/mysql-test/suite/rpl/t/rpl_ipv6.cnf
+++ b/mysql-test/suite/rpl/t/rpl_ipv6.cnf
@@ -12,7 +12,7 @@ log-bin= master-bin
loose-innodb
skip-name-resolve
-bind-address= ::
+bind-address= *
[mysqld.2]
@@ -38,7 +38,7 @@ report-user= root
skip-slave-start
skip-name-resolve
-bind-address= ::
+bind-address= *
# Directory where slaves find the dumps generated by "load data"
# on the server. The path need to have constant length otherwise
diff --git a/sql/handle_connections_win.cc b/sql/handle_connections_win.cc
index debbce998fa..07d50590869 100644
--- a/sql/handle_connections_win.cc
+++ b/sql/handle_connections_win.cc
@@ -22,11 +22,13 @@
#include <mswsock.h>
#include <mysql/psi/mysql_socket.h>
#include <sddl.h>
+#include <vector>
#include <handle_connections_win.h>
/* From mysqld.cc */
-extern MYSQL_SOCKET base_ip_sock, extra_ip_sock;
+extern HANDLE hEventShutdown;
+extern std::vector<MYSQL_SOCKET> listen_sockets;
#ifdef HAVE_POOL_OF_THREADS
extern PTP_CALLBACK_ENVIRON get_threadpool_win_callback_environ();
extern void tp_win_callback_prolog();
@@ -128,6 +130,9 @@ struct Socket_Listener: public Listener
/** Client socket passed to AcceptEx() call.*/
SOCKET m_client_socket;
+ /** Listening socket. */
+ MYSQL_SOCKET m_listen_socket;
+
/** Buffer for sockaddrs passed to AcceptEx()/GetAcceptExSockaddrs() */
char m_buffer[2 * sizeof(sockaddr_storage) + 32];
@@ -162,7 +167,8 @@ struct Socket_Listener: public Listener
*/
Socket_Listener(MYSQL_SOCKET listen_socket, PTP_CALLBACK_ENVIRON callback_environ) :
Listener((HANDLE)listen_socket.fd,0),
- m_client_socket(INVALID_SOCKET)
+ m_client_socket(INVALID_SOCKET),
+ m_listen_socket(listen_socket)
{
if (callback_environ)
{
@@ -184,7 +190,8 @@ struct Socket_Listener: public Listener
void begin_accept()
{
retry :
- m_client_socket= socket(server_socket_ai_family, SOCK_STREAM, IPPROTO_TCP);
+ m_client_socket= socket(m_listen_socket.address_family, SOCK_STREAM,
+ IPPROTO_TCP);
if (m_client_socket == INVALID_SOCKET)
{
sql_perror("socket() call failed.");
@@ -233,7 +240,6 @@ retry :
}
MYSQL_SOCKET s_client{m_client_socket};
- MYSQL_SOCKET s_listen{(SOCKET)m_handle};
#ifdef HAVE_PSI_SOCKET_INTERFACE
/* Parse socket addresses buffer filled by AcceptEx(),
@@ -246,7 +252,8 @@ retry :
&local_addr, &local_addr_len, &remote_addr, &remote_addr_len);
s_client.m_psi= PSI_SOCKET_CALL(init_socket)
- (key_socket_client_connection, (const my_socket*)&s_listen.fd, remote_addr, remote_addr_len);
+ (key_socket_client_connection, (const my_socket*)&m_listen_socket.fd,
+ remote_addr, remote_addr_len);
#endif
/* Start accepting new connection. After this point, do not use
@@ -255,7 +262,7 @@ retry :
/* Some chores post-AcceptEx() that we need to create a normal socket.*/
if (setsockopt(s_client.fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
- (char *)&s_listen.fd, sizeof(s_listen.fd)))
+ (char *)&m_listen_socket.fd, sizeof(m_listen_socket.fd)))
{
if (!abort_loop)
{
@@ -265,7 +272,7 @@ retry :
}
/* Create a new connection.*/
- handle_accepted_socket(s_client, s_listen);
+ handle_accepted_socket(s_client, m_listen_socket);
}
~Socket_Listener()
@@ -280,14 +287,12 @@ retry :
*/
static void init_winsock_extensions()
{
- SOCKET s= mysql_socket_getfd(base_ip_sock);
- if (s == INVALID_SOCKET)
- s= mysql_socket_getfd(extra_ip_sock);
- if (s == INVALID_SOCKET)
- {
+ if (listen_sockets.size() == 0) {
/* --skip-networking was used*/
return;
}
+
+ SOCKET s= mysql_socket_getfd(listen_sockets[0]);
GUID guid_AcceptEx= WSAID_ACCEPTEX;
GUID guid_GetAcceptExSockaddrs= WSAID_GETACCEPTEXSOCKADDRS;
@@ -540,22 +545,24 @@ static void create_shutdown_event()
*/
-#define MAX_WAIT_HANDLES 32
#define NUM_PIPE_LISTENERS 24
#define SHUTDOWN_IDX 0
#define LISTENER_START_IDX 1
-static Listener *all_listeners[MAX_WAIT_HANDLES];
-static HANDLE wait_events[MAX_WAIT_HANDLES];
-static int n_listeners;
+static std::vector<Listener *> all_listeners;
+static std::vector<HANDLE> wait_events;
void network_init_win()
{
Socket_Listener::init_winsock_extensions();
/* Listen for TCP connections on "extra-port" (no threadpool).*/
- if (extra_ip_sock.fd != INVALID_SOCKET)
- all_listeners[n_listeners++]= new Socket_Listener(extra_ip_sock, 0);
+ for (std::vector<MYSQL_SOCKET>::iterator it= listen_sockets.begin();
+ it != listen_sockets.end(); ++it)
+ {
+ if (it->is_extra_port)
+ all_listeners.push_back(new Socket_Listener(*it, 0));
+ }
/* Listen for named pipe connections */
if (mysqld_unix_port[0] && !opt_bootstrap && opt_enable_named_pipe)
@@ -564,17 +571,22 @@ void network_init_win()
Use several listeners for pipe, to reduce ERROR_PIPE_BUSY on client side.
*/
for (int i= 0; i < NUM_PIPE_LISTENERS; i++)
- all_listeners[n_listeners++]= new Pipe_Listener();
+ all_listeners.push_back(new Pipe_Listener());
}
- if (base_ip_sock.fd != INVALID_SOCKET)
+ for (std::vector<MYSQL_SOCKET>::iterator it= listen_sockets.begin();
+ it != listen_sockets.end(); ++it)
{
- /* Wait for TCP connections.*/
- SetFileCompletionNotificationModes((HANDLE)base_ip_sock.fd, FILE_SKIP_SET_EVENT_ON_HANDLE);
- all_listeners[n_listeners++]= new Socket_Listener(base_ip_sock, get_threadpool_win_callback_environ());
+ if (it->is_extra_port)
+ continue;
+ /* Wait for TCP connections.*/
+ SetFileCompletionNotificationModes((HANDLE)it->fd,
+ FILE_SKIP_SET_EVENT_ON_HANDLE);
+ all_listeners.push_back(
+ new Socket_Listener(*it, get_threadpool_win_callback_environ()));
}
- if (!n_listeners && !opt_bootstrap)
+ if (all_listeners.size() == 0 && !opt_bootstrap)
{
sql_print_error("Either TCP connections or named pipe connections must be enabled.");
unireg_abort(1);
@@ -586,26 +598,41 @@ void handle_connections_win()
int n_waits;
create_shutdown_event();
- wait_events[SHUTDOWN_IDX]= hEventShutdown;
+ wait_events.push_back(hEventShutdown);
n_waits= 1;
- for (int i= 0; i < n_listeners; i++)
+ for (int i= 0; i < all_listeners.size(); i++)
{
HANDLE wait_handle= all_listeners[i]->wait_handle();
if (wait_handle)
{
DBUG_ASSERT((i == 0) || (all_listeners[i - 1]->wait_handle() != 0));
- wait_events[n_waits++]= wait_handle;
+ wait_events.push_back(wait_handle);
}
all_listeners[i]->begin_accept();
}
mysqld_win_set_startup_complete();
+ // WaitForMultipleObjects can't wait on more than MAXIMUM_WAIT_OBJECTS
+ // handles simultaneously. Since MAXIMUM_WAIT_OBJECTS is only 64, there is
+ // a theoretical possiblity of exceeding that limit on installations where
+ // host name resolves to a lot of addresses.
+ if (wait_events.size() > MAXIMUM_WAIT_OBJECTS)
+ {
+ sql_print_warning(
+ "Too many wait events (%lu). Some connection listeners won't be handled. "
+ "Try to switch \"thread-handling\" to \"pool-of-threads\" and/or disable "
+ "\"extra-port\".", static_cast<ulong>(wait_events.size()));
+ wait_events.resize(MAXIMUM_WAIT_OBJECTS);
+ }
+
for (;;)
{
- DWORD idx = WaitForMultipleObjects(n_waits ,wait_events, FALSE, INFINITE);
- DBUG_ASSERT((int)idx >= 0 && (int)idx < n_waits);
+ DBUG_ASSERT(wait_events.size() <= MAXIMUM_WAIT_OBJECTS);
+ DWORD idx = WaitForMultipleObjects((DWORD)wait_events.size(),
+ wait_events.data(), FALSE, INFINITE);
+ DBUG_ASSERT((int)idx >= 0 && (int)idx < (int)wait_events.size());
if (idx == SHUTDOWN_IDX)
break;
@@ -616,7 +643,7 @@ void handle_connections_win()
mysqld_win_initiate_shutdown();
/* Cleanup */
- for (int i= 0; i < n_listeners; i++)
+ for (size_t i= 0; i < all_listeners.size(); i++)
{
Listener *listener= all_listeners[i];
if (listener->wait_handle())
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 02f69e1d512..39c764d71b9 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -338,7 +338,6 @@ static char *character_set_filesystem_name;
static char *lc_messages;
static char *lc_time_names_name;
char *my_bind_addr_str;
-int server_socket_ai_family;
static char *default_collation_name;
char *default_storage_engine, *default_tmp_storage_engine;
char *enforced_storage_engine=NULL;
@@ -1349,7 +1348,8 @@ static Buffered_logs buffered_logs;
struct my_rnd_struct sql_rand; ///< used by sql_class.cc:THD::THD()
#ifndef EMBEDDED_LIBRARY
-MYSQL_SOCKET unix_sock, base_ip_sock, extra_ip_sock;
+std::vector<MYSQL_SOCKET> listen_sockets;
+bool unix_sock_is_online= false;
/**
Error reporter that buffer log messages.
@param level log message level
@@ -1690,28 +1690,15 @@ static void close_connections(void)
/* Abort listening to new connections */
DBUG_PRINT("quit",("Closing sockets"));
- if (!opt_disable_networking )
+ for (std::vector<MYSQL_SOCKET>::iterator sock = listen_sockets.begin();
+ sock != listen_sockets.end(); ++sock)
{
- if (mysql_socket_getfd(base_ip_sock) != INVALID_SOCKET)
- {
- (void) mysql_socket_close(base_ip_sock);
- base_ip_sock= MYSQL_INVALID_SOCKET;
- }
- if (mysql_socket_getfd(extra_ip_sock) != INVALID_SOCKET)
- {
- (void) mysql_socket_close(extra_ip_sock);
- extra_ip_sock= MYSQL_INVALID_SOCKET;
- }
+ (void) mysql_socket_close(*sock);
+ if (sock->is_unix_domain_socket)
+ (void) unlink(mysqld_unix_port);
}
+ listen_sockets.clear();
-#ifdef HAVE_SYS_UN_H
- if (mysql_socket_getfd(unix_sock) != INVALID_SOCKET)
- {
- (void) mysql_socket_close(unix_sock);
- (void) unlink(mysqld_unix_port);
- unix_sock= MYSQL_INVALID_SOCKET;
- }
-#endif
end_thr_alarm(0); // Abort old alarms.
/*
@@ -1800,13 +1787,20 @@ static void close_server_sock()
#ifdef HAVE_CLOSE_SERVER_SOCK
DBUG_ENTER("close_server_sock");
- close_socket(base_ip_sock, "TCP/IP");
- close_socket(extra_ip_sock, "TCP/IP");
- close_socket(unix_sock, "unix/IP");
-
- if (mysql_socket_getfd(unix_sock) != INVALID_SOCKET)
- (void) unlink(mysqld_unix_port);
- base_ip_sock= extra_ip_sock= unix_sock= MYSQL_INVALID_SOCKET;
+ for (std::vector<MYSQL_SOCKET>::iterator sock= listen_sockets.begin();
+ sock != listen_sockets.end(); ++sock)
+ {
+ if (sock->is_unix_domain_socket)
+ {
+ close_socket(*sock, "unix/IP");
+ (void) unlink(mysqld_unix_port);
+ }
+ else
+ {
+ close_socket(*sock, "TCP/IP");
+ }
+ }
+ listen_sockets.clear();
DBUG_VOID_RETURN;
#endif
@@ -2241,7 +2235,9 @@ static void set_root(const char *path)
Activate usage of a tcp port
*/
-static MYSQL_SOCKET activate_tcp_port(uint port)
+static void activate_tcp_port(uint port,
+ std::vector<MYSQL_SOCKET> *listen_sockets,
+ bool is_extra_port= false)
{
struct addrinfo *ai, *a;
struct addrinfo hints;
@@ -2273,20 +2269,6 @@ static MYSQL_SOCKET activate_tcp_port(uint port)
unireg_abort(1); /* purecov: tested */
}
- /*
- special case: for wildcard addresses prefer ipv6 over ipv4,
- because we later switch off IPV6_V6ONLY, so ipv6 wildcard
- addresses will work for ipv4 too
- */
- if (!real_bind_addr_str && ai->ai_family == AF_INET && ai->ai_next
- && ai->ai_next->ai_family == AF_INET6)
- {
- a= ai;
- ai= ai->ai_next;
- a->ai_next= ai->ai_next;
- ai->ai_next= a;
- }
-
for (a= ai; a != NULL; a= a->ai_next)
{
ip_sock= mysql_socket_socket(key_socket_tcpip, a->ai_family,
@@ -2309,99 +2291,98 @@ static MYSQL_SOCKET activate_tcp_port(uint port)
}
else
{
- server_socket_ai_family= a->ai_family;
+ ip_sock.address_family= a->ai_family;
sql_print_information("Server socket created on IP: '%s'.",
(const char *) ip_addr);
- break;
- }
- }
- if (mysql_socket_getfd(ip_sock) == INVALID_SOCKET)
- {
- DBUG_PRINT("error",("Got error: %d from socket()",socket_errno));
- sql_perror(ER_DEFAULT(ER_IPSOCK_ERROR)); /* purecov: tested */
- unireg_abort(1); /* purecov: tested */
- }
+ if (mysql_socket_getfd(ip_sock) == INVALID_SOCKET)
+ {
+ DBUG_PRINT("error",("Got error: %d from socket()",socket_errno));
+ sql_perror(ER_DEFAULT(ER_IPSOCK_ERROR)); /* purecov: tested */
+ unireg_abort(1); /* purecov: tested */
+ }
- mysql_socket_set_thread_owner(ip_sock);
+ mysql_socket_set_thread_owner(ip_sock);
#ifndef __WIN__
- /*
- We should not use SO_REUSEADDR on windows as this would enable a
- user to open two mysqld servers with the same TCP/IP port.
- */
- arg= 1;
- (void) mysql_socket_setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,
- sizeof(arg));
+ /*
+ We should not use SO_REUSEADDR on windows as this would enable a
+ user to open two mysqld servers with the same TCP/IP port.
+ */
+ arg= 1;
+ (void) mysql_socket_setsockopt(ip_sock, SOL_SOCKET, SO_REUSEADDR,
+ (char*)&arg, sizeof(arg));
#endif /* __WIN__ */
#ifdef IPV6_V6ONLY
- /*
- For interoperability with older clients, IPv6 socket should
- listen on both IPv6 and IPv4 wildcard addresses.
- Turn off IPV6_V6ONLY option.
-
- NOTE: this will work starting from Windows Vista only.
- On Windows XP dual stack is not available, so it will not
- listen on the corresponding IPv4-address.
- */
- if (a->ai_family == AF_INET6)
- {
- arg= 0;
- (void) mysql_socket_setsockopt(ip_sock, IPPROTO_IPV6, IPV6_V6ONLY,
- (char*)&arg, sizeof(arg));
- }
+ /*
+ If an address name resolves to both IPv4 and IPv6 addresses, the server
+ will listen on them both. With IPV6_V6ONLY unset, listening on an IPv6
+ wildcard address may cause listening on an IPv4 wildcard address
+ to fail. That's why IPV6_V6ONLY needs to be forcefully turned on.
+ */
+ if (a->ai_family == AF_INET6)
+ {
+ arg= 1;
+ (void) mysql_socket_setsockopt(ip_sock, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char*)&arg, sizeof(arg));
+ }
#endif
#ifdef IP_FREEBIND
- arg= 1;
- (void) mysql_socket_setsockopt(ip_sock, IPPROTO_IP, IP_FREEBIND, (char*) &arg,
- sizeof(arg));
+ arg= 1;
+ (void) mysql_socket_setsockopt(ip_sock, IPPROTO_IP, IP_FREEBIND,
+ (char*) &arg, sizeof(arg));
#endif
- /*
- Sometimes the port is not released fast enough when stopping and
- restarting the server. This happens quite often with the test suite
- on busy Linux systems. Retry to bind the address at these intervals:
- Sleep intervals: 1, 2, 4, 6, 9, 13, 17, 22, ...
- Retry at second: 1, 3, 7, 13, 22, 35, 52, 74, ...
- Limit the sequence by mysqld_port_timeout (set --port-open-timeout=#).
- */
- int ret;
- uint waited, retry, this_wait;
- for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
- {
- if (((ret= mysql_socket_bind(ip_sock, a->ai_addr, a->ai_addrlen)) >= 0 ) ||
- (socket_errno != SOCKET_EADDRINUSE) ||
- (waited >= mysqld_port_timeout))
- break;
- sql_print_information("Retrying bind on TCP/IP port %u", port);
- this_wait= retry * retry / 3 + 1;
- sleep(this_wait);
- }
- freeaddrinfo(ai);
- if (ret < 0)
- {
- char buff[100];
- sprintf(buff, "Can't start server: Bind on TCP/IP port. Got error: %d",
- (int) socket_errno);
- sql_perror(buff);
- sql_print_error("Do you already have another mysqld server running on "
- "port: %u ?", port);
- unireg_abort(1);
- }
- if (mysql_socket_listen(ip_sock,(int) back_log) < 0)
- {
- sql_perror("Can't start server: listen() on TCP/IP port");
- sql_print_error("listen() on TCP/IP failed with error %d",
- socket_errno);
- unireg_abort(1);
- }
+ /*
+ Sometimes the port is not released fast enough when stopping and
+ restarting the server. This happens quite often with the test suite
+ on busy Linux systems. Retry to bind the address at these intervals:
+ Sleep intervals: 1, 2, 4, 6, 9, 13, 17, 22, ...
+ Retry at second: 1, 3, 7, 13, 22, 35, 52, 74, ...
+ Limit the sequence by mysqld_port_timeout (set --port-open-timeout=#).
+ */
+ int ret;
+ uint waited, retry, this_wait;
+ for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
+ {
+ if (((ret= mysql_socket_bind(ip_sock, a->ai_addr, a->ai_addrlen)) >= 0 )
+ || (socket_errno != SOCKET_EADDRINUSE)
+ || (waited >= mysqld_port_timeout))
+ break;
+ sql_print_information("Retrying bind on TCP/IP port %u", port);
+ this_wait= retry * retry / 3 + 1;
+ sleep(this_wait);
+ }
+
+ if (ret < 0)
+ {
+ char buff[100];
+ sprintf(buff, "Can't start server: Bind on TCP/IP port. Got error: %d",
+ (int) socket_errno);
+ sql_perror(buff);
+ sql_print_error("Do you already have another mysqld server running on "
+ "port: %u ?", port);
+ unireg_abort(1);
+ }
+ if (mysql_socket_listen(ip_sock,(int) back_log) < 0)
+ {
+ sql_perror("Can't start server: listen() on TCP/IP port");
+ sql_print_error("listen() on TCP/IP failed with error %d",
+ socket_errno);
+ unireg_abort(1);
+ }
#ifdef FD_CLOEXEC
- (void) fcntl(mysql_socket_getfd(ip_sock), F_SETFD, FD_CLOEXEC);
+ (void) fcntl(mysql_socket_getfd(ip_sock), F_SETFD, FD_CLOEXEC);
#endif
+ ip_sock.is_extra_port= is_extra_port;
+ listen_sockets->push_back(ip_sock);
+ }
+ }
- DBUG_RETURN(ip_sock);
+ freeaddrinfo(ai);
+ DBUG_VOID_RETURN;
}
static void network_init(void)
@@ -2431,9 +2412,11 @@ static void network_init(void)
if (!opt_disable_networking && !opt_bootstrap)
{
if (mysqld_port)
- base_ip_sock= activate_tcp_port(mysqld_port);
+ activate_tcp_port(mysqld_port, &listen_sockets,
+ /* is_extra_port= */ false);
if (mysqld_extra_port)
- extra_ip_sock= activate_tcp_port(mysqld_extra_port);
+ activate_tcp_port(mysqld_extra_port, &listen_sockets,
+ /* is_extra_port= */ true);
}
#if defined(HAVE_SYS_UN_H)
@@ -2442,6 +2425,7 @@ static void network_init(void)
*/
if (mysqld_unix_port[0] && !opt_bootstrap)
{
+ MYSQL_SOCKET unix_sock= MYSQL_INVALID_SOCKET;
size_t port_len;
DBUG_PRINT("general",("UNIX Socket is %s",mysqld_unix_port));
@@ -2458,6 +2442,9 @@ static void network_init(void)
unireg_abort(1); /* purecov: inspected */
}
+ unix_sock.is_unix_domain_socket= true;
+ listen_sockets.push_back(unix_sock);
+ unix_sock_is_online= true;
mysql_socket_set_thread_owner(unix_sock);
bzero((char*) &UNIXaddr, sizeof(UNIXaddr));
@@ -5645,8 +5632,7 @@ int mysqld_main(int argc, char **argv)
if (IS_SYSVAR_AUTOSIZE(&server_version_ptr))
sql_print_information(ER_DEFAULT(ER_STARTUP), my_progname, server_version,
- ((mysql_socket_getfd(unix_sock) == INVALID_SOCKET) ?
- (char*) "" : mysqld_unix_port),
+ (unix_sock_is_online ? mysqld_unix_port : (char*) ""),
mysqld_port, MYSQL_COMPILATION_COMMENT);
else
{
@@ -5658,8 +5644,7 @@ int mysqld_main(int argc, char **argv)
sql_print_information(ER_DEFAULT(ER_STARTUP), my_progname,
real_server_version,
- ((mysql_socket_getfd(unix_sock) == INVALID_SOCKET) ?
- (char*) "" : mysqld_unix_port),
+ (unix_sock_is_online ? mysqld_unix_port : (char*) ""),
mysqld_port, MYSQL_COMPILATION_COMMENT);
}
@@ -5866,8 +5851,7 @@ void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock)
{
#ifdef HAVE_LIBWRAP
{
- if (mysql_socket_getfd(sock) == mysql_socket_getfd(base_ip_sock) ||
- mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock))
+ if (!sock.is_unix_domain_socket)
{
struct request_info req;
signal(SIGCHLD, SIG_DFL);
@@ -5910,11 +5894,9 @@ void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock)
DBUG_PRINT("info", ("Creating CONNECT for new connection"));
if (auto connect= new CONNECT(new_sock,
- mysql_socket_getfd(sock) ==
- mysql_socket_getfd(unix_sock) ?
+ sock.is_unix_domain_socket ?
VIO_TYPE_SOCKET : VIO_TYPE_TCPIP,
- mysql_socket_getfd(sock) ==
- mysql_socket_getfd(extra_ip_sock) ?
+ sock.is_extra_port ?
extra_thread_scheduler : thread_scheduler))
create_new_thread(connect);
else
@@ -5950,36 +5932,30 @@ void handle_connections_sockets()
struct sockaddr_storage cAddr;
int retval;
#ifdef HAVE_POLL
- int socket_count= 0;
- struct pollfd fds[3]; // for ip_sock, unix_sock and extra_ip_sock
- MYSQL_SOCKET pfs_fds[3]; // for performance schema
-#define setup_fds(X) \
- mysql_socket_set_thread_owner(X); \
- pfs_fds[socket_count]= (X); \
- fds[socket_count].fd= mysql_socket_getfd(X); \
- fds[socket_count].events= POLLIN; \
- socket_count++
+ std::vector<struct pollfd> fds; // for ip_sock, unix_sock and extra_ip_sock
#else
-#define setup_fds(X) FD_SET(mysql_socket_getfd(X),&clientFDs)
fd_set readFDs,clientFDs;
- FD_ZERO(&clientFDs);
#endif
DBUG_ENTER("handle_connections_sockets");
- if (mysql_socket_getfd(base_ip_sock) != INVALID_SOCKET)
+#ifdef HAVE_POLL
+ fds.resize(listen_sockets.size());
+ for (size_t i= 0; i < listen_sockets.size(); i++)
{
- setup_fds(base_ip_sock);
- set_non_blocking_if_supported(base_ip_sock);
+ mysql_socket_set_thread_owner(listen_sockets[i]);
+ fds[i].fd= mysql_socket_getfd(listen_sockets[i]);
+ fds[i].events= POLLIN;
+ set_non_blocking_if_supported(listen_sockets[i]);
}
- if (mysql_socket_getfd(extra_ip_sock) != INVALID_SOCKET)
+#else
+ FD_ZERO(&clientFDs);
+ for (size_t i= 0; i < listen_sockets.size(); i++)
{
- setup_fds(extra_ip_sock);
- set_non_blocking_if_supported(extra_ip_sock);
+ int fd= mysql_socket_getfd(listen_sockets[i]);
+ FD_SET(fd, &clientFDs);
+ set_non_blocking_if_supported(listen_sockets[i]);
}
-#ifdef HAVE_SYS_UN_H
- setup_fds(unix_sock);
- set_non_blocking_if_supported(unix_sock);
#endif
sd_notify(0, "READY=1\n"
@@ -5989,10 +5965,10 @@ void handle_connections_sockets()
while (!abort_loop)
{
#ifdef HAVE_POLL
- retval= poll(fds, socket_count, -1);
+ retval= poll(fds.data(), fds.size(), -1);
#else
readFDs=clientFDs;
- retval= select((int) 0,&readFDs,0,0,0);
+ retval= select(FD_SETSIZE, &readFDs, NULL, NULL, NULL);
#endif
if (retval < 0)
@@ -6016,22 +5992,23 @@ void handle_connections_sockets()
/* Is this a new connection request ? */
#ifdef HAVE_POLL
- for (int i= 0; i < socket_count; ++i)
+ for (size_t i= 0; i < fds.size(); ++i)
{
if (fds[i].revents & POLLIN)
{
- sock= pfs_fds[i];
+ sock= listen_sockets[i];
break;
}
}
#else // HAVE_POLL
- if (FD_ISSET(mysql_socket_getfd(base_ip_sock),&readFDs))
- sock= base_ip_sock;
- else
- if (FD_ISSET(mysql_socket_getfd(extra_ip_sock),&readFDs))
- sock= extra_ip_sock;
- else
- sock = unix_sock;
+ for (size_t i=0; i < listen_sockets.size(); i++)
+ {
+ if (FD_ISSET(mysql_socket_getfd(listen_sockets[i]), &readFDs))
+ {
+ sock= listen_sockets[i];
+ break;
+ }
+ }
#endif // HAVE_POLL
for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++)
@@ -7514,9 +7491,6 @@ static int mysql_init_variables(void)
character_set_filesystem= &my_charset_bin;
opt_specialflag= SPECIAL_ENGLISH;
-#ifndef EMBEDDED_LIBRARY
- unix_sock= base_ip_sock= extra_ip_sock= MYSQL_INVALID_SOCKET;
-#endif
mysql_home_ptr= mysql_home;
log_error_file_ptr= log_error_file;
protocol_version= PROTOCOL_VERSION;
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 2a73e518ded..64cf1c5ebb0 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -147,7 +147,6 @@ extern ulong opt_replicate_events_marked_for_skip;
extern char *default_tz_name;
extern Time_zone *default_tz;
extern char *my_bind_addr_str;
-extern int server_socket_ai_family;
extern char *default_storage_engine, *default_tmp_storage_engine;
extern char *enforced_storage_engine;
extern char *gtid_pos_auto_engines;