summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2015-03-05 09:39:43 (GMT)
committerThomas Haller <thaller@redhat.com>2015-03-05 11:10:28 (GMT)
commit2d61e890379888907a93ddd0a04187b130629f6f (patch)
tree5ff06ee6e8aa229615012961d5fe6617684da2ed
parent9614acf4c4354892b5b734cace4778acfc019999 (diff)
parentf91e6959eae3a819decaa2cc20d2af9d827060f3 (diff)
downloadlibnl-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>
-rw-r--r--include/netlink/socket.h1
-rw-r--r--lib/nl.c9
-rw-r--r--lib/socket.c62
-rw-r--r--libnl-3.sym1
4 files changed, 71 insertions, 2 deletions
diff --git a/include/netlink/socket.h b/include/netlink/socket.h
index 1007eba..9a68cad 100644
--- a/include/netlink/socket.h
+++ b/include/netlink/socket.h
@@ -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 *);
diff --git a/lib/nl.c b/lib/nl.c
index 8e4c455..8fc9ec1 100644
--- a/lib/nl.c
+++ b/lib/nl.c
@@ -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.
*
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;