From 3e5f04bf6468fcb79c080f02b0eab08f258bff0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Renaud=20M=C3=A9trich?= Date: Thu, 20 Aug 2020 13:00:37 +0200 Subject: [PATCH] socket: New option 'FlushPending' (boolean) to flush socket before entering listening state Disabled by default. When Enabled, before listening on the socket, flush the content. Applies when Accept=no only. --- docs/TRANSIENT-SETTINGS.md | 1 + man/org.freedesktop.systemd1.xml | 8 ++++++++ man/systemd.socket.xml | 12 ++++++++++++ src/core/dbus-socket.c | 4 ++++ src/core/load-fragment-gperf.gperf.m4 | 1 + src/core/socket.c | 11 +++++++++++ src/core/socket.h | 1 + src/shared/bus-unit-util.c | 1 + 8 files changed, 39 insertions(+) diff --git a/docs/TRANSIENT-SETTINGS.md b/docs/TRANSIENT-SETTINGS.md index 2c0aea07da..89f0a7e80d 100644 --- a/docs/TRANSIENT-SETTINGS.md +++ b/docs/TRANSIENT-SETTINGS.md @@ -415,6 +415,7 @@ Most socket unit settings are available to transient units. ✓ SocketMode= ✓ DirectoryMode= ✓ Accept= +✓ FlushPending= ✓ Writable= ✓ MaxConnections= ✓ MaxConnectionsPerSource= diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 75909aa9e5..1093458e89 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -3950,6 +3950,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly u NRefused = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly u FlushPending = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly s FileDescriptorName = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly i SocketProtocol = ...; @@ -5031,6 +5033,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -5508,6 +5512,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { meaning as they have for the corresponding field of service units (see above). In addition to that, the value service-failed-permanent indicates that the service of this socket failed continuously. + + FlushPending specifies whether to flush the socket + just before entering the listening state. This setting only applies to sockets with + Accept= set to no. diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 29ce0b1c20..1bcbef2033 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -427,6 +427,18 @@ false, in read-only mode. Defaults to false. + + FlushPending= + Takes a boolean argument. May only be used when + . If yes, the socket's buffers are cleared after the + triggered service exited. This causes any pending data to be + flushed and any pending incoming connections to be rejected. If no, the + socket's buffers won't be cleared, permitting the service to handle any + pending connections after restart, which is the usually expected behaviour. + Defaults to . + + + MaxConnections= The maximum number of connections to diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 90a95c996d..07d030adb3 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -86,6 +86,7 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("SocketMode", "u", bus_property_get_mode, offsetof(Socket, socket_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Socket, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Accept", "b", bus_property_get_bool, offsetof(Socket, accept), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("FlushPending", "b", bus_property_get_bool, offsetof(Socket, flush_pending), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Writable", "b", bus_property_get_bool, offsetof(Socket, writable), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KeepAlive", "b", bus_property_get_bool, offsetof(Socket, keep_alive), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KeepAliveTimeUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_time), SD_BUS_VTABLE_PROPERTY_CONST), @@ -179,6 +180,9 @@ static int bus_socket_set_transient_property( if (streq(name, "Accept")) return bus_set_transient_bool(u, name, &s->accept, message, flags, error); + if (streq(name, "FlushPending")) + return bus_set_transient_bool(u, name, &s->flush_pending, message, flags, error); + if (streq(name, "Writable")) return bus_set_transient_bool(u, name, &s->writable, message, flags, error); diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 45147f0d57..4bad8314dc 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -391,6 +391,7 @@ Socket.SocketGroup, config_parse_user_group_compat, 0, Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode) Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode) Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept) +Socket.FlushPending, config_parse_bool, 0, offsetof(Socket, flush_pending) Socket.Writable, config_parse_bool, 0, offsetof(Socket, writable) Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections) Socket.MaxConnectionsPerSource, config_parse_unsigned, 0, offsetof(Socket, max_connections_per_source) diff --git a/src/core/socket.c b/src/core/socket.c index 0588a34e38..ac8d1e7aea 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -72,6 +72,7 @@ static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); +static void flush_ports(Socket *s); static void socket_init(Unit *u) { Socket *s = SOCKET(u); @@ -669,6 +670,11 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { prefix, s->n_connections, prefix, s->max_connections, prefix, s->max_connections_per_source); + else + fprintf(f, + "%sFlushPending: %s\n", + prefix, yes_no(s->flush_pending)); + if (s->priority >= 0) fprintf(f, @@ -2201,6 +2207,11 @@ static void socket_enter_listening(Socket *s) { int r; assert(s); + if (!s->accept && s->flush_pending) { + log_unit_debug(UNIT(s), "Flushing socket before listening."); + flush_ports(s); + } + r = socket_watch_fds(s); if (r < 0) { log_unit_warning_errno(UNIT(s), r, "Failed to watch sockets: %m"); diff --git a/src/core/socket.h b/src/core/socket.h index bb14e6b0f7..cf475e2638 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -110,6 +110,7 @@ struct Socket { bool accept; bool remove_on_stop; bool writable; + bool flush_pending; int socket_protocol; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 2ad196e824..b6def087f6 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1956,6 +1956,7 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons int r; if (STR_IN_SET(field, "Accept", + "FlushPending", "Writable", "KeepAlive", "NoDelay",