1 /* This case tests websocket disconnect corresponding logic, mainly focusing on the influence
2 brought by the disconnect state which may hinder other functions such as send/receive */
3 #include "tx_api.h"
4 #include "nx_api.h"
5
6 extern void test_control_return(UINT);
7
8 #if !defined(NX_DISABLE_IPV4) && defined(__PRODUCT_NETXDUO__) && !defined(NX_DISABLE_PACKET_CHAIN)
9 #include "nx_websocket_client.h"
10 #include "netx_websocket_common_process.c"
11
12 #define DEMO_STACK_SIZE 4096
13 #define PACKET_SIZE 1536
14 #define TOTAL_SIZE DEMO_STACK_SIZE + (PACKET_SIZE * 8) + 2048 + 1024
15
16 /* Define device drivers. */
17 extern void _nx_ram_network_driver_1024(NX_IP_DRIVER *driver_req_ptr);
18
19 static UINT test_done = NX_FALSE;
20
21 static TX_THREAD client_thread;
22 static NX_PACKET_POOL client_pool;
23 static NX_TCP_SOCKET test_client;
24 static NX_IP client_ip;
25
26 static NX_TCP_SOCKET test_server;
27 static NX_PACKET_POOL server_pool;
28 static TX_THREAD server_thread;
29 static NX_IP server_ip;
30 static UINT test_server_start = 0;
31 static UINT test_client_stop = 0;
32
33 /* Set up the websocket global variables */
34 static NX_WEBSOCKET_CLIENT client_websocket;
35 static UCHAR *client_websocket_host;
36 static UINT client_websocket_host_length;
37 static UCHAR *client_websocket_uri_path;
38 static UINT client_websocket_uri_path_length;
39
40
41 static void thread_client_entry(ULONG thread_input);
42 static void thread_server_entry(ULONG thread_input);
43
44 #define TEST_SERVER_ADDRESS IP_ADDRESS(1,2,3,4)
45 #define TEST_CLIENT_ADDRESS IP_ADDRESS(1,2,3,5)
46 #define TEST_SERVER_PORT 80
47
48 #define TEST_HOST_NAME "1.2.3.4"
49 #define TEST_URI_PATH "/test"
50 #define TEST_PROTOCOL "test"
51
52 static UCHAR server_switch_101[] =
53 {
54 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, // HTTP1.1/
55 0x31, 0x30, 0x31, 0x20, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x20, // 101 Switching
56 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x0d, 0x0a, // Protocols\r\n
57 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, // Upgrade:
58 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, // WebSocket\r\n
59 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, // Connection:
60 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, // Upgrade\r\n
61 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, // Sec-WebSocket-Protocol:
62 0x74, 0x2d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x3a, 0x20,
63 0x74, 0x65, 0x73, 0x74, 0x0d, 0x0a, // test
64 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, // Sec-WebSocket-Accept:
65 0x65, 0x74, 0x2d, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20,
66 0x35, 0x75, 0x31, 0x6c, 0x55, 0x72, 0x32, 0x57, 0x68, 0x70, 0x34, 0x64, 0x44, 0x57, 0x6e, // 5u1lUr2Whp4dDWnskk9JcJZobO0=
67 0x73, 0x6b, 0x6b, 0x39, 0x4a, 0x63, 0x4a, 0x5a, 0x6f, 0x62, 0x4f, 0x30, 0x3d, 0x0d, 0x0a,
68 0x0d, 0x0a,
69 };
70
71 static UCHAR server_response_1[] =
72 {
73 0x82, 0x04, 0x01, 0x02, 0x03, 0x04,
74 };
75
76 static UCHAR server_response_2[] =
77 {
78 0x88, 0x00, 0x01, 0x02, 0x03, 0x04,
79 };
80
81 static UCHAR client_test_data[] =
82 {
83 0x11, 0x22, 0x33, 0x44,
84 };
85
86 static ULONG error_counter;
87
88 extern void SET_ERROR_COUNTER(ULONG *error_counter, CHAR *filename, int line_number);
89
90 #define TEST_LOOP 3
91
92 #ifdef CTEST
test_application_define(void * first_unused_memory)93 VOID test_application_define(void *first_unused_memory)
94 #else
95 void netx_websocket_disconnect_test_application_define(void *first_unused_memory)
96 #endif
97 {
98 CHAR *pointer;
99 UINT status;
100
101
102 error_counter = 0;
103
104 /* Setup the working pointer. */
105 pointer = (CHAR *) first_unused_memory;
106
107 /* Create a helper thread for the server. */
108 tx_thread_create(&server_thread, "Test Server thread", thread_server_entry, 0,
109 pointer, DEMO_STACK_SIZE,
110 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
111
112 pointer = pointer + DEMO_STACK_SIZE;
113
114 /* Initialize the NetX system. */
115 nx_system_initialize();
116
117 /* Create the server packet pool. */
118 status = nx_packet_pool_create(&server_pool, "Test Server Packet Pool", PACKET_SIZE,
119 pointer, PACKET_SIZE * 8);
120 pointer = pointer + PACKET_SIZE * 8;
121 if (status)
122 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
123
124 /* Create an IP instance. */
125 status = nx_ip_create(&server_ip, "Test Server IP", TEST_SERVER_ADDRESS,
126 0xFFFFFF00UL, &server_pool, _nx_ram_network_driver_1024,
127 pointer, 2048, 1);
128 pointer = pointer + 2048;
129 if (status)
130 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
131
132 /* Enable ARP and supply ARP cache memory for the server IP instance. */
133 status = nx_arp_enable(&server_ip, (void *) pointer, 1024);
134 pointer = pointer + 1024;
135 if (status)
136 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
137
138
139 /* Enable TCP traffic. */
140 status = nx_tcp_enable(&server_ip);
141 if (status)
142 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
143
144 /* Create the Test Client thread. */
145 status = tx_thread_create(&client_thread, "Test Client", thread_client_entry, 0,
146 pointer, DEMO_STACK_SIZE,
147 6, 6, TX_NO_TIME_SLICE, TX_AUTO_START);
148 pointer = pointer + DEMO_STACK_SIZE;
149 if (status)
150 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
151
152 /* Create the Client packet pool. */
153 status = nx_packet_pool_create(&client_pool, "Test Client Packet Pool", PACKET_SIZE,
154 pointer, PACKET_SIZE * 8);
155 pointer = pointer + PACKET_SIZE * 8;
156 if (status)
157 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
158
159 /* Create an IP instance. */
160 status = nx_ip_create(&client_ip, "Test Client IP", TEST_CLIENT_ADDRESS,
161 0xFFFFFF00UL, &client_pool, _nx_ram_network_driver_1024,
162 pointer, 2048, 1);
163 pointer = pointer + 2048;
164 if (status)
165 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
166
167 status = nx_arp_enable(&client_ip, (void *) pointer, 1024);
168 pointer = pointer + 1024;
169 if (status)
170 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
171
172 /* Enable TCP traffic. */
173 status = nx_tcp_enable(&client_ip);
174 if (status)
175 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
176 }
177
thread_client_entry(ULONG thread_input)178 void thread_client_entry(ULONG thread_input)
179 {
180 UINT i, status;
181 NX_PACKET *packet_ptr;
182 NX_PACKET *packet_ptr1;
183 NXD_ADDRESS server_ip_address;
184 UINT code;
185
186 /* Create client socket. */
187 status = nx_tcp_socket_create(&client_ip, &test_client, "Client Socket", NX_IP_NORMAL, NX_FRAGMENT_OKAY,
188 NX_IP_TIME_TO_LIVE, 1000, NX_NULL, NX_NULL);
189 if (status)
190 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
191
192 /* Create WebSocket. */
193 status = nx_websocket_client_create(&client_websocket, (UCHAR *)" ", &client_ip, &client_pool);
194
195 /* Check status. */
196 if (status)
197 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
198
199 /* Give IP task and driver a chance to initialize the system. */
200 tx_thread_sleep(NX_IP_PERIODIC_RATE);
201
202 /* Bind and connect to server. */
203 status = nx_tcp_client_socket_bind(&test_client, TEST_SERVER_PORT, NX_IP_PERIODIC_RATE);
204 if (status)
205 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
206
207 /* Wait test server started. */
208 while(!test_server_start)
209 {
210 tx_thread_sleep(NX_IP_PERIODIC_RATE);
211 }
212
213 /* Set server IP address. */
214 server_ip_address.nxd_ip_address.v4 = TEST_SERVER_ADDRESS;
215 server_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
216
217 /* Connect to the server */
218 status = nxd_tcp_client_socket_connect(&test_client, &server_ip_address, TEST_SERVER_PORT, NX_WAIT_FOREVER);
219 if (status)
220 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
221
222 /* The disconnect shall fail since is succeed only when the state is connected */
223 status = nx_websocket_client_disconnect(&client_websocket, 0);
224 if (status != NX_WEBSOCKET_INVALID_STATE || client_websocket.nx_websocket_client_mutex.tx_mutex_ownership_count != 0)
225 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
226
227 /* Upgrade to websocket */
228 status = nx_websocket_client_connect(&client_websocket, &test_client,
229 TEST_HOST_NAME, sizeof(TEST_HOST_NAME) - 1,
230 (UCHAR *)TEST_URI_PATH, sizeof(TEST_URI_PATH) - 1,
231 (UCHAR *)TEST_PROTOCOL, sizeof(TEST_PROTOCOL) - 1,
232 NX_WAIT_FOREVER);
233
234 if (status)
235 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
236 else
237 {
238 status = nx_packet_allocate(&client_pool, &packet_ptr, NX_TCP_PACKET, NX_IP_PERIODIC_RATE);
239 if (status)
240 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
241
242 /* Append and send data. */
243 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr;
244 packet_ptr -> nx_packet_length = 0;
245 status = nx_packet_data_append(packet_ptr, client_test_data, sizeof(client_test_data), &client_pool, NX_IP_PERIODIC_RATE);
246 if (status)
247 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
248 status = nx_websocket_client_send(&client_websocket, packet_ptr, NX_WEBSOCKET_OPCODE_BINARY_FRAME, NX_TRUE, NX_WAIT_FOREVER);
249 if (status)
250 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
251
252 /* Receive the responsed data from server. */
253 status = nx_websocket_client_receive(&client_websocket, &packet_ptr, &code, NX_NO_WAIT);
254 if (status)
255 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
256 /* The first response from the server shall be an unfragmented frame */
257 if (client_websocket.nx_websocket_client_frame_fragmented == NX_TRUE)
258 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
259 nx_packet_release(packet_ptr);
260
261 /* Test normal disconnect which shall return success */
262 status = nx_websocket_client_disconnect(&client_websocket, 0);
263 if (status || client_websocket.nx_websocket_client_mutex.tx_mutex_ownership_count != 0)
264 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
265 if (client_websocket.nx_websocket_client_state != NX_WEBSOCKET_CLIENT_STATE_DISCONNECT_SENT)
266 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
267
268 /* Receive the responsed data from server. */
269 status = nx_websocket_client_receive(&client_websocket, &packet_ptr, &code, NX_NO_WAIT);
270 if (status != NX_WEBSOCKET_DISCONNECTED)
271 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
272 if (client_websocket.nx_websocket_client_state != NX_WEBSOCKET_CLIENT_STATE_IDLE)
273 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
274
275 /* Re-disconnect shall fail */
276 status = nx_websocket_client_disconnect(&client_websocket, 0);
277 if (status != NX_WEBSOCKET_INVALID_STATE || client_websocket.nx_websocket_client_mutex.tx_mutex_ownership_count != 0)
278 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
279
280 /* Send data shall be fine */
281 status = nx_packet_allocate(&client_pool, &packet_ptr, NX_TCP_PACKET, NX_IP_PERIODIC_RATE);
282 if (status)
283 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
284 status = nx_packet_data_append(packet_ptr, client_test_data, sizeof(client_test_data), &client_pool, NX_IP_PERIODIC_RATE);
285 if (status)
286 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
287 status = nx_websocket_client_send(&client_websocket, packet_ptr, NX_WEBSOCKET_OPCODE_BINARY_FRAME, NX_TRUE, NX_WAIT_FOREVER);
288 if (status != NX_WEBSOCKET_NOT_CONNECTED)
289 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
290 }
291
292 nx_packet_release(packet_ptr);
293 nx_tcp_client_socket_unbind(&test_client);
294 nx_tcp_socket_delete(&test_client);
295
296 test_done = NX_TRUE;
297 }
298
299 /* Define the helper Test server thread. */
thread_server_entry(ULONG thread_input)300 void thread_server_entry(ULONG thread_input)
301 {
302 UINT i, status;
303 NX_PACKET *packet_ptr;
304
305
306 /* Print out test information banner. */
307 printf("NetX Test: Websocket Disconnect Test.....................................");
308
309 /* Check for earlier error. */
310 if (error_counter)
311 {
312 printf("ERROR!\n");
313 test_control_return(1);
314 }
315
316 /* Give NetX a chance to initialize the system. */
317 tx_thread_sleep(NX_IP_PERIODIC_RATE);
318
319 status = nx_tcp_socket_create(&server_ip, &test_server, "Test Server Socket",
320 NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 1000,
321 NX_NULL, NX_NULL);
322
323 status = nx_tcp_server_socket_listen(&server_ip, TEST_SERVER_PORT, &test_server, 5, NX_NULL);
324 if (status)
325 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
326
327 /* Set the flag. */
328 test_server_start = 1;
329
330 /* Accept a connection from test client. */
331 status = nx_tcp_server_socket_accept(&test_server, 5 * NX_IP_PERIODIC_RATE);
332 if (status)
333 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
334
335 for (i = 0; i < TEST_LOOP; i++)
336 {
337 /* Receive client data. */
338 status = nx_tcp_socket_receive(&test_server, &packet_ptr, 5 * NX_IP_PERIODIC_RATE);
339 if (status)
340 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
341 else
342 {
343 /* Response data. */
344 switch (i)
345 {
346 case 0:
347 /* Update the value in the field Sec-Protocol-Accept since it is calculated based on a random value */
348 _server_connect_response_process(packet_ptr);
349 memcpy(&server_switch_101[127], connect_key, 28);
350
351 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr;
352 packet_ptr -> nx_packet_length = 0;
353 nx_packet_data_append(packet_ptr, server_switch_101, sizeof(server_switch_101), &server_pool, NX_IP_PERIODIC_RATE);
354 status = nx_tcp_socket_send(&test_server, packet_ptr, NX_IP_PERIODIC_RATE);
355 if (status)
356 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
357 break;
358 case 1:
359 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr;
360 packet_ptr -> nx_packet_length = 0;
361 nx_packet_data_append(packet_ptr, server_response_1, sizeof(server_response_1), &server_pool, NX_IP_PERIODIC_RATE);
362 status = nx_tcp_socket_send(&test_server, packet_ptr, NX_IP_PERIODIC_RATE);
363 if (status)
364 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
365 break;
366 case 2:
367 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr;
368 packet_ptr -> nx_packet_length = 0;
369 nx_packet_data_append(packet_ptr, server_response_2, sizeof(server_response_2), &server_pool, NX_IP_PERIODIC_RATE);
370 status = nx_tcp_socket_send(&test_server, packet_ptr, NX_IP_PERIODIC_RATE);
371 if (status)
372 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
373 break;
374 default:
375 break;
376 }
377 }
378 }
379
380 /* Wait for test done. */
381 while (test_done == NX_FALSE)
382 {
383 tx_thread_sleep(NX_IP_PERIODIC_RATE);
384 }
385
386 nx_tcp_server_socket_unlisten(&server_ip, TEST_SERVER_PORT);
387 nx_tcp_socket_delete(&test_server);
388
389 if (client_pool.nx_packet_pool_available != client_pool.nx_packet_pool_total)
390 {
391 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
392 }
393 else if (client_pool.nx_packet_pool_invalid_releases)
394 {
395 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
396 }
397
398 if (server_pool.nx_packet_pool_available != server_pool.nx_packet_pool_total)
399 {
400 SET_ERROR_COUNTER(&error_counter, __FILE__, __LINE__);
401 }
402
403 if (error_counter)
404 {
405 printf("ERROR!\n");
406 test_control_return(1);
407 }
408 else
409 {
410 printf("SUCCESS!\n");
411 test_control_return(0);
412 }
413 }
414
415 #else
416
417 #ifdef CTEST
test_application_define(void * first_unused_memory)418 VOID test_application_define(void *first_unused_memory)
419 #else
420 void netx_websocket_disconnect_test_application_define(void *first_unused_memory)
421 #endif
422 {
423
424 /* Print out test information banner. */
425 printf("NetX Test: Websocket Disconnect Test.....................................N/A\n");
426
427 test_control_return(3);
428 }
429 #endif
430
431