From 9eed5aeb0793427d979e886155f478a1363c6d97 Mon Sep 17 00:00:00 2001 From: Igor Katson Date: Wed, 28 Aug 2024 12:33:50 +0100 Subject: [PATCH] sending notifies to all interfaces --- Cargo.lock | 1 + crates/upnp-serve/Cargo.toml | 1 + crates/upnp-serve/src/ssdp.rs | 59 ++++++++++++++++++++++++++--------- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6fe9901..775bb9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1639,6 +1639,7 @@ dependencies = [ "librqbit-sha1-wrapper", "librqbit-upnp", "mime_guess", + "network-interface", "parking_lot", "quick-xml", "reqwest", diff --git a/crates/upnp-serve/Cargo.toml b/crates/upnp-serve/Cargo.toml index 411327b..1b3c829 100644 --- a/crates/upnp-serve/Cargo.toml +++ b/crates/upnp-serve/Cargo.toml @@ -34,6 +34,7 @@ tokio-util = "0.7.11" reqwest = { version = "0.12.7", default-features = false } socket2 = "0.5.7" quick-xml = { version = "0.36.1", features = ["serialize"] } +network-interface = "2.0.0" [dev-dependencies] tracing-subscriber = "0.3.18" diff --git a/crates/upnp-serve/src/ssdp.rs b/crates/upnp-serve/src/ssdp.rs index 95197af..cc4d37f 100644 --- a/crates/upnp-serve/src/ssdp.rs +++ b/crates/upnp-serve/src/ssdp.rs @@ -133,16 +133,15 @@ impl SsdpRunner { Ok(Self { opts, socket }) } - fn generate_notify_message(&self, kind: &str, nts: &str) -> String { + fn generate_notify_message(&self, kind: &str, nts: &str, location: &str) -> String { let usn: &str = &self.opts.usn; - let description_http_location = &self.opts.description_http_location; let server: &str = &self.opts.server_string; let bcast_addr = UPNP_BROADCAST_ADDR; format!( "NOTIFY * HTTP/1.1\r Host: {bcast_addr}\r Cache-Control: max-age=75\r -Location: {description_http_location}\r +Location: {location}\r NT: {kind}\r NTS: {nts}\r Server: {server}\r @@ -169,17 +168,49 @@ Content-Length: 0\r\n\r\n" } async fn try_send_notifies(&self, nts: &str) { - for kind in [UPNP_KIND_ROOT_DEVICE, UPNP_KIND_MEDIASERVER] { - let msg = self.generate_notify_message(kind, nts); - trace!(content=?msg, addr=?UPNP_BROADCAST_ADDR, "sending SSDP NOTIFY"); - if let Err(e) = self - .socket - .send_to(msg.as_bytes(), UPNP_BROADCAST_ADDR) - .await - { - warn!(error=?e, "error sending SSDP NOTIFY") - } else { - debug!(kind, nts, "sent SSDP NOTIFY") + use network_interface::NetworkInterfaceConfig; + let interfaces = network_interface::NetworkInterface::show(); + let interfaces = match interfaces { + Ok(interfaces) => interfaces, + Err(e) => { + warn!(error=?e, "error determining network interfaces"); + return; + } + }; + + let location = match url::Url::parse(&self.opts.description_http_location) { + Ok(u) => u, + // TODO: rewrite this + Err(e) => { + warn!(error=?e, "error parsing description_http_location"); + return; + } + }; + + for ni in interfaces { + for niaddr in ni.addr { + let ip = niaddr.ip(); + let addr = SocketAddr::new(ip, 0); + let sock = match tokio::net::UdpSocket::bind(addr).await { + Ok(sock) => sock, + Err(e) => { + debug!(%addr, error=?e, "error binding UDP to send NOTIFY"); + continue; + } + }; + + let mut location = location.clone(); + location.set_host(Some(&format!("{ip}"))).unwrap(); + + for kind in [UPNP_KIND_ROOT_DEVICE, UPNP_KIND_MEDIASERVER] { + let msg = self.generate_notify_message(kind, nts, &format!("{location}")); + trace!(content=?msg, addr=?UPNP_BROADCAST_ADDR, "sending SSDP NOTIFY"); + if let Err(e) = sock.send_to(msg.as_bytes(), UPNP_BROADCAST_ADDR).await { + warn!(error=?e, "error sending SSDP NOTIFY") + } else { + debug!(kind, nts, "sent SSDP NOTIFY") + } + } } } }