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