Skip to content

Commit 7216eaf

Browse files
committed
feat(netwatch): Attempt to switch to snafu
1 parent 74f75b8 commit 7216eaf

File tree

12 files changed

+153
-76
lines changed

12 files changed

+153
-76
lines changed

Cargo.lock

+4-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

netwatch/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ workspace = true
1919
atomic-waker = "1.1.2"
2020
bytes = "1.7"
2121
n0-future = "0.1.1"
22-
thiserror = "2"
22+
n0-snafu = { git = "https://github.com/n0-computer/n0-snafu", branch = "matheus23/clone" }
23+
nested_enum_utils = "0.2.0"
24+
snafu = "0.8.5"
2325
time = "0.3.20"
2426
tokio = { version = "1", features = [
2527
"io-util",

netwatch/src/interfaces/bsd.rs

+27-15
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ use std::{
88
sync::LazyLock,
99
};
1010

11+
use nested_enum_utils::common_fields;
12+
use snafu::{Backtrace, IntoError, Snafu};
13+
1114
use libc::{c_int, uintptr_t, AF_INET, AF_INET6, AF_LINK, AF_ROUTE, AF_UNSPEC, CTL_NET};
1215
#[cfg(any(target_os = "macos", target_os = "ios"))]
1316
use libc::{
@@ -627,20 +630,29 @@ pub struct InterfaceAnnounceMessage {
627630
/// Represents a type of routing information base.
628631
type RIBType = i32;
629632

630-
#[derive(Debug, thiserror::Error)]
633+
#[common_fields({
634+
backtrace: Option<Backtrace>,
635+
#[snafu(implicit)]
636+
span_trace: n0_snafu::SpanTrace,
637+
})]
638+
#[derive(Debug, Snafu)]
639+
#[non_exhaustive]
631640
pub enum RouteError {
632-
#[error("message mismatch")]
633-
MessageMismatch,
634-
#[error("message too short")]
635-
MessageTooShort,
636-
#[error("invalid message")]
637-
InvalidMessage,
638-
#[error("invalid address")]
639-
InvalidAddress,
640-
#[error("invalid rib type: {0}")]
641-
InvalidRibType(RIBType),
642-
#[error("io error calling: '{0}': {1:?}")]
643-
Io(&'static str, std::io::Error),
641+
#[snafu(display("message mismatch"))]
642+
MessageMismatch {},
643+
#[snafu(display("message too short"))]
644+
MessageTooShort {},
645+
#[snafu(display("invalid message"))]
646+
InvalidMessage {},
647+
#[snafu(display("invalid address"))]
648+
InvalidAddress {},
649+
#[snafu(display("invalid rib type {rib_type}"))]
650+
InvalidRibType { rib_type: RIBType },
651+
#[snafu(display("io error calling '{name}'"))]
652+
Io {
653+
source: std::io::Error,
654+
name: &'static str,
655+
},
644656
}
645657

646658
/// FetchRIB fetches a routing information base from the operating system.
@@ -670,7 +682,7 @@ fn fetch_rib(af: i32, typ: RIBType, arg: i32) -> Result<Vec<u8>, RouteError> {
670682
)
671683
};
672684
if err != 0 {
673-
return Err(RouteError::Io("sysctl", std::io::Error::last_os_error()));
685+
return Err(std::io::Error::last_os_error().into_error(IoSnafu { name: "sysctl" }));
674686
}
675687
if n == 0 {
676688
// nothing available
@@ -696,7 +708,7 @@ fn fetch_rib(af: i32, typ: RIBType, arg: i32) -> Result<Vec<u8>, RouteError> {
696708
if io_err.raw_os_error().unwrap_or_default() == libc::ENOMEM && round < MAX_TRIES {
697709
continue;
698710
}
699-
return Err(RouteError::Io("sysctl", io_err));
711+
return Err(io_err.into_error(IoSnafu { name: "sysctl" }));
700712
}
701713
// Truncate b, to the new length
702714
b.truncate(n);

netwatch/src/interfaces/linux.rs

+28-15
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,40 @@
22
33
#[cfg(not(target_os = "android"))]
44
use n0_future::TryStreamExt;
5+
use nested_enum_utils::common_fields;
6+
use snafu::{Backtrace, ResultExt, Snafu};
57
use tokio::{
68
fs::File,
79
io::{AsyncBufReadExt, BufReader},
810
};
911

1012
use super::DefaultRouteDetails;
1113

12-
#[derive(Debug, thiserror::Error)]
14+
#[common_fields({
15+
backtrace: Option<Backtrace>,
16+
#[snafu(implicit)]
17+
span_trace: n0_snafu::SpanTrace,
18+
})]
19+
#[derive(Debug, Snafu)]
20+
#[non_exhaustive]
1321
pub enum Error {
14-
#[error("IO {0}")]
15-
Io(#[from] std::io::Error),
22+
#[snafu(display("IO"))]
23+
Io { source: std::io::Error },
1624
#[cfg(not(target_os = "android"))]
17-
#[error("no netlink response")]
25+
#[snafu(display("no netlink response"))]
1826
NoResponse,
1927
#[cfg(not(target_os = "android"))]
20-
#[error("interface not found")]
28+
#[snafu(display("interface not found"))]
2129
InterfaceNotFound,
22-
#[error("iface field is missing")]
30+
#[snafu(display("iface field is missing"))]
2331
MissingIfaceField,
24-
#[error("destination field is missing")]
32+
#[snafu(display("destination field is missing"))]
2533
MissingDestinationField,
26-
#[error("mask field is missing")]
34+
#[snafu(display("mask field is missing"))]
2735
MissingMaskField,
2836
#[cfg(not(target_os = "android"))]
29-
#[error("netlink")]
30-
Netlink(#[from] rtnetlink::Error),
37+
#[snafu(display("netlink"))]
38+
Netlink { source: rtnetlink::Error },
3139
}
3240

3341
pub async fn default_route() -> Option<DefaultRouteDetails> {
@@ -49,7 +57,7 @@ const PROC_NET_ROUTE_PATH: &str = "/proc/net/route";
4957

5058
async fn default_route_proc() -> Result<Option<DefaultRouteDetails>, Error> {
5159
const ZERO_ADDR: &str = "00000000";
52-
let file = File::open(PROC_NET_ROUTE_PATH).await?;
60+
let file = File::open(PROC_NET_ROUTE_PATH).await.context(IoSnafu)?;
5361

5462
// Explicitly set capacity, this is min(4096, DEFAULT_BUF_SIZE):
5563
// https://github.com/google/gvisor/issues/5732
@@ -65,7 +73,7 @@ async fn default_route_proc() -> Result<Option<DefaultRouteDetails>, Error> {
6573
// read it all in one call.
6674
let reader = BufReader::with_capacity(8 * 1024, file);
6775
let mut lines_iter = reader.lines();
68-
while let Some(line) = lines_iter.next_line().await? {
76+
while let Some(line) = lines_iter.next_line().await.context(IoSnafu)? {
6977
if !line.contains(ZERO_ADDR) {
7078
continue;
7179
}
@@ -127,7 +135,7 @@ fn parse_android_ip_route(stdout: &str) -> Option<&str> {
127135
async fn default_route_netlink() -> Result<Option<DefaultRouteDetails>, Error> {
128136
use tracing::{info_span, Instrument};
129137

130-
let (connection, handle, _receiver) = rtnetlink::new_connection()?;
138+
let (connection, handle, _receiver) = rtnetlink::new_connection().context(IoSnafu)?;
131139
let task = tokio::spawn(connection.instrument(info_span!("rtnetlink.conn")));
132140

133141
let default = default_route_netlink_family(&handle, rtnetlink::IpVersion::V4).await?;
@@ -151,7 +159,7 @@ async fn default_route_netlink_family(
151159
use netlink_packet_route::route::RouteAttribute;
152160

153161
let mut routes = handle.route().get(family).execute();
154-
while let Some(route) = routes.try_next().await? {
162+
while let Some(route) = routes.try_next().await.context(NetlinkSnafu)? {
155163
let route_attrs = route.attributes;
156164

157165
if !route_attrs
@@ -187,9 +195,14 @@ async fn default_route_netlink_family(
187195
#[cfg(not(target_os = "android"))]
188196
async fn iface_by_index(handle: &rtnetlink::Handle, index: u32) -> Result<String, Error> {
189197
use netlink_packet_route::link::LinkAttribute;
198+
use snafu::OptionExt;
190199

191200
let mut links = handle.link().get().match_index(index).execute();
192-
let msg = links.try_next().await?.ok_or(Error::NoResponse)?;
201+
let msg = links
202+
.try_next()
203+
.await
204+
.context(NetlinkSnafu)?
205+
.context(NoResponseSnafu)?;
193206

194207
for nla in msg.attributes {
195208
if let LinkAttribute::IfName(name) = nla {

netwatch/src/interfaces/windows.rs

+19-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::collections::HashMap;
22

3+
use nested_enum_utils::common_fields;
34
use serde::Deserialize;
5+
use snafu::{Backtrace, OptionExt, ResultExt, Snafu};
46
use tracing::warn;
57
use wmi::{query::FilterValue, COMLibrary, WMIConnection};
68

@@ -13,26 +15,33 @@ struct Win32_IP4RouteTable {
1315
Name: String,
1416
}
1517

16-
#[derive(Debug, thiserror::Error)]
18+
#[common_fields({
19+
backtrace: Option<Backtrace>,
20+
#[snafu(implicit)]
21+
span_trace: n0_snafu::SpanTrace,
22+
})]
23+
#[derive(Debug, Snafu)]
24+
#[non_exhaustive]
1725
pub enum Error {
18-
#[error("IO {0}")]
19-
Io(#[from] std::io::Error),
20-
#[error("not route found")]
26+
#[snafu(display("IO"))]
27+
Io { source: std::io::Error },
28+
#[snafu(display("not route found"))]
2129
NoRoute,
22-
#[error("WMI {0}")]
23-
Wmi(#[from] wmi::WMIError),
30+
#[snafu(display("WMI"))]
31+
Wmi { source: wmi::WMIError },
2432
}
2533

2634
fn get_default_route() -> Result<DefaultRouteDetails, Error> {
27-
let com_con = COMLibrary::new()?;
28-
let wmi_con = WMIConnection::new(com_con)?;
35+
let com_con = COMLibrary::new().context(WmiSnafu)?;
36+
let wmi_con = WMIConnection::new(com_con).context(WmiSnafu)?;
2937

3038
let query: HashMap<_, _> = [("Destination".into(), FilterValue::Str("0.0.0.0"))].into();
3139
let route: Win32_IP4RouteTable = wmi_con
32-
.filtered_query(&query)?
40+
.filtered_query(&query)
41+
.context(WmiSnafu)?
3342
.drain(..)
3443
.next()
35-
.ok_or(Error::NoRoute)?;
44+
.context(NoRouteSnafu)?;
3645

3746
Ok(DefaultRouteDetails {
3847
interface_name: route.Name,

netwatch/src/netmon.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use n0_future::{
44
boxed::BoxFuture,
55
task::{self, AbortOnDropHandle},
66
};
7+
use nested_enum_utils::common_fields;
8+
use snafu::{Backtrace, ResultExt, Snafu};
79
use tokio::sync::{mpsc, oneshot};
810

911
mod actor;
@@ -35,30 +37,36 @@ pub struct Monitor {
3537
actor_tx: mpsc::Sender<ActorMessage>,
3638
}
3739

38-
#[derive(Debug, thiserror::Error)]
40+
#[common_fields({
41+
backtrace: Option<Backtrace>,
42+
#[snafu(implicit)]
43+
span_trace: n0_snafu::SpanTrace,
44+
})]
45+
#[derive(Debug, Snafu)]
46+
#[non_exhaustive]
3947
pub enum Error {
40-
#[error("channel closed")]
41-
ChannelClosed,
42-
#[error("actor {0}")]
43-
Actor(#[from] actor::Error),
48+
#[snafu(display("channel closed"))]
49+
ChannelClosed {},
50+
#[snafu(display("actor error"))]
51+
Actor { source: actor::Error },
4452
}
4553

4654
impl<T> From<mpsc::error::SendError<T>> for Error {
4755
fn from(_value: mpsc::error::SendError<T>) -> Self {
48-
Self::ChannelClosed
56+
ChannelClosedSnafu.build()
4957
}
5058
}
5159

5260
impl From<oneshot::error::RecvError> for Error {
5361
fn from(_value: oneshot::error::RecvError) -> Self {
54-
Self::ChannelClosed
62+
ChannelClosedSnafu.build()
5563
}
5664
}
5765

5866
impl Monitor {
5967
/// Create a new monitor.
6068
pub async fn new() -> Result<Self, Error> {
61-
let actor = Actor::new().await?;
69+
let actor = Actor::new().await.context(ActorSnafu)?;
6270
let actor_tx = actor.subscribe();
6371

6472
let handle = task::spawn(async move {

netwatch/src/netmon/android.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ use tokio::sync::mpsc;
22

33
use super::actor::NetworkMessage;
44

5-
#[derive(Debug, thiserror::Error)]
6-
#[error("error")]
5+
#[derive(Debug, derive_more::Display)]
6+
#[display("error")]
77
pub struct Error;
88

9+
impl std::error::Error for Error {}
10+
911
#[derive(Debug)]
1012
pub(super) struct RouteMonitor {
1113
_sender: mpsc::Sender<NetworkMessage>,

netwatch/src/netmon/bsd.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#[cfg(any(target_os = "macos", target_os = "ios"))]
22
use libc::{RTAX_DST, RTAX_IFP};
3+
use snafu::{Backtrace, ResultExt, Snafu};
34
use tokio::{io::AsyncReadExt, sync::mpsc};
45
use tokio_util::task::AbortOnDropHandle;
56
use tracing::{trace, warn};
@@ -14,10 +15,16 @@ pub(super) struct RouteMonitor {
1415
_handle: AbortOnDropHandle<()>,
1516
}
1617

17-
#[derive(Debug, thiserror::Error)]
18+
#[derive(Debug, Snafu)]
19+
#[non_exhaustive]
1820
pub enum Error {
19-
#[error("IO {0}")]
20-
Io(#[from] std::io::Error),
21+
#[snafu(display("IO"))]
22+
Io {
23+
source: std::io::Error,
24+
backtrace: Option<Backtrace>,
25+
#[snafu(implicit)]
26+
span_trace: n0_snafu::SpanTrace,
27+
},
2128
}
2229

2330
fn create_socket() -> std::io::Result<tokio::net::UnixStream> {
@@ -33,7 +40,7 @@ fn create_socket() -> std::io::Result<tokio::net::UnixStream> {
3340

3441
impl RouteMonitor {
3542
pub(super) fn new(sender: mpsc::Sender<NetworkMessage>) -> Result<Self, Error> {
36-
let mut socket = create_socket()?;
43+
let mut socket = create_socket().context(IoSnafu)?;
3744
let handle = tokio::task::spawn(async move {
3845
trace!("AF_ROUTE monitor started");
3946

0 commit comments

Comments
 (0)