Add an option to specify IPs that zeroconf will bind to (#1071)

* added an option to specify ip addresses to which mDNS should bind (ignored by `DNS-SD`)
* changed command line option to `zeroconf-interface` to be consistent with `zeroconf-port`
use builder pattern to DRY up the code
used macro to print warning message
* fixing register error
* renamed `bind_ip` variables to match the option to `zeroconf_ip`, to be more consistent
* Changed user help
Modified comments
Added block for condition to clean the code
Added new modification to the change log

Co-authored-by: setime <timeframe1@gmx.de>
This commit is contained in:
setime 2022-11-25 09:57:14 +01:00 committed by GitHub
parent b0db6502b5
commit bf7cbbaadd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 14 deletions

View file

@ -68,6 +68,7 @@ https://github.com/librespot-org/librespot
- [all] Check that array indexes are within bounds (panic safety) - [all] Check that array indexes are within bounds (panic safety)
- [all] Wrap errors in librespot `Error` type (breaking) - [all] Wrap errors in librespot `Error` type (breaking)
- [connect] Add option on which zeroconf will bind. Defaults to all interfaces. Ignored by DNS-SD.
- [connect] Add session events - [connect] Add session events
- [connect] Add `repeat`, `set_position_ms` and `set_volume` to `spirc.rs` - [connect] Add `repeat`, `set_position_ms` and `set_volume` to `spirc.rs`
- [contrib] Add `event_handler_example.py` - [contrib] Add `event_handler_example.py`

View file

@ -47,6 +47,7 @@ pub struct Discovery {
pub struct Builder { pub struct Builder {
server_config: server::Config, server_config: server::Config,
port: u16, port: u16,
zeroconf_ip: Vec<std::net::IpAddr>,
} }
/// Errors that can occur while setting up a [`Discovery`] instance. /// Errors that can occur while setting up a [`Discovery`] instance.
@ -87,6 +88,7 @@ impl Builder {
client_id: client_id.into(), client_id: client_id.into(),
}, },
port: 0, port: 0,
zeroconf_ip: vec![],
} }
} }
@ -102,6 +104,12 @@ impl Builder {
self self
} }
/// Set the ip addresses on which it should listen to incoming connections. The default is all interfaces.
pub fn zeroconf_ip(mut self, zeroconf_ip: Vec<std::net::IpAddr>) -> Self {
self.zeroconf_ip = zeroconf_ip;
self
}
/// Sets the port on which it should listen to incoming connections. /// Sets the port on which it should listen to incoming connections.
/// The default value `0` means any port. /// The default value `0` means any port.
pub fn port(mut self, port: u16) -> Self { pub fn port(mut self, port: u16) -> Self {
@ -117,9 +125,12 @@ impl Builder {
let mut port = self.port; let mut port = self.port;
let name = self.server_config.name.clone().into_owned(); let name = self.server_config.name.clone().into_owned();
let server = DiscoveryServer::new(self.server_config, &mut port)??; let server = DiscoveryServer::new(self.server_config, &mut port)??;
let _zeroconf_ip = self.zeroconf_ip;
let svc;
#[cfg(feature = "with-dns-sd")] #[cfg(feature = "with-dns-sd")]
let svc = dns_sd::DNSService::register( {
svc = dns_sd::DNSService::register(
Some(name.as_ref()), Some(name.as_ref()),
"_spotify-connect._tcp", "_spotify-connect._tcp",
None, None,
@ -127,14 +138,25 @@ impl Builder {
port, port,
&["VERSION=1.0", "CPath=/"], &["VERSION=1.0", "CPath=/"],
)?; )?;
}
#[cfg(not(feature = "with-dns-sd"))] #[cfg(not(feature = "with-dns-sd"))]
let svc = libmdns::Responder::spawn(&tokio::runtime::Handle::current())?.register( {
let _svc = if !_zeroconf_ip.is_empty() {
libmdns::Responder::spawn_with_ip_list(
&tokio::runtime::Handle::current(),
_zeroconf_ip,
)?
} else {
libmdns::Responder::spawn(&tokio::runtime::Handle::current())?
};
svc = _svc.register(
"_spotify-connect._tcp".to_owned(), "_spotify-connect._tcp".to_owned(),
name, name,
port, port,
&["VERSION=1.0", "CPath=/"], &["VERSION=1.0", "CPath=/"],
); );
}
Ok(Discovery { server, _svc: svc }) Ok(Discovery { server, _svc: svc })
} }

View file

@ -185,6 +185,7 @@ struct Setup {
zeroconf_port: u16, zeroconf_port: u16,
player_event_program: Option<String>, player_event_program: Option<String>,
emit_sink_events: bool, emit_sink_events: bool,
zeroconf_ip: Vec<std::net::IpAddr>,
} }
fn get_setup() -> Setup { fn get_setup() -> Setup {
@ -240,6 +241,7 @@ fn get_setup() -> Setup {
const VOLUME_CTRL: &str = "volume-ctrl"; const VOLUME_CTRL: &str = "volume-ctrl";
const VOLUME_RANGE: &str = "volume-range"; const VOLUME_RANGE: &str = "volume-range";
const ZEROCONF_PORT: &str = "zeroconf-port"; const ZEROCONF_PORT: &str = "zeroconf-port";
const ZEROCONF_INTERFACE: &str = "zeroconf-interface";
// Mostly arbitrary. // Mostly arbitrary.
const AP_PORT_SHORT: &str = "a"; const AP_PORT_SHORT: &str = "a";
@ -258,6 +260,7 @@ fn get_setup() -> Setup {
const DISABLE_GAPLESS_SHORT: &str = "g"; const DISABLE_GAPLESS_SHORT: &str = "g";
const DISABLE_CREDENTIAL_CACHE_SHORT: &str = "H"; const DISABLE_CREDENTIAL_CACHE_SHORT: &str = "H";
const HELP_SHORT: &str = "h"; const HELP_SHORT: &str = "h";
const ZEROCONF_INTERFACE_SHORT: &str = "i";
const CACHE_SIZE_LIMIT_SHORT: &str = "M"; const CACHE_SIZE_LIMIT_SHORT: &str = "M";
const MIXER_TYPE_SHORT: &str = "m"; const MIXER_TYPE_SHORT: &str = "m";
const ENABLE_VOLUME_NORMALISATION_SHORT: &str = "N"; const ENABLE_VOLUME_NORMALISATION_SHORT: &str = "N";
@ -570,6 +573,12 @@ fn get_setup() -> Setup {
AUTOPLAY, AUTOPLAY,
"Explicitly set autoplay {on|off}. Defaults to following the client setting.", "Explicitly set autoplay {on|off}. Defaults to following the client setting.",
"OVERRIDE", "OVERRIDE",
)
.optopt(
ZEROCONF_INTERFACE_SHORT,
ZEROCONF_INTERFACE,
"Comma-separated interface IP addresses on which zeroconf will bind. Defaults to all interfaces. Ignored by DNS-SD.",
"IP"
); );
#[cfg(feature = "passthrough-decoder")] #[cfg(feature = "passthrough-decoder")]
@ -1168,6 +1177,31 @@ fn get_setup() -> Setup {
None => SessionConfig::default().autoplay, None => SessionConfig::default().autoplay,
}; };
let zeroconf_ip: Vec<std::net::IpAddr> = if opt_present(ZEROCONF_INTERFACE) {
if let Some(zeroconf_ip) = opt_str(ZEROCONF_INTERFACE) {
zeroconf_ip
.split(',')
.map(|s| {
s.trim().parse::<std::net::IpAddr>().unwrap_or_else(|_| {
invalid_error_msg(
ZEROCONF_INTERFACE,
ZEROCONF_INTERFACE_SHORT,
s,
"IPv4 and IPv6 addresses",
"",
);
exit(1);
})
})
.collect()
} else {
warn!("Unable to use zeroconf-interface option, default to all interfaces.");
vec![]
}
} else {
vec![]
};
let connect_config = { let connect_config = {
let connect_default_config = ConnectConfig::default(); let connect_default_config = ConnectConfig::default();
@ -1608,6 +1642,7 @@ fn get_setup() -> Setup {
zeroconf_port, zeroconf_port,
player_event_program, player_event_program,
emit_sink_events, emit_sink_events,
zeroconf_ip,
} }
} }
@ -1640,6 +1675,7 @@ async fn main() {
.name(setup.connect_config.name.clone()) .name(setup.connect_config.name.clone())
.device_type(setup.connect_config.device_type) .device_type(setup.connect_config.device_type)
.port(setup.zeroconf_port) .port(setup.zeroconf_port)
.zeroconf_ip(setup.zeroconf_ip)
.launch() .launch()
{ {
Ok(d) => discovery = Some(d), Ok(d) => discovery = Some(d),