diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h index 0149604d2a..4997936fa9 100644 --- a/src/libsystemd-bus/bus-internal.h +++ b/src/libsystemd-bus/bus-internal.h @@ -74,7 +74,7 @@ enum bus_auth { struct sd_bus { unsigned n_ref; enum bus_state state; - int fd; + int input_fd, output_fd; int message_version; bool negotiate_fds:1; diff --git a/src/libsystemd-bus/bus-socket.c b/src/libsystemd-bus/bus-socket.c index fed1971ec7..9d08674bf7 100644 --- a/src/libsystemd-bus/bus-socket.c +++ b/src/libsystemd-bus/bus-socket.c @@ -88,7 +88,7 @@ static int bus_socket_write_auth(sd_bus *b) { mh.msg_iov = b->auth_iovec + b->auth_index; mh.msg_iovlen = ELEMENTSOF(b->auth_iovec) - b->auth_index; - k = sendmsg(b->fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL); + k = sendmsg(b->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL); if (k < 0) return errno == EAGAIN ? 0 : -errno; @@ -463,7 +463,7 @@ static int bus_socket_read_auth(sd_bus *b) { mh.msg_control = &control; mh.msg_controllen = sizeof(control); - k = recvmsg(b->fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); + k = recvmsg(b->input_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); if (k < 0) return errno == EAGAIN ? 0 : -errno; if (k == 0) @@ -515,12 +515,12 @@ static int bus_socket_setup(sd_bus *b) { /* Enable SO_PASSCRED + SO_PASSEC. We try this on any * socket, just in case. */ enable = !b->bus_client; - setsockopt(b->fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable)); - setsockopt(b->fd, SOL_SOCKET, SO_PASSSEC, &enable, sizeof(enable)); + setsockopt(b->input_fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable)); + setsockopt(b->input_fd, SOL_SOCKET, SO_PASSSEC, &enable, sizeof(enable)); /* Increase the buffers to a MB */ - fd_inc_rcvbuf(b->fd, 1024*1024); - fd_inc_sndbuf(b->fd, 1024*1024); + fd_inc_rcvbuf(b->input_fd, 1024*1024); + fd_inc_sndbuf(b->output_fd, 1024*1024); return 0; } @@ -577,13 +577,17 @@ static int bus_socket_start_auth(sd_bus *b) { b->auth_timeout = now(CLOCK_MONOTONIC) + BUS_DEFAULT_TIMEOUT; sl = sizeof(domain); - r = getsockopt(b->fd, SOL_SOCKET, SO_DOMAIN, &domain, &sl); - if (r < 0) - return -errno; - - if (domain != AF_UNIX) + r = getsockopt(b->input_fd, SOL_SOCKET, SO_DOMAIN, &domain, &sl); + if (r < 0 || domain != AF_UNIX) b->negotiate_fds = false; + if (b->output_fd != b->input_fd) { + r = getsockopt(b->output_fd, SOL_SOCKET, SO_DOMAIN, &domain, &sl); + if (r < 0 || domain != AF_UNIX) + b->negotiate_fds = false; + } + + if (b->is_server) return bus_socket_read_auth(b); else @@ -594,18 +598,21 @@ int bus_socket_connect(sd_bus *b) { int r; assert(b); - assert(b->fd < 0); + assert(b->input_fd < 0); + assert(b->output_fd < 0); assert(b->sockaddr.sa.sa_family != AF_UNSPEC); - b->fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (b->fd < 0) + b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (b->input_fd < 0) return -errno; + b->output_fd = b->input_fd; + r = bus_socket_setup(b); if (r < 0) return r; - r = connect(b->fd, &b->sockaddr.sa, b->sockaddr_size); + r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size); if (r < 0) { if (errno == EINPROGRESS) return 1; @@ -617,15 +624,16 @@ int bus_socket_connect(sd_bus *b) { } int bus_socket_exec(sd_bus *b) { - int s[2]; + int s[2], r; pid_t pid; assert(b); - assert(b->fd < 0); + assert(b->input_fd < 0); + assert(b->output_fd < 0); assert(b->exec_path); - b->fd = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, s); - if (b->fd < 0) + r = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, s); + if (r < 0) return -errno; pid = fork(); @@ -636,8 +644,9 @@ int bus_socket_exec(sd_bus *b) { if (pid == 0) { /* Child */ - close_all_fds(s, 2); - close_nointr_nofail(s[0]); + reset_all_signal_handlers(); + + close_all_fds(s+1, 1); assert_se(dup3(s[1], STDIN_FILENO, 0) == STDIN_FILENO); assert_se(dup3(s[1], STDOUT_FILENO, 0) == STDOUT_FILENO); @@ -661,7 +670,7 @@ int bus_socket_exec(sd_bus *b) { } close_nointr_nofail(s[1]); - b->fd = s[0]; + b->output_fd = b->input_fd = s[0]; return bus_socket_start_auth(b); } @@ -714,7 +723,7 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { mh.msg_iov = iov; mh.msg_iovlen = m->n_iovec; - k = sendmsg(bus->fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL); + k = sendmsg(bus->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL); if (k < 0) return errno == EAGAIN ? 0 : -errno; @@ -854,7 +863,7 @@ int bus_socket_read_message(sd_bus *bus, sd_bus_message **m) { mh.msg_control = &control; mh.msg_controllen = sizeof(control); - k = recvmsg(bus->fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); + k = recvmsg(bus->input_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); if (k < 0) return errno == EAGAIN ? 0 : -errno; if (k == 0) @@ -924,7 +933,7 @@ int bus_socket_process_opening(sd_bus *b) { assert(b->state == BUS_OPENING); zero(p); - p.fd = b->fd; + p.fd = b->output_fd; p.events = POLLOUT; r = poll(&p, 1, 0); @@ -934,7 +943,7 @@ int bus_socket_process_opening(sd_bus *b) { if (!(p.revents & (POLLOUT|POLLERR|POLLHUP))) return 0; - r = getsockopt(b->fd, SOL_SOCKET, SO_ERROR, &error, &slen); + r = getsockopt(b->output_fd, SOL_SOCKET, SO_ERROR, &error, &slen); if (r < 0) b->last_connect_error = errno; else if (error != 0) diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index a71d7b5d77..4f004add2e 100644 --- a/src/libsystemd-bus/sd-bus.c +++ b/src/libsystemd-bus/sd-bus.c @@ -48,8 +48,7 @@ static void bus_free(sd_bus *b) { assert(b); - if (b->fd >= 0) - close_nointr_nofail(b->fd); + sd_bus_close(b); free(b->rbuffer); free(b->unique_name); @@ -101,7 +100,7 @@ int sd_bus_new(sd_bus **ret) { return -ENOMEM; r->n_ref = 1; - r->fd = -1; + r->input_fd = r->output_fd = -1; r->message_version = 1; r->negotiate_fds = true; @@ -137,15 +136,18 @@ int sd_bus_set_address(sd_bus *bus, const char *address) { return 0; } -int sd_bus_set_fd(sd_bus *bus, int fd) { +int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) { if (!bus) return -EINVAL; if (bus->state != BUS_UNSET) return -EPERM; - if (fd < 0) + if (input_fd < 0) + return -EINVAL; + if (output_fd < 0) return -EINVAL; - bus->fd = fd; + bus->input_fd = input_fd; + bus->output_fd = output_fd; return 0; } @@ -679,10 +681,7 @@ static int bus_start_address(sd_bus *b) { assert(b); for (;;) { - if (b->fd >= 0) { - close_nointr_nofail(b->fd); - b->fd = -1; - } + sd_bus_close(b); if (b->sockaddr.sa.sa_family != AF_UNSPEC) { @@ -720,15 +719,27 @@ static int bus_start_fd(sd_bus *b) { int r; assert(b); + assert(b->input_fd >= 0); + assert(b->output_fd >= 0); - r = fd_nonblock(b->fd, true); + r = fd_nonblock(b->input_fd, true); if (r < 0) return r; - r = fd_cloexec(b->fd, true); + r = fd_cloexec(b->input_fd, true); if (r < 0) return r; + if (b->input_fd != b->output_fd) { + r = fd_nonblock(b->output_fd, true); + if (r < 0) + return r; + + r = fd_cloexec(b->output_fd, true); + if (r < 0) + return r; + } + return bus_socket_take_fd(b); } @@ -745,7 +756,7 @@ int sd_bus_start(sd_bus *bus) { if (bus->is_server && bus->bus_client) return -EINVAL; - if (bus->fd >= 0) + if (bus->input_fd >= 0) r = bus_start_fd(bus); else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path) r = bus_start_address(bus); @@ -848,11 +859,13 @@ fail: void sd_bus_close(sd_bus *bus) { if (!bus) return; - if (bus->fd < 0) - return; - close_nointr_nofail(bus->fd); - bus->fd = -1; + if (bus->input_fd >= 0) + close_nointr_nofail(bus->input_fd); + if (bus->output_fd >= 0 && bus->output_fd != bus->input_fd) + close_nointr_nofail(bus->output_fd); + + bus->input_fd = bus->output_fd = -1; } sd_bus *sd_bus_ref(sd_bus *bus) { @@ -882,7 +895,7 @@ int sd_bus_is_open(sd_bus *bus) { if (!bus) return -EINVAL; - return bus->state != BUS_UNSET && bus->fd >= 0; + return bus->state != BUS_UNSET && bus->input_fd >= 0; } int sd_bus_can_send(sd_bus *bus, char type) { @@ -890,7 +903,7 @@ int sd_bus_can_send(sd_bus *bus, char type) { if (!bus) return -EINVAL; - if (bus->fd < 0) + if (bus->output_fd < 0) return -ENOTCONN; if (type == SD_BUS_TYPE_UNIX_FD) { @@ -941,7 +954,7 @@ static int dispatch_wqueue(sd_bus *bus) { assert(bus); assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); - if (bus->fd < 0) + if (bus->output_fd < 0) return -ENOTCONN; while (bus->wqueue_size > 0) { @@ -984,7 +997,7 @@ static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) { assert(m); assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; if (bus->rqueue_size > 0) { @@ -1020,7 +1033,7 @@ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial) { return -EINVAL; if (bus->state == BUS_UNSET) return -ENOTCONN; - if (bus->fd < 0) + if (bus->output_fd < 0) return -ENOTCONN; if (!m) return -EINVAL; @@ -1129,7 +1142,7 @@ int sd_bus_send_with_reply( return -EINVAL; if (bus->state == BUS_UNSET) return -ENOTCONN; - if (bus->fd < 0) + if (bus->output_fd < 0) return -ENOTCONN; if (!m) return -EINVAL; @@ -1211,7 +1224,7 @@ int bus_ensure_running(sd_bus *bus) { assert(bus); - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; if (bus->state == BUS_UNSET) return -ENOTCONN; @@ -1248,7 +1261,7 @@ int sd_bus_send_with_reply_and_block( if (!bus) return -EINVAL; - if (bus->fd < 0) + if (bus->output_fd < 0) return -ENOTCONN; if (bus->state == BUS_UNSET) return -ENOTCONN; @@ -1358,11 +1371,12 @@ int sd_bus_send_with_reply_and_block( int sd_bus_get_fd(sd_bus *bus) { if (!bus) return -EINVAL; - - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; + if (bus->input_fd != bus->output_fd) + return -EPERM; - return bus->fd; + return bus->input_fd; } int sd_bus_get_events(sd_bus *bus) { @@ -1372,7 +1386,7 @@ int sd_bus_get_events(sd_bus *bus) { return -EINVAL; if (bus->state == BUS_UNSET) return -ENOTCONN; - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; if (bus->state == BUS_OPENING) @@ -1403,7 +1417,7 @@ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) { return -EINVAL; if (bus->state == BUS_UNSET) return -ENOTCONN; - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; if (bus->state == BUS_AUTHENTICATING) { @@ -1824,7 +1838,7 @@ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) { if (!bus) return -EINVAL; - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; switch (bus->state) { @@ -1859,14 +1873,14 @@ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) { } static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { - struct pollfd p; - int r, e; + struct pollfd p[2]; + int r, e, n; struct timespec ts; usec_t until, m; assert(bus); - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; e = sd_bus_get_events(bus); @@ -1882,19 +1896,28 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { if (r == 0) m = (uint64_t) -1; else { - usec_t n; - n = now(CLOCK_MONOTONIC); - m = until > n ? until - n : 0; + usec_t nw; + nw = now(CLOCK_MONOTONIC); + m = until > nw ? until - nw : 0; } if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m)) m = timeout_usec; zero(p); - p.fd = bus->fd; - p.events = e; + p[0].fd = bus->input_fd; - r = ppoll(&p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL); + if (bus->output_fd == bus->input_fd) { + p[0].events = e; + n = 1; + } else { + p[0].events = e & POLLIN; + p[1].fd = bus->output_fd; + p[1].events = e & POLLOUT; + n = 2; + } + + r = ppoll(p, n, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL); if (r < 0) return -errno; @@ -1907,7 +1930,7 @@ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) { return -EINVAL; if (bus->state == BUS_UNSET) return -ENOTCONN; - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; if (bus->rqueue_size > 0) return 0; @@ -1922,7 +1945,7 @@ int sd_bus_flush(sd_bus *bus) { return -EINVAL; if (bus->state == BUS_UNSET) return -ENOTCONN; - if (bus->fd < 0) + if (bus->output_fd < 0) return -ENOTCONN; r = bus_ensure_running(bus); diff --git a/src/libsystemd-bus/test-bus-server.c b/src/libsystemd-bus/test-bus-server.c index 2cb4157498..a594ce3157 100644 --- a/src/libsystemd-bus/test-bus-server.c +++ b/src/libsystemd-bus/test-bus-server.c @@ -53,7 +53,7 @@ static void *server(void *p) { assert_se(sd_id128_randomize(&id) >= 0); assert_se(sd_bus_new(&bus) >= 0); - assert_se(sd_bus_set_fd(bus, c->fds[0]) >= 0); + assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0); assert_se(sd_bus_set_server(bus, 1, id) >= 0); assert_se(sd_bus_set_negotiate_fds(bus, c->server_negotiate_unix_fds) >= 0); assert_se(sd_bus_set_anonymous(bus, c->server_anonymous_auth) >= 0); @@ -132,7 +132,7 @@ static int client(struct context *c) { int r; assert_se(sd_bus_new(&bus) >= 0); - assert_se(sd_bus_set_fd(bus, c->fds[1]) >= 0); + assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0); assert_se(sd_bus_set_negotiate_fds(bus, c->client_negotiate_unix_fds) >= 0); assert_se(sd_bus_set_anonymous(bus, c->client_anonymous_auth) >= 0); assert_se(sd_bus_start(bus) >= 0);