#include "strv.h"
#include "unit-name.h"
#include "dbus-socket.h"
+#include "missing.h"
+#include "special.h"
static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
[SOCKET_DEAD] = UNIT_INACTIVE,
[SOCKET_STOP_POST] = UNIT_DEACTIVATING,
[SOCKET_FINAL_SIGTERM] = UNIT_DEACTIVATING,
[SOCKET_FINAL_SIGKILL] = UNIT_DEACTIVATING,
- [SOCKET_MAINTENANCE] = UNIT_INACTIVE,
+ [SOCKET_MAINTENANCE] = UNIT_MAINTENANCE
};
static void socket_init(Unit *u) {
s->max_connections = 64;
+ s->priority = -1;
+ s->ip_tos = -1;
+ s->ip_ttl = -1;
+ s->mark = -1;
+
exec_context_init(&s->exec_context);
s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
static int socket_verify(Socket *s) {
assert(s);
- if (UNIT(s)->meta.load_state != UNIT_LOADED)
+ if (s->meta.load_state != UNIT_LOADED)
return 0;
if (!s->ports) {
- log_error("%s lacks Listen setting. Refusing.", UNIT(s)->meta.id);
+ log_error("%s lacks Listen setting. Refusing.", s->meta.id);
return -EINVAL;
}
if (s->accept && s->max_connections <= 0) {
- log_error("%s's MaxConnection setting too small. Refusing.", UNIT(s)->meta.id);
+ log_error("%s's MaxConnection setting too small. Refusing.", s->meta.id);
+ return -EINVAL;
+ }
+
+ if (s->exec_context.pam_name && s->kill_mode != KILL_CONTROL_GROUP) {
+ log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", s->meta.id);
return -EINVAL;
}
if (!socket_needs_mount(s, m->where))
return 0;
- if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, UNIT(s), true)) < 0)
- return r;
-
- if ((r = unit_add_dependency(UNIT(s), UNIT_REQUIRES, UNIT(m), true)) < 0)
+ if ((r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
return r;
return 0;
return r;
}
+static int socket_add_default_dependencies(Socket *s) {
+ int r;
+ assert(s);
+
+ if (s->meta.manager->running_as == MANAGER_SYSTEM)
+ if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
+ return r;
+
+ return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+}
+
static int socket_load(Unit *u) {
Socket *s = SOCKET(u);
int r;
if ((r = unit_add_default_cgroup(u)) < 0)
return r;
+
+ if (s->meta.default_dependencies)
+ if ((r = socket_add_default_dependencies(s)) < 0)
+ return r;
}
return socket_verify(s);
"%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,
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) {
}
}
+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) {
+ int r, x;
+
+ r = setsockopt(fd, IPPROTO_IP, IP_TTL, &s->ip_ttl, sizeof(s->ip_ttl));
+ x = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &s->ip_ttl, sizeof(s->ip_ttl));
+
+ if (r < 0 && x < 0)
+ log_warning("IP_TTL/IPV6_UNICAST_HOPS 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;
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);
r = -EEXIST;
goto rollback;
}
+
+ socket_apply_pipe_options(s, p->fd);
}
}
s->meta.manager->environment,
true,
true,
- UNIT(s)->meta.manager->confirm_spawn,
- UNIT(s)->meta.cgroup_bondings,
+ s->meta.manager->confirm_spawn,
+ s->meta.cgroup_bondings,
&pid);
strv_free(argv);
if (s->kill_mode == KILL_CONTROL_GROUP) {
- if ((r = cgroup_bonding_kill_list(UNIT(s)->meta.cgroup_bondings, sig)) < 0) {
+ if ((r = cgroup_bonding_kill_list(s->meta.cgroup_bondings, sig)) < 0) {
if (r != -EAGAIN && r != -ESRCH)
goto fail;
} else
assert(s);
if (cfd < 0) {
- if ((r = manager_add_job(UNIT(s)->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, NULL)) < 0)
+ if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, NULL)) < 0)
goto fail;
socket_set_state(s, SOCKET_RUNNING);
if ((r = instance_from_socket(cfd, s->n_accepted++, &instance)) < 0)
goto fail;
- if (!(prefix = unit_name_to_prefix(UNIT(s)->meta.id))) {
+ if (!(prefix = unit_name_to_prefix(s->meta.id))) {
free(instance);
r = -ENOMEM;
goto fail;
goto fail;
}
- r = manager_load_unit(UNIT(s)->meta.manager, name, NULL, &u);
+ r = manager_load_unit(s->meta.manager, name, NULL, &u);
free(name);
if (r < 0)
break;
}
+
+ socket_apply_socket_options(s, cfd);
}
socket_enter_running(s, cfd);