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