Skip to main content

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}