• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::gatt::server::att_database::AttDatabase;
2 use crate::packets::att;
3 use pdl_runtime::EncodeError;
4 
handle_read_request<T: AttDatabase>( request: att::AttReadRequest, mtu: usize, db: &T, ) -> Result<att::Att, EncodeError>5 pub async fn handle_read_request<T: AttDatabase>(
6     request: att::AttReadRequest,
7     mtu: usize,
8     db: &T,
9 ) -> Result<att::Att, EncodeError> {
10     let handle = request.attribute_handle.into();
11 
12     match db.read_attribute(handle).await {
13         Ok(mut data) => {
14             // as per 5.3 3F 3.4.4.4 ATT_READ_RSP, we truncate to MTU - 1
15             data.truncate(mtu - 1);
16             att::AttReadResponse { value: data }.try_into()
17         }
18         Err(error_code) => att::AttErrorResponse {
19             opcode_in_error: att::AttOpcode::ReadRequest,
20             handle_in_error: handle.into(),
21             error_code,
22         }
23         .try_into(),
24     }
25 }
26 
27 #[cfg(test)]
28 mod test {
29     use super::*;
30 
31     use crate::core::uuid::Uuid;
32     use crate::gatt::ids::AttHandle;
33     use crate::gatt::server::att_database::{AttAttribute, AttPermissions};
34     use crate::gatt::server::test::test_att_db::TestAttDatabase;
35     use crate::packets::att;
36 
make_db_with_handle_and_value(handle: u16, value: Vec<u8>) -> TestAttDatabase37     fn make_db_with_handle_and_value(handle: u16, value: Vec<u8>) -> TestAttDatabase {
38         TestAttDatabase::new(vec![(
39             AttAttribute {
40                 handle: AttHandle(handle),
41                 type_: Uuid::new(0x1234),
42                 permissions: AttPermissions::READABLE,
43             },
44             value,
45         )])
46     }
47 
do_read_request_with_handle_and_mtu( handle: u16, mtu: usize, db: &TestAttDatabase, ) -> Result<att::Att, EncodeError>48     fn do_read_request_with_handle_and_mtu(
49         handle: u16,
50         mtu: usize,
51         db: &TestAttDatabase,
52     ) -> Result<att::Att, EncodeError> {
53         let att_view = att::AttReadRequest { attribute_handle: AttHandle(handle).into() };
54         tokio_test::block_on(handle_read_request(att_view, mtu, db))
55     }
56 
57     #[test]
test_simple_read()58     fn test_simple_read() {
59         let db = make_db_with_handle_and_value(3, vec![4, 5]);
60 
61         let response = do_read_request_with_handle_and_mtu(3, 31, &db);
62 
63         assert_eq!(response, att::AttReadResponse { value: vec![4, 5] }.try_into());
64     }
65 
66     #[test]
test_truncated_read()67     fn test_truncated_read() {
68         let db = make_db_with_handle_and_value(3, vec![4, 5]);
69 
70         // act
71         let response = do_read_request_with_handle_and_mtu(3, 2, &db);
72 
73         // assert
74         assert_eq!(response, att::AttReadResponse { value: vec![4] }.try_into());
75     }
76 
77     #[test]
test_missed_read()78     fn test_missed_read() {
79         let db = make_db_with_handle_and_value(3, vec![4, 5]);
80 
81         // act
82         let response = do_read_request_with_handle_and_mtu(4, 31, &db);
83 
84         // assert
85         assert_eq!(
86             response,
87             att::AttErrorResponse {
88                 opcode_in_error: att::AttOpcode::ReadRequest,
89                 handle_in_error: AttHandle(4).into(),
90                 error_code: att::AttErrorCode::InvalidHandle,
91             }
92             .try_into()
93         );
94     }
95 
make_db_with_unreadable_handle(handle: u16) -> TestAttDatabase96     fn make_db_with_unreadable_handle(handle: u16) -> TestAttDatabase {
97         TestAttDatabase::new(vec![(
98             AttAttribute {
99                 handle: AttHandle(handle),
100                 type_: Uuid::new(0x1234),
101                 permissions: AttPermissions::empty(),
102             },
103             vec![],
104         )])
105     }
106 
107     #[test]
test_not_readable()108     fn test_not_readable() {
109         let db = make_db_with_unreadable_handle(3);
110 
111         // act
112         let response = do_read_request_with_handle_and_mtu(3, 31, &db);
113 
114         // assert
115         assert_eq!(
116             response,
117             att::AttErrorResponse {
118                 opcode_in_error: att::AttOpcode::ReadRequest,
119                 handle_in_error: AttHandle(3).into(),
120                 error_code: att::AttErrorCode::ReadNotPermitted,
121             }
122             .try_into()
123         );
124     }
125 }
126