diff options
author | Thomas Haller <thaller@redhat.com> | 2015-03-05 09:39:43 (GMT) |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-03-05 11:10:28 (GMT) |
commit | 2d61e890379888907a93ddd0a04187b130629f6f (patch) | |
tree | 5ff06ee6e8aa229615012961d5fe6617684da2ed /lib | |
parent | 9614acf4c4354892b5b734cace4778acfc019999 (diff) | |
parent | f91e6959eae3a819decaa2cc20d2af9d827060f3 (diff) | |
download | libnl-2d61e890379888907a93ddd0a04187b130629f6f.zip libnl-2d61e890379888907a93ddd0a04187b130629f6f.tar.gz libnl-2d61e890379888907a93ddd0a04187b130629f6f.tar.bz2 |
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>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/nl.c | 9 | ||||
-rw-r--r-- | lib/socket.c | 62 |
2 files changed, 69 insertions, 2 deletions
@@ -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) { diff --git a/lib/socket.c b/lib/socket.c index 628a96d..049b8b9 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -573,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. * |