Commit 08098366 authored by Daniel Black's avatar Daniel Black Committed by Sergey Vojtovich

MDEV-15655: Add Linux abstract socket support

The functionality of the socket system variable is extended
here such that a preciding '@' indicates that the socket
will be an abstract socket. Thie socket name wil be
the remainder of the name after the '@'. This is consistent
with the approached used by systemd in socket activation.

Thanks to Sergey Vojtovich:

On OS X sockaddr_un is defined as:

struct sockaddr_un
{
  u_char sun_len;
  u_char sun_family;
  char  sun_path[104];
};

There is a comment in man 7 unix (on linux):

"
On Linux, the above offsetof() expression equates to the same value as sizeof(sa_family_t),
but some other implementations include other fields before sun_path, so the offsetof()
expression more portably describes the size of the address structure.
"

As such, use the offsetof for Linux and use the previous sizeof(UNIXaddr)
for non-unix platforms as that's what worked before and they don't
support abstract sockets so there's no compatibility problem..

strace -fe trace=networking mysqld --skip-networking --socket @abc ...
...
[pid 10578] socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0) = 22
[pid 10578] setsockopt(22, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
[pid 10578] bind(22, {sa_family=AF_UNIX, sun_path=@"abc"}, 6) = 0
[pid 10578] listen(22, 80)              = 0
...
Version: '10.3.6-MariaDB-log'  socket: '@abc'  port: 0  Source distribution

$ lsof -p 10578
mysqld  10578  dan   22u  unix 0x00000000087e688c       0t0 4787815 @abc type=STREAM
parent eaaf004c
...@@ -6010,9 +6010,10 @@ void do_connect(struct st_command *command) ...@@ -6010,9 +6010,10 @@ void do_connect(struct st_command *command)
{ {
/* /*
If the socket is specified just as a name without path If the socket is specified just as a name without path
or an abstract socket indicator ('@'), then
append tmpdir in front append tmpdir in front
*/ */
if (*ds_sock.str != FN_LIBCHAR) if (*ds_sock.str != FN_LIBCHAR && *ds_sock.str != '@')
{ {
char buff[FN_REFLEN]; char buff[FN_REFLEN];
fn_format(buff, ds_sock.str, TMPDIR, "", 0); fn_format(buff, ds_sock.str, TMPDIR, "", 0);
......
!include include/default_my.cnf
[mysqld.1]
socket= @ENV.ABSTRACT_SOCKET
# Using @OPT.port here for uniqueness
[ENV]
ABSTRACT_SOCKET= @mtr-test-abstract-socket-@OPT.port
connect con1,localhost,root,,test,,$ABSTRACT_SOCKET;
select 1;
1
1
disconnect con1;
--source include/linux.inc
--source include/not_embedded.inc
connect(con1,localhost,root,,test,,$ABSTRACT_SOCKET);
select 1;
disconnect con1;
...@@ -2784,9 +2784,10 @@ static void network_init(void) ...@@ -2784,9 +2784,10 @@ static void network_init(void)
*/ */
if (mysqld_unix_port[0] && !opt_bootstrap) if (mysqld_unix_port[0] && !opt_bootstrap)
{ {
size_t port_len;
DBUG_PRINT("general",("UNIX Socket is %s",mysqld_unix_port)); DBUG_PRINT("general",("UNIX Socket is %s",mysqld_unix_port));
if (strlen(mysqld_unix_port) > (sizeof(UNIXaddr.sun_path) - 1)) if ((port_len=strlen(mysqld_unix_port)) > (sizeof(UNIXaddr.sun_path) - 1))
{ {
sql_print_error("The socket file path is too long (> %u): %s", sql_print_error("The socket file path is too long (> %u): %s",
(uint) sizeof(UNIXaddr.sun_path) - 1, mysqld_unix_port); (uint) sizeof(UNIXaddr.sun_path) - 1, mysqld_unix_port);
...@@ -2804,14 +2805,25 @@ static void network_init(void) ...@@ -2804,14 +2805,25 @@ static void network_init(void)
bzero((char*) &UNIXaddr, sizeof(UNIXaddr)); bzero((char*) &UNIXaddr, sizeof(UNIXaddr));
UNIXaddr.sun_family = AF_UNIX; UNIXaddr.sun_family = AF_UNIX;
strmov(UNIXaddr.sun_path, mysqld_unix_port); strmov(UNIXaddr.sun_path, mysqld_unix_port);
(void) unlink(mysqld_unix_port); #if defined(__linux__)
/* Abstract socket */
if (mysqld_unix_port[0] == '@')
UNIXaddr.sun_path[0]= '\0';
else
#endif
(void) unlink(mysqld_unix_port);
arg= 1; arg= 1;
(void) mysql_socket_setsockopt(unix_sock,SOL_SOCKET,SO_REUSEADDR, (void) mysql_socket_setsockopt(unix_sock,SOL_SOCKET,SO_REUSEADDR,
(char*)&arg, sizeof(arg)); (char*)&arg, sizeof(arg));
umask(0); umask(0);
if (mysql_socket_bind(unix_sock, if (mysql_socket_bind(unix_sock,
reinterpret_cast<struct sockaddr *>(&UNIXaddr), reinterpret_cast<struct sockaddr *>(&UNIXaddr),
sizeof(UNIXaddr)) < 0) #if defined(__linux__)
offsetof(struct sockaddr_un, sun_path) + port_len
#else
sizeof(UNIXaddr)
#endif
) < 0)
{ {
sql_perror("Can't start server : Bind on unix socket"); /* purecov: tested */ sql_perror("Can't start server : Bind on unix socket"); /* purecov: tested */
sql_print_error("Do you already have another mysqld server running on socket: %s ?",mysqld_unix_port); sql_print_error("Do you already have another mysqld server running on socket: %s ?",mysqld_unix_port);
......
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