imsg_map/mns_server.rs
1//! MNS OBEX server — accepts connections from the remote device and yields MAP event reports.
2
3use bytes::Bytes;
4use futures::{SinkExt, StreamExt};
5use obex_core::{packet::OpCode, server::ObexServer};
6use obex_core::{wrap, ObexTransport};
7use tokio::io::{AsyncRead, AsyncWrite};
8
9use crate::mns_event::{parse_event_report, MnsError, MnsEvent};
10
11const MNS_TARGET: [u8; 16] = [
12 0xbb, 0x58, 0x2b, 0x41, 0x42, 0x0c, 0x11, 0xdb, 0xb0, 0xde, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66,
13];
14
15/// MNS OBEX server. Receives a connection from the remote device on the MNS RFCOMM channel,
16/// performs the OBEX handshake, and yields MAP event reports via [`next_event`](Self::next_event).
17///
18/// Obtain via [`MnsServer::accept`].
19pub struct MnsServer<T> {
20 transport: ObexTransport<T>,
21}
22
23impl<T: AsyncRead + AsyncWrite + Unpin> MnsServer<T> {
24 /// Wraps `stream` in OBEX framing, performs the OBEX CONNECT handshake as the MNS server,
25 /// and validates the `Target` UUID against the MNS service UUID.
26 ///
27 /// # Errors
28 ///
29 /// Returns [`MnsError::InvalidTarget`] if the CONNECT request Target header is absent or
30 /// does not match `bb582b41-420c-11db-b0de-0800200c9a66`. Returns [`MnsError::Obex`] on
31 /// packet decode failure or [`MnsError::Transport`] on I/O failure.
32 pub async fn accept(stream: T) -> Result<Self, MnsError> {
33 let mut transport = wrap(stream);
34 let mut server = ObexServer::new();
35 let req = Self::recv(&mut transport).await?;
36 let (packet, rsp) = server.handle_connect(&req, &MNS_TARGET)?;
37 if packet.header_target() != Some(MNS_TARGET.as_ref()) {
38 return Err(MnsError::InvalidTarget);
39 }
40 transport.send(rsp).await?;
41 Ok(Self { transport })
42 }
43
44 /// Returns the raw event-report XML body bytes from the next OBEX PUT, or `None` on
45 /// OBEX DISCONNECT. Handles the full OBEX exchange. Does not parse the body — callers
46 /// needing a typed [`MnsEvent`] should call [`next_event`](Self::next_event) instead.
47 ///
48 /// # Errors
49 ///
50 /// Returns [`MnsError::UnexpectedOpcode`] if the device sends an opcode other than PUT,
51 /// `PUT_FINAL`, or DISCONNECT. Returns [`MnsError::UnexpectedEof`] if the stream closes
52 /// mid-packet. Returns [`MnsError::Transport`] on I/O failure.
53 pub async fn next_event_raw(&mut self) -> Result<Option<Bytes>, MnsError> {
54 let bytes = Self::recv(&mut self.transport).await?;
55 let opcode = bytes.first().copied().ok_or(MnsError::UnexpectedEof)?;
56 match OpCode::from_byte(opcode) {
57 OpCode::Put | OpCode::PutFinal => {
58 let (body, rsp) = ObexServer::handle_put(&bytes)?;
59 self.transport.send(rsp).await?;
60 Ok(Some(body.unwrap_or_default()))
61 }
62 OpCode::Disconnect => {
63 self.transport.send(ObexServer::ok_response()).await?;
64 Ok(None)
65 }
66 other => {
67 let _ = self.transport.send(ObexServer::bad_request_response()).await;
68 Err(MnsError::UnexpectedOpcode(other.to_byte()))
69 }
70 }
71 }
72
73 /// Returns `Ok(None)` when the device sends a clean OBEX DISCONNECT.
74 ///
75 /// # Errors
76 ///
77 /// Returns [`MnsError::UnexpectedOpcode`] if the device sends an opcode other than PUT,
78 /// `PUT_FINAL`, or DISCONNECT. Returns [`MnsError::UnexpectedEof`] if the stream closes
79 /// mid-packet. XML parse errors from [`parse_event_report`] are propagated unchanged.
80 pub async fn next_event(&mut self) -> Result<Option<MnsEvent>, MnsError> {
81 match self.next_event_raw().await? {
82 Some(body) => Ok(Some(parse_event_report(&body)?)),
83 None => Ok(None),
84 }
85 }
86
87 async fn recv(transport: &mut ObexTransport<T>) -> Result<Bytes, MnsError> {
88 transport.next().await.ok_or(MnsError::UnexpectedEof)?.map_err(MnsError::Transport)
89 }
90}