ryantimwilson / rpms / systemd

Forked from rpms/systemd a month ago
Clone
bd1529
From 262544a451c11c38e92c45047ec2adeaeb2a0a7e Mon Sep 17 00:00:00 2001
bd1529
From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
bd1529
Date: Thu, 20 Aug 2020 13:00:37 +0200
bd1529
Subject: [PATCH] socket: New option 'FlushPending' (boolean) to flush socket
bd1529
 before entering listening state
bd1529
bd1529
Disabled by default. When Enabled, before listening on the socket, flush the content.
bd1529
Applies when Accept=no only.
bd1529
bd1529
(cherry picked from commit 3e5f04bf6468fcb79c080f02b0eab08f258bff0c)
bd1529
bd1529
Resolves: #1870638
bd1529
---
bd1529
 doc/TRANSIENT-SETTINGS.md             |  1 +
bd1529
 man/systemd.socket.xml                | 12 ++++++++++++
bd1529
 src/core/dbus-socket.c                |  4 ++++
bd1529
 src/core/load-fragment-gperf.gperf.m4 |  1 +
bd1529
 src/core/socket.c                     | 11 +++++++++++
bd1529
 src/core/socket.h                     |  1 +
bd1529
 src/shared/bus-unit-util.c            |  3 ++-
bd1529
 7 files changed, 32 insertions(+), 1 deletion(-)
bd1529
bd1529
diff --git a/doc/TRANSIENT-SETTINGS.md b/doc/TRANSIENT-SETTINGS.md
bd1529
index 1a4e79190a..995b8797ef 100644
bd1529
--- a/doc/TRANSIENT-SETTINGS.md
bd1529
+++ b/doc/TRANSIENT-SETTINGS.md
bd1529
@@ -388,6 +388,7 @@ Most socket unit settings are available to transient units.
bd1529
 ✓ SocketMode=
bd1529
 ✓ DirectoryMode=
bd1529
 ✓ Accept=
bd1529
+✓ FlushPending=
bd1529
 ✓ Writable=
bd1529
 ✓ MaxConnections=
bd1529
 ✓ MaxConnectionsPerSource=
bd1529
diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
bd1529
index 19c2ca9907..8676b4e03f 100644
bd1529
--- a/man/systemd.socket.xml
bd1529
+++ b/man/systemd.socket.xml
bd1529
@@ -425,6 +425,18 @@
bd1529
         false, in read-only mode. Defaults to false.</para></listitem>
bd1529
       </varlistentry>
bd1529
 
bd1529
+      <varlistentry>
bd1529
+        <term><varname>FlushPending=</varname></term>
bd1529
+        <listitem><para>Takes a boolean argument. May only be used when
bd1529
+        <option>Accept=no</option>. If yes, the socket's buffers are cleared after the
bd1529
+        triggered service exited. This causes any pending data to be
bd1529
+        flushed and any pending incoming connections to be rejected. If no, the
bd1529
+        socket's buffers won't be cleared, permitting the service to handle any
bd1529
+        pending connections after restart, which is the usually expected behaviour.
bd1529
+        Defaults to <option>no</option>.
bd1529
+        </para></listitem>
bd1529
+      </varlistentry>
bd1529
+
bd1529
       <varlistentry>
bd1529
         <term><varname>MaxConnections=</varname></term>
bd1529
         <listitem><para>The maximum number of connections to
bd1529
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
bd1529
index 913cc74918..bb77539030 100644
bd1529
--- a/src/core/dbus-socket.c
bd1529
+++ b/src/core/dbus-socket.c
bd1529
@@ -85,6 +85,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
bd1529
         SD_BUS_PROPERTY("SocketMode", "u", bus_property_get_mode, offsetof(Socket, socket_mode), SD_BUS_VTABLE_PROPERTY_CONST),
bd1529
         SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Socket, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
bd1529
         SD_BUS_PROPERTY("Accept", "b", bus_property_get_bool, offsetof(Socket, accept), SD_BUS_VTABLE_PROPERTY_CONST),
bd1529
+        SD_BUS_PROPERTY("FlushPending", "b", bus_property_get_bool, offsetof(Socket, flush_pending), SD_BUS_VTABLE_PROPERTY_CONST),
bd1529
         SD_BUS_PROPERTY("Writable", "b", bus_property_get_bool, offsetof(Socket, writable), SD_BUS_VTABLE_PROPERTY_CONST),
bd1529
         SD_BUS_PROPERTY("KeepAlive", "b", bus_property_get_bool, offsetof(Socket, keep_alive), SD_BUS_VTABLE_PROPERTY_CONST),
