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