1 use crate::{
2     gatt::server::att_database::AttDatabase,
3     packets::{
4         AttAttributeDataBuilder, AttAttributeDataChild, AttChild, AttErrorResponseBuilder,
5         AttOpcode, AttReadRequestView, AttReadResponseBuilder,
6     },
7 };
8 
handle_read_request<T: AttDatabase>( request: AttReadRequestView<'_>, mtu: usize, db: &T, ) -> AttChild9 pub async fn handle_read_request<T: AttDatabase>(
10     request: AttReadRequestView<'_>,
11     mtu: usize,
12     db: &T,
13 ) -> AttChild {
14     let handle = request.get_attribute_handle().into();
15 
16     match db.read_attribute(handle).await {
17         Ok(mut data) => {
18             // as per 5.3 3F 3.4.4.4 ATT_READ_RSP, we truncate to MTU - 1
19             data.truncate(mtu - 1);
20             AttReadResponseBuilder {
21                 value: AttAttributeDataBuilder {
22                     _child_: AttAttributeDataChild::RawData(data.into_boxed_slice()),
23                 },
24             }
25             .into()
26         }
27         Err(error_code) => AttErrorResponseBuilder {
28             opcode_in_error: AttOpcode::READ_REQUEST,
29             handle_in_error: handle.into(),
30             error_code,
31         }
32         .into(),
33     }
34 }
35 
36 #[cfg(test)]
37 mod test {
38     use super::*;
39 
40     use crate::{
41         core::uuid::Uuid,
42         gatt::{
43             ids::AttHandle,
44             server::{
45                 att_database::{AttAttribute, AttPermissions},
46                 test::test_att_db::TestAttDatabase,
47             },
48         },
49         packets::{AttAttributeDataChild, AttErrorCode, AttReadRequestBuilder, Serializable},
50         utils::packet::{build_att_data, build_view_or_crash},
51     };
52 
make_db_with_handle_and_value(handle: u16, value: Vec<u8>) -> TestAttDatabase53     fn make_db_with_handle_and_value(handle: u16, value: Vec<u8>) -> TestAttDatabase {
54         TestAttDatabase::new(vec![(
55             AttAttribute {
56                 handle: AttHandle(handle),
57                 type_: Uuid::new(0x1234),
58                 permissions: AttPermissions::READABLE,
59             },
60             value,
61         )])
62     }
63 
do_read_request_with_handle_and_mtu( handle: u16, mtu: usize, db: &TestAttDatabase, ) -> AttChild64     fn do_read_request_with_handle_and_mtu(
65         handle: u16,
66         mtu: usize,
67         db: &TestAttDatabase,
68     ) -> AttChild {
69         let att_view = build_view_or_crash(AttReadRequestBuilder {
70             attribute_handle: AttHandle(handle).into(),
71         });
72         tokio_test::block_on(handle_read_request(att_view.view(), mtu, db))
73     }
74 
75     #[test]
test_simple_read()76     fn test_simple_read() {
77         let db = make_db_with_handle_and_value(3, vec![4, 5]);
78 
79         let response = do_read_request_with_handle_and_mtu(3, 31, &db);
80 
81         response.to_vec().unwrap(); // check it serializes
82         assert_eq!(
83             response,
84             AttChild::AttReadResponse(AttReadResponseBuilder {
85                 value: build_att_data(AttAttributeDataChild::RawData([4, 5].into()))
86             })
87         )
88     }
89 
90     #[test]
test_truncated_read()91     fn test_truncated_read() {
92         let db = make_db_with_handle_and_value(3, vec![4, 5]);
93 
94         // act
95         let response = do_read_request_with_handle_and_mtu(3, 2, &db);
96 
97         // assert
98         assert_eq!(response.to_vec().unwrap(), vec![4]);
99     }
100 
101     #[test]
test_missed_read()102     fn test_missed_read() {
103         let db = make_db_with_handle_and_value(3, vec![4, 5]);
104 
105         // act
106         let response = do_read_request_with_handle_and_mtu(4, 31, &db);
107 
108         // assert
109         assert_eq!(
110             response,
111             AttChild::AttErrorResponse(AttErrorResponseBuilder {
112                 opcode_in_error: AttOpcode::READ_REQUEST,
113                 handle_in_error: AttHandle(4).into(),
114                 error_code: AttErrorCode::INVALID_HANDLE,
115             })
116         );
117     }
118 
make_db_with_unreadable_handle(handle: u16) -> TestAttDatabase119     fn make_db_with_unreadable_handle(handle: u16) -> TestAttDatabase {
120         TestAttDatabase::new(vec![(
121             AttAttribute {
122                 handle: AttHandle(handle),
123                 type_: Uuid::new(0x1234),
124                 permissions: AttPermissions::empty(),
125             },
126             vec![],
127         )])
128     }
129 
130     #[test]
test_not_readable()131     fn test_not_readable() {
132         let db = make_db_with_unreadable_handle(3);
133 
134         // act
135         let response = do_read_request_with_handle_and_mtu(3, 31, &db);
136 
137         // assert
138         assert_eq!(
139             response,
140             AttChild::AttErrorResponse(AttErrorResponseBuilder {
141                 opcode_in_error: AttOpcode::READ_REQUEST,
142                 handle_in_error: AttHandle(3).into(),
143                 error_code: AttErrorCode::READ_NOT_PERMITTED,
144             })
145         );
146     }
147 }
148