find with mdns

This commit is contained in:
Alex Janka 2024-02-23 14:06:44 +11:00
parent 6ddabfbf11
commit 8982b11073
4 changed files with 455 additions and 12 deletions

384
Cargo.lock generated
View file

@ -90,6 +90,16 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "avahi-sys"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e00c83b3887835fd326daae1b2c4e7a435405033331a876ae1dd03f77b8274"
dependencies = [
"bindgen 0.69.4",
"libc",
]
[[package]]
name = "backtrace"
version = "0.3.69"
@ -111,12 +121,64 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bindgen"
version = "0.68.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078"
dependencies = [
"bitflags 2.4.2",
"cexpr",
"clang-sys",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn 2.0.48",
"which",
]
[[package]]
name = "bindgen"
version = "0.69.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
dependencies = [
"bitflags 2.4.2",
"cexpr",
"clang-sys",
"itertools",
"lazy_static",
"lazycell",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn 2.0.48",
"which",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[package]]
name = "block-buffer"
version = "0.10.4"
@ -126,6 +188,16 @@ dependencies = [
"generic-array",
]
[[package]]
name = "bonjour-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09c6bd8cd70ddd43e654232eae6fce46d60a43e250b2cc8f08c750e6325604ca"
dependencies = [
"bindgen 0.68.1",
"libc",
]
[[package]]
name = "bytes"
version = "1.5.0"
@ -141,6 +213,15 @@ dependencies = [
"libc",
]
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -182,6 +263,17 @@ dependencies = [
"zeroize",
]
[[package]]
name = "clang-sys"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "clap"
version = "4.5.0"
@ -201,7 +293,7 @@ dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
"strsim 0.11.0",
]
[[package]]
@ -213,7 +305,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
"syn 2.0.48",
]
[[package]]
@ -279,7 +371,42 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.48",
]
[[package]]
name = "darling"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim 0.9.3",
"syn 1.0.109",
]
[[package]]
name = "darling_macro"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
dependencies = [
"darling_core",
"quote",
"syn 1.0.109",
]
[[package]]
@ -292,6 +419,53 @@ dependencies = [
"zeroize",
]
[[package]]
name = "derive-getters"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2c35ab6e03642397cdda1dd58abbc05d418aef8e36297f336d5aba060fe8df"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "derive-new"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "derive_builder"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0"
dependencies = [
"darling",
"derive_builder_core",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "derive_builder_core"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "digest"
version = "0.10.7"
@ -327,6 +501,12 @@ dependencies = [
"zeroize",
]
[[package]]
name = "either"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
[[package]]
name = "env_filter"
version = "0.1.0"
@ -350,6 +530,16 @@ dependencies = [
"log",
]
[[package]]
name = "errno"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "fiat-crypto"
version = "0.2.6"
@ -389,6 +579,12 @@ version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "heck"
version = "0.4.1"
@ -428,6 +624,15 @@ dependencies = [
"digest",
]
[[package]]
name = "home"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "homekit-controller"
version = "0.1.0"
@ -445,6 +650,7 @@ dependencies = [
"thiserror",
"tokio",
"x25519-dalek",
"zeroconf",
]
[[package]]
@ -481,6 +687,12 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "inout"
version = "0.1.3"
@ -490,18 +702,55 @@ dependencies = [
"generic-array",
]
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "libloading"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
[[package]]
name = "lock_api"
version = "0.4.11"
@ -524,6 +773,12 @@ version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.7.2"
@ -544,6 +799,16 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num_cpus"
version = "1.16.0"
@ -563,6 +828,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "opaque-debug"
version = "0.3.0"
@ -592,6 +863,12 @@ dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "pin-project-lite"
version = "0.2.13"
@ -625,6 +902,16 @@ dependencies = [
"universal-hash",
]
[[package]]
name = "prettyplease"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5"
dependencies = [
"proc-macro2",
"syn 2.0.48",
]
[[package]]
name = "proc-macro2"
version = "1.0.78"
@ -658,7 +945,7 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -696,6 +983,12 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc_version"
version = "0.4.0"
@ -705,6 +998,19 @@ dependencies = [
"semver",
]
[[package]]
name = "rustix"
version = "0.38.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
dependencies = [
"bitflags 2.4.2",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
]
[[package]]
name = "ryu"
version = "1.0.16"
@ -740,7 +1046,7 @@ checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.48",
]
[[package]]
@ -765,6 +1071,12 @@ dependencies = [
"digest",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
@ -809,6 +1121,12 @@ dependencies = [
"der",
]
[[package]]
name = "strsim"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "strsim"
version = "0.11.0"
@ -821,6 +1139,17 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.48"
@ -849,7 +1178,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.48",
]
[[package]]
@ -879,7 +1208,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.48",
]
[[package]]
@ -922,6 +1251,18 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
@ -1066,6 +1407,33 @@ dependencies = [
"zeroize",
]
[[package]]
name = "zeroconf"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ac03705931460d2a7b50545e22fd299e851e72a4d36cefcc678b99c70c4bfb0"
dependencies = [
"avahi-sys",
"bonjour-sys",
"derive-getters",
"derive-new",
"derive_builder",
"libc",
"log",
"serde",
"zeroconf-macros",
]
[[package]]
name = "zeroconf-macros"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e324c4824e4e9db1f2aeeb83dfa1ab57dbe30c2105eb4b5dcd58fc080b4adcdb"
dependencies = [
"quote",
"syn 2.0.48",
]
[[package]]
name = "zeroize"
version = "1.7.0"
@ -1083,5 +1451,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.48",
]

