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