bt_obex/
operation.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use bitflags::bitflags;
6use core::fmt::Debug;
7use packet_encoding::{decodable_enum, Decodable, Encodable};
8use std::cmp::PartialEq;
9
10use crate::error::{Error, PacketError};
11use crate::header::{HeaderIdentifier, HeaderSet};
12
13/// The current OBEX Protocol version number is 1.0.
14/// The protocol version is not necessarily the same as the specification version.
15/// Defined in OBEX 1.5 Section 3.4.1.1.
16const OBEX_PROTOCOL_VERSION_NUMBER: u8 = 0x10;
17
18/// The maximum length of an OBEX packet is bounded by the 2-byte field describing the packet
19/// length (u16::MAX).
20/// Defined in OBEX 1.5 Section 3.4.1.3.
21pub const MAX_PACKET_SIZE: usize = std::u16::MAX as usize;
22
23/// The minimum size of the OBEX maximum packet length is 255 bytes.
24/// Defined in OBEX 1.5. Section 3.4.1.4.
25pub const MIN_MAX_PACKET_SIZE: usize = 255;
26
27bitflags! {
28    /// The flags used in a SetPath operation.
29    /// Defined in OBEX 1.5 Section 3.4.6.1.
30    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
31    pub struct SetPathFlags: u8 {
32        /// Backup a directory level before applying (e.g. `../` on some systems).
33        const BACKUP = 0b0000_0001;
34        /// Don't create a folder if it does not exist. Return an Error instead.
35        const DONT_CREATE = 0b0000_0010;
36    }
37}
38
39#[derive(Debug, Clone, Copy, PartialEq)]
40#[repr(u8)]
41pub enum OpCode {
42    Connect = 0x80,
43    Disconnect = 0x81,
44    Put = 0x02,
45    PutFinal = 0x82,
46    Get = 0x03,
47    GetFinal = 0x83,
48    Reserved = 0x04,
49    ReservedFinal = 0x84,
50    SetPath = 0x85,
51    Action = 0x06,
52    ActionFinal = 0x86,
53    Session = 0x87,
54    /// 0x08 to 0x0F are reserved and not used in OBEX.
55    /// 0x10 to 0x1f are user defined.
56    User(u8),
57    Abort = 0xff,
58}
59
60impl OpCode {
61    fn final_bit_set(v: u8) -> bool {
62        (v & 0x80) != 0
63    }
64
65    fn is_user(code: u8) -> bool {
66        // Defined in OBEX 1.5 Section 3.4.
67        code >= 0x10 && code <= 0x1f
68    }
69
70    fn is_reserved(code: u8) -> bool {
71        // Defined in OBEX 1.5 Section 3.4.
72        code >= 0x08 && code <= 0x0f
73    }
74
75    /// Returns true if the Final bit is set.
76    pub fn is_final(&self) -> bool {
77        let opcode_raw: u8 = self.into();
78        Self::final_bit_set(opcode_raw)
79    }
80
81    /// Returns the expected optional request data length (in bytes) if the Operation is expected to
82    /// include request data.
83    /// Returns 0 if the Operation is not expected to contain any data.
84    /// See OBEX 1.5 Section 3.4 for more details on the specifics of the Operations.
85    fn request_data_length(&self) -> usize {
86        match &self {
87            Self::Connect => 4, // OBEX Version (1) + Flags (1) + Max Packet Length (2)
88            Self::SetPath => 2, // Flags (1) + Constants (1)
89            _ => 0,             // All other operation requests don't require additional data
90        }
91    }
92
93    /// Returns the expected optional response data length (in bytes) if the Operation is expected
94    /// to include response data.
95    /// Returns 0 if the Operation is not expected to contain any data.
96    /// See OBEX 1.5 Section 3.4 for more details on the specifics of the Operations.
97    pub fn response_data_length(&self) -> usize {
98        match &self {
99            Self::Connect => 4, // OBEX Version (1) + flags (1) + Max Packet Length (2)
100            _ => 0,             // All other operation responses don't require additional data
101        }
102    }
103}
104
105impl Into<u8> for &OpCode {
106    fn into(self) -> u8 {
107        match &self {
108            OpCode::Connect => 0x80,
109            OpCode::Disconnect => 0x81,
110            OpCode::Put => 0x02,
111            OpCode::PutFinal => 0x82,
112            OpCode::Get => 0x03,
113            OpCode::GetFinal => 0x83,
114            OpCode::Reserved => 0x04,
115            OpCode::ReservedFinal => 0x84,
116            OpCode::SetPath => 0x85,
117            OpCode::Action => 0x06,
118            OpCode::ActionFinal => 0x86,
119            OpCode::Session => 0x87,
120            OpCode::User(v) => *v,
121            OpCode::Abort => 0xff,
122        }
123    }
124}
125
126impl TryFrom<u8> for OpCode {
127    type Error = PacketError;
128
129    fn try_from(src: u8) -> Result<OpCode, Self::Error> {
130        // The Abort operation is unique in that it uses all bits in the opcode.
131        if src == 0xff {
132            return Ok(OpCode::Abort);
133        }
134
135        // Per OBEX 1.5 Section 3.4, only bits 0-4 are used to determine the OpCode. Bits 5,6
136        // should be unset and are ignored. Bit 7 (msb) represents the final bit.
137        const FINAL_BIT_AND_OPCODE_BITMASK: u8 = 0x9f;
138        const OPCODE_BITMASK: u8 = 0x1f;
139        let src = src & FINAL_BIT_AND_OPCODE_BITMASK;
140        let is_final = OpCode::final_bit_set(src);
141        // Check the lower 5 bits for opcode.
142        match src & OPCODE_BITMASK {
143            0x00 if is_final => Ok(OpCode::Connect),
144            0x01 if is_final => Ok(OpCode::Disconnect),
145            0x02 if is_final => Ok(OpCode::PutFinal),
146            0x02 => Ok(OpCode::Put),
147            0x03 if is_final => Ok(OpCode::GetFinal),
148            0x03 => Ok(OpCode::Get),
149            0x04 if is_final => Ok(OpCode::ReservedFinal),
150            0x04 => Ok(OpCode::Reserved),
151            0x05 if is_final => Ok(OpCode::SetPath),
152            0x06 if is_final => Ok(OpCode::ActionFinal),
153            0x06 => Ok(OpCode::Action),
154            0x07 if is_final => Ok(OpCode::Session),
155            v if OpCode::is_user(v) => Ok(OpCode::User(src)), // Save the final bit.
156            v if OpCode::is_reserved(v) => Err(PacketError::Reserved),
157            _ => Err(PacketError::OpCode(src)),
158        }
159    }
160}
161
162/// An OBEX Packet that can be encoded/decoded to/from a raw byte buffer. This is sent over the
163/// L2CAP or RFCOMM transport.
164#[derive(Clone, Debug, PartialEq)]
165pub struct Packet<T>
166where
167    T: Clone + Debug + PartialEq,
168    for<'a> &'a T: Into<u8>,
169{
170    /// The code associated with the packet.
171    code: T,
172    /// The data associated with the packet (e.g. Flags, Packet Size, etc..). This can be empty.
173    /// Only used in the `OpCode::Connect` & `OpCode::SetPath` Operations.
174    data: Vec<u8>,
175    /// The headers describing the packet - there can be 0 or more headers included in the packet.
176    headers: HeaderSet,
177}
178
179impl<T> Packet<T>
180where
181    T: Clone + Debug + PartialEq,
182    for<'a> &'a T: Into<u8>,
183{
184    /// The minimum packet consists of an opcode (1 byte) and packet length (2 bytes).
185    pub const MIN_PACKET_SIZE: usize = 3;
186
187    pub fn new(code: T, data: Vec<u8>, headers: HeaderSet) -> Self {
188        Self { code, data, headers }
189    }
190
191    pub fn code(&self) -> &T {
192        &self.code
193    }
194
195    pub fn data(&self) -> &Vec<u8> {
196        &self.data
197    }
198
199    pub fn headers(&self) -> &HeaderSet {
200        &self.headers
201    }
202
203    /// Attempts to decode the body of `buf` into a `Packet`.
204    /// `optional_data_length` specifies the expected length of the packet data and can be 0.
205    fn decode_body(buf: &[u8], code: T, optional_data_length: usize) -> Result<Self, PacketError> {
206        // Potentially decode the optional request data.
207        let (headers_idx, data) = if optional_data_length != 0 {
208            if buf.len() < optional_data_length {
209                return Err(PacketError::BufferTooSmall);
210            }
211            let mut data = vec![0u8; optional_data_length];
212            data.copy_from_slice(&buf[..optional_data_length]);
213            (optional_data_length, data)
214        } else {
215            (0, vec![])
216        };
217
218        // Decode the headers.
219        let headers = HeaderSet::decode(&buf[headers_idx..])?;
220        Ok(Self::new(code, data, headers))
221    }
222}
223
224impl<T> Encodable for Packet<T>
225where
226    T: Clone + Debug + PartialEq,
227    for<'a> &'a T: Into<u8>,
228{
229    type Error = PacketError;
230
231    fn encoded_len(&self) -> usize {
232        Self::MIN_PACKET_SIZE + self.data.len() + self.headers.encoded_len()
233    }
234
235    fn encode(&self, buf: &mut [u8]) -> Result<(), Self::Error> {
236        if buf.len() < self.encoded_len() {
237            return Err(PacketError::BufferTooSmall);
238        }
239
240        // Per OBEX 1.5 Section 3.1, the first byte contains the opcode and bytes 1,2 contain
241        // the packet length - this includes the opcode / length fields.
242        buf[0] = (&self.code).into();
243        let packet_length_bytes = (self.encoded_len() as u16).to_be_bytes();
244        buf[1..Self::MIN_PACKET_SIZE].copy_from_slice(&packet_length_bytes[..]);
245
246        // Encode the optional request data for relevant operations.
247        let headers_idx = if self.data.len() != 0 {
248            let end_idx = Self::MIN_PACKET_SIZE + self.data.len();
249            buf[Self::MIN_PACKET_SIZE..end_idx].copy_from_slice(&self.data[..]);
250            end_idx
251        } else {
252            Self::MIN_PACKET_SIZE
253        };
254
255        // Encode the headers.
256        self.headers.encode(&mut buf[headers_idx..])
257    }
258}
259
260impl<T> From<Packet<T>> for HeaderSet
261where
262    T: Clone + Debug + PartialEq,
263    for<'a> &'a T: Into<u8>,
264{
265    fn from(value: Packet<T>) -> Self {
266        value.headers
267    }
268}
269
270/// An OBEX request packet.
271/// Defined in OBEX 1.5 Section 3.1.
272pub type RequestPacket = Packet<OpCode>;
273
274impl RequestPacket {
275    /// Returns a CONNECT request packet with the provided `headers`.
276    pub fn new_connect(max_packet_size: u16, headers: HeaderSet) -> Self {
277        // The CONNECT request contains optional data - Version Number, Flags, Max Packet Size.
278        let mut data = vec![
279            OBEX_PROTOCOL_VERSION_NUMBER,
280            0, // All flags are currently reserved in a CONNECT request. See OBEX 3.4.1.2.
281        ];
282        data.extend_from_slice(&max_packet_size.to_be_bytes());
283        Self::new(OpCode::Connect, data, headers)
284    }
285
286    pub fn new_disconnect(headers: HeaderSet) -> Self {
287        Self::new(OpCode::Disconnect, vec![], headers)
288    }
289
290    pub fn new_get(headers: HeaderSet) -> Self {
291        Self::new(OpCode::Get, vec![], headers)
292    }
293
294    pub fn new_get_final(headers: HeaderSet) -> Self {
295        Self::new(OpCode::GetFinal, vec![], headers)
296    }
297
298    pub fn new_put(headers: HeaderSet) -> Self {
299        Self::new(OpCode::Put, vec![], headers)
300    }
301
302    pub fn new_put_final(headers: HeaderSet) -> Self {
303        Self::new(OpCode::PutFinal, vec![], headers)
304    }
305
306    pub fn new_set_path(flags: SetPathFlags, headers: HeaderSet) -> Result<Self, Error> {
307        // The Name header is mandatory in almost all cases. All other headers are optional.
308        // It is only considered optional when the request is to back up one level.
309        // See Section 3.4.6.3.
310        if !headers.contains_header(&HeaderIdentifier::Name)
311            && !flags.contains(SetPathFlags::BACKUP)
312        {
313            return Err(Error::operation(OpCode::SetPath, "name is required"));
314        }
315        // The request contains optional data - Flags & Constants. Constants are currently reserved
316        // and are set to 0. See Section 3.4.6.2.
317        let data = vec![flags.bits(), 0];
318        Ok(Self::new(OpCode::SetPath, data, headers))
319    }
320
321    pub fn new_abort(headers: HeaderSet) -> Self {
322        Self::new(OpCode::Abort, vec![], headers)
323    }
324}
325
326impl Decodable for RequestPacket {
327    type Error = PacketError;
328
329    fn decode(buf: &[u8]) -> Result<Self, Self::Error> {
330        if buf.len() < Self::MIN_PACKET_SIZE {
331            return Err(PacketError::BufferTooSmall);
332        }
333
334        let code = OpCode::try_from(buf[0])?;
335        let packet_length =
336            u16::from_be_bytes(buf[1..Self::MIN_PACKET_SIZE].try_into().expect("checked length"));
337
338        if buf.len() < packet_length.into() {
339            return Err(PacketError::BufferTooSmall);
340        }
341        // Decode the optional response data and headers.
342        Self::decode_body(&buf[Self::MIN_PACKET_SIZE..], code, code.request_data_length())
343    }
344}
345
346decodable_enum! {
347    /// Response codes that an OBEX server may send to the Client after receiving a request.
348    /// The most significant bit of the response code is the Final Bit. This is always set in OBEX
349    /// response codes - see OBEX 1.5 Section 3.2.
350    /// Defined in OBEX 1.5 Section 3.2.1.
351    pub enum ResponseCode<u8, PacketError, Reserved> {
352        Continue = 0x90,
353        Ok = 0xa0,
354        Created = 0xa1,
355        Accepted = 0xa2,
356        NonAuthoritativeInformation = 0xa3,
357        NoContent = 0xa4,
358        ResetContent = 0xa5,
359        PartialContent = 0xa6,
360        MultipleChoices = 0xb0,
361        MovedPermanently = 0xb1,
362        MovedTemporarily = 0xb2,
363        SeeOther = 0xb3,
364        NotModified = 0xb4,
365        UseProxy = 0xb5,
366        BadRequest = 0xc0,
367        Unauthorized = 0xc1,
368        PaymentRequired = 0xc2,
369        Forbidden = 0xc3,
370        NotFound = 0xc4,
371        MethodNotAllowed = 0xc5,
372        NotAcceptable = 0xc6,
373        ProxyAuthenticationRequired = 0xc7,
374        RequestTimeOut = 0xc8,
375        Conflict = 0xc9,
376        Gone = 0xca,
377        LengthRequired = 0xcb,
378        PreconditionFailed = 0xcc,
379        RequestedEntityTooLarge = 0xcd,
380        RequestedUrlTooLarge = 0xce,
381        UnsupportedMediaType = 0xcf,
382        InternalServerError = 0xd0,
383        NotImplemented = 0xd1,
384        BadGateway = 0xd2,
385        ServiceUnavailable = 0xd3,
386        GatewayTimeout = 0xd4,
387        HttpVersionNotSupported = 0xd5,
388        DatabaseFull = 0xe0,
389        DatabaseLocked = 0xe1,
390    }
391}
392
393/// An OBEX response packet.
394/// Defined in OBEX 1.5 Section 3.2.
395pub type ResponsePacket = Packet<ResponseCode>;
396
397impl ResponsePacket {
398    pub fn new_no_data(code: ResponseCode, headers: HeaderSet) -> Self {
399        Self::new(code, vec![], headers)
400    }
401
402    pub fn new_connect(code: ResponseCode, max_packet_size: u16, headers: HeaderSet) -> Self {
403        // The CONNECT response contains optional data - Version Number, Flags, Max Packet Size.
404
405        // Only Bit0 is defined for the CONNECT response. We currently do not support multiple
406        // lrMP connections.
407        const OBEX_CONNECT_RESPONSE_FLAGS: u8 = 0;
408        let mut data = vec![OBEX_PROTOCOL_VERSION_NUMBER, OBEX_CONNECT_RESPONSE_FLAGS];
409        data.extend_from_slice(&max_packet_size.to_be_bytes());
410        Self::new(code, data, headers)
411    }
412
413    pub fn new_disconnect(headers: HeaderSet) -> Self {
414        Self::new(ResponseCode::Ok, vec![], headers)
415    }
416
417    pub fn new_setpath(code: ResponseCode, headers: HeaderSet) -> Self {
418        Self::new(code, vec![], headers)
419    }
420
421    pub fn new_get(code: ResponseCode, headers: HeaderSet) -> Self {
422        Self::new(code, vec![], headers)
423    }
424
425    pub fn expect_code(self, request: OpCode, expected: ResponseCode) -> Result<Self, Error> {
426        if *self.code() == expected {
427            return Ok(self);
428        }
429        Err(Error::peer_rejected(request, *self.code()))
430    }
431
432    /// Attempts to decode the raw `buf` into a ResponsePacket for the provided `request` type.
433    // `Decodable` is not implemented for `ResponsePacket` because the `OpCode` is not included in
434    // a response packet. Because only one Operation can be outstanding, it is assumed that a
435    // response is associated with the most recently sent request.
436    pub fn decode(buf: &[u8], request: OpCode) -> Result<Self, PacketError> {
437        if buf.len() < Self::MIN_PACKET_SIZE {
438            return Err(PacketError::BufferTooSmall);
439        }
440
441        let code = ResponseCode::try_from(buf[0]).map_err(|_| PacketError::ResponseCode(buf[0]))?;
442        let packet_length =
443            u16::from_be_bytes(buf[1..Self::MIN_PACKET_SIZE].try_into().expect("checked length"));
444
445        if buf.len() < packet_length.into() {
446            return Err(PacketError::BufferTooSmall);
447        }
448        // Decode the optional response data and headers.
449        Self::decode_body(&buf[Self::MIN_PACKET_SIZE..], code, request.response_data_length())
450    }
451}
452
453#[cfg(test)]
454mod tests {
455    use super::*;
456
457    use assert_matches::assert_matches;
458
459    use crate::header::{ConnectionIdentifier, Header};
460
461    #[fuchsia::test]
462    fn convert_opcode_success() {
463        // Roundtrip with final disabled should succeed.
464        let raw = 0x02;
465        let converted = OpCode::try_from(raw).expect("valid opcode");
466        assert_eq!(converted, OpCode::Put);
467        assert!(!converted.is_final());
468        assert_eq!(converted.request_data_length(), 0);
469        assert_eq!(converted.response_data_length(), 0);
470        let converted_raw: u8 = (&converted).into();
471        assert_eq!(converted_raw, raw);
472
473        // Roundtrip with final enabled should succeed.
474        let raw = 0x84;
475        let converted = OpCode::try_from(raw).expect("valid opcode");
476        assert_eq!(converted, OpCode::ReservedFinal);
477        assert!(converted.is_final());
478        let converted_raw: u8 = (&converted).into();
479        assert_eq!(converted_raw, raw);
480
481        // Roundtrip for Abort should succeed (special).
482        let raw = 0xff;
483        let converted = OpCode::try_from(raw).expect("valid opcode");
484        assert_eq!(converted, OpCode::Abort);
485        assert!(converted.is_final());
486        let converted_raw: u8 = (&converted).into();
487        assert_eq!(converted_raw, raw);
488
489        // Roundtrip for an opcode with bits 5,6 set is OK. The bits are unused, and the
490        // receiving side should ignore.
491        let raw = 0xe5; // SetPath (0x85) with bits 5,6 set.
492        let converted = OpCode::try_from(raw).expect("valid opcode");
493        assert_eq!(converted, OpCode::SetPath);
494        assert!(converted.is_final());
495        let converted_raw: u8 = (&converted).into();
496        assert_eq!(converted_raw, 0x85); // We will never set bits 5,6.
497    }
498
499    #[fuchsia::test]
500    fn convert_user_opcode_success() {
501        // User opcode with final bit unset.
502        let user = 0x1a;
503        let converted = OpCode::try_from(user).expect("valid opcode");
504        assert_eq!(converted, OpCode::User(0x1a));
505        assert!(!converted.is_final());
506        let converted_raw: u8 = (&converted).into();
507        assert_eq!(converted_raw, user);
508
509        // User opcode with final bit set.
510        let user = 0x9d;
511        let converted = OpCode::try_from(user).expect("valid opcode");
512        assert_eq!(converted, OpCode::User(0x9d));
513        assert!(converted.is_final());
514        let converted_raw: u8 = (&converted).into();
515        // Final bit should be preserved when converting back.
516        assert_eq!(converted_raw, user);
517
518        // User opcode with bits 5,6 set. Bits 5,6 should be ignored.
519        let user = 0xf3;
520        let converted = OpCode::try_from(user).expect("valid opcode");
521        assert_eq!(converted, OpCode::User(0x93)); // Bits 5,6 should be zeroed out.
522        assert!(converted.is_final());
523        let converted_raw: u8 = (&converted).into();
524        assert_eq!(converted_raw, 0x93);
525    }
526
527    #[fuchsia::test]
528    fn convert_invalid_opcode_is_error() {
529        // A Disconnect OpCode without the final bit set is invalid.
530        let invalid = 0x01;
531        assert_matches!(OpCode::try_from(invalid), Err(PacketError::OpCode(_)));
532        // Opcode is reserved for future use.
533        let reserved = 0x08;
534        assert_matches!(OpCode::try_from(reserved), Err(PacketError::Reserved));
535        // Opcode is reserved for future use (final bit set).
536        let reserved = 0x8f;
537        assert_matches!(OpCode::try_from(reserved), Err(PacketError::Reserved));
538    }
539
540    #[fuchsia::test]
541    fn construct_setpath() {
542        // A request with all flags enabled & Name header is valid.
543        let headers = HeaderSet::from_header(Header::name("foo"));
544        let _request = RequestPacket::new_set_path(SetPathFlags::all(), headers.clone())
545            .expect("valid set path args");
546
547        // A request with no flags enabled & Name header is valid.
548        let _request = RequestPacket::new_set_path(SetPathFlags::empty(), headers)
549            .expect("valid set path args");
550
551        // A request to back up a level doesn't require a Name header.
552        let _request = RequestPacket::new_set_path(SetPathFlags::BACKUP, HeaderSet::new())
553            .expect("valid set path args");
554
555        // Otherwise, a request without a Name header is an Error.
556        assert_matches!(
557            RequestPacket::new_set_path(SetPathFlags::DONT_CREATE, HeaderSet::new()),
558            Err(Error::OperationError { .. })
559        );
560    }
561
562    #[fuchsia::test]
563    fn encode_request_packet_success() {
564        let headers = HeaderSet::from_headers(vec![Header::Permissions(2)]).unwrap();
565        let request = RequestPacket::new(OpCode::Abort, vec![], headers);
566        // 3 bytes for prefix + 5 bytes for Permissions Header.
567        assert_eq!(request.encoded_len(), 8);
568        let mut buf = vec![0; request.encoded_len()];
569        request.encode(&mut buf[..]).expect("can encode request");
570        let expected = [0xff, 0x00, 0x08, 0xd6, 0x00, 0x00, 0x00, 0x02];
571        assert_eq!(buf, expected);
572    }
573
574    #[fuchsia::test]
575    fn encode_request_packet_no_headers_success() {
576        // 3 bytes for prefix - no additional headers.
577        let request = RequestPacket::new(OpCode::Abort, vec![], HeaderSet::new());
578        assert_eq!(request.encoded_len(), 3);
579        let mut buf = vec![0; request.encoded_len()];
580        request.encode(&mut buf[..]).expect("can encode request");
581        let expected = [0xff, 0x00, 0x03];
582        assert_eq!(buf, expected);
583    }
584
585    #[fuchsia::test]
586    fn decode_request_packet_success() {
587        let request_buf = [
588            0x81, // OpCode = Disconnect
589            0x00, 0x0e, // Total Length = 14 bytes (3 for prefix, 11 for "Name" Header)
590            0x01, 0x00, 0xb, 0x00, 0x66, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x00, // Name = "fun"
591        ];
592        let decoded = RequestPacket::decode(&request_buf[..]).expect("valid request");
593        let expected_headers = HeaderSet::from_headers(vec![Header::name("fun")]).unwrap();
594        let expected = RequestPacket::new(OpCode::Disconnect, vec![], expected_headers);
595        assert_eq!(decoded, expected);
596    }
597
598    /// Example taken from OBEX 1.5 Section 3.4.1.9.
599    #[fuchsia::test]
600    fn encode_connect_request_packet_success() {
601        let headers =
602            HeaderSet::from_headers(vec![Header::Count(4), Header::Length(0xf483)]).unwrap();
603        let request = RequestPacket::new_connect(0x2000, headers);
604        assert_eq!(request.encoded_len(), 17);
605        let mut buf = vec![0; request.encoded_len()];
606        request.encode(&mut buf[..]).expect("can encode request");
607        let expected = [
608            0x80, // OpCode = CONNECT
609            0x00, 0x11, // Packet length = 17
610            0x10, 0x00, 0x20, 0x00, // Version = 1.0, Flags = 0, Max packet size = 8k bytes
611            0xc0, 0x00, 0x00, 0x00, 0x04, // Count Header = 0x4
612            0xc3, 0x00, 0x00, 0xf4, 0x83, // Length Header = 0xf483
613        ];
614        assert_eq!(buf, expected);
615    }
616
617    #[fuchsia::test]
618    fn decode_connect_request_packet_success() {
619        // Raw request contains CONNECT OpCode (length = 12) with a max packet size of 0xffff. An
620        // optional Count header is included.
621        let request_buf = [
622            0x80, // OpCode = Connect
623            0x00, 0x0c, // Total Length = 12 bytes
624            0x10, 0x00, 0xff, 0xff, // Version = 1.0, Flags = 0, Max packet size = u16::MAX
625            0xc0, 0x00, 0x00, 0xff, 0xff, // Optional Count Header = 0xffff
626        ];
627        let decoded = RequestPacket::decode(&request_buf[..]).expect("valid request");
628        let expected_headers = HeaderSet::from_headers(vec![Header::Count(0xffff)]).unwrap();
629        let expected =
630            RequestPacket::new(OpCode::Connect, vec![0x10, 0x00, 0xff, 0xff], expected_headers);
631        assert_eq!(decoded, expected);
632    }
633
634    #[fuchsia::test]
635    fn decode_invalid_connect_request_error() {
636        let missing_data = [
637            0x80, // OpCode = Connect
638            0x00, 0x03, // Total Length = 3 bytes (Only prefix, missing data)
639        ];
640        let decoded = RequestPacket::decode(&missing_data[..]);
641        assert_matches!(decoded, Err(PacketError::BufferTooSmall));
642
643        let invalid_data = [
644            0x80, // OpCode = Connect
645            0x00, 0x07, // Total Length = 7 bytes (Prefix, no optional headers, invalid data)
646            0x10, 0x00, // Data is missing max packet size, should be 4 bytes total.
647        ];
648        let decoded = RequestPacket::decode(&invalid_data[..]);
649        assert_matches!(decoded, Err(PacketError::BufferTooSmall));
650
651        // Any additional data will be treated as part of the optional Headers, and so this will
652        // fail.
653        let invalid_data_too_long = [
654            0x80, // OpCode = Connect
655            0x00, 0x08, // Total Length = 8 bytes (Prefix, no optional headers, invalid data)
656            0x10, 0x00, 0x00, 0xff, 0x01, // Data should only be 4 bytes
657        ];
658        let decoded = RequestPacket::decode(&invalid_data_too_long[..]);
659        assert_matches!(decoded, Err(PacketError::BufferTooSmall));
660    }
661
662    #[fuchsia::test]
663    fn encode_setpath_request_success() {
664        let headers = HeaderSet::from_headers(vec![Header::name("bar")]).unwrap();
665        let request = RequestPacket::new_set_path(SetPathFlags::all(), headers).unwrap();
666        assert_eq!(request.encoded_len(), 16);
667        let mut buf = vec![0; request.encoded_len()];
668        request.encode(&mut buf[..]).expect("can encode request");
669        let expected = [
670            0x85, // OpCode = SETPATH
671            0x00, 0x10, // Packet length = 16
672            0x03, 0x00, // Flags = 3 (Backup & Don't create), Constants = 0
673            0x01, 0x00, 0x0b, 0x00, 0x62, 0x00, 0x61, 0x00, 0x72, 0x00,
674            0x00, // Name Header = "bar"
675        ];
676        assert_eq!(buf, expected);
677    }
678
679    #[fuchsia::test]
680    fn decode_setpath_request_success() {
681        let request_buf = [
682            0x85, // OpCode = SETPATH
683            0x00, 0x0e, // Packet length = 14
684            0x02, 0x00, // Flags = 2 (Don't create), Constants = 0
685            0x01, 0x00, 0x09, 0x00, 0x61, 0x00, 0x72, 0x00, 0x00, // Name Header = "ar"
686        ];
687        let decoded = RequestPacket::decode(&request_buf[..]).expect("valid request");
688        let expected_headers = HeaderSet::from_headers(vec![Header::name("ar")]).unwrap();
689        let expected = RequestPacket::new(OpCode::SetPath, vec![0x02, 0x00], expected_headers);
690        assert_eq!(decoded, expected);
691    }
692
693    #[fuchsia::test]
694    fn decode_invalid_setpath_request_error() {
695        let missing_data = [
696            0x85, // OpCode = SetPath
697            0x00,
698            0x03, // Total Length = 3 bytes (Only prefix, missing data, optional headers)
699        ];
700        let decoded = RequestPacket::decode(&missing_data[..]);
701        assert_matches!(decoded, Err(PacketError::BufferTooSmall));
702
703        let invalid_data = [
704            0x85, // OpCode = Connect
705            0x00, 0x04, // Total Length = 4 bytes (Prefix, no optional headers, invalid data)
706            0x02, // Data is missing `constants` (should be 2 bytes total)
707        ];
708        let decoded = RequestPacket::decode(&invalid_data[..]);
709        assert_matches!(decoded, Err(PacketError::BufferTooSmall));
710
711        // Any additional data will be treated as part of the optional Headers, and so this will
712        // fail.
713        let invalid_data_too_long = [
714            0x85, // OpCode = SetPath
715            0x00, 0x08, // Total Length = 8 bytes (Prefix, no optional headers, invalid data)
716            0x10, 0x00, 0x00, 0xff, 0x01, // Data should only be 2 bytes
717        ];
718        let decoded = RequestPacket::decode(&invalid_data_too_long[..]);
719        assert_matches!(decoded, Err(_));
720    }
721
722    #[fuchsia::test]
723    fn encode_response_packet_success() {
724        let headers = HeaderSet::from_headers(vec![Header::DestName("foo".into())]).unwrap();
725        let response = ResponsePacket::new(ResponseCode::Gone, vec![], headers);
726        assert_eq!(response.encoded_len(), 14);
727        let mut buf = vec![0; response.encoded_len()];
728        response.encode(&mut buf[..]).expect("can encode valid response packet");
729        let expected_buf = [
730            0xca, 0x00, 0x0e, // Response = Gone, Length = 14
731            0x15, 0x00, 0x0b, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x6f, 0x00,
732            0x00, // DestName = "foo"
733        ];
734        assert_eq!(buf, expected_buf);
735    }
736
737    #[fuchsia::test]
738    fn decode_response_packet_success() {
739        let response_buf = [
740            0xa0, 0x00, 0x09, // ResponseCode = Ok, Total Length = 9
741            0x46, 0x00, 0x06, 0x00, 0x02, 0x04, // Target = [0x00, 0x02, 0x04]
742        ];
743        let decoded = ResponsePacket::decode(&response_buf[..], OpCode::GetFinal)
744            .expect("can decode valid response");
745        let expected_headers =
746            HeaderSet::from_headers(vec![Header::Target(vec![0x00, 0x02, 0x04])]).unwrap();
747        let expected = ResponsePacket::new(ResponseCode::Ok, vec![], expected_headers);
748        assert_eq!(decoded, expected);
749    }
750
751    #[fuchsia::test]
752    fn decode_invalid_response_packet_error() {
753        // Input buffer too small
754        let response_buf = [0x90];
755        let decoded = ResponsePacket::decode(&response_buf[..], OpCode::SetPath);
756        assert_matches!(decoded, Err(PacketError::BufferTooSmall));
757
758        // Invalid response code
759        let response_buf = [
760            0x0f, 0x00, 0x03, // ResponseCode = invalid, Total Length = 3
761        ];
762        let decoded = ResponsePacket::decode(&response_buf[..], OpCode::PutFinal);
763        assert_matches!(decoded, Err(PacketError::ResponseCode(_)));
764
765        // Valid response code with final bit not set.
766        let response_buf = [
767            0x10, 0x00, 0x03, // ResponseCode = Continue, final bit unset, Total Length = 3
768        ];
769        let decoded = ResponsePacket::decode(&response_buf[..], OpCode::Disconnect);
770        assert_matches!(decoded, Err(PacketError::ResponseCode(_)));
771
772        // Packet length doesn't match specified length
773        let response_buf = [0x90, 0x00, 0x04];
774        let decoded = ResponsePacket::decode(&response_buf[..], OpCode::ActionFinal);
775        assert_matches!(decoded, Err(PacketError::BufferTooSmall));
776
777        // Missing optional data
778        let response_buf = [
779            0xa0, 0x00, 0x05, // ResponseCode = Ok, Total Length = 5
780            0x10, 0x00, // Data: Missing max packet size
781        ];
782        let decoded = ResponsePacket::decode(&response_buf[..], OpCode::Connect);
783        assert_matches!(decoded, Err(PacketError::BufferTooSmall));
784    }
785
786    #[fuchsia::test]
787    fn encode_connect_response_packet_success() {
788        // A CONNECT response with Version = 1.0, Flags = 0, Max packet = 255. No additional headers
789        let connect_response = ResponsePacket::new(
790            ResponseCode::Accepted,
791            vec![0x10, 0x00, 0x00, 0xff],
792            HeaderSet::new(),
793        );
794        assert_eq!(connect_response.encoded_len(), 7);
795        let mut buf = vec![0; connect_response.encoded_len()];
796        connect_response.encode(&mut buf[..]).expect("can encode response");
797        let expected_buf = [
798            0xa2, 0x00, 0x07, // Response = Accepted, Total Length = 7
799            0x10, 0x00, 0x00, 0xff, // Data
800        ];
801        assert_eq!(buf, expected_buf);
802    }
803
804    #[fuchsia::test]
805    fn encode_setpath_response_packet_success() {
806        let setpath_response = ResponsePacket::new(ResponseCode::Ok, vec![], HeaderSet::new());
807        assert_eq!(setpath_response.encoded_len(), 3);
808        let mut buf = vec![0; setpath_response.encoded_len()];
809        setpath_response.encode(&mut buf[..]).expect("can encode response");
810        let expected_buf = [
811            0xa0, 0x00, 0x03, // Response = Ok, Total Length = 3 (no data, headers)
812        ];
813        assert_eq!(buf, expected_buf);
814    }
815
816    #[fuchsia::test]
817    fn expect_response_code() {
818        let response = ResponsePacket::new_no_data(ResponseCode::Ok, HeaderSet::new());
819        assert_matches!(response.clone().expect_code(OpCode::Get, ResponseCode::Ok), Ok(_));
820        assert_matches!(
821            response.expect_code(OpCode::Get, ResponseCode::Continue),
822            Err(Error::PeerRejected { .. })
823        );
824
825        let response = ResponsePacket::new_no_data(ResponseCode::Continue, HeaderSet::new());
826        assert_matches!(response.clone().expect_code(OpCode::Get, ResponseCode::Continue), Ok(_));
827        assert_matches!(
828            response.expect_code(OpCode::Get, ResponseCode::Ok),
829            Err(Error::PeerRejected { .. })
830        );
831
832        let response = ResponsePacket::new_no_data(ResponseCode::Conflict, HeaderSet::new());
833        assert_matches!(response.clone().expect_code(OpCode::Get, ResponseCode::Conflict), Ok(_));
834        assert_matches!(
835            response.expect_code(OpCode::Get, ResponseCode::Ok),
836            Err(Error::PeerRejected { .. })
837        );
838    }
839
840    #[fuchsia::test]
841    fn decode_connect_response_packet_success() {
842        let connect_response = [
843            0xa0, 0x00, 0x0c, // ResponseCode = Ok, Total Length = 12
844            0x10, 0x00, 0x12, 0x34, // Data: Version = 0x10, Flags = 0, Max Packet = 0x1234
845            0xcb, 0x00, 0x00, 0x00, 0x01, // ConnectionId = 1
846        ];
847        let decoded = ResponsePacket::decode(&connect_response[..], OpCode::Connect)
848            .expect("can decode valid response");
849        let expected_headers =
850            HeaderSet::from_headers(vec![Header::ConnectionId(ConnectionIdentifier(1))]).unwrap();
851        let expected =
852            ResponsePacket::new(ResponseCode::Ok, vec![0x10, 0x00, 0x12, 0x34], expected_headers);
853        assert_eq!(decoded, expected);
854    }
855
856    #[fuchsia::test]
857    fn decode_setpath_response_packet_success() {
858        let setpath_response = [
859            0xc3, 0x00, 0x08, // ResponseCode = Forbidden, Total length = 8
860            0xcf, 0x00, 0x00, 0x00, 0x02, // CreatorId = 2.
861        ];
862        let decoded = ResponsePacket::decode(&setpath_response[..], OpCode::SetPath)
863            .expect("can decode valid response");
864        let expected_headers = HeaderSet::from_headers(vec![Header::CreatorId(2)]).unwrap();
865        let expected = ResponsePacket::new(ResponseCode::Forbidden, vec![], expected_headers);
866        assert_eq!(decoded, expected);
867    }
868
869    #[fuchsia::test]
870    fn decode_setpath_response_packet_additional_data_error() {
871        let setpath_response = [
872            0xc3, 0x00, 0x0b, // ResponseCode = Forbidden, Total length = 11
873            0xaa, 0xbb, 0xcc, // Additional data is not supported in SetPath response.
874            0xcf, 0x00, 0x00, 0x00, 0x03, // CreatorId = 3.
875        ];
876        let decoded = ResponsePacket::decode(&setpath_response[..], OpCode::SetPath);
877        assert_matches!(decoded, Err(_));
878    }
879}