View file

@ -19,3 +19,4 @@ hex = { version = "0.4", features = ["serde"] }
http = "1.0"
httparse = "1.8"
tokio = { version = "1.36", features = ["net"] }
zeroconf = "0.14"

View file

@ -1,13 +1,22 @@
use std::collections::HashMap;
use std::{
collections::HashMap,
sync::{Arc, RwLock},
time::Duration,
};
use chacha20poly1305::{
aead::generic_array::GenericArray, AeadInPlace, ChaCha20Poly1305, KeyInit, Nonce,
};
use http::{Method, Request};
use thiserror::Error;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::TcpStream,
};
use zeroconf::{
browser::TMdnsBrowser, event_loop::TEventLoop, txt_record::TTxtRecord, MdnsBrowser,
ServiceDiscovery, ServiceType,
};
use crate::{
pairing_data::{Accessory, ServiceCharacteristic},
@ -40,9 +49,57 @@ impl SocketEncryption {
}
}
pub async fn discover(duration_seconds: u64) -> Result<Vec<ServiceDiscovery>, DiscoveryError> {
let service_type = ServiceType::new("hap", "tcp")?;
let mut browser = MdnsBrowser::new(service_type);
let discovered: Arc<RwLock<Vec<ServiceDiscovery>>> = Arc::new(RwLock::new(Vec::new()));
let d2 = discovered.clone();
browser.set_service_discovered_callback(Box::new(move |r, _| {
if let Ok(r) = r {
discovered.write().unwrap().push(r)
}
}));
let event_loop = browser.browse_services()?;
event_loop.poll(Duration::from_secs(duration_seconds))?;
let result = d2.read().unwrap().clone();
Ok(result)
}
async fn reconnect(pairing_id: &str) -> Result<TcpStream, HomekitError> {
log::warn!("error connecting to device...");
log::warn!("trying to find accessory ip/port via bonjour/mdns...");
let discovered = discover(20).await?;
if let Some((hostname, port)) = discovered
.iter()
.find(|d| {
d.txt()
.as_ref()
.map(|t| t.get("id"))
.is_some_and(|txt| txt.is_some_and(|id| id == pairing_id))
})
.map(|d| (d.host_name(), d.port()))
{
let socket = TcpStream::connect(format!("{hostname}:{port}")).await?;
log::info!("successfully found device at {hostname}:{port}");
Ok(socket)
} else {
Err(HomekitError::DeviceNotFound)
}
}
impl AccessorySocket {
pub async fn new(ip: &str, port: usize) -> Result<Self, HomekitError> {
let socket = TcpStream::connect(format!("{ip}:{port}")).await?;
pub async fn new(pairing_id: &str, ip: &str, port: usize) -> Result<Self, HomekitError> {
let socket = tokio::select! {
stream = TcpStream::connect(format!("{ip}:{port}")) => match stream {
Ok(v) => v,
Err(_) => reconnect(pairing_id).await?
},
_ = tokio::time::sleep(Duration::from_secs(1)) => reconnect(pairing_id).await?
};
Ok(Self {
socket,
@ -291,3 +348,9 @@ impl AccessorySocket {
}
}
}
#[derive(Debug, Error)]
pub enum DiscoveryError {
#[error("zeroconf")]
Zeroconf(#[from] zeroconf::error::Error),
}

View file

@ -3,6 +3,7 @@ use chacha20poly1305::{
};
use ed25519_dalek::{Signer, Verifier};
use hkdf::Hkdf;
use homekit_http::DiscoveryError;
use sha2::Sha512;
use std::{collections::HashMap, path::PathBuf};
use thiserror::Error;
@ -31,7 +32,13 @@ impl DevicePairingData {
pub async fn connect(&self) -> Result<ConnectedDevice, HomekitError> {
let key = EphemeralSecret::random();
let pubkey = PublicKey::from(&key);
let mut socket = AccessorySocket::new(&self.accessory_ip, self.accessory_port).await?;
let mut socket = AccessorySocket::new(
&self.accessory_pairing_id,
&self.accessory_ip,
self.accessory_port,
)
.await?;
// 5.7.1 M1: iOS Device -> Accessory 'Verify Start Request'
let step1_response = decode(
@ -321,6 +328,10 @@ pub enum HomekitError {
TlvDeviceError(TlvError),
#[error("parsing utf-8")]
Utf8(#[from] std::string::FromUtf8Error),
#[error("discovery")]
Discovery(#[from] DiscoveryError),
#[error("device not found")]
DeviceNotFound,
}
impl From<TlvError> for HomekitError {