nell 0.3.0

Linux netlink interface
Documentation
// Copyright (C) 2020 - Will Glozer. All rights reserved.

use std::convert::TryFrom;
use std::mem::size_of;
use std::os::raw::{c_int, c_void};
use std::os::unix::io::AsRawFd;
use errno::errno;
use libc::*;
use crate::Result;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(transparent)]
pub struct Level(c_int);

impl Level {
    pub const NETLINK: Level = Self(SOL_NETLINK);
    pub const SOCKET:  Level = Self(SOL_SOCKET);

    pub const fn from(n: c_int) -> Self {
        Self(n)
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(transparent)]
pub struct Name(c_int);

impl Name {
    pub const NETLINK_PKTINFO:          Name = Self(NETLINK_PKTINFO);
    pub const NETLINK_ADD_MEMBERSHIP:   Name = Self(NETLINK_ADD_MEMBERSHIP);
    pub const NETLINK_DROP_MEMBERSHIP:  Name = Self(NETLINK_DROP_MEMBERSHIP);
    pub const NETLINK_LIST_MEMBERSHIPS: Name = Self(NETLINK_LIST_MEMBERSHIPS);
    pub const NETLINK_BROADCAST_ERROR:  Name = Self(NETLINK_BROADCAST_ERROR);
    pub const NETLINK_NO_ENOBUFS:       Name = Self(NETLINK_NO_ENOBUFS);
    pub const NETLINK_LISTEN_ALL_NSID:  Name = Self(NETLINK_LISTEN_ALL_NSID);
    pub const NETLINK_CAP_ACK:          Name = Self(NETLINK_CAP_ACK);

    pub const SO_RCVBUF:                Name = Self(SO_RCVBUF);
    pub const SO_SNDBUF:                Name = Self(SO_SNDBUF);

    pub const fn from(n: c_int) -> Self {
        Self(n)
    }
}

pub unsafe trait Opt: Copy + Default {
    fn socklen() -> Result<socklen_t> {
        Ok(socklen_t::try_from(size_of::<Self>())?)
    }

    fn as_mut_ptr(&mut self) -> *mut c_void {
        self as *mut _ as *mut _
    }
}

pub fn getsockopt<T: AsRawFd, O: Opt>(sock: &T, level: Level, name: Name) -> Result<O> {
    let fd = sock.as_raw_fd();

    let mut val = O::default();
    let mut len = O::socklen()?;
    let ptr = val.as_mut_ptr();

    unsafe {
        match libc::getsockopt(fd, level.into(), name.into(), ptr, &mut len) {
            0 => Ok(val),
            _ => Err(errno().into()),
        }
    }
}

pub fn setsockopt<T: AsRawFd, O: Opt>(sock: &T, level: Level, name: Name, value: &O) -> Result<()> {
    let fd  = sock.as_raw_fd();
    let ptr = value as *const _ as *const _;
    let len = O::socklen()?;

    unsafe {
        match libc::setsockopt(fd, level.into(), name.into(), ptr, len) {
            0 => Ok(()),
            _ => Err(errno().into()),
        }
    }
}

pub fn list_memberships<T: AsRawFd>(sock: &T) -> Result<Vec<u32>> {
    let fd = sock.as_raw_fd();

    let level = Level::NETLINK;
    let name  = Name::NETLINK_LIST_MEMBERSHIPS;

    let mut groups = [0u32; 32];
    let mut len = socklen_t::try_from(groups.len())?;
    let ptr = groups.as_mut_ptr();

    let n = unsafe {
        match libc::getsockopt(fd, level.into(), name.into(), ptr, &mut len) {
            0 => Ok(usize::try_from(len)?),
            _ => Err(errno()),
        }
    }?;

    Ok(groups[..n].to_vec())
}

unsafe impl Opt for c_int     {}
unsafe impl Opt for [u32; 32] {}

impl Into<c_int> for Level {
    fn into(self) -> c_int {
        self.0
    }
}

impl Into<c_int> for Name {
    fn into(self) -> c_int {
        self.0
    }
}