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-sha1-wrapper",
"librqbit-upnp", "librqbit-upnp",
"mime_guess", "mime_guess",
"network-interface",
"parking_lot", "parking_lot",
"quick-xml", "quick-xml",
"reqwest", "reqwest",

View file

@ -34,6 +34,7 @@ tokio-util = "0.7.11"
reqwest = { version = "0.12.7", default-features = false } reqwest = { version = "0.12.7", default-features = false }
socket2 = "0.5.7" socket2 = "0.5.7"
quick-xml = { version = "0.36.1", features = ["serialize"] } quick-xml = { version = "0.36.1", features = ["serialize"] }
network-interface = "2.0.0"
[dev-dependencies] [dev-dependencies]
tracing-subscriber = "0.3.18" tracing-subscriber = "0.3.18"

View file

@ -133,16 +133,15 @@ impl SsdpRunner {
Ok(Self { opts, socket }) 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 usn: &str = &self.opts.usn;
let description_http_location = &self.opts.description_http_location;
let server: &str = &self.opts.server_string; let server: &str = &self.opts.server_string;
let bcast_addr = UPNP_BROADCAST_ADDR; let bcast_addr = UPNP_BROADCAST_ADDR;
format!( format!(
"NOTIFY * HTTP/1.1\r "NOTIFY * HTTP/1.1\r
Host: {bcast_addr}\r Host: {bcast_addr}\r
Cache-Control: max-age=75\r Cache-Control: max-age=75\r
Location: {description_http_location}\r Location: {location}\r
NT: {kind}\r NT: {kind}\r
NTS: {nts}\r NTS: {nts}\r
Server: {server}\r Server: {server}\r
@ -169,17 +168,49 @@ Content-Length: 0\r\n\r\n"
} }
async fn try_send_notifies(&self, nts: &str) { async fn try_send_notifies(&self, nts: &str) {
for kind in [UPNP_KIND_ROOT_DEVICE, UPNP_KIND_MEDIASERVER] { use network_interface::NetworkInterfaceConfig;
let msg = self.generate_notify_message(kind, nts); let interfaces = network_interface::NetworkInterface::show();
trace!(content=?msg, addr=?UPNP_BROADCAST_ADDR, "sending SSDP NOTIFY"); let interfaces = match interfaces {
if let Err(e) = self Ok(interfaces) => interfaces,
.socket Err(e) => {
.send_to(msg.as_bytes(), UPNP_BROADCAST_ADDR) warn!(error=?e, "error determining network interfaces");
.await return;
{ }
warn!(error=?e, "error sending SSDP NOTIFY") };
} else {
debug!(kind, nts, "sent SSDP NOTIFY") 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")
}
}
} }
} }
} }