Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ targets = [

[features]
unstable = []
l2cap = ["dep:piper", "futures-lite/std", "futures-lite/alloc"]
l2cap = ["dep:piper", "futures-lite/std", "futures-lite/alloc", "bluer/l2cap", "async-compat"]
serde = ["dep:serde", "uuid/serde", "bluer/serde"]

[dependencies]
Expand Down Expand Up @@ -57,7 +57,8 @@ windows = { version = "0.48.0", features = [
] }

[target.'cfg(target_os = "linux")'.dependencies]
bluer = { version = "0.16.1", features = ["bluetoothd"] }
bluer = { version = "0.17.4", features = ["bluetoothd"] }
async-compat = { version = "0.2", optional = true }
tokio = { version = "1.20.1", features = ["rt-multi-thread"] }

[target.'cfg(target_os = "android")'.dependencies]
Expand Down
12 changes: 4 additions & 8 deletions src/android/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ use java_spaghetti::Global;
use uuid::Uuid;

use super::bindings::android::bluetooth::BluetoothDevice;
#[cfg(feature = "l2cap")]
use super::l2cap_channel::{L2capChannelReader, L2capChannelWriter};
use crate::pairing::PairingAgent;
use crate::{DeviceId, Result, Service, ServicesChanged};

Expand Down Expand Up @@ -100,12 +98,10 @@ impl DeviceImpl {
}

#[cfg(feature = "l2cap")]
pub async fn open_l2cap_channel(
&self,
psm: u16,
secure: bool,
) -> std::prelude::v1::Result<(L2capChannelReader, L2capChannelWriter), crate::Error> {
super::l2cap_channel::open_l2cap_channel(self.device.clone(), psm, secure)
pub async fn open_l2cap_channel(&self, psm: u16, secure: bool) -> Result<super::l2cap_channel::L2capChannel> {
let (reader, writer) = super::l2cap_channel::open_l2cap_channel(self.device.clone(), psm, secure)?;

Ok(super::l2cap_channel::L2capChannel { reader, writer })
}
}

Expand Down
61 changes: 19 additions & 42 deletions src/android/l2cap_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ use tracing::{debug, trace, warn};

use super::bindings::android::bluetooth::{BluetoothDevice, BluetoothSocket};
use super::OptionExt;
use crate::l2cap_channel::PIPE_CAPACITY;
use crate::Result;
use crate::l2cap_channel::{derive_async_read, derive_async_write, PIPE_CAPACITY};

pub fn open_l2cap_channel(
device: Global<BluetoothDevice>,
Expand Down Expand Up @@ -116,11 +115,11 @@ pub fn open_l2cap_channel(

Ok((
L2capChannelReader {
closer: closer.clone(),
_closer: closer.clone(),
stream: read_receiver,
},
L2capChannelWriter {
closer,
_closer: closer,
stream: write_sender,
},
))
Expand Down Expand Up @@ -150,25 +149,27 @@ impl Drop for L2capCloser {
}
}

pub struct L2capChannelReader {
stream: piper::Reader,
closer: Arc<L2capCloser>,
pub struct L2capChannel {
pub(super) reader: L2capChannelReader,
pub(super) writer: L2capChannelWriter,
}

impl L2capChannelReader {
pub async fn close(&mut self) -> Result<()> {
self.closer.close();
Ok(())
impl L2capChannel {
pub fn split(self) -> (L2capChannelReader, L2capChannelWriter) {
(self.reader, self.writer)
}
}

impl AsyncRead for L2capChannelReader {
fn poll_read(mut self: pin::Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<std::io::Result<usize>> {
let stream = pin::pin!(&mut self.stream);
stream.poll_read(cx, buf)
}
derive_async_read!(L2capChannel, reader);
derive_async_write!(L2capChannel, writer);

pub struct L2capChannelReader {
stream: piper::Reader,
_closer: Arc<L2capCloser>,
}

derive_async_read!(L2capChannelReader, stream);

impl fmt::Debug for L2capChannelReader {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("L2capChannelReader")
Expand All @@ -177,34 +178,10 @@ impl fmt::Debug for L2capChannelReader {

pub struct L2capChannelWriter {
stream: piper::Writer,
closer: Arc<L2capCloser>,
}

impl L2capChannelWriter {
pub async fn close(&mut self) -> Result<()> {
self.closer.close();
Ok(())
}
_closer: Arc<L2capCloser>,
}

impl AsyncWrite for L2capChannelWriter {
fn poll_write(mut self: pin::Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<std::io::Result<usize>> {
let stream = pin::pin!(&mut self.stream);
let ret = stream.poll_write(cx, buf);
ret
}

fn poll_flush(mut self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<std::io::Result<()>> {
let stream = pin::pin!(&mut self.stream);
stream.poll_flush(cx)
}

fn poll_close(mut self: pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
self.closer.close();
let stream = pin::pin!(&mut self.stream);
stream.poll_close(cx)
}
}
derive_async_write!(L2capChannelWriter, stream);

impl fmt::Debug for L2capChannelWriter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down
14 changes: 9 additions & 5 deletions src/bluer/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ use std::sync::Arc;
use futures_core::Stream;
use futures_lite::StreamExt;

#[cfg(feature = "l2cap")]
use super::l2cap_channel::{L2capChannelReader, L2capChannelWriter};
use super::DeviceId;
use crate::device::ServicesChanged;
use crate::error::ErrorKind;
Expand Down Expand Up @@ -296,10 +294,16 @@ impl DeviceImpl {
#[cfg(feature = "l2cap")]
pub async fn open_l2cap_channel(
&self,
_psm: u16,
psm: u16,
_secure: bool,
) -> std::prelude::v1::Result<(L2capChannelReader, L2capChannelWriter), crate::Error> {
Err(ErrorKind::NotSupported.into())
) -> Result<super::l2cap_channel::L2capChannel, crate::Error> {
use async_compat::Compat;
use bluer::l2cap::{SocketAddr, Stream as L2CapStream};
use bluer::AddressType;

let target_sa = SocketAddr::new(self.inner.address(), AddressType::LePublic, psm);
let stream = L2CapStream::connect(target_sa).await?;
Ok(super::l2cap_channel::L2capChannel(Compat::new(stream)))
}
}

Expand Down
31 changes: 31 additions & 0 deletions src/bluer/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,34 @@ fn kind_from_bluer(err: &bluer::Error) -> ErrorKind {
_ => ErrorKind::Other,
}
}

#[cfg(feature = "l2cap")]
impl From<std::io::Error> for crate::Error {
fn from(err: std::io::Error) -> Self {
crate::Error::new(kind_from_io(&err.kind()), Some(Box::new(err)), String::new())
}
}

#[cfg(feature = "l2cap")]
fn kind_from_io(err: &std::io::ErrorKind) -> ErrorKind {
use std::io::ErrorKind as StdErrorKind;

match err {
StdErrorKind::NotFound => ErrorKind::NotFound,
StdErrorKind::PermissionDenied => ErrorKind::NotAuthorized,
StdErrorKind::ConnectionRefused
| StdErrorKind::ConnectionReset
| StdErrorKind::HostUnreachable
| StdErrorKind::NetworkUnreachable
| StdErrorKind::ConnectionAborted => ErrorKind::ConnectionFailed,
StdErrorKind::NotConnected => ErrorKind::NotConnected,
StdErrorKind::AddrNotAvailable | StdErrorKind::NetworkDown | StdErrorKind::ResourceBusy => {
ErrorKind::AdapterUnavailable
}
StdErrorKind::TimedOut => ErrorKind::Timeout,
StdErrorKind::Unsupported => ErrorKind::NotSupported,
StdErrorKind::Other => ErrorKind::Other,
// None of the other errors have semantic meaning for us
_ => ErrorKind::Internal,
}
}
64 changes: 31 additions & 33 deletions src/bluer/l2cap_channel.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,49 @@
#![cfg(feature = "l2cap")]

use std::pin::Pin;
use std::task::Context;
use std::fmt::Debug;
use std::pin;
use std::task::{Context, Poll};

use async_compat::Compat;
use bluer::l2cap::stream::{OwnedReadHalf, OwnedWriteHalf};
use bluer::l2cap::Stream;
use futures_lite::io::{AsyncRead, AsyncWrite};

#[derive(Debug)]
pub struct L2capChannelReader {
_private: (),
}
use crate::l2cap_channel::{derive_async_read, derive_async_write};

impl L2capChannelReader {
pub async fn close(&mut self) -> crate::Result<()> {
todo!()
}
}
pub struct L2capChannel(pub(super) Compat<Stream>);

impl AsyncRead for L2capChannelReader {
fn poll_read(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
_buf: &mut [u8],
) -> std::task::Poll<std::io::Result<usize>> {
todo!()
impl L2capChannel {
pub fn split(self) -> (L2capChannelReader, L2capChannelWriter) {
let (reader, writer) = self.0.into_inner().into_split();
let (reader, writer) = (Compat::new(reader), Compat::new(writer));
(L2capChannelReader { reader }, L2capChannelWriter { writer })
}
}
#[derive(Debug)]
pub struct L2capChannelWriter {
_private: (),

derive_async_read!(L2capChannel, 0);
derive_async_write!(L2capChannel, 0);

pub struct L2capChannelReader {
pub(crate) reader: Compat<OwnedReadHalf>,
}

impl L2capChannelWriter {
pub async fn close(&mut self) -> crate::Result<()> {
todo!()
derive_async_read!(L2capChannelReader, reader);

impl Debug for L2capChannelReader {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(self.reader.get_ref(), f)
}
}

impl AsyncWrite for L2capChannelWriter {
fn poll_write(self: Pin<&mut Self>, _cx: &mut Context<'_>, _buf: &[u8]) -> std::task::Poll<std::io::Result<usize>> {
todo!()
}
pub struct L2capChannelWriter {
pub(crate) writer: Compat<OwnedWriteHalf>,
}

fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> std::task::Poll<std::io::Result<()>> {
todo!()
}
derive_async_write!(L2capChannelWriter, writer);

fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> std::task::Poll<std::io::Result<()>> {
todo!()
impl Debug for L2capChannelWriter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(self.writer.get_ref(), f)
}
}
8 changes: 2 additions & 6 deletions src/corebluetooth/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,7 @@ impl DeviceImpl {

/// Open L2CAP channel given PSM
#[cfg(feature = "l2cap")]
pub async fn open_l2cap_channel(
&self,
psm: u16,
_secure: bool,
) -> Result<(L2capChannelReader, L2capChannelWriter)> {
pub async fn open_l2cap_channel(&self, psm: u16, _secure: bool) -> Result<super::l2cap_channel::L2capChannel> {
use tracing::{debug, info};

let mut receiver = self.delegate.sender().new_receiver();
Expand Down Expand Up @@ -267,7 +263,7 @@ impl DeviceImpl {
let reader = L2capChannelReader::new(l2capchannel.clone());
let writer = L2capChannelWriter::new(l2capchannel);

Ok((reader, writer))
Ok(super::l2cap_channel::L2capChannel { reader, writer })
}
}

Expand Down
40 changes: 18 additions & 22 deletions src/corebluetooth/l2cap_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ use objc2_foundation::{
use tracing::{debug, trace, warn};

use super::dispatch::Dispatched;
use crate::l2cap_channel::PIPE_CAPACITY;
use crate::Result;
use crate::l2cap_channel::{derive_async_read, derive_async_write, PIPE_CAPACITY};

/// Utility struct to close the channel on drop.
pub(super) struct L2capCloser {
Expand All @@ -43,10 +42,24 @@ impl Drop for L2capCloser {
}
}

pub struct L2capChannel {
pub(super) reader: L2capChannelReader,
pub(super) writer: L2capChannelWriter,
}

impl L2capChannel {
pub fn split(self) -> (L2capChannelReader, L2capChannelWriter) {
(self.reader, self.writer)
}
}

derive_async_read!(L2capChannel, reader);
derive_async_write!(L2capChannel, writer);

/// The reader side of an L2CAP channel.
pub struct L2capChannelReader {
stream: piper::Reader,
closer: Arc<L2capCloser>,
_closer: Arc<L2capCloser>,
_delegate: Retained<InputStreamDelegate>,
}

Expand All @@ -70,23 +83,12 @@ impl L2capChannelReader {
Self {
stream: read_rx,
_delegate: delegate,
closer,
_closer: closer,
}
}

/// Closes the L2CAP channel reader.
pub async fn close(&mut self) -> Result<()> {
self.closer.close();
Ok(())
}
}

impl AsyncRead for L2capChannelReader {
fn poll_read(mut self: pin::Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<std::io::Result<usize>> {
let stream = pin::pin!(&mut self.stream);
stream.poll_read(cx, buf)
}
}
derive_async_read!(L2capChannelReader, stream);

impl fmt::Debug for L2capChannelReader {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down Expand Up @@ -136,12 +138,6 @@ impl L2capChannelWriter {
center.postNotificationName_object(&name, None);
}
}

/// Closes the L2CAP channel writer.
pub async fn close(&mut self) -> Result<()> {
self.closer.close();
Ok(())
}
}

impl AsyncWrite for L2capChannelWriter {
Expand Down
Loading
Loading