bd1529
         SD_BUS_PROPERTY("KeepAliveTimeUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_time), SD_BUS_VTABLE_PROPERTY_CONST),
bd1529
@@ -177,6 +178,9 @@ static int bus_socket_set_transient_property(
bd1529
         if (streq(name, "Accept"))
bd1529
                 return bus_set_transient_bool(u, name, &s->accept, message, flags, error);
bd1529
 
bd1529
+        if (streq(name, "FlushPending"))
bd1529
+                return bus_set_transient_bool(u, name, &s->flush_pending, message, flags, error);
bd1529
+
bd1529
         if (streq(name, "Writable"))
bd1529
                 return bus_set_transient_bool(u, name, &s->writable, message, flags, error);
bd1529
 
bd1529
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
bd1529
index 6d21b2e433..24ee5ae6fe 100644
bd1529
--- a/src/core/load-fragment-gperf.gperf.m4
bd1529
+++ b/src/core/load-fragment-gperf.gperf.m4
bd1529
@@ -359,6 +359,7 @@ Socket.SocketGroup,              config_parse_user_group,            0,
bd1529
 Socket.SocketMode,               config_parse_mode,                  0,                             offsetof(Socket, socket_mode)
bd1529
 Socket.DirectoryMode,            config_parse_mode,                  0,                             offsetof(Socket, directory_mode)
bd1529
 Socket.Accept,                   config_parse_bool,                  0,                             offsetof(Socket, accept)
bd1529
+Socket.FlushPending,             config_parse_bool,                  0,                             offsetof(Socket, flush_pending)
bd1529
 Socket.Writable,                 config_parse_bool,                  0,                             offsetof(Socket, writable)
bd1529
 Socket.MaxConnections,           config_parse_unsigned,              0,                             offsetof(Socket, max_connections)
bd1529
 Socket.MaxConnectionsPerSource,  config_parse_unsigned,              0,                             offsetof(Socket, max_connections_per_source)
bd1529
diff --git a/src/core/socket.c b/src/core/socket.c
bd1529
index fe061eb73b..97c3a7fc9a 100644
bd1529
--- a/src/core/socket.c
bd1529
+++ b/src/core/socket.c
bd1529
@@ -70,6 +70,7 @@ static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
bd1529
 
bd1529
 static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
bd1529
 static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
bd1529
+static void flush_ports(Socket *s);
bd1529
 
bd1529
 static void socket_init(Unit *u) {
bd1529
         Socket *s = SOCKET(u);
bd1529
@@ -703,6 +704,11 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
bd1529
                         prefix, s->n_connections,
bd1529
                         prefix, s->max_connections,
bd1529
                         prefix, s->max_connections_per_source);
bd1529
+        else
bd1529
+                fprintf(f,
bd1529
+                        "%sFlushPending: %s\n",
bd1529
+                         prefix, yes_no(s->flush_pending));
bd1529
+
bd1529
 
bd1529
         if (s->priority >= 0)
bd1529
                 fprintf(f,
bd1529
@@ -2111,6 +2117,11 @@ static void socket_enter_listening(Socket *s) {
bd1529
         int r;
bd1529
         assert(s);
bd1529
 
bd1529
+        if (!s->accept && s->flush_pending) {
bd1529
+                log_unit_debug(UNIT(s), "Flushing socket before listening.");
bd1529
+                flush_ports(s);
bd1529
+        }
bd1529
+
bd1529
         r = socket_watch_fds(s);
bd1529
         if (r < 0) {
bd1529
                 log_unit_warning_errno(UNIT(s), r, "Failed to watch sockets: %m");
bd1529
diff --git a/src/core/socket.h b/src/core/socket.h
bd1529
index c4e25db1fc..b7a25d91fd 100644
bd1529
--- a/src/core/socket.h
bd1529
+++ b/src/core/socket.h
bd1529
@@ -109,6 +109,7 @@ struct Socket {
bd1529
         bool accept;
bd1529
         bool remove_on_stop;
bd1529
         bool writable;
bd1529
+        bool flush_pending;
bd1529
 
bd1529
         int socket_protocol;
bd1529
 
bd1529
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
bd1529
index 77788f0fe2..7029aa5615 100644
bd1529
--- a/src/shared/bus-unit-util.c
bd1529
+++ b/src/shared/bus-unit-util.c
bd1529
@@ -1468,7 +1468,8 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons
bd1529
 
bd1529
         if (STR_IN_SET(field,
bd1529
                        "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
bd1529
-                       "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
bd1529
+                       "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet",
bd1529
+                       "FlushPending"))
bd1529
 
bd1529
                 return bus_append_parse_boolean(m, field, eq);
bd1529