socket: make various socket/pipe options configurable

This commit is contained in:
Lennart Poettering 2010-07-01 00:29:17 +02:00
parent 6398320759
commit 4fd5948e74
11 changed files with 231 additions and 10 deletions

View file

@ -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 }
};

View 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;

View 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

View 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" },

View file

@ -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);
}

View 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;

View 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);

View 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);

View 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 */

View 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);

View 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