lib/socket: add nl_socket_set_fd() function

This is based on the patch by sagil@infinidat.com, but heavily modified.

Add a function nl_socket_set_fd(), I renamed it from nl_connect_fd().

Now nl_connect() and nl_socket_set_fd() are implemented independently as
they share little code. But they have similar functionality:
to initialize a libnl socket and set it's file descriptor.

A user who wants libnl to setup the socket can continue to use nl_connect().
A user with special requirements should setup the socket entirely. That includes
calling socket() (with or without SOCK_CLOEXEC), bind(), setting buffer size.

For the same reason I dropped nl_create_fd(). It didn't do much more then
calling socket() -- which the user can do directly.

https://github.com/thom311/libnl/pull/68

Signed-off-by: Thomas Haller <thaller@redhat.com>
This commit is contained in:
Thomas Haller 2015-03-05 10:39:43 +01:00
commit 2d61e89037
4 changed files with 71 additions and 2 deletions

View File

@ -60,6 +60,7 @@ 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 *);

View File

@ -86,8 +86,13 @@
* 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.
*
@ -105,8 +110,8 @@ int nl_connect(struct nl_sock *sk, int protocol)
flags |= SOCK_CLOEXEC;
#endif
if (sk->s_fd != -1)
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) {

View File

@ -572,6 +572,68 @@ int nl_socket_get_fd(const struct nl_sock *sk)
return sk->s_fd;
}
/**
* 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.

View File

@ -328,4 +328,5 @@ libnl_3_2_26 {
global:
nl_cache_pickup_checkdup;
nl_pickup_keep_syserr;
nl_socket_set_fd;
} libnl_3;