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
}
}