1use fuchsia_bluetooth::types::Channel;
6use futures::stream::{FusedStream, TryStreamExt};
7use log::{info, trace};
8use packet_encoding::Encodable;
9use std::cell::{RefCell, RefMut};
10use std::pin::Pin;
11use std::task::{Context, Poll};
12
13use crate::error::{Error, PacketError};
14use crate::operation::{MAX_PACKET_SIZE, MIN_MAX_PACKET_SIZE, OpCode, ResponsePacket};
15
16pub fn max_packet_size_from_transport(transport_max: usize) -> u16 {
19 let bounded = transport_max.clamp(MIN_MAX_PACKET_SIZE, MAX_PACKET_SIZE);
20 bounded.try_into().expect("bounded by u16 max")
21}
22
23#[derive(Copy, Clone, Debug, PartialEq)]
25pub enum TransportType {
26 L2cap,
27 Rfcomm,
28}
29
30impl TransportType {
31 pub fn srm_supported(&self) -> bool {
32 match &self {
33 Self::L2cap => true,
35 Self::Rfcomm => false,
39 }
40 }
41}
42
43#[derive(Debug)]
45pub struct ObexTransport<'a> {
46 channel: RefMut<'a, Channel>,
49 type_: TransportType,
51}
52
53impl<'a> ObexTransport<'a> {
54 pub fn new(channel: RefMut<'a, Channel>, type_: TransportType) -> Self {
55 Self { channel, type_ }
56 }
57
58 pub fn srm_supported(&self) -> bool {
60 self.type_.srm_supported()
61 }
62
63 pub async fn receive_response(&mut self, code: OpCode) -> Result<ResponsePacket, Error> {
68 if self.channel.is_terminated() {
69 return Err(Error::PeerDisconnected);
70 }
71
72 match self.channel.try_next().await? {
73 Some(raw_data) => {
74 let decoded = ResponsePacket::decode(&raw_data[..], code)?;
75 trace!("Received response: {decoded:?}");
76 Ok(decoded)
77 }
78 None => {
79 info!("OBEX transport closed");
80 Err(Error::PeerDisconnected)
81 }
82 }
83 }
84}
85
86impl<'a, T> futures::sink::Sink<T> for ObexTransport<'a>
87where
88 T: Encodable<Error = PacketError>,
89{
90 type Error = Error;
91
92 fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
93 let this = self.get_mut();
94 Pin::new(&mut *this.channel).poll_ready(cx).map_err(Into::into)
95 }
96
97 fn start_send(self: Pin<&mut Self>, data: T) -> Result<(), Self::Error> {
98 let mut buf = vec![0; data.encoded_len()];
99 data.encode(&mut buf[..])?;
100 let this = self.get_mut();
101 Pin::new(&mut *this.channel).start_send(buf).map_err(Into::into)
102 }
103
104 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
105 let this = self.get_mut();
106 Pin::new(&mut *this.channel).poll_flush(cx).map_err(Into::into)
107 }
108
109 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
110 let this = self.get_mut();
111 Pin::new(&mut *this.channel).poll_close(cx).map_err(Into::into)
112 }
113}
114
115#[derive(Debug)]
118pub struct ObexTransportManager {
119 channel: RefCell<Channel>,
125 type_: TransportType,
127}
128
129impl ObexTransportManager {
130 pub fn new(channel: Channel, type_: TransportType) -> Self {
131 Self { channel: RefCell::new(channel), type_ }
132 }
133
134 fn new_permit(&self) -> Result<RefMut<'_, Channel>, Error> {
135 self.channel.try_borrow_mut().map_err(|_| Error::OperationInProgress)
136 }
137
138 pub fn is_transport_closed(&self) -> bool {
139 self.channel.try_borrow().map_or(false, |chan| chan.is_closed())
140 }
141
142 pub fn try_new_operation(&self) -> Result<ObexTransport<'_>, Error> {
143 let channel = self.new_permit()?;
145 Ok(ObexTransport::new(channel, self.type_))
146 }
147}
148
149#[cfg(test)]
150pub(crate) mod test_utils {
151 use super::*;
152 use bt_channel_test_support::{Transport, create_test_channels};
153 use futures::SinkExt;
154
155 use async_test_helpers::expect_stream_item;
156 use fuchsia_async as fasync;
157 use packet_encoding::Decodable;
158
159 use crate::operation::RequestPacket;
160
161 pub(crate) fn new_manager(
163 transport: Transport,
164 srm_supported: bool,
165 ) -> (ObexTransportManager, Channel) {
166 let (local, remote) = create_test_channels(transport);
167 let type_ = if srm_supported { TransportType::L2cap } else { TransportType::Rfcomm };
168 let manager = ObexTransportManager::new(local, type_);
169 (manager, remote)
170 }
171
172 #[derive(Clone)]
173 pub struct TestPacket(pub u8);
174
175 impl Encodable for TestPacket {
176 type Error = PacketError;
177 fn encoded_len(&self) -> usize {
178 1
179 }
180 fn encode(&self, buf: &mut [u8]) -> Result<(), Self::Error> {
181 buf[0] = self.0;
182 Ok(())
183 }
184 }
185
186 impl Decodable for TestPacket {
187 type Error = PacketError;
188 fn decode(buf: &[u8]) -> Result<Self, Self::Error> {
189 Ok(TestPacket(buf[0]))
190 }
191 }
192
193 #[track_caller]
194 fn assert_write_initiated(res: Poll<Result<(), zx::Status>>) {
195 match res {
196 Poll::Ready(Err(e)) => panic!("Write failed: {:?}", e),
197 _ => {}
198 }
199 }
200
201 #[track_caller]
202 pub fn reply(exec: &mut fasync::TestExecutor, channel: &mut Channel, response: ResponsePacket) {
203 let mut response_buf = vec![0; response.encoded_len()];
204 response.encode(&mut response_buf[..]).expect("can encode response");
205 let mut fut = channel.send(response_buf.to_vec());
206 assert_write_initiated(exec.run_until_stalled(&mut fut));
207 }
208
209 #[track_caller]
210 pub fn send_packet<T>(exec: &mut fasync::TestExecutor, channel: &mut Channel, packet: T)
211 where
212 T: Encodable,
213 <T as Encodable>::Error: std::fmt::Debug,
214 {
215 let mut buf = vec![0; packet.encoded_len()];
216 packet.encode(&mut buf[..]).expect("can encode packet");
217 let mut fut = channel.send(buf.to_vec());
218 assert_write_initiated(exec.run_until_stalled(&mut fut));
219 }
220
221 #[track_caller]
222 pub fn expect_request<F>(exec: &mut fasync::TestExecutor, channel: &mut Channel, expectation: F)
223 where
224 F: FnOnce(RequestPacket),
225 {
226 let request_raw = expect_stream_item(exec, channel).expect("request");
227 let request = RequestPacket::decode(&request_raw[..]).expect("can decode request");
228 expectation(request);
229 }
230
231 #[track_caller]
232 pub fn expect_response<F>(
233 exec: &mut fasync::TestExecutor,
234 channel: &mut Channel,
235 expectation: F,
236 opcode: OpCode,
237 ) where
238 F: FnOnce(ResponsePacket),
239 {
240 let request_raw = expect_stream_item(exec, channel).expect("request");
241 let request = ResponsePacket::decode(&request_raw[..], opcode).expect("can decode request");
242 expectation(request);
243 }
244
245 #[track_caller]
248 pub fn expect_request_and_reply<F>(
249 exec: &mut fasync::TestExecutor,
250 channel: &mut Channel,
251 expectation: F,
252 response: ResponsePacket,
253 ) where
254 F: FnOnce(RequestPacket),
255 {
256 expect_request(exec, channel, expectation);
257 reply(exec, channel, response)
258 }
259
260 pub fn expect_code(code: OpCode) -> impl FnOnce(RequestPacket) {
261 let f = move |request: RequestPacket| {
262 assert_eq!(*request.code(), code);
263 };
264 f
265 }
266}
267
268#[cfg(test)]
269mod tests {
270 use super::*;
271 use bt_channel_test_support::Transport;
272 use futures::SinkExt;
273 use test_case::test_case;
274
275 use assert_matches::assert_matches;
276
277 use async_utils::PollExt;
278 use fuchsia_async as fasync;
279 use std::pin::pin;
280
281 use crate::header::HeaderSet;
282 use crate::operation::{RequestPacket, ResponseCode};
283 use crate::transport::test_utils::{
284 TestPacket, expect_code, expect_request_and_reply, new_manager,
285 };
286
287 #[test_case(Transport::Socket ; "socket")]
288 #[test_case(Transport::Fidl ; "fidl")]
289 #[fuchsia::test]
290 fn transport_manager_new_operation(transport: Transport) {
291 let mut exec = fasync::TestExecutor::new();
292 let (manager, _remote) = new_manager(transport, false);
293
294 assert_matches!(manager.new_permit(), Ok(_));
296
297 let transport1 = manager.try_new_operation().expect("can start operation");
299 assert_matches!(manager.try_new_operation(), Err(Error::OperationInProgress));
301
302 drop(transport1);
304 let mut transport2 = manager.try_new_operation().expect("can start another operation");
305 let request = RequestPacket::new_connect(100, HeaderSet::new());
306 let mut send_fut = pin!(transport2.send(request));
307 exec.run_until_stalled(&mut send_fut)
308 .expect("send result ready")
309 .expect("can send request");
310 }
311
312 #[test_case(Transport::Socket ; "socket")]
313 #[test_case(Transport::Fidl ; "fidl")]
314 #[fuchsia::test]
315 fn send_and_receive(transport: Transport) {
316 let mut exec = fasync::TestExecutor::new();
317 let (manager, mut remote) = new_manager(transport, false);
318 let mut transport = manager.try_new_operation().expect("can start operation");
319
320 let request = RequestPacket::new_connect(100, HeaderSet::new());
322 {
323 let mut send_fut = pin!(transport.send(request));
324 exec.run_until_stalled(&mut send_fut)
325 .expect("send result ready")
326 .expect("can send request");
327 }
328 let peer_response =
330 ResponsePacket::new(ResponseCode::Ok, vec![0x10, 0x00, 0x00, 0xff], HeaderSet::new());
331 expect_request_and_reply(
332 &mut exec,
333 &mut remote,
334 expect_code(OpCode::Connect),
335 peer_response,
336 );
337 let receive_fut = transport.receive_response(OpCode::Connect);
339 let mut receive_fut = pin!(receive_fut);
340 let received_response = exec
341 .run_until_stalled(&mut receive_fut)
342 .expect("stream item from response")
343 .expect("valid response");
344 assert_eq!(*received_response.code(), ResponseCode::Ok);
345 }
346
347 #[test_case(Transport::Socket ; "socket")]
348 #[test_case(Transport::Fidl ; "fidl")]
349 #[fuchsia::test]
350 async fn send_while_channel_closed_is_error(transport: Transport) {
351 let (manager, remote) = new_manager(transport, false);
352 let mut transport = manager.try_new_operation().expect("can start operation");
353 drop(remote);
354
355 let data = TestPacket(10);
356 let send_result = transport.send(data.clone()).await;
357 assert_matches!(send_result, Err(Error::IOError(_)));
358 let send_result = transport.send(data.clone()).await;
360 assert_matches!(send_result, Err(Error::IOError(_)));
361 }
362
363 #[test_case(Transport::Socket ; "socket")]
364 #[test_case(Transport::Fidl ; "fidl")]
365 #[fuchsia::test]
366 fn is_transport_closed(transport: Transport) {
367 let mut exec = fasync::TestExecutor::new();
368 let (manager, remote) = new_manager(transport, false);
369 assert!(!manager.is_transport_closed());
370
371 {
372 let _transport = manager.try_new_operation().expect("can start operation");
373 assert!(!manager.is_transport_closed());
374
375 drop(remote);
378 let _ = exec.run_until_stalled(&mut futures::future::pending::<()>());
379 assert!(!manager.is_transport_closed());
380 }
381
382 assert!(manager.is_transport_closed());
385 }
386
387 #[test_case(Transport::Socket ; "socket")]
388 #[test_case(Transport::Fidl ; "fidl")]
389 #[fuchsia::test]
390 async fn receive_while_channel_closed_is_error(transport: Transport) {
391 let (manager, remote) = new_manager(transport, false);
392 let mut transport = manager.try_new_operation().expect("can start operation");
393 drop(remote);
394
395 let receive_result = transport.receive_response(OpCode::Connect).await;
396 assert_matches!(receive_result, Err(Error::PeerDisconnected));
397 let receive_result = transport.receive_response(OpCode::Connect).await;
399 assert_matches!(receive_result, Err(Error::PeerDisconnected));
400 }
401}