Skip to content

Commit eab38af

Browse files
committed
use a HashMap to list interfaces of each resolved address
modify query example to use the new ServiceDetailed
1 parent 255cb8a commit eab38af

File tree

4 files changed

+35
-89
lines changed

4 files changed

+35
-89
lines changed

examples/query.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,36 +18,42 @@ use mdns_sd::{ServiceDaemon, ServiceEvent};
1818
fn main() {
1919
env_logger::builder().format_timestamp_millis().init();
2020

21-
// Create a daemon
22-
let mdns = ServiceDaemon::new().expect("Failed to create daemon");
23-
2421
let mut service_type = match std::env::args().nth(1) {
2522
Some(arg) => arg,
2623
None => {
2724
print_usage();
2825
return;
2926
}
3027
};
31-
32-
// Browse for a service type.
3328
service_type.push_str(".local.");
29+
30+
// Create a daemon
31+
let mdns = ServiceDaemon::new().expect("Failed to create daemon");
32+
mdns.use_service_detailed(true)
33+
.expect("Failed to use service detailed");
34+
35+
// Browse for the service type
3436
let receiver = mdns.browse(&service_type).expect("Failed to browse");
3537

3638
let now = std::time::Instant::now();
3739
while let Ok(event) = receiver.recv() {
3840
match event {
39-
ServiceEvent::ServiceResolved(info) => {
41+
ServiceEvent::ServiceDetailed(info) => {
4042
println!(
4143
"At {:?}: Resolved a new service: {}\n host: {}\n port: {}",
4244
now.elapsed(),
43-
info.get_fullname(),
44-
info.get_hostname(),
45-
info.get_port(),
45+
info.fullname,
46+
info.host,
47+
info.port,
4648
);
47-
for addr in info.get_addresses().iter() {
48-
println!(" Address: {}", addr);
49+
for (addr, interfaces) in info.addresses.iter() {
50+
println!(
51+
" Address: {} ({:?})",
52+
addr,
53+
interfaces.iter().map(|i| i.name()).collect::<Vec<_>>()
54+
);
4955
}
50-
for prop in info.get_properties().iter() {
56+
for prop in info.txt_properties.iter() {
5157
println!(" Property: {}", prop);
5258
}
5359
}

src/service_daemon.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ use crate::{
3939
},
4040
error::{e_fmt, Error, Result},
4141
service_info::{
42-
split_sub_domain, valid_ip_on_intf, DnsRegistry, Probe, ScopedAddr, ServiceInfo,
43-
ServiceStatus,
42+
split_sub_domain, valid_ip_on_intf, DnsRegistry, Probe, ServiceInfo, ServiceStatus,
4443
},
4544
Receiver, ResolvedService, TxtProperties,
4645
};
@@ -1899,7 +1898,7 @@ impl Zeroconf {
18991898
fullname: fullname.to_string(),
19001899
host: String::new(),
19011900
port: 0,
1902-
addresses: HashSet::new(),
1901+
addresses: HashMap::new(),
19031902
txt_properties: TxtProperties::new(),
19041903
};
19051904

@@ -1942,9 +1941,11 @@ impl Zeroconf {
19421941
if dns_a.expires_soon(now) {
19431942
trace!("Addr expired or expires soon: {}", dns_a.address());
19441943
} else {
1945-
let intf_addr =
1946-
ScopedAddr::new(dns_a.address(), dns_a.interface_id().clone());
1947-
resolved_service.addresses.insert(intf_addr);
1944+
resolved_service
1945+
.addresses
1946+
.entry(dns_a.address())
1947+
.or_default()
1948+
.push(dns_a.interface_id().clone());
19481949
}
19491950
}
19501951
}

src/service_info.rs

Lines changed: 7 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use std::{
1212
collections::{HashMap, HashSet},
1313
convert::TryInto,
1414
fmt,
15-
hash::Hash,
1615
net::{IpAddr, Ipv4Addr},
1716
str::FromStr,
1817
};
@@ -50,68 +49,6 @@ pub struct ServiceInfo {
5049
requires_probe: bool,
5150
}
5251

53-
/// An IP address that is scoped to a specific interface.
54-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
55-
pub struct ScopedAddr {
56-
addr: IpAddr,
57-
58-
/// The interface that this address is scoped to.
59-
scope: InterfaceId,
60-
}
61-
62-
impl ScopedAddr {
63-
pub(crate) fn new(addr: IpAddr, interface: InterfaceId) -> Self {
64-
Self {
65-
addr,
66-
scope: interface,
67-
}
68-
}
69-
70-
pub fn is_ipv4(&self) -> bool {
71-
self.addr.is_ipv4()
72-
}
73-
74-
pub fn is_ipv6(&self) -> bool {
75-
self.addr.is_ipv6()
76-
}
77-
78-
pub fn is_loopback(&self) -> bool {
79-
self.addr.is_loopback()
80-
}
81-
82-
pub fn ip(&self) -> &IpAddr {
83-
&self.addr
84-
}
85-
86-
/// Returns the interface which this address is scoped to.
87-
///
88-
/// I.e. via which interface this address is detected.
89-
pub fn scope(&self) -> &InterfaceId {
90-
&self.scope
91-
}
92-
}
93-
94-
impl From<IpAddr> for ScopedAddr {
95-
fn from(addr: IpAddr) -> Self {
96-
Self {
97-
addr,
98-
scope: InterfaceId::default(), // Default interface ID, can be set later.
99-
}
100-
}
101-
}
102-
103-
impl From<ScopedAddr> for IpAddr {
104-
fn from(intf_addr: ScopedAddr) -> Self {
105-
intf_addr.addr
106-
}
107-
}
108-
109-
impl fmt::Display for ScopedAddr {
110-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111-
write!(f, "{} ({})", self.addr, self.scope)
112-
}
113-
}
114-
11552
#[derive(Debug, Clone, PartialEq, Eq)]
11653
pub(crate) enum ServiceStatus {
11754
Probing,
@@ -435,11 +372,11 @@ impl ServiceInfo {
435372

436373
/// Consumes self and returns a resolved service, i.e. a lite version of `ServiceInfo`.
437374
pub fn as_resolved_service(self) -> ResolvedService {
438-
let addresses = self
375+
let addresses: HashMap<IpAddr, Vec<InterfaceId>> = self
439376
.addresses
440377
.into_iter()
441-
.map(|a| a.into())
442-
.collect::<HashSet<ScopedAddr>>();
378+
.map(|a| (a, Vec::new()))
379+
.collect();
443380
ResolvedService {
444381
ty_domain: self.ty_domain,
445382
sub_ty_domain: self.sub_domain,
@@ -1239,8 +1176,10 @@ pub struct ResolvedService {
12391176
/// Port of the service. I.e. TCP or UDP port.
12401177
pub port: u16,
12411178

1242-
/// Addresses of the service. IPv4 or IPv6 addresses.
1243-
pub addresses: HashSet<ScopedAddr>,
1179+
/// Addresses of the service.
1180+
/// Each address maps to the list of interfaces on which the address is found.
1181+
/// The interface list is particularly useful for link-local IPv6 addresses.
1182+
pub addresses: HashMap<IpAddr, Vec<InterfaceId>>,
12441183

12451184
/// Properties of the service, decoded from TXT record.
12461185
pub txt_properties: TxtProperties,

tests/mdns_test.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2635,10 +2635,10 @@ fn test_use_service_detailed_v6() {
26352635
resolved.addresses.len() > 0,
26362636
"Should have at least one address"
26372637
);
2638-
let first_addr = resolved.addresses.into_iter().next().unwrap();
2638+
let (first_addr, interfaces) = resolved.addresses.into_iter().next().unwrap();
26392639
assert!(first_addr.is_ipv6(), "Address should be IPv6");
2640-
let interface_id = first_addr.scope();
2641-
println!("Resolved address: {:?}", first_addr.ip());
2640+
let interface_id = interfaces.get(0).unwrap();
2641+
println!("Resolved address: {:?}", first_addr);
26422642
println!(
26432643
"Interface ID of the first addr: {} index: {}",
26442644
interface_id.name(),

0 commit comments

Comments
 (0)