]> git.ipfire.org Git - thirdparty/libnl.git/commitdiff
lib/socket: add nl_socket_set_fd() function
authorThomas Haller <thaller@redhat.com>
Thu, 5 Mar 2015 09:39:43 +0000 (10:39 +0100)
committerThomas Haller <thaller@redhat.com>
Thu, 5 Mar 2015 11:10:28 +0000 (12:10 +0100)
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>
1  2 
include/netlink/socket.h
lib/nl.c
lib/socket.c
libnl-3.sym

index 1007eba03ad982b67402f3d4b01cfc480fdf50ec,bda0ff3509fde6ae35e96b8af675b17a018cd9ff..9a68cad9fd76f337b2fe717fa05fa07ca8866fd3
@@@ -60,6 -60,6 +60,7 @@@ extern void           nl_socket_disable_auto_ack
  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 --cc lib/nl.c
index 8e4c4552cf4e59e1765119cf25993ec1aef20208,4997e7984491246f096952dc0430debc994433dd..8fc9ec104a2357053f461b528bddaca9bf74ffd4
+++ b/lib/nl.c
   *       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.
   *
@@@ -101,21 -170,10 +106,21 @@@ int nl_connect(struct nl_sock *sk, int 
        struct sockaddr_nl local = { 0 };
        char buf[64];
  
 -    if (fd < 0)
 -        return -NLE_BAD_SOCK;
 +#ifdef SOCK_CLOEXEC
 +      flags |= SOCK_CLOEXEC;
 +#endif
  
-         if (sk->s_fd != -1)
-                 return -NLE_BAD_SOCK;
 -    sk->s_fd = fd;
++      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;
 +      }
  
        err = nl_socket_set_buffer_size(sk, 0, 0);
        if (err < 0)
diff --cc lib/socket.c
index 628a96de5c7dc7badc25b6aed5455eae6e6b422f,01cc2193e64fc16e7f9e0e1ab5347068588f44cc..049b8b9ce544024cec0a3229998682225d322dd1
@@@ -572,6 -578,6 +572,68 @@@ int nl_socket_get_fd(const struct nl_so
        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.
diff --cc libnl-3.sym
index df61001ab3bd7f59cb06fedf4e6c592c1d67e3b4,df61001ab3bd7f59cb06fedf4e6c592c1d67e3b4..c8ef8a35a2af99d1e77e41b1194c07c2c2b95c81
@@@ -328,4 -328,4 +328,5 @@@ libnl_3_2_26 
  global:
        nl_cache_pickup_checkdup;
        nl_pickup_keep_syserr;
++      nl_socket_set_fd;
  } libnl_3;