chiark / gitweb /
nspawn: add new option "--port=" for exposing container ports on the local host
[elogind.git] / src / libsystemd / sd-rtnl / sd-rtnl.c
index 543bad9f4f4447d82abbf62cd01b8440428755a2..a45ca5e9f57370528836a1fc8aa6be862e8cc124 100644 (file)
@@ -22,6 +22,7 @@
 #include <sys/socket.h>
 #include <poll.h>
 
+#include "missing.h"
 #include "macro.h"
 #include "util.h"
 #include "hashmap.h"
@@ -75,42 +76,101 @@ static bool rtnl_pid_changed(sd_rtnl *rtnl) {
         return rtnl->original_pid != getpid();
 }
 
-int sd_rtnl_open(sd_rtnl **ret, uint32_t groups) {
+static int rtnl_compute_groups_ap(uint32_t *_groups, unsigned n_groups, va_list ap) {
+        uint32_t groups = 0;
+        unsigned i;
+
+        for (i = 0; i < n_groups; i++) {
+                unsigned group;
+
+                group = va_arg(ap, unsigned);
+                assert_return(group < 32, -EINVAL);
+
+                groups |= group ? (1 << (group - 1)) : 0;
+        }
+
+        *_groups = groups;
+
+        return 0;
+}
+
+static int rtnl_open_fd_ap(sd_rtnl **ret, int fd, unsigned n_groups, va_list ap) {
         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
         socklen_t addrlen;
         int r, one = 1;
 
         assert_return(ret, -EINVAL);
+        assert_return(fd >= 0, -EINVAL);
 
         r = sd_rtnl_new(&rtnl);
         if (r < 0)
                 return r;
 
-        rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
-        if (rtnl->fd < 0)
+        r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
+        if (r < 0)
                 return -errno;
 
-        if (setsockopt(rtnl->fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
+        r = setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
+        if (r < 0)
                 return -errno;
 
-        rtnl->sockaddr.nl.nl_groups = groups;
+        r = rtnl_compute_groups_ap(&rtnl->sockaddr.nl.nl_groups, n_groups, ap);
+        if (r < 0)
+                return r;
 
         addrlen = sizeof(rtnl->sockaddr);
 
-        r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
+        r = bind(fd, &rtnl->sockaddr.sa, addrlen);
         if (r < 0)
                 return -errno;
 
-        r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
+        r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
         if (r < 0)
                 return r;
 
+        rtnl->fd = fd;
+
         *ret = rtnl;
         rtnl = NULL;
 
         return 0;
 }
 
+int sd_rtnl_open_fd(sd_rtnl **ret, int fd, unsigned n_groups, ...) {
+        va_list ap;
+        int r;
+
+        va_start(ap, n_groups);
+        r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
+        va_end(ap);
+
+        return r;
+}
+
+int sd_rtnl_open(sd_rtnl **ret, unsigned n_groups, ...) {
+        va_list ap;
+        int fd, r;
+
+        fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
+        if (fd < 0)
+                return -errno;
+
+        va_start(ap, n_groups);
+        r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
+        va_end(ap);
+
+        if (r < 0) {
+                safe_close(fd);
+                return r;
+        }
+
+        return 0;
+}
+
+int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size) {
+        return fd_inc_rcvbuf(rtnl->fd, size);
+}
+
 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
         assert_return(rtnl, NULL);
         assert_return(!rtnl_pid_changed(rtnl), NULL);
@@ -444,7 +504,7 @@ static usec_t calc_elapse(uint64_t usec) {
 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
         struct pollfd p[1] = {};
         struct timespec ts;
-        usec_t m = (usec_t) -1;
+        usec_t m = USEC_INFINITY;
         int r, e;
 
         assert(rtnl);
@@ -456,7 +516,7 @@ static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
         if (need_more)
                 /* Caller wants more data, and doesn't care about
                  * what's been read or any other timeouts. */
-                return e |= POLLIN;
+                e |= POLLIN;
         else {
                 usec_t until;
                 /* Caller wants to process if there is something to
@@ -528,7 +588,7 @@ int sd_rtnl_call_async(sd_rtnl *nl,
         assert_return(callback, -EINVAL);
         assert_return(!rtnl_pid_changed(nl), -ECHILD);
 
-        r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
+        r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
         if (r < 0)
                 return r;
 
@@ -651,7 +711,7 @@ int sd_rtnl_call(sd_rtnl *rtnl,
                 if (r < 0)
                         return r;
                 if (r > 0)
-                        /* receieved message, so try to process straight away */
+                        /* received message, so try to process straight away */
                         continue;
 
                 if (timeout > 0) {
@@ -668,6 +728,8 @@ int sd_rtnl_call(sd_rtnl *rtnl,
                 r = rtnl_poll(rtnl, true, left);
                 if (r < 0)
                         return r;
+                else if (r == 0)
+                        return -ETIMEDOUT;
 
                 r = dispatch_wqueue(rtnl);
                 if (r < 0)
@@ -830,6 +892,10 @@ int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
         if (r < 0)
                 goto fail;
 
+        r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
+        if (r < 0)
+                goto fail;
+
         r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
         if (r < 0)
                 goto fail;
@@ -842,10 +908,18 @@ int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
         if (r < 0)
                 goto fail;
 
+        r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
+        if (r < 0)
+                goto fail;
+
         r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
         if (r < 0)
                 goto fail;
 
+        r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
+        if (r < 0)
+                goto fail;
+
         return 0;
 
 fail: