mirror of
https://github.com/danog/libdvb.git
synced 2024-11-30 04:19:00 +01:00
net device
This commit is contained in:
parent
5e9e38a372
commit
21712ee95e
@ -1,10 +1,32 @@
|
|||||||
use {
|
use {
|
||||||
std::{
|
std::{
|
||||||
path::Path,
|
path::Path,
|
||||||
|
os::unix::io::AsRawFd,
|
||||||
},
|
},
|
||||||
|
|
||||||
anyhow::Result,
|
anyhow::Result,
|
||||||
|
|
||||||
|
nix::{
|
||||||
|
poll::{
|
||||||
|
PollFd,
|
||||||
|
PollFlags,
|
||||||
|
poll,
|
||||||
|
},
|
||||||
|
sys::{
|
||||||
|
timerfd::{
|
||||||
|
ClockId,
|
||||||
|
Expiration,
|
||||||
|
TimerFd,
|
||||||
|
TimerFlags,
|
||||||
|
TimerSetTimeFlags,
|
||||||
|
},
|
||||||
|
time::{
|
||||||
|
TimeSpec,
|
||||||
|
TimeValLike,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
libdvb::{
|
libdvb::{
|
||||||
CaDevice,
|
CaDevice,
|
||||||
},
|
},
|
||||||
@ -14,13 +36,64 @@ use {
|
|||||||
fn check_ca(path: &Path) -> Result<()> {
|
fn check_ca(path: &Path) -> Result<()> {
|
||||||
println!("CA: {}", path.display());
|
println!("CA: {}", path.display());
|
||||||
|
|
||||||
let mut ca = CaDevice::open(path, 0)?;
|
// let mut ca = CaDevice::open(path, 0)?;
|
||||||
|
|
||||||
// loop for about 3s
|
let timer = TimerFd::new(
|
||||||
for _ in 0 .. 30 {
|
ClockId::CLOCK_MONOTONIC,
|
||||||
ca.poll()?;
|
TimerFlags::all()
|
||||||
|
)?;
|
||||||
|
|
||||||
|
timer.set(
|
||||||
|
Expiration::Interval(
|
||||||
|
TimeSpec::milliseconds(100)
|
||||||
|
),
|
||||||
|
TimerSetTimeFlags::empty()
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut pool: Vec<PollFd> = Vec::new();
|
||||||
|
|
||||||
|
pool.push(PollFd::new(
|
||||||
|
timer.as_raw_fd(),
|
||||||
|
PollFlags::POLLIN
|
||||||
|
));
|
||||||
|
|
||||||
|
let instant = std::time::Instant::now();
|
||||||
|
|
||||||
|
for _ in 0 .. 10 {
|
||||||
|
let mut total = poll(&mut pool, -1)?;
|
||||||
|
// less than 0 not needed to check we got error in this case
|
||||||
|
// equal to 0 not needed to check we have no timeout
|
||||||
|
|
||||||
|
for (i, item) in pool.iter().enumerate() {
|
||||||
|
let revent = item.revents().unwrap_or_else(PollFlags::empty);
|
||||||
|
if revent.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == 0 {
|
||||||
|
timer.wait()?;
|
||||||
|
dbg!(instant.elapsed());
|
||||||
|
}
|
||||||
|
|
||||||
|
if total > 1 {
|
||||||
|
total -= 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// let fd = PollFd::new(
|
||||||
|
// ca.as_raw_fd(),
|
||||||
|
// PollFlags::POLLIN,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// TODO: CaPool
|
||||||
|
// TODO: timer CA_DELAY -> poll_timer()
|
||||||
|
// TODO: self.as_raw_fd() -> poll_event()
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
48
examples/netinfo.rs
Normal file
48
examples/netinfo.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
use {
|
||||||
|
std::{
|
||||||
|
path::Path,
|
||||||
|
},
|
||||||
|
|
||||||
|
anyhow::Result,
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
let mac = match dev.get_mac() {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => e.to_string(),
|
||||||
|
};
|
||||||
|
println!("MAC: {}", mac);
|
||||||
|
|
||||||
|
dev.remove_if(&info)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let mut args = std::env::args().skip(1);
|
||||||
|
if let Some(path) = args.next() {
|
||||||
|
let path = Path::new(&path);
|
||||||
|
check_net(&path)?;
|
||||||
|
} else {
|
||||||
|
eprintln!("path to ca device is not defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -139,9 +139,7 @@ impl CaDevice {
|
|||||||
Ok(ca)
|
Ok(ca)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll(&mut self) -> Result<()> {
|
fn poll_timer(&mut self) -> Result<()> {
|
||||||
thread::sleep(CA_DELAY);
|
|
||||||
|
|
||||||
let flags = self.slot.flags;
|
let flags = self.slot.flags;
|
||||||
|
|
||||||
self.get_slot_info()?;
|
self.get_slot_info()?;
|
||||||
@ -166,8 +164,14 @@ impl CaDevice {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: poll self.as_raw_fd()
|
// TODO: check queue?
|
||||||
|
|
||||||
unimplemented!()
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_event(&mut self) -> Result<()> {
|
||||||
|
// TODO: tpdu read
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ extern crate anyhow;
|
|||||||
|
|
||||||
pub mod ca;
|
pub mod ca;
|
||||||
pub mod fe;
|
pub mod fe;
|
||||||
|
pub mod net;
|
||||||
|
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
@ -15,4 +16,8 @@ pub use {
|
|||||||
FeDevice,
|
FeDevice,
|
||||||
FeStatus,
|
FeStatus,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
net::{
|
||||||
|
NetDevice,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
138
src/net/mod.rs
Normal file
138
src/net/mod.rs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
pub mod sys;
|
||||||
|
|
||||||
|
|
||||||
|
use {
|
||||||
|
std::{
|
||||||
|
io::{
|
||||||
|
Read,
|
||||||
|
},
|
||||||
|
fs::{
|
||||||
|
File,
|
||||||
|
OpenOptions,
|
||||||
|
},
|
||||||
|
os::unix::{
|
||||||
|
fs::{
|
||||||
|
OpenOptionsExt,
|
||||||
|
},
|
||||||
|
io::{
|
||||||
|
AsRawFd,
|
||||||
|
RawFd,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
path::Path,
|
||||||
|
},
|
||||||
|
|
||||||
|
anyhow::{
|
||||||
|
Context,
|
||||||
|
Result,
|
||||||
|
},
|
||||||
|
|
||||||
|
nix::{
|
||||||
|
fcntl::{
|
||||||
|
readlink,
|
||||||
|
},
|
||||||
|
sys::{
|
||||||
|
stat::{
|
||||||
|
fstat,
|
||||||
|
major,
|
||||||
|
minor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
ioctl_readwrite,
|
||||||
|
ioctl_write_int_bad,
|
||||||
|
request_code_none,
|
||||||
|
},
|
||||||
|
|
||||||
|
sys::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// A reference to the network device
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NetDevice {
|
||||||
|
file: File,
|
||||||
|
|
||||||
|
/// Interface name
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl AsRawFd for NetDevice {
|
||||||
|
#[inline]
|
||||||
|
fn as_raw_fd(&self) -> RawFd { self.file.as_raw_fd() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl NetDevice {
|
||||||
|
/// Attempts to open a network device in read-write mode
|
||||||
|
pub fn open<P: AsRef<Path>>(path: P) -> Result<NetDevice> {
|
||||||
|
let file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.custom_flags(::nix::libc::O_NONBLOCK)
|
||||||
|
.open(path)
|
||||||
|
.context("NET: open")?;
|
||||||
|
|
||||||
|
let s = fstat(file.as_raw_fd())?;
|
||||||
|
let sys_path = format!(
|
||||||
|
"/sys/dev/char/{}:{}",
|
||||||
|
major(s.st_rdev),
|
||||||
|
minor(s.st_rdev)
|
||||||
|
);
|
||||||
|
let name = readlink(sys_path.as_str())?
|
||||||
|
.to_str()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.rsplit('/')
|
||||||
|
.next()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.split(".net")
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.join("_");
|
||||||
|
|
||||||
|
let net = NetDevice {
|
||||||
|
file,
|
||||||
|
name,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(net)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns interface name in format `dvb{0}_{1}` where `{0}` is adapter number
|
||||||
|
/// and `{1}` is a device number
|
||||||
|
pub fn get_name(&self) -> &str { self.name.as_str() }
|
||||||
|
|
||||||
|
/// Reads and returns interface MAC address
|
||||||
|
pub fn get_mac(&self) -> Result<String> {
|
||||||
|
let path = format!("/sys/class/net/{}/address", self.get_name());
|
||||||
|
|
||||||
|
let len = 2 * 6 + 5;
|
||||||
|
let file = File::open(&path)?;
|
||||||
|
let mut result = String::with_capacity(len);
|
||||||
|
file.take(2 * 6 + 5).read_to_string(&mut result)?;
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new network interface
|
||||||
|
pub fn add_if(&self, data: &mut DvbNetIf) -> Result<()> {
|
||||||
|
// NET_ADD_IF
|
||||||
|
ioctl_readwrite!(#[inline] ioctl_call, b'o', 52, DvbNetIf);
|
||||||
|
unsafe {
|
||||||
|
ioctl_call(self.as_raw_fd(), data as *mut _)
|
||||||
|
}.context("NET: add if")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes a network interface
|
||||||
|
pub fn remove_if(&self, data: &DvbNetIf) -> Result<()> {
|
||||||
|
// NET_REMOVE_IF
|
||||||
|
ioctl_write_int_bad!(#[inline] ioctl_call, request_code_none!(b'o', 53));
|
||||||
|
unsafe {
|
||||||
|
ioctl_call(self.as_raw_fd(), data.if_num as _)
|
||||||
|
}.context("NET: remove if")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
26
src/net/sys.rs
Normal file
26
src/net/sys.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
pub use {
|
||||||
|
feed_type::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
mod feed_type {
|
||||||
|
/// Multi Protocol Encapsulation (MPE) encoding
|
||||||
|
pub const DVB_NET_FEEDTYPE_MPE: u8 = 0;
|
||||||
|
/// Ultra Lightweight Encapsulation (ULE) encoding
|
||||||
|
pub const DVB_NET_FEEDTYPE_ULE: u8 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Describes a DVB network interface
|
||||||
|
/// Configures adapter to decapsulate IP packets from MPEG-TS stream
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DvbNetIf {
|
||||||
|
/// Packet ID (PID) of the MPEG-TS that contains data
|
||||||
|
pub pid: u16,
|
||||||
|
/// Number of the Digital TV interface
|
||||||
|
pub if_num: u16,
|
||||||
|
/// Encapsulation type of the feed
|
||||||
|
pub feedtype: u8,
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user