mirror of
https://github.com/systemd/systemd.git
synced 2024-12-23 21:35:11 +03:00
socket: make various socket/pipe options configurable
This commit is contained in:
parent
6398320759
commit
4fd5948e74
@ -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 }
|
||||
};
|
||||
|
||||
|
16
src/dbus.c
16
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;
|
||||
|
@ -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
|
||||
|
@ -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" },
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
109
src/socket.c
109
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);
|
||||
|
25
src/socket.h
25
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 */
|
||||
|
10
src/util.c
10
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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user