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