Logo Search packages:      
Sourcecode: libnl version File versions  Download package

int nl_recv ( struct nl_handle *  handle,
struct sockaddr_nl nla,
unsigned char **  buf,
struct ucred **  creds 
)

Receive data from netlink socket

  • handle Netlink handle.
  • nla Destination pointer for peer's netlink address.
  • buf Destination pointer for message content.
  • creds Destination pointer for credentials.
Receives a netlink message, allocates a buffer in *buf and stores the message content. The peer's netlink address is stored in *nla. The caller is responsible for freeing the buffer allocated in *buf if a positive value is returned. Interruped system calls are handled by repeating the read. The input buffer size is determined by peeking before the actual read is done.

A non-blocking sockets causes the function to return immediately with a return value of 0 if no data is available.

Returns:
Number of octets read, 0 on EOF or a negative error code.

Definition at line 460 of file nl.c.

{
      int n;
      int flags = 0;
      static int page_size = 0;
      struct iovec iov;
      struct msghdr msg = {
            .msg_name = (void *) nla,
            .msg_namelen = sizeof(struct sockaddr_nl),
            .msg_iov = &iov,
            .msg_iovlen = 1,
            .msg_control = NULL,
            .msg_controllen = 0,
            .msg_flags = 0,
      };
      struct cmsghdr *cmsg;

      if (handle->h_flags & NL_MSG_PEEK)
            flags |= MSG_PEEK;

      if (page_size == 0)
            page_size = getpagesize();

      iov.iov_len = page_size;
      iov.iov_base = *buf = calloc(1, iov.iov_len);

      if (handle->h_flags & NL_SOCK_PASSCRED) {
            msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
            msg.msg_control = calloc(1, msg.msg_controllen);
      }
retry:

      n = recvmsg(handle->h_fd, &msg, flags);
      if (!n)
            goto abort;
      else if (n < 0) {
            if (errno == EINTR) {
                  NL_DBG(3, "recvmsg() returned EINTR, retrying\n");
                  goto retry;
            } else if (errno == EAGAIN) {
                  NL_DBG(3, "recvmsg() returned EAGAIN, aborting\n");
                  goto abort;
            } else {
                  free(msg.msg_control);
                  free(*buf);
                  return nl_error(errno, "recvmsg failed");
            }
      }

      if (iov.iov_len < n ||
          msg.msg_flags & MSG_TRUNC) {
            /* Provided buffer is not long enough, enlarge it
             * and try again. */
            iov.iov_len *= 2;
            iov.iov_base = *buf = realloc(*buf, iov.iov_len);
            goto retry;
      } else if (msg.msg_flags & MSG_CTRUNC) {
            msg.msg_controllen *= 2;
            msg.msg_control = realloc(msg.msg_control, msg.msg_controllen);
            goto retry;
      } else if (flags != 0) {
            /* Buffer is big enough, do the actual reading */
            flags = 0;
            goto retry;
      }

      if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
            free(msg.msg_control);
            free(*buf);
            return nl_error(EADDRNOTAVAIL, "socket address size mismatch");
      }

      for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
            if (cmsg->cmsg_level == SOL_SOCKET &&
                cmsg->cmsg_type == SCM_CREDENTIALS) {
                  *creds = calloc(1, sizeof(struct ucred));
                  memcpy(*creds, CMSG_DATA(cmsg), sizeof(struct ucred));
                  break;
            }
      }

      free(msg.msg_control);
      return n;

abort:
      free(msg.msg_control);
      free(*buf);
      return 0;
}


Generated by  Doxygen 1.6.0   Back to index