From 83c60c9f0c7581b607dc5c0f84582978894e3d4a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 23 Jan 2010 22:56:47 +0100 Subject: [PATCH] implement proper binding on ports --- job.c | 11 ++-- main.c | 8 +-- manager.c | 10 ++++ manager.h | 2 + name.c | 33 ++++++------ name.h | 2 +- socket-util.c | 10 ++-- socket-util.h | 2 +- socket.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++----- test1/postfix.socket | 4 +- test1/syslog.socket | 4 +- 11 files changed, 181 insertions(+), 49 deletions(-) diff --git a/job.c b/job.c index 0ae1a76..7accf72 100644 --- a/job.c +++ b/job.c @@ -362,6 +362,8 @@ int job_run_and_invalidate(Job *j) { if (j->state != JOB_WAITING) return 0; + j->state = JOB_RUNNING; + switch (j->type) { case JOB_START: @@ -422,11 +424,12 @@ int job_run_and_invalidate(Job *j) { ; } - if (r >= 0) - j->state = JOB_RUNNING; - else if (r == -EALREADY) + if (r == -EALREADY) r = job_finish_and_invalidate(j, true); - else if (r != -EAGAIN) + else if (r == -EAGAIN) { + j->state = JOB_WAITING; + return -EAGAIN; + } else if (r < 0) r = job_finish_and_invalidate(j, false); return r; diff --git a/main.c b/main.c index b22a639..f073c8f 100644 --- a/main.c +++ b/main.c @@ -42,13 +42,7 @@ int main(int argc, char *argv[]) { printf("- By jobs:\n"); manager_dump_jobs(m, stdout, "\t"); - if ((r = manager_add_job(m, JOB_STOP, syslog, JOB_REPLACE, false, &job)) < 0) { - log_error("Failed to start default milestone: %s", strerror(-r)); - goto finish; - } - - printf("- By jobs:\n"); - manager_dump_jobs(m, stdout, "\t"); + manager_run_jobs(m); retval = 0; diff --git a/manager.c b/manager.c index 27b740e..7941d89 100644 --- a/manager.c +++ b/manager.c @@ -882,3 +882,13 @@ void manager_clear_jobs(Manager *m) { while ((j = hashmap_first(m->jobs))) job_free(j); } + +void manager_run_jobs(Manager *m) { + Job *j; + void *state; + int r; + + HASHMAP_FOREACH(j, m->jobs, state) { + r = job_run_and_invalidate(j); + } +} diff --git a/manager.h b/manager.h index e669f9f..68f0dd9 100644 --- a/manager.h +++ b/manager.h @@ -54,4 +54,6 @@ void manager_transaction_unlink_job(Manager *m, Job *j); void manager_clear_jobs(Manager *m); +void manager_run_jobs(Manager *m); + #endif diff --git a/name.c b/name.c index 33d7f34..b6e62e9 100644 --- a/name.c +++ b/name.c @@ -617,7 +617,7 @@ static void retroactively_stop_dependencies(Name *n) { manager_add_job(n->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL); } -int name_notify(Name *n, NameActiveState os, NameActiveState ns) { +void name_notify(Name *n, NameActiveState os, NameActiveState ns) { assert(n); assert(os < _NAME_ACTIVE_STATE_MAX); assert(ns < _NAME_ACTIVE_STATE_MAX); @@ -625,7 +625,7 @@ int name_notify(Name *n, NameActiveState os, NameActiveState ns) { assert(!(os == NAME_INACTIVE && ns == NAME_DEACTIVATING)); if (os == ns) - return 0; + return; if (n->meta.job) { @@ -649,10 +649,11 @@ int name_notify(Name *n, NameActiveState os, NameActiveState ns) { case JOB_START: case JOB_VERIFY_ACTIVE: - if (NAME_IS_ACTIVE_OR_RELOADING(ns)) - return job_finish_and_invalidate(n->meta.job, true); - else if (ns == NAME_ACTIVATING) - return 0; + if (NAME_IS_ACTIVE_OR_RELOADING(ns)) { + job_finish_and_invalidate(n->meta.job, true); + return; + } else if (ns == NAME_ACTIVATING) + return; else job_finish_and_invalidate(n->meta.job, false); @@ -661,10 +662,11 @@ int name_notify(Name *n, NameActiveState os, NameActiveState ns) { case JOB_RELOAD: case JOB_RELOAD_OR_START: - if (ns == NAME_ACTIVE) - return job_finish_and_invalidate(n->meta.job, true); - else if (ns == NAME_ACTIVATING || ns == NAME_ACTIVE_RELOADING) - return 0; + if (ns == NAME_ACTIVE) { + job_finish_and_invalidate(n->meta.job, true); + return; + } else if (ns == NAME_ACTIVATING || ns == NAME_ACTIVE_RELOADING) + return; else job_finish_and_invalidate(n->meta.job, false); @@ -674,10 +676,11 @@ int name_notify(Name *n, NameActiveState os, NameActiveState ns) { case JOB_RESTART: case JOB_TRY_RESTART: - if (ns == NAME_INACTIVE) - return job_finish_and_invalidate(n->meta.job, true); - else if (ns == NAME_DEACTIVATING) - return 0; + if (ns == NAME_INACTIVE) { + job_finish_and_invalidate(n->meta.job, true); + return; + } else if (ns == NAME_DEACTIVATING) + return; else job_finish_and_invalidate(n->meta.job, false); @@ -696,6 +699,4 @@ int name_notify(Name *n, NameActiveState os, NameActiveState ns) { retroactively_start_dependencies(n); else if (NAME_IS_ACTIVE_OR_ACTIVATING(os) && NAME_IS_INACTIVE_OR_DEACTIVATING(ns)) retroactively_stop_dependencies(n); - - return 0; } diff --git a/name.h b/name.h index 33baea1..8c526ba 100644 --- a/name.h +++ b/name.h @@ -189,6 +189,6 @@ int name_start(Name *n); int name_stop(Name *n); int name_reload(Name *n); -int name_notify(Name *n, NameActiveState old, NameActiveState new); +void name_notify(Name *n, NameActiveState os, NameActiveState ns); #endif diff --git a/socket-util.c b/socket-util.c index 525c334..1024ecb 100644 --- a/socket-util.c +++ b/socket-util.c @@ -115,13 +115,13 @@ int socket_address_parse(SocketAddress *a, const char *s) { idx = if_nametoindex(n); free(n); - if (n == 0) + if (idx == 0) return -EINVAL; a->sockaddr.in6.sin6_family = AF_INET6; a->sockaddr.in6.sin6_port = htons((uint16_t) u); a->sockaddr.in6.sin6_scope_id = idx; - memcpy(&a->sockaddr.in6.sin6_addr, &in6addr_any, INET6_ADDRSTRLEN); + a->sockaddr.in6.sin6_addr = in6addr_any; a->size = sizeof(struct sockaddr_in6); } } else { @@ -135,7 +135,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { a->sockaddr.in6.sin6_family = AF_INET6; a->sockaddr.in6.sin6_port = htons((uint16_t) u); - memcpy(&a->sockaddr.in6.sin6_addr, &in6addr_any, INET6_ADDRSTRLEN); + a->sockaddr.in6.sin6_addr = in6addr_any; a->size = sizeof(struct sockaddr_in6); } } @@ -274,9 +274,10 @@ int socket_address_print(const SocketAddress *a, char **p) { } } -int socket_address_listen(const SocketAddress *a, int backlog, SocketAddressBindIPv6Only only) { +int socket_address_listen(const SocketAddress *a, int backlog, SocketAddressBindIPv6Only only, int *ret) { int r, fd; assert(a); + assert(ret); if ((r = socket_address_verify(a)) < 0) return r; @@ -304,5 +305,6 @@ int socket_address_listen(const SocketAddress *a, int backlog, SocketAddressBind return -errno; } + *ret = fd; return 0; } diff --git a/socket-util.h b/socket-util.h index bea3a89..1f939ae 100644 --- a/socket-util.h +++ b/socket-util.h @@ -38,6 +38,6 @@ typedef enum SocketAddressBindIPv6Only { int socket_address_parse(SocketAddress *a, const char *s); int socket_address_print(const SocketAddress *a, char **p); int socket_address_verify(const SocketAddress *a); -int socket_address_listen(const SocketAddress *a, int backlog, SocketAddressBindIPv6Only only); +int socket_address_listen(const SocketAddress *a, int backlog, SocketAddressBindIPv6Only only, int *ret); #endif diff --git a/socket.c b/socket.c index 9b69487..ed14db5 100644 --- a/socket.c +++ b/socket.c @@ -1,7 +1,25 @@ /*-*- Mode: C; c-basic-offset: 8 -*-*/ +#include +#include +#include +#include +#include + #include "name.h" #include "socket.h" +#include "log.h" + +static const NameActiveState state_table[_SOCKET_STATE_MAX] = { + [SOCKET_DEAD] = NAME_INACTIVE, + [SOCKET_START_PRE] = NAME_ACTIVATING, + [SOCKET_START_POST] = NAME_ACTIVATING, + [SOCKET_LISTENING] = NAME_ACTIVE, + [SOCKET_RUNNING] = NAME_ACTIVE, + [SOCKET_STOP_PRE] = NAME_DEACTIVATING, + [SOCKET_STOP_POST] = NAME_DEACTIVATING, + [SOCKET_MAINTAINANCE] = NAME_INACTIVE, +}; static int socket_load(Name *n) { Socket *s = SOCKET(n); @@ -87,28 +105,130 @@ static void socket_dump(Name *n, FILE *f, const char *prefix) { } } +static void socket_set_state(Socket *s, SocketState state) { + SocketState old_state; + assert(s); + + old_state = s->state; + s->state = state; + + name_notify(NAME(s), state_table[old_state], state_table[s->state]); +} + +static void close_fds(Socket *s) { + SocketPort *p; + + assert(s); + + LIST_FOREACH(p, s->ports) { + if (p->fd < 0) + continue; + + close_nointr(p->fd); + p->fd = -1; + } +} + static int socket_start(Name *n) { + Socket *s = SOCKET(n); + SocketPort *p; + int r; + + assert(s); + + if (s->state == SOCKET_START_PRE || + s->state == SOCKET_START_POST) + return 0; + + if (s->state == SOCKET_LISTENING || + s->state == SOCKET_RUNNING) + return -EALREADY; + + if (s->state == SOCKET_STOP_PRE || + s->state == SOCKET_STOP_POST) + return -EAGAIN; + + assert(s->state == SOCKET_DEAD || s->state == SOCKET_MAINTAINANCE); + + LIST_FOREACH(p, s->ports) { + + assert(p->fd < 0); + + if (p->type == SOCKET_SOCKET) { + + if ((r = socket_address_listen(&p->address, s->backlog, s->bind_ipv6_only, &p->fd)) < 0) + goto rollback; + + } else { + struct stat st; + assert(p->type == SOCKET_FIFO); + + if (mkfifo(p->path, 0666 & ~s->exec_context.umask) < 0 && errno != EEXIST) { + r = -errno; + goto rollback; + } + + if ((p->fd = open(p->path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) { + r = -errno; + goto rollback; + } + + if (fstat(p->fd, &st) < 0) { + r = -errno; + goto rollback; + } + + /* FIXME verify user, access mode */ + + if (!S_ISFIFO(st.st_mode)) { + r = -EEXIST; + goto rollback; + } + } + } + + socket_set_state(s, SOCKET_LISTENING); + return 0; + +rollback: + close_fds(s); + + socket_set_state(s, SOCKET_MAINTAINANCE); + + return r; } static int socket_stop(Name *n) { + Socket *s = SOCKET(n); + + assert(s); + + if (s->state == SOCKET_START_PRE || + s->state == SOCKET_START_POST) + return -EAGAIN; + + if (s->state == SOCKET_DEAD || + s->state == SOCKET_MAINTAINANCE) + return -EALREADY; + + if (s->state == SOCKET_STOP_PRE || + s->state == SOCKET_STOP_POST) + return 0; + + assert(s->state == SOCKET_LISTENING || s->state == SOCKET_RUNNING); + + close_fds(s); + + socket_set_state(s, SOCKET_DEAD); + return 0; } static NameActiveState socket_active_state(Name *n) { + assert(n); - static const NameActiveState table[_SOCKET_STATE_MAX] = { - [SOCKET_DEAD] = NAME_INACTIVE, - [SOCKET_START_PRE] = NAME_ACTIVATING, - [SOCKET_START_POST] = NAME_ACTIVATING, - [SOCKET_LISTENING] = NAME_ACTIVE, - [SOCKET_RUNNING] = NAME_ACTIVE, - [SOCKET_STOP_PRE] = NAME_DEACTIVATING, - [SOCKET_STOP_POST] = NAME_DEACTIVATING, - [SOCKET_MAINTAINANCE] = NAME_INACTIVE, - }; - - return table[SOCKET(n)->state]; + return state_table[SOCKET(n)->state]; } static void socket_free_hook(Name *n) { diff --git a/test1/postfix.socket b/test1/postfix.socket index 81c2b07..1baae5b 100644 --- a/test1/postfix.socket +++ b/test1/postfix.socket @@ -2,5 +2,5 @@ Description=Postfix SMTP Socket [Socket] -ListenStream=25 -ListenFIFO=/dev/test +ListenStream=53333 +ListenFIFO=/tmp/systemd-fifo diff --git a/test1/syslog.socket b/test1/syslog.socket index 73a5662..8d7baa5 100644 --- a/test1/syslog.socket +++ b/test1/syslog.socket @@ -2,5 +2,5 @@ Description=Syslog Socket [Socket] -ListenDatagram=/dev/log -ListenStream=eth0:4711 +ListenDatagram=/tmp/systemd-socket +ListenStream=eth0:3456 -- 2.7.4