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 <stdio.h>
12 #include <setjmp.h>
13 #include <cmocka.h> /* macros: https://api.cmocka.org/group__cmocka__asserts.html */
14
15 #include "nx_api.h"
16 #include "nx_azure_iot_hub_client.h"
17 #include "nx_azure_iot_cert.h"
18 #include "nx_azure_iot_ciphersuites.h"
19
20
21 #define DEMO_DHCP_DISABLE
22 #define DEMO_IPV4_ADDRESS IP_ADDRESS(192, 168, 100, 33)
23 #define DEMO_IPV4_MASK 0xFFFFFF00UL
24 #define DEMO_GATEWAY_ADDRESS IP_ADDRESS(192, 168, 100, 1)
25 #define DEMO_DNS_SERVER_ADDRESS IP_ADDRESS(192, 168, 100, 1)
26 #define NETWORK_DRIVER _nx_ram_network_driver
27
28 /* Include main.c in the test case since we need to disable DHCP in this test. */
29 #include "main.c"
30
31
32 #define STRING_UNSIGNED_ARGS(s) (UCHAR *)s, strlen(s)
33
34 #ifndef DEMO_CLOUD_STACK_SIZE
35 #define DEMO_CLOUD_STACK_SIZE 2048
36 #endif /* DEMO_CLOUD_STACK_SIZE */
37
38 #ifndef DEMO_CLOUD_THREAD_PRIORITY
39 #define DEMO_CLOUD_THREAD_PRIORITY (4)
40 #endif /* DEMO_CLOUD_THREAD_PRIORITY */
41
42 static UINT deplete_packets(NX_PACKET_POOL *pool_ptr, UINT remaining_packets);
43 static VOID release_packets(NX_PACKET_POOL *pool_ptr, UINT count);
44
45 static NX_AZURE_IOT iot;
46 static NX_AZURE_IOT_HUB_CLIENT iot_client;
47 static NX_SECURE_X509_CERT root_ca_cert;
48 static UCHAR metadata_buffer[NX_AZURE_IOT_TLS_METADATA_BUFFER_SIZE];
49 static ULONG demo_cloud_thread_stack[DEMO_CLOUD_STACK_SIZE / sizeof(ULONG)];
50 static NX_PACKET *allocated_packets[256];
51 static UCHAR large_property_name[2048];
52 static ULONG small_pool_stack[1024 >> 2];
53 static NX_PACKET_POOL small_pool;
54 extern int g_argc;
55 extern char **g_argv;
56
57 CHAR *expected_topic = "";
58 CHAR *expected_message = "";
59
demo_entry(NX_IP * ip_ptr,NX_PACKET_POOL * pool_ptr,NX_DNS * dns_ptr,UINT (* unix_time_callback)(ULONG * unix_time))60 VOID demo_entry(NX_IP* ip_ptr, NX_PACKET_POOL* pool_ptr, NX_DNS* dns_ptr, UINT (*unix_time_callback)(ULONG *unix_time))
61 {
62 CHAR *host_name = "host_name";
63 CHAR *device_id = "device_id";
64 CHAR *module_id = "module_id";
65 CHAR *symmetric_key = "symmetric_key";
66 CHAR property_name[] = "property_name";
67 CHAR property_value[] = "property_value";
68 NX_PACKET *packet_ptr;
69 UINT count;
70 ULONG pool_ptr_available_packet;
71 ULONG small_pool_available_packet;
72
73 assert_int_equal(nx_packet_pool_create(&small_pool, "Small Packet Pool", 4,
74 (UCHAR *)small_pool_stack , sizeof(small_pool_stack)),
75 NX_AZURE_IOT_SUCCESS);
76
77 /* Initialize root certificate. */
78 assert_int_equal(nx_secure_x509_certificate_initialize(&root_ca_cert, (UCHAR *)_nx_azure_iot_root_cert, (USHORT)_nx_azure_iot_root_cert_size,
79 NX_NULL, 0, NULL, 0, NX_SECURE_X509_KEY_TYPE_NONE),
80 NX_AZURE_IOT_SUCCESS);
81
82 assert_int_equal(nx_azure_iot_create(&iot, (UCHAR *)"Azure IoT", ip_ptr, pool_ptr, dns_ptr, (UCHAR *)demo_cloud_thread_stack,
83 sizeof(demo_cloud_thread_stack), DEMO_CLOUD_THREAD_PRIORITY, unix_time_callback),
84 NX_AZURE_IOT_SUCCESS);
85
86 /* Record number of available packet before test */
87 pool_ptr_available_packet = pool_ptr -> nx_packet_pool_available;
88 small_pool_available_packet = small_pool.nx_packet_pool_available;
89
90 assert_int_equal(nx_azure_iot_hub_client_initialize(&iot_client, &iot,
91 STRING_UNSIGNED_ARGS(host_name),
92 STRING_UNSIGNED_ARGS(device_id),
93 STRING_UNSIGNED_ARGS(""),
94 _nx_azure_iot_tls_supported_crypto,
95 _nx_azure_iot_tls_supported_crypto_size,
96 _nx_azure_iot_tls_ciphersuite_map,
97 _nx_azure_iot_tls_ciphersuite_map_size,
98 metadata_buffer, sizeof(metadata_buffer),
99 &root_ca_cert),
100 NX_AZURE_IOT_SUCCESS);
101
102 /* FAIL: allocate packet before connect. */
103 iot_client.nx_azure_iot_hub_client_resource.resource_mqtt.nxd_mqtt_client_use_tls = NX_TRUE;
104 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_message_create(&iot_client, &packet_ptr, NX_IP_PERIODIC_RATE),
105 NX_AZURE_IOT_SUCCESS);
106 iot_client.nx_azure_iot_hub_client_resource.resource_mqtt.nxd_mqtt_client_use_tls = NX_FALSE;
107
108 assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
109 NX_AZURE_IOT_SUCCESS);
110
111 expected_topic = "devices/device_id/messages/events/";
112 expected_message = "{\"Message\": \"Empty\"}";
113
114 will_return(__wrap__nxd_mqtt_client_publish_packet_send, NXD_MQTT_NOT_CONNECTED);
115 assert_int_equal(nx_azure_iot_hub_client_telemetry_message_create(&iot_client, &packet_ptr, NX_IP_PERIODIC_RATE),
116 NX_AZURE_IOT_SUCCESS);
117 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_send(&iot_client, packet_ptr, expected_message,
118 strlen(expected_message), NX_IP_PERIODIC_RATE),
119 NX_AZURE_IOT_SUCCESS);
120 assert_int_equal(nx_azure_iot_hub_client_telemetry_message_delete(packet_ptr), NX_AZURE_IOT_SUCCESS);
121
122 will_return_always(__wrap__nxd_mqtt_client_publish_packet_send, NXD_MQTT_SUCCESS);
123 assert_int_equal(nx_azure_iot_hub_client_telemetry_message_create(&iot_client, &packet_ptr, NX_IP_PERIODIC_RATE),
124 NX_AZURE_IOT_SUCCESS);
125
126 /* FAIL: hub_client_ptr is NULL. */
127 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_send(NX_NULL, packet_ptr, expected_message,
128 strlen(expected_message), NX_IP_PERIODIC_RATE),
129 NX_AZURE_IOT_SUCCESS);
130
131 /* FAIL: packet_ptr is NULL. */
132 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_send(&iot_client, NX_NULL, expected_message,
133 strlen(expected_message), NX_IP_PERIODIC_RATE),
134 NX_AZURE_IOT_SUCCESS);
135
136 /* SUCCESS: Send telemetry as a device. */
137 assert_int_equal(nx_azure_iot_hub_client_telemetry_send(&iot_client, packet_ptr, expected_message,
138 strlen(expected_message), NX_IP_PERIODIC_RATE),
139 NX_AZURE_IOT_SUCCESS);
140
141 /* FAIL: hub_client_ptr is NULL. */
142 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_message_create(NX_NULL, &packet_ptr, NX_IP_PERIODIC_RATE),
143 NX_AZURE_IOT_SUCCESS);
144
145 /* FAIL: packet_pptr is NULL. */
146 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_message_create(&iot_client, NX_NULL, NX_IP_PERIODIC_RATE),
147 NX_AZURE_IOT_SUCCESS);
148
149 /* FAIL: All packets are depleted. */
150 count = deplete_packets(pool_ptr, 0);
151 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_message_create(&iot_client, &packet_ptr, NX_IP_PERIODIC_RATE),
152 NX_AZURE_IOT_SUCCESS);
153 release_packets(pool_ptr, count);
154
155 /* FAIL: Packet pool is too small. */
156 iot.nx_azure_iot_pool_ptr = &small_pool;
157 iot_client.nx_azure_iot_hub_client_resource.resource_mqtt.nxd_mqtt_client_use_tls = NX_TRUE;
158 iot_client.nx_azure_iot_hub_client_resource.resource_mqtt.nxd_mqtt_client_packet_pool_ptr = iot.nx_azure_iot_pool_ptr;
159 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_message_create(&iot_client, &packet_ptr, NX_IP_PERIODIC_RATE),
160 NX_AZURE_IOT_SUCCESS);
161 iot.nx_azure_iot_pool_ptr = pool_ptr;
162 iot_client.nx_azure_iot_hub_client_resource.resource_mqtt.nxd_mqtt_client_use_tls = NX_FALSE;
163 iot_client.nx_azure_iot_hub_client_resource.resource_mqtt.nxd_mqtt_client_packet_pool_ptr = iot.nx_azure_iot_pool_ptr;
164
165 /* SUCCESS: All parameters are valid. */
166 assert_int_equal(nx_azure_iot_hub_client_telemetry_message_create(&iot_client, &packet_ptr, NX_IP_PERIODIC_RATE),
167 NX_AZURE_IOT_SUCCESS);
168
169 /* FAIL: packet_ptr is NULL. */
170 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_property_add(NX_NULL,
171 STRING_UNSIGNED_ARGS(property_name),
172 STRING_UNSIGNED_ARGS(property_value),
173 NX_IP_PERIODIC_RATE),
174 NX_AZURE_IOT_SUCCESS);
175
176 /* FAIL: property_name is NULL. */
177 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_property_add(packet_ptr,
178 NX_NULL, 0,
179 STRING_UNSIGNED_ARGS(property_value),
180 NX_IP_PERIODIC_RATE),
181 NX_AZURE_IOT_SUCCESS);
182
183 /* FAIL: property_value is NULL. */
184 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_property_add(packet_ptr,
185 STRING_UNSIGNED_ARGS(property_name),
186 NX_NULL, 0,
187 NX_IP_PERIODIC_RATE),
188 NX_AZURE_IOT_SUCCESS);
189
190 /* FAIL: All packets are depleted and current packet is too small to hold property. */
191 count = deplete_packets(pool_ptr, 0);
192 memset(large_property_name, 'A', sizeof(large_property_name) - 1);
193 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_property_add(packet_ptr,
194 STRING_UNSIGNED_ARGS(large_property_name),
195 STRING_UNSIGNED_ARGS(property_value),
196 NX_IP_PERIODIC_RATE),
197 NX_AZURE_IOT_SUCCESS);
198 nx_packet_release(packet_ptr);
199 assert_int_equal(nx_azure_iot_hub_client_telemetry_message_create(&iot_client, &packet_ptr, NX_IP_PERIODIC_RATE),
200 NX_AZURE_IOT_SUCCESS);
201
202 /* SUCCESS: All parameters are valid. */
203 assert_int_equal(nx_azure_iot_hub_client_telemetry_property_add(packet_ptr,
204 STRING_UNSIGNED_ARGS(property_name),
205 STRING_UNSIGNED_ARGS(property_value),
206 NX_IP_PERIODIC_RATE),
207 NX_AZURE_IOT_SUCCESS);
208
209 /* FAIL: Adjust the current packet to full. No room to append '&' */
210 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_data_end;
211 packet_ptr -> nx_packet_length = (ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr);
212 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_property_add(packet_ptr,
213 STRING_UNSIGNED_ARGS(property_name),
214 STRING_UNSIGNED_ARGS(property_value),
215 NX_IP_PERIODIC_RATE),
216 NX_AZURE_IOT_SUCCESS);
217 nx_packet_release(packet_ptr);
218 assert_int_equal(nx_azure_iot_hub_client_telemetry_message_create(&iot_client, &packet_ptr, NX_IP_PERIODIC_RATE),
219 NX_AZURE_IOT_SUCCESS);
220
221 /* FAIL: Adjust the current packet to full. Left two bytes for '&' and property name 'n' */
222 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_data_end - 2;
223 packet_ptr -> nx_packet_length = (ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) - 2;
224 assert_int_not_equal(nx_azure_iot_hub_client_telemetry_property_add(packet_ptr,
225 "n", 1,
226 STRING_UNSIGNED_ARGS(property_value),
227 NX_IP_PERIODIC_RATE),
228 NX_AZURE_IOT_SUCCESS);
229 nx_packet_release(packet_ptr);
230 assert_int_equal(nx_azure_iot_hub_client_telemetry_message_create(&iot_client, &packet_ptr, NX_IP_PERIODIC_RATE),
231 NX_AZURE_IOT_SUCCESS);
232 release_packets(pool_ptr, count);
233
234 /* SUCCESS: All parameters are valid. */
235 assert_int_equal(nx_azure_iot_hub_client_telemetry_property_add(packet_ptr,
236 STRING_UNSIGNED_ARGS(property_name),
237 STRING_UNSIGNED_ARGS(property_value),
238 NX_IP_PERIODIC_RATE),
239 NX_AZURE_IOT_SUCCESS);
240 nx_packet_release(packet_ptr);
241
242 iot_client.nx_azure_iot_hub_client_resource.resource_mqtt.nxd_mqtt_client_socket.nx_tcp_socket_state = NX_TCP_CLOSED;
243 assert_int_equal(nx_azure_iot_hub_client_deinitialize(&iot_client),
244 NX_AZURE_IOT_SUCCESS);
245
246 assert_int_equal(nx_azure_iot_hub_client_initialize(&iot_client, &iot,
247 STRING_UNSIGNED_ARGS(host_name),
248 STRING_UNSIGNED_ARGS(device_id),
249 STRING_UNSIGNED_ARGS(module_id),
250 _nx_azure_iot_tls_supported_crypto,
251 _nx_azure_iot_tls_supported_crypto_size,
252 _nx_azure_iot_tls_ciphersuite_map,
253 _nx_azure_iot_tls_ciphersuite_map_size,
254 metadata_buffer, sizeof(metadata_buffer),
255 &root_ca_cert),
256 NX_AZURE_IOT_SUCCESS);
257
258 assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
259 NX_AZURE_IOT_SUCCESS);
260
261 /* SUCCESS: Send telemetry as a module. */
262 expected_topic = "devices/device_id/modules/module_id/messages/events/";
263 expected_message = "{\"Message\": \"Empty\"}";
264 assert_int_equal(nx_azure_iot_hub_client_telemetry_message_create(&iot_client, &packet_ptr, NX_IP_PERIODIC_RATE),
265 NX_AZURE_IOT_SUCCESS);
266 assert_int_equal(nx_azure_iot_hub_client_telemetry_send(&iot_client, packet_ptr, expected_message,
267 strlen(expected_message), NX_IP_PERIODIC_RATE),
268 NX_AZURE_IOT_SUCCESS);
269
270 iot_client.nx_azure_iot_hub_client_resource.resource_mqtt.nxd_mqtt_client_socket.nx_tcp_socket_state = NX_TCP_CLOSED;
271 assert_int_equal(nx_azure_iot_hub_client_deinitialize(&iot_client),
272 NX_AZURE_IOT_SUCCESS);
273
274 /* Check if all the packet are released */
275 assert_int_equal(pool_ptr -> nx_packet_pool_available, pool_ptr_available_packet);
276 assert_int_equal(small_pool.nx_packet_pool_available, small_pool_available_packet);
277
278 /* SUCCESS: iot is created. */
279 assert_int_equal(nx_azure_iot_delete(&iot), NX_AZURE_IOT_SUCCESS);
280 }
281
deplete_packets(NX_PACKET_POOL * pool_ptr,UINT remaining_packets)282 static UINT deplete_packets(NX_PACKET_POOL *pool_ptr, UINT remaining_packets)
283 {
284 UINT count = 0;
285
286 while (pool_ptr -> nx_packet_pool_available > remaining_packets)
287 {
288 nx_packet_allocate(pool_ptr, &allocated_packets[count++], 0, NX_WAIT_FOREVER);
289 }
290 return(count);
291 }
292
release_packets(NX_PACKET_POOL * pool_ptr,UINT count)293 static VOID release_packets(NX_PACKET_POOL *pool_ptr, UINT count)
294 {
295 while (count != 0)
296 {
297 nx_packet_release(allocated_packets[--count]);
298 }
299 }
300
__wrap__nxde_mqtt_client_secure_connect(NXD_MQTT_CLIENT * client_ptr,NXD_ADDRESS * server_ip,UINT server_port,UINT (* tls_setup)(NXD_MQTT_CLIENT * client_ptr,NX_SECURE_TLS_SESSION *,NX_SECURE_X509_CERT *,NX_SECURE_X509_CERT *),UINT keepalive,UINT clean_session,ULONG timeout)301 UINT __wrap__nxde_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port,
302 UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *,
303 NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *),
304 UINT keepalive, UINT clean_session, ULONG timeout)
305 {
306 printf("HIJACKED: %s\n", __func__);
307 tx_thread_suspend(&(iot.nx_azure_iot_ip_ptr -> nx_ip_thread));
308 client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_CONNECTED;
309 client_ptr -> nxd_mqtt_client_packet_identifier = 1;
310 client_ptr -> nxd_mqtt_tls_session.nx_secure_tls_id = NX_SECURE_TLS_ID;
311 client_ptr -> nxd_mqtt_tls_session.nx_secure_tls_local_session_active = NX_FALSE;
312 client_ptr -> nxd_mqtt_tls_session.nx_secure_tls_tcp_socket = &client_ptr -> nxd_mqtt_client_socket;
313 client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_connect_ip.nxd_ip_version = NX_IP_VERSION_V4;
314 client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_state = NX_TCP_ESTABLISHED;
315 return(NXD_MQTT_SUCCESS);
316 }
317
__wrap__nxde_dns_host_by_name_get(NX_DNS * dns_ptr,UCHAR * host_name,NXD_ADDRESS * host_address_ptr,ULONG wait_option,UINT lookup_type)318 UINT __wrap__nxde_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr,
319 ULONG wait_option, UINT lookup_type)
320 {
321 printf("HIJACKED: %s\n", __func__);
322 host_address_ptr -> nxd_ip_address.v4 = IP_ADDRESS(127, 0, 0, 1);
323 return(NX_DNS_SUCCESS);
324 }
325
__wrap__nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT * client_ptr,NX_PACKET * packet_ptr,USHORT packet_id,UINT QoS,ULONG wait_option)326 UINT __wrap__nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr,
327 USHORT packet_id, UINT QoS, ULONG wait_option)
328 {
329 UINT topic_name_length;
330 UINT message_length;
331 UCHAR *buffer_ptr;
332 UINT status = (UINT)mock();
333
334 printf("HIJACKED: %s\n", __func__);
335 tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr);
336
337 if (status)
338 {
339 return(status);
340 }
341
342 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
343 topic_name_length = (buffer_ptr[5] << 8) | (buffer_ptr[6]);
344 message_length = packet_ptr -> nx_packet_length - (9 + topic_name_length);
345 assert_int_equal(topic_name_length, strlen(expected_topic));
346 assert_memory_equal(&buffer_ptr[7], expected_topic, topic_name_length);
347 assert_int_equal(message_length, strlen(expected_message));
348 assert_memory_equal(&buffer_ptr[9 + topic_name_length], expected_message, message_length);
349 assert_int_equal(QoS, 1);
350
351 /* packet ownership taken and released */
352 nx_packet_release(packet_ptr);
353
354 return(status);
355 }
356
__wrap_nx_azure_iot_security_module_enable(NX_AZURE_IOT * nx_azure_iot_ptr)357 UINT __wrap_nx_azure_iot_security_module_enable(NX_AZURE_IOT *nx_azure_iot_ptr)
358 {
359 printf("HIJACKED: %s\n", __func__);
360 return(NX_AZURE_IOT_SUCCESS);
361 }
362
__wrap_nx_azure_iot_security_module_disable(NX_AZURE_IOT * nx_azure_iot_ptr)363 UINT __wrap_nx_azure_iot_security_module_disable(NX_AZURE_IOT *nx_azure_iot_ptr)
364 {
365 printf("HIJACKED: %s\n", __func__);
366 return(NX_AZURE_IOT_SUCCESS);
367 }
368