Skip to main content

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