Nothing: renames and tiny refactors

This commit is contained in:
Igor Katson 2024-09-16 09:21:21 +01:00
parent 8d8d5491f9
commit 028addcf6a
No known key found for this signature in database
GPG key ID: B4EC22B66D61A3F5
2 changed files with 42 additions and 27 deletions

View file

@ -1,5 +1,5 @@
pub const UPNP_KIND_ROOT_DEVICE: &str = "upnp:rootdevice"; pub const UPNP_DEVICE_ROOT: &str = "upnp:rootdevice";
pub const UPNP_KIND_MEDIASERVER: &str = "urn:schemas-upnp-org:device:MediaServer:1"; pub const UPNP_DEVICE_MEDIASERVER: &str = "urn:schemas-upnp-org:device:MediaServer:1";
pub const SOAP_ACTION_CONTENT_DIRECTORY_BROWSE: &[u8] = pub const SOAP_ACTION_CONTENT_DIRECTORY_BROWSE: &[u8] =
b"\"urn:schemas-upnp-org:service:ContentDirectory:1#Browse\""; b"\"urn:schemas-upnp-org:service:ContentDirectory:1#Browse\"";

View file

@ -12,7 +12,7 @@ use tokio::net::UdpSocket;
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use tracing::{debug, trace, warn}; use tracing::{debug, trace, warn};
use crate::constants::{UPNP_KIND_MEDIASERVER, UPNP_KIND_ROOT_DEVICE}; use crate::constants::{UPNP_DEVICE_MEDIASERVER, UPNP_DEVICE_ROOT};
const SSDP_PORT: u16 = 1900; const SSDP_PORT: u16 = 1900;
const SSDM_MCAST_IPV4: Ipv4Addr = Ipv4Addr::new(239, 255, 255, 250); const SSDM_MCAST_IPV4: Ipv4Addr = Ipv4Addr::new(239, 255, 255, 250);
@ -23,8 +23,10 @@ const NTS_ALIVE: &str = "ssdp:alive";
const NTS_BYEBYE: &str = "ssdp:byebye"; const NTS_BYEBYE: &str = "ssdp:byebye";
fn ipv6_is_link_local(ip: Ipv6Addr) -> bool { fn ipv6_is_link_local(ip: Ipv6Addr) -> bool {
let s = ip.segments(); const LL: Ipv6Addr = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
[s[0], s[1], s[2], s[3]] == [0xfe80, 0, 0, 0] const MASK: Ipv6Addr = Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0xffff, 0, 0, 0, 0);
ip.to_bits() & MASK.to_bits() == LL.to_bits() & MASK.to_bits()
} }
#[derive(Debug)] #[derive(Debug)]
@ -49,7 +51,7 @@ impl<'a> SsdpMSearchRequest<'a> {
if self.man != "\"ssdp:discover\"" { if self.man != "\"ssdp:discover\"" {
return false; return false;
} }
if self.st == UPNP_KIND_ROOT_DEVICE || self.st == UPNP_KIND_MEDIASERVER { if self.st == UPNP_DEVICE_ROOT || self.st == UPNP_DEVICE_MEDIASERVER {
return true; return true;
} }
false false
@ -200,6 +202,7 @@ async fn bind_v6_socket() -> anyhow::Result<UdpSocket> {
if !present { if !present {
continue; continue;
} }
trace!(multiaddr=?multiaddr, interface=?nic.index, "joining multicast v6 group");
if let Err(e) = socket.join_multicast_v6(&multiaddr, nic.index) { if let Err(e) = socket.join_multicast_v6(&multiaddr, nic.index) {
debug!(multiaddr=?multiaddr, interface=?nic.index, "error joining multicast v6 group: {e:#}"); debug!(multiaddr=?multiaddr, interface=?nic.index, "error joining multicast v6 group: {e:#}");
} }
@ -210,10 +213,10 @@ async fn bind_v6_socket() -> anyhow::Result<UdpSocket> {
} }
struct MulticastOpts { struct MulticastOpts {
local_interface_ip: IpAddr, interface_addr: IpAddr,
#[allow(dead_code)] #[allow(dead_code)]
local_interface_id: u32, interface_id: u32,
addr: SocketAddr, mcast_addr: SocketAddr,
} }
fn set_mcast_if(sock: &UdpSocket, local_ip: Ipv4Addr) -> anyhow::Result<()> { fn set_mcast_if(sock: &UdpSocket, local_ip: Ipv4Addr) -> anyhow::Result<()> {
@ -259,7 +262,7 @@ fn set_mcast_if(sock: &UdpSocket, local_ip: Ipv4Addr) -> anyhow::Result<()> {
impl MulticastOpts { impl MulticastOpts {
fn addr_no_scope(&self) -> SocketAddr { fn addr_no_scope(&self) -> SocketAddr {
let mut addr = self.addr; let mut addr = self.mcast_addr;
if let SocketAddr::V6(v6) = &mut addr { if let SocketAddr::V6(v6) = &mut addr {
v6.set_scope_id(0); v6.set_scope_id(0);
} }
@ -284,21 +287,26 @@ impl SsdpRunner {
}) })
} }
fn generate_notify_message(&self, kind: &str, nts: &str, opts: &MulticastOpts) -> String { fn generate_notify_message(
&self,
device_kind: &str,
nts: &str,
opts: &MulticastOpts,
) -> String {
let usn: &str = &self.opts.usn; let usn: &str = &self.opts.usn;
let server: &str = &self.opts.server_string; let server: &str = &self.opts.server_string;
let host = opts.addr_no_scope(); let host = opts.addr_no_scope();
let mut location = self.opts.description_http_location.clone(); let mut location = self.opts.description_http_location.clone();
let _ = location.set_ip_host(opts.local_interface_ip); let _ = location.set_ip_host(opts.interface_addr);
format!( format!(
"NOTIFY * HTTP/1.1\r "NOTIFY * HTTP/1.1\r
Host: {host}\r Host: {host}\r
Cache-Control: max-age=75\r Cache-Control: max-age=75\r
Location: {location}\r Location: {location}\r
NT: {kind}\r NT: {device_kind}\r
NTS: {nts}\r NTS: {nts}\r
Server: {server}\r Server: {server}\r
USN: {usn}::{kind}\r USN: {usn}::{device_kind}\r
\r \r
" "
) )
@ -352,15 +360,15 @@ Content-Length: 0\r\n\r\n"
.filter_map(|(ifidx, addr)| match addr.ip() { .filter_map(|(ifidx, addr)| match addr.ip() {
std::net::IpAddr::V4(a) if !a.is_loopback() && a.is_private() => { std::net::IpAddr::V4(a) if !a.is_loopback() && a.is_private() => {
Some(MulticastOpts { Some(MulticastOpts {
local_interface_ip: addr.ip(), interface_addr: addr.ip(),
local_interface_id: ifidx, interface_id: ifidx,
addr: SocketAddr::V4(SocketAddrV4::new(SSDM_MCAST_IPV4, SSDP_PORT)), mcast_addr: SocketAddr::V4(SocketAddrV4::new(SSDM_MCAST_IPV4, SSDP_PORT)),
}) })
} }
std::net::IpAddr::V6(a) if !a.is_loopback() => Some(MulticastOpts { std::net::IpAddr::V6(a) if !a.is_loopback() => Some(MulticastOpts {
local_interface_ip: addr.ip(), interface_addr: addr.ip(),
local_interface_id: ifidx, interface_id: ifidx,
addr: { mcast_addr: {
let bip = if ipv6_is_link_local(a) { let bip = if ipv6_is_link_local(a) {
SSDP_MCAST_IPV6_LINK_LOCAL SSDP_MCAST_IPV6_LINK_LOCAL
} else { } else {
@ -375,20 +383,27 @@ Content-Length: 0\r\n\r\n"
let payload = get_payload(&opts); let payload = get_payload(&opts);
if !sent if !sent
.lock() .lock()
.insert((payload.clone(), opts.local_interface_id, opts.addr)) .insert((payload.clone(), opts.interface_id, opts.mcast_addr))
{ {
// don't send duplicates // don't send duplicates
return; return;
} }
let sock = match ( let sock = match (
opts.local_interface_ip, opts.interface_addr,
self.socket_v4.as_ref(), self.socket_v4.as_ref(),
self.socket_v6.as_ref(), self.socket_v6.as_ref(),
) { ) {
// For IPv4 sockets, call setsockopt(IP_MULTICAST_IF), so that the message
// gets sent out of the interface we want (otherwise it'll get sent through
// default one).
// For IPv6 it's not necessary as we specify scope_id in SocketAddr.
//
// It's important we don't .await() in between also, so that concurrent sends
// have the proper IP_MULTICAST_IF.
(IpAddr::V4(ip), Some(sock_v4), _) => { (IpAddr::V4(ip), Some(sock_v4), _) => {
if let Err(e) = set_mcast_if(sock_v4, ip) { if let Err(e) = set_mcast_if(sock_v4, ip) {
debug!(addr=%ip, "error calling set_mcast_if: {e:#}"); debug!(addr=%ip, "error setting IP_MULTICAST_IF: {e:#}");
} }
sock_v4 sock_v4
} }
@ -396,10 +411,10 @@ Content-Length: 0\r\n\r\n"
_ => return, _ => return,
}; };
match sock.send_to(payload.as_slice(), opts.addr).await { match sock.send_to(payload.as_slice(), opts.mcast_addr).await {
Ok(sz) => trace!(payload=?payload, addr=%opts.addr, size=sz, "sent"), Ok(sz) => trace!(payload=?payload, addr=%opts.mcast_addr, size=sz, "sent"),
Err(e) => { Err(e) => {
debug!(payload=?payload, addr=%opts.addr, "error sending: {e:#}") debug!(payload=?payload, addr=%opts.mcast_addr, "error sending: {e:#}")
} }
}; };
}); });
@ -409,7 +424,7 @@ Content-Length: 0\r\n\r\n"
async fn try_send_notifies(&self, nts: &str) { async fn try_send_notifies(&self, nts: &str) {
self.try_send_mcast_everywhere(&|opts| { self.try_send_mcast_everywhere(&|opts| {
self.generate_notify_message(UPNP_KIND_MEDIASERVER, nts, opts) self.generate_notify_message(UPNP_DEVICE_MEDIASERVER, nts, opts)
.into() .into()
}) })
.await .await