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