Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/netlink-private/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ struct nl_sock
int s_flags;
struct nl_cb * s_cb;
size_t s_bufsize;
int s_cloexec;
};

struct nl_cache
Expand Down
2 changes: 2 additions & 0 deletions include/netlink/netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ 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 */
Expand Down
3 changes: 3 additions & 0 deletions include/netlink/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ 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
}
#endif
Expand Down
98 changes: 77 additions & 21 deletions lib/nl.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,54 @@
*/

/**
* Create file descriptor and bind socket.
* Create file descriptor.
* @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;

#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, "create_socket(%p): socket() failed with %d\n", sk, errsv);
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()
Expand All @@ -95,24 +130,45 @@
*/
int nl_connect(struct nl_sock *sk, int protocol)
{
int err, flags = 0;
int errsv;
socklen_t addrlen;
int err = nl_create_fd(sk, protocol);
if (err != 0)
return err;

#ifdef SOCK_CLOEXEC
flags |= SOCK_CLOEXEC;
#endif
return nl_connect_fd(sk, protocol, sk->s_fd);
}

if (sk->s_fd != -1)
return -NLE_BAD_SOCK;
/**
* @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 errsv;
socklen_t addrlen;

if (fd < 0)
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\n", sk, errsv);
err = -nl_syserr2nlerr(errsv);
goto errout;
}
sk->s_fd = fd;

if (!(sk->s_flags & NL_SOCK_BUFSIZE_SET)) {
err = nl_socket_set_buffer_size(sk, 0, 0);
Expand Down
6 changes: 6 additions & 0 deletions lib/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,12 @@ 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;

Expand Down