Skip to content

Commit

Permalink
Expose device making request in GATT server.
Browse files Browse the repository at this point in the history
Provide access to name of adapter and address of device that is
responsible for a GATT server request.

Fixes #62
  • Loading branch information
surban committed Dec 14, 2022
1 parent 6e5b147 commit 85c93de
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 11 deletions.
4 changes: 2 additions & 2 deletions bluer/examples/gatt_server_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@ async fn main() -> bluer::Result<()> {
evt = char_control.next() => {
match evt {
Some(CharacteristicControlEvent::Write(req)) => {
println!("Accepting write event with MTU {}", req.mtu());
println!("Accepting write event with MTU {} from {}", req.mtu(), req.device_address());
read_buf = vec![0; req.mtu()];
reader_opt = Some(req.accept()?);
},
Some(CharacteristicControlEvent::Notify(notifier)) => {
println!("Accepting notify request event with MTU {}", notifier.mtu());
println!("Accepting notify request event with MTU {} from {}", notifier.mtu(), notifier.device_address());
writer_opt = Some(notifier);
},
None => break,
Expand Down
81 changes: 74 additions & 7 deletions bluer/src/gatt/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ use super::{
CHARACTERISTIC_INTERFACE, DESCRIPTOR_INTERFACE, SERVICE_INTERFACE,
};
use crate::{
method_call, parent_path, Adapter, DbusResult, Error, ErrorKind, Result, SessionInner, ERR_PREFIX,
SERVICE_NAME, TIMEOUT,
method_call, parent_path, Adapter, Address, DbusResult, Device, Error, ErrorKind, Result, SessionInner,
ERR_PREFIX, SERVICE_NAME, TIMEOUT,
};

pub(crate) const MANAGER_INTERFACE: &str = "org.bluez.GattManager1";
Expand Down Expand Up @@ -430,10 +430,24 @@ impl Characteristic {
// Callback interface
// ------------------

/// Parse the `device` option.
fn parse_device(dict: &PropMap) -> DbusResult<(String, Address)> {
let path = read_prop!(dict, "device", Path);
let (adapter, addr) = Device::parse_dbus_path(&path).ok_or_else(|| {
log::warn!("cannot parse device path: {}", path);
MethodErr::invalid_arg("device")
})?;
Ok((adapter.to_string(), addr))
}

/// Read value request.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct CharacteristicReadRequest {
/// Name of adapter making this request.
pub adapter_name: String,
/// Address of device making this request.
pub device_address: Address,
/// Offset.
pub offset: u16,
/// Exchanged MTU.
Expand All @@ -444,7 +458,10 @@ pub struct CharacteristicReadRequest {

impl CharacteristicReadRequest {
fn from_dict(dict: &PropMap) -> DbusResult<Self> {
let (adapter_name, device_address) = parse_device(dict)?;
Ok(Self {
adapter_name,
device_address,
offset: read_opt_prop!(dict, "offset", u16).unwrap_or_default(),
mtu: read_prop!(dict, "mtu", u16),
link: read_opt_prop!(dict, "link", String).and_then(|v| v.parse().ok()),
Expand All @@ -456,6 +473,10 @@ impl CharacteristicReadRequest {
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct CharacteristicWriteRequest {
/// Name of adapter making this request.
pub adapter_name: String,
/// Address of device making this request.
pub device_address: Address,
/// Start offset.
pub offset: u16,
/// Write operation type.
Expand All @@ -470,7 +491,10 @@ pub struct CharacteristicWriteRequest {

impl CharacteristicWriteRequest {
fn from_dict(dict: &PropMap) -> DbusResult<Self> {
let (adapter_name, device_address) = parse_device(dict)?;
Ok(Self {
adapter_name,
device_address,
offset: read_opt_prop!(dict, "offset", u16).unwrap_or_default(),
op_type: read_opt_prop!(dict, "type", String)
.map(|s| s.parse().map_err(|_| MethodErr::invalid_arg("type")))
Expand Down Expand Up @@ -563,12 +587,24 @@ impl CharacteristicNotifier {

/// A remote request to start writing to a characteristic via IO.
pub struct CharacteristicWriteIoRequest {
adapter_name: String,
device_address: Address,
mtu: u16,
link: Option<LinkType>,
tx: oneshot::Sender<ReqResult<OwnedFd>>,
}

impl CharacteristicWriteIoRequest {
/// Name of adapter making this request.
pub fn adapter_name(&self) -> &str {
&self.adapter_name
}

/// Address of device making this request.
pub fn device_address(&self) -> Address {
self.device_address
}

/// Maximum transmission unit.
pub fn mtu(&self) -> usize {
self.mtu.into()
Expand All @@ -581,10 +617,10 @@ impl CharacteristicWriteIoRequest {

/// Accept the write request.
pub fn accept(self) -> Result<CharacteristicReader> {
let CharacteristicWriteIoRequest { mtu, tx, .. } = self;
let CharacteristicWriteIoRequest { adapter_name, device_address, mtu, tx, .. } = self;
let (fd, stream) = make_socket_pair(false)?;
let _ = tx.send(Ok(fd));
Ok(CharacteristicReader { mtu: mtu.into(), stream, buf: Vec::new() })
Ok(CharacteristicReader { adapter_name, device_address, mtu: mtu.into(), stream, buf: Vec::new() })
}

/// Reject the write request.
Expand Down Expand Up @@ -696,6 +732,10 @@ pub fn characteristic_control() -> (CharacteristicControl, CharacteristicControl
#[derive(Debug, Clone)]
#[non_exhaustive]
struct CharacteristicAcquireRequest {
/// Name of adapter making this request.
pub adapter_name: String,
/// Address of device making this request.
pub device_address: Address,
/// Exchanged MTU.
pub mtu: u16,
/// Link type.
Expand All @@ -704,7 +744,10 @@ struct CharacteristicAcquireRequest {

impl CharacteristicAcquireRequest {
fn from_dict(dict: &PropMap) -> DbusResult<Self> {
let (adapter, device) = parse_device(dict)?;
Ok(Self {
adapter_name: adapter,
device_address: device,
mtu: read_prop!(dict, "mtu", u16),
link: read_opt_prop!(dict, "link", String).and_then(|v| v.parse().ok()),
})
Expand Down Expand Up @@ -866,8 +909,13 @@ impl RegisteredCharacteristic {
match &reg.c.write {
Some(CharacteristicWrite { method: CharacteristicWriteMethod::Io, .. }) => {
let (tx, rx) = oneshot::channel();
let req =
CharacteristicWriteIoRequest { mtu: options.mtu, link: options.link, tx };
let req = CharacteristicWriteIoRequest {
adapter_name: options.adapter_name.clone(),
device_address: options.device_address,
mtu: options.mtu,
link: options.link,
tx,
};
reg.c
.control_handle
.events_tx
Expand Down Expand Up @@ -896,7 +944,12 @@ impl RegisteredCharacteristic {
let (fd, stream) = make_socket_pair(true).map_err(|_| ReqError::Failed)?;
// WORKAROUND: BlueZ drops data at end of packet if full MTU is used.
let mtu = options.mtu.saturating_sub(5).into();
let writer = CharacteristicWriter { mtu, stream };
let writer = CharacteristicWriter {
adapter_name: options.adapter_name.clone(),
device_address: options.device_address,
mtu,
stream,
};
let _ = reg
.c
.control_handle
Expand Down Expand Up @@ -1046,6 +1099,10 @@ impl Descriptor {
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct DescriptorReadRequest {
/// Name of adapter making this request.
pub adapter_name: String,
/// Address of device making this request.
pub device_address: Address,
/// Offset.
pub offset: u16,
/// Link type.
Expand All @@ -1054,7 +1111,10 @@ pub struct DescriptorReadRequest {

impl DescriptorReadRequest {
fn from_dict(dict: &PropMap) -> DbusResult<Self> {
let (adapter_name, device_address) = parse_device(dict)?;
Ok(Self {
adapter_name,
device_address,
offset: read_opt_prop!(dict, "offset", u16).unwrap_or_default(),
link: read_opt_prop!(dict, "link", String).and_then(|v| v.parse().ok()),
})
Expand All @@ -1065,6 +1125,10 @@ impl DescriptorReadRequest {
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct DescriptorWriteRequest {
/// Name of adapter making this request.
pub adapter_name: String,
/// Address of device making this request.
pub device_address: Address,
/// Offset.
pub offset: u16,
/// Link type.
Expand All @@ -1075,7 +1139,10 @@ pub struct DescriptorWriteRequest {

impl DescriptorWriteRequest {
fn from_dict(dict: &PropMap) -> DbusResult<Self> {
let (adapter_name, device_address) = parse_device(dict)?;
Ok(Self {
adapter_name,
device_address,
offset: read_opt_prop!(dict, "offset", u16).unwrap_or_default(),
link: read_opt_prop!(dict, "link", String).and_then(|v| v.parse().ok()),
prepare_authorize: read_prop!(dict, "prepare_authorize", bool),
Expand Down
26 changes: 26 additions & 0 deletions bluer/src/gatt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use tokio::{
net::UnixStream,
};

use crate::Address;

pub mod local;
pub mod remote;

Expand Down Expand Up @@ -106,13 +108,25 @@ impl Default for WriteOp {
#[pin_project]
#[derive(Debug)]
pub struct CharacteristicReader {
adapter_name: String,
device_address: Address,
mtu: usize,
#[pin]
stream: UnixStream,
buf: Vec<u8>,
}

impl CharacteristicReader {
/// Name of adapter.
pub fn adapter_name(&self) -> &str {
&self.adapter_name
}

/// Address of remote device.
pub fn device_address(&self) -> Address {
self.device_address
}

/// Maximum transmission unit.
pub fn mtu(&self) -> usize {
self.mtu
Expand Down Expand Up @@ -208,12 +222,24 @@ impl IntoRawFd for CharacteristicReader {
#[pin_project]
#[derive(Debug)]
pub struct CharacteristicWriter {
adapter_name: String,
device_address: Address,
mtu: usize,
#[pin]
stream: UnixStream,
}

impl CharacteristicWriter {
/// Name of adapter.
pub fn adapter_name(&self) -> &str {
&self.adapter_name
}

/// Address of remote device.
pub fn device_address(&self) -> Address {
self.device_address
}

/// Maximum transmission unit.
pub fn mtu(&self) -> usize {
self.mtu
Expand Down
15 changes: 13 additions & 2 deletions bluer/src/gatt/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,12 @@ impl Characteristic {
let stream = UnixStream::from_std(stream)?;
// WORKAROUND: BlueZ drops data at end of packet if full MTU is used.
let mtu = mtu.saturating_sub(5).into();
Ok(CharacteristicWriter { mtu, stream })
Ok(CharacteristicWriter {
adapter_name: self.adapter_name().to_string(),
device_address: self.device_address,
mtu,
stream,
})
}

/// Starts a notification or indication session from this characteristic
Expand Down Expand Up @@ -430,7 +435,13 @@ impl Characteristic {
let stream = unsafe { std::os::unix::net::UnixStream::from_raw_fd(fd.into_fd()) };
stream.set_nonblocking(true)?;
let stream = UnixStream::from_std(stream)?;
Ok(CharacteristicReader { mtu: mtu.into(), stream, buf: Vec::new() })
Ok(CharacteristicReader {
adapter_name: self.adapter_name().to_string(),
device_address: self.device_address,
mtu: mtu.into(),
stream,
buf: Vec::new(),
})
}

dbus_interface!();
Expand Down

0 comments on commit 85c93de

Please sign in to comment.