1 use log::warn;
2 
3 use crate::{
4     gatt::ids::AttHandle,
5     packets::{
6         AttChild, AttErrorCode, AttErrorResponseBuilder, AttFindByTypeValueRequestView,
7         AttFindInformationRequestView, AttOpcode, AttReadByGroupTypeRequestView,
8         AttReadByTypeRequestView, AttReadRequestView, AttView, AttWriteRequestView, Packet,
9         ParseError,
10     },
11 };
12 
13 use super::{
14     att_database::AttDatabase,
15     transactions::{
16         find_by_type_value::handle_find_by_type_value_request,
17         find_information_request::handle_find_information_request,
18         read_by_group_type_request::handle_read_by_group_type_request,
19         read_by_type_request::handle_read_by_type_request, read_request::handle_read_request,
20         write_request::handle_write_request,
21     },
22 };
23 
24 /// This struct handles all requests needing ACKs. Only ONE should exist per
25 /// bearer per database, to ensure serialization.
26 pub struct AttRequestHandler<Db: AttDatabase> {
27     db: Db,
28 }
29 
30 impl<Db: AttDatabase> AttRequestHandler<Db> {
new(db: Db) -> Self31     pub fn new(db: Db) -> Self {
32         Self { db }
33     }
34 
35     // Runs a task to process an incoming packet. Takes an exclusive reference to
36     // ensure that only one request is outstanding at a time (notifications +
37     // commands should take a different path)
process_packet(&mut self, packet: AttView<'_>, mtu: usize) -> AttChild38     pub async fn process_packet(&mut self, packet: AttView<'_>, mtu: usize) -> AttChild {
39         match self.try_parse_and_process_packet(packet, mtu).await {
40             Ok(result) => result,
41             Err(_) => {
42                 // parse error, assume it's an unsupported request
43                 // TODO(aryarahul): distinguish between REQUEST_NOT_SUPPORTED and INVALID_PDU
44                 AttErrorResponseBuilder {
45                     opcode_in_error: packet.get_opcode(),
46                     handle_in_error: AttHandle(0).into(),
47                     error_code: AttErrorCode::REQUEST_NOT_SUPPORTED,
48                 }
49                 .into()
50             }
51         }
52     }
53 
try_parse_and_process_packet( &mut self, packet: AttView<'_>, mtu: usize, ) -> Result<AttChild, ParseError>54     async fn try_parse_and_process_packet(
55         &mut self,
56         packet: AttView<'_>,
57         mtu: usize,
58     ) -> Result<AttChild, ParseError> {
59         let snapshotted_db = self.db.snapshot();
60         match packet.get_opcode() {
61             AttOpcode::READ_REQUEST => {
62                 Ok(handle_read_request(AttReadRequestView::try_parse(packet)?, mtu, &self.db).await)
63             }
64             AttOpcode::READ_BY_GROUP_TYPE_REQUEST => {
65                 handle_read_by_group_type_request(
66                     AttReadByGroupTypeRequestView::try_parse(packet)?,
67                     mtu,
68                     &snapshotted_db,
69                 )
70                 .await
71             }
72             AttOpcode::READ_BY_TYPE_REQUEST => {
73                 handle_read_by_type_request(
74                     AttReadByTypeRequestView::try_parse(packet)?,
75                     mtu,
76                     &snapshotted_db,
77                 )
78                 .await
79             }
80             AttOpcode::FIND_INFORMATION_REQUEST => Ok(handle_find_information_request(
81                 AttFindInformationRequestView::try_parse(packet)?,
82                 mtu,
83                 &snapshotted_db,
84             )),
85             AttOpcode::FIND_BY_TYPE_VALUE_REQUEST => Ok(handle_find_by_type_value_request(
86                 AttFindByTypeValueRequestView::try_parse(packet)?,
87                 mtu,
88                 &snapshotted_db,
89             )
90             .await),
91             AttOpcode::WRITE_REQUEST => {
92                 Ok(handle_write_request(AttWriteRequestView::try_parse(packet)?, &self.db).await)
93             }
94             _ => {
95                 warn!("Dropping unsupported opcode {:?}", packet.get_opcode());
96                 Err(ParseError::InvalidEnumValue)
97             }
98         }
99     }
100 }
101 
102 #[cfg(test)]
103 mod test {
104     use super::*;
105 
106     use crate::{
107         core::uuid::Uuid,
108         gatt::server::{
109             att_database::{AttAttribute, AttPermissions},
110             request_handler::AttRequestHandler,
111             test::test_att_db::TestAttDatabase,
112         },
113         packets::{
114             AttAttributeDataChild, AttReadRequestBuilder, AttReadResponseBuilder,
115             AttWriteResponseBuilder,
116         },
117         utils::packet::{build_att_data, build_att_view_or_crash},
118     };
119 
120     #[test]
test_read_request()121     fn test_read_request() {
122         // arrange
123         let db = TestAttDatabase::new(vec![(
124             AttAttribute {
125                 handle: AttHandle(3),
126                 type_: Uuid::new(0x1234),
127                 permissions: AttPermissions::READABLE,
128             },
129             vec![1, 2, 3],
130         )]);
131         let mut handler = AttRequestHandler { db };
132         let att_view = build_att_view_or_crash(AttReadRequestBuilder {
133             attribute_handle: AttHandle(3).into(),
134         });
135 
136         // act
137         let response = tokio_test::block_on(handler.process_packet(att_view.view(), 31));
138 
139         // assert
140         assert_eq!(
141             response,
142             AttChild::AttReadResponse(AttReadResponseBuilder {
143                 value: build_att_data(AttAttributeDataChild::RawData([1, 2, 3].into()))
144             })
145         );
146     }
147 
148     #[test]
test_unsupported_request()149     fn test_unsupported_request() {
150         // arrange
151         let db = TestAttDatabase::new(vec![(
152             AttAttribute {
153                 handle: AttHandle(3),
154                 type_: Uuid::new(0x1234),
155                 permissions: AttPermissions::READABLE,
156             },
157             vec![1, 2, 3],
158         )]);
159         let mut handler = AttRequestHandler { db };
160         let att_view = build_att_view_or_crash(AttWriteResponseBuilder {});
161 
162         // act
163         let response = tokio_test::block_on(handler.process_packet(att_view.view(), 31));
164 
165         // assert
166         assert_eq!(
167             response,
168             AttChild::AttErrorResponse(AttErrorResponseBuilder {
169                 opcode_in_error: AttOpcode::WRITE_RESPONSE,
170                 handle_in_error: AttHandle(0).into(),
171                 error_code: AttErrorCode::REQUEST_NOT_SUPPORTED
172             })
173         );
174     }
175 }
176