Cleanup a bit the mDns story
This commit is contained in:
parent
a7ca17fabc
commit
52185ec9a4
9 changed files with 429 additions and 284 deletions
|
@ -48,7 +48,8 @@ fn main() {
|
|||
device_name: "OnOff Light",
|
||||
};
|
||||
|
||||
let mut mdns = matter::sys::LinuxMdns::new().unwrap();
|
||||
//let mut mdns = matter::mdns::bonjour::BonjourMdns::new().unwrap();
|
||||
let mut mdns = matter::mdns::libmdns::LibMdns::new().unwrap();
|
||||
|
||||
let matter = Matter::new_default(&dev_info, &mut mdns);
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ path = "src/lib.rs"
|
|||
|
||||
[features]
|
||||
default = ["std", "crypto_mbedtls", "nightly"]
|
||||
std = ["alloc", "env_logger", "chrono", "rand", "qrcode", "smol"]
|
||||
std = ["alloc", "env_logger", "chrono", "rand", "qrcode", "libmdns", "simple-mdns", "simple-dns", "smol"]
|
||||
alloc = []
|
||||
nightly = []
|
||||
crypto_openssl = ["openssl", "foreign-types", "hmac", "sha2"]
|
||||
|
@ -43,8 +43,12 @@ colored = "2.0.0" # TODO: Requires STD
|
|||
env_logger = { version = "0.10.0", default-features = false, optional = true }
|
||||
chrono = { version = "0.4.23", optional = true, default-features = false, features = ["clock", "std"] }
|
||||
rand = { version = "0.8.5", optional = true }
|
||||
smol = { version = "1.3.0", optional = true}
|
||||
qrcode = { version = "0.12", default-features = false, optional = true } # Print QR code
|
||||
libmdns = { version = "0.7", optional = true }
|
||||
simple-mdns = { version = "0.4", features = ["sync"], optional = true }
|
||||
simple-dns = { version = "0.5", optional = true }
|
||||
astro-dnssd = { version = "0.3", optional = true }
|
||||
smol = { version = "1.3.0", optional = true}
|
||||
|
||||
# crypto
|
||||
openssl = { git = "https://github.com/sfackler/rust-openssl", optional = true }
|
||||
|
@ -66,13 +70,6 @@ x509-cert = { version = "0.2.0", default-features = false, features = ["pem", "s
|
|||
# to compute the check digit
|
||||
verhoeff = "1"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
astro-dnssd = "0.3"
|
||||
|
||||
# MDNS support
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
libmdns = { version = "0.7.4" }
|
||||
|
||||
[[example]]
|
||||
name = "onoff_light"
|
||||
path = "../examples/onoff_light/src/main.rs"
|
||||
|
|
|
@ -25,6 +25,7 @@ pub trait Mdns {
|
|||
name: &str,
|
||||
service_type: &str,
|
||||
port: u16,
|
||||
service_subtypes: &[&str],
|
||||
txt_kvs: &[(&str, &str)],
|
||||
) -> Result<(), Error>;
|
||||
|
||||
|
@ -40,9 +41,10 @@ where
|
|||
name: &str,
|
||||
service_type: &str,
|
||||
port: u16,
|
||||
service_subtypes: &[&str],
|
||||
txt_kvs: &[(&str, &str)],
|
||||
) -> Result<(), Error> {
|
||||
(**self).add(name, service_type, port, txt_kvs)
|
||||
(**self).add(name, service_type, port, service_subtypes, txt_kvs)
|
||||
}
|
||||
|
||||
fn remove(&mut self, name: &str, service_type: &str, port: u16) -> Result<(), Error> {
|
||||
|
@ -58,6 +60,7 @@ impl Mdns for DummyMdns {
|
|||
_name: &str,
|
||||
_service_type: &str,
|
||||
_port: u16,
|
||||
_service_subtypes: &[&str],
|
||||
_txt_kvs: &[(&str, &str)],
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
|
@ -112,11 +115,12 @@ impl<'a> MdnsMgr<'a> {
|
|||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub fn publish_service(&mut self, name: &str, mode: ServiceMode) -> Result<(), Error> {
|
||||
match mode {
|
||||
ServiceMode::Commissioned => self.mdns.add(name, "_matter._tcp", self.matter_port, &[]),
|
||||
ServiceMode::Commissioned => {
|
||||
self.mdns
|
||||
.add(name, "_matter._tcp", self.matter_port, &[], &[])
|
||||
}
|
||||
ServiceMode::Commissionable(discriminator) => {
|
||||
let discriminator_str = Self::get_discriminator_str(discriminator);
|
||||
|
||||
let serv_type = self.get_service_type(discriminator);
|
||||
let vp = self.get_vp();
|
||||
|
||||
let txt_kvs = [
|
||||
|
@ -129,7 +133,17 @@ impl<'a> MdnsMgr<'a> {
|
|||
("PH", "33"), /* Pairing Hint */
|
||||
("PI", ""), /* Pairing Instruction */
|
||||
];
|
||||
self.mdns.add(name, &serv_type, self.matter_port, &txt_kvs)
|
||||
|
||||
self.mdns.add(
|
||||
name,
|
||||
"_matter._udp",
|
||||
self.matter_port,
|
||||
&[
|
||||
&self.get_long_service_subtype(discriminator),
|
||||
&self.get_short_service_type(discriminator),
|
||||
],
|
||||
&txt_kvs,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,28 +151,32 @@ impl<'a> MdnsMgr<'a> {
|
|||
pub fn unpublish_service(&mut self, name: &str, mode: ServiceMode) -> Result<(), Error> {
|
||||
match mode {
|
||||
ServiceMode::Commissioned => self.mdns.remove(name, "_matter._tcp", self.matter_port),
|
||||
ServiceMode::Commissionable(discriminator) => {
|
||||
let serv_type = self.get_service_type(discriminator);
|
||||
|
||||
self.mdns.remove(name, &serv_type, self.matter_port)
|
||||
ServiceMode::Commissionable(_) => {
|
||||
self.mdns.remove(name, "_matter._udp", self.matter_port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_service_type(&self, discriminator: u16) -> heapless::String<32> {
|
||||
let short = Self::compute_short_discriminator(discriminator);
|
||||
fn get_long_service_subtype(&self, discriminator: u16) -> heapless::String<32> {
|
||||
let mut serv_type = heapless::String::new();
|
||||
|
||||
write!(
|
||||
&mut serv_type,
|
||||
"_matterc._udp,_S{},_L{}",
|
||||
short, discriminator
|
||||
)
|
||||
.unwrap();
|
||||
write!(&mut serv_type, "_L{}", discriminator).unwrap();
|
||||
|
||||
serv_type
|
||||
}
|
||||
|
||||
fn get_short_service_type(&self, discriminator: u16) -> heapless::String<32> {
|
||||
let short = Self::compute_short_discriminator(discriminator);
|
||||
|
||||
let mut serv_type = heapless::String::new();
|
||||
write!(&mut serv_type, "_S{}", short).unwrap();
|
||||
|
||||
serv_type
|
||||
}
|
||||
|
||||
fn get_discriminator_str(discriminator: u16) -> heapless::String<5> {
|
||||
discriminator.into()
|
||||
}
|
||||
|
||||
fn get_vp(&self) -> heapless::String<11> {
|
||||
let mut vp = heapless::String::new();
|
||||
|
||||
|
@ -167,10 +185,6 @@ impl<'a> MdnsMgr<'a> {
|
|||
vp
|
||||
}
|
||||
|
||||
fn get_discriminator_str(discriminator: u16) -> heapless::String<5> {
|
||||
discriminator.into()
|
||||
}
|
||||
|
||||
fn compute_short_discriminator(discriminator: u16) -> u16 {
|
||||
const SHORT_DISCRIMINATOR_MASK: u16 = 0xF00;
|
||||
const SHORT_DISCRIMINATOR_SHIFT: u16 = 8;
|
||||
|
@ -179,6 +193,353 @@ impl<'a> MdnsMgr<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", feature = "bonjour"))]
|
||||
pub mod bonjour {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::Mdns;
|
||||
use crate::error::Error;
|
||||
use astro_dnssd::{DNSServiceBuilder, RegisteredDnsService};
|
||||
use log::info;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct ServiceId {
|
||||
name: String,
|
||||
service_type: String,
|
||||
port: u16,
|
||||
}
|
||||
|
||||
pub struct BonjourMdns {
|
||||
services: HashMap<RegisteredDnsService, RegisteredDnsService>,
|
||||
}
|
||||
|
||||
impl BonjourMdns {
|
||||
pub fn new() -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
services: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add(
|
||||
&mut self,
|
||||
name: &str,
|
||||
service_type: &str,
|
||||
port: u16,
|
||||
service_subtypes: &[&str],
|
||||
txt_kvs: &[(&str, &str)],
|
||||
) -> Result<(), Error> {
|
||||
info!(
|
||||
"Registering mDNS service {}/{}/{}",
|
||||
name, service_type, port
|
||||
);
|
||||
|
||||
let _ = self.remove(name, service_type, port);
|
||||
|
||||
let composite_service_type = if !service_subtypes.is_empty() {
|
||||
format!("{}{}", service_type, service_subtypes.join(","))
|
||||
} else {
|
||||
service_type
|
||||
};
|
||||
|
||||
let mut builder = DNSServiceBuilder::new(composite_service_type, port).with_name(name);
|
||||
|
||||
for kvs in txt_kvs {
|
||||
info!("mDNS TXT key {} val {}", kvs.0, kvs.1);
|
||||
builder = builder.with_key_value(kvs.0.to_string(), kvs.1.to_string());
|
||||
}
|
||||
|
||||
let service = builder.register().map_err(|_| Error::MdnsError)?;
|
||||
|
||||
self.services.insert(
|
||||
ServiceId {
|
||||
name: name.into(),
|
||||
service_type: service_type.into(),
|
||||
port,
|
||||
},
|
||||
service,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, name: &str, service_type: &str, port: u16) -> Result<(), Error> {
|
||||
let id = ServiceId {
|
||||
name: name.into(),
|
||||
service_type: service_type.into(),
|
||||
port,
|
||||
};
|
||||
|
||||
if self.services.remove(&id).is_some() {
|
||||
info!(
|
||||
"Deregistering mDNS service {}/{}/{}",
|
||||
name, service_type, port
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Mdns for BonjourMdns {
|
||||
fn add(
|
||||
&mut self,
|
||||
name: &str,
|
||||
service_type: &str,
|
||||
port: u16,
|
||||
service_subtypes: &[&str],
|
||||
txt_kvs: &[(&str, &str)],
|
||||
) -> Result<(), Error> {
|
||||
BonjourMdns::add(self, name, service_type, port, service_subtypes, txt_kvs)
|
||||
}
|
||||
|
||||
fn remove(&mut self, name: &str, service_type: &str, port: u16) -> Result<(), Error> {
|
||||
BonjourMdns::remove(self, name, service_type, port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub mod libmdns {
|
||||
use super::Mdns;
|
||||
use crate::error::Error;
|
||||
use libmdns::{Responder, Service};
|
||||
use log::info;
|
||||
use std::collections::HashMap;
|
||||
use std::vec::Vec;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct ServiceId {
|
||||
name: String,
|
||||
service_type: String,
|
||||
port: u16,
|
||||
}
|
||||
|
||||
pub struct LibMdns {
|
||||
responder: Responder,
|
||||
services: HashMap<ServiceId, Service>,
|
||||
}
|
||||
|
||||
impl LibMdns {
|
||||
pub fn new() -> Result<Self, Error> {
|
||||
let responder = Responder::new()?;
|
||||
|
||||
Ok(Self {
|
||||
responder,
|
||||
services: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add(
|
||||
&mut self,
|
||||
name: &str,
|
||||
service_type: &str,
|
||||
port: u16,
|
||||
txt_kvs: &[(&str, &str)],
|
||||
) -> Result<(), Error> {
|
||||
info!(
|
||||
"Registering mDNS service {}/{}/{}",
|
||||
name, service_type, port
|
||||
);
|
||||
|
||||
let _ = self.remove(name, service_type, port);
|
||||
|
||||
let mut properties = Vec::new();
|
||||
for kvs in txt_kvs {
|
||||
info!("mDNS TXT key {} val {}", kvs.0, kvs.1);
|
||||
properties.push(format!("{}={}", kvs.0, kvs.1));
|
||||
}
|
||||
let properties: Vec<&str> = properties.iter().map(|entry| entry.as_str()).collect();
|
||||
|
||||
let service = self.responder.register(
|
||||
service_type.to_owned(),
|
||||
name.to_owned(),
|
||||
port,
|
||||
&properties,
|
||||
);
|
||||
|
||||
self.services.insert(
|
||||
ServiceId {
|
||||
name: name.into(),
|
||||
service_type: service_type.into(),
|
||||
port,
|
||||
},
|
||||
service,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, name: &str, service_type: &str, port: u16) -> Result<(), Error> {
|
||||
let id = ServiceId {
|
||||
name: name.into(),
|
||||
service_type: service_type.into(),
|
||||
port,
|
||||
};
|
||||
|
||||
if self.services.remove(&id).is_some() {
|
||||
info!(
|
||||
"Deregistering mDNS service {}/{}/{}",
|
||||
name, service_type, port
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Mdns for LibMdns {
|
||||
fn add(
|
||||
&mut self,
|
||||
name: &str,
|
||||
service_type: &str,
|
||||
port: u16,
|
||||
_service_subtypes: &[&str],
|
||||
txt_kvs: &[(&str, &str)],
|
||||
) -> Result<(), Error> {
|
||||
LibMdns::add(self, name, service_type, port, txt_kvs)
|
||||
}
|
||||
|
||||
fn remove(&mut self, name: &str, service_type: &str, port: u16) -> Result<(), Error> {
|
||||
LibMdns::remove(self, name, service_type, port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(feature = "std")]
|
||||
// pub mod simplemdns {
|
||||
// use std::net::Ipv4Addr;
|
||||
|
||||
// use crate::error::Error;
|
||||
// use super::Mdns;
|
||||
// use log::info;
|
||||
// use simple_dns::{
|
||||
// rdata::{RData, A, SRV, TXT, PTR},
|
||||
// CharacterString, Name, ResourceRecord, CLASS,
|
||||
// };
|
||||
// use simple_mdns::sync_discovery::SimpleMdnsResponder;
|
||||
|
||||
// #[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
// pub struct ServiceId {
|
||||
// name: String,
|
||||
// service_type: String,
|
||||
// port: u16,
|
||||
// }
|
||||
|
||||
// pub struct SimpleMdns {
|
||||
// responder: SimpleMdnsResponder,
|
||||
// }
|
||||
|
||||
// impl SimpleMdns {
|
||||
// pub fn new() -> Result<Self, Error> {
|
||||
// Ok(Self {
|
||||
// responder: Default::default(),
|
||||
// })
|
||||
// }
|
||||
|
||||
// pub fn add(
|
||||
// &mut self,
|
||||
// name: &str,
|
||||
// service_type: &str,
|
||||
// port: u16,
|
||||
// txt_kvs: &[(&str, &str)],
|
||||
// ) -> Result<(), Error> {
|
||||
// info!(
|
||||
// "Registering mDNS service {}/{}/{}",
|
||||
// name, service_type, port
|
||||
// );
|
||||
|
||||
// let _ = self.remove(name, service_type, port);
|
||||
|
||||
// let mut txt = TXT::new();
|
||||
// for kvs in txt_kvs {
|
||||
// info!("mDNS TXT key {} val {}", kvs.0, kvs.1);
|
||||
|
||||
// let string = format!("{}={}", kvs.0, kvs.1);
|
||||
// txt.add_char_string(
|
||||
// CharacterString::new(string.as_bytes())
|
||||
// .unwrap()
|
||||
// .into_owned(),
|
||||
// );
|
||||
// }
|
||||
|
||||
// let name = Name::new_unchecked(name).into_owned();
|
||||
// let service_type = Name::new_unchecked(service_type).into_owned();
|
||||
|
||||
// self.responder.add_resource(ResourceRecord::new(
|
||||
// name.clone(),
|
||||
// CLASS::IN,
|
||||
// 10,
|
||||
// RData::A(A {
|
||||
// address: Ipv4Addr::new(192, 168, 10, 189).into(),
|
||||
// }),
|
||||
// ));
|
||||
|
||||
// self.responder.add_resource(ResourceRecord::new(
|
||||
// name.clone(),
|
||||
// CLASS::IN,
|
||||
// 10,
|
||||
// RData::SRV(SRV {
|
||||
// port: port,
|
||||
// priority: 0,
|
||||
// weight: 0,
|
||||
// target: service_type.clone(),
|
||||
// }),
|
||||
// ));
|
||||
|
||||
// self.responder.add_resource(ResourceRecord::new(
|
||||
// srv_name.clone(),
|
||||
// CLASS::IN,
|
||||
// 10,
|
||||
// RData::PTR(PTR(srv_name.clone()),
|
||||
// )));
|
||||
|
||||
// self.responder.add_resource(ResourceRecord::new(
|
||||
// srv_name,
|
||||
// CLASS::IN,
|
||||
// 10,
|
||||
// RData::TXT(txt),
|
||||
// ));
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// pub fn remove(&mut self, name: &str, service_type: &str, port: u16) -> Result<(), Error> {
|
||||
// // TODO
|
||||
// // let id = ServiceId {
|
||||
// // name: name.into(),
|
||||
// // service_type: service_type.into(),
|
||||
// // port,
|
||||
// // };
|
||||
|
||||
// // if self.responder.remove_resource_record(resource).remove(&id).is_some() {
|
||||
// // info!(
|
||||
// // "Deregistering mDNS service {}/{}/{}",
|
||||
// // name, service_type, port
|
||||
// // );
|
||||
// // }
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl Mdns for SimpleMdns {
|
||||
// fn add(
|
||||
// &mut self,
|
||||
// name: &str,
|
||||
// service_type: &str,
|
||||
// port: u16,
|
||||
// _service_subtypes: &[&str],
|
||||
// txt_kvs: &[(&str, &str)],
|
||||
// ) -> Result<(), Error> {
|
||||
// SimpleMdns::add(self, name, service_type, port, txt_kvs)
|
||||
// }
|
||||
|
||||
// fn remove(&mut self, name: &str, service_type: &str, port: u16) -> Result<(), Error> {
|
||||
// SimpleMdns::remove(self, name, service_type, port)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -315,10 +315,7 @@ fn estimate_struct_overhead(first_field_size: usize) -> usize {
|
|||
}
|
||||
|
||||
pub(super) fn print_qr_code(qr_data: &str) {
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
info!("\n QR CODE DATA: {}", qr_data);
|
||||
}
|
||||
info!("QR Code: {}", qr_data);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
use crate::{
|
||||
crypto::{self, HmacSha256},
|
||||
sys,
|
||||
utils::rand::Rand,
|
||||
};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
@ -31,7 +30,7 @@ use crate::{
|
|||
|
||||
use super::{common::SCStatusCodes, crypto::CryptoSpake2};
|
||||
|
||||
// This file handle Spake2+ specific instructions. In itself, this file is
|
||||
// This file handles Spake2+ specific instructions. In itself, this file is
|
||||
// independent from the BigNum and EC operations that are typically required
|
||||
// Spake2+. We use the CryptoSpake2 trait object that allows us to abstract
|
||||
// out the specific implementations.
|
||||
|
@ -39,6 +38,8 @@ use super::{common::SCStatusCodes, crypto::CryptoSpake2};
|
|||
// In the case of the verifier, we don't actually release the Ke until we
|
||||
// validate that the cA is confirmed.
|
||||
|
||||
pub const SPAKE2_ITERATION_COUNT: u32 = 2000;
|
||||
|
||||
#[derive(PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Spake2VerifierState {
|
||||
// Initialised - w0, L are set
|
||||
|
@ -104,7 +105,7 @@ impl VerifierData {
|
|||
pub fn new_with_pw(pw: u32, rand: Rand) -> Self {
|
||||
let mut s = Self {
|
||||
salt: [0; MAX_SALT_SIZE_BYTES],
|
||||
count: sys::SPAKE2_ITERATION_COUNT,
|
||||
count: SPAKE2_ITERATION_COUNT,
|
||||
data: VerifierOption::Password(pw),
|
||||
};
|
||||
rand(&mut s.salt);
|
||||
|
|
|
@ -15,18 +15,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#[cfg(all(feature = "std", target_os = "macos"))]
|
||||
mod sys_macos;
|
||||
#[cfg(all(feature = "std", target_os = "macos"))]
|
||||
pub use self::sys_macos::*;
|
||||
|
||||
#[cfg(all(feature = "std", target_os = "linux"))]
|
||||
mod sys_linux;
|
||||
#[cfg(all(feature = "std", target_os = "linux"))]
|
||||
pub use self::sys_linux::*;
|
||||
|
||||
pub const SPAKE2_ITERATION_COUNT: u32 = 2000;
|
||||
|
||||
// The Packet Pool that is allocated from. POSIX systems can use
|
||||
// higher values unlike embedded systems
|
||||
pub const MAX_PACKET_POOL_SIZE: usize = 25;
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2020-2022 Project CHIP Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::mdns::Mdns;
|
||||
use libmdns::{Responder, Service};
|
||||
use log::info;
|
||||
use std::collections::HashMap;
|
||||
use std::vec::Vec;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct ServiceId {
|
||||
name: String,
|
||||
service_type: String,
|
||||
port: u16,
|
||||
}
|
||||
|
||||
pub struct LinuxMdns {
|
||||
responder: Responder,
|
||||
services: HashMap<ServiceId, Service>,
|
||||
}
|
||||
|
||||
impl LinuxMdns {
|
||||
pub fn new() -> Result<Self, Error> {
|
||||
let responder = Responder::new()?;
|
||||
|
||||
Ok(Self {
|
||||
responder,
|
||||
services: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add(
|
||||
&mut self,
|
||||
name: &str,
|
||||
service_type: &str,
|
||||
port: u16,
|
||||
txt_kvs: &[(&str, &str)],
|
||||
) -> Result<(), Error> {
|
||||
info!(
|
||||
"Registering mDNS service {}/{}/{}",
|
||||
name, service_type, port
|
||||
);
|
||||
|
||||
let _ = self.remove(name, service_type, port);
|
||||
|
||||
let mut properties = Vec::new();
|
||||
for kvs in txt_kvs {
|
||||
info!("mDNS TXT key {} val {}", kvs.0, kvs.1);
|
||||
properties.push(format!("{}={}", kvs.0, kvs.1));
|
||||
}
|
||||
let properties: Vec<&str> = properties.iter().map(|entry| entry.as_str()).collect();
|
||||
|
||||
let service =
|
||||
self.responder
|
||||
.register(service_type.to_owned(), name.to_owned(), port, &properties);
|
||||
|
||||
self.services.insert(
|
||||
ServiceId {
|
||||
name: name.into(),
|
||||
service_type: service_type.into(),
|
||||
port,
|
||||
},
|
||||
service,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, name: &str, service_type: &str, port: u16) -> Result<(), Error> {
|
||||
let id = ServiceId {
|
||||
name: name.into(),
|
||||
service_type: service_type.into(),
|
||||
port,
|
||||
};
|
||||
|
||||
if self.services.remove(&id).is_some() {
|
||||
info!(
|
||||
"Deregistering mDNS service {}/{}/{}",
|
||||
name, service_type, port
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Mdns for LinuxMdns {
|
||||
fn add(
|
||||
&mut self,
|
||||
name: &str,
|
||||
service_type: &str,
|
||||
port: u16,
|
||||
txt_kvs: &[(&str, &str)],
|
||||
) -> Result<(), Error> {
|
||||
LinuxMdns::add(self, name, service_type, port, txt_kvs)
|
||||
}
|
||||
|
||||
fn remove(&mut self, name: &str, service_type: &str, port: u16) -> Result<(), Error> {
|
||||
LinuxMdns::remove(self, name, service_type, port)
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2020-2022 Project CHIP Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{error::Error, mdns::Mdns};
|
||||
use astro_dnssd::{DNSServiceBuilder, RegisteredDnsService};
|
||||
use log::info;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct ServiceId {
|
||||
name: String,
|
||||
service_type: String,
|
||||
port: u16,
|
||||
}
|
||||
|
||||
pub struct MacOsMdns {
|
||||
services: HashMap<RegisteredDnsService, RegisteredDnsService>,
|
||||
}
|
||||
|
||||
impl MacOsMdns {
|
||||
pub fn new() -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
services: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add(
|
||||
&mut self,
|
||||
name: &str,
|
||||
service_type: &str,
|
||||
port: u16,
|
||||
txt_kvs: &[(&str, &str)],
|
||||
) -> Result<(), Error> {
|
||||
info!(
|
||||
"Registering mDNS service {}/{}/{}",
|
||||
name, service_type, port
|
||||
);
|
||||
|
||||
let _ = self.remove(name, service_type, port);
|
||||
|
||||
let mut builder = DNSServiceBuilder::new(service_type, port).with_name(name);
|
||||
|
||||
for kvs in txt_kvs {
|
||||
info!("mDNS TXT key {} val {}", kvs.0, kvs.1);
|
||||
builder = builder.with_key_value(kvs.0.to_string(), kvs.1.to_string());
|
||||
}
|
||||
|
||||
let service = builder.register().map_err(|_| Error::MdnsError)?;
|
||||
|
||||
self.services.insert(
|
||||
ServiceId {
|
||||
name: name.into(),
|
||||
service_type: service_type.into(),
|
||||
port,
|
||||
},
|
||||
service,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, name: &str, service_type: &str, port: u16) -> Result<(), Error> {
|
||||
let id = ServiceId {
|
||||
name: name.into(),
|
||||
service_type: service_type.into(),
|
||||
port,
|
||||
};
|
||||
|
||||
if self.services.remove(&id).is_some() {
|
||||
info!(
|
||||
"Deregistering mDNS service {}/{}/{}",
|
||||
name, service_type, port
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Mdns for MacOsMdns {
|
||||
fn add(
|
||||
&mut self,
|
||||
name: &str,
|
||||
service_type: &str,
|
||||
port: u16,
|
||||
txt_kvs: &[(&str, &str)],
|
||||
) -> Result<(), Error> {
|
||||
MacOsMdns::add(self, name, service_type, port, txt_kvs)
|
||||
}
|
||||
|
||||
fn remove(&mut self, name: &str, service_type: &str, port: u16) -> Result<(), Error> {
|
||||
MacOsMdns::remove(self, name, service_type, port)
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
use crate::error::*;
|
||||
use log::info;
|
||||
use log::{info, warn};
|
||||
use smol::net::{Ipv6Addr, UdpSocket};
|
||||
|
||||
use super::network::Address;
|
||||
|
@ -35,25 +35,50 @@ pub const MATTER_PORT: u16 = 5540;
|
|||
|
||||
impl UdpListener {
|
||||
pub async fn new() -> Result<UdpListener, Error> {
|
||||
Ok(UdpListener {
|
||||
let listener = UdpListener {
|
||||
socket: UdpSocket::bind((Ipv6Addr::UNSPECIFIED, MATTER_PORT)).await?,
|
||||
})
|
||||
};
|
||||
|
||||
info!(
|
||||
"Listening on {:?} port {}",
|
||||
Ipv6Addr::UNSPECIFIED,
|
||||
MATTER_PORT
|
||||
);
|
||||
|
||||
Ok(listener)
|
||||
}
|
||||
|
||||
pub async fn recv(&self, in_buf: &mut [u8]) -> Result<(usize, Address), Error> {
|
||||
info!("Waiting for incoming packets");
|
||||
|
||||
let (size, addr) = self.socket.recv_from(in_buf).await.map_err(|e| {
|
||||
info!("Error on the network: {:?}", e);
|
||||
warn!("Error on the network: {:?}", e);
|
||||
Error::Network
|
||||
})?;
|
||||
|
||||
info!("Got packet: {:?} from addr {:?}", in_buf, addr);
|
||||
|
||||
Ok((size, Address::Udp(addr)))
|
||||
}
|
||||
|
||||
pub async fn send(&self, addr: Address, out_buf: &[u8]) -> Result<usize, Error> {
|
||||
match addr {
|
||||
Address::Udp(addr) => self.socket.send_to(out_buf, addr).await.map_err(|e| {
|
||||
info!("Error on the network: {:?}", e);
|
||||
Error::Network
|
||||
}),
|
||||
Address::Udp(addr) => {
|
||||
let len = self.socket.send_to(out_buf, addr).await.map_err(|e| {
|
||||
warn!("Error on the network: {:?}", e);
|
||||
Error::Network
|
||||
})?;
|
||||
|
||||
info!(
|
||||
"Send packet: {:?} ({}/{}) to addr {:?}",
|
||||
out_buf,
|
||||
out_buf.len(),
|
||||
len,
|
||||
addr
|
||||
);
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue