mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-10-28 11:55:23 +03:00
core: rework how we flush incoming traffic when a socket unit goes down
Previously, we'd simply close and reopen the socket file descriptors. This is problematic however, as we won't transition through the SOCKET_CHOWN state then, and thus the file ownership won't be correct for the sockets. Rework the flushing logic, and actually read any queued data from the sockets for flushing, and accept any queued messages and disconnect them.
This commit is contained in:
parent
01a8b46757
commit
60d9771c59
@ -33,6 +33,11 @@ int flush_fd(int fd) {
|
||||
.events = POLLIN,
|
||||
};
|
||||
|
||||
/* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything
|
||||
* read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read
|
||||
* (due to IP packet checksum mismatches), hence this function is only safe to be non-blocking if the fd used
|
||||
* was set to non-blocking too. */
|
||||
|
||||
for (;;) {
|
||||
char buf[LINE_MAX];
|
||||
ssize_t l;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <poll.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@ -970,3 +971,42 @@ fallback:
|
||||
|
||||
return (ssize_t) k;
|
||||
}
|
||||
|
||||
int flush_accept(int fd) {
|
||||
|
||||
struct pollfd pollfd = {
|
||||
.fd = fd,
|
||||
.events = POLLIN,
|
||||
};
|
||||
int r;
|
||||
|
||||
|
||||
/* Similar to flush_fd() but flushes all incoming connection by accepting them and immediately closing them. */
|
||||
|
||||
for (;;) {
|
||||
int cfd;
|
||||
|
||||
r = poll(&pollfd, 1, 0);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
return -errno;
|
||||
|
||||
} else if (r == 0)
|
||||
return 0;
|
||||
|
||||
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
|
||||
if (cfd < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno == EAGAIN)
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
close(cfd);
|
||||
}
|
||||
}
|
||||
|
@ -135,5 +135,7 @@ int receive_one_fd(int transport_fd, int flags);
|
||||
|
||||
ssize_t next_datagram_size_fd(int fd);
|
||||
|
||||
int flush_accept(int fd);
|
||||
|
||||
#define CMSG_FOREACH(cmsg, mh) \
|
||||
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include <unistd.h>
|
||||
#include <linux/sctp.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
#include "alloc-util.h"
|
||||
#include "bus-error.h"
|
||||
#include "bus-util.h"
|
||||
@ -38,6 +37,7 @@
|
||||
#include "exit-status.h"
|
||||
#include "fd-util.h"
|
||||
#include "formats-util.h"
|
||||
#include "io-util.h"
|
||||
#include "label.h"
|
||||
#include "log.h"
|
||||
#include "missing.h"
|
||||
@ -1960,6 +1960,21 @@ fail:
|
||||
socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
|
||||
}
|
||||
|
||||
static void flush_ports(Socket *s) {
|
||||
SocketPort *p;
|
||||
|
||||
/* Flush all incoming traffic, regardless if actual bytes or new connections, so that this socket isn't busy
|
||||
* anymore */
|
||||
|
||||
LIST_FOREACH(port, p, s->ports) {
|
||||
if (p->fd < 0)
|
||||
continue;
|
||||
|
||||
(void) flush_accept(p->fd);
|
||||
(void) flush_fd(p->fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void socket_enter_running(Socket *s, int cfd) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
int r;
|
||||
@ -1969,31 +1984,15 @@ static void socket_enter_running(Socket *s, int cfd) {
|
||||
|
||||
assert(s);
|
||||
|
||||
/* We don't take connections anymore if we are supposed to
|
||||
* shut down anyway */
|
||||
/* We don't take connections anymore if we are supposed to shut down anyway */
|
||||
if (unit_stop_pending(UNIT(s))) {
|
||||
|
||||
log_unit_debug(UNIT(s), "Suppressing connection request since unit stop is scheduled.");
|
||||
|
||||
if (cfd >= 0)
|
||||
cfd = safe_close(cfd);
|
||||
else {
|
||||
/* Flush all sockets by closing and reopening them */
|
||||
socket_close_fds(s);
|
||||
|
||||
r = socket_open_fds(s);
|
||||
if (r < 0) {
|
||||
log_unit_warning_errno(UNIT(s), r, "Failed to listen on sockets: %m");
|
||||
socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
|
||||
return;
|
||||
}
|
||||
|
||||
r = socket_watch_fds(s);
|
||||
if (r < 0) {
|
||||
log_unit_warning_errno(UNIT(s), r, "Failed to watch sockets: %m");
|
||||
socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
|
||||
}
|
||||
}
|
||||
else
|
||||
flush_ports(s);
|
||||
|
||||
return;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user