chiark / gitweb /
socket: make various socket/pipe options configurable
authorLennart Poettering <lennart@poettering.net>
Wed, 30 Jun 2010 22:29:17 +0000 (00:29 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 30 Jun 2010 22:29:17 +0000 (00:29 +0200)
src/dbus-socket.c
src/dbus.c
src/dbus.h
src/load-fragment.c
src/missing.h
src/socket-util.c
src/socket-util.h
src/socket.c
src/socket.h
src/util.c
src/util.h

index a5474c9..3ba26cc 100644 (file)
         "  <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 }
         };
 
index 74b1c37..2c2a9cd 100644 (file)
@@ -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;
index af837f2..91132fd 100644 (file)
@@ -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
index b7bb4d7..12f7617 100644 (file)
@@ -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"   },
index 7db7d7d..75bc511 100644 (file)
 #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);
 }
index 4a1b3d8..344d6b9 100644 (file)
@@ -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;
index ffcc868..ae311ea 100644 (file)
@@ -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);
index 7a8624c..f20b78d 100644 (file)
@@ -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);
index 31b3870..0674cd8 100644 (file)
@@ -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 */
index 41d8e7f..b66eb46 100644 (file)
@@ -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);
index 91e0359..eda8e5c 100644 (file)
@@ -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