Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

register service: apply interface selection for auto IP addr #262

Merged
merged 2 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion examples/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
//!
//! Options:
//! "--unregister": automatically unregister after 2 seconds.
//! "--disable-ipv6": not to use IPv6 interfaces.

use mdns_sd::{DaemonEvent, ServiceDaemon, ServiceInfo};
use mdns_sd::{DaemonEvent, IfKind, ServiceDaemon, ServiceInfo};
use std::{env, thread, time::Duration};

fn main() {
Expand All @@ -20,14 +21,23 @@ fn main() {
// Simple command line options.
let args: Vec<String> = env::args().collect();
let mut should_unreg = false;
let mut disable_ipv6 = false;

for arg in args.iter() {
if arg.as_str() == "--unregister" {
should_unreg = true
} else if arg.as_str() == "--disable-ipv6" {
disable_ipv6 = true
}
}

// Create a new mDNS daemon.
let mdns = ServiceDaemon::new().expect("Could not create service daemon");

if disable_ipv6 {
mdns.disable_interface(IfKind::IPv6).unwrap();
}

let service_type = match args.get(1) {
Some(arg) => format!("{}.local.", arg),
None => {
Expand Down
47 changes: 37 additions & 10 deletions src/service_daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,16 +285,10 @@ impl ServiceDaemon {
///
/// To re-announce a service with an updated `service_info`, just call
/// this `register` function again. No need to call `unregister` first.
pub fn register(&self, mut service_info: ServiceInfo) -> Result<()> {
pub fn register(&self, service_info: ServiceInfo) -> Result<()> {
check_service_name(service_info.get_fullname())?;
check_hostname(service_info.get_hostname())?;

if service_info.is_addr_auto() {
for iface in my_ip_interfaces() {
service_info.insert_ipaddr(iface.ip());
}
}

self.send_cmd(Command::Register(service_info))
}

Expand Down Expand Up @@ -624,7 +618,6 @@ impl ServiceDaemon {
}

Command::Register(service_info) => {
debug!("register service {:?}", &service_info);
zc.register_service(service_info);
zc.increase_counter(Counter::Register, 1);
}
Expand Down Expand Up @@ -1081,6 +1074,31 @@ impl Zeroconf {
self.timers.pop().map(|Reverse(v)| v)
}

/// Apply all selections to `interfaces` and return the selected addresses.
fn selected_addrs(&self, interfaces: Vec<Interface>) -> HashSet<IpAddr> {
let intf_count = interfaces.len();
let mut intf_selections = vec![true; intf_count];

// apply if_selections
for selection in self.if_selections.iter() {
// Mark the interfaces for this selection.
for i in 0..intf_count {
if selection.if_kind.matches(&interfaces[i]) {
intf_selections[i] = selection.selected;
}
}
}

let mut selected_addrs = HashSet::new();
for i in 0..intf_count {
if intf_selections[i] {
selected_addrs.insert(interfaces[i].addr.ip());
}
}

selected_addrs
}

/// Apply all selections to `interfaces`.
///
/// For any interface, add it if selected but not bound yet,
Expand Down Expand Up @@ -1192,14 +1210,23 @@ impl Zeroconf {
/// Section, all of its newly registered resource records
///
/// Zeroconf will then respond to requests for information about this service.
fn register_service(&mut self, info: ServiceInfo) {
fn register_service(&mut self, mut info: ServiceInfo) {
// Check the service name length.
if let Err(e) = check_service_name_length(info.get_type(), self.service_name_len_max) {
error!("check_service_name_length: {}", &e);
self.notify_monitors(DaemonEvent::Error(e));
return;
}

if info.is_addr_auto() {
let selected_addrs = self.selected_addrs(my_ip_interfaces());
for addr in selected_addrs {
info.insert_ipaddr(addr);
}
}

debug!("register service {:?}", &info);

let outgoing_addrs = self.send_unsolicited_response(&info);
if !outgoing_addrs.is_empty() {
self.notify_monitors(DaemonEvent::Announce(
Expand Down Expand Up @@ -2483,7 +2510,7 @@ fn check_service_name(fullname: &str) -> Result<()> {
/// Validate a hostname.
fn check_hostname(hostname: &str) -> Result<()> {
if !hostname.ends_with(".local.") {
return Err(e_fmt!("Hostname must end with '.local.'"));
return Err(e_fmt!("Hostname must end with '.local.': {hostname}"));
}

if hostname == ".local." {
Expand Down