bluer/gatt/
local.rs

1//! Publish local GATT services to remove devices.
2
3use dbus::{
4    arg::{OwnedFd, PropMap, Variant},
5    channel::Sender,
6    message::SignalArgs,
7    nonblock::{stdintf::org_freedesktop_dbus::PropertiesPropertiesChanged, Proxy, SyncConnection},
8    MethodErr, Path,
9};
10use dbus_crossroads::{Crossroads, IfaceBuilder, IfaceToken};
11use futures::{channel::oneshot, lock::Mutex, Future, FutureExt, Stream};
12use pin_project::pin_project;
13use std::{
14    collections::HashSet,
15    fmt,
16    mem::take,
17    num::NonZeroU16,
18    pin::Pin,
19    sync::{Arc, Weak},
20    task::Poll,
21};
22use strum::{Display, EnumString, IntoStaticStr};
23use tokio::sync::{mpsc, watch};
24use tokio_stream::wrappers::ReceiverStream;
25use uuid::Uuid;
26
27use super::{
28    make_socket_pair, mtu_workaround, CharacteristicFlags, CharacteristicReader, CharacteristicWriter,
29    DescriptorFlags, WriteOp, CHARACTERISTIC_INTERFACE, DESCRIPTOR_INTERFACE, SERVICE_INTERFACE,
30};
31use crate::{
32    method_call, parent_path, Adapter, Address, DbusResult, Device, Error, ErrorKind, Result, SessionInner,
33    ERR_PREFIX, SERVICE_NAME, TIMEOUT,
34};
35
36pub(crate) const MANAGER_INTERFACE: &str = "org.bluez.GattManager1";
37
38/// Link type.
39#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Display, EnumString)]
40#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
41pub enum LinkType {
42    /// BR/EDR
43    #[strum(serialize = "BR/EDR")]
44    BrEdr,
45    /// LE
46    #[strum(serialize = "LE")]
47    Le,
48}
49
50// ===========================================================================================
51// Request error
52// ===========================================================================================
53
54/// Error response from us to a Bluetooth request.
55#[derive(Clone, Copy, Debug, displaydoc::Display, Eq, PartialEq, Ord, PartialOrd, Hash, IntoStaticStr)]
56#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
57#[non_exhaustive]
58pub enum ReqError {
59    /// Bluetooth request failed
60    Failed,
61    /// Bluetooth request already in progress
62    InProgress,
63    /// Invalid offset for Bluetooth GATT property
64    InvalidOffset,
65    /// Invalid value length for Bluetooth GATT property
66    InvalidValueLength,
67    /// Bluetooth request not permitted
68    NotPermitted,
69    /// Bluetooth request not authorized
70    NotAuthorized,
71    /// Bluetooth request not supported
72    NotSupported,
73}
74
75impl std::error::Error for ReqError {}
76
77impl Default for ReqError {
78    fn default() -> Self {
79        Self::Failed
80    }
81}
82
83impl From<ReqError> for dbus::MethodErr {
84    fn from(err: ReqError) -> Self {
85        let name: &'static str = err.into();
86        Self::from((ERR_PREFIX.to_string() + name, &err.to_string()))
87    }
88}
89
90/// Result of a Bluetooth request to us.
91pub type ReqResult<T> = std::result::Result<T, ReqError>;
92
93// ===========================================================================================
94// Service
95// ===========================================================================================
96
97// ----------
98// Definition
99// ----------
100
101/// Definition of local GATT service exposed over Bluetooth.
102#[derive(Debug, Default)]
103pub struct Service {
104    /// 128-bit service UUID.
105    pub uuid: Uuid,
106    /// Service handle.
107    ///
108    /// Set to [None] to auto allocate an available handle.
109    pub handle: Option<NonZeroU16>,
110    /// Indicates whether or not this GATT service is a
111    /// primary service.
112    ///
113    /// If false, the service is secondary.
114    pub primary: bool,
115    /// List of GATT characteristics to expose.
116    pub characteristics: Vec<Characteristic>,
117    /// Control handle for service once it has been registered.
118    pub control_handle: ServiceControlHandle,
119    #[doc(hidden)]
120    pub _non_exhaustive: (),
121}
122
123// ----------
124// Controller
125// ----------
126
127/// An object to control a service once it has been registered.
128///
129/// Use [service_control] to obtain controller and associated handle.
130pub struct ServiceControl {
131    handle_rx: watch::Receiver<Option<NonZeroU16>>,
132}
133
134impl fmt::Debug for ServiceControl {
135    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136        write!(f, "ServiceControl {{ handle: {} }}", self.handle().map(|h| h.get()).unwrap_or_default())
137    }
138}
139
140impl ServiceControl {
141    /// Gets the assigned handle of the service.
142    pub fn handle(&self) -> crate::Result<NonZeroU16> {
143        match *self.handle_rx.borrow() {
144            Some(handle) => Ok(handle),
145            None => Err(Error::new(ErrorKind::NotRegistered)),
146        }
147    }
148}
149
150/// A handle to store inside a service definition to make it controllable
151/// once it has been registered.
152///
153/// Use [service_control] to obtain controller and associated handle.
154pub struct ServiceControlHandle {
155    handle_tx: watch::Sender<Option<NonZeroU16>>,
156}
157
158impl Default for ServiceControlHandle {
159    fn default() -> Self {
160        Self { handle_tx: watch::channel(None).0 }
161    }
162}
163
164impl fmt::Debug for ServiceControlHandle {
165    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
166        write!(f, "ServiceControlHandle")
167    }
168}
169
170/// Creates a [ServiceControl] and its associated [ServiceControlHandle].
171///
172/// Keep the [ServiceControl] and store the [ServiceControlHandle] in [Service::control_handle].
173pub fn service_control() -> (ServiceControl, ServiceControlHandle) {
174    let (handle_tx, handle_rx) = watch::channel(None);
175    (ServiceControl { handle_rx }, ServiceControlHandle { handle_tx })
176}
177
178// ---------------
179// D-Bus interface
180// ---------------
181
182/// A service exposed over D-Bus to bluez.
183pub(crate) struct RegisteredService {
184    s: Service,
185}
186
187impl RegisteredService {
188    fn new(s: Service) -> Self {
189        if let Some(handle) = s.handle {
190            let _ = s.control_handle.handle_tx.send(Some(handle));
191        }
192        Self { s }
193    }
194
195    pub(crate) fn register_interface(cr: &mut Crossroads) -> IfaceToken<Arc<Self>> {
196        cr.register(SERVICE_INTERFACE, |ib: &mut IfaceBuilder<Arc<Self>>| {
197            cr_property!(ib, "UUID", reg => {
198                Some(reg.s.uuid.to_string())
199            });
200            cr_property!(ib, "Primary", reg => {
201                Some(reg.s.primary)
202            });
203            ib.property("Handle").get(|_ctx, reg| Ok(reg.s.handle.map(|h| h.get()).unwrap_or_default())).set(
204                |ctx, reg, handle| {
205                    log::trace!("{}: {}.Handle <- {}", ctx.path(), SERVICE_INTERFACE, handle);
206                    let handle = NonZeroU16::new(handle);
207                    let _ = reg.s.control_handle.handle_tx.send(handle);
208                    Ok(None)
209                },
210            );
211        })
212    }
213}
214
215// ===========================================================================================
216// Characteristic
217// ===========================================================================================
218
219// ----------
220// Definition
221// ----------
222
223/// Characteristic read value function.
224pub type CharacteristicReadFun = Box<
225    dyn (Fn(CharacteristicReadRequest) -> Pin<Box<dyn Future<Output = ReqResult<Vec<u8>>> + Send>>) + Send + Sync,
226>;
227
228/// Characteristic read definition.
229#[derive(custom_debug::Debug)]
230pub struct CharacteristicRead {
231    /// If set allows clients to read this characteristic.
232    pub read: bool,
233    /// Require encryption.
234    pub encrypt_read: bool,
235    /// Require authentication.
236    pub encrypt_authenticated_read: bool,
237    /// Require security.
238    pub secure_read: bool,
239    /// Function called for each read request returning value.
240    #[debug(skip)]
241    pub fun: CharacteristicReadFun,
242    #[doc(hidden)]
243    pub _non_exhaustive: (),
244}
245
246impl Default for CharacteristicRead {
247    fn default() -> Self {
248        Self {
249            read: false,
250            encrypt_read: false,
251            encrypt_authenticated_read: false,
252            secure_read: false,
253            fun: Box::new(|_| async move { Err(ReqError::NotSupported) }.boxed()),
254            _non_exhaustive: (),
255        }
256    }
257}
258
259impl CharacteristicRead {
260    fn set_characteristic_flags(&self, f: &mut CharacteristicFlags) {
261        f.read = self.read;
262        f.encrypt_read = self.encrypt_read;
263        f.encrypt_authenticated_read = self.encrypt_authenticated_read;
264        f.secure_read = self.secure_read;
265    }
266}
267
268/// Characteristic write value function.
269pub type CharacteristicWriteFun = Box<
270    dyn Fn(Vec<u8>, CharacteristicWriteRequest) -> Pin<Box<dyn Future<Output = ReqResult<()>> + Send>>
271        + Send
272        + Sync,
273>;
274
275/// Characteristic write value method.
276pub enum CharacteristicWriteMethod {
277    /// Call specified function for each write request.
278    Fun(CharacteristicWriteFun),
279    /// Provide written data over asynchronous IO functions.
280    /// This has low overhead.
281    ///
282    /// Use [CharacteristicControl] to obtain reader.
283    Io,
284}
285
286impl fmt::Debug for CharacteristicWriteMethod {
287    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
288        match self {
289            Self::Fun(_) => write!(f, "Fun"),
290            Self::Io => write!(f, "Io"),
291        }
292    }
293}
294
295impl Default for CharacteristicWriteMethod {
296    fn default() -> Self {
297        Self::Fun(Box::new(|_, _| async move { Err(ReqError::NotSupported) }.boxed()))
298    }
299}
300
301/// Characteristic write definition.
302#[derive(Debug, Default)]
303pub struct CharacteristicWrite {
304    /// If set allows clients to use the Write Command ATT operation.
305    pub write: bool,
306    /// If set allows clients to use the Write Request/Response operation.
307    pub write_without_response: bool,
308    /// If set allows clients to use the Reliable Writes procedure.
309    pub reliable_write: bool,
310    /// If set allows clients to use the Signed Write Without Response procedure.
311    pub authenticated_signed_writes: bool,
312    /// Require encryption.
313    pub encrypt_write: bool,
314    /// Require authentication.
315    pub encrypt_authenticated_write: bool,
316    /// Require security.
317    pub secure_write: bool,
318    /// Write value method.
319    pub method: CharacteristicWriteMethod,
320    #[doc(hidden)]
321    pub _non_exhaustive: (),
322}
323
324impl CharacteristicWrite {
325    fn set_characteristic_flags(&self, f: &mut CharacteristicFlags) {
326        f.write = self.write;
327        f.write_without_response = self.write_without_response;
328        f.reliable_write = self.reliable_write;
329        f.authenticated_signed_writes = self.authenticated_signed_writes;
330        f.encrypt_write = self.encrypt_write;
331        f.encrypt_authenticated_write = self.encrypt_authenticated_write;
332        f.secure_write = self.secure_write;
333    }
334}
335
336/// Characteristic start notifications function.
337///
338/// This function cannot fail, since there is to way to provide an error response to the
339/// requesting device.
340pub type CharacteristicNotifyFun =
341    Box<dyn Fn(CharacteristicNotifier) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync>;
342
343/// Characteristic notify value method.
344pub enum CharacteristicNotifyMethod {
345    /// Call specified function when client starts a notification session.
346    Fun(CharacteristicNotifyFun),
347    /// Write notify data over asynchronous IO.
348    /// This has low overhead.
349    ///
350    /// Use [CharacteristicControl] to obtain writer.
351    Io,
352}
353
354impl Default for CharacteristicNotifyMethod {
355    fn default() -> Self {
356        Self::Fun(Box::new(|_| async move {}.boxed()))
357    }
358}
359
360impl fmt::Debug for CharacteristicNotifyMethod {
361    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
362        match self {
363            Self::Fun(_) => write!(f, "Fun"),
364            Self::Io => write!(f, "Io"),
365        }
366    }
367}
368
369/// Characteristic notify definition.
370#[derive(Debug, Default)]
371pub struct CharacteristicNotify {
372    /// If set allows the client to use the Handle Value Notification operation.
373    pub notify: bool,
374    /// If set allows the client to use the Handle Value Indication/Confirmation operation.
375    ///
376    /// Confirmations will only be provided when this is [true] and [notify](Self::notify) is [false].
377    pub indicate: bool,
378    /// Notification and indication method.
379    pub method: CharacteristicNotifyMethod,
380    #[doc(hidden)]
381    pub _non_exhaustive: (),
382}
383
384impl CharacteristicNotify {
385    fn set_characteristic_flags(&self, f: &mut CharacteristicFlags) {
386        f.notify = self.notify;
387        f.indicate = self.indicate;
388    }
389}
390
391/// Definition of local GATT characteristic exposed over Bluetooth.
392#[derive(Default, Debug)]
393pub struct Characteristic {
394    /// 128-bit characteristic UUID.
395    pub uuid: Uuid,
396    /// Characteristic handle.
397    ///
398    /// Set to [None] to auto allocate an available handle.
399    pub handle: Option<NonZeroU16>,
400    /// If set, permits broadcasts of the Characteristic Value using
401    /// Server Characteristic Configuration Descriptor.
402    pub broadcast: bool,
403    /// If set a client can write to the Characteristic User Description Descriptor.
404    pub writable_auxiliaries: bool,
405    /// Authorize flag.
406    pub authorize: bool,
407    /// Characteristic descriptors.
408    pub descriptors: Vec<Descriptor>,
409    /// Read value of characteristic.
410    pub read: Option<CharacteristicRead>,
411    /// Write value of characteristic.
412    pub write: Option<CharacteristicWrite>,
413    /// Notify client of characteristic value change.
414    pub notify: Option<CharacteristicNotify>,
415    /// Control handle for characteristic once it has been registered.
416    pub control_handle: CharacteristicControlHandle,
417    #[doc(hidden)]
418    pub _non_exhaustive: (),
419}
420
421impl Characteristic {
422    fn set_characteristic_flags(&self, f: &mut CharacteristicFlags) {
423        f.broadcast = self.broadcast;
424        f.writable_auxiliaries = self.writable_auxiliaries;
425        f.authorize = self.authorize;
426    }
427}
428
429// ------------------
430// Callback interface
431// ------------------
432
433/// Parse the `device` option.
434fn parse_device(dict: &PropMap) -> DbusResult<(String, Address)> {
435    let path = read_prop!(dict, "device", Path);
436    let (adapter, addr) = Device::parse_dbus_path(&path).ok_or_else(|| {
437        log::warn!("cannot parse device path: {}", path);
438        MethodErr::invalid_arg("device")
439    })?;
440    Ok((adapter.to_string(), addr))
441}
442
443/// Read value request.
444#[derive(Debug, Clone)]
445#[non_exhaustive]
446pub struct CharacteristicReadRequest {
447    /// Name of adapter making this request.
448    pub adapter_name: String,
449    /// Address of device making this request.
450    pub device_address: Address,
451    /// Offset.
452    pub offset: u16,
453    /// Exchanged MTU.
454    pub mtu: u16,
455    /// Link type.
456    pub link: Option<LinkType>,
457}
458
459impl CharacteristicReadRequest {
460    fn from_dict(dict: &PropMap) -> DbusResult<Self> {
461        let (adapter_name, device_address) = parse_device(dict)?;
462        Ok(Self {
463            adapter_name,
464            device_address,
465            offset: read_opt_prop!(dict, "offset", u16).unwrap_or_default(),
466            mtu: read_prop!(dict, "mtu", u16),
467            link: read_opt_prop!(dict, "link", String).and_then(|v| v.parse().ok()),
468        })
469    }
470}
471
472/// Write value request.
473#[derive(Debug, Clone)]
474#[non_exhaustive]
475pub struct CharacteristicWriteRequest {
476    /// Name of adapter making this request.
477    pub adapter_name: String,
478    /// Address of device making this request.
479    pub device_address: Address,
480    /// Start offset.
481    pub offset: u16,
482    /// Write operation type.
483    pub op_type: WriteOp,
484    /// Exchanged MTU.
485    pub mtu: u16,
486    /// Link type.
487    pub link: Option<LinkType>,
488    /// True if prepare authorization request.
489    pub prepare_authorize: bool,
490}
491
492impl CharacteristicWriteRequest {
493    fn from_dict(dict: &PropMap) -> DbusResult<Self> {
494        let (adapter_name, device_address) = parse_device(dict)?;
495        Ok(Self {
496            adapter_name,
497            device_address,
498            offset: read_opt_prop!(dict, "offset", u16).unwrap_or_default(),
499            op_type: read_opt_prop!(dict, "type", String)
500                .map(|s| s.parse().map_err(|_| MethodErr::invalid_arg("type")))
501                .transpose()?
502                .unwrap_or_default(),
503            mtu: read_prop!(dict, "mtu", u16),
504            link: read_opt_prop!(dict, "link", String).and_then(|v| v.parse().ok()),
505            prepare_authorize: read_opt_prop!(dict, "prepare-authorize", bool).unwrap_or_default(),
506        })
507    }
508}
509
510/// Notification session.
511///
512/// Use this to send notifications or indications.
513pub struct CharacteristicNotifier {
514    connection: Weak<SyncConnection>,
515    path: Path<'static>,
516    stop_notify_tx: mpsc::Sender<()>,
517    confirm_rx: Option<mpsc::Receiver<()>>,
518}
519
520impl CharacteristicNotifier {
521    /// True, if each notification is confirmed by the receiving device.
522    ///
523    /// This is the case when the Indication mechanism is used.
524    pub fn confirming(&self) -> bool {
525        self.confirm_rx.is_some()
526    }
527
528    /// True, if the notification session has been stopped by the receiving device.
529    pub fn is_stopped(&self) -> bool {
530        self.stop_notify_tx.is_closed()
531    }
532
533    /// Resolves once the notification session has been stopped by the receiving device.
534    pub fn stopped(&self) -> impl Future<Output = ()> {
535        let stop_notify_tx = self.stop_notify_tx.clone();
536        async move { stop_notify_tx.closed().await }
537    }
538
539    /// Sends a notification or indication with the specified data to the receiving device.
540    ///
541    /// If [confirming](Self::confirming) is true, the function waits until a confirmation is received from
542    /// the device before it returns.
543    ///
544    /// This fails when the notification session has been stopped by the receiving device.
545    pub async fn notify(&mut self, value: Vec<u8>) -> Result<()> {
546        let connection =
547            self.connection.upgrade().ok_or_else(|| Error::new(ErrorKind::NotificationSessionStopped))?;
548        if self.is_stopped() {
549            return Err(Error::new(ErrorKind::NotificationSessionStopped));
550        }
551
552        // Flush confirmation queue.
553        // This is necessary because previous notify call could have been aborted
554        // before receiving the confirmation.
555        if let Some(confirm_rx) = &mut self.confirm_rx {
556            while let Some(Some(())) = confirm_rx.recv().now_or_never() {}
557        }
558
559        // Send notification.
560        let mut changed_properties = PropMap::new();
561        changed_properties.insert("Value".to_string(), Variant(Box::new(value)));
562        let ppc = PropertiesPropertiesChanged {
563            interface_name: CHARACTERISTIC_INTERFACE.to_string(),
564            changed_properties,
565            invalidated_properties: Vec::new(),
566        };
567        let msg = ppc.to_emit_message(&self.path);
568        connection.send(msg).map_err(|_| Error::new(ErrorKind::NotificationSessionStopped))?;
569        drop(connection);
570
571        // Wait for confirmation if this is an indication session.
572        // Note that we can be aborted before we receive the confirmation.
573        if let Some(confirm_rx) = &mut self.confirm_rx {
574            match confirm_rx.recv().await {
575                Some(()) => Ok(()),
576                None => Err(Error::new(ErrorKind::IndicationUnconfirmed)),
577            }
578        } else {
579            Ok(())
580        }
581    }
582}
583
584// ------------
585// IO interface
586// ------------
587
588/// A remote request to start writing to a characteristic via IO.
589pub struct CharacteristicWriteIoRequest {
590    adapter_name: String,
591    device_address: Address,
592    mtu: u16,
593    link: Option<LinkType>,
594    tx: oneshot::Sender<ReqResult<OwnedFd>>,
595}
596
597impl CharacteristicWriteIoRequest {
598    /// Name of adapter making this request.
599    pub fn adapter_name(&self) -> &str {
600        &self.adapter_name
601    }
602
603    /// Address of device making this request.
604    pub fn device_address(&self) -> Address {
605        self.device_address
606    }
607
608    /// Maximum transmission unit.
609    pub fn mtu(&self) -> usize {
610        self.mtu.into()
611    }
612
613    /// Link type.
614    pub fn link(&self) -> Option<LinkType> {
615        self.link
616    }
617
618    /// Accept the write request.
619    pub fn accept(self) -> Result<CharacteristicReader> {
620        let CharacteristicWriteIoRequest { adapter_name, device_address, mtu, tx, .. } = self;
621        let (fd, socket) = make_socket_pair(false)?;
622        let _ = tx.send(Ok(fd));
623        Ok(CharacteristicReader { adapter_name, device_address, mtu: mtu.into(), socket, buf: Vec::new() })
624    }
625
626    /// Reject the write request.
627    pub fn reject(self, reason: ReqError) {
628        let _ = self.tx.send(Err(reason));
629    }
630}
631
632// ----------
633// Controller
634// ----------
635
636/// An event on a published characteristic.
637pub enum CharacteristicControlEvent {
638    /// A remote request to start writing via IO.
639    ///
640    /// This event occurs only when using [CharacteristicWriteMethod::Io].
641    Write(CharacteristicWriteIoRequest),
642    /// A remote request to start notifying via IO.
643    ///
644    /// Note that BlueZ acknowledges the client's request before notifying us
645    /// of the start of the notification session.
646    ///
647    /// This event occurs only when using [CharacteristicNotifyMethod::Io].
648    Notify(CharacteristicWriter),
649}
650
651impl fmt::Debug for CharacteristicControlEvent {
652    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
653        match self {
654            Self::Write(_) => write!(f, "Write"),
655            Self::Notify(_) => write!(f, "Notify"),
656        }
657    }
658}
659
660/// An object to control a characteristic and receive events once it has been registered.
661///
662/// Use [characteristic_control] to obtain controller and associated handle.
663#[pin_project]
664pub struct CharacteristicControl {
665    handle_rx: watch::Receiver<Option<NonZeroU16>>,
666    #[pin]
667    events_rx: ReceiverStream<CharacteristicControlEvent>,
668}
669
670impl fmt::Debug for CharacteristicControl {
671    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
672        write!(f, "CharacteristicControl {{ handle: {} }}", self.handle().map(|h| h.get()).unwrap_or_default())
673    }
674}
675
676impl CharacteristicControl {
677    /// Gets the assigned handle of the characteristic.
678    pub fn handle(&self) -> crate::Result<NonZeroU16> {
679        match *self.handle_rx.borrow() {
680            Some(handle) => Ok(handle),
681            None => Err(Error::new(ErrorKind::NotRegistered)),
682        }
683    }
684}
685
686impl Stream for CharacteristicControl {
687    type Item = CharacteristicControlEvent;
688
689    fn poll_next(self: Pin<&mut Self>, cx: &mut std::task::Context) -> Poll<Option<Self::Item>> {
690        self.project().events_rx.poll_next(cx)
691    }
692}
693
694/// A handle to store inside a characteristic definition to make it controllable
695/// once it has been registered.
696///
697/// Use [characteristic_control] to obtain controller and associated handle.
698pub struct CharacteristicControlHandle {
699    handle_tx: watch::Sender<Option<NonZeroU16>>,
700    events_tx: mpsc::Sender<CharacteristicControlEvent>,
701}
702
703impl Default for CharacteristicControlHandle {
704    fn default() -> Self {
705        Self { handle_tx: watch::channel(None).0, events_tx: mpsc::channel(1).0 }
706    }
707}
708
709impl fmt::Debug for CharacteristicControlHandle {
710    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
711        write!(f, "CharacteristicControlHandle")
712    }
713}
714
715/// Creates a [CharacteristicControl] and its associated [CharacteristicControlHandle].
716///
717/// Keep the [CharacteristicControl] and store the [CharacteristicControlHandle] in [Characteristic::control_handle].
718pub fn characteristic_control() -> (CharacteristicControl, CharacteristicControlHandle) {
719    let (handle_tx, handle_rx) = watch::channel(None);
720    let (events_tx, events_rx) = mpsc::channel(1);
721    (
722        CharacteristicControl { handle_rx, events_rx: ReceiverStream::new(events_rx) },
723        CharacteristicControlHandle { handle_tx, events_tx },
724    )
725}
726
727// ---------------
728// D-Bus interface
729// ---------------
730
731/// Characteristic acquire write or notify request.
732#[derive(Debug, Clone)]
733#[non_exhaustive]
734struct CharacteristicAcquireRequest {
735    /// Name of adapter making this request.
736    pub adapter_name: String,
737    /// Address of device making this request.
738    pub device_address: Address,
739    /// Exchanged MTU.
740    pub mtu: u16,
741    /// Link type.
742    pub link: Option<LinkType>,
743}
744
745impl CharacteristicAcquireRequest {
746    fn from_dict(dict: &PropMap) -> DbusResult<Self> {
747        let (adapter, device) = parse_device(dict)?;
748        Ok(Self {
749            adapter_name: adapter,
750            device_address: device,
751            mtu: read_prop!(dict, "mtu", u16),
752            link: read_opt_prop!(dict, "link", String).and_then(|v| v.parse().ok()),
753        })
754    }
755}
756
757/// Notification state of a registered characteristic.
758struct CharacteristicNotifyState {
759    confirm_tx: Option<mpsc::Sender<()>>,
760    _stop_notify_rx: mpsc::Receiver<()>,
761}
762
763/// A characteristic exposed over D-Bus to bluez.
764pub(crate) struct RegisteredCharacteristic {
765    c: Characteristic,
766    notify: Mutex<Option<CharacteristicNotifyState>>,
767    connection: Weak<SyncConnection>,
768}
769
770impl RegisteredCharacteristic {
771    fn new(c: Characteristic, connection: &Arc<SyncConnection>) -> Self {
772        if let Some(handle) = c.handle {
773            let _ = c.control_handle.handle_tx.send(Some(handle));
774        }
775        Self { c, notify: Mutex::new(None), connection: Arc::downgrade(connection) }
776    }
777
778    pub(crate) fn register_interface(cr: &mut Crossroads) -> IfaceToken<Arc<Self>> {
779        cr.register(CHARACTERISTIC_INTERFACE, |ib: &mut IfaceBuilder<Arc<Self>>| {
780            cr_property!(ib, "UUID", reg => {
781                Some(reg.c.uuid.to_string())
782            });
783            cr_property!(ib, "Flags", reg => {
784                let mut flags = CharacteristicFlags::default();
785                reg.c.set_characteristic_flags(&mut flags);
786                if let Some(read) = &reg.c.read {
787                    read.set_characteristic_flags(&mut flags);
788                }
789                if let Some(write) = &reg.c.write {
790                    write.set_characteristic_flags(&mut flags);
791                }
792                if let Some(notify) = &reg.c.notify {
793                    notify.set_characteristic_flags(&mut flags);
794                }
795                Some(flags.as_vec())
796            });
797            ib.property("Service").get(|ctx, _| Ok(parent_path(ctx.path())));
798            ib.property("Handle").get(|_ctx, reg| Ok(reg.c.handle.map(|h| h.get()).unwrap_or_default())).set(
799                |ctx, reg, handle| {
800                    log::trace!("{}: {}.Handle <- {}", ctx.path(), CHARACTERISTIC_INTERFACE, handle);
801                    let handle = NonZeroU16::new(handle);
802                    let _ = reg.c.control_handle.handle_tx.send(handle);
803                    Ok(None)
804                },
805            );
806            cr_property!(ib, "WriteAcquired", reg => {
807                match &reg.c.write {
808                    Some(CharacteristicWrite { method: CharacteristicWriteMethod::Io, .. }) =>
809                        Some(false),
810                    _ => None,
811                }
812            });
813            cr_property!(ib, "NotifyAcquired", reg => {
814                match &reg.c.notify {
815                    Some(CharacteristicNotify { method: CharacteristicNotifyMethod::Io, .. }) =>
816                        Some(false),
817                    _ => None,
818                }
819            });
820            ib.method_with_cr_async("ReadValue", ("options",), ("value",), |ctx, cr, (options,): (PropMap,)| {
821                method_call(ctx, cr, |reg: Arc<Self>| async move {
822                    let options = CharacteristicReadRequest::from_dict(&options)?;
823                    match &reg.c.read {
824                        Some(read) => {
825                            let value = (read.fun)(options).await?;
826                            Ok((value,))
827                        }
828                        None => Err(ReqError::NotSupported.into()),
829                    }
830                })
831            });
832            ib.method_with_cr_async(
833                "WriteValue",
834                ("value", "options"),
835                (),
836                |ctx, cr, (value, options): (Vec<u8>, PropMap)| {
837                    method_call(ctx, cr, |reg: Arc<Self>| async move {
838                        let options = CharacteristicWriteRequest::from_dict(&options)?;
839                        match &reg.c.write {
840                            Some(CharacteristicWrite { method: CharacteristicWriteMethod::Fun(fun), .. }) => {
841                                fun(value, options).await?;
842                                Ok(())
843                            }
844                            _ => Err(ReqError::NotSupported.into()),
845                        }
846                    })
847                },
848            );
849            ib.method_with_cr_async("StartNotify", (), (), |ctx, cr, ()| {
850                let path = ctx.path().clone();
851                method_call(ctx, cr, |reg: Arc<Self>| async move {
852                    match &reg.c.notify {
853                        Some(CharacteristicNotify {
854                            method: CharacteristicNotifyMethod::Fun(notify_fn),
855                            indicate,
856                            notify,
857                            _non_exhaustive: (),
858                        }) => {
859                            let (stop_notify_tx, stop_notify_rx) = mpsc::channel(1);
860                            let (confirm_tx, confirm_rx) = if *indicate && !*notify {
861                                let (tx, rx) = mpsc::channel(1);
862                                (Some(tx), Some(rx))
863                            } else {
864                                (None, None)
865                            };
866                            {
867                                let mut notify = reg.notify.lock().await;
868                                *notify = Some(CharacteristicNotifyState {
869                                    _stop_notify_rx: stop_notify_rx,
870                                    confirm_tx,
871                                });
872                            }
873                            let notifier = CharacteristicNotifier {
874                                connection: reg.connection.clone(),
875                                path,
876                                stop_notify_tx,
877                                confirm_rx,
878                            };
879                            notify_fn(notifier).await;
880                            Ok(())
881                        }
882                        _ => Err(ReqError::NotSupported.into()),
883                    }
884                })
885            });
886            ib.method_with_cr_async("StopNotify", (), (), |ctx, cr, ()| {
887                method_call(ctx, cr, |reg: Arc<Self>| async move {
888                    let mut notify = reg.notify.lock().await;
889                    *notify = None;
890                    Ok(())
891                })
892            });
893            ib.method_with_cr_async("Confirm", (), (), |ctx, cr, ()| {
894                method_call(ctx, cr, |reg: Arc<Self>| async move {
895                    let mut notify = reg.notify.lock().await;
896                    if let Some(CharacteristicNotifyState { confirm_tx: Some(confirm_tx), .. }) = &mut *notify {
897                        let _ = confirm_tx.send(()).await;
898                    }
899                    Ok(())
900                })
901            });
902            ib.method_with_cr_async(
903                "AcquireWrite",
904                ("options",),
905                ("fd", "mtu"),
906                |ctx, cr, (options,): (PropMap,)| {
907                    method_call(ctx, cr, |reg: Arc<Self>| async move {
908                        let options = CharacteristicAcquireRequest::from_dict(&options)?;
909                        match &reg.c.write {
910                            Some(CharacteristicWrite { method: CharacteristicWriteMethod::Io, .. }) => {
911                                let (tx, rx) = oneshot::channel();
912                                let req = CharacteristicWriteIoRequest {
913                                    adapter_name: options.adapter_name.clone(),
914                                    device_address: options.device_address,
915                                    mtu: options.mtu,
916                                    link: options.link,
917                                    tx,
918                                };
919                                reg.c
920                                    .control_handle
921                                    .events_tx
922                                    .send(CharacteristicControlEvent::Write(req))
923                                    .await
924                                    .map_err(|_| ReqError::Failed)?;
925                                let fd = rx.await.map_err(|_| ReqError::Failed)??;
926                                Ok((fd, options.mtu))
927                            }
928                            _ => Err(ReqError::NotSupported.into()),
929                        }
930                    })
931                },
932            );
933            ib.method_with_cr_async(
934                "AcquireNotify",
935                ("options",),
936                ("fd", "mtu"),
937                |ctx, cr, (options,): (PropMap,)| {
938                    method_call(ctx, cr, |reg: Arc<Self>| async move {
939                        let options = CharacteristicAcquireRequest::from_dict(&options)?;
940                        match &reg.c.notify {
941                            Some(CharacteristicNotify { method: CharacteristicNotifyMethod::Io, .. }) => {
942                                // BlueZ has already confirmed the start of the notification session.
943                                // So there is no point in making this fail-able by our users.
944                                let (fd, socket) = make_socket_pair(true).map_err(|_| ReqError::Failed)?;
945                                let mtu = mtu_workaround(options.mtu.into());
946                                let writer = CharacteristicWriter {
947                                    adapter_name: options.adapter_name.clone(),
948                                    device_address: options.device_address,
949                                    mtu,
950                                    socket,
951                                };
952                                let _ = reg
953                                    .c
954                                    .control_handle
955                                    .events_tx
956                                    .send(CharacteristicControlEvent::Notify(writer))
957                                    .await;
958                                Ok((fd, options.mtu))
959                            }
960                            _ => Err(ReqError::NotSupported.into()),
961                        }
962                    })
963                },
964            );
965        })
966    }
967}
968
969// ===========================================================================================
970// Characteristic descriptor
971// ===========================================================================================
972
973// ----------
974// Definition
975// ----------
976
977/// Characteristic descriptor read value function.
978pub type DescriptorReadFun =
979    Box<dyn Fn(DescriptorReadRequest) -> Pin<Box<dyn Future<Output = ReqResult<Vec<u8>>> + Send>> + Send + Sync>;
980
981/// Characteristic descriptor read definition.
982#[derive(custom_debug::Debug)]
983pub struct DescriptorRead {
984    /// If set allows clients to read this characteristic descriptor.
985    pub read: bool,
986    /// Require encryption.
987    pub encrypt_read: bool,
988    /// Require authentication.
989    pub encrypt_authenticated_read: bool,
990    /// Require security.
991    pub secure_read: bool,
992    /// Function called for each read request returning value.
993    #[debug(skip)]
994    pub fun: DescriptorReadFun,
995    #[doc(hidden)]
996    pub _non_exhaustive: (),
997}
998
999impl Default for DescriptorRead {
1000    fn default() -> Self {
1001        Self {
1002            read: false,
1003            encrypt_read: false,
1004            encrypt_authenticated_read: false,
1005            secure_read: false,
1006            fun: Box::new(|_| async move { Err(ReqError::NotSupported) }.boxed()),
1007            _non_exhaustive: (),
1008        }
1009    }
1010}
1011
1012impl DescriptorRead {
1013    fn set_descriptor_flags(&self, f: &mut DescriptorFlags) {
1014        f.read = self.read;
1015        f.encrypt_read = self.encrypt_read;
1016        f.encrypt_authenticated_read = self.encrypt_authenticated_read;
1017        f.secure_read = self.secure_read;
1018    }
1019}
1020
1021/// Characteristic descriptor write value function.
1022pub type DescriptorWriteFun = Box<
1023    dyn Fn(Vec<u8>, DescriptorWriteRequest) -> Pin<Box<dyn Future<Output = ReqResult<()>> + Send>> + Send + Sync,
1024>;
1025
1026/// Characteristic descriptor write definition.
1027#[derive(custom_debug::Debug)]
1028pub struct DescriptorWrite {
1029    /// If set allows clients to use the Write Command ATT operation.
1030    pub write: bool,
1031    /// Require encryption.
1032    pub encrypt_write: bool,
1033    /// Require authentication.
1034    pub encrypt_authenticated_write: bool,
1035    /// Require security.
1036    pub secure_write: bool,
1037    /// Function called for each write request.
1038    #[debug(skip)]
1039    pub fun: DescriptorWriteFun,
1040    #[doc(hidden)]
1041    pub _non_exhaustive: (),
1042}
1043
1044impl Default for DescriptorWrite {
1045    fn default() -> Self {
1046        Self {
1047            write: false,
1048            encrypt_write: false,
1049            encrypt_authenticated_write: false,
1050            secure_write: false,
1051            fun: Box::new(|_, _| async move { Err(ReqError::NotSupported) }.boxed()),
1052            _non_exhaustive: (),
1053        }
1054    }
1055}
1056
1057impl DescriptorWrite {
1058    fn set_descriptor_flags(&self, f: &mut DescriptorFlags) {
1059        f.write = self.write;
1060        f.encrypt_write = self.encrypt_write;
1061        f.encrypt_authenticated_write = self.encrypt_authenticated_write;
1062        f.secure_write = self.secure_write;
1063    }
1064}
1065
1066/// Definition of local GATT characteristic descriptor exposed over Bluetooth.
1067#[derive(Default, Debug)]
1068pub struct Descriptor {
1069    /// 128-bit descriptor UUID.
1070    pub uuid: Uuid,
1071    /// Characteristic descriptor handle.
1072    ///
1073    /// Set to [None] to auto allocate an available handle.
1074    pub handle: Option<NonZeroU16>,
1075    /// Authorize flag.
1076    pub authorize: bool,
1077    /// Read value of characteristic descriptor.
1078    pub read: Option<DescriptorRead>,
1079    /// Write value of characteristic descriptor.
1080    pub write: Option<DescriptorWrite>,
1081    /// Control handle for characteristic descriptor once it has been registered.
1082    pub control_handle: DescriptorControlHandle,
1083    #[doc(hidden)]
1084    pub _non_exhaustive: (),
1085}
1086
1087impl Descriptor {
1088    fn set_descriptor_flags(&self, f: &mut DescriptorFlags) {
1089        f.authorize = self.authorize;
1090    }
1091}
1092
1093// ------------------
1094// Callback interface
1095// ------------------
1096
1097/// Read characteristic descriptor value request.
1098#[derive(Debug, Clone)]
1099#[non_exhaustive]
1100pub struct DescriptorReadRequest {
1101    /// Name of adapter making this request.
1102    pub adapter_name: String,
1103    /// Address of device making this request.
1104    pub device_address: Address,
1105    /// Offset.
1106    pub offset: u16,
1107    /// Link type.
1108    pub link: Option<LinkType>,
1109}
1110
1111impl DescriptorReadRequest {
1112    fn from_dict(dict: &PropMap) -> DbusResult<Self> {
1113        let (adapter_name, device_address) = parse_device(dict)?;
1114        Ok(Self {
1115            adapter_name,
1116            device_address,
1117            offset: read_opt_prop!(dict, "offset", u16).unwrap_or_default(),
1118            link: read_opt_prop!(dict, "link", String).and_then(|v| v.parse().ok()),
1119        })
1120    }
1121}
1122
1123/// Write characteristic descriptor value request.
1124#[derive(Debug, Clone)]
1125#[non_exhaustive]
1126pub struct DescriptorWriteRequest {
1127    /// Name of adapter making this request.
1128    pub adapter_name: String,
1129    /// Address of device making this request.
1130    pub device_address: Address,
1131    /// Offset.
1132    pub offset: u16,
1133    /// Link type.
1134    pub link: Option<LinkType>,
1135    /// Is prepare authorization request?
1136    pub prepare_authorize: bool,
1137}
1138
1139impl DescriptorWriteRequest {
1140    fn from_dict(dict: &PropMap) -> DbusResult<Self> {
1141        let (adapter_name, device_address) = parse_device(dict)?;
1142        Ok(Self {
1143            adapter_name,
1144            device_address,
1145            offset: read_opt_prop!(dict, "offset", u16).unwrap_or_default(),
1146            link: read_opt_prop!(dict, "link", String).and_then(|v| v.parse().ok()),
1147            prepare_authorize: read_prop!(dict, "prepare_authorize", bool),
1148        })
1149    }
1150}
1151
1152// ----------
1153// Controller
1154// ----------
1155
1156/// An object to control a characteristic descriptor once it has been registered.
1157///
1158/// Use [descriptor_control] to obtain controller and associated handle.
1159pub struct DescriptorControl {
1160    handle_rx: watch::Receiver<Option<NonZeroU16>>,
1161}
1162
1163impl fmt::Debug for DescriptorControl {
1164    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1165        write!(f, "DescriptorControl {{ handle: {} }}", self.handle().map(|h| h.get()).unwrap_or_default())
1166    }
1167}
1168
1169impl DescriptorControl {
1170    /// Gets the assigned handle of the characteristic descriptor.
1171    pub fn handle(&self) -> crate::Result<NonZeroU16> {
1172        match *self.handle_rx.borrow() {
1173            Some(handle) => Ok(handle),
1174            None => Err(Error::new(ErrorKind::NotRegistered)),
1175        }
1176    }
1177}
1178
1179/// A handle to store inside a characteristic descriptors definition to make
1180/// it controllable once it has been registered.
1181///
1182/// Use [descriptor_control] to obtain controller and associated handle.
1183pub struct DescriptorControlHandle {
1184    handle_tx: watch::Sender<Option<NonZeroU16>>,
1185}
1186
1187impl Default for DescriptorControlHandle {
1188    fn default() -> Self {
1189        Self { handle_tx: watch::channel(None).0 }
1190    }
1191}
1192
1193impl fmt::Debug for DescriptorControlHandle {
1194    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1195        write!(f, "DescriptorControlHandle")
1196    }
1197}
1198
1199/// Creates a [DescriptorControl] and its associated [DescriptorControlHandle].
1200///
1201/// Keep the [DescriptorControl] and store the [DescriptorControlHandle] in [Descriptor::control_handle].
1202pub fn descriptor_control() -> (DescriptorControl, DescriptorControlHandle) {
1203    let (handle_tx, handle_rx) = watch::channel(None);
1204    (DescriptorControl { handle_rx }, DescriptorControlHandle { handle_tx })
1205}
1206
1207// ---------------
1208// D-Bus interface
1209// ---------------
1210
1211/// A characteristic descriptor exposed over D-Bus to bluez.
1212pub(crate) struct RegisteredDescriptor {
1213    d: Descriptor,
1214}
1215
1216impl RegisteredDescriptor {
1217    fn new(d: Descriptor) -> Self {
1218        if let Some(handle) = d.handle {
1219            let _ = d.control_handle.handle_tx.send(Some(handle));
1220        }
1221        Self { d }
1222    }
1223
1224    pub(crate) fn register_interface(cr: &mut Crossroads) -> IfaceToken<Arc<Self>> {
1225        cr.register(DESCRIPTOR_INTERFACE, |ib: &mut IfaceBuilder<Arc<Self>>| {
1226            cr_property!(ib, "UUID", reg => {
1227                Some(reg.d.uuid.to_string())
1228            });
1229            cr_property!(ib, "Flags", reg => {
1230                let mut flags = DescriptorFlags::default();
1231                reg.d.set_descriptor_flags(&mut flags);
1232                if let Some(read) = &reg.d.read {
1233                    read.set_descriptor_flags(&mut flags);
1234                }
1235                if let Some(write) = &reg.d.write {
1236                    write.set_descriptor_flags(&mut flags);
1237                }
1238                Some(flags.as_vec())
1239            });
1240            ib.property("Characteristic").get(|ctx, _| Ok(parent_path(ctx.path())));
1241            ib.property("Handle").get(|_ctx, reg| Ok(reg.d.handle.map(|h| h.get()).unwrap_or_default())).set(
1242                |ctx, reg, handle| {
1243                    log::trace!("{}: {}.Handle <- {}", ctx.path(), DESCRIPTOR_INTERFACE, handle);
1244                    let handle = NonZeroU16::new(handle);
1245                    let _ = reg.d.control_handle.handle_tx.send(handle);
1246                    Ok(None)
1247                },
1248            );
1249            ib.method_with_cr_async("ReadValue", ("flags",), ("value",), |ctx, cr, (flags,): (PropMap,)| {
1250                method_call(ctx, cr, |reg: Arc<Self>| async move {
1251                    let options = DescriptorReadRequest::from_dict(&flags)?;
1252                    match &reg.d.read {
1253                        Some(read) => {
1254                            let value = (read.fun)(options).await?;
1255                            Ok((value,))
1256                        }
1257                        None => Err(ReqError::NotSupported.into()),
1258                    }
1259                })
1260            });
1261            ib.method_with_cr_async(
1262                "WriteValue",
1263                ("value", "flags"),
1264                (),
1265                |ctx, cr, (value, flags): (Vec<u8>, PropMap)| {
1266                    method_call(ctx, cr, |reg: Arc<Self>| async move {
1267                        let options = DescriptorWriteRequest::from_dict(&flags)?;
1268                        match &reg.d.write {
1269                            Some(write) => {
1270                                (write.fun)(value, options).await?;
1271                                Ok(())
1272                            }
1273                            None => Err(ReqError::NotSupported.into()),
1274                        }
1275                    })
1276                },
1277            );
1278        })
1279    }
1280}
1281
1282// ===========================================================================================
1283// Application
1284// ===========================================================================================
1285
1286pub(crate) const GATT_APP_PREFIX: &str = publish_path!("gatt/app/");
1287
1288/// Definition of local GATT application to publish over Bluetooth.
1289#[derive(Debug, Default)]
1290pub struct Application {
1291    /// Services to publish.
1292    pub services: Vec<Service>,
1293    #[doc(hidden)]
1294    pub _non_exhaustive: (),
1295}
1296
1297impl Application {
1298    pub(crate) async fn register(
1299        mut self, inner: Arc<SessionInner>, adapter_name: Arc<String>,
1300    ) -> crate::Result<ApplicationHandle> {
1301        let mut reg_paths = Vec::new();
1302        let app_path = format!("{}{}", GATT_APP_PREFIX, Uuid::new_v4().as_simple());
1303        let app_path = dbus::Path::new(app_path).unwrap();
1304        log::trace!("Publishing application at {}", &app_path);
1305
1306        {
1307            let mut cr = inner.crossroads.lock().await;
1308
1309            let services = take(&mut self.services);
1310            reg_paths.push(app_path.clone());
1311            let om = cr.object_manager::<Self>();
1312            cr.insert(app_path.clone(), &[om], self);
1313
1314            for (service_idx, mut service) in services.into_iter().enumerate() {
1315                let chars = take(&mut service.characteristics);
1316
1317                let reg_service = RegisteredService::new(service);
1318                let service_path = format!("{}/service{}", &app_path, service_idx);
1319                let service_path = dbus::Path::new(service_path).unwrap();
1320                log::trace!("Publishing service at {}", &service_path);
1321                reg_paths.push(service_path.clone());
1322                cr.insert(service_path.clone(), &[inner.gatt_reg_service_token], Arc::new(reg_service));
1323
1324                for (char_idx, mut char) in chars.into_iter().enumerate() {
1325                    let descs = take(&mut char.descriptors);
1326
1327                    let reg_char = RegisteredCharacteristic::new(char, &inner.connection);
1328                    let char_path = format!("{}/char{}", &service_path, char_idx);
1329                    let char_path = dbus::Path::new(char_path).unwrap();
1330                    log::trace!("Publishing characteristic at {}", &char_path);
1331                    reg_paths.push(char_path.clone());
1332                    cr.insert(char_path.clone(), &[inner.gatt_reg_characteristic_token], Arc::new(reg_char));
1333
1334                    for (desc_idx, desc) in descs.into_iter().enumerate() {
1335                        let reg_desc = RegisteredDescriptor::new(desc);
1336                        let desc_path = format!("{}/desc{}", &char_path, desc_idx);
1337                        let desc_path = dbus::Path::new(desc_path).unwrap();
1338                        log::trace!("Publishing descriptor at {}", &desc_path);
1339                        reg_paths.push(desc_path.clone());
1340                        cr.insert(
1341                            desc_path,
1342                            &[inner.gatt_reg_characteristic_descriptor_token],
1343                            Arc::new(reg_desc),
1344                        );
1345                    }
1346                }
1347            }
1348        }
1349
1350        log::trace!("Registering application at {}", &app_path);
1351        let proxy =
1352            Proxy::new(SERVICE_NAME, Adapter::dbus_path(&adapter_name)?, TIMEOUT, inner.connection.clone());
1353        let () = proxy
1354            .method_call(MANAGER_INTERFACE, "RegisterApplication", (app_path.clone(), PropMap::new()))
1355            .await?;
1356
1357        let (drop_tx, drop_rx) = oneshot::channel();
1358        let app_path_unreg = app_path.clone();
1359        tokio::spawn(async move {
1360            let _ = drop_rx.await;
1361
1362            log::trace!("Unregistering application at {}", &app_path_unreg);
1363            let _: std::result::Result<(), dbus::Error> =
1364                proxy.method_call(MANAGER_INTERFACE, "UnregisterApplication", (app_path_unreg,)).await;
1365
1366            let mut cr = inner.crossroads.lock().await;
1367            for reg_path in reg_paths.into_iter().rev() {
1368                log::trace!("Unpublishing {}", &reg_path);
1369                let _: Option<Self> = cr.remove(&reg_path);
1370            }
1371        });
1372
1373        Ok(ApplicationHandle { name: app_path, _drop_tx: drop_tx })
1374    }
1375}
1376
1377/// Handle to local GATT application published over Bluetooth.
1378///
1379/// Drop this handle to unpublish.
1380pub struct ApplicationHandle {
1381    name: dbus::Path<'static>,
1382    _drop_tx: oneshot::Sender<()>,
1383}
1384
1385impl Drop for ApplicationHandle {
1386    fn drop(&mut self) {
1387        // required for drop order
1388    }
1389}
1390
1391impl fmt::Debug for ApplicationHandle {
1392    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1393        write!(f, "ApplicationHandle {{ {} }}", &self.name)
1394    }
1395}
1396
1397// ===========================================================================================
1398// GATT profile
1399// ===========================================================================================
1400
1401pub(crate) const GATT_PROFILE_PREFIX: &str = publish_path!("gatt/profile/");
1402
1403/// Definition of local profile (GATT client) instance.
1404///
1405/// By registering this type of object
1406/// an application effectively indicates support for a specific GATT profile
1407/// and requests automatic connections to be established to devices
1408/// supporting it.
1409#[derive(Debug, Clone, Default)]
1410pub struct Profile {
1411    /// 128-bit GATT service UUIDs to auto connect.
1412    pub uuids: HashSet<Uuid>,
1413    #[doc(hidden)]
1414    pub _non_exhaustive: (),
1415}
1416
1417impl Profile {
1418    pub(crate) fn register_interface(cr: &mut Crossroads) -> IfaceToken<Self> {
1419        cr.register("org.bluez.GattProfile1", |ib: &mut IfaceBuilder<Self>| {
1420            cr_property!(ib, "UUIDs", p => {
1421                Some(p.uuids.iter().map(|uuid| uuid.to_string()).collect::<Vec<_>>())
1422            });
1423        })
1424    }
1425
1426    pub(crate) async fn register(
1427        self, inner: Arc<SessionInner>, adapter_name: Arc<String>,
1428    ) -> crate::Result<ProfileHandle> {
1429        let profile_path = format!("{}{}", GATT_PROFILE_PREFIX, Uuid::new_v4().as_simple());
1430        let profile_path = dbus::Path::new(profile_path).unwrap();
1431        log::trace!("Publishing profile at {}", &profile_path);
1432
1433        {
1434            let mut cr = inner.crossroads.lock().await;
1435            let om = cr.object_manager::<Self>();
1436            cr.insert(profile_path.clone(), &[inner.gatt_profile_token, om], self);
1437        }
1438
1439        log::trace!("Registering profile at {}", &profile_path);
1440        let proxy =
1441            Proxy::new(SERVICE_NAME, Adapter::dbus_path(&adapter_name)?, TIMEOUT, inner.connection.clone());
1442        let () = proxy
1443            .method_call(MANAGER_INTERFACE, "RegisterApplication", (profile_path.clone(), PropMap::new()))
1444            .await?;
1445
1446        let (drop_tx, drop_rx) = oneshot::channel();
1447        let profile_path_unreg = profile_path.clone();
1448        tokio::spawn(async move {
1449            let _ = drop_rx.await;
1450
1451            log::trace!("Unregistering profile at {}", &profile_path_unreg);
1452            let _: std::result::Result<(), dbus::Error> = proxy
1453                .method_call(MANAGER_INTERFACE, "UnregisterApplication", (profile_path_unreg.clone(),))
1454                .await;
1455
1456            log::trace!("Unpublishing profile at {}", &profile_path_unreg);
1457            let mut cr = inner.crossroads.lock().await;
1458            let _: Option<Self> = cr.remove(&profile_path_unreg);
1459        });
1460
1461        Ok(ProfileHandle { name: profile_path, _drop_tx: drop_tx })
1462    }
1463}
1464
1465/// Handle to published local profile (GATT client) instance.
1466///
1467/// Drop this handle to unpublish.
1468#[must_use = "ProfileHandle must be held for profile to be published"]
1469pub struct ProfileHandle {
1470    name: dbus::Path<'static>,
1471    _drop_tx: oneshot::Sender<()>,
1472}
1473
1474impl Drop for ProfileHandle {
1475    fn drop(&mut self) {
1476        // required for drop order
1477    }
1478}
1479
1480impl fmt::Debug for ProfileHandle {
1481    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1482        write!(f, "ProfileHandle {{ {} }}", &self.name)
1483    }
1484}