1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-11 16:58:40 +03:00

ctdb-tcp: Factor out listening code to avoid repetition

Modernise debug and comments while here.

Signed-off-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Volker Lendecke <vl@samba.org>
This commit is contained in:
Martin Schwenke 2024-07-05 15:51:25 +10:00 committed by Volker Lendecke
parent 2c75bb8687
commit b433663414

View File

@ -386,24 +386,105 @@ static void ctdb_listen_event(struct tevent_context *ev, struct tevent_fd *fde,
}
}
static int ctdb_tcp_listen_addr(struct ctdb_context *ctdb,
ctdb_sock_addr *addr,
bool strict)
{
struct ctdb_tcp *ctcp = talloc_get_type_abort(
ctdb->transport_data, struct ctdb_tcp);
ctdb_sock_addr sock;
int sock_size;
int one = 1;
struct tevent_fd *fde = NULL;
int ret;
sock = *addr;
ctcp->listen_fd = -1;
switch (sock.sa.sa_family) {
case AF_INET:
sock_size = sizeof(sock.ip);
break;
case AF_INET6:
sock_size = sizeof(sock.ip6);
break;
default:
DBG_ERR("Unknown family %u\n", sock.sa.sa_family);
goto failed;
}
ctcp->listen_fd = socket(sock.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
if (ctcp->listen_fd == -1) {
DBG_ERR("Socket failed - %s (%d)\n", strerror(errno), errno);
goto failed;
}
set_close_on_exec(ctcp->listen_fd);
ret = setsockopt(ctcp->listen_fd,
SOL_SOCKET,
SO_REUSEADDR,
(char *)&one,
sizeof(one));
if (ret == -1) {
DBG_WARNING("Failed to set REUSEADDR on fd - %s (%d)\n",
strerror(errno),
errno);
}
ret =bind(ctcp->listen_fd, (struct sockaddr * )&sock, sock_size);
if (ret != 0) {
if (strict || errno != EADDRNOTAVAIL) {
DBG_ERR("Failed to bind() to socket - %s (%d)\n",
strerror(errno),
errno);
} else {
DBG_DEBUG("Failed to bind() to socket - %s (%d)\n",
strerror(errno),
errno);
}
goto failed;
}
ret = listen(ctcp->listen_fd, 10);
if (ret == -1) {
DBG_ERR("Failed to listen() on socket - %s (%d)\n",
strerror(errno),
errno);
goto failed;
}
fde = tevent_add_fd(ctdb->ev,
ctcp,
ctcp->listen_fd,
TEVENT_FD_READ,
ctdb_listen_event,
ctdb);
tevent_fd_set_auto_close(fde);
return 0;
failed:
if (ctcp->listen_fd != -1) {
close(ctcp->listen_fd);
ctcp->listen_fd = -1;
}
return -1;
}
/*
automatically find which address to listen on
*/
static int ctdb_tcp_listen_automatic(struct ctdb_context *ctdb)
{
struct ctdb_tcp *ctcp = talloc_get_type(ctdb->transport_data,
struct ctdb_tcp);
ctdb_sock_addr sock;
int lock_fd;
unsigned int i;
const char *lock_path = CTDB_RUNDIR "/.socket_lock";
struct flock lock;
int one = 1;
int sock_size;
struct tevent_fd *fde;
int ret;
/* If there are no nodes, then it won't be possible to find
/*
* If there are no nodes, then it won't be possible to find
* the first one. Log a failure and short circuit the whole
* process.
*/
@ -412,13 +493,15 @@ static int ctdb_tcp_listen_automatic(struct ctdb_context *ctdb)
return -1;
}
/* in order to ensure that we don't get two nodes with the
same address, we must make the bind() and listen() calls
atomic. The SO_REUSEADDR setsockopt only prevents double
binds if the first socket is in LISTEN state */
/*
* In order to ensure that we don't get two nodes with the
* same address, we must make the bind() and listen() calls
* atomic. The SO_REUSEADDR setsockopt only prevents double
* binds if the first socket is in LISTEN state.
*/
lock_fd = open(lock_path, O_RDWR|O_CREAT, 0666);
if (lock_fd == -1) {
DEBUG(DEBUG_CRIT,("Unable to open %s\n", lock_path));
DBG_ERR("Unable to open %s\n", lock_path);
return -1;
}
@ -429,7 +512,7 @@ static int ctdb_tcp_listen_automatic(struct ctdb_context *ctdb)
lock.l_pid = 0;
if (fcntl(lock_fd, F_SETLKW, &lock) != 0) {
DEBUG(DEBUG_CRIT,("Unable to lock %s\n", lock_path));
DBG_ERR("Unable to lock %s\n", lock_path);
close(lock_fd);
return -1;
}
@ -438,91 +521,36 @@ static int ctdb_tcp_listen_automatic(struct ctdb_context *ctdb)
if (ctdb->nodes[i]->flags & NODE_FLAGS_DELETED) {
continue;
}
sock = ctdb->nodes[i]->address;
switch (sock.sa.sa_family) {
case AF_INET:
sock_size = sizeof(sock.ip);
break;
case AF_INET6:
sock_size = sizeof(sock.ip6);
break;
default:
DEBUG(DEBUG_ERR, (__location__ " unknown family %u\n",
sock.sa.sa_family));
continue;
}
ctcp->listen_fd = socket(sock.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
if (ctcp->listen_fd == -1) {
ctdb_set_error(ctdb, "socket failed\n");
continue;
}
set_close_on_exec(ctcp->listen_fd);
if (setsockopt(ctcp->listen_fd,SOL_SOCKET,SO_REUSEADDR,
(char *)&one,sizeof(one)) == -1) {
DEBUG(DEBUG_WARNING, ("Failed to set REUSEADDR on fd - %s\n",
strerror(errno)));
}
if (bind(ctcp->listen_fd, (struct sockaddr * )&sock, sock_size) == 0) {
ret = ctdb_tcp_listen_addr(ctdb,
&ctdb->nodes[i]->address,
false);
if (ret == 0) {
break;
}
if (errno == EADDRNOTAVAIL) {
DEBUG(DEBUG_DEBUG,(__location__ " Failed to bind() to socket. %s(%d)\n",
strerror(errno), errno));
} else {
DEBUG(DEBUG_ERR,(__location__ " Failed to bind() to socket. %s(%d)\n",
strerror(errno), errno));
}
close(ctcp->listen_fd);
ctcp->listen_fd = -1;
}
if (i == ctdb->num_nodes) {
DEBUG(DEBUG_CRIT,("Unable to bind to any of the node addresses - giving up\n"));
goto failed;
D_ERR("Unable to bind to any node address - giving up\n");
return -1;
}
ctdb->address = talloc_memdup(ctdb,
&ctdb->nodes[i]->address,
sizeof(ctdb_sock_addr));
if (ctdb->address == NULL) {
ctdb_set_error(ctdb, "Out of memory at %s:%d",
__FILE__, __LINE__);
goto failed;
DBG_ERR("Memory allocation error\n");
return -1;
}
ctdb->name = talloc_strdup(ctdb, ctdb->nodes[i]->name);
if (ctdb->name == NULL) {
ctdb_set_error(ctdb, "Out of memory at %s:%d",
__FILE__, __LINE__);
goto failed;
}
DEBUG(DEBUG_INFO,("ctdb chose network address %s\n", ctdb->name));
if (listen(ctcp->listen_fd, 10) == -1) {
goto failed;
DBG_ERR("Memory allocation error\n");
return -1;
}
fde = tevent_add_fd(ctdb->ev, ctcp, ctcp->listen_fd, TEVENT_FD_READ,
ctdb_listen_event, ctdb);
tevent_fd_set_auto_close(fde);
close(lock_fd);
D_INFO("ctdb chose network address %s\n", ctdb->name);
return 0;
failed:
close(lock_fd);
if (ctcp->listen_fd != -1) {
close(ctcp->listen_fd);
ctcp->listen_fd = -1;
}
return -1;
}
@ -531,67 +559,15 @@ failed:
*/
int ctdb_tcp_listen(struct ctdb_context *ctdb)
{
struct ctdb_tcp *ctcp = talloc_get_type(ctdb->transport_data,
struct ctdb_tcp);
ctdb_sock_addr sock;
int sock_size;
int one = 1;
struct tevent_fd *fde;
int ret;
/* we can either auto-bind to the first available address, or we can
use a specified address */
if (!ctdb->address) {
return ctdb_tcp_listen_automatic(ctdb);
ret = ctdb_tcp_listen_automatic(ctdb);
return ret;
}
sock = *ctdb->address;
switch (sock.sa.sa_family) {
case AF_INET:
sock_size = sizeof(sock.ip);
break;
case AF_INET6:
sock_size = sizeof(sock.ip6);
break;
default:
DEBUG(DEBUG_ERR, (__location__ " unknown family %u\n",
sock.sa.sa_family));
goto failed;
}
ctcp->listen_fd = socket(sock.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
if (ctcp->listen_fd == -1) {
ctdb_set_error(ctdb, "socket failed\n");
return -1;
}
set_close_on_exec(ctcp->listen_fd);
if (setsockopt(ctcp->listen_fd,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)) == -1) {
DEBUG(DEBUG_WARNING, ("Failed to set REUSEADDR on fd - %s\n",
strerror(errno)));
}
if (bind(ctcp->listen_fd, (struct sockaddr * )&sock, sock_size) != 0) {
DEBUG(DEBUG_ERR,(__location__ " Failed to bind() to socket. %s(%d)\n", strerror(errno), errno));
goto failed;
}
if (listen(ctcp->listen_fd, 10) == -1) {
goto failed;
}
fde = tevent_add_fd(ctdb->ev, ctcp, ctcp->listen_fd, TEVENT_FD_READ,
ctdb_listen_event, ctdb);
tevent_fd_set_auto_close(fde);
return 0;
failed:
if (ctcp->listen_fd != -1) {
close(ctcp->listen_fd);
}
ctcp->listen_fd = -1;
return -1;
ret = ctdb_tcp_listen_addr(ctdb, ctdb->address, true);
return ret;
}