summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dbus-socket.c18
-rw-r--r--src/dbus.c16
-rw-r--r--src/dbus.h1
-rw-r--r--src/load-fragment.c36
-rw-r--r--src/missing.h12
-rw-r--r--src/socket-util.c7
-rw-r--r--src/socket-util.h1
-rw-r--r--src/socket.c109
-rw-r--r--src/socket.h25
-rw-r--r--src/util.c10
-rw-r--r--src/util.h6
11 files changed, 231 insertions, 10 deletions
diff --git a/src/dbus-socket.c b/src/dbus-socket.c
index a5474c9f35..3ba26cc515 100644
--- a/src/dbus-socket.c
+++ b/src/dbus-socket.c
@@ -37,6 +37,15 @@
" <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
" <property name=\"SocketMode\" type=\"u\" access=\"read\"/>\n" \
" <property name=\"Accept\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"KeepAlive\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"Priority\" type=\"i\" access=\"read\"/>\n" \
+ " <priority name=\"ReceiveBuffer\" type=\"t\" access=\"read\"/>\n" \
+ " <priority name=\"SendBuffer\" type=\"t\" access=\"read\"/>\n" \
+ " <priority name=\"IPTOS\" type=\"i\" access=\"read\"/>\n" \
+ " <priority name=\"IPTTL\" type=\"i\" access=\"read\"/>\n" \
+ " <priority name=\"PipeSize\" type=\"t\" access=\"read\"/>\n" \
+ " <priority name=\"FreeBind\" type=\"b\" access=\"read\"/>\n" \
+ " <priority name=\"Mark\" type=\"i\" access=\"read\"/>\n" \
" </interface>\n" \
#define INTROSPECTION \
@@ -66,6 +75,15 @@ DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMes
{ "org.freedesktop.systemd1.Socket", "DirectoryMode", bus_property_append_mode, "u", &u->socket.directory_mode },
{ "org.freedesktop.systemd1.Socket", "SocketMode", bus_property_append_mode, "u", &u->socket.socket_mode },
{ "org.freedesktop.systemd1.Socket", "Accept", bus_property_append_bool, "b", &u->socket.accept },
+ { "org.freedesktop.systemd1.Socket", "KeepAlive", bus_property_append_bool, "b", &u->socket.keep_alive },
+ { "org.freedesktop.systemd1.Socket", "Priority", bus_property_append_int, "i", &u->socket.priority },
+ { "org.freedesktop.systemd1.Socket", "ReceiveBuffer", bus_property_append_size, "t", &u->socket.receive_buffer },
+ { "org.freedesktop.systemd1.Socket", "SendBuffer", bus_property_append_size, "t", &u->socket.send_buffer },
+ { "org.freedesktop.systemd1.Socket", "IPTOS", bus_property_append_int, "i", &u->socket.ip_tos },
+ { "org.freedesktop.systemd1.Socket", "IPTTL", bus_property_append_int, "i", &u->socket.ip_ttl },
+ { "org.freedesktop.systemd1.Socket", "PipeSize", bus_property_append_size, "t", &u->socket.pipe_size },
+ { "org.freedesktop.systemd1.Socket", "FreeBind", bus_property_append_bool, "b", &u->socket.free_bind },
+ { "org.freedesktop.systemd1.Socket", "Mark", bus_property_append_int, "i", &u->socket.mark },
{ NULL, NULL, NULL, NULL, NULL }
};
diff --git a/src/dbus.c b/src/dbus.c
index 74b1c37dda..2c2a9cd6c2 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -1460,6 +1460,22 @@ int bus_property_append_int32(Manager *m, DBusMessageIter *i, const char *proper
return 0;
}
+int bus_property_append_size(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+ uint64_t u;
+
+ assert(m);
+ assert(i);
+ assert(property);
+ assert(data);
+
+ u = (uint64_t) *(size_t*) data;
+
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
+ return -ENOMEM;
+
+ return 0;
+}
+
int bus_parse_strv(DBusMessage *m, char ***_l) {
DBusMessageIter iter, sub;
unsigned n = 0, i = 0;
diff --git a/src/dbus.h b/src/dbus.h
index af837f283f..91132fd93c 100644
--- a/src/dbus.h
+++ b/src/dbus.h
@@ -77,6 +77,7 @@ int bus_property_append_bool(Manager *m, DBusMessageIter *i, const char *propert
int bus_property_append_int32(Manager *m, DBusMessageIter *i, const char *property, void *data);
int bus_property_append_uint32(Manager *m, DBusMessageIter *i, const char *property, void *data);
int bus_property_append_uint64(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_property_append_size(Manager *m, DBusMessageIter *i, const char *property, void *data);
#define bus_property_append_int bus_property_append_int32
#define bus_property_append_pid bus_property_append_uint32
diff --git a/src/load-fragment.c b/src/load-fragment.c
index b7bb4d7c5c..12f7617965 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -1205,6 +1205,33 @@ finish:
return r;
}
+static int config_parse_ip_tos(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ int *ip_tos = data, x;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if ((x = ip_tos_from_string(rvalue)) < 0)
+ if ((r = safe_atoi(rvalue, &x)) < 0) {
+ log_error("[%s:%u] Failed to parse IP TOS value: %s", filename, line, rvalue);
+ return r;
+ }
+
+ *ip_tos = x;
+ return 0;
+}
+
DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
#define FOLLOW_MAX 8
@@ -1517,6 +1544,15 @@ static int load_from_path(Unit *u, const char *path) {
{ "KillMode", config_parse_kill_mode, &u->socket.kill_mode, "Socket" },
{ "Accept", config_parse_bool, &u->socket.accept, "Socket" },
{ "MaxConnections", config_parse_unsigned, &u->socket.max_connections, "Socket" },
+ { "KeepAlive", config_parse_bool, &u->socket.keep_alive, "Socket" },
+ { "Priority", config_parse_int, &u->socket.priority, "Socket" },
+ { "ReceiveBuffer", config_parse_size, &u->socket.receive_buffer, "Socket" },
+ { "SendBuffer", config_parse_size, &u->socket.send_buffer, "Socket" },
+ { "IPTOS", config_parse_ip_tos, &u->socket.ip_tos, "Socket" },
+ { "IPTTL", config_parse_int, &u->socket.ip_ttl, "Socket" },
+ { "Mark", config_parse_int, &u->socket.mark, "Socket" },
+ { "PipeSize", config_parse_size, &u->socket.pipe_size, "Socket" },
+ { "FreeBind", config_parse_bool, &u->socket.free_bind, "Socket" },
EXEC_CONTEXT_CONFIG_ITEMS(u->socket.exec_context, "Socket"),
{ "What", config_parse_string, &u->mount.parameters_fragment.what, "Mount" },
diff --git a/src/missing.h b/src/missing.h
index 7db7d7d2e8..75bc5117f8 100644
--- a/src/missing.h
+++ b/src/missing.h
@@ -31,6 +31,18 @@
#define RLIMIT_RTTIME 15
#endif
+#ifndef F_LINUX_SPECIFIC_BASE
+#define F_LINUX_SPECIFIC_BASE 1024
+#endif
+
+#ifndef F_SETPIPE_SZ
+#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
+#endif
+
+#ifndef F_GETPIPE_SZ
+#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8)
+#endif
+
static inline int pivot_root(const char *new_root, const char *put_old) {
return syscall(SYS_pivot_root, new_root, put_old);
}
diff --git a/src/socket-util.c b/src/socket-util.c
index 4a1b3d8b51..344d6b98a4 100644
--- a/src/socket-util.c
+++ b/src/socket-util.c
@@ -305,6 +305,7 @@ int socket_address_listen(
int backlog,
SocketAddressBindIPv6Only only,
const char *bind_to_device,
+ bool free_bind,
mode_t directory_mode,
mode_t socket_mode,
int *ret) {
@@ -330,6 +331,12 @@ int socket_address_listen(
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
goto fail;
+ if (free_bind) {
+ one = 1;
+ if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
+ log_warning("IP_FREEBIND failed: %m");
+ }
+
one = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
goto fail;
diff --git a/src/socket-util.h b/src/socket-util.h
index ffcc86882f..ae311ea33a 100644
--- a/src/socket-util.h
+++ b/src/socket-util.h
@@ -68,6 +68,7 @@ int socket_address_listen(
int backlog,
SocketAddressBindIPv6Only only,
const char *bind_to_device,
+ bool free_bind,
mode_t directory_mode,
mode_t socket_mode,
int *ret);
diff --git a/src/socket.c b/src/socket.c
index 7a8624c848..f20b78d1a6 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -36,6 +36,7 @@
#include "strv.h"
#include "unit-name.h"
#include "dbus-socket.h"
+#include "missing.h"
static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
[SOCKET_DEAD] = UNIT_INACTIVE,
@@ -65,6 +66,16 @@ static void socket_init(Unit *u) {
s->max_connections = 64;
+ s->keep_alive = false;
+ s->priority = -1;
+ s->receive_buffer = 0;
+ s->send_buffer = 0;
+ s->ip_tos = -1;
+ s->ip_ttl = -1;
+ s->pipe_size = 0;
+ s->mark = -1;
+ s->free_bind = false;
+
exec_context_init(&s->exec_context);
s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
@@ -308,13 +319,17 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
"%sBacklog: %u\n"
"%sKillMode: %s\n"
"%sSocketMode: %04o\n"
- "%sDirectoryMode: %04o\n",
+ "%sDirectoryMode: %04o\n"
+ "%sKeepAlive: %s\n"
+ "%sFreeBind: %s\n",
prefix, socket_state_to_string(s->state),
prefix, socket_address_bind_ipv6_only_to_string(s->bind_ipv6_only),
prefix, s->backlog,
prefix, kill_mode_to_string(s->kill_mode),
prefix, s->socket_mode,
- prefix, s->directory_mode);
+ prefix, s->directory_mode,
+ prefix, yes_no(s->keep_alive),
+ prefix, yes_no(s->free_bind));
if (s->control_pid > 0)
fprintf(f,
@@ -335,6 +350,41 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
prefix, s->n_connections,
prefix, s->max_connections);
+ if (s->priority >= 0)
+ fprintf(f,
+ "%sPriority: %i\n",
+ prefix, s->priority);
+
+ if (s->receive_buffer > 0)
+ fprintf(f,
+ "%sReceiveBuffer: %zu\n",
+ prefix, s->receive_buffer);
+
+ if (s->send_buffer > 0)
+ fprintf(f,
+ "%sSendBuffer: %zu\n",
+ prefix, s->send_buffer);
+
+ if (s->ip_tos >= 0)
+ fprintf(f,
+ "%sIPTOS: %i\n",
+ prefix, s->ip_tos);
+
+ if (s->ip_ttl >= 0)
+ fprintf(f,
+ "%sIPTTL: %i\n",
+ prefix, s->ip_ttl);
+
+ if (s->pipe_size > 0)
+ fprintf(f,
+ "%sPipeSize: %zu\n",
+ prefix, s->pipe_size);
+
+ if (s->mark >= 0)
+ fprintf(f,
+ "%sMark: %i\n",
+ prefix, s->mark);
+
LIST_FOREACH(port, p, s->ports) {
if (p->type == SOCKET_SOCKET) {
@@ -493,6 +543,54 @@ static void socket_close_fds(Socket *s) {
}
}
+static void socket_apply_socket_options(Socket *s, int fd) {
+ assert(s);
+ assert(fd >= 0);
+
+ if (s->keep_alive) {
+ int b = s->keep_alive;
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &b, sizeof(b)) < 0)
+ log_warning("SO_KEEPALIVE failed: %m");
+ }
+
+ if (s->priority >= 0)
+ if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &s->priority, sizeof(s->priority)) < 0)
+ log_warning("SO_PRIORITY failed: %m");
+
+ if (s->receive_buffer > 0) {
+ int value = (int) s->receive_buffer;
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
+ log_warning("SO_RCVBUF failed: %m");
+ }
+
+ if (s->send_buffer > 0) {
+ int value = (int) s->send_buffer;
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
+ log_warning("SO_SNDBUF failed: %m");
+ }
+
+ if (s->mark >= 0)
+ if (setsockopt(fd, SOL_SOCKET, SO_MARK, &s->mark, sizeof(s->mark)) < 0)
+ log_warning("SO_MARK failed: %m");
+
+ if (s->ip_tos >= 0)
+ if (setsockopt(fd, IPPROTO_IP, IP_TOS, &s->ip_tos, sizeof(s->ip_tos)) < 0)
+ log_warning("IP_TOS failed: %m");
+
+ if (s->ip_ttl >= 0)
+ if (setsockopt(fd, IPPROTO_IP, IP_TTL, &s->ip_ttl, sizeof(s->ip_ttl)) < 0)
+ log_warning("IP_TTL failed: %m");
+}
+
+static void socket_apply_pipe_options(Socket *s, int fd) {
+ assert(s);
+ assert(fd >= 0);
+
+ if (s->pipe_size > 0)
+ if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0)
+ log_warning("F_SETPIPE_SZ: %m");
+}
+
static int socket_open_fds(Socket *s) {
SocketPort *p;
int r;
@@ -511,11 +609,14 @@ static int socket_open_fds(Socket *s) {
s->backlog,
s->bind_ipv6_only,
s->bind_to_device,
+ s->free_bind,
s->directory_mode,
s->socket_mode,
&p->fd)) < 0)
goto rollback;
+ socket_apply_socket_options(s, p->fd);
+
} else {
struct stat st;
assert(p->type == SOCKET_FIFO);
@@ -543,6 +644,8 @@ static int socket_open_fds(Socket *s) {
r = -EEXIST;
goto rollback;
}
+
+ socket_apply_pipe_options(s, p->fd);
}
}
@@ -1253,6 +1356,8 @@ static void socket_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
break;
}
+
+ socket_apply_socket_options(s, cfd);
}
socket_enter_running(s, cfd);
diff --git a/src/socket.h b/src/socket.h
index 31b3870ef6..0674cd81bf 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -78,10 +78,7 @@ struct Socket {
LIST_HEAD(SocketPort, ports);
- /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
- SocketAddressBindIPv6Only bind_ipv6_only;
unsigned backlog;
-
usec_t timeout_usec;
ExecCommand* exec_command[_SOCKET_EXEC_COMMAND_MAX];
@@ -97,10 +94,6 @@ struct Socket {
SocketExecCommand control_command_id;
pid_t control_pid;
- char *bind_to_device;
- mode_t directory_mode;
- mode_t socket_mode;
-
bool accept;
unsigned n_accepted;
unsigned n_connections;
@@ -108,6 +101,24 @@ struct Socket {
bool failure;
Watch timer_watch;
+
+ /* Socket options */
+ bool keep_alive;
+ int priority;
+ size_t receive_buffer;
+ size_t send_buffer;
+ int ip_tos;
+ int ip_ttl;
+ size_t pipe_size;
+ int mark;
+ bool free_bind;
+ char *bind_to_device;
+
+ /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
+ SocketAddressBindIPv6Only bind_ipv6_only;
+
+ mode_t directory_mode;
+ mode_t socket_mode;
};
/* Called from the service code when collecting fds */
diff --git a/src/util.c b/src/util.c
index 41d8e7f999..b66eb466b6 100644
--- a/src/util.c
+++ b/src/util.c
@@ -46,6 +46,7 @@
#include <sys/prctl.h>
#include <sys/utsname.h>
#include <pwd.h>
+#include <netinet/ip.h>
#include "macro.h"
#include "util.h"
@@ -2625,3 +2626,12 @@ static const char* const rlimit_table[] = {
};
DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
+
+static const char* const ip_tos_table[] = {
+ [IPTOS_LOWDELAY] = "low-delay",
+ [IPTOS_THROUGHPUT] = "throughput",
+ [IPTOS_RELIABILITY] = "reliability",
+ [IPTOS_LOWCOST] = "low-cost",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(ip_tos, int);
diff --git a/src/util.h b/src/util.h
index 91e0359e0c..eda8e5c406 100644
--- a/src/util.h
+++ b/src/util.h
@@ -226,7 +226,8 @@ unsigned long long random_ull(void);
unsigned u = 0; \
assert(s); \
for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \
- if (streq(name##_table[i], s)) \
+ if (name##_table[i] && \
+ streq(name##_table[i], s)) \
return i; \
if (safe_atou(s, &u) >= 0 && \
u < ELEMENTSOF(name##_table)) \
@@ -301,4 +302,7 @@ int sched_policy_from_string(const char *s);
const char *rlimit_to_string(int i);
int rlimit_from_string(const char *s);
+const char *ip_tos_to_string(int i);
+int ip_tos_from_string(const char *s);
+
#endif