/* * * 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::sync::{Arc, Mutex, Once}; use crate::{ error::Error, sys::{sys_publish_service, SysMdnsService}, transport::udp::MATTER_PORT, }; #[derive(Default)] /// The mDNS service handler pub struct MdnsInner { /// Vendor ID vid: u16, /// Product ID pid: u16, /// Discriminator discriminator: u16, } pub struct Mdns { inner: Mutex, } const SHORT_DISCRIMINATOR_MASK: u16 = 0x700; const SHORT_DISCRIMINATOR_SHIFT: u16 = 8; static mut G_MDNS: Option> = None; static INIT: Once = Once::new(); pub enum ServiceMode { Commissioned, Commissionable, } impl Mdns { fn new() -> Self { Self { inner: Mutex::new(MdnsInner { ..Default::default() }), } } /// Get a handle to the globally unique mDNS instance pub fn get() -> Result, Error> { unsafe { INIT.call_once(|| { G_MDNS = Some(Arc::new(Mdns::new())); }); Ok(G_MDNS.as_ref().ok_or(Error::Invalid)?.clone()) } } /// Set mDNS service specific values /// Values like vid, pid, discriminator etc // TODO: More things like device-type etc can be added here pub fn set_values(&self, vid: u16, pid: u16, discriminator: u16) { let mut inner = self.inner.lock().unwrap(); inner.vid = vid; inner.pid = pid; inner.discriminator = discriminator; } /// Publish a mDNS service /// name - is the service name (comma separated subtypes may follow) /// mode - the current service mode pub fn publish_service(&self, name: &str, mode: ServiceMode) -> Result { match mode { ServiceMode::Commissioned => { sys_publish_service(name, "_matter._tcp", MATTER_PORT, &[]) } ServiceMode::Commissionable => { let inner = self.inner.lock().unwrap(); let short = (inner.discriminator & SHORT_DISCRIMINATOR_MASK) >> SHORT_DISCRIMINATOR_SHIFT; let serv_type = format!("_matterc._udp,_S{},_L{}", short, inner.discriminator); let str_discriminator = format!("{}", inner.discriminator); let txt_kvs = [["D", &str_discriminator], ["CM", "1"]]; sys_publish_service(name, &serv_type, MATTER_PORT, &txt_kvs) } } } }