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 interface_type_check(ULONG interface_type);
43 static UINT deplete_packets(NX_PACKET_POOL *pool_ptr, UINT remaining_packets);
44 static VOID release_packets(NX_PACKET_POOL *pool_ptr, UINT count);
45
46 static NX_AZURE_IOT iot;
47 static NX_AZURE_IOT_HUB_CLIENT iot_client;
48 static NX_SECURE_X509_CERT root_ca_cert;
49 static UCHAR metadata_buffer[NX_AZURE_IOT_TLS_METADATA_BUFFER_SIZE];
50 static ULONG demo_cloud_thread_stack[DEMO_CLOUD_STACK_SIZE / sizeof(ULONG)];
51 static NX_PACKET *allocated_packets[256];
52 static UCHAR large_property_name[2048];
53 static ULONG small_pool_stack[1024 >> 2];
54 static NX_PACKET_POOL small_pool;
55 extern int g_argc;
56 extern char **g_argv;
57
58 ULONG g_interface_type = 0;
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 to set the type. */
103 g_interface_type = NX_INTERFACE_TYPE_UNKNOWN;
104 will_return(__wrap__nxe_ip_driver_interface_direct_command, NX_NOT_SUCCESSFUL);
105
106 assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
107 NX_AZURE_IOT_SUCCESS);
108
109 /* The interface type should not be updated. */
110 assert_int_equal(interface_type_check(NX_INTERFACE_TYPE_UNKNOWN), NX_AZURE_IOT_SUCCESS);
111
112 nx_azure_iot_hub_client_disconnect(&iot_client);
113
114 /* Set the type as NX_INTERFACE_TYPE_OTHER. */
115 g_interface_type = NX_INTERFACE_TYPE_OTHER;
116 will_return(__wrap__nxe_ip_driver_interface_direct_command, NX_SUCCESS);
117
118 assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
119 NX_AZURE_IOT_SUCCESS);
120
121 /* The interface type should be updated as NX_INTERFACE_TYPE_OTHER. */
122 assert_int_equal(interface_type_check(NX_INTERFACE_TYPE_OTHER), NX_AZURE_IOT_SUCCESS);
123
124 nx_azure_iot_hub_client_disconnect(&iot_client);
125
126 /* Set the type as NX_INTERFACE_TYPE_ETHERNET. */
127 g_interface_type = NX_INTERFACE_TYPE_ETHERNET;
128 will_return(__wrap__nxe_ip_driver_interface_direct_command, NX_SUCCESS);
129
130 assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
131 NX_AZURE_IOT_SUCCESS);
132
133 /* The interface type should be updated as NX_INTERFACE_TYPE_ETHERNET. */
134 assert_int_equal(interface_type_check(NX_INTERFACE_TYPE_ETHERNET), NX_AZURE_IOT_SUCCESS);
135
136 nx_azure_iot_hub_client_disconnect(&iot_client);
137
138 /* Set the type as NX_INTERFACE_TYPE_LORAWAN. */
139 g_interface_type = NX_INTERFACE_TYPE_LORAWAN;
140 will_return(__wrap__nxe_ip_driver_interface_direct_command, NX_SUCCESS);
141
142 assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
143 NX_AZURE_IOT_SUCCESS);
144
145 /* The interface type should be updated as NX_INTERFACE_TYPE_LORAWAN. */
146 assert_int_equal(interface_type_check(NX_INTERFACE_TYPE_LORAWAN), NX_AZURE_IOT_SUCCESS);
147
148 nx_azure_iot_hub_client_disconnect(&iot_client);
149
150 /* Set the type as NX_INTERFACE_TYPE_MAX - 1. */
151 g_interface_type = NX_INTERFACE_TYPE_MAX - 1;
152 will_return(__wrap__nxe_ip_driver_interface_direct_command, NX_SUCCESS);
153
154 assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
155 NX_AZURE_IOT_SUCCESS);
156
157 /* The interface type should be updated as NX_INTERFACE_TYPE_MAX - 1. */
158 assert_int_equal(interface_type_check(NX_INTERFACE_TYPE_MAX - 1), NX_AZURE_IOT_SUCCESS);
159
160 nx_azure_iot_hub_client_disconnect(&iot_client);
161
162 /* Set the type as NX_INTERFACE_TYPE_MAX. */
163 g_interface_type = NX_INTERFACE_TYPE_MAX;
164 will_return(__wrap__nxe_ip_driver_interface_direct_command, NX_SUCCESS);
165
166 assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
167 NX_AZURE_IOT_SUCCESS);
168
169 /* The interface type should be updated as NX_INTERFACE_TYPE_OTHER. */
170 assert_int_equal(interface_type_check(NX_INTERFACE_TYPE_OTHER), NX_AZURE_IOT_SUCCESS);
171
172 nx_azure_iot_hub_client_disconnect(&iot_client);
173
174 iot_client.nx_azure_iot_hub_client_resource.resource_mqtt.nxd_mqtt_client_socket.nx_tcp_socket_state = NX_TCP_CLOSED;
175 assert_int_equal(nx_azure_iot_hub_client_deinitialize(&iot_client),
176 NX_AZURE_IOT_SUCCESS);
177
178 /* Check if all the packet are released */
179 assert_int_equal(pool_ptr -> nx_packet_pool_available, pool_ptr_available_packet);
180 assert_int_equal(small_pool.nx_packet_pool_available, small_pool_available_packet);
181
182 /* SUCCESS: iot is created. */
183 assert_int_equal(nx_azure_iot_delete(&iot), NX_AZURE_IOT_SUCCESS);
184 }
185
interface_type_check(ULONG interface_type)186 static UINT interface_type_check(ULONG interface_type)
187 {
188 UINT index;
189 UCHAR type;
190
191 /* Decode the interface type. */
192 for (index = 0; index < (iot_client.iot_hub_client_core._internal.options.user_agent._internal.size - 3); index++)
193 {
194
195 /* The interface type is after the first semicolon. */
196 if ((*(iot_client.iot_hub_client_core._internal.options.user_agent._internal.ptr + index) == '%') &&
197 (*(iot_client.iot_hub_client_core._internal.options.user_agent._internal.ptr + index + 1) == '3') &&
198 (*(iot_client.iot_hub_client_core._internal.options.user_agent._internal.ptr + index + 2) == 'B'))
199 {
200 type = *(iot_client.iot_hub_client_core._internal.options.user_agent._internal.ptr + index + 3) - '0';
201 if (type == interface_type)
202 {
203 return(NX_AZURE_IOT_SUCCESS);
204 }
205 else
206 {
207 return(NX_AZURE_IOT_FAILURE);
208 }
209 }
210 }
211
212 return(NX_AZURE_IOT_FAILURE);
213 }
214
deplete_packets(NX_PACKET_POOL * pool_ptr,UINT remaining_packets)215 static UINT deplete_packets(NX_PACKET_POOL *pool_ptr, UINT remaining_packets)
216 {
217 UINT count = 0;
218
219 while (pool_ptr -> nx_packet_pool_available > remaining_packets)
220 {
221 nx_packet_allocate(pool_ptr, &allocated_packets[count++], 0, NX_WAIT_FOREVER);
222 }
223 return(count);
224 }
225
release_packets(NX_PACKET_POOL * pool_ptr,UINT count)226 static VOID release_packets(NX_PACKET_POOL *pool_ptr, UINT count)
227 {
228 while (count != 0)
229 {
230 nx_packet_release(allocated_packets[--count]);
231 }
232 }
233
__wrap__nxe_ip_driver_interface_direct_command(NX_IP * ip_ptr,UINT command,UINT interface_index,ULONG * return_value_ptr)234 UINT __wrap__nxe_ip_driver_interface_direct_command(NX_IP *ip_ptr, UINT command, UINT interface_index, ULONG *return_value_ptr)
235 {
236 printf("HIJACKED: %s\n", __func__);
237 *return_value_ptr = g_interface_type;
238 return((UINT)mock());
239 }
240
__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)241 UINT __wrap__nxde_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port,
242 UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *,
243 NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *),
244 UINT keepalive, UINT clean_session, ULONG timeout)
245 {
246 printf("HIJACKED: %s\n", __func__);
247 tx_thread_suspend(&(iot.nx_azure_iot_ip_ptr -> nx_ip_thread));
248 client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_CONNECTED;
249 client_ptr -> nxd_mqtt_client_packet_identifier = 1;
250 client_ptr -> nxd_mqtt_tls_session.nx_secure_tls_id = NX_SECURE_TLS_ID;
251 client_ptr -> nxd_mqtt_tls_session.nx_secure_tls_local_session_active = NX_FALSE;
252 client_ptr -> nxd_mqtt_tls_session.nx_secure_tls_tcp_socket = &client_ptr -> nxd_mqtt_client_socket;
253 client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_connect_ip.nxd_ip_version = NX_IP_VERSION_V4;
254 client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_state = NX_TCP_ESTABLISHED;
255 return(NXD_MQTT_SUCCESS);
256 }
257
__wrap__nxde_mqtt_client_disconnect(NXD_MQTT_CLIENT * client_ptr)258 UINT __wrap__nxde_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr)
259 {
260 printf("HIJACKED: %s\n", __func__);
261 client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_IDLE;
262 client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_state = NX_TCP_CLOSED;
263 return(NXD_MQTT_SUCCESS);
264 }
265
__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)266 UINT __wrap__nxde_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr,
267 ULONG wait_option, UINT lookup_type)
268 {
269 printf("HIJACKED: %s\n", __func__);
270 host_address_ptr -> nxd_ip_version = NX_IP_VERSION_V4;
271 host_address_ptr -> nxd_ip_address.v4 = IP_ADDRESS(127, 0, 0, 1);
272 return(NX_DNS_SUCCESS);
273 }
274
__wrap__nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT * client_ptr,NX_PACKET * packet_ptr,USHORT packet_id,UINT QoS,ULONG wait_option)275 UINT __wrap__nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr,
276 USHORT packet_id, UINT QoS, ULONG wait_option)
277 {
278 UINT topic_name_length;
279 UINT message_length;
280 UCHAR *buffer_ptr;
281 UINT status = (UINT)mock();
282
283 printf("HIJACKED: %s\n", __func__);
284 tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr);
285
286 if (status)
287 {
288 return(status);
289 }
290
291 /* packet ownership taken and released */
292 nx_packet_release(packet_ptr);
293
294 return(status);
295 }
296
__wrap_nx_azure_iot_security_module_enable(NX_AZURE_IOT * nx_azure_iot_ptr)297 UINT __wrap_nx_azure_iot_security_module_enable(NX_AZURE_IOT *nx_azure_iot_ptr)
298 {
299 printf("HIJACKED: %s\n", __func__);
300 return(NX_AZURE_IOT_SUCCESS);
301 }
302
__wrap_nx_azure_iot_security_module_disable(NX_AZURE_IOT * nx_azure_iot_ptr)303 UINT __wrap_nx_azure_iot_security_module_disable(NX_AZURE_IOT *nx_azure_iot_ptr)
304 {
305 printf("HIJACKED: %s\n", __func__);
306 return(NX_AZURE_IOT_SUCCESS);
307 }
308