diff options
-rw-r--r-- | include/netlink-private/types.h | 1 | ||||
-rw-r--r-- | include/netlink/netlink.h | 2 | ||||
-rw-r--r-- | include/netlink/socket.h | 3 | ||||
-rw-r--r-- | lib/nl.c | 105 | ||||
-rw-r--r-- | lib/socket.c | 68 | ||||
-rw-r--r-- | libnl-3.sym | 1 |
6 files changed, 90 insertions, 90 deletions
diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h index 7d044f1..54f06b5 100644 --- a/include/netlink-private/types.h +++ b/include/netlink-private/types.h @@ -77,7 +77,6 @@ struct nl_sock int s_flags; struct nl_cb * s_cb; size_t s_bufsize; - int s_cloexec; }; struct nl_cache diff --git a/include/netlink/netlink.h b/include/netlink/netlink.h index 7b6cb60..f8f2082 100644 --- a/include/netlink/netlink.h +++ b/include/netlink/netlink.h @@ -49,8 +49,6 @@ extern struct nl_dump_params nl_debug_dp; /* Connection Management */ extern int nl_connect(struct nl_sock *, int); -extern int nl_create_fd(struct nl_sock *, int); -extern int nl_connect_fd(struct nl_sock *, int, int); extern void nl_close(struct nl_sock *); /* Send */ diff --git a/include/netlink/socket.h b/include/netlink/socket.h index bda0ff3..9a68cad 100644 --- a/include/netlink/socket.h +++ b/include/netlink/socket.h @@ -60,11 +60,10 @@ extern void nl_socket_disable_auto_ack(struct nl_sock *); extern void nl_socket_enable_auto_ack(struct nl_sock *); extern int nl_socket_get_fd(const struct nl_sock *); +extern int nl_socket_set_fd(struct nl_sock *sk, int protocol, int fd); extern int nl_socket_set_nonblocking(const struct nl_sock *); extern void nl_socket_enable_msg_peek(struct nl_sock *); extern void nl_socket_disable_msg_peek(struct nl_sock *); -extern int nl_socket_enable_cloexec(struct nl_sock *); -extern void nl_socket_disable_cloexec(struct nl_sock *); #ifdef __cplusplus } @@ -63,57 +63,19 @@ */ /** - * Create file descriptor. + * Create file descriptor and bind socket. * @arg sk Netlink socket (required) * @arg protocol Netlink protocol to use (required) * - * Creates a new Netlink socket using `socket()` . Fails if - * the socket is already connected. - */ -int nl_create_fd(struct nl_sock *sk, int protocol) -{ - int err, flags = 0; - int errsv; - char buf[64]; - - -#ifdef SOCK_CLOEXEC - if (sk->s_cloexec == 1) - flags |= SOCK_CLOEXEC; -#endif - - if (sk->s_fd != -1) - return -NLE_BAD_SOCK; - - sk->s_fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol); - if (sk->s_fd < 0) { - errsv = errno; - NL_DBG(4, "nl_connect(%p): socket() failed with %d (%s)\n", sk, errsv, - strerror_r(errsv, buf, sizeof(buf))); - err = -nl_syserr2nlerr(errsv); - goto errout; - } - - return 0; - -errout: - if (sk->s_fd != -1) { - close(sk->s_fd); - sk->s_fd = -1; - } - - return err; -} - -/** - * Create file descriptor and bind socket. - * @arg sk Netlink socket (required) - * @arg protocol Netlink protocol to use (required) - * * Creates a new Netlink socket using `socket()` and binds the socket to the * protocol and local port specified in the `sk` socket object. Fails if * the socket is already connected. * + * @note If available, the `close-on-exec` (`SOCK_CLOEXEC`) feature is enabled + * automatically on the new file descriptor. This causes the socket to + * be closed automatically if any of the `exec` family functions succeed. + * This is essential for multi threaded programs. + * * @note The local port (`nl_socket_get_local_port()`) is unspecified after * creating a new socket. It only gets determined when accessing the * port the first time or during `nl_connect()`. When nl_connect() @@ -124,8 +86,13 @@ errout: * This capability is indicated by * `%NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE`. * + * @note nl_connect() creates and sets the file descriptor. You can setup the file + * descriptor yourself by creating and binding it, and then calling + * nl_socket_set_fd(). The result will be the same. + * * @see nl_socket_alloc() * @see nl_close() + * @see nl_socket_set_fd() * * @return 0 on success or a negative error code. * @@ -133,47 +100,27 @@ errout: */ int nl_connect(struct nl_sock *sk, int protocol) { - int err = nl_create_fd(sk, protocol); - if (err != 0) - return err; - - return nl_connect_fd(sk, protocol, sk->s_fd); -} - -/** - * @arg sk Netlink socket (required) - * @arg protocol Netlink protocol to use (required) - * @arg fd Socket file descriptor to use (required) - * - * @note The local port (`nl_socket_get_local_port()`) is unspecified after - * creating a new socket. It only gets determined when accessing the - * port the first time or during `nl_connect_fd()`. When nl_connect_fd() - * fails during `bind()` due to `ADDRINUSE`, it will retry with - * different ports if the port is unspecified. Unless you want to enforce - * the use of a specific local port, don't access the local port (or - * reset it to `unspecified` by calling `nl_socket_set_local_port(sk, 0)`). - * This capability is indicated by - * `%NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE`. - * - * @see nl_socket_alloc() - * @see nl_close() - * - * @return 0 on success or a negative error code. - * - * @retval -NLE_BAD_SOCK Socket is not connected - */ -int nl_connect_fd(struct nl_sock *sk, int protocol, int fd) -{ - int err = 0; + int err, flags = 0; int errsv; socklen_t addrlen; struct sockaddr_nl local = { 0 }; char buf[64]; - if (fd < 0) - return -NLE_BAD_SOCK; +#ifdef SOCK_CLOEXEC + flags |= SOCK_CLOEXEC; +#endif - sk->s_fd = fd; + if (sk->s_fd != -1) + return -NLE_BAD_SOCK; + + sk->s_fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol); + if (sk->s_fd < 0) { + errsv = errno; + NL_DBG(4, "nl_connect(%p): socket() failed with %d (%s)\n", sk, errsv, + strerror_r(errsv, buf, sizeof(buf))); + err = -nl_syserr2nlerr(errsv); + goto errout; + } err = nl_socket_set_buffer_size(sk, 0, 0); if (err < 0) diff --git a/lib/socket.c b/lib/socket.c index 01cc219..049b8b9 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -192,12 +192,6 @@ static struct nl_sock *__alloc_socket(struct nl_cb *cb) sk->s_peer.nl_family = AF_NETLINK; sk->s_seq_expect = sk->s_seq_next = time(NULL); -#ifdef SOCK_CLOEXEC - sk->s_cloexec = 1; -#else - sk->s_cloexec = 0; -#endif - /* the port is 0 (unspecified), meaning NL_OWN_PORT */ sk->s_flags = NL_OWN_PORT; @@ -579,6 +573,68 @@ int nl_socket_get_fd(const struct nl_sock *sk) } /** + * Set the socket file descriptor externally which initializes the + * socket similar to nl_connect(). + * + * @arg sk Netlink socket (required) + * @arg protocol Netlink protocol to use (required) + * @arg fd Socket file descriptor to use (required) + * + * Set the socket file descriptor. @fd must be valid and bind'ed. + * + * This is an alternative to nl_connect(). nl_connect() creates, binds and + * sets the socket. With this function you can set the socket to an externally + * created file descriptor. + * + * @see nl_connect() + * + * @return 0 on success or a negative error code. On error, @fd is not closed but + * possibly unusable. + * + * @retval -NLE_BAD_SOCK Netlink socket is already connected + * @retval -NLE_INVAL Socket is not connected + */ +int nl_socket_set_fd(struct nl_sock *sk, int protocol, int fd) +{ + int err = 0; + socklen_t addrlen; + char buf[64]; + struct sockaddr_nl local = { 0 }; + + if (sk->s_fd != -1) + return -NLE_BAD_SOCK; + if (fd < 0) + return -NLE_INVAL; + + addrlen = sizeof(local); + err = getsockname(fd, (struct sockaddr *) &local, + &addrlen); + if (err < 0) { + NL_DBG(4, "nl_socket_set_fd(%p): getsockname() failed with %d (%s)\n", + sk, errno, strerror_r(errno, buf, sizeof(buf))); + return -nl_syserr2nlerr(errno); + } + + if (addrlen != sizeof(local)) + return -NLE_NOADDR; + + if (local.nl_family != AF_NETLINK) + return -NLE_AF_NOSUPPORT; + + if (sk->s_local.nl_pid != local.nl_pid) { + /* the port id differs. The socket is using a port id not managed by + * libnl, hence reset the local port id to release a possibly generated + * port. */ + nl_socket_set_local_port (sk, local.nl_pid); + } + sk->s_local = local; + sk->s_fd = fd; + sk->s_proto = protocol; + + return 0; +} + +/** * Set file descriptor of socket to non-blocking state * @arg sk Netlink socket. * diff --git a/libnl-3.sym b/libnl-3.sym index df61001..c8ef8a3 100644 --- a/libnl-3.sym +++ b/libnl-3.sym @@ -328,4 +328,5 @@ libnl_3_2_26 { global: nl_cache_pickup_checkdup; nl_pickup_keep_syserr; + nl_socket_set_fd; } libnl_3; |