]> granicus.if.org Git - libnl/commitdiff
Fix creation and destruction of sockets
authorThomas Graf <tgr@deb.localdomain>
Mon, 17 Dec 2007 15:26:49 +0000 (16:26 +0100)
committerThomas Graf <tgr@deb.localdomain>
Mon, 17 Dec 2007 15:26:49 +0000 (16:26 +0100)
Fixes an off-by-one when releasing local ports. Fixes nl_connect()
to properly close the socket upon failure. Return EBADFD if
operations are performed on unconnected sockets where appropriate.
Makes nl_handle_alloc() return an error if all local ports are
used up.

lib/nl.c
lib/socket.c
tests/test-socket-creation.c

index 3866846ae0bbf4971568cb6b1cfb96150e07fe3f..fd69de7349d4e29b6d0b22963dc7c8ae3501ae95 100644 (file)
--- a/lib/nl.c
+++ b/lib/nl.c
@@ -194,35 +194,50 @@ int nl_connect(struct nl_handle *handle, int protocol)
        socklen_t addrlen;
 
        handle->h_fd = socket(AF_NETLINK, SOCK_RAW, protocol);
-       if (handle->h_fd < 0)
-               return nl_error(1, "socket(AF_NETLINK, ...) failed");
+       if (handle->h_fd < 0) {
+               err = nl_error(1, "socket(AF_NETLINK, ...) failed");
+               goto errout;
+       }
 
        if (!(handle->h_flags & NL_SOCK_BUFSIZE_SET)) {
                err = nl_set_buffer_size(handle, 0, 0);
                if (err < 0)
-                       return err;
+                       goto errout;
        }
 
        err = bind(handle->h_fd, (struct sockaddr*) &handle->h_local,
                   sizeof(handle->h_local));
-       if (err < 0)
-               return nl_error(1, "bind() failed");
+       if (err < 0) {
+               err = nl_error(1, "bind() failed");
+               goto errout;
+       }
 
        addrlen = sizeof(handle->h_local);
        err = getsockname(handle->h_fd, (struct sockaddr *) &handle->h_local,
                          &addrlen);
-       if (err < 0)
-               return nl_error(1, "getsockname failed");
+       if (err < 0) {
+               err = nl_error(1, "getsockname failed");
+               goto errout;
+       }
 
-       if (addrlen != sizeof(handle->h_local))
-               return nl_error(EADDRNOTAVAIL, "Invalid address length");
+       if (addrlen != sizeof(handle->h_local)) {
+               err = nl_error(EADDRNOTAVAIL, "Invalid address length");
+               goto errout;
+       }
 
-       if (handle->h_local.nl_family != AF_NETLINK)
-               return nl_error(EPFNOSUPPORT, "Address format not supported");
+       if (handle->h_local.nl_family != AF_NETLINK) {
+               err = nl_error(EPFNOSUPPORT, "Address format not supported");
+               goto errout;
+       }
 
        handle->h_proto = protocol;
 
        return 0;
+errout:
+       close(handle->h_fd);
+       handle->h_fd = -1;
+
+       return err;
 }
 
 /**
index f68e8cfd0d6b76e1565c3ad4e6ea344e7cec4fd4..4e24c4536f4dff7ab4062859e3e4e8444d6b258d 100644 (file)
@@ -127,9 +127,13 @@ static uint32_t generate_local_port(void)
 
 static void release_local_port(uint32_t port)
 {
-       int nr = port >> 22;
+       int nr;
 
-       used_ports_map[nr / 32] &= ~(nr % 32);
+       if (port == UINT_MAX)
+               return;
+       
+       nr = port >> 22;
+       used_ports_map[nr / 32] &= ~((nr % 32) + 1);
 }
 
 /**
@@ -147,11 +151,17 @@ static struct nl_handle *__alloc_handle(struct nl_cb *cb)
                return NULL;
        }
 
+       handle->h_fd = -1;
        handle->h_cb = cb;
        handle->h_local.nl_family = AF_NETLINK;
-       handle->h_local.nl_pid = generate_local_port();
        handle->h_peer.nl_family = AF_NETLINK;
        handle->h_seq_expect = handle->h_seq_next = time(0);
+       handle->h_local.nl_pid = generate_local_port();
+       if (handle->h_local.nl_pid == UINT_MAX) {
+               nl_handle_destroy(handle);
+               nl_error(ENOBUFS, "Out of sequence numbers");
+               return NULL;
+       }
 
        return handle;
 }
@@ -200,6 +210,9 @@ void nl_handle_destroy(struct nl_handle *handle)
        if (!handle)
                return;
 
+       if (handle->h_fd >= 0)
+               close(handle->h_fd);
+
        if (!(handle->h_flags & NL_OWN_PORT))
                release_local_port(handle->h_local.nl_pid);
 
@@ -311,6 +324,9 @@ int nl_socket_add_membership(struct nl_handle *handle, int group)
 {
        int err;
 
+       if (handle->h_fd == -1)
+               return nl_error(EBADFD, "Socket not connected");
+
        err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
                         &group, sizeof(group));
        if (err < 0)
@@ -335,6 +351,9 @@ int nl_socket_drop_membership(struct nl_handle *handle, int group)
 {
        int err;
 
+       if (handle->h_fd == -1)
+               return nl_error(EBADFD, "Socket not connected");
+
        err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
                         &group, sizeof(group));
        if (err < 0)
@@ -396,6 +415,9 @@ int nl_socket_get_fd(struct nl_handle *handle)
  */
 int nl_socket_set_nonblocking(struct nl_handle *handle)
 {
+       if (handle->h_fd == -1)
+               return nl_error(EBADFD, "Socket not connected");
+
        if (fcntl(handle->h_fd, F_SETFL, O_NONBLOCK) < 0)
                return nl_error(errno, "fcntl(F_SETFL, O_NONBLOCK) failed");
 
@@ -484,6 +506,9 @@ int nl_set_buffer_size(struct nl_handle *handle, int rxbuf, int txbuf)
 
        if (txbuf <= 0)
                txbuf = 32768;
+
+       if (handle->h_fd == -1)
+               return nl_error(EBADFD, "Socket not connected");
        
        err = setsockopt(handle->h_fd, SOL_SOCKET, SO_SNDBUF,
                         &txbuf, sizeof(txbuf));
@@ -511,6 +536,9 @@ int nl_set_passcred(struct nl_handle *handle, int state)
 {
        int err;
 
+       if (handle->h_fd == -1)
+               return nl_error(EBADFD, "Socket not connected");
+
        err = setsockopt(handle->h_fd, SOL_SOCKET, SO_PASSCRED,
                         &state, sizeof(state));
        if (err < 0)
@@ -535,6 +563,9 @@ int nl_socket_recv_pktinfo(struct nl_handle *handle, int state)
 {
        int err;
 
+       if (handle->h_fd == -1)
+               return nl_error(EBADFD, "Socket not connected");
+
        err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_PKTINFO,
                         &state, sizeof(state));
        if (err < 0)
index 5a06661d9a9978a93d58ec4fb5eba281ac433305..4066eef97505e11fb38d0e17fb88ad3e7c150488 100644 (file)
@@ -2,13 +2,25 @@
 
 int main(int argc, char *argv[])
 {
-       struct nl_handle *h;
+       struct nl_handle *h[1025];
        int i;
 
+       h[0] = nl_handle_alloc();
+       printf("Created handle with port 0x%x\n",
+                       nl_socket_get_local_port(h[0]));
+       nl_handle_destroy(h[0]);
+       h[0] = nl_handle_alloc();
+       printf("Created handle with port 0x%x\n",
+                       nl_socket_get_local_port(h[0]));
+       nl_handle_destroy(h[0]);
+
        for (i = 0; i < 1025; i++) {
-               h = nl_handle_alloc();
-               printf("Created handle with port 0x%x\n",
-                       nl_socket_get_local_port(h));
+               h[i] = nl_handle_alloc();
+               if (h[i] == NULL)
+                       nl_perror("Unable to allocate socket");
+               else
+                       printf("Created handle with port 0x%x\n",
+                               nl_socket_get_local_port(h[i]));
        }
 
        return 0;