add socket nl_connect_fd() & nl_create_fd()
- Added option to create socket (fd) without bind. It is now possible to forward the socket fd to another child process... ...later use nl_connect_fd() to connect to socket from the child process. - Added option to disable CLOEXEC even if defined (in socket.h) 'nl_socket_enable_cloexec' & 'nl_socket_disable_cloexec' No change to current default behavior. Signed-off-by: Sagi Lowenhardt <sagil@infinidat.com>
This commit is contained in:
parent
9614acf4c4
commit
f91e6959ea
5 changed files with 90 additions and 21 deletions
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -63,6 +63,8 @@ extern int nl_socket_get_fd(const struct nl_sock *);
|
|||
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
|
||||
}
|
||||
|
|
100
lib/nl.c
100
lib/nl.c
|
@ -63,19 +63,57 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* 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;
|
||||
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()
|
||||
|
@ -95,27 +133,47 @@
|
|||
*/
|
||||
int nl_connect(struct nl_sock *sk, int protocol)
|
||||
{
|
||||
int err, flags = 0;
|
||||
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 errsv;
|
||||
socklen_t addrlen;
|
||||
struct sockaddr_nl local = { 0 };
|
||||
char buf[64];
|
||||
|
||||
#ifdef SOCK_CLOEXEC
|
||||
flags |= SOCK_CLOEXEC;
|
||||
#endif
|
||||
if (fd < 0)
|
||||
return -NLE_BAD_SOCK;
|
||||
|
||||
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;
|
||||
}
|
||||
sk->s_fd = fd;
|
||||
|
||||
err = nl_socket_set_buffer_size(sk, 0, 0);
|
||||
if (err < 0)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue