Commit b3abcf80 authored by Rinat Ibragimov's avatar Rinat Ibragimov Committed by Daniel Black

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
parent f691d986
...@@ -75,6 +75,15 @@ struct st_mysql_socket ...@@ -75,6 +75,15 @@ struct st_mysql_socket
/** The real socket descriptor. */ /** The real socket descriptor. */
my_socket fd; 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. The instrumentation hook.
Note that this hook is not conditionally defined, Note that this hook is not conditionally defined,
...@@ -105,7 +114,7 @@ typedef struct st_mysql_socket MYSQL_SOCKET; ...@@ -105,7 +114,7 @@ typedef struct st_mysql_socket MYSQL_SOCKET;
static inline MYSQL_SOCKET static inline MYSQL_SOCKET
mysql_socket_invalid() mysql_socket_invalid()
{ {
MYSQL_SOCKET mysql_socket= {INVALID_SOCKET, NULL}; MYSQL_SOCKET mysql_socket= {INVALID_SOCKET, 0, 0, 0, NULL};
return mysql_socket; return mysql_socket;
} }
......
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;
--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
...@@ -80,15 +80,16 @@ Expect 1 ...@@ -80,15 +80,16 @@ Expect 1
1 1
# Characteristics of 'server_tcpip_socket' entry # Characteristics of 'server_tcpip_socket' entry
# Server listening socket, TCP/IP # Server listening socket, TCP/IP
# There is only one entry with 'wait/io/socket/sql/server_tcpip_socket'. # There are two entries with 'wait/io/socket/sql/server_tcpip_socket',
# It shares the same thread id as 'wait/io/socket/sql/server_unix_socket'. # for [::] and for 0.0.0.0.
SELECT COUNT(*) = 1 AS 'Expect 1' # 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 FROM performance_schema.socket_instances
WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket'; WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket';
Expect 1 Expect 1
1 1
# Get the 'server_tcpip_socket' thread id # 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 FROM performance_schema.socket_instances
WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket'; WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket';
# Check the content. # Check the content.
...@@ -100,6 +101,7 @@ FROM performance_schema.socket_instances ...@@ -100,6 +101,7 @@ FROM performance_schema.socket_instances
WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket'; WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket';
Expect 1 Expect 1
1 1
1
# Characteristics of 'server_unix_socket' entry # Characteristics of 'server_unix_socket' entry
# Server listening socket, unix domain (socket file) # Server listening socket, unix domain (socket file)
# There is only one entry with 'wait/io/socket/sql/server_unix_socket'. # 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'; ...@@ -123,12 +125,12 @@ WHERE EVENT_NAME = 'wait/io/socket/sql/server_unix_socket';
Expect 1 Expect 1
1 1
# Server listening sockets (TCP and Unix) are handled on the same thread # 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 FROM performance_schema.socket_instances
WHERE THREAD_ID = @thread_id; WHERE THREAD_ID = @thread_id;
Expect 1 Expect 1
1 1
SELECT COUNT(*) = 2 AS 'Expect 1' SELECT COUNT(*) = 3 AS 'Expect 1'
FROM performance_schema.socket_instances FROM performance_schema.socket_instances
WHERE THREAD_ID = @thread_id; WHERE THREAD_ID = @thread_id;
Expect 1 Expect 1
......
...@@ -38,6 +38,10 @@ if($my_socket_debug) ...@@ -38,6 +38,10 @@ if($my_socket_debug)
--echo IPV6=$check_ipv6_supported, IPV4_MAPPED=$check_ipv4_mapped_supported, LOCALHOST=$my_localhost --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 # Preserve the current state of SOCKET_INSTANCES
# #
...@@ -222,17 +226,18 @@ AND PORT = 0 AND THREAD_ID = @thread_id; ...@@ -222,17 +226,18 @@ AND PORT = 0 AND THREAD_ID = @thread_id;
--echo # Characteristics of 'server_tcpip_socket' entry --echo # Characteristics of 'server_tcpip_socket' entry
--echo # Server listening socket, TCP/IP --echo # Server listening socket, TCP/IP
--echo # There is only one entry with 'wait/io/socket/sql/server_tcpip_socket'. --echo # There are two entries with 'wait/io/socket/sql/server_tcpip_socket',
--echo # It shares the same thread id as 'wait/io/socket/sql/server_unix_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 FROM performance_schema.socket_instances
WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket'; WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket';
# Store the thread id of server_tcpip_socket # Store the thread id of server_tcpip_socket
--echo # Get the 'server_tcpip_socket' thread id --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 FROM performance_schema.socket_instances
WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket'; WHERE EVENT_NAME = 'wait/io/socket/sql/server_tcpip_socket';
...@@ -288,14 +293,14 @@ WHERE EVENT_NAME = 'wait/io/socket/sql/server_unix_socket'; ...@@ -288,14 +293,14 @@ WHERE EVENT_NAME = 'wait/io/socket/sql/server_unix_socket';
--disable_query_log ONCE --disable_query_log ONCE
eval SET @thread_id = $server_tcpip_thread_id; 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 FROM performance_schema.socket_instances
WHERE THREAD_ID = @thread_id; WHERE THREAD_ID = @thread_id;
--disable_query_log ONCE --disable_query_log ONCE
eval SET @thread_id = $server_unix_thread_id; 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 FROM performance_schema.socket_instances
WHERE THREAD_ID = @thread_id; WHERE THREAD_ID = @thread_id;
......
...@@ -12,7 +12,7 @@ log-bin= master-bin ...@@ -12,7 +12,7 @@ log-bin= master-bin
loose-innodb loose-innodb
skip-name-resolve skip-name-resolve
bind-address= :: bind-address= *
[mysqld.2] [mysqld.2]
...@@ -38,7 +38,7 @@ report-user= root ...@@ -38,7 +38,7 @@ report-user= root
skip-slave-start skip-slave-start
skip-name-resolve skip-name-resolve
bind-address= :: bind-address= *
# Directory where slaves find the dumps generated by "load data" # Directory where slaves find the dumps generated by "load data"
# on the server. The path need to have constant length otherwise # on the server. The path need to have constant length otherwise
......
...@@ -22,11 +22,13 @@ ...@@ -22,11 +22,13 @@
#include <mswsock.h> #include <mswsock.h>
#include <mysql/psi/mysql_socket.h> #include <mysql/psi/mysql_socket.h>
#include <sddl.h> #include <sddl.h>
#include <vector>
#include <handle_connections_win.h> #include <handle_connections_win.h>
/* From mysqld.cc */ /* 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 #ifdef HAVE_POOL_OF_THREADS
extern PTP_CALLBACK_ENVIRON get_threadpool_win_callback_environ(); extern PTP_CALLBACK_ENVIRON get_threadpool_win_callback_environ();
extern void tp_win_callback_prolog(); extern void tp_win_callback_prolog();
...@@ -128,6 +130,9 @@ struct Socket_Listener: public Listener ...@@ -128,6 +130,9 @@ struct Socket_Listener: public Listener
/** Client socket passed to AcceptEx() call.*/ /** Client socket passed to AcceptEx() call.*/
SOCKET m_client_socket; SOCKET m_client_socket;
/** Listening socket. */
MYSQL_SOCKET m_listen_socket;
/** Buffer for sockaddrs passed to AcceptEx()/GetAcceptExSockaddrs() */ /** Buffer for sockaddrs passed to AcceptEx()/GetAcceptExSockaddrs() */
char m_buffer[2 * sizeof(sockaddr_storage) + 32]; char m_buffer[2 * sizeof(sockaddr_storage) + 32];
...@@ -162,7 +167,8 @@ struct Socket_Listener: public Listener ...@@ -162,7 +167,8 @@ struct Socket_Listener: public Listener
*/ */
Socket_Listener(MYSQL_SOCKET listen_socket, PTP_CALLBACK_ENVIRON callback_environ) : Socket_Listener(MYSQL_SOCKET listen_socket, PTP_CALLBACK_ENVIRON callback_environ) :
Listener((HANDLE)listen_socket.fd,0), Listener((HANDLE)listen_socket.fd,0),
m_client_socket(INVALID_SOCKET) m_client_socket(INVALID_SOCKET),
m_listen_socket(listen_socket)
{ {
if (callback_environ) if (callback_environ)
{ {
...@@ -184,7 +190,8 @@ struct Socket_Listener: public Listener ...@@ -184,7 +190,8 @@ struct Socket_Listener: public Listener
void begin_accept() void begin_accept()
{ {
retry : 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) if (m_client_socket == INVALID_SOCKET)
{ {
sql_perror("socket() call failed."); sql_perror("socket() call failed.");
...@@ -233,7 +240,6 @@ retry : ...@@ -233,7 +240,6 @@ retry :
} }
MYSQL_SOCKET s_client{m_client_socket}; MYSQL_SOCKET s_client{m_client_socket};
MYSQL_SOCKET s_listen{(SOCKET)m_handle};
#ifdef HAVE_PSI_SOCKET_INTERFACE #ifdef HAVE_PSI_SOCKET_INTERFACE
/* Parse socket addresses buffer filled by AcceptEx(), /* Parse socket addresses buffer filled by AcceptEx(),
...@@ -246,7 +252,8 @@ retry : ...@@ -246,7 +252,8 @@ retry :
&local_addr, &local_addr_len, &remote_addr, &remote_addr_len); &local_addr, &local_addr_len, &remote_addr, &remote_addr_len);
s_client.m_psi= PSI_SOCKET_CALL(init_socket) 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 #endif
/* Start accepting new connection. After this point, do not use /* Start accepting new connection. After this point, do not use
...@@ -255,7 +262,7 @@ retry : ...@@ -255,7 +262,7 @@ retry :
/* Some chores post-AcceptEx() that we need to create a normal socket.*/ /* Some chores post-AcceptEx() that we need to create a normal socket.*/
if (setsockopt(s_client.fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, 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) if (!abort_loop)
{ {
...@@ -265,7 +272,7 @@ retry : ...@@ -265,7 +272,7 @@ retry :
} }
/* Create a new connection.*/ /* Create a new connection.*/
handle_accepted_socket(s_client, s_listen); handle_accepted_socket(s_client, m_listen_socket);
} }
~Socket_Listener() ~Socket_Listener()
...@@ -280,14 +287,12 @@ retry : ...@@ -280,14 +287,12 @@ retry :
*/ */
static void init_winsock_extensions() static void init_winsock_extensions()
{ {
SOCKET s= mysql_socket_getfd(base_ip_sock); if (listen_sockets.size() == 0) {
if (s == INVALID_SOCKET)
s= mysql_socket_getfd(extra_ip_sock);
if (s == INVALID_SOCKET)
{
/* --skip-networking was used*/ /* --skip-networking was used*/
return; return;
} }
SOCKET s= mysql_socket_getfd(listen_sockets[0]);
GUID guid_AcceptEx= WSAID_ACCEPTEX; GUID guid_AcceptEx= WSAID_ACCEPTEX;
GUID guid_GetAcceptExSockaddrs= WSAID_GETACCEPTEXSOCKADDRS; GUID guid_GetAcceptExSockaddrs= WSAID_GETACCEPTEXSOCKADDRS;
...@@ -540,22 +545,24 @@ static void create_shutdown_event() ...@@ -540,22 +545,24 @@ static void create_shutdown_event()
*/ */
#define MAX_WAIT_HANDLES 32
#define NUM_PIPE_LISTENERS 24 #define NUM_PIPE_LISTENERS 24
#define SHUTDOWN_IDX 0 #define SHUTDOWN_IDX 0
#define LISTENER_START_IDX 1 #define LISTENER_START_IDX 1
static Listener *all_listeners[MAX_WAIT_HANDLES]; static std::vector<Listener *> all_listeners;
static HANDLE wait_events[MAX_WAIT_HANDLES]; static std::vector<HANDLE> wait_events;
static int n_listeners;
void network_init_win() void network_init_win()
{ {
Socket_Listener::init_winsock_extensions(); Socket_Listener::init_winsock_extensions();
/* Listen for TCP connections on "extra-port" (no threadpool).*/ /* Listen for TCP connections on "extra-port" (no threadpool).*/
if (extra_ip_sock.fd != INVALID_SOCKET) for (std::vector<MYSQL_SOCKET>::iterator it= listen_sockets.begin();
all_listeners[n_listeners++]= new Socket_Listener(extra_ip_sock, 0); it != listen_sockets.end(); ++it)
{
if (it->is_extra_port)
all_listeners.push_back(new Socket_Listener(*it, 0));
}
/* Listen for named pipe connections */ /* Listen for named pipe connections */
if (mysqld_unix_port[0] && !opt_bootstrap && opt_enable_named_pipe) if (mysqld_unix_port[0] && !opt_bootstrap && opt_enable_named_pipe)
...@@ -564,17 +571,22 @@ void network_init_win() ...@@ -564,17 +571,22 @@ void network_init_win()
Use several listeners for pipe, to reduce ERROR_PIPE_BUSY on client side. Use several listeners for pipe, to reduce ERROR_PIPE_BUSY on client side.
*/ */
for (int i= 0; i < NUM_PIPE_LISTENERS; i++) 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)
{ {
if (it->is_extra_port)
continue;
/* Wait for TCP connections.*/ /* Wait for TCP connections.*/
SetFileCompletionNotificationModes((HANDLE)base_ip_sock.fd, FILE_SKIP_SET_EVENT_ON_HANDLE); SetFileCompletionNotificationModes((HANDLE)it->fd,
all_listeners[n_listeners++]= new Socket_Listener(base_ip_sock, get_threadpool_win_callback_environ()); 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."); sql_print_error("Either TCP connections or named pipe connections must be enabled.");
unireg_abort(1); unireg_abort(1);
...@@ -586,26 +598,41 @@ void handle_connections_win() ...@@ -586,26 +598,41 @@ void handle_connections_win()
int n_waits; int n_waits;
create_shutdown_event(); create_shutdown_event();
wait_events[SHUTDOWN_IDX]= hEventShutdown; wait_events.push_back(hEventShutdown);
n_waits= 1; 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(); HANDLE wait_handle= all_listeners[i]->wait_handle();
if (wait_handle) if (wait_handle)
{ {
DBUG_ASSERT((i == 0) || (all_listeners[i - 1]->wait_handle() != 0)); 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(); all_listeners[i]->begin_accept();
} }
mysqld_win_set_startup_complete(); 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 (;;) for (;;)
{ {
DWORD idx = WaitForMultipleObjects(n_waits ,wait_events, FALSE, INFINITE); DBUG_ASSERT(wait_events.size() <= MAXIMUM_WAIT_OBJECTS);
DBUG_ASSERT((int)idx >= 0 && (int)idx < n_waits); 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) if (idx == SHUTDOWN_IDX)
break; break;
...@@ -616,7 +643,7 @@ void handle_connections_win() ...@@ -616,7 +643,7 @@ void handle_connections_win()
mysqld_win_initiate_shutdown(); mysqld_win_initiate_shutdown();
/* Cleanup */ /* Cleanup */
for (int i= 0; i < n_listeners; i++) for (size_t i= 0; i < all_listeners.size(); i++)
{ {
Listener *listener= all_listeners[i]; Listener *listener= all_listeners[i];
if (listener->wait_handle()) if (listener->wait_handle())
......
...@@ -338,7 +338,6 @@ static char *character_set_filesystem_name; ...@@ -338,7 +338,6 @@ static char *character_set_filesystem_name;
static char *lc_messages; static char *lc_messages;
static char *lc_time_names_name; static char *lc_time_names_name;
char *my_bind_addr_str; char *my_bind_addr_str;
int server_socket_ai_family;
static char *default_collation_name; static char *default_collation_name;
char *default_storage_engine, *default_tmp_storage_engine; char *default_storage_engine, *default_tmp_storage_engine;
char *enforced_storage_engine=NULL; char *enforced_storage_engine=NULL;
...@@ -1349,7 +1348,8 @@ static Buffered_logs buffered_logs; ...@@ -1349,7 +1348,8 @@ static Buffered_logs buffered_logs;
struct my_rnd_struct sql_rand; ///< used by sql_class.cc:THD::THD() struct my_rnd_struct sql_rand; ///< used by sql_class.cc:THD::THD()
#ifndef EMBEDDED_LIBRARY #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. Error reporter that buffer log messages.
@param level log message level @param level log message level
...@@ -1690,28 +1690,15 @@ static void close_connections(void) ...@@ -1690,28 +1690,15 @@ static void close_connections(void)
/* Abort listening to new connections */ /* Abort listening to new connections */
DBUG_PRINT("quit",("Closing sockets")); 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(*sock);
{ if (sock->is_unix_domain_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;
}
}
#ifdef HAVE_SYS_UN_H
if (mysql_socket_getfd(unix_sock) != INVALID_SOCKET)
{
(void) mysql_socket_close(unix_sock);
(void) unlink(mysqld_unix_port); (void) unlink(mysqld_unix_port);
unix_sock= MYSQL_INVALID_SOCKET;
} }
#endif listen_sockets.clear();
end_thr_alarm(0); // Abort old alarms. end_thr_alarm(0); // Abort old alarms.
/* /*
...@@ -1800,13 +1787,20 @@ static void close_server_sock() ...@@ -1800,13 +1787,20 @@ static void close_server_sock()
#ifdef HAVE_CLOSE_SERVER_SOCK #ifdef HAVE_CLOSE_SERVER_SOCK
DBUG_ENTER("close_server_sock"); DBUG_ENTER("close_server_sock");
close_socket(base_ip_sock, "TCP/IP"); for (std::vector<MYSQL_SOCKET>::iterator sock= listen_sockets.begin();
close_socket(extra_ip_sock, "TCP/IP"); sock != listen_sockets.end(); ++sock)
close_socket(unix_sock, "unix/IP"); {
if (sock->is_unix_domain_socket)
if (mysql_socket_getfd(unix_sock) != INVALID_SOCKET) {
close_socket(*sock, "unix/IP");
(void) unlink(mysqld_unix_port); (void) unlink(mysqld_unix_port);
base_ip_sock= extra_ip_sock= unix_sock= MYSQL_INVALID_SOCKET; }
else
{
close_socket(*sock, "TCP/IP");
}
}
listen_sockets.clear();
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
#endif #endif
...@@ -2241,7 +2235,9 @@ static void set_root(const char *path) ...@@ -2241,7 +2235,9 @@ static void set_root(const char *path)
Activate usage of a tcp port 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 *ai, *a;
struct addrinfo hints; struct addrinfo hints;
...@@ -2273,20 +2269,6 @@ static MYSQL_SOCKET activate_tcp_port(uint port) ...@@ -2273,20 +2269,6 @@ static MYSQL_SOCKET activate_tcp_port(uint port)
unireg_abort(1); /* purecov: tested */ 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) for (a= ai; a != NULL; a= a->ai_next)
{ {
ip_sock= mysql_socket_socket(key_socket_tcpip, a->ai_family, ip_sock= mysql_socket_socket(key_socket_tcpip, a->ai_family,
...@@ -2309,12 +2291,9 @@ static MYSQL_SOCKET activate_tcp_port(uint port) ...@@ -2309,12 +2291,9 @@ static MYSQL_SOCKET activate_tcp_port(uint port)
} }
else else
{ {
server_socket_ai_family= a->ai_family; ip_sock.address_family= a->ai_family;
sql_print_information("Server socket created on IP: '%s'.", sql_print_information("Server socket created on IP: '%s'.",
(const char *) ip_addr); (const char *) ip_addr);
break;
}
}
if (mysql_socket_getfd(ip_sock) == INVALID_SOCKET) if (mysql_socket_getfd(ip_sock) == INVALID_SOCKET)
{ {
...@@ -2331,23 +2310,20 @@ static MYSQL_SOCKET activate_tcp_port(uint port) ...@@ -2331,23 +2310,20 @@ static MYSQL_SOCKET activate_tcp_port(uint port)
user to open two mysqld servers with the same TCP/IP port. user to open two mysqld servers with the same TCP/IP port.
*/ */
arg= 1; arg= 1;
(void) mysql_socket_setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg, (void) mysql_socket_setsockopt(ip_sock, SOL_SOCKET, SO_REUSEADDR,
sizeof(arg)); (char*)&arg, sizeof(arg));
#endif /* __WIN__ */ #endif /* __WIN__ */
#ifdef IPV6_V6ONLY #ifdef IPV6_V6ONLY
/* /*
For interoperability with older clients, IPv6 socket should If an address name resolves to both IPv4 and IPv6 addresses, the server
listen on both IPv6 and IPv4 wildcard addresses. will listen on them both. With IPV6_V6ONLY unset, listening on an IPv6
Turn off IPV6_V6ONLY option. wildcard address may cause listening on an IPv4 wildcard address
to fail. That's why IPV6_V6ONLY needs to be forcefully turned on.
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) if (a->ai_family == AF_INET6)
{ {
arg= 0; arg= 1;
(void) mysql_socket_setsockopt(ip_sock, IPPROTO_IPV6, IPV6_V6ONLY, (void) mysql_socket_setsockopt(ip_sock, IPPROTO_IPV6, IPV6_V6ONLY,
(char*)&arg, sizeof(arg)); (char*)&arg, sizeof(arg));
} }
...@@ -2355,8 +2331,8 @@ static MYSQL_SOCKET activate_tcp_port(uint port) ...@@ -2355,8 +2331,8 @@ static MYSQL_SOCKET activate_tcp_port(uint port)
#ifdef IP_FREEBIND #ifdef IP_FREEBIND
arg= 1; arg= 1;
(void) mysql_socket_setsockopt(ip_sock, IPPROTO_IP, IP_FREEBIND, (char*) &arg, (void) mysql_socket_setsockopt(ip_sock, IPPROTO_IP, IP_FREEBIND,
sizeof(arg)); (char*) &arg, sizeof(arg));
#endif #endif
/* /*
Sometimes the port is not released fast enough when stopping and Sometimes the port is not released fast enough when stopping and
...@@ -2370,15 +2346,15 @@ static MYSQL_SOCKET activate_tcp_port(uint port) ...@@ -2370,15 +2346,15 @@ static MYSQL_SOCKET activate_tcp_port(uint port)
uint waited, retry, this_wait; uint waited, retry, this_wait;
for (waited= 0, retry= 1; ; retry++, waited+= 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 ) || if (((ret= mysql_socket_bind(ip_sock, a->ai_addr, a->ai_addrlen)) >= 0 )
(socket_errno != SOCKET_EADDRINUSE) || || (socket_errno != SOCKET_EADDRINUSE)
(waited >= mysqld_port_timeout)) || (waited >= mysqld_port_timeout))
break; break;
sql_print_information("Retrying bind on TCP/IP port %u", port); sql_print_information("Retrying bind on TCP/IP port %u", port);
this_wait= retry * retry / 3 + 1; this_wait= retry * retry / 3 + 1;
sleep(this_wait); sleep(this_wait);
} }
freeaddrinfo(ai);
if (ret < 0) if (ret < 0)
{ {
char buff[100]; char buff[100];
...@@ -2400,8 +2376,13 @@ static MYSQL_SOCKET activate_tcp_port(uint port) ...@@ -2400,8 +2376,13 @@ static MYSQL_SOCKET activate_tcp_port(uint port)
#ifdef FD_CLOEXEC #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 #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) static void network_init(void)
...@@ -2431,9 +2412,11 @@ static void network_init(void) ...@@ -2431,9 +2412,11 @@ static void network_init(void)
if (!opt_disable_networking && !opt_bootstrap) if (!opt_disable_networking && !opt_bootstrap)
{ {
if (mysqld_port) 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) 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) #if defined(HAVE_SYS_UN_H)
...@@ -2442,6 +2425,7 @@ static void network_init(void) ...@@ -2442,6 +2425,7 @@ static void network_init(void)
*/ */
if (mysqld_unix_port[0] && !opt_bootstrap) if (mysqld_unix_port[0] && !opt_bootstrap)
{ {
MYSQL_SOCKET unix_sock= MYSQL_INVALID_SOCKET;
size_t port_len; size_t port_len;
DBUG_PRINT("general",("UNIX Socket is %s",mysqld_unix_port)); DBUG_PRINT("general",("UNIX Socket is %s",mysqld_unix_port));
...@@ -2458,6 +2442,9 @@ static void network_init(void) ...@@ -2458,6 +2442,9 @@ static void network_init(void)
unireg_abort(1); /* purecov: inspected */ 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); mysql_socket_set_thread_owner(unix_sock);
bzero((char*) &UNIXaddr, sizeof(UNIXaddr)); bzero((char*) &UNIXaddr, sizeof(UNIXaddr));
...@@ -5645,8 +5632,7 @@ int mysqld_main(int argc, char **argv) ...@@ -5645,8 +5632,7 @@ int mysqld_main(int argc, char **argv)
if (IS_SYSVAR_AUTOSIZE(&server_version_ptr)) if (IS_SYSVAR_AUTOSIZE(&server_version_ptr))
sql_print_information(ER_DEFAULT(ER_STARTUP), my_progname, server_version, sql_print_information(ER_DEFAULT(ER_STARTUP), my_progname, server_version,
((mysql_socket_getfd(unix_sock) == INVALID_SOCKET) ? (unix_sock_is_online ? mysqld_unix_port : (char*) ""),
(char*) "" : mysqld_unix_port),
mysqld_port, MYSQL_COMPILATION_COMMENT); mysqld_port, MYSQL_COMPILATION_COMMENT);
else else
{ {
...@@ -5658,8 +5644,7 @@ int mysqld_main(int argc, char **argv) ...@@ -5658,8 +5644,7 @@ int mysqld_main(int argc, char **argv)
sql_print_information(ER_DEFAULT(ER_STARTUP), my_progname, sql_print_information(ER_DEFAULT(ER_STARTUP), my_progname,
real_server_version, real_server_version,
((mysql_socket_getfd(unix_sock) == INVALID_SOCKET) ? (unix_sock_is_online ? mysqld_unix_port : (char*) ""),
(char*) "" : mysqld_unix_port),
mysqld_port, MYSQL_COMPILATION_COMMENT); mysqld_port, MYSQL_COMPILATION_COMMENT);
} }
...@@ -5866,8 +5851,7 @@ void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock) ...@@ -5866,8 +5851,7 @@ void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock)
{ {
#ifdef HAVE_LIBWRAP #ifdef HAVE_LIBWRAP
{ {
if (mysql_socket_getfd(sock) == mysql_socket_getfd(base_ip_sock) || if (!sock.is_unix_domain_socket)
mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock))
{ {
struct request_info req; struct request_info req;
signal(SIGCHLD, SIG_DFL); signal(SIGCHLD, SIG_DFL);
...@@ -5910,11 +5894,9 @@ void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock) ...@@ -5910,11 +5894,9 @@ void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock)
DBUG_PRINT("info", ("Creating CONNECT for new connection")); DBUG_PRINT("info", ("Creating CONNECT for new connection"));
if (auto connect= new CONNECT(new_sock, if (auto connect= new CONNECT(new_sock,
mysql_socket_getfd(sock) == sock.is_unix_domain_socket ?
mysql_socket_getfd(unix_sock) ?
VIO_TYPE_SOCKET : VIO_TYPE_TCPIP, VIO_TYPE_SOCKET : VIO_TYPE_TCPIP,
mysql_socket_getfd(sock) == sock.is_extra_port ?
mysql_socket_getfd(extra_ip_sock) ?
extra_thread_scheduler : thread_scheduler)) extra_thread_scheduler : thread_scheduler))
create_new_thread(connect); create_new_thread(connect);
else else
...@@ -5950,36 +5932,30 @@ void handle_connections_sockets() ...@@ -5950,36 +5932,30 @@ void handle_connections_sockets()
struct sockaddr_storage cAddr; struct sockaddr_storage cAddr;
int retval; int retval;
#ifdef HAVE_POLL #ifdef HAVE_POLL
int socket_count= 0; std::vector<struct pollfd> fds; // for ip_sock, unix_sock and extra_ip_sock
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++
#else #else
#define setup_fds(X) FD_SET(mysql_socket_getfd(X),&clientFDs)
fd_set readFDs,clientFDs; fd_set readFDs,clientFDs;
FD_ZERO(&clientFDs);
#endif #endif
DBUG_ENTER("handle_connections_sockets"); 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); mysql_socket_set_thread_owner(listen_sockets[i]);
set_non_blocking_if_supported(base_ip_sock); 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); int fd= mysql_socket_getfd(listen_sockets[i]);
set_non_blocking_if_supported(extra_ip_sock); 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 #endif
sd_notify(0, "READY=1\n" sd_notify(0, "READY=1\n"
...@@ -5989,10 +5965,10 @@ void handle_connections_sockets() ...@@ -5989,10 +5965,10 @@ void handle_connections_sockets()
while (!abort_loop) while (!abort_loop)
{ {
#ifdef HAVE_POLL #ifdef HAVE_POLL
retval= poll(fds, socket_count, -1); retval= poll(fds.data(), fds.size(), -1);
#else #else
readFDs=clientFDs; readFDs=clientFDs;
retval= select((int) 0,&readFDs,0,0,0); retval= select(FD_SETSIZE, &readFDs, NULL, NULL, NULL);
#endif #endif
if (retval < 0) if (retval < 0)
...@@ -6016,22 +5992,23 @@ void handle_connections_sockets() ...@@ -6016,22 +5992,23 @@ void handle_connections_sockets()
/* Is this a new connection request ? */ /* Is this a new connection request ? */
#ifdef HAVE_POLL #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) if (fds[i].revents & POLLIN)
{ {
sock= pfs_fds[i]; sock= listen_sockets[i];
break; break;
} }
} }
#else // HAVE_POLL #else // HAVE_POLL
if (FD_ISSET(mysql_socket_getfd(base_ip_sock),&readFDs)) for (size_t i=0; i < listen_sockets.size(); i++)
sock= base_ip_sock; {
else if (FD_ISSET(mysql_socket_getfd(listen_sockets[i]), &readFDs))
if (FD_ISSET(mysql_socket_getfd(extra_ip_sock),&readFDs)) {
sock= extra_ip_sock; sock= listen_sockets[i];
else break;
sock = unix_sock; }
}
#endif // HAVE_POLL #endif // HAVE_POLL
for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++) for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++)
...@@ -7514,9 +7491,6 @@ static int mysql_init_variables(void) ...@@ -7514,9 +7491,6 @@ static int mysql_init_variables(void)
character_set_filesystem= &my_charset_bin; character_set_filesystem= &my_charset_bin;
opt_specialflag= SPECIAL_ENGLISH; opt_specialflag= SPECIAL_ENGLISH;
#ifndef EMBEDDED_LIBRARY
unix_sock= base_ip_sock= extra_ip_sock= MYSQL_INVALID_SOCKET;
#endif
mysql_home_ptr= mysql_home; mysql_home_ptr= mysql_home;
log_error_file_ptr= log_error_file; log_error_file_ptr= log_error_file;
protocol_version= PROTOCOL_VERSION; protocol_version= PROTOCOL_VERSION;
......
...@@ -147,7 +147,6 @@ extern ulong opt_replicate_events_marked_for_skip; ...@@ -147,7 +147,6 @@ extern ulong opt_replicate_events_marked_for_skip;
extern char *default_tz_name; extern char *default_tz_name;
extern Time_zone *default_tz; extern Time_zone *default_tz;
extern char *my_bind_addr_str; extern char *my_bind_addr_str;
extern int server_socket_ai_family;
extern char *default_storage_engine, *default_tmp_storage_engine; extern char *default_storage_engine, *default_tmp_storage_engine;
extern char *enforced_storage_engine; extern char *enforced_storage_engine;
extern char *gtid_pos_auto_engines; extern char *gtid_pos_auto_engines;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment