summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRenaud Métrich <rmetrich@redhat.com>2020-08-20 13:00:37 +0200
committerLennart Poettering <lennart@poettering.net>2020-09-01 17:20:23 +0200
commit3e5f04bf6468fcb79c080f02b0eab08f258bff0c (patch)
tree4bd8f30a63684745216e7cde2d56436026f531ac
parentf77d6ec9539fd87eb3ecad3a742ac684cc6dc5d2 (diff)
downloadsystemd-3e5f04bf6468fcb79c080f02b0eab08f258bff0c.tar.gz
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.
-rw-r--r--docs/TRANSIENT-SETTINGS.md1
-rw-r--r--man/org.freedesktop.systemd1.xml8
-rw-r--r--man/systemd.socket.xml12
-rw-r--r--src/core/dbus-socket.c4
-rw-r--r--src/core/load-fragment-gperf.gperf.m41
-rw-r--r--src/core/socket.c11
-rw-r--r--src/core/socket.h1
-rw-r--r--src/shared/bus-unit-util.c1
8 files changed, 39 insertions, 0 deletions
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 {
<variablelist class="dbus-property" generated="True" extra-ref="NRefused"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="FlushPending"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="FileDescriptorName"/>
<variablelist class="dbus-property" generated="True" extra-ref="SocketProtocol"/>
@@ -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 <literal>service-failed-permanent</literal> indicates that the service of this socket failed
continuously.</para>
+
+ <para><varname>FlushPending</varname> specifies whether to flush the socket
+ just before entering the listening state. This setting only applies to sockets with
+ <varname>Accept=</varname> set to <literal>no</literal>.</para>
</refsect2>
</refsect1>
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
@@ -428,6 +428,18 @@
</varlistentry>
<varlistentry>
+ <term><varname>FlushPending=</varname></term>
+ <listitem><para>Takes a boolean argument. May only be used when
+ <option>Accept=no</option>. 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 <option>no</option>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>MaxConnections=</varname></term>
<listitem><para>The maximum number of connections to
simultaneously run services instances for, when
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",