1
0
mirror of https://github.com/danog/libdvb.git synced 2024-11-26 20:04:39 +01:00

net refactoring

This commit is contained in:
Andrey Dyldin 2021-03-05 17:04:10 +02:00
parent 0b23424405
commit 8fe2424f56
2 changed files with 84 additions and 103 deletions

View File

@ -1,43 +1,32 @@
use { use anyhow::{Context, bail};
std::{
path::Path,
},
use {
anyhow::Result, anyhow::Result,
libdvb::NetDevice, libdvb::NetDevice,
}; };
fn check_net(path: &Path) -> Result<()> {
println!("NET: {}", path.display());
let dev = NetDevice::open(path)?;
let mut info = libdvb::net::sys::DvbNetIf {
pid: 0,
if_num: 0,
feedtype: libdvb::net::sys::DVB_NET_FEEDTYPE_MPE,
};
dev.add_if(&mut info)?;
println!("Interface: {}", dev.get_name());
println!("MAC: {}", dev.get_mac());
dev.remove_if(&info)?;
Ok(())
}
fn main() -> Result<()> { fn main() -> Result<()> {
let mut args = std::env::args().skip(1); let mut args = std::env::args().skip(1);
if let Some(path) = args.next() {
let path = Path::new(&path); let adapter = match args.next() {
check_net(&path)?; Some(v) => v.parse::<u32>().context("adapter number")?,
} else { None => bail!("adapter number not defined"),
eprintln!("path to ca device is not defined"); };
}
let device = match args.next() {
Some(v) => v.parse::<u32>().context("device number")?,
None => 0,
};
let dev = NetDevice::open(adapter, device)?;
let interface = dev.add_if(0, libdvb::net::sys::DVB_NET_FEEDTYPE_MPE)?;
println!("Interface: {}", &interface);
let mac = interface.get_mac();
println!("MAC: {}", &mac);
dev.remove_if(interface)?;
Ok(()) Ok(())
} }

View File

@ -3,13 +3,12 @@ pub mod sys;
use { use {
std::{ std::{
io::{ fmt,
Read,
},
fs::{ fs::{
File, File,
OpenOptions, OpenOptions,
}, },
io::Read,
os::unix::{ os::unix::{
fs::{ fs::{
OpenOptionsExt, OpenOptionsExt,
@ -19,7 +18,6 @@ use {
RawFd, RawFd,
}, },
}, },
path::Path,
}, },
anyhow::{ anyhow::{
@ -28,17 +26,6 @@ use {
}, },
nix::{ nix::{
fcntl::{
readlink,
},
sys::{
stat::{
fstat,
major,
minor,
},
},
ioctl_readwrite, ioctl_readwrite,
ioctl_write_int_bad, ioctl_write_int_bad,
request_code_none, request_code_none,
@ -49,18 +36,16 @@ use {
pub const EMPTY_MAC: &str = "00:00:00:00:00:00"; pub const EMPTY_MAC: &str = "00:00:00:00:00:00";
const MAC_SIZE: usize = EMPTY_MAC.len();
/// A reference to the network device /// A reference to the network device
#[derive(Debug)] #[derive(Debug)]
pub struct NetDevice { pub struct NetDevice {
adapter: u32,
device: u32,
file: File, file: File,
/// Interface name
name: String,
/// MAC address
mac: String,
} }
@ -70,86 +55,93 @@ impl AsRawFd for NetDevice {
} }
fn read_interface_name<T: AsRawFd>(file: &T) -> Result<String> {
let s = fstat(file.as_raw_fd())?;
let path = format!("/sys/dev/char/{}:{}", major(s.st_rdev), minor(s.st_rdev));
let name = readlink(path.as_str())?
.to_str()
.unwrap_or_default()
.rsplit('/')
.next()
.unwrap_or_default()
.split(".net")
.collect::<Vec<&str>>()
.join("_");
Ok(name)
}
fn read_mac_address(name: &str) -> Result<String> {
ensure!(name.starts_with("dvb"), "incorrect interface name");
let len = 2 * 6 + 5;
let mut mac = String::with_capacity(len);
let path = format!("/sys/class/net/{}/address", name);
let file = File::open(&path)?;
file.take(len as u64).read_to_string(&mut mac)?;
Ok(mac)
}
impl NetDevice { impl NetDevice {
/// Attempts to open a network device in read-write mode /// Attempts to open a network device in read-write mode
pub fn open<P: AsRef<Path>>(path: P) -> Result<NetDevice> { pub fn open(adapter: u32, device: u32) -> Result<NetDevice> {
let path = format!("/dev/dvb/adapter{}/net{}", adapter, device);
let file = OpenOptions::new() let file = OpenOptions::new()
.read(true) .read(true)
.write(true) .write(true)
.custom_flags(::nix::libc::O_NONBLOCK) .custom_flags(::nix::libc::O_NONBLOCK)
.open(path) .open(&path)
.context("NET: open")?; .context("NET: open")?;
let name = read_interface_name(&file).context("NET: read interface name")?;
let mac = read_mac_address(&name).unwrap_or_else(|_| EMPTY_MAC.to_owned());
let net = NetDevice { let net = NetDevice {
adapter,
device,
file, file,
name,
mac,
}; };
Ok(net) Ok(net)
} }
/// Returns interface name in format `dvb{0}_{1}` where `{0}` is adapter number /// Creates a new network interface and returns interface number
/// and `{1}` is a device number pub fn add_if(&self, pid: u16, feedtype: u8) -> Result<NetInterface> {
pub fn get_name(&self) -> &str { self.name.as_str() } let mut data = DvbNetIf {
pid,
if_num: 0,
feedtype,
};
/// Returns interface MAC address
pub fn get_mac(&self) -> &str { self.mac.as_str() }
/// Creates a new network interface
pub fn add_if(&self, data: &mut DvbNetIf) -> Result<()> {
// NET_ADD_IF // NET_ADD_IF
ioctl_readwrite!(#[inline] ioctl_call, b'o', 52, DvbNetIf); ioctl_readwrite!(#[inline] ioctl_call, b'o', 52, DvbNetIf);
unsafe { unsafe {
ioctl_call(self.as_raw_fd(), data as *mut _) ioctl_call(self.as_raw_fd(), &mut data as *mut _)
}.context("NET: add if")?; }.context("NET: add if")?;
Ok(()) Ok(NetInterface {
net: self,
if_num: data.if_num,
})
} }
/// Removes a network interface /// Removes a network interface
pub fn remove_if(&self, data: &DvbNetIf) -> Result<()> { pub fn remove_if(&self, interface: NetInterface) -> Result<()> {
// NET_REMOVE_IF // NET_REMOVE_IF
ioctl_write_int_bad!(#[inline] ioctl_call, request_code_none!(b'o', 53)); ioctl_write_int_bad!(#[inline] ioctl_call, request_code_none!(b'o', 53));
unsafe { unsafe {
ioctl_call(self.as_raw_fd(), data.if_num as _) ioctl_call(self.as_raw_fd(), i32::from(interface.if_num))
}.context("NET: remove if")?; }.context("NET: remove if")?;
Ok(()) Ok(())
} }
} }
pub struct NetInterface<'a> {
net: &'a NetDevice,
if_num: u16,
}
impl<'a> fmt::Display for NetInterface<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.net.device == 0 {
write!(f, "dvb{}_{}", self.net.adapter, self.if_num)
} else {
write!(f, "dvb{}{}{}", self.net.adapter, self.net.device, self.if_num)
}
}
}
impl<'a> NetInterface<'a> {
/// Returns interface mac address or empty mac on any error
pub fn get_mac(&self) -> String {
let path = format!("/sys/class/net/{}/address", self);
let file = match File::open(&path) {
Ok(v) => v,
_ => return EMPTY_MAC.to_owned(),
};
let mut mac = String::with_capacity(MAC_SIZE);
let result = file
.take(MAC_SIZE as u64)
.read_to_string(&mut mac);
match result {
Ok(MAC_SIZE) => mac,
_ => EMPTY_MAC.to_owned(),
}
}
}