1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 #include "nx_azure_iot_hub_client_properties.h"
12 
13 extern UINT nx_azure_iot_hub_client_adjust_payload(NX_PACKET *packet_ptr);
14 VOID nx_azure_iot_hub_client_properties_component_process(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
15                                                           NX_PACKET *packet_ptr, UINT message_type);
16 
nx_azure_iot_hub_client_reported_properties_component_begin(NX_AZURE_IOT_HUB_CLIENT * hub_client_ptr,NX_AZURE_IOT_JSON_WRITER * writer_ptr,const UCHAR * component_name_ptr,USHORT component_name_length)17 UINT nx_azure_iot_hub_client_reported_properties_component_begin(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
18                                                                  NX_AZURE_IOT_JSON_WRITER *writer_ptr,
19                                                                  const UCHAR *component_name_ptr,
20                                                                  USHORT component_name_length)
21 {
22 az_result core_result;
23 az_span component_name;
24 
25     if ((hub_client_ptr == NX_NULL) ||
26         (writer_ptr == NX_NULL) ||
27         (component_name_ptr == NX_NULL) ||
28         (component_name_length == 0))
29     {
30         LogError(LogLiteralArgs("IoT PnP reported property begin fail: INVALID POINTER"));
31         return(NX_AZURE_IOT_INVALID_PARAMETER);
32     }
33 
34     component_name = az_span_create((UCHAR *)component_name_ptr, (INT)component_name_length);
35 
36     core_result = az_iot_hub_client_properties_writer_begin_component(&(hub_client_ptr -> iot_hub_client_core),
37                                                                       &(writer_ptr -> json_writer), component_name);
38     if (az_result_failed(core_result))
39     {
40         LogError(LogLiteralArgs("IoT PnP failed to append component, core error : %d"), core_result);
41         return(NX_AZURE_IOT_SDK_CORE_ERROR);
42     }
43 
44     return(NX_AZURE_IOT_SUCCESS);
45 }
46 
nx_azure_iot_hub_client_reported_properties_component_end(NX_AZURE_IOT_HUB_CLIENT * hub_client_ptr,NX_AZURE_IOT_JSON_WRITER * writer_ptr)47 UINT nx_azure_iot_hub_client_reported_properties_component_end(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
48                                                                NX_AZURE_IOT_JSON_WRITER *writer_ptr)
49 {
50 az_result core_result;
51 
52     if ((hub_client_ptr == NX_NULL) ||
53         (writer_ptr == NX_NULL))
54     {
55         LogError(LogLiteralArgs("IoT PnP reported property end fail: INVALID POINTER"));
56         return(NX_AZURE_IOT_INVALID_PARAMETER);
57     }
58 
59     core_result = az_iot_hub_client_properties_writer_end_component(&(hub_client_ptr -> iot_hub_client_core),
60                                                                     &(writer_ptr -> json_writer));
61     if (az_result_failed(core_result))
62     {
63         LogError(LogLiteralArgs("IoT PnP failed to append component, core error : %d"), core_result);
64         return(NX_AZURE_IOT_SDK_CORE_ERROR);
65     }
66 
67     return(NX_AZURE_IOT_SUCCESS);
68 }
69 
nx_azure_iot_hub_client_reported_properties_status_begin(NX_AZURE_IOT_HUB_CLIENT * hub_client_ptr,NX_AZURE_IOT_JSON_WRITER * writer_ptr,const UCHAR * property_name_ptr,UINT property_name_length,UINT status_code,ULONG version,const UCHAR * description_ptr,UINT description_length)70 UINT nx_azure_iot_hub_client_reported_properties_status_begin(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
71                                                               NX_AZURE_IOT_JSON_WRITER *writer_ptr,
72                                                               const UCHAR *property_name_ptr, UINT property_name_length,
73                                                               UINT status_code, ULONG version,
74                                                               const UCHAR *description_ptr, UINT description_length)
75 {
76 az_span property_name;
77 az_span description;
78 az_result core_result;
79 
80     if ((hub_client_ptr == NX_NULL) ||
81         (writer_ptr == NX_NULL) ||
82         (property_name_ptr == NX_NULL) ||
83         (property_name_length == 0) )
84     {
85         LogError(LogLiteralArgs("IoT PnP client begin reported status failed: INVALID POINTER"));
86         return(NX_AZURE_IOT_INVALID_PARAMETER);
87     }
88 
89     property_name = az_span_create((UCHAR *)property_name_ptr, (INT)property_name_length);
90     description = az_span_create((UCHAR *)description_ptr, (INT)description_length);
91 
92     core_result = az_iot_hub_client_properties_writer_begin_response_status(&(hub_client_ptr -> iot_hub_client_core),
93                                                                             &(writer_ptr -> json_writer),
94                                                                             property_name, (int32_t)status_code,
95                                                                             (int32_t)version, description);
96     if (az_result_failed(core_result))
97     {
98         LogError(LogLiteralArgs("Failed to prefix data with core error : %d"), core_result);
99         return(NX_AZURE_IOT_SDK_CORE_ERROR);
100     }
101 
102     return(NX_AZURE_IOT_SUCCESS);
103 }
104 
nx_azure_iot_hub_client_reported_properties_status_end(NX_AZURE_IOT_HUB_CLIENT * hub_client_ptr,NX_AZURE_IOT_JSON_WRITER * writer_ptr)105 UINT nx_azure_iot_hub_client_reported_properties_status_end(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
106                                                             NX_AZURE_IOT_JSON_WRITER *writer_ptr)
107 {
108 az_result core_result;
109 
110     if ((hub_client_ptr == NX_NULL) ||
111         (writer_ptr == NX_NULL))
112     {
113         LogError(LogLiteralArgs("IoT PnP client end reported status failed: INVALID POINTER"));
114         return(NX_AZURE_IOT_INVALID_PARAMETER);
115     }
116 
117     core_result = az_iot_hub_client_properties_writer_end_response_status(&(hub_client_ptr -> iot_hub_client_core),
118                                                                            &(writer_ptr -> json_writer));
119     if (az_result_failed(core_result))
120     {
121         LogError(LogLiteralArgs("Failed to suffix data with core error : %d"), core_result);
122         return(NX_AZURE_IOT_SDK_CORE_ERROR);
123     }
124 
125     return(NX_AZURE_IOT_SUCCESS);
126 }
127 
nx_azure_iot_hub_client_properties_version_get(NX_AZURE_IOT_HUB_CLIENT * hub_client_ptr,NX_AZURE_IOT_JSON_READER * reader_ptr,UINT message_type,ULONG * version_ptr)128 UINT nx_azure_iot_hub_client_properties_version_get(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
129                                                     NX_AZURE_IOT_JSON_READER *reader_ptr,
130                                                     UINT message_type, ULONG *version_ptr)
131 {
132 az_result core_result;
133 az_iot_hub_client_properties_message_type core_message_type;
134 
135     if ((hub_client_ptr == NX_NULL) ||
136         (reader_ptr == NX_NULL) ||
137         (version_ptr == NX_NULL) ||
138         ((message_type != NX_AZURE_IOT_HUB_PROPERTIES) &&
139          (message_type != NX_AZURE_IOT_HUB_WRITABLE_PROPERTIES)))
140     {
141         LogError(LogLiteralArgs("IoTHub client get properties version failed: INVALID POINTER"));
142         return(NX_AZURE_IOT_INVALID_PARAMETER);
143     }
144 
145     core_message_type = (message_type == NX_AZURE_IOT_HUB_PROPERTIES) ? AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_TYPE_GET_RESPONSE :
146                         AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_TYPE_WRITABLE_UPDATED;
147 
148     core_result = az_iot_hub_client_properties_get_properties_version(&(hub_client_ptr -> iot_hub_client_core),
149                                                                       &(reader_ptr -> json_reader),
150                                                                       core_message_type,
151                                                                       (int32_t *)version_ptr);
152     if (az_result_failed(core_result))
153     {
154         LogError(LogLiteralArgs("IoTHub client get properties version failed : %d"), core_result);
155         return(NX_AZURE_IOT_SDK_CORE_ERROR);
156     }
157 
158     return(NX_AZURE_IOT_SUCCESS);
159 }
160 
nx_azure_iot_hub_client_properties_component_property_next_get_internal(NX_AZURE_IOT_HUB_CLIENT * hub_client_ptr,NX_AZURE_IOT_JSON_READER * reader_ptr,UINT message_type,UINT property_type,const UCHAR ** component_name_pptr,USHORT * component_name_length_ptr,UINT * component_index,UINT parse_system_component)161 static UINT nx_azure_iot_hub_client_properties_component_property_next_get_internal(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
162                                                                                     NX_AZURE_IOT_JSON_READER *reader_ptr,
163                                                                                     UINT message_type, UINT property_type,
164                                                                                     const UCHAR **component_name_pptr,
165                                                                                     USHORT *component_name_length_ptr,
166                                                                                     UINT *component_index,
167                                                                                     UINT parse_system_component)
168 {
169 az_span component_name;
170 az_iot_hub_client_properties_message_type core_message_type;
171 az_iot_hub_client_property_type core_property_type;
172 az_result core_result;
173 UINT index;
174 UINT system_component;
175 
176     if (((message_type != NX_AZURE_IOT_HUB_WRITABLE_PROPERTIES) &&
177          (message_type != NX_AZURE_IOT_HUB_PROPERTIES)) ||
178         ((property_type != NX_AZURE_IOT_HUB_CLIENT_PROPERTY_REPORTED_FROM_DEVICE) &&
179          (property_type != NX_AZURE_IOT_HUB_CLIENT_PROPERTY_WRITABLE)) ||
180         ((property_type == NX_AZURE_IOT_HUB_CLIENT_PROPERTY_REPORTED_FROM_DEVICE) &&
181          (message_type != NX_AZURE_IOT_HUB_PROPERTIES)))
182     {
183         LogError(LogLiteralArgs("Invalid response type or property type passed"));
184         return(NX_AZURE_IOT_INVALID_PARAMETER);
185     }
186 
187     component_name = az_span_create((UCHAR *)*component_name_pptr, (INT)*component_name_length_ptr);
188     core_message_type = (message_type == NX_AZURE_IOT_HUB_PROPERTIES) ? AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_TYPE_GET_RESPONSE :
189                         AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_TYPE_WRITABLE_UPDATED;
190     core_property_type = (property_type == NX_AZURE_IOT_HUB_CLIENT_PROPERTY_REPORTED_FROM_DEVICE) ? AZ_IOT_HUB_CLIENT_PROPERTY_REPORTED_FROM_DEVICE :
191                         AZ_IOT_HUB_CLIENT_PROPERTY_WRITABLE;
192 
193     do
194     {
195         core_result = az_iot_hub_client_properties_get_next_component_property(&(hub_client_ptr -> iot_hub_client_core),
196                                                                                &(reader_ptr -> json_reader),
197                                                                                core_message_type, core_property_type,
198                                                                                &component_name);
199         if (core_result == AZ_ERROR_IOT_END_OF_PROPERTIES)
200         {
201             return(NX_AZURE_IOT_NOT_FOUND);
202         }
203         else if (az_result_failed(core_result))
204         {
205             LogError(LogLiteralArgs("Failed to parse document with core error : %d"), core_result);
206             return(NX_AZURE_IOT_SDK_CORE_ERROR);
207         }
208 
209         *component_name_pptr = az_span_ptr(component_name);
210         *component_name_length_ptr = (USHORT)az_span_size(component_name);
211 
212         /* Check if it is system component.  */
213         system_component = NX_FALSE;
214         for (index = 0; index < (UINT)hub_client_ptr -> iot_hub_client_core._internal.options.component_names_length; index++)
215         {
216             if ((az_span_is_content_equal(component_name, hub_client_ptr -> nx_azure_iot_hub_client_component_list[index]))&&
217                 (hub_client_ptr -> nx_azure_iot_hub_client_component_callback[index] != NX_NULL))
218             {
219                 system_component = NX_TRUE;
220                 break;
221             }
222         }
223 
224         /* System component.  */
225         if ((parse_system_component == NX_TRUE) && (system_component == NX_TRUE))
226         {
227             *component_index = index;
228             return(NX_AZURE_IOT_SUCCESS);
229         }
230         else if ((parse_system_component == NX_FALSE) && (system_component == NX_FALSE))
231         {
232             return(NX_AZURE_IOT_SUCCESS);
233         }
234 
235         /* Skip it and find the next one.  */
236         nx_azure_iot_json_reader_next_token(reader_ptr);
237 
238         /* Skip children in case the property value is an object.  */
239         if (nx_azure_iot_json_reader_token_type(reader_ptr) == NX_AZURE_IOT_READER_TOKEN_BEGIN_OBJECT)
240         {
241             nx_azure_iot_json_reader_skip_children(reader_ptr);
242         }
243         nx_azure_iot_json_reader_next_token(reader_ptr);
244 
245     } while(1);
246 }
247 
nx_azure_iot_hub_client_properties_component_property_next_get(NX_AZURE_IOT_HUB_CLIENT * hub_client_ptr,NX_AZURE_IOT_JSON_READER * reader_ptr,UINT message_type,UINT property_type,const UCHAR ** component_name_pptr,USHORT * component_name_length_ptr)248 UINT nx_azure_iot_hub_client_properties_component_property_next_get(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
249                                                                     NX_AZURE_IOT_JSON_READER *reader_ptr,
250                                                                     UINT message_type, UINT property_type,
251                                                                     const UCHAR **component_name_pptr,
252                                                                     USHORT *component_name_length_ptr)
253 {
254 
255 UINT status;
256 
257     if ((hub_client_ptr == NX_NULL) ||
258         (reader_ptr == NX_NULL) ||
259         (component_name_pptr == NX_NULL) ||
260         (component_name_length_ptr == NX_NULL))
261     {
262         LogError(LogLiteralArgs("IoTHub client component next property failed: INVALID POINTER"));
263         return(NX_AZURE_IOT_INVALID_PARAMETER);
264     }
265 
266     status = nx_azure_iot_hub_client_properties_component_property_next_get_internal(hub_client_ptr, reader_ptr,
267                                                                                      message_type, property_type,
268                                                                                      component_name_pptr, component_name_length_ptr,
269                                                                                      NX_NULL, NX_FALSE);
270 
271     return(status);
272 }
273 
nx_azure_iot_hub_client_properties_component_process(NX_AZURE_IOT_HUB_CLIENT * hub_client_ptr,NX_PACKET * packet_ptr,UINT message_type)274 VOID nx_azure_iot_hub_client_properties_component_process(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
275                                                           NX_PACKET *packet_ptr, UINT message_type)
276 {
277 
278 UINT status;
279 ULONG version;
280 NX_AZURE_IOT_JSON_READER reader_ptr;
281 const UCHAR *component_name_ptr = NX_NULL;
282 USHORT component_name_length = 0;
283 UINT component_index;
284 UCHAR *prepend_ptr = NX_NULL;
285 
286 
287     /* Check the message type.  */
288     if ((message_type != NX_AZURE_IOT_HUB_PROPERTIES) &&
289         (message_type != NX_AZURE_IOT_HUB_WRITABLE_PROPERTIES))
290     {
291         return;
292     }
293 
294     /* Record the prepend pointer.  */
295     prepend_ptr = packet_ptr -> nx_packet_prepend_ptr;
296 
297     if (nx_azure_iot_hub_client_adjust_payload(packet_ptr))
298     {
299         return;
300     }
301 
302     if (nx_azure_iot_json_reader_init(&reader_ptr, packet_ptr))
303     {
304 
305         /* Recover the prepend pointer since other functions will retreive the topic again.  */
306         packet_ptr -> nx_packet_length += (ULONG)(packet_ptr -> nx_packet_prepend_ptr - prepend_ptr);
307         packet_ptr -> nx_packet_prepend_ptr = prepend_ptr;
308         return;
309     }
310 
311     /* Get the version.  */
312     status = nx_azure_iot_hub_client_properties_version_get(hub_client_ptr, &reader_ptr,
313                                                             message_type, &version);
314     if (status)
315     {
316 
317         /* Recover the prepend pointer since other functions will retreive the topic again.  */
318         packet_ptr -> nx_packet_length += (ULONG)(packet_ptr -> nx_packet_prepend_ptr - prepend_ptr);
319         packet_ptr -> nx_packet_prepend_ptr = prepend_ptr;
320         return;
321     }
322 
323     /* Re-initialize the JSON reader state */
324     if (nx_azure_iot_json_reader_init(&reader_ptr, packet_ptr))
325     {
326 
327         /* Recover the prepend pointer since other functions will retreive the topic again.  */
328         packet_ptr -> nx_packet_length += (ULONG)(packet_ptr -> nx_packet_prepend_ptr - prepend_ptr);
329         packet_ptr -> nx_packet_prepend_ptr = prepend_ptr;
330         return;
331     }
332 
333     /* Loop to process system component.  */
334     while (nx_azure_iot_hub_client_properties_component_property_next_get_internal(hub_client_ptr,
335                                                                                    &reader_ptr, message_type,
336                                                                                    NX_AZURE_IOT_HUB_CLIENT_PROPERTY_WRITABLE,
337                                                                                    &component_name_ptr, &component_name_length,
338                                                                                    &component_index, NX_TRUE) == NX_AZURE_IOT_SUCCESS)
339     {
340 
341         /* Check if it is system component.  */
342         if ((component_name_ptr) && (component_name_length) &&
343             (hub_client_ptr -> nx_azure_iot_hub_client_component_callback[component_index]))
344         {
345             status = hub_client_ptr -> nx_azure_iot_hub_client_component_callback[component_index](&reader_ptr, version,
346                                                                                                    hub_client_ptr -> nx_azure_iot_hub_client_component_callback_args[component_index]);
347             if (status)
348             {
349 
350                 /* Recover the prepend pointer since other functions will retreive the topic again.  */
351                 packet_ptr -> nx_packet_length += (ULONG)(packet_ptr -> nx_packet_prepend_ptr - prepend_ptr);
352                 packet_ptr -> nx_packet_prepend_ptr = prepend_ptr;
353                 return;
354             }
355 
356         }
357         else
358         {
359 
360             /* The JSON reader must be advanced regardless of whether the property
361                 is of interest or not.  */
362             nx_azure_iot_json_reader_next_token(&reader_ptr);
363 
364             /* Skip children in case the property value is an object.  */
365             if (nx_azure_iot_json_reader_token_type(&reader_ptr) == NX_AZURE_IOT_READER_TOKEN_BEGIN_OBJECT)
366             {
367                 nx_azure_iot_json_reader_skip_children(&reader_ptr);
368             }
369             nx_azure_iot_json_reader_next_token(&reader_ptr);
370         }
371     }
372 
373     /* Recover the prepend pointer since other functions will retreive the topic again.  */
374     packet_ptr -> nx_packet_length += (ULONG)(packet_ptr -> nx_packet_prepend_ptr - prepend_ptr);
375     packet_ptr -> nx_packet_prepend_ptr = prepend_ptr;
376 
377     return;
378 }
379