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