chiark / gitweb /
rtnl: fix sockaddr confusion
authorTom Gundersen <teg@jklm.no>
Tue, 29 Oct 2013 20:20:25 +0000 (21:20 +0100)
committerTom Gundersen <teg@jklm.no>
Tue, 29 Oct 2013 20:26:22 +0000 (21:26 +0100)
src/libsystemd-rtnl/rtnl-internal.h
src/libsystemd-rtnl/rtnl-message.c
src/libsystemd-rtnl/sd-rtnl.c
src/libsystemd-rtnl/test-rtnl.c

index c24d12b..70bb6d0 100644 (file)
@@ -31,7 +31,8 @@ struct sd_rtnl {
                 struct sockaddr_nl nl;
         } sockaddr;
 
-        unsigned serial;
+        uint32_t serial;
+
         pid_t original_pid;
 };
 
index 557e690..eae73a6 100644 (file)
@@ -344,13 +344,19 @@ static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
 
 /* returns the number of bytes sent, or a negative error code */
 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } addr = {
+                .nl.nl_family = AF_NETLINK,
+        };
         ssize_t k;
 
         assert_return(nl, -EINVAL);
         assert_return(m, -EINVAL);
 
         k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
-                        0, &nl->sockaddr.sa, sizeof(nl->sockaddr));
+                        0, &addr.sa, sizeof(addr));
         if (k < 0)
                 return (errno == EAGAIN) ? 0 : -errno;
 
@@ -364,7 +370,11 @@ int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
  */
 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
         sd_rtnl_message *m;
-        socklen_t addr_len = sizeof(nl->sockaddr);
+        union {
+                struct sockaddr sa;
+                struct sockaddr_nl nl;
+        } addr;
+        socklen_t addr_len;
         int r;
         ssize_t k;
         size_t need;
@@ -380,21 +390,23 @@ int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
         if (r < 0)
                 return r;
 
+        addr_len = sizeof(addr);
+
         k = recvfrom(nl->fd, m->hdr, need,
-                        0, &nl->sockaddr.sa, &addr_len);
+                        0, &addr.sa, &addr_len);
         if (k < 0)
                 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
         else if (k == 0)
                 k = -ECONNRESET; /* connection was closed by the kernel */
-        else if (addr_len != sizeof(nl->sockaddr.nl) ||
-                        nl->sockaddr.nl.nl_family != AF_NETLINK)
+        else if (addr_len != sizeof(addr.nl) ||
+                        addr.nl.nl_family != AF_NETLINK)
                 k = -EIO; /* not a netlink message */
-        else if (nl->sockaddr.nl.nl_pid != 0)
+        else if (addr.nl.nl_pid != 0)
                 k = 0; /* not from the kernel */
         else if ((size_t) k < sizeof(struct nlmsghdr) ||
                         (size_t) k < m->hdr->nlmsg_len)
                 k = -EIO; /* too small (we do accept too big though) */
-        else if ((pid_t) m->hdr->nlmsg_pid != getpid())
+        else if (m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
                 k = 0; /* not for us */
 
         if (k > 0)
index 9c1f40e..ed145b9 100644 (file)
@@ -60,6 +60,7 @@ static bool rtnl_pid_changed(sd_rtnl *rtnl) {
 
 int sd_rtnl_open(uint32_t groups, sd_rtnl **ret) {
         _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        socklen_t addrlen;
         int r;
 
         r = sd_rtnl_new(&rtnl);
@@ -72,10 +73,16 @@ int sd_rtnl_open(uint32_t groups, sd_rtnl **ret) {
 
         rtnl->sockaddr.nl.nl_groups = groups;
 
-        r = bind(rtnl->fd, &rtnl->sockaddr.sa, sizeof(rtnl->sockaddr));
+        addrlen = sizeof(rtnl->sockaddr);
+
+        r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
         if (r < 0)
                 return -errno;
 
+        r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
+        if (r < 0)
+                return r;
+
         *ret = rtnl;
         rtnl = NULL;
 
index 1cdd6e1..601548b 100644 (file)
@@ -51,7 +51,17 @@ static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
         assert(type == IFLA_MTU);
         assert(mtu == *(unsigned int *) data);
 
-        assert(sd_rtnl_send_with_reply_and_block(rtnl, message, 2 * USEC_PER_SEC, NULL) == 0);
+        assert(sd_rtnl_send_with_reply_and_block(rtnl, message, 0, NULL) == 0);
+}
+
+static void test_multiple(void) {
+        sd_rtnl *rtnl1, *rtnl2;
+
+        assert(sd_rtnl_open(0, &rtnl1) >= 0);
+        assert(sd_rtnl_open(0, &rtnl2) >= 0);
+
+        rtnl1 = sd_rtnl_unref(rtnl1);
+        rtnl2 = sd_rtnl_unref(rtnl2);
 }
 
 int main(void) {
@@ -64,6 +74,8 @@ int main(void) {
         unsigned int mtu = 0;
         unsigned int *mtu_reply;
 
+        test_multiple();
+
         assert(sd_rtnl_open(0, &rtnl) >= 0);
         assert(rtnl);
 
@@ -80,7 +92,7 @@ int main(void) {
 
         assert(sd_rtnl_message_read(m, &type, &data) == 0);
 
-        assert(sd_rtnl_send_with_reply_and_block(rtnl, m, 100000000, &r) >= 0);
+        assert(sd_rtnl_send_with_reply_and_block(rtnl, m, 0, &r) >= 0);
         assert(sd_rtnl_message_get_type(r, &type) >= 0);
         assert(type == RTM_NEWLINK);