-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Linux and CoreBluetooth L2Cap Channels #18
Conversation
I intentionally did not do this, I don't think we should do it. AsyncRead/AsyncWrite (and std::io::Read/Write) model a byte stream. This is a "pipe" with some bytes in the buffer, where L2CAP channels are NOT byte streams. They're packet streams. The "buffer" holds packets of a known size ( This distinction is important because higher layers building on top of L2CAP channels can use the packet boundaries as framing. For example the IPSP protocol sends IPv6 packets as L2CAP packets. It needs a packet stream, it wouldn't work over a byte stream because reads could return half of an IPv6 packet, or two IPv6 packets smooshed together. See how std's UdpSocket doesn't implement Read/Write, while TcpSocket does. This is because UdpSocket is also packet-based, like L2CAP CoC channels. |
I still think that having the stream option is useful, but I also see your point about preserving any information from packet boundaries. How about we emulate |
stream l2cap channels are BR/EDR only (Bluetooth Classic only). Bluetooth Low Energy only has packet-based l2cap channels, and this library focuses only on BLE. |
The connect/bind APIs for the socket types that @abezukor linked allow passing in a |
If you read the bluetooth Core Specification, it says the only allowed L2CAP modes of operation for BLE are
And "LE Credit Based Flow Control Mode" is packet-based. All the other modes (Flow Control Mode, Retransmission Mode, Enhanced Retransmission Mode, Streaming Mode, Enhanced Credit Based Flow Control Mode) are BR/EDR-only. They're not usable on BLE. I don't know what Linux/BlueZ does if you request a channel of the "wrong" type in BLE. Perhaps it behaves wrong, perhaps it helpfully emulates a byte-stream by buffering packets and letting you read/write individual bytes off packets. The Android/iOS APIs don't do that, and I'm not convinced bluest should be the one emulating it. |
@Dirbaio are you sure the Android and CoreBluetooth interfaces operate in packet mode? They both seem to use the generic byte stream types from their respective platforms. For example, if the device sends two packets over an L2CAP channel before the host calls calls If Android, iOS and Linux all provide an effective packet-based interface to the L2CAP channel, then I agree that we should preserve that functionality. However, if they actually treat them as generic byte streams I don't think we can count on packet based behavior without introducing race conditions. |
A few notes from some tests that I have ran
|
Thanks @abezukor. I suspect Android is also using a stream-oriented channel instead of a packet oriented one, though the documentation is not completely clear. Based on that it seems that Linux is the only platform to support a packet oriented L2CAP connection. Since Bluest aims to be cross platform and target the lowest-common-denominator between platforms, I think the stream model is what we need to support. However, I'm not keen in making Tokio a required dependency or async runtime for users of Bluest on non-Linux platforms, even if L2CAP is an optional feature. I would rather implement the I'd also like to see minimal changes to the existing Android implementation and the root |
There are two reasons that I used the tokio version instead of the futures version
#[cfg(target_os = "linux")]
use tokio::io::AsyncReadExt;
#[cfg(not(target_os = "linux"))]
use futures_util::io::AsyncReadExt Additionally some functions are only available in either
I will also note that tokio is only a required dependency if the |
Agreed. We need to use the
Minimizing both the number and weight of dependencies is a major design consideration for bluest and maintaining async runtime agnosticism is a high priority (with the exception of Linux since |
For my usecase, I need the Regardless, I will not have time to work on this in the near future, so I am closing this PR. If someone else wants to pick it up, feel free. |
Yes, that would be fine. Tokio does come with adapters for the futures versions. |
Partly Addresses #3.
This PR does 3 things.
AsyncRead + AsyncWrite
. These traits seem better than using customread
andwrite
methods as they integrate better with the rest of the rust async ecosystem. They also haveread
andwrite
methods. I am using the tokio versions instead of the futures versions because the bluer (Linux) implementation relies on the tokio version and making an adapter seems like unnecessary complexity. I also think it is important to keep the interface the same for all platforms. Note thatbluest
can still be used without tokio if thel2cap
feature is disabled.I have only tested on MacOS, IOS, and Linux. I have written an android implementation but it may have bugs, or be entirely the wrong way of doing things. @Dirbaio can you take a look at the android code?