sending notifies to all interfaces

This commit is contained in:
Igor Katson 2024-08-28 12:33:50 +01:00
parent b22298189c
commit 9eed5aeb07
No known key found for this signature in database
GPG key ID: B4EC22B66D61A3F5
3 changed files with 47 additions and 14 deletions

1
Cargo.lock generated
View file

@ -1639,6 +1639,7 @@ dependencies = [
"librqbit-sha1-wrapper",
"librqbit-upnp",
"mime_guess",
"network-interface",
"parking_lot",
"quick-xml",
"reqwest",

View file

@ -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"

View file

@ -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")
}
}
}
}
}