From 4fd5948e74b776b6d68ba55f558da5f354179e52 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Jul 2010 00:29:17 +0200 Subject: [PATCH] socket: make various socket/pipe options configurable --- src/dbus-socket.c | 18 ++++++++ src/dbus.c | 16 +++++++ src/dbus.h | 1 + src/load-fragment.c | 36 +++++++++++++++ src/missing.h | 12 +++++ src/socket-util.c | 7 +++ src/socket-util.h | 1 + src/socket.c | 109 +++++++++++++++++++++++++++++++++++++++++++- src/socket.h | 25 +++++++--- src/util.c | 10 ++++ src/util.h | 6 ++- 11 files changed, 231 insertions(+), 10 deletions(-) diff --git a/src/dbus-socket.c b/src/dbus-socket.c index a5474c9f..3ba26cc5 100644 --- a/src/dbus-socket.c +++ b/src/dbus-socket.c @@ -37,6 +37,15 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \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 74b1c37d..2c2a9cd6 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 af837f28..91132fd9 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 b7bb4d7c..12f76179 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 7db7d7d2..75bc5117 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 4a1b3d8b..344d6b98 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 ffcc8688..ae311ea3 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 7a8624c8..f20b78d1 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 31b3870e..0674cd81 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 41d8e7f9..b66eb466 100644 --- a/src/util.c +++ b/src/util.c @@ -46,6 +46,7 @@ #include #include #include +#include #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 91e0359e..eda8e5c4 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 -- 2.39.5