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