Receive data from Netlink socket.

    https://github.com/thom311/libnl/blob/libnl3_2_25/lib/nl.c#L625

    Receives data from a connected netlink socket using recvmsg() and returns the number of bytes read. The read data is
    stored in a newly allocated buffer that is assigned to `buf`. The peer's netlink address will be stored in `nla`.

    This function blocks until data is available to be read unless the socket has been put into non-blocking mode using
    nl_socket_set_nonblocking() in which case this function will return immediately with a return value of 0.

    The buffer size used when reading from the netlink socket and thus limiting the maximum size of a netlink message
    that can be read defaults to the size of a memory page (getpagesize()). The buffer size can be modified on a per
    socket level using the function `nl_socket_set_msg_buf_size()`.

    If message peeking is enabled using nl_socket_enable_msg_peek() the size of the message to be read will be
    determined using the MSG_PEEK flag prior to performing the actual read. This leads to an additional recvmsg() call
    for every read operation which has performance implications and is not recommended for high throughput protocols.

    An eventual interruption of the recvmsg() system call is automatically handled by retrying the operation.

    If receiving of credentials has been enabled using the function `nl_socket_set_passcred()`, this function will
    allocate a new struct `ucred` filled with the received credentials and assign it to `creds`.

    Positional arguments:
    sk -- Netlink socket (nl_sock class instance) (input).
    nla -- Netlink socket structure to hold address of peer (sockaddr_nl class instance) (output).
    buf -- destination bytearray() for message content (output).
    creds -- destination class instance for credentials (ucred class instance) (output).

    Returns:
    Two-item tuple. First item is number of bytes read, 0 on EOF, 0 on no data event (non-blocking mode), or a negative
    error code. Second item is the message content from the socket or None.

def nl_recv(sk, nla, buf, creds=None):
    """Receive data from Netlink socket.

    https://github.com/thom311/libnl/blob/libnl3_2_25/lib/nl.c#L625

    Receives data from a connected netlink socket using recvmsg() and returns the number of bytes read. The read data is
    stored in a newly allocated buffer that is assigned to `buf`. The peer's netlink address will be stored in `nla`.

    This function blocks until data is available to be read unless the socket has been put into non-blocking mode using
    nl_socket_set_nonblocking() in which case this function will return immediately with a return value of 0.

    The buffer size used when reading from the netlink socket and thus limiting the maximum size of a netlink message
    that can be read defaults to the size of a memory page (getpagesize()). The buffer size can be modified on a per
    socket level using the function `nl_socket_set_msg_buf_size()`.

    If message peeking is enabled using nl_socket_enable_msg_peek() the size of the message to be read will be
    determined using the MSG_PEEK flag prior to performing the actual read. This leads to an additional recvmsg() call
    for every read operation which has performance implications and is not recommended for high throughput protocols.

    An eventual interruption of the recvmsg() system call is automatically handled by retrying the operation.

    If receiving of credentials has been enabled using the function `nl_socket_set_passcred()`, this function will
    allocate a new struct `ucred` filled with the received credentials and assign it to `creds`.

    Positional arguments:
    sk -- Netlink socket (nl_sock class instance) (input).
    nla -- Netlink socket structure to hold address of peer (sockaddr_nl class instance) (output).
    buf -- destination bytearray() for message content (output).
    creds -- destination class instance for credentials (ucred class instance) (output).

    Returns:
    Two-item tuple. First item is number of bytes read, 0 on EOF, 0 on no data event (non-blocking mode), or a negative
    error code. Second item is the message content from the socket or None.
    """
    flags = 0
    page_size = resource.getpagesize() * 4
    if sk.s_flags & NL_MSG_PEEK:
        flags |= socket.MSG_PEEK | socket.MSG_TRUNC
    iov_len = sk.s_bufsize or page_size

    if creds and sk.s_flags & NL_SOCK_PASSCRED:
        raise NotImplementedError  # TODO https://github.com/Robpol86/libnl/issues/2

    while True:  # This is the `goto retry` implementation.
        try:
            if hasattr(sk.socket_instance, 'recvmsg'):
                iov, _, msg_flags, address = sk.socket_instance.recvmsg(iov_len, 0, flags)
            else:
                iov, address = sk.socket_instance.recvfrom(iov_len, flags)
                msg_flags = 0
        except OSError as exc:
            if exc.errno == errno.EINTR:
                continue  # recvmsg() returned EINTR, retrying.
            return -nl_syserr2nlerr(exc.errno)
        nla.nl_family = sk.socket_instance.family  # recvmsg() in C does this, but not Python's.
        if not iov:
            return 0

        if msg_flags & socket.MSG_CTRUNC:
            raise NotImplementedError  # TODO https://github.com/Robpol86/libnl/issues/2

        if iov_len < len(iov) or msg_flags & socket.MSG_TRUNC:
            # Provided buffer is not long enough.
            # Enlarge it to size of n (which should be total length of the message) and try again.
            iov_len = len(iov)
            continue

        if flags:
            # Buffer is big enough, do the actual reading.
            flags = 0
            continue

        nla.nl_pid = address[0]
        nla.nl_groups = address[1]

        if creds and sk.s_flags * NL_SOCK_PASSCRED:
            raise NotImplementedError  # TODO https://github.com/Robpol86/libnl/issues/2

        if iov:
            buf += iov

        return len(buf)