summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2010-10-05 19:49:15 +0200
committerLennart Poettering <lennart@poettering.net>2010-10-05 19:50:00 +0200
commitf976f3f67ce5140dc0ba48e0c21a91a553905c57 (patch)
treedbb2171d6d6d8b03ef58b2a8f53f0ba59c819a3e /src
parentd9ff321ad9477664c34b81a9dd4fce616e44124e (diff)
socket: make sockets to pass to a service configurable
Diffstat (limited to 'src')
-rw-r--r--src/load-fragment.c61
-rw-r--r--src/service.c52
-rw-r--r--src/service.h3
-rw-r--r--src/socket.c29
-rw-r--r--src/unit.c17
-rw-r--r--src/unit.h1
6 files changed, 134 insertions, 29 deletions
diff --git a/src/load-fragment.c b/src/load-fragment.c
index eba3fdbdfd..1685c4adb7 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -1246,8 +1246,8 @@ static int config_parse_socket_service(
dbus_error_init(&error);
- if (endswith(rvalue, ".service")) {
- log_error("[%s:%u] Unit must be of type serivce, ignoring: %s", filename, line, rvalue);
+ if (!endswith(rvalue, ".service")) {
+ log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
return 0;
}
@@ -1260,6 +1260,60 @@ static int config_parse_socket_service(
return 0;
}
+static int config_parse_service_sockets(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Service *s = data;
+ int r;
+ DBusError error;
+ char *state, *w;
+ size_t l;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ dbus_error_init(&error);
+
+ FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+ char *t;
+ Unit *sock;
+
+ if (!(t = strndup(w, l)))
+ return -ENOMEM;
+
+ if (!endswith(t, ".socket")) {
+ log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
+ free(t);
+ continue;
+ }
+
+ r = manager_load_unit(s->meta.manager, t, NULL, &error, &sock);
+ free(t);
+
+ if (r < 0) {
+ log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
+ dbus_error_free(&error);
+ continue;
+ }
+
+ if ((r = set_ensure_allocated(&s->configured_sockets, trivial_hash_func, trivial_compare_func)) < 0)
+ return r;
+
+ if ((r = set_put(s->configured_sockets, sock)) < 0)
+ return r;
+ }
+
+ return 0;
+}
+
static int config_parse_env_file(
const char *filename,
unsigned line,
@@ -1655,11 +1709,12 @@ static int load_from_path(Unit *u, const char *path) {
#ifdef HAVE_SYSV_COMPAT
{ "SysVStartPriority", config_parse_sysv_priority, &u->service.sysv_start_priority, "Service" },
#else
- { "SysVStartPriority", config_parse_warn_compat, NULL, "Service" },
+ { "SysVStartPriority", config_parse_warn_compat, NULL, "Service" },
#endif
{ "NonBlocking", config_parse_bool, &u->service.exec_context.non_blocking, "Service" },
{ "BusName", config_parse_string_printf, &u->service.bus_name, "Service" },
{ "NotifyAccess", config_parse_notify_access, &u->service.notify_access, "Service" },
+ { "Sockets", config_parse_service_sockets, &u->service, "Service" },
EXEC_CONTEXT_CONFIG_ITEMS(u->service.exec_context, "Service"),
{ "ListenStream", config_parse_listen, &u->socket, "Socket" },
diff --git a/src/service.c b/src/service.c
index b18c950baa..301633ec7e 100644
--- a/src/service.c
+++ b/src/service.c
@@ -178,11 +178,11 @@ static void service_close_socket_fd(Service *s) {
static void service_connection_unref(Service *s) {
assert(s);
- if (!s->socket)
+ if (!s->accept_socket)
return;
- socket_connection_unref(s->socket);
- s->socket = NULL;
+ socket_connection_unref(s->accept_socket);
+ s->accept_socket = NULL;
}
static void service_done(Unit *u) {
@@ -222,6 +222,8 @@ static void service_done(Unit *u) {
service_close_socket_fd(s);
service_connection_unref(s);
+ set_free(s->configured_sockets);
+
unit_unwatch_timer(u, &s->timer_watch);
}
@@ -1177,6 +1179,9 @@ static int service_get_sockets(Service *s, Set **_set) {
if (s->socket_fd >= 0)
return 0;
+ if (!set_isempty(s->configured_sockets))
+ return 0;
+
/* Collects all Socket objects that belong to this
* service. Note that a service might have multiple sockets
* via multiple names. */
@@ -1216,23 +1221,30 @@ fail:
static int service_notify_sockets_dead(Service *s) {
Iterator i;
- Set *set;
+ Set *set, *free_set = NULL;
Socket *sock;
int r;
assert(s);
+ /* Notifies all our sockets when we die */
+
if (s->socket_fd >= 0)
return 0;
- /* Notifies all our sockets when we die */
- if ((r = service_get_sockets(s, &set)) < 0)
- return r;
+ if (!set_isempty(s->configured_sockets))
+ set = s->configured_sockets;
+ else {
+ if ((r = service_get_sockets(s, &free_set)) < 0)
+ return r;
+
+ set = free_set;
+ }
SET_FOREACH(sock, set, i)
socket_notify_service_dead(sock);
- set_free(set);
+ set_free(free_set);
return 0;
}
@@ -1390,7 +1402,7 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
int r;
int *rfds = NULL;
unsigned rn_fds = 0;
- Set *set;
+ Set *set, *free_set = NULL;
Socket *sock;
assert(s);
@@ -1400,8 +1412,14 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
if (s->socket_fd >= 0)
return 0;
- if ((r = service_get_sockets(s, &set)) < 0)
- return r;
+ if (!set_isempty(s->configured_sockets))
+ set = s->configured_sockets;
+ else {
+ if ((r = service_get_sockets(s, &free_set)) < 0)
+ return r;
+
+ set = free_set;
+ }
SET_FOREACH(sock, set, i) {
int *cfds;
@@ -1438,7 +1456,7 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
*fds = rfds;
*n_fds = rn_fds;
- set_free(set);
+ set_free(free_set);
return 0;
@@ -2084,14 +2102,6 @@ static int service_start(Unit *u) {
return -ECANCELED;
}
- if ((s->exec_context.std_input == EXEC_INPUT_SOCKET ||
- s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
- s->exec_context.std_error == EXEC_OUTPUT_SOCKET) &&
- s->socket_fd < 0) {
- log_warning("%s can only be started with a per-connection socket.", u->meta.id);
- return -EINVAL;
- }
-
s->failure = false;
s->main_pid_known = false;
s->forbid_restart = false;
@@ -3062,7 +3072,7 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock) {
s->socket_fd = fd;
s->got_socket_fd = true;
- s->socket = sock;
+ s->accept_socket = sock;
return 0;
}
diff --git a/src/service.h b/src/service.h
index 39bd1b3401..e2b11db671 100644
--- a/src/service.h
+++ b/src/service.h
@@ -133,7 +133,8 @@ struct Service {
RateLimit ratelimit;
- struct Socket *socket;
+ struct Socket *accept_socket;
+ Set *configured_sockets;
Watch timer_watch;
diff --git a/src/socket.c b/src/socket.c
index bbb54f6308..2567d0febf 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -129,8 +129,10 @@ static void socket_done(Unit *u) {
LIST_FOREACH(units_per_type, i, u->meta.manager->units_per_type[UNIT_SERVICE]) {
Service *service = (Service *) i;
- if (service->socket == s)
- service->socket = NULL;
+ if (service->accept_socket == s)
+ service->accept_socket = NULL;
+
+ set_remove(service->configured_sockets, s);
}
}
@@ -1197,8 +1199,27 @@ static void socket_enter_running(Socket *s, int cfd) {
}
if (cfd < 0) {
- if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, &error, NULL)) < 0)
- goto fail;
+ bool pending = false;
+ Meta *i;
+
+ /* If there's already a start pending don't bother to
+ * do anything */
+ LIST_FOREACH(units_per_type, i, s->meta.manager->units_per_type[UNIT_SERVICE]) {
+ Service *service = (Service *) i;
+
+ if (!set_get(service->configured_sockets, s))
+ continue;
+
+ if (!unit_pending_active(UNIT(service)))
+ continue;
+
+ pending = true;
+ break;
+ }
+
+ if (!pending)
+ if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, &error, NULL)) < 0)
+ goto fail;
socket_set_state(s, SOCKET_RUNNING);
} else {
diff --git a/src/unit.c b/src/unit.c
index 0a8ee61900..fefa0eb516 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -2190,6 +2190,23 @@ bool unit_pending_inactive(Unit *u) {
return false;
}
+bool unit_pending_active(Unit *u) {
+ assert(u);
+
+ /* Returns true if the unit is inactive or going down */
+
+ if (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
+ return true;
+
+ if (u->meta.job &&
+ (u->meta.job->type == JOB_START ||
+ u->meta.job->type == JOB_RELOAD_OR_START ||
+ u->meta.job->type == JOB_RESTART))
+ return true;
+
+ return false;
+}
+
static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
[UNIT_STUB] = "stub",
[UNIT_LOADED] = "loaded",
diff --git a/src/unit.h b/src/unit.h
index 20bb6a2a18..47a1eb6350 100644
--- a/src/unit.h
+++ b/src/unit.h
@@ -500,6 +500,7 @@ void unit_reset_failed(Unit *u);
Unit *unit_following(Unit *u);
bool unit_pending_inactive(Unit *u);
+bool unit_pending_active(Unit *u);
int unit_add_default_target_dependency(Unit *u, Unit *target);