summaryrefslogtreecommitdiff
path: root/src/core/dbus-socket.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2017-12-23 18:47:33 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2017-12-23 18:47:33 +0900
commit9c0320e7abda82f78c448c2b173d2809dac6bfb1 (patch)
tree8ec56ef7cea3708653575475c5281f149e29926d /src/core/dbus-socket.c
parent398ce0bc5a0e1aad57223a62dcbcc8854e103c90 (diff)
downloadsystemd-9c0320e7abda82f78c448c2b173d2809dac6bfb1.tar.gz
core: implement transient socket unit
Diffstat (limited to 'src/core/dbus-socket.c')
-rw-r--r--src/core/dbus-socket.c486
1 files changed, 485 insertions, 1 deletions
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index 930b7fa87d..6c5d5944fc 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -22,10 +22,17 @@
#include "bus-util.h"
#include "dbus-cgroup.h"
#include "dbus-execute.h"
+#include "dbus-kill.h"
#include "dbus-socket.h"
+#include "fd-util.h"
+#include "parse-util.h"
+#include "path-util.h"
#include "socket.h"
+#include "socket-util.h"
#include "string-util.h"
#include "unit.h"
+#include "user-util.h"
+#include "utf8.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, socket_result, SocketResult);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
@@ -141,6 +148,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("MaxConnectionsPerSource", "u", bus_property_get_unsigned, offsetof(Socket, max_connections_per_source), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MessageQueueMaxMessages", "x", bus_property_get_long, offsetof(Socket, mq_maxmsg), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MessageQueueMessageSize", "x", bus_property_get_long, offsetof(Socket, mq_msgsize), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TCPCongestion", "s", NULL, offsetof(Socket, tcp_congestion), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ReusePort", "b", bus_property_get_bool, offsetof(Socket, reuse_port), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SmackLabel", "s", NULL, offsetof(Socket, smack), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SmackLabelIPIn", "s", NULL, offsetof(Socket, smack_ip_in), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -162,6 +170,457 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_VTABLE_END
};
+static int bus_socket_set_transient_property(
+ Socket *s,
+ const char *name,
+ sd_bus_message *message,
+ UnitWriteFlags flags,
+ sd_bus_error *error) {
+
+ SocketExecCommand ci;
+ Unit *u = UNIT(s);
+ int r;
+
+ assert(s);
+ assert(name);
+ assert(message);
+
+ flags |= UNIT_PRIVATE;
+
+ if (STR_IN_SET(name,
+ "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
+ "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet")) {
+ int b;
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ if (streq(name, "Accept"))
+ s->accept = b;
+ else if (streq(name, "Writable"))
+ s->writable = b;
+ else if (streq(name, "KeepAlive"))
+ s->keep_alive = b;
+ else if (streq(name, "NoDelay"))
+ s->no_delay = b;
+ else if (streq(name, "FreeBind"))
+ s->free_bind = b;
+ else if (streq(name, "Transparent"))
+ s->transparent = b;
+ else if (streq(name, "Broadcast"))
+ s->broadcast = b;
+ else if (streq(name, "PassCredentials"))
+ s->pass_cred = b;
+ else if (streq(name, "PassSecurity"))
+ s->pass_sec = b;
+ else if (streq(name, "ReusePort"))
+ s->reuse_port = b;
+ else if (streq(name, "RemoveOnStop"))
+ s->remove_on_stop = b;
+ else /* "SELinuxContextFromNet" */
+ s->selinux_context_from_net = b;
+
+ unit_write_settingf(u, flags, name, "%s=%s", name, yes_no(b));
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "Priority", "IPTTL", "Mark")) {
+ int32_t i;
+
+ r = sd_bus_message_read(message, "i", &i);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ if (streq(name, "Priority"))
+ s->priority = i;
+ else if (streq(name, "IPTTL"))
+ s->ip_ttl = i;
+ else /* "Mark" */
+ s->mark = i;
+
+ unit_write_settingf(u, flags, name, "%s=%i", name, i);
+ }
+
+ return 1;
+
+ } else if (streq(name, "IPTOS")) {
+ _cleanup_free_ char *str = NULL;
+ int32_t i;
+
+ r = sd_bus_message_read(message, "i", &i);
+ if (r < 0)
+ return r;
+
+ r = ip_tos_to_string_alloc(i, &str);
+ if (r < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %i", name, i);
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ s->ip_tos = i;
+
+ unit_write_settingf(u, flags, name, "%s=%s", name, str);
+ }
+
+ return 1;
+
+ } else if (streq(name, "SocketProtocol")) {
+ int32_t i;
+
+ r = sd_bus_message_read(message, "i", &i);
+ if (r < 0)
+ return r;
+
+ if (!IN_SET(i, IPPROTO_UDPLITE, IPPROTO_SCTP))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %i", name, i);
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ s->socket_protocol = i;
+ unit_write_settingf(u, flags, name, "%s=%s", name, i == IPPROTO_UDPLITE ? "udplite" : "sctp");
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst")) {
+ uint32_t n;
+
+ r = sd_bus_message_read(message, "u", &n);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ if (streq(name, "Backlog"))
+ s->backlog = n;
+ else if (streq(name, "MaxConnections"))
+ s->max_connections = n;
+ else if (streq(name, "MaxConnectionsPerSource"))
+ s->max_connections_per_source = n;
+ else if (streq(name, "KeepAliveProbes"))
+ s->keep_alive_cnt = n;
+ else /* "TriggerLimitBurst" */
+ s->trigger_limit.burst = n;
+
+ unit_write_settingf(u, flags, name, "%s=%u", name, n);
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "SocketMode", "DirectoryMode")) {
+ mode_t m;
+
+ r = sd_bus_message_read(message, "u", &m);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ if (streq(name, "SocketMode"))
+ s->socket_mode = m;
+ else /* "DirectoryMode" */
+ s->directory_mode = m;
+
+ unit_write_settingf(u, flags, name, "%s=%040o", name, m);
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "MessageQueueMaxMessages", "MessageQueueMessageSize")) {
+ int64_t n;
+
+ r = sd_bus_message_read(message, "x", &n);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ if (streq(name, "MessageQueueMaxMessages"))
+ s->mq_maxmsg = (long) n;
+ else /* "MessageQueueMessageSize" */
+ s->mq_msgsize = (long) n;
+
+ unit_write_settingf(u, flags, name, "%s=%" PRIi64, name, n);
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "TimeoutUSec", "KeepAliveTimeUSec", "KeepAliveIntervalUSec", "DeferAcceptUSec", "TriggerLimitIntervalUSec")) {
+ usec_t t;
+
+ r = sd_bus_message_read(message, "t", &t);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ if (streq(name, "TimeoutUSec"))
+ s->timeout_usec = t ?: USEC_INFINITY;
+ else if (streq(name, "KeepAliveTimeUSec"))
+ s->keep_alive_time = t;
+ else if (streq(name, "KeepAliveIntervalUSec"))
+ s->keep_alive_interval = t;
+ else if (streq(name, "DeferAcceptUSec"))
+ s->defer_accept = t;
+ else /* "TriggerLimitIntervalUSec" */
+ s->trigger_limit.interval = t;
+
+ unit_write_settingf(u, flags, name, "%s=" USEC_FMT, name, t);
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "ReceiveBuffer", "SendBuffer", "PipeSize")) {
+ uint64_t t;
+
+ r = sd_bus_message_read(message, "t", &t);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ if (streq(name, "ReceiveBuffer"))
+ s->receive_buffer = t;
+ else if (streq(name, "SendBuffer"))
+ s->send_buffer = t;
+ else /* "PipeSize" */
+ s->pipe_size = t;
+
+ unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, t);
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion")) {
+ const char *n;
+
+ r = sd_bus_message_read(message, "s", &n);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+
+ if (streq(name, "SmackLabel"))
+ r = free_and_strdup(&s->smack, empty_to_null(n));
+ else if (streq(name, "SmackLabelIPin"))
+ r = free_and_strdup(&s->smack_ip_in, empty_to_null(n));
+ else if (streq(name, "SmackLabelIPOut"))
+ r = free_and_strdup(&s->smack_ip_out, empty_to_null(n));
+ else /* "TCPCongestion" */
+ r = free_and_strdup(&s->tcp_congestion, empty_to_null(n));
+ if (r < 0)
+ return r;
+
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(n));
+ }
+
+ return 1;
+
+ } else if (streq(name, "BindToDevice")) {
+ const char *n;
+
+ r = sd_bus_message_read(message, "s", &n);
+ if (r < 0)
+ return r;
+
+ if (n[0] && !streq(n, "*")) {
+ if (!ifname_valid(n))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface name for %s: %s", name, n);
+ } else
+ n = NULL;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+
+ r = free_and_strdup(&s->bind_to_device, empty_to_null(n));
+ if (r < 0)
+ return r;
+
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(n));
+ }
+
+ return 1;
+
+ } else if (streq(name, "BindIPv6Only")) {
+ SocketAddressBindIPv6Only b;
+ const char *n;
+
+ r = sd_bus_message_read(message, "s", &n);
+ if (r < 0)
+ return r;
+
+ b = socket_address_bind_ipv6_only_from_string(n);
+ if (b < 0) {
+ r = parse_boolean(n);
+ if (r < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %s", name, n);
+
+ b = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
+ }
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ s->bind_ipv6_only = b;
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, n);
+ }
+
+ return 1;
+
+ } else if (streq(name, "FileDescriptorName")) {
+ const char *n;
+
+ r = sd_bus_message_read(message, "s", &n);
+ if (r < 0)
+ return r;
+
+ if (!isempty(n) && !fdname_is_valid(n))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %s", name, n);
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ r = free_and_strdup(&s->fdname, empty_to_null(n));
+ if (r < 0)
+ return r;
+
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(n));
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "SocketUser", "SocketGroup")) {
+ const char *n;
+
+ r = sd_bus_message_read(message, "s", &n);
+ if (r < 0)
+ return r;
+
+ if (!isempty(n) && !valid_user_group_name_or_id(n))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %s", name, n);
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+
+ if (streq(name, "SocketUser"))
+ r = free_and_strdup(&s->user, empty_to_null(n));
+ else /* "SocketGroup" */
+ r = free_and_strdup(&s->user, empty_to_null(n));
+ if (r < 0)
+ return r;
+
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(n));
+ }
+
+ return 1;
+
+ } else if (streq(name, "Symlinks")) {
+ _cleanup_strv_free_ char **l = NULL;
+ char **p;
+
+ r = sd_bus_message_read_strv(message, &l);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(p, l) {
+ if (!utf8_is_valid(*p))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "String is not UTF-8 clean, ignoring assignment: %s", *p);
+
+ if (!path_is_absolute(*p))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Symlink path is not absolute: %s", *p);
+ }
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ if (strv_isempty(l)) {
+ s->symlinks = strv_free(s->symlinks);
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=", name);
+ } else {
+ _cleanup_free_ char *joined = NULL;
+
+ r = strv_extend_strv(&s->symlinks, l, true);
+ if (r < 0)
+ return -ENOMEM;
+
+ joined = strv_join(l, " ");
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, joined);
+ }
+ }
+
+ return 1;
+
+ } else if (streq(name, "Listen")) {
+ const char *t, *a;
+ bool empty = true;
+
+ r = sd_bus_message_enter_container(message, 'a', "(ss)");
+ if (r < 0)
+ return r;
+
+ while ((r = sd_bus_message_read(message, "(ss)", &t, &a)) > 0) {
+ _cleanup_free_ SocketPort *p = NULL;
+
+ p = new0(SocketPort, 1);
+ if (!p)
+ return log_oom();
+
+ p->type = socket_type_from_string(t);
+ if (p->type < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown Socket type: %s", t);
+
+ if (p->type != SOCKET_SOCKET) {
+ p->path = strdup(a);
+ path_kill_slashes(p->path);
+
+ } else if (streq(t, "Netlink")) {
+ r = socket_address_parse_netlink(&p->address, a);
+ if (r < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid netlink address: %s", a);
+
+ } else {
+ r = socket_address_parse(&p->address, a);
+ if (r < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address: %s", a);
+
+ p->address.type = socket_address_type_from_string(t);
+ if (p->address.type < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address type: %s", t);
+
+ if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Address family not supported: %s", a);
+ }
+
+ p->fd = -1;
+ p->auxiliary_fds = NULL;
+ p->n_auxiliary_fds = 0;
+ p->socket = s;
+
+ empty = false;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ SocketPort *tail;
+
+ LIST_FIND_TAIL(port, s->ports, tail);
+ LIST_INSERT_AFTER(port, s->ports, tail, p);
+
+ p = NULL;
+
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "Listen%s=%s", t, a);
+ }
+ }
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
+ socket_free_ports(s);
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "ListenStream=");
+ }
+
+ return 1;
+
+ } else if ((ci = socket_exec_command_from_string(name)) >= 0)
+ return bus_exec_command_set_transient_property(UNIT(s), name, &s->exec_command[ci], message, flags, error);
+
+ return 0;
+}
+
int bus_socket_set_property(
Unit *u,
const char *name,
@@ -170,12 +629,37 @@ int bus_socket_set_property(
sd_bus_error *error) {
Socket *s = SOCKET(u);
+ int r;
+
+ assert(s);
+ assert(name);
+ assert(message);
assert(s);
assert(name);
assert(message);
- return bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
+ r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
+ if (r != 0)
+ return r;
+
+ if (u->transient && u->load_state == UNIT_STUB) {
+ /* This is a transient unit, let's load a little more */
+
+ r = bus_socket_set_transient_property(s, name, message, flags, error);
+ if (r != 0)
+ return r;
+
+ r = bus_exec_context_set_transient_property(u, &s->exec_context, name, message, flags, error);
+ if (r != 0)
+ return r;
+
+ r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, flags, error);
+ if (r != 0)
+ return r;
+ }
+
+ return 0;
}
int bus_socket_commit_properties(Unit *u) {