diff --git a/Cargo.lock b/Cargo.lock index dca4e75c..63522106 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -34,7 +34,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -111,9 +111,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.41" +version = "1.2.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" +checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" dependencies = [ "find-msvc-tools", "shlex", @@ -186,9 +186,9 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "deranged" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -219,7 +219,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", "unicode-xid", ] @@ -231,7 +231,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", "unicode-xid", ] @@ -249,7 +249,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -390,7 +390,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -789,9 +789,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -802,9 +802,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -815,11 +815,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -830,42 +829,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -933,29 +928,29 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iroh-metrics" -version = "0.36.2" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84c167b59ae22f940e78eb347ca5f02aa25608e994cb5a7cc016ac2d5eada18" +checksum = "79e3381da7c93c12d353230c74bba26131d1c8bf3a4d8af0fec041546454582e" dependencies = [ "iroh-metrics-derive", "itoa", + "n0-error", "postcard", "ryu", "serde", - "snafu", "tracing", ] [[package]] name = "iroh-metrics-derive" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "748d380f26f7c25307c0a7acd181b84b977ddc2a1b7beece1e5998623c323aa1" +checksum = "d4e12bd0763fd16062f5cc5e8db15dd52d26e75a8af4c7fb57ccee3589b344b8" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1002,9 +997,9 @@ checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" @@ -1070,6 +1065,29 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "n0-error" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a4839a11b62f1fdd75be912ee20634053c734c2240e867ded41c7f50822c549" +dependencies = [ + "derive_more 2.0.1", + "n0-error-macros", + "spez", +] + +[[package]] +name = "n0-error-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed2a7e5ca3cb5729d4a162d7bcab5b338bed299a2fee8457568d7e0a747ed89" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.108", +] + [[package]] name = "n0-future" version = "0.3.0" @@ -1093,25 +1111,13 @@ dependencies = [ [[package]] name = "n0-watcher" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34c65e127e06e5a2781b28df6a33ea474a7bddc0ac0cfea888bd20c79a1b6516" +checksum = "38acf13c1ddafc60eb7316d52213467f8ccb70b6f02b65e7d97f7799b1f50be4" dependencies = [ "derive_more 2.0.1", + "n0-error", "n0-future", - "snafu", -] - -[[package]] -name = "nested_enum_utils" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d5475271bdd36a4a2769eac1ef88df0f99428ea43e52dfd8b0ee5cb674695f" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.107", ] [[package]] @@ -1190,9 +1196,9 @@ dependencies = [ "iroh-quinn-udp", "js-sys", "libc", + "n0-error", "n0-future", "n0-watcher", - "nested_enum_utils", "netdev", "netlink-packet-core", "netlink-packet-route", @@ -1200,7 +1206,6 @@ dependencies = [ "netlink-sys", "pin-project-lite", "serde", - "snafu", "socket2 0.6.1", "testresult", "time", @@ -1292,7 +1297,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1336,7 +1341,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1364,7 +1369,7 @@ dependencies = [ "igd-next", "iroh-metrics", "libc", - "nested_enum_utils", + "n0-error", "netwatch", "ntest", "num_enum", @@ -1372,7 +1377,6 @@ dependencies = [ "rand_chacha", "serde", "smallvec", - "snafu", "socket2 0.6.1", "time", "tokio", @@ -1397,9 +1401,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -1430,9 +1434,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -1590,7 +1594,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1654,27 +1658,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "snafu" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e84b3f4eacbf3a1ce05eac6763b4d629d60cbc94d632e4092c54ade71f1e1a2" -dependencies = [ - "snafu-derive", -] - -[[package]] -name = "snafu-derive" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.107", -] - [[package]] name = "socket2" version = "0.5.10" @@ -1695,6 +1678,17 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "spez" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87e960f4dca2788eeb86bbdde8dd246be8948790b7618d656e68f9b720a86e8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.108", +] + [[package]] name = "spin" version = "0.9.8" @@ -1729,9 +1723,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.107" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -1746,7 +1740,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1802,7 +1796,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1813,7 +1807,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1846,9 +1840,9 @@ checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -1878,7 +1872,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1957,7 +1951,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -2018,9 +2012,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-xid" @@ -2131,7 +2125,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", "wasm-bindgen-shared", ] @@ -2165,7 +2159,7 @@ checksum = "085b2df989e1e6f9620c1311df6c996e83fe16f57792b272ce1e024ac16a90f1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -2318,7 +2312,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -2329,7 +2323,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -2615,15 +2609,15 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "xml-rs" -version = "0.8.27" +version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" [[package]] name = "xmltree" @@ -2636,11 +2630,10 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -2648,13 +2641,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", "synstructure", ] @@ -2675,7 +2668,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -2695,15 +2688,15 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", "synstructure", ] [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -2712,9 +2705,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -2723,11 +2716,11 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] diff --git a/netwatch/Cargo.toml b/netwatch/Cargo.toml index 0d483ae9..db901a22 100644 --- a/netwatch/Cargo.toml +++ b/netwatch/Cargo.toml @@ -18,11 +18,10 @@ workspace = true [dependencies] atomic-waker = "1.1.2" bytes = "1.7" +n0-error = "0.1.0" n0-future = "0.3.0" -n0-watcher = "0.4.0" -nested_enum_utils = "0.2.3" +n0-watcher = "0.5.0" pin-project-lite = "0.2.16" -snafu = "0.8.5" time = "0.3.20" tokio = { version = "1", features = [ "io-util", diff --git a/netwatch/src/interfaces/bsd.rs b/netwatch/src/interfaces/bsd.rs index ee18e719..3db2b6f3 100644 --- a/netwatch/src/interfaces/bsd.rs +++ b/netwatch/src/interfaces/bsd.rs @@ -13,8 +13,7 @@ use libc::{AF_INET, AF_INET6, AF_LINK, AF_ROUTE, AF_UNSPEC, CTL_NET, c_int, uint use libc::{ NET_RT_DUMP, RTA_IFP, RTAX_BRD, RTAX_DST, RTAX_GATEWAY, RTAX_MAX, RTAX_NETMASK, RTF_GATEWAY, }; -use nested_enum_utils::common_fields; -use snafu::{Backtrace, IntoError, OptionExt, Snafu}; +use n0_error::{e, ensure, stack_error}; use tracing::warn; use super::DefaultRouteDetails; @@ -249,7 +248,7 @@ fn u16_from_ne_range( data.get(range) .and_then(|s| TryInto::<[u8; 2]>::try_into(s).ok()) .map(u16::from_ne_bytes) - .context(MessageTooShortSnafu) + .ok_or_else(|| e!(RouteError::MessageTooShort)) } /// Safely convert some bytes from a slice into a u32. @@ -260,7 +259,7 @@ fn u32_from_ne_range( data.get(range) .and_then(|s| TryInto::<[u8; 4]>::try_into(s).ok()) .map(u32::from_ne_bytes) - .context(MessageTooShortSnafu) + .ok_or_else(|| e!(RouteError::MessageTooShort)) } impl WireFormat { @@ -273,12 +272,12 @@ impl WireFormat { target_os = "ios" ))] MessageType::Route => { - snafu::ensure!(data.len() >= self.body_off, MessageTooShortSnafu); + ensure!(data.len() >= self.body_off, RouteError::MessageTooShort); let l = u16_from_ne_range(data, ..2)?; - snafu::ensure!(data.len() >= l as usize, InvalidMessageSnafu); + ensure!(data.len() >= l as usize, RouteError::InvalidMessage); let attrs: i32 = u32_from_ne_range(data, 12..16)? .try_into() - .map_err(|_| InvalidMessageSnafu.build())?; + .map_err(|_| e!(RouteError::InvalidMessage))?; let addrs = parse_addrs(attrs, parse_kernel_inet_addr, &data[self.body_off..])?; let mut m = RouteMessage { version: data[2] as _, @@ -300,11 +299,11 @@ impl WireFormat { } #[cfg(target_os = "openbsd")] MessageType::Route => { - snafu::ensure!(data.len() >= self.body_off, MessageTooShortSnafu); + ensure!(data.len() >= self.body_off, RouteError::MessageTooShort); let l = u16_from_ne_range(data, ..2)?; - snafu::ensure!(data.len() >= l as usize, InvalidMessageSnafu); + ensure!(data.len() >= l as usize, RouteError::InvalidMessage); let ll = u16_from_ne_range(data, 4..6)? as usize; - snafu::ensure!(data.len() >= ll as usize, InvalidMessageSnafu); + ensure!(data.len() >= ll as usize, RouteError::InvalidMessage); let addrs = parse_addrs( u32_from_ne_range(data, 12..16)? as _, @@ -331,9 +330,9 @@ impl WireFormat { Ok(Some(WireMessage::Route(m))) } MessageType::Interface => { - snafu::ensure!(data.len() >= self.body_off, MessageTooShortSnafu); + ensure!(data.len() >= self.body_off, RouteError::MessageTooShort); let l = u16_from_ne_range(data, 0..2)?; - snafu::ensure!(data.len() >= l as usize, InvalidMessageSnafu); + ensure!(data.len() >= l as usize, RouteError::InvalidMessage); let attrs = u32_from_ne_range(data, 4..8)?; if attrs as c_int & RTA_IFP == 0 { @@ -354,9 +353,9 @@ impl WireFormat { Ok(Some(WireMessage::Interface(m))) } MessageType::InterfaceAddr => { - snafu::ensure!(data.len() >= self.body_off, MessageTooShortSnafu); + ensure!(data.len() >= self.body_off, RouteError::MessageTooShort); let l = u16_from_ne_range(data, ..2)?; - snafu::ensure!(data.len() >= l as usize, InvalidMessageSnafu); + ensure!(data.len() >= l as usize, RouteError::InvalidMessage); #[cfg(target_os = "netbsd")] let index = u16_from_ne_range(data, 16..18)?; @@ -379,9 +378,9 @@ impl WireFormat { Ok(Some(WireMessage::InterfaceAddr(m))) } MessageType::InterfaceMulticastAddr => { - snafu::ensure!(data.len() >= self.body_off, MessageTooShortSnafu); + ensure!(data.len() >= self.body_off, RouteError::MessageTooShort); let l = u16_from_ne_range(data, ..2)?; - snafu::ensure!(data.len() >= l as usize, InvalidMessageSnafu); + ensure!(data.len() >= l as usize, RouteError::InvalidMessage); let addrs = parse_addrs( u32_from_ne_range(data, 4..8)? as _, @@ -398,9 +397,9 @@ impl WireFormat { Ok(Some(WireMessage::InterfaceMulticastAddr(m))) } MessageType::InterfaceAnnounce => { - snafu::ensure!(data.len() >= self.body_off, MessageTooShortSnafu); + ensure!(data.len() >= self.body_off, RouteError::MessageTooShort); let l = u16_from_ne_range(data, ..2)?; - snafu::ensure!(data.len() >= l as usize, InvalidMessageSnafu); + ensure!(data.len() >= l as usize, RouteError::InvalidMessage); let mut name = String::new(); for i in 0..16 { @@ -408,7 +407,7 @@ impl WireFormat { continue; } name = std::str::from_utf8(&data[6..6 + i]) - .map_err(|_| InvalidAddressSnafu.build())? + .map_err(|_| e!(RouteError::InvalidAddress))? .to_string(); break; } @@ -446,9 +445,9 @@ struct RoutingStack { /// Parses b as a routing information base and returns a list of routing messages. pub fn parse_rib(typ: RIBType, data: &[u8]) -> Result, RouteError> { - snafu::ensure!( + ensure!( is_valid_rib_type(typ), - InvalidRibTypeSnafu { rib_type: typ } + RouteError::InvalidRibType { rib_type: typ } ); let mut msgs = Vec::new(); @@ -459,8 +458,8 @@ pub fn parse_rib(typ: RIBType, data: &[u8]) -> Result, RouteErr while b.len() > 4 { nmsgs += 1; let l = u16_from_ne_range(b, ..2)?; - snafu::ensure!(l != 0, InvalidMessageSnafu); - snafu::ensure!(b.len() >= l as usize, MessageTooShortSnafu); + ensure!(l != 0, RouteError::InvalidMessage); + ensure!(b.len() >= l as usize, RouteError::MessageTooShort); if b[2] as i32 != ROUTING_STACK.rtm_version { // b = b[l:]; continue; @@ -485,7 +484,7 @@ pub fn parse_rib(typ: RIBType, data: &[u8]) -> Result, RouteErr } // We failed to parse any of the messages - version mismatch? - snafu::ensure!(nmsgs == msgs.len() + nskips, MessageMismatchSnafu); + ensure!(nmsgs == msgs.len() + nskips, RouteError::MessageMismatch); Ok(msgs) } @@ -599,24 +598,22 @@ pub struct InterfaceAnnounceMessage { /// Represents a type of routing information base. type RIBType = i32; -#[common_fields({ - backtrace: Option, -})] -#[derive(Debug, Snafu)] +#[stack_error(derive, add_meta)] #[non_exhaustive] pub enum RouteError { - #[snafu(display("message mismatch"))] + #[error("message mismatch")] MessageMismatch {}, - #[snafu(display("message too short"))] + #[error("message too short")] MessageTooShort {}, - #[snafu(display("invalid message"))] + #[error("invalid message")] InvalidMessage {}, - #[snafu(display("invalid address"))] + #[error("invalid address")] InvalidAddress {}, - #[snafu(display("invalid rib type {rib_type}"))] + #[error("invalid rib type {rib_type}")] InvalidRibType { rib_type: RIBType }, - #[snafu(display("io error calling '{name}'"))] + #[error("io error calling '{name}'")] Io { + #[error(std_err)] source: std::io::Error, name: &'static str, }, @@ -649,7 +646,10 @@ fn fetch_rib(af: i32, typ: RIBType, arg: i32) -> Result, RouteError> { ) }; if err != 0 { - return Err(IoSnafu { name: "sysctl" }.into_error(std::io::Error::last_os_error())); + return Err(e!( + RouteError::Io { name: "sysctl" }, + std::io::Error::last_os_error() + )); } if n == 0 { // nothing available @@ -675,7 +675,7 @@ fn fetch_rib(af: i32, typ: RIBType, arg: i32) -> Result, RouteError> { if io_err.raw_os_error().unwrap_or_default() == libc::ENOMEM && round < MAX_TRIES { continue; } - return Err(IoSnafu { name: "sysctl" }.into_error(io_err)); + return Err(e!(RouteError::Io { name: "sysctl" }, io_err)); } // Truncate b, to the new length b.truncate(n); @@ -768,7 +768,7 @@ where let a = parse_link_addr(b)?; addrs.push(a); let l = roundup(b[0] as usize); - snafu::ensure!(b.len() >= l, MessageTooShortSnafu); + ensure!(b.len() >= l, RouteError::MessageTooShort); b = &b[l..]; } AF_INET | AF_INET6 => { @@ -776,7 +776,7 @@ where let a = parse_inet_addr(af, b)?; addrs.push(a); let l = roundup(b[0] as usize); - snafu::ensure!(b.len() >= l, MessageTooShortSnafu); + ensure!(b.len() >= l, RouteError::MessageTooShort); b = &b[l..]; } _ => { @@ -794,7 +794,7 @@ where let a = parse_default_addr(b)?; addrs.push(a); let l = roundup(b[0] as usize); - snafu::ensure!(b.len() >= l, MessageTooShortSnafu); + ensure!(b.len() >= l, RouteError::MessageTooShort); b = &b[l..]; } } @@ -809,19 +809,19 @@ where fn parse_inet_addr(af: i32, b: &[u8]) -> Result { match af { AF_INET => { - snafu::ensure!(b.len() >= SIZEOF_SOCKADDR_INET, InvalidAddressSnafu); + ensure!(b.len() >= SIZEOF_SOCKADDR_INET, RouteError::InvalidAddress); let ip = Ipv4Addr::new(b[4], b[5], b[6], b[7]); Ok(Addr::Inet4 { ip }) } AF_INET6 => { - snafu::ensure!(b.len() >= SIZEOF_SOCKADDR_INET6, InvalidAddressSnafu); + ensure!(b.len() >= SIZEOF_SOCKADDR_INET6, RouteError::InvalidAddress); let mut zone = u32_from_ne_range(b, 24..28)?; let mut oc: [u8; 16] = b .get(8..24) .and_then(|s| TryInto::<[u8; 16]>::try_into(s).ok()) - .context(InvalidMessageSnafu)?; + .ok_or_else(|| e!(RouteError::InvalidMessage))?; if oc[0] == 0xfe && oc[1] & 0xc0 == 0x80 || oc[0] == 0xff && (oc[1] & 0x0f == 0x01 || oc[1] & 0x0f == 0x02) { @@ -834,7 +834,7 @@ fn parse_inet_addr(af: i32, b: &[u8]) -> Result { .get(2..4) .and_then(|s| TryInto::<[u8; 2]>::try_into(s).ok()) .map(u16::from_be_bytes) - .context(InvalidMessageSnafu)? as u32; + .ok_or_else(|| e!(RouteError::InvalidMessage))? as u32; if id != 0 { zone = id; oc[2] = 0; @@ -846,7 +846,7 @@ fn parse_inet_addr(af: i32, b: &[u8]) -> Result { zone, }) } - _ => Err(InvalidAddressSnafu.build()), + _ => Err(e!(RouteError::InvalidAddress)), } } @@ -885,7 +885,7 @@ fn parse_kernel_inet_addr(af: i32, b: &[u8]) -> Result<(i32, Addr), RouteError> l = roundup(l); } - snafu::ensure!(b.len() >= l, InvalidAddressSnafu); + ensure!(b.len() >= l, RouteError::InvalidAddress); // Don't reorder case expressions. // The case expressions for IPv6 must come first. const OFF4: usize = 4; // offset of in_addr @@ -895,7 +895,7 @@ fn parse_kernel_inet_addr(af: i32, b: &[u8]) -> Result<(i32, Addr), RouteError> let octets: [u8; 16] = b .get(OFF6..OFF6 + 16) .and_then(|s| TryInto::try_into(s).ok()) - .context(InvalidMessageSnafu)?; + .ok_or_else(|| e!(RouteError::InvalidMessage))?; let ip = Ipv6Addr::from(octets); Addr::Inet6 { ip, zone: 0 } } else if af == AF_INET6 { @@ -911,7 +911,7 @@ fn parse_kernel_inet_addr(af: i32, b: &[u8]) -> Result<(i32, Addr), RouteError> let octets: [u8; 4] = b .get(OFF4..OFF4 + 4) .and_then(|s| TryInto::try_into(s).ok()) - .context(InvalidMessageSnafu)?; + .ok_or_else(|| e!(RouteError::InvalidMessage))?; let ip = Ipv4Addr::from(octets); Addr::Inet4 { ip } } else { @@ -930,7 +930,7 @@ fn parse_kernel_inet_addr(af: i32, b: &[u8]) -> Result<(i32, Addr), RouteError> } fn parse_link_addr(b: &[u8]) -> Result { - snafu::ensure!(b.len() >= 8, InvalidAddressSnafu); + ensure!(b.len() >= 8, RouteError::InvalidAddress); let (_, mut a) = parse_kernel_link_addr(AF_LINK, &b[4..])?; if let Addr::Link { index, .. } = &mut a { @@ -972,12 +972,12 @@ fn parse_kernel_link_addr(_: i32, b: &[u8]) -> Result<(usize, Addr), RouteError> } let l = 4 + nlen + alen + slen; - snafu::ensure!(b.len() >= l, InvalidAddressSnafu); + ensure!(b.len() >= l, RouteError::InvalidAddress); let mut data = &b[4..]; let name = if nlen > 0 { let name = std::str::from_utf8(&data[..nlen]) - .map_err(|_| InvalidAddressSnafu.build())? + .map_err(|_| e!(RouteError::InvalidAddress))? .to_string(); data = &data[nlen..]; Some(name) @@ -1001,9 +1001,9 @@ fn parse_kernel_link_addr(_: i32, b: &[u8]) -> Result<(usize, Addr), RouteError> } fn parse_default_addr(b: &[u8]) -> Result { - snafu::ensure!( + ensure!( b.len() >= 2 && b.len() >= b[0] as usize, - InvalidAddressSnafu + RouteError::InvalidAddress ); Ok(Addr::Default { af: b[1] as _, diff --git a/netwatch/src/interfaces/linux.rs b/netwatch/src/interfaces/linux.rs index 71d73085..e70c22e0 100644 --- a/netwatch/src/interfaces/linux.rs +++ b/netwatch/src/interfaces/linux.rs @@ -1,7 +1,6 @@ //! Linux-specific network interfaces implementations. -use nested_enum_utils::common_fields; -use snafu::{Backtrace, OptionExt, ResultExt, Snafu}; +use n0_error::{e, stack_error}; use tokio::{ fs::File, io::{AsyncBufReadExt, BufReader}, @@ -9,37 +8,33 @@ use tokio::{ use super::DefaultRouteDetails; -#[common_fields({ - backtrace: Option, -})] -#[derive(Debug, Snafu)] -#[snafu(visibility(pub(super)))] +#[stack_error(derive, add_meta, from_sources, std_sources)] #[non_exhaustive] pub enum Error { - #[snafu(display("IO"))] + #[error("IO")] Io { source: std::io::Error }, #[cfg(not(target_os = "android"))] - #[snafu(display("no netlink response"))] + #[error("no netlink response")] NoResponse {}, #[cfg(not(target_os = "android"))] - #[snafu(display("interface not found"))] + #[error("interface not found")] InterfaceNotFound {}, - #[snafu(display("iface field is missing"))] + #[error("iface field is missing")] MissingIfaceField {}, - #[snafu(display("destination field is missing"))] + #[error("destination field is missing")] MissingDestinationField {}, - #[snafu(display("mask field is missing"))] + #[error("mask field is missing")] MissingMaskField {}, #[cfg(not(target_os = "android"))] - #[snafu(display("netlink"))] + #[error("netlink")] Netlink { source: netlink_proto::Error, }, #[cfg(not(target_os = "android"))] - #[snafu(display("unexpected netlink message"))] + #[error("unexpected netlink message")] UnexpectedNetlinkMessage {}, #[cfg(not(target_os = "android"))] - #[snafu(display("netlink error message: {message:?}"))] + #[error("netlink error message: {message:?}")] NetlinkErrorMessage { message: netlink_packet_core::ErrorMessage, }, @@ -64,7 +59,7 @@ const PROC_NET_ROUTE_PATH: &str = "/proc/net/route"; async fn default_route_proc() -> Result, Error> { const ZERO_ADDR: &str = "00000000"; - let file = File::open(PROC_NET_ROUTE_PATH).await.context(IoSnafu)?; + let file = File::open(PROC_NET_ROUTE_PATH).await?; // Explicitly set capacity, this is min(4096, DEFAULT_BUF_SIZE): // https://github.com/google/gvisor/issues/5732 @@ -80,14 +75,16 @@ async fn default_route_proc() -> Result, Error> { // read it all in one call. let reader = BufReader::with_capacity(8 * 1024, file); let mut lines_iter = reader.lines(); - while let Some(line) = lines_iter.next_line().await.context(IoSnafu)? { + while let Some(line) = lines_iter.next_line().await? { if !line.contains(ZERO_ADDR) { continue; } let mut fields = line.split_ascii_whitespace(); - let iface = fields.next().context(MissingIfaceFieldSnafu)?; - let destination = fields.next().context(MissingDestinationFieldSnafu)?; - let mask = fields.nth(5).context(MissingMaskFieldSnafu)?; + let iface = fields.next().ok_or_else(|| e!(Error::MissingIfaceField))?; + let destination = fields + .next() + .ok_or_else(|| e!(Error::MissingDestinationField))?; + let mask = fields.nth(5).ok_or_else(|| e!(Error::MissingMaskField))?; // if iface.starts_with("tailscale") || iface.starts_with("wg") { // continue; // } @@ -115,8 +112,7 @@ mod android { .args(["route", "show", "table", "0"]) .kill_on_drop(true) .output() - .await - .context(IoSnafu)?; + .await?; let stdout = std::string::String::from_utf8_lossy(&output.stdout); let details = parse_android_ip_route(&stdout).map(|iface| DefaultRouteDetails { interface_name: iface.to_string(), @@ -127,6 +123,7 @@ mod android { #[cfg(not(target_os = "android"))] mod sane { + use n0_error::e; use n0_future::{Either, StreamExt, TryStream}; use netlink_packet_core::{NLM_F_DUMP, NLM_F_REQUEST, NetlinkMessage}; use netlink_packet_route::{ @@ -135,7 +132,6 @@ mod sane { route::{RouteAttribute, RouteHeader, RouteMessage, RouteProtocol, RouteScope, RouteType}, }; use netlink_sys::protocols::NETLINK_ROUTE; - use snafu::IntoError; use tracing::{Instrument, info_span}; use super::*; @@ -151,16 +147,16 @@ mod sane { match payload { NetlinkPayload::InnerMessage($message_type(msg)) => msg, NetlinkPayload::Error(err) => { - return Err(NetlinkErrorMessageSnafu { message: err }.build()); + return Err(e!(Error::NetlinkErrorMessage { message: err })); } - _ => return Err(UnexpectedNetlinkMessageSnafu.build()), + _ => return Err(e!(Error::UnexpectedNetlinkMessage)), } }}; } pub async fn default_route() -> Result, Error> { let (connection, handle, _receiver) = - netlink_proto::new_connection::(NETLINK_ROUTE).context(IoSnafu)?; + netlink_proto::new_connection::(NETLINK_ROUTE)?; let task = tokio::spawn(connection.instrument(info_span!("netlink.conn"))); @@ -191,7 +187,7 @@ mod sane { response.map(move |msg| Ok(try_rtnl!(msg, RouteNetlinkMessage::NewRoute))), ), Err(e) => Either::Right(n0_future::stream::once::>(Err( - NetlinkSnafu.into_error(e), + e!(Error::Netlink, e), ))), } } @@ -259,7 +255,7 @@ mod sane { response.map(move |msg| Ok(try_rtnl!(msg, RouteNetlinkMessage::NewLink))), ), Err(e) => Either::Right(n0_future::stream::once::>(Err( - NetlinkSnafu.into_error(e), + e!(Error::Netlink, e), ))), } } @@ -273,14 +269,17 @@ mod sane { async fn iface_by_index(handle: &Handle, index: u32) -> Result { let message = create_link_get_message(index); let mut links = get_link(handle.clone(), message); - let msg = links.try_next().await?.context(NoResponseSnafu)?; + let msg = links + .try_next() + .await? + .ok_or_else(|| e!(Error::NoResponse))?; for nla in msg.attributes { if let LinkAttribute::IfName(name) = nla { return Ok(name); } } - Err(InterfaceNotFoundSnafu.build()) + Err(e!(Error::InterfaceNotFound)) } #[cfg(test)] diff --git a/netwatch/src/interfaces/windows.rs b/netwatch/src/interfaces/windows.rs index 6ff2457e..4f91ce9c 100644 --- a/netwatch/src/interfaces/windows.rs +++ b/netwatch/src/interfaces/windows.rs @@ -1,8 +1,7 @@ use std::collections::HashMap; -use nested_enum_utils::common_fields; +use n0_error::{e, stack_error}; use serde::Deserialize; -use snafu::{Backtrace, OptionExt, ResultExt, Snafu}; use tracing::warn; use wmi::{COMLibrary, FilterValue, WMIConnection}; @@ -15,32 +14,28 @@ struct Win32_IP4RouteTable { Name: String, } -#[common_fields({ - backtrace: Option, -})] -#[derive(Debug, Snafu)] +#[stack_error(derive, add_meta, std_sources, from_sources)] #[non_exhaustive] pub enum Error { #[allow(dead_code)] // not sure why we have this here? - #[snafu(display("IO"))] + #[error("IO")] Io { source: std::io::Error }, - #[snafu(display("not route found"))] + #[error("not route found")] NoRoute {}, - #[snafu(display("WMI"))] + #[error("WMI")] Wmi { source: wmi::WMIError }, } fn get_default_route() -> Result { - let com_con = COMLibrary::new().context(WmiSnafu)?; - let wmi_con = WMIConnection::new(com_con).context(WmiSnafu)?; + let com_con = COMLibrary::new()?; + let wmi_con = WMIConnection::new(com_con)?; let query: HashMap<_, _> = [("Destination".into(), FilterValue::Str("0.0.0.0"))].into(); let route: Win32_IP4RouteTable = wmi_con - .filtered_query(&query) - .context(WmiSnafu)? + .filtered_query(&query)? .drain(..) .next() - .context(NoRouteSnafu)?; + .ok_or_else(|| e!(Error::NoRoute))?; Ok(DefaultRouteDetails { interface_name: route.Name, diff --git a/netwatch/src/netmon.rs b/netwatch/src/netmon.rs index 772c7bc7..22cafaa5 100644 --- a/netwatch/src/netmon.rs +++ b/netwatch/src/netmon.rs @@ -1,9 +1,8 @@ //! Monitoring of networking interfaces and route changes. +use n0_error::{e, stack_error}; use n0_future::task::{self, AbortOnDropHandle}; use n0_watcher::Watchable; -use nested_enum_utils::common_fields; -use snafu::{Backtrace, ResultExt, Snafu}; use tokio::sync::{mpsc, oneshot}; mod actor; @@ -38,34 +37,31 @@ pub struct Monitor { interface_state: Watchable, } -#[common_fields({ - backtrace: Option, -})] -#[derive(Debug, Snafu)] +#[stack_error(derive, add_meta, from_sources)] #[non_exhaustive] pub enum Error { - #[snafu(display("channel closed"))] + #[error("channel closed")] ChannelClosed {}, - #[snafu(display("actor error"))] + #[error("actor error")] Actor { source: actor::Error }, } impl From> for Error { fn from(_value: mpsc::error::SendError) -> Self { - ChannelClosedSnafu.build() + e!(Error::ChannelClosed) } } impl From for Error { fn from(_value: oneshot::error::RecvError) -> Self { - ChannelClosedSnafu.build() + e!(Error::ChannelClosed) } } impl Monitor { /// Create a new monitor. pub async fn new() -> Result { - let actor = Actor::new().await.context(ActorSnafu)?; + let actor = Actor::new().await?; let actor_tx = actor.subscribe(); let interface_state = actor.state().clone(); diff --git a/netwatch/src/netmon/android.rs b/netwatch/src/netmon/android.rs index 1d37dc08..9e62b465 100644 --- a/netwatch/src/netmon/android.rs +++ b/netwatch/src/netmon/android.rs @@ -1,13 +1,11 @@ +use n0_error::stack_error; use tokio::sync::mpsc; use super::actor::NetworkMessage; -#[derive(Debug, derive_more::Display)] -#[display("error")] +#[stack_error(derive, add_meta)] pub struct Error; -impl std::error::Error for Error {} - #[derive(Debug)] pub(super) struct RouteMonitor { _sender: mpsc::Sender, diff --git a/netwatch/src/netmon/bsd.rs b/netwatch/src/netmon/bsd.rs index 32b75097..af016f3d 100644 --- a/netwatch/src/netmon/bsd.rs +++ b/netwatch/src/netmon/bsd.rs @@ -1,6 +1,6 @@ #[cfg(any(target_os = "macos", target_os = "ios"))] use libc::{RTAX_DST, RTAX_IFP}; -use snafu::{Backtrace, ResultExt, Snafu}; +use n0_error::stack_error; use tokio::{io::AsyncReadExt, sync::mpsc}; use tokio_util::task::AbortOnDropHandle; use tracing::{trace, warn}; @@ -15,14 +15,11 @@ pub(super) struct RouteMonitor { _handle: AbortOnDropHandle<()>, } -#[derive(Debug, Snafu)] +#[stack_error(derive, add_meta, from_sources, std_sources)] #[non_exhaustive] pub enum Error { - #[snafu(display("IO"))] - Io { - source: std::io::Error, - backtrace: Option, - }, + #[error("IO")] + Io { source: std::io::Error }, } fn create_socket() -> std::io::Result { @@ -38,7 +35,7 @@ fn create_socket() -> std::io::Result { impl RouteMonitor { pub(super) fn new(sender: mpsc::Sender) -> Result { - let mut socket = create_socket().context(IoSnafu)?; + let mut socket = create_socket()?; let handle = tokio::task::spawn(async move { trace!("AF_ROUTE monitor started"); diff --git a/netwatch/src/netmon/linux.rs b/netwatch/src/netmon/linux.rs index 00d5bb4d..026ab879 100644 --- a/netwatch/src/netmon/linux.rs +++ b/netwatch/src/netmon/linux.rs @@ -7,11 +7,11 @@ use libc::{ RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV4_RULE, RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_ROUTE, RTNLGRP_IPV6_RULE, }; +use n0_error::stack_error; use n0_future::StreamExt; use netlink_packet_core::NetlinkPayload; use netlink_packet_route::{RouteNetlinkMessage, address, route}; use netlink_sys::{AsyncSocket, SocketAddr}; -use snafu::{Backtrace, ResultExt, Snafu}; use tokio::{sync::mpsc, task::JoinHandle}; use tracing::{trace, warn}; @@ -31,14 +31,11 @@ impl Drop for RouteMonitor { } } -#[derive(Debug, Snafu)] +#[stack_error(derive, add_meta, from_sources, std_sources)] #[non_exhaustive] pub enum Error { - #[snafu(display("IO"))] - Io { - source: std::io::Error, - backtrace: Option, - }, + #[error("IO")] + Io { source: std::io::Error }, } const fn nl_mgrp(group: u32) -> u32 { @@ -62,8 +59,7 @@ impl RouteMonitor { let (mut conn, _handle, mut messages) = netlink_proto::new_connection::< netlink_packet_route::RouteNetlinkMessage, - >(NETLINK_ROUTE) - .context(IoSnafu)?; + >(NETLINK_ROUTE)?; // Specify flags to listen on. let groups = nl_mgrp(RTNLGRP_IPV4_IFADDR) @@ -74,10 +70,7 @@ impl RouteMonitor { | nl_mgrp(RTNLGRP_IPV6_RULE); let addr = SocketAddr::new(0, groups); - conn.socket_mut() - .socket_mut() - .bind(&addr) - .context(IoSnafu)?; + conn.socket_mut().socket_mut().bind(&addr)?; let conn_handle = tokio::task::spawn(conn); diff --git a/netwatch/src/netmon/wasm_browser.rs b/netwatch/src/netmon/wasm_browser.rs index 37695406..51a1187c 100644 --- a/netwatch/src/netmon/wasm_browser.rs +++ b/netwatch/src/netmon/wasm_browser.rs @@ -2,18 +2,16 @@ use js_sys::{ Function, wasm_bindgen::{JsCast, prelude::Closure}, }; +use n0_error::stack_error; use n0_future::task; use tokio::sync::mpsc; use web_sys::{EventListener, EventTarget}; use super::actor::NetworkMessage; -#[derive(Debug, derive_more::Display)] -#[display("error")] +#[stack_error(derive, add_meta)] pub struct Error; -impl std::error::Error for Error {} - #[derive(Debug)] pub(super) struct RouteMonitor { _listeners: Option, diff --git a/netwatch/src/netmon/windows.rs b/netwatch/src/netmon/windows.rs index b601092b..d97b6b50 100644 --- a/netwatch/src/netmon/windows.rs +++ b/netwatch/src/netmon/windows.rs @@ -1,8 +1,7 @@ use std::{collections::HashMap, sync::Arc}; use libc::c_void; -use nested_enum_utils::common_fields; -use snafu::{Backtrace, ResultExt, Snafu}; +use n0_error::stack_error; use tokio::sync::mpsc; use tracing::{trace, warn}; use windows::Win32::{ @@ -20,15 +19,12 @@ pub(super) struct RouteMonitor { cb_handler: CallbackHandler, } -#[common_fields({ - backtrace: Option, -})] -#[derive(Debug, Snafu)] +#[stack_error(derive, add_meta, std_sources, from_sources)] #[non_exhaustive] pub enum Error { - #[snafu(display("IO"))] + #[error("IO")] Io { source: std::io::Error }, - #[snafu(display("win32"))] + #[error("win32")] Win32 { source: windows_result::Error }, } @@ -120,8 +116,7 @@ impl CallbackHandler { false, // initial notification, &mut handle, ) - .ok() - .context(Win32Snafu)?; + .ok()?; } self.unicast_callbacks.insert(handle.0 as isize, cb); @@ -141,8 +136,7 @@ impl CallbackHandler { { unsafe { windows::Win32::NetworkManagement::IpHelper::CancelMibChangeNotify2(handle.0) - .ok() - .context(Win32Snafu)?; + .ok()?; } } @@ -164,8 +158,7 @@ impl CallbackHandler { false, // initial notification, &mut handle, ) - .ok() - .context(Win32Snafu)?; + .ok()?; } self.route_callbacks.insert(handle.0 as isize, cb); @@ -185,8 +178,7 @@ impl CallbackHandler { { unsafe { windows::Win32::NetworkManagement::IpHelper::CancelMibChangeNotify2(handle.0) - .ok() - .context(Win32Snafu)?; + .ok()?; } } diff --git a/portmapper/Cargo.toml b/portmapper/Cargo.toml index 55016461..bbe1a075 100644 --- a/portmapper/Cargo.toml +++ b/portmapper/Cargo.toml @@ -22,15 +22,14 @@ derive_more = { version = "2.0.1", features = ["debug", "display", "from", "try_ futures-lite = "2.5" futures-util = "0.3.25" igd-next = { version = "0.16.1", features = ["aio_tokio"] } -iroh-metrics = { version = "0.36", default-features = false } +iroh-metrics = { version = "0.37", default-features = false } libc = "0.2.139" -nested_enum_utils = "0.2.3" netwatch = { version = "0.11.0", path = "../netwatch" } +n0-error = "0.1.0" num_enum = "0.7" rand = "0.9" serde = { version = "1", features = ["derive", "rc"] } smallvec = "1.11.1" -snafu = { version = "0.8.5", features = ["rust_1_81"] } socket2 = "0.6" time = "0.3.20" tokio = { version = "1", features = ["io-util", "macros", "sync", "rt", "net", "fs", "io-std", "signal", "process"] } diff --git a/portmapper/src/lib.rs b/portmapper/src/lib.rs index 64b9a76b..07b5ddef 100644 --- a/portmapper/src/lib.rs +++ b/portmapper/src/lib.rs @@ -9,8 +9,8 @@ use std::{ use current_mapping::CurrentMapping; use futures_lite::StreamExt; +use n0_error::{e, stack_error}; use netwatch::interfaces::HomeRouter; -use snafu::Snafu; use tokio::sync::{mpsc, oneshot, watch}; use tokio_util::task::AbortOnDropHandle; use tracing::{Instrument, debug, info_span, trace}; @@ -67,23 +67,20 @@ impl ProbeOutput { } } -// Cannot have backtrace due to Clone bound -// #[nested_enum_utils::common_fields({ -// backtrace: Option, -// })] #[allow(missing_docs)] -#[derive(Debug, Clone, Snafu)] +#[stack_error(derive, add_meta)] +#[derive(Clone)] #[non_exhaustive] pub enum ProbeError { - #[snafu(display("Mapping channel is full"))] + #[error("Mapping channel is full")] ChannelFull, - #[snafu(display("Mapping channel is closed"))] + #[error("Mapping channel is closed")] ChannelClosed, - #[snafu(display("No gateway found for probe"))] + #[error("No gateway found for probe")] NoGateway, - #[snafu(display("gateway found is ipv6, ignoring"))] + #[error("gateway found is ipv6, ignoring")] Ipv6Gateway, - #[snafu(display("Probe task stopped. is_panic: {is_panic}, is_cancelled: {is_cancelled}"))] + #[error("Probe task stopped. is_panic: {is_panic}, is_cancelled: {is_cancelled}")] Join { is_panic: bool, is_cancelled: bool }, } @@ -198,8 +195,8 @@ impl Client { // recover the sender and return the error there let (result_tx, e) = match e { - Full(Message::Probe { result_tx }) => (result_tx, ChannelFullSnafu.build()), - Closed(Message::Probe { result_tx }) => (result_tx, ChannelClosedSnafu.build()), + Full(Message::Probe { result_tx }) => (result_tx, e!(ProbeError::ChannelFull)), + Closed(Message::Probe { result_tx }) => (result_tx, e!(ProbeError::ChannelClosed)), Full(_) | Closed(_) => unreachable!("Sent value is a probe."), }; @@ -526,7 +523,7 @@ impl Service { trace!("tick: probe ready"); // retrieve the receivers and clear the task let receivers = self.probing_task.take().expect("is some").1; - let probe_result = probe_result.map_err(|e| JoinSnafu { is_panic: e.is_panic(), is_cancelled: e.is_cancelled() }.build()); + let probe_result = probe_result.map_err(|e| e!(ProbeError::Join { is_panic: e.is_panic(), is_cancelled: e.is_cancelled() })); self.on_probe_result(probe_result, receivers); } Some(event) = self.current_mapping.next() => { @@ -774,7 +771,7 @@ impl Service { /// Gets the local ip and gateway address for port mapping. fn ip_and_gateway() -> Result<(Ipv4Addr, Ipv4Addr), ProbeError> { let Some(HomeRouter { gateway, my_ip }) = HomeRouter::new() else { - return Err(NoGatewaySnafu.build()); + return Err(e!(ProbeError::NoGateway)); }; let local_ip = match my_ip { @@ -790,7 +787,7 @@ fn ip_and_gateway() -> Result<(Ipv4Addr, Ipv4Addr), ProbeError> { }; let std::net::IpAddr::V4(gateway) = gateway else { - return Err(Ipv6GatewaySnafu.build()); + return Err(e!(ProbeError::Ipv6Gateway)); }; Ok((local_ip, gateway)) diff --git a/portmapper/src/mapping.rs b/portmapper/src/mapping.rs index 91a58789..914d0149 100644 --- a/portmapper/src/mapping.rs +++ b/portmapper/src/mapping.rs @@ -2,8 +2,7 @@ use std::{net::Ipv4Addr, num::NonZeroU16, time::Duration}; -use nested_enum_utils::common_fields; -use snafu::{Backtrace, ResultExt, Snafu}; +use n0_error::stack_error; use super::{nat_pmp, pcp, upnp}; use crate::Protocol; @@ -26,18 +25,15 @@ pub enum Mapping { } /// Mapping error. -#[common_fields({ - backtrace: Option, -})] #[allow(missing_docs)] -#[derive(Debug, Snafu)] +#[stack_error(derive, add_meta, from_sources)] #[non_exhaustive] pub enum Error { - #[snafu(display("PCP mapping failed"))] + #[error("PCP mapping failed")] Pcp { source: pcp::Error }, - #[snafu(display("NAT-PMP mapping failed"))] + #[error("NAT-PMP mapping failed")] NatPmp { source: nat_pmp::Error }, - #[snafu(display("UPnP mapping failed"))] + #[error("UPnP mapping failed")] Upnp { source: upnp::Error }, } @@ -53,7 +49,7 @@ impl Mapping { pcp::Mapping::new(protocol, local_ip, local_port, gateway, external_addr) .await .map(Self::Pcp) - .context(PcpSnafu) + .map_err(Error::from) } /// Create a new NAT-PMP mapping. @@ -73,7 +69,7 @@ impl Mapping { ) .await .map(Self::NatPmp) - .context(NatPmpSnafu) + .map_err(Error::from) } /// Create a new UPnP mapping. @@ -87,15 +83,15 @@ impl Mapping { upnp::Mapping::new(protocol, local_ip, local_port, gateway, external_port) .await .map(Self::Upnp) - .context(UpnpSnafu) + .map_err(Error::from) } /// Release the mapping. pub(crate) async fn release(self) -> Result<(), Error> { match self { - Mapping::Upnp(m) => m.release().await.context(UpnpSnafu)?, - Mapping::Pcp(m) => m.release().await.context(PcpSnafu)?, - Mapping::NatPmp(m) => m.release().await.context(NatPmpSnafu)?, + Mapping::Upnp(m) => m.release().await?, + Mapping::Pcp(m) => m.release().await?, + Mapping::NatPmp(m) => m.release().await?, } Ok(()) } diff --git a/portmapper/src/nat_pmp.rs b/portmapper/src/nat_pmp.rs index fe7847c2..88adb30d 100644 --- a/portmapper/src/nat_pmp.rs +++ b/portmapper/src/nat_pmp.rs @@ -2,9 +2,8 @@ use std::{net::Ipv4Addr, num::NonZeroU16, time::Duration}; -use nested_enum_utils::common_fields; +use n0_error::{e, stack_error}; use netwatch::UdpSocket; -use snafu::{Backtrace, Snafu}; use tracing::{debug, trace}; use self::protocol::{MapProtocol, Request, Response}; @@ -33,20 +32,20 @@ pub struct Mapping { lifetime_seconds: u32, } -#[common_fields({ - backtrace: Option -})] #[allow(missing_docs)] -#[derive(Debug, Snafu)] +#[stack_error(derive, add_meta, from_sources)] #[non_exhaustive] pub enum Error { - #[snafu(display("server returned unexpected response for mapping request"))] + #[error("server returned unexpected response for mapping request")] UnexpectedServerResponse {}, - #[snafu(display("received 0 port from server as external port"))] + #[error("received 0 port from server as external port")] ZeroExternalPort {}, - #[snafu(transparent)] - Io { source: std::io::Error }, - #[snafu(transparent)] + #[error(transparent)] + Io { + #[error(std_err)] + source: std::io::Error, + }, + #[error(transparent)] Protocol { source: protocol::Error }, } @@ -105,12 +104,12 @@ impl Mapping { } if private_port == Into::::into(local_port) && proto == proto_rcvd => { (external_port, lifetime_seconds) } - _ => return Err(UnexpectedServerResponseSnafu.build()), + _ => return Err(e!(Error::UnexpectedServerResponse)), }; let external_port = external_port .try_into() - .map_err(|_| ZeroExternalPortSnafu.build())?; + .map_err(|_| e!(Error::ZeroExternalPort))?; // now send the second request to get the external address let req = Request::ExternalAddress; @@ -130,7 +129,7 @@ impl Mapping { epoch_time: _, public_ip, } => public_ip, - _ => return Err(UnexpectedServerResponseSnafu.build()), + _ => return Err(e!(Error::UnexpectedServerResponse)), }; Ok(Mapping { diff --git a/portmapper/src/nat_pmp/protocol/response.rs b/portmapper/src/nat_pmp/protocol/response.rs index 87f3379d..7fc30a46 100644 --- a/portmapper/src/nat_pmp/protocol/response.rs +++ b/portmapper/src/nat_pmp/protocol/response.rs @@ -2,9 +2,8 @@ use std::net::Ipv4Addr; -use nested_enum_utils::common_fields; +use n0_error::{e, stack_error}; use num_enum::{IntoPrimitive, TryFromPrimitive}; -use snafu::{Backtrace, Snafu}; use super::{MapProtocol, Opcode, Version}; @@ -53,42 +52,39 @@ pub enum ResultCode { } /// Errors that can occur when decoding a [`Response`] from a server. -#[common_fields({ - backtrace: Option, -})] #[allow(missing_docs)] -#[derive(Debug, Snafu)] +#[stack_error(derive, add_meta)] #[non_exhaustive] pub enum Error { /// Request is too short or is otherwise malformed. - #[snafu(display("Response is malformed"))] + #[error("Response is malformed")] Malformed {}, /// The [`Response::RESPONSE_INDICATOR`] is not present. - #[snafu(display("Packet does not appear to be a response"))] + #[error("Packet does not appear to be a response")] NotAResponse {}, /// The received opcode is not recognized. - #[snafu(display("Invalid Opcode received"))] + #[error("Invalid Opcode received")] InvalidOpcode {}, /// The received version is not recognized. - #[snafu(display("Invalid version received"))] + #[error("Invalid version received")] InvalidVersion {}, /// The received result code is not recognized. - #[snafu(display("Invalid result code received"))] + #[error("Invalid result code received")] InvalidResultCode {}, /// Received an error code indicating the server does not support the sent version. - #[snafu(display("Server does not support the version"))] + #[error("Server does not support the version")] UnsupportedVersion {}, /// Received an error code indicating the operation is supported but not authorized. - #[snafu(display("Operation is supported but not authorized"))] + #[error("Operation is supported but not authorized")] NotAuthorizedOrRefused {}, /// Received an error code indicating the server experienced a network failure - #[snafu(display("Server experienced a network failure"))] + #[error("Server experienced a network failure")] NetworkFailure {}, /// Received an error code indicating the server cannot create more mappings at this time. - #[snafu(display("Server is out of resources"))] + #[error("Server is out of resources")] OutOfResources {}, /// Received an error code indicating the Opcode is not supported by the server. - #[snafu(display("Server does not support this opcode"))] + #[error("Server does not support this opcode")] UnsupportedOpcode {}, } @@ -117,7 +113,7 @@ impl Response { /// Decode a map response. fn decode_map(buf: &[u8], proto: MapProtocol) -> Result { if buf.len() != Self::MAX_SIZE { - return Err(MalformedSnafu.build()); + return Err(e!(Error::Malformed)); } let epoch_bytes = buf[4..8].try_into().expect("slice has the right len"); @@ -144,30 +140,30 @@ impl Response { /// Decode a response. pub fn decode(buf: &[u8]) -> Result { if buf.len() < Self::MIN_SIZE || buf.len() > Self::MAX_SIZE { - return Err(MalformedSnafu.build()); + return Err(e!(Error::Malformed)); } - let _: Version = buf[0].try_into().map_err(|_| InvalidVersionSnafu.build())?; + let _: Version = buf[0].try_into().map_err(|_| e!(Error::InvalidVersion))?; let opcode = buf[1]; if opcode & Self::RESPONSE_INDICATOR != Self::RESPONSE_INDICATOR { - return Err(NotAResponseSnafu.build()); + return Err(e!(Error::NotAResponse)); } let opcode: Opcode = (opcode & !Self::RESPONSE_INDICATOR) .try_into() - .map_err(|_| InvalidOpcodeSnafu.build())?; + .map_err(|_| e!(Error::InvalidOpcode))?; let result_bytes = u16::from_be_bytes(buf[2..4].try_into().expect("slice has the right len")); let result_code = result_bytes .try_into() - .map_err(|_| InvalidResultCodeSnafu.build())?; + .map_err(|_| e!(Error::InvalidResultCode))?; match result_code { ResultCode::Success => Ok(()), - ResultCode::UnsupportedVersion => Err(UnsupportedVersionSnafu.build()), - ResultCode::NotAuthorizedOrRefused => Err(NotAuthorizedOrRefusedSnafu.build()), - ResultCode::NetworkFailure => Err(NetworkFailureSnafu.build()), - ResultCode::OutOfResources => Err(OutOfResourcesSnafu.build()), - ResultCode::UnsupportedOpcode => Err(UnsupportedOpcodeSnafu.build()), + ResultCode::UnsupportedVersion => Err(e!(Error::UnsupportedVersion)), + ResultCode::NotAuthorizedOrRefused => Err(e!(Error::NotAuthorizedOrRefused)), + ResultCode::NetworkFailure => Err(e!(Error::NetworkFailure)), + ResultCode::OutOfResources => Err(e!(Error::OutOfResources)), + ResultCode::UnsupportedOpcode => Err(e!(Error::UnsupportedOpcode)), }?; let response = match opcode { diff --git a/portmapper/src/pcp.rs b/portmapper/src/pcp.rs index 5d762c3a..e700c9bb 100644 --- a/portmapper/src/pcp.rs +++ b/portmapper/src/pcp.rs @@ -2,10 +2,9 @@ use std::{net::Ipv4Addr, num::NonZeroU16, time::Duration}; -use nested_enum_utils::common_fields; +use n0_error::{e, stack_error}; use netwatch::UdpSocket; use rand::RngCore; -use snafu::{Backtrace, ResultExt, Snafu}; use tracing::{debug, trace}; use crate::{Protocol, defaults::PCP_RECV_TIMEOUT as RECV_TIMEOUT}; @@ -38,28 +37,28 @@ pub struct Mapping { nonce: [u8; 12], } -#[common_fields({ - backtrace: Option, -})] #[allow(missing_docs)] -#[derive(Debug, Snafu)] +#[stack_error(derive, add_meta, from_sources)] #[non_exhaustive] pub enum Error { - #[snafu(display("received nonce does not match sent request"))] + #[error("received nonce does not match sent request")] NonceMissmatch {}, - #[snafu(display("received mapping does not match the requested protocol"))] + #[error("received mapping does not match the requested protocol")] ProtocolMissmatch {}, - #[snafu(display("received mapping is for a local port that does not match the requested one"))] + #[error("received mapping is for a local port that does not match the requested one")] PortMissmatch {}, - #[snafu(display("received 0 external port for mapping"))] + #[error("received 0 external port for mapping")] ZeroExternalPort {}, - #[snafu(display("received external address is not ipv4"))] + #[error("received external address is not ipv4")] NotIpv4 {}, - #[snafu(display("received an announce response for a map request"))] + #[error("received an announce response for a map request")] InvalidAnnounce {}, - #[snafu(display("IO error during PCP"))] - Io { source: std::io::Error }, - #[snafu(display("Protocol error during PCP"))] + #[error("IO error during PCP")] + Io { + #[error(std_err)] + source: std::io::Error, + }, + #[error("Protocol error during PCP")] Protocol { source: protocol::Error }, } @@ -83,10 +82,8 @@ impl Mapping { preferred_external_address: Option<(Ipv4Addr, NonZeroU16)>, ) -> Result { // create the socket and send the request - let socket = UdpSocket::bind_full((local_ip, 0)).context(IoSnafu)?; - socket - .connect((gateway, protocol::SERVER_PORT).into()) - .context(IoSnafu)?; + let socket = UdpSocket::bind_full((local_ip, 0))?; + socket.connect((gateway, protocol::SERVER_PORT).into())?; let mut nonce = [0u8; 12]; rand::rng().fill_bytes(&mut nonce); @@ -110,7 +107,7 @@ impl Mapping { MAPPING_REQUESTED_LIFETIME_SECONDS, ); - socket.send(&req.encode()).await.context(IoSnafu)?; + socket.send(&req.encode()).await?; // wait for the response and decode it let mut buffer = vec![0; protocol::Response::MAX_SIZE]; @@ -118,10 +115,8 @@ impl Mapping { .await .map_err(|_| { std::io::Error::new(std::io::ErrorKind::TimedOut, "read timeout".to_string()) - }) - .context(IoSnafu)? - .context(IoSnafu)?; - let response = protocol::Response::decode(&buffer[..read]).context(ProtocolSnafu)?; + })??; + let response = protocol::Response::decode(&buffer[..read])?; // verify that the response is correct and matches the request let protocol::Response { @@ -141,24 +136,24 @@ impl Mapping { } = map_data; if nonce != received_nonce { - return Err(NonceMissmatchSnafu.build()); + return Err(e!(Error::NonceMissmatch)); } if received_protocol != protocol { - return Err(ProtocolMissmatchSnafu.build()); + return Err(e!(Error::ProtocolMissmatch)); } let sent_port: u16 = local_port.into(); if received_local_port != sent_port { - return Err(PortMissmatchSnafu.build()); + return Err(e!(Error::PortMissmatch)); } let external_port = external_port .try_into() - .map_err(|_| ZeroExternalPortSnafu.build())?; + .map_err(|_| e!(Error::ZeroExternalPort))?; let external_address = external_address .to_ipv4_mapped() - .ok_or(NotIpv4Snafu.build())?; + .ok_or(e!(Error::NotIpv4))?; Ok(Mapping { protocol: received_protocol, @@ -171,7 +166,7 @@ impl Mapping { gateway, }) } - protocol::OpcodeData::Announce => Err(InvalidAnnounceSnafu.build()), + protocol::OpcodeData::Announce => Err(e!(Error::InvalidAnnounce)), } } @@ -186,15 +181,13 @@ impl Mapping { } = self; // create the socket and send the request - let socket = UdpSocket::bind_full((local_ip, 0)).context(IoSnafu)?; - socket - .connect((gateway, protocol::SERVER_PORT).into()) - .context(IoSnafu)?; + let socket = UdpSocket::bind_full((local_ip, 0))?; + socket.connect((gateway, protocol::SERVER_PORT).into())?; let local_port = local_port.into(); let req = protocol::Request::mapping(nonce, protocol, local_port, local_ip, None, None, 0); - socket.send(&req.encode()).await.context(IoSnafu)?; + socket.send(&req.encode()).await?; // mapping deletion is a notification, no point in waiting for the response Ok(()) @@ -232,21 +225,22 @@ async fn probe_available_fallible( gateway: Ipv4Addr, ) -> Result { // create the socket and send the request - let socket = UdpSocket::bind_full((local_ip, 0)).context(IoSnafu)?; - socket - .connect((gateway, protocol::SERVER_PORT).into()) - .context(IoSnafu)?; + let socket = UdpSocket::bind_full((local_ip, 0))?; + socket.connect((gateway, protocol::SERVER_PORT).into())?; let req = protocol::Request::announce(local_ip.to_ipv6_mapped()); - socket.send(&req.encode()).await.context(IoSnafu)?; + socket.send(&req.encode()).await?; // wait for the response and decode it let mut buffer = vec![0; protocol::Response::MAX_SIZE]; let read = tokio::time::timeout(RECV_TIMEOUT, socket.recv(&mut buffer)) .await - .map_err(|_| std::io::Error::new(std::io::ErrorKind::TimedOut, "read timeout".to_string())) - .context(IoSnafu)? - .context(IoSnafu)?; - let response = protocol::Response::decode(&buffer[..read]).context(ProtocolSnafu)?; + .map_err(|_| { + e!( + Error::Io, + std::io::Error::new(std::io::ErrorKind::TimedOut, "read timeout".to_string()) + ) + })??; + let response = protocol::Response::decode(&buffer[..read])?; Ok(response) } diff --git a/portmapper/src/pcp/protocol/response.rs b/portmapper/src/pcp/protocol/response.rs index f7e69358..37f31cc2 100644 --- a/portmapper/src/pcp/protocol/response.rs +++ b/portmapper/src/pcp/protocol/response.rs @@ -1,9 +1,8 @@ //! A PCP response encoding and decoding. use derive_more::Display; -use nested_enum_utils::common_fields; +use n0_error::{e, ensure, stack_error}; use num_enum::{IntoPrimitive, TryFromPrimitive, TryFromPrimitiveError}; -use snafu::{Backtrace, Snafu}; use super::{Opcode, Version, opcode_data::OpcodeData}; @@ -124,37 +123,37 @@ pub struct Response { /// Errors that can occur when decoding a [`Response`] from a server. #[allow(missing_docs)] #[non_exhaustive] -#[common_fields({ - backtrace: Option, -})] -#[derive(Debug, Snafu)] +#[stack_error(derive, add_meta)] pub enum DecodeError { /// Request is too short or is otherwise malformed. - #[snafu(display("Response is malformed"))] + #[error("Response is malformed")] Malformed {}, /// The [`Response::RESPONSE_INDICATOR`] is not present. - #[snafu(display("Packet does not appear to be a response"))] + #[error("Packet does not appear to be a response")] NotAResponse {}, /// The received opcode is not recognized. - #[snafu(display("Invalid Opcode received"))] + #[error("Invalid Opcode received")] InvalidOpcode {}, /// The received version is not recognized. - #[snafu(display("Invalid version received"))] + #[error("Invalid version received")] InvalidVersion {}, /// The received result code is not recognized. - #[snafu(display("Invalid result code received"))] + #[error("Invalid result code received")] InvalidResultCode {}, /// The received opcode data could not be decoded. - #[snafu(display("Invalid opcode data received"))] + #[error("Invalid opcode data received")] InvalidOpcodeData {}, } -#[derive(Debug, Snafu)] +#[stack_error(derive, add_meta, from_sources)] pub enum Error { - #[snafu(transparent)] + #[error(transparent)] DecodeError { source: DecodeError }, - #[snafu(transparent)] - ErrorCode { source: ErrorCode }, + #[error("PCP error code")] + ErrorCode { + #[error(std_err)] + source: ErrorCode, + }, } impl Response { @@ -177,28 +176,30 @@ impl Response { /// Decode a response. pub fn decode(buf: &[u8]) -> Result { - snafu::ensure!( + ensure!( Self::MIN_SIZE <= buf.len() && buf.len() <= Self::MAX_SIZE, - MalformedSnafu + DecodeError::Malformed ); - let _version: Version = buf[0].try_into().map_err(|_| InvalidVersionSnafu.build())?; + let _version: Version = buf[0] + .try_into() + .map_err(|_| e!(DecodeError::InvalidVersion))?; let opcode = buf[1]; - snafu::ensure!( + ensure!( opcode & Self::RESPONSE_INDICATOR == Self::RESPONSE_INDICATOR, - NotAResponseSnafu + DecodeError::NotAResponse ); let opcode: Opcode = (opcode & !Self::RESPONSE_INDICATOR) .try_into() - .map_err(|_| InvalidOpcodeSnafu.build())?; + .map_err(|_| e!(DecodeError::InvalidOpcode))?; // buf[2] reserved // return early if the result code is an error let result_code: ResultCode = buf[3] .try_into() - .map_err(|_| InvalidResultCodeSnafu.build())?; + .map_err(|_| e!(DecodeError::InvalidResultCode))?; match result_code { ResultCode::Success => {} ResultCode::Error(error_code) => return Err(error_code.into()), @@ -212,8 +213,8 @@ impl Response { // buf[12..24] reserved - let data = - OpcodeData::decode(opcode, &buf[24..]).map_err(|_| InvalidOpcodeDataSnafu.build())?; + let data = OpcodeData::decode(opcode, &buf[24..]) + .map_err(|_| e!(DecodeError::InvalidOpcodeData))?; Ok(Response { lifetime_seconds, diff --git a/portmapper/src/upnp.rs b/portmapper/src/upnp.rs index 69673282..22cda586 100644 --- a/portmapper/src/upnp.rs +++ b/portmapper/src/upnp.rs @@ -6,8 +6,7 @@ use std::{ }; use igd_next::{AddAnyPortError, GetExternalIpError, RemovePortError, SearchError, aio as aigd}; -use nested_enum_utils::common_fields; -use snafu::{Backtrace, ResultExt, Snafu}; +use n0_error::{e, stack_error}; use tracing::debug; use super::Metrics; @@ -39,26 +38,23 @@ pub struct Mapping { external_port: NonZeroU16, } -#[common_fields({ - backtrace: Option, -})] #[allow(missing_docs)] -#[derive(Debug, Snafu)] +#[stack_error(derive, add_meta, std_sources, from_sources)] #[non_exhaustive] pub enum Error { - #[snafu(display("Zero external port"))] + #[error("Zero external port")] ZeroExternalPort {}, - #[snafu(display("igd device's external ip is ipv6"))] + #[error("igd device's external ip is ipv6")] NotIpv4 {}, - #[snafu(display("Remove Port"))] + #[error("Remove Port")] RemovePort { source: RemovePortError }, - #[snafu(display("Search"))] + #[error("Search")] Search { source: SearchError }, - #[snafu(display("Get external IP"))] + #[error("Get external IP")] GetExternalIp { source: GetExternalIpError }, - #[snafu(display("Add any port"))] + #[error("Add any port")] AddAnyPort { source: AddAnyPortError }, - #[snafu(display("IO"))] + #[error("IO")] Io { source: std::io::Error }, } @@ -87,17 +83,11 @@ impl Mapping { .await .map_err(|_| { std::io::Error::new(std::io::ErrorKind::TimedOut, "read timeout".to_string()) - }) - .context(IoSnafu)? - .context(SearchSnafu)? + })?? }; - let std::net::IpAddr::V4(external_ip) = gateway - .get_external_ip() - .await - .context(GetExternalIpSnafu)? - else { - return Err(NotIpv4Snafu.build()); + let std::net::IpAddr::V4(external_ip) = gateway.get_external_ip().await? else { + return Err(e!(Error::NotIpv4)); }; let protocol = match protocol { @@ -135,10 +125,9 @@ impl Mapping { PORT_MAPPING_LEASE_DURATION_SECONDS, PORT_MAPPING_DESCRIPTION, ) - .await - .context(AddAnyPortSnafu)? + .await? .try_into() - .map_err(|_| ZeroExternalPortSnafu.build())?; + .map_err(|_| e!(Error::ZeroExternalPort))?; Ok(Mapping { protocol, @@ -160,10 +149,7 @@ impl Mapping { protocol, .. } = self; - gateway - .remove_port(protocol, external_port.into()) - .await - .context(RemovePortSnafu)?; + gateway.remove_port(protocol, external_port.into()).await?; Ok(()) }