1 /* This NetX test concentrates on the basic BSD TCP blocking operation.  */
2 /* The BSD APIs involved in this test are:  socket(), connect(), send(), soc_close() */
3 
4 #include   "tx_api.h"
5 #include   "nx_api.h"
6 #if defined(NX_BSD_ENABLE) && !defined(NX_DISABLE_IPV4)
7 #include   "nx_icmpv6.h"
8 #include   "nxd_bsd.h"
9 #define     DEMO_STACK_SIZE         4096
10 
11 
12 /* Define the ThreadX and NetX object control blocks...  */
13 
14 static TX_THREAD               ntest_0;
15 static TX_THREAD               ntest_1;
16 
17 static NX_PACKET_POOL          pool_0;
18 static NX_IP                   ip_0;
19 static NX_IP                   ip_1;
20 static ULONG                   bsd_thread_area[DEMO_STACK_SIZE / sizeof(ULONG)];
21 static TX_SEMAPHORE            sema_0;
22 static TX_SEMAPHORE            sema_1;
23 static TX_SEMAPHORE            sema_2;
24 #define BSD_THREAD_PRIORITY    2
25 #define NUM_CLIENTS            NX_BSD_MAX_SOCKETS
26 /* Define the counters used in the test application...  */
27 
28 static ULONG                   error_counter;
29 static ULONG                   packet_pool_area[(256 + sizeof(NX_PACKET)) * (NUM_CLIENTS + 4) * 8 / 4];
30 
31 /* Define thread prototypes.  */
32 
33 static void    ntest_0_entry(ULONG thread_input);
34 static void    ntest_1_entry(ULONG thread_input);
35 extern void    test_control_return(UINT status);
36 extern void    _nx_ram_network_driver_256(struct NX_IP_DRIVER_STRUCT *driver_req);
37 static void    validate_bsd_structure(void);
38 extern NX_BSD_SOCKET  nx_bsd_socket_array[NX_BSD_MAX_SOCKETS];
39 static char *requests[4] = {"Request1", "Request2", "Request3", "Request4"};
40 static char *response[4] = {"Response1", "Response2", "Response3", "Response4"};
41 static void validate_bsd_structure(void);
42 /* Define what the initial system looks like.  */
43 
44 #ifdef CTEST
test_application_define(void * first_unused_memory)45 VOID test_application_define(void *first_unused_memory)
46 #else
47 void    netx_bsd_tcp_accept_blocking_timeout_test_application_define(void *first_unused_memory)
48 #endif
49 {
50 
51 CHAR    *pointer;
52 UINT    status;
53 
54 
55     /* Setup the working pointer.  */
56     pointer =  (CHAR *) first_unused_memory;
57 
58     error_counter =  0;
59 
60     /* Create the main thread.  */
61     tx_thread_create(&ntest_0, "thread 0", ntest_0_entry, 0,
62                      pointer, DEMO_STACK_SIZE,
63                      3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
64 
65     pointer =  pointer + DEMO_STACK_SIZE;
66 
67     /* Create the main thread.  */
68     tx_thread_create(&ntest_1, "thread 1", ntest_1_entry, 0,
69                      pointer, DEMO_STACK_SIZE,
70                      3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
71 
72     pointer =  pointer + DEMO_STACK_SIZE;
73 
74 
75     /* Initialize the NetX system.  */
76     nx_system_initialize();
77 
78     /* Create a packet pool.  */
79     status =  nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 256, packet_pool_area, sizeof(packet_pool_area));
80 
81 
82     if (status)
83         error_counter++;
84 
85     /* Create an IP instance.  */
86     status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver_256,
87                     pointer, 2048, 1);
88     pointer =  pointer + 2048;
89 
90     /* Create another IP instance.  */
91     status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(1, 2, 3, 5), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver_256,
92                     pointer, 2048, 1);
93     pointer =  pointer + 2048;
94     if (status)
95         error_counter++;
96 
97     /* Enable ARP and supply ARP cache memory for IP Instance 0.  */
98     status =  nx_arp_enable(&ip_0, (void *) pointer, 1024);
99     pointer = pointer + 1024;
100     if (status)
101         error_counter++;
102 
103     /* Enable ARP and supply ARP cache memory for IP Instance 1.  */
104     status  =  nx_arp_enable(&ip_1, (void *) pointer, 1024);
105     pointer = pointer + 1024;
106     if (status)
107         error_counter++;
108 
109     /* Enable TCP processing for both IP instances.  */
110     status =  nx_tcp_enable(&ip_0);
111     status += nx_tcp_enable(&ip_1);
112 
113     /* Enable BSD */
114     status += bsd_initialize(&ip_0, &pool_0, (CHAR*)&bsd_thread_area[0], sizeof(bsd_thread_area), BSD_THREAD_PRIORITY);
115 
116     /* Check TCP enable status.  */
117     if (status)
118         error_counter++;
119 
120     status = tx_semaphore_create(&sema_0, "SEMA 0", 0);
121     status += tx_semaphore_create(&sema_1, "SEMA 1", 0);
122     status += tx_semaphore_create(&sema_2, "SEMA 2", 0);
123     if(status)
124         error_counter++;
125 }
126 typedef struct client_info_struct
127 {
128     int sockfd;
129     int message_id;
130 } client_info;
131 
132 static client_info client_data[NUM_CLIENTS];
133 static ULONG stack_space[NUM_CLIENTS][DEMO_STACK_SIZE / sizeof(ULONG)];
134 static TX_THREAD helper_thread[NUM_CLIENTS];
135 
bsd_server_helper_thread_entry(ULONG thread_input)136 static VOID bsd_server_helper_thread_entry(ULONG thread_input)
137 {
138 int         ret;
139 int         sockfd, message_id;
140 char        buf[30];
141 
142     sockfd = client_data[thread_input].sockfd;
143     message_id = client_data[thread_input].message_id;
144     /* Receive data from the client. */
145     ret = recv(sockfd, buf, sizeof(buf), 0);
146     if(ret <= 0)
147         error_counter++;
148 
149     /* Validate the data. */
150     if((ret != (int)strlen(requests[message_id & 3])) || strncmp(buf, requests[message_id & 3], ret))
151         error_counter++;
152 
153     /* Send a response back. */
154     ret = send(sockfd, response[message_id & 3], strlen(response[message_id & 3]), 0);
155     if(ret != (int)strlen(response[message_id & 3]))
156         error_counter++;
157 
158     /* Wait until client received. */
159     if((sockfd - NX_BSD_SOCKFD_START + 1) != (NUM_CLIENTS / 2))
160         tx_semaphore_get(&sema_1, 5 * NX_IP_PERIODIC_RATE);
161     else
162         tx_semaphore_get(&sema_2, 5 * NX_IP_PERIODIC_RATE);
163 
164     ret = soc_close(sockfd);
165     if(ret < 0)
166         error_counter++;
167 
168     tx_semaphore_put(&sema_0);
169     return;
170 }
171 
172 
173 
test_tcp_server4(void)174 static void test_tcp_server4(void)
175 {
176 int                sockfd;
177 struct sockaddr_in remote_addr, local_addr;
178 int                address_length;
179 int                ret;
180 int                newsock;
181 int                i;
182 UINT               status;
183 int                accept_no_memory = 0;
184 
185 
186 
187     sockfd = socket(AF_INET, SOCK_STREAM, 0);
188     if(sockfd < 0)
189         error_counter++;
190 
191     local_addr.sin_family = AF_INET;
192     local_addr.sin_port = htons(12345);
193     local_addr.sin_addr.s_addr = INADDR_ANY;
194 
195     ret = bind(sockfd, (struct sockaddr*)&local_addr, sizeof(local_addr));
196     if(ret < 0)
197         error_counter++;
198 
199     ret = listen(sockfd, 5);
200     if(ret < 0)
201         error_counter++;
202 
203     /* 3 iterations. */
204     for(i = 0; i < NUM_CLIENTS; i++)
205     {
206         address_length = sizeof(remote_addr);
207 
208         newsock = accept(sockfd, (struct sockaddr*)&remote_addr, &address_length);
209 
210         if(newsock <= 0)
211         {
212             if(i != (NUM_CLIENTS - 1))
213                 error_counter++;
214             else
215             {
216                 if(errno != ENOMEM)
217                     error_counter++;
218                 else
219                 {
220                     accept_no_memory = 1;
221                     tx_thread_sleep(10);
222                     i--;
223                     continue;
224                 }
225             }
226         }
227         else if(address_length != sizeof(remote_addr))
228             error_counter++;
229         else if((remote_addr.sin_family != AF_INET) || (remote_addr.sin_addr.s_addr != htonl(0x01020305)))
230             error_counter++;
231 
232 
233         /* Set the client data */
234         client_data[i].sockfd = newsock;
235         client_data[i].message_id = i;
236 
237         /* Create a helper thread to handle the new socket. */
238         status = tx_thread_create(&helper_thread[i], "helper thread", bsd_server_helper_thread_entry,
239                                   i, stack_space[i], DEMO_STACK_SIZE, 2, 2, TX_NO_TIME_SLICE, TX_AUTO_START);
240         if(status != TX_SUCCESS)
241             error_counter++;
242 
243 
244         tx_thread_relinquish();
245     }
246 
247     if(accept_no_memory != 1)
248          error_counter++;
249 
250     /* Close downt he socket. */
251     ret = soc_close(sockfd);
252     if(ret < 0)
253         error_counter++;
254 
255     for(i = 0; i < NUM_CLIENTS; i++)
256     {
257 
258         /* Wakeup server thread. */
259         tx_semaphore_get(&sema_0, 5 * NX_IP_PERIODIC_RATE);
260     }
261 }
262 
263 
264 /* Define the test threads.  */
ntest_0_entry(ULONG thread_input)265 static void    ntest_0_entry(ULONG thread_input)
266 {
267 
268     printf("NetX Test:   Basic BSD TCP Accept Blocking Timeout Test....");
269 
270     /* Check for earlier error.  */
271     if (error_counter)
272     {
273 
274         printf("ERROR!\n");
275         test_control_return(1);
276     }
277 
278     /* Wakeup client. */
279     tx_semaphore_put(&sema_1);
280 
281     test_tcp_server4();
282 
283     /* Wait until client finish. */
284     tx_semaphore_get(&sema_0, 5 * NX_IP_PERIODIC_RATE);
285 
286     validate_bsd_structure();
287 
288     if(error_counter)
289         printf("ERROR!\n");
290     else
291         printf("SUCCESS!\n");
292 
293     if(error_counter)
294         test_control_return(1);
295 
296     test_control_return(0);
297 }
298 
299 static NX_TCP_SOCKET tcp_sockets[NUM_CLIENTS];
multiple_client4(void)300 static void    multiple_client4(void)
301 {
302 
303 int           i;
304 UINT          status = NX_SUCCESS;
305 NX_PACKET     *packet_ptr;
306     for(i = 0; i < NUM_CLIENTS; i++)
307     {
308         status +=  nx_tcp_socket_create(&ip_1, &tcp_sockets[i], "Server Socket",
309                                         NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 100,
310                                         NX_NULL, NX_NULL);
311         status +=  nx_tcp_client_socket_bind(&tcp_sockets[i], NX_ANY_PORT, 0);
312     }
313     if(status != NX_SUCCESS)
314         error_counter++;
315 
316     status = NX_SUCCESS;
317     for(i = 0; i < (NUM_CLIENTS - 1); i++)
318     {
319         status += nx_tcp_client_socket_connect(&tcp_sockets[i], IP_ADDRESS(1, 2, 3, 4), 12345, NX_IP_PERIODIC_RATE);
320 
321     }
322     if(status != NX_SUCCESS)
323         error_counter++;
324 
325     /* Now we should be able to try another connection */
326     status = nx_tcp_client_socket_connect(&tcp_sockets[NUM_CLIENTS - 1], IP_ADDRESS(1, 2, 3, 4), 12345, NX_IP_PERIODIC_RATE);
327     if(status == NX_SUCCESS)
328     {
329         /* At this point, we anticpate the BSD system to run out of resource and is unable to make
330            this connection.  */
331         error_counter++;
332     }
333     else
334     {
335         /* Let's delete the socket. */
336         if(tcp_sockets[NUM_CLIENTS - 1].nx_tcp_socket_bound_next)
337         {
338             status = nx_tcp_client_socket_unbind(&tcp_sockets[NUM_CLIENTS - 1]);
339             if(status)
340                 error_counter++;
341         }
342 
343         status = nx_tcp_socket_delete(&tcp_sockets[NUM_CLIENTS - 1]);
344 
345         /* Recreate the socket. */
346         status +=  nx_tcp_socket_create(&ip_1, &tcp_sockets[NUM_CLIENTS - 1], "Server Socket",
347                                         NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 100,
348                                         NX_NULL, NX_NULL);
349         status +=  nx_tcp_client_socket_bind(&tcp_sockets[NUM_CLIENTS - 1], NX_ANY_PORT, 0);
350         if(status)
351             error_counter++;
352     }
353 
354     status = NX_SUCCESS;
355 
356     /* Send messages to each server */
357     for(i = 0; i < (NUM_CLIENTS - 1); i++)
358     {
359         status += nx_packet_allocate(&pool_0, &packet_ptr, NX_TCP_PACKET, NX_NO_WAIT);
360         status += nx_packet_data_append(packet_ptr, requests[i & 3], strlen(requests[i & 3]),
361                                         &pool_0, NX_NO_WAIT);
362         status += nx_tcp_socket_send(&tcp_sockets[i], packet_ptr, NX_IP_PERIODIC_RATE);
363 
364     }
365 
366     if(status != NX_SUCCESS)
367         error_counter++;
368 
369     status = NX_SUCCESS;
370 
371     /* Receive messages. */
372 
373     for(i = 0; i < NUM_CLIENTS - 1; i++)
374     {
375         status = nx_tcp_socket_receive(&tcp_sockets[i], &packet_ptr, 2 * NX_IP_PERIODIC_RATE);
376         if(status != NX_SUCCESS)
377         {
378             error_counter++;
379             continue;
380         }
381 
382         /* Validate the received data. */
383         else if(packet_ptr -> nx_packet_length != strlen(response[i & 3]))
384             error_counter++;
385         else if(strncmp((char*)packet_ptr -> nx_packet_prepend_ptr, response[i & 3], packet_ptr -> nx_packet_length))
386             error_counter++;
387         nx_packet_release(packet_ptr);
388     }
389 
390     /* Wakeup server thread. */
391     tx_semaphore_put(&sema_2);
392 
393     /* Shutdown one socket (the one in the middle of the group. */
394     status = nx_tcp_socket_disconnect(&tcp_sockets[NUM_CLIENTS/2], NX_IP_PERIODIC_RATE);
395     if(status == NX_NOT_CONNECTED || status == NX_DISCONNECT_FAILED)
396         status = 0;
397 
398     if(tcp_sockets[NUM_CLIENTS/2].nx_tcp_socket_bound_next)
399         status += nx_tcp_client_socket_unbind(&tcp_sockets[NUM_CLIENTS/2]);
400 
401     status += nx_tcp_socket_delete(&tcp_sockets[NUM_CLIENTS/2]);
402     if(status != NX_SUCCESS)
403         error_counter++;
404 
405     /* Now we should be able to try another connection */
406     status = nx_tcp_client_socket_connect(&tcp_sockets[NUM_CLIENTS - 1], IP_ADDRESS(1, 2, 3, 4), 12345, NX_IP_PERIODIC_RATE);
407     if(status != NX_SUCCESS)
408     {
409         /* At this point, we anticpate the BSD system to run out of resource and is unable to make
410            this connection.  */
411         error_counter++;
412     }
413 
414     status = nx_packet_allocate(&pool_0, &packet_ptr, NX_TCP_PACKET, NX_NO_WAIT);
415     status += nx_packet_data_append(packet_ptr, requests[(NUM_CLIENTS - 1) & 3], strlen(requests[(NUM_CLIENTS - 1) & 3]),
416                                     &pool_0, NX_NO_WAIT);
417     status += nx_tcp_socket_send(&tcp_sockets[NUM_CLIENTS - 1], packet_ptr, NX_IP_PERIODIC_RATE);
418     if(status != NX_SUCCESS)
419         error_counter++;
420 
421     status = nx_tcp_socket_receive(&tcp_sockets[NUM_CLIENTS - 1], &packet_ptr, 2 * NX_IP_PERIODIC_RATE);
422     if(status != NX_SUCCESS)
423         error_counter++;
424     /* Validate the received data. */
425     else if(packet_ptr -> nx_packet_length != strlen(response[(NUM_CLIENTS - 1) & 3]))
426         error_counter++;
427     else if(strncmp((char*)packet_ptr -> nx_packet_prepend_ptr, response[(NUM_CLIENTS - 1) & 3], packet_ptr -> nx_packet_length))
428         error_counter++;
429     if(status == NX_SUCCESS)
430         nx_packet_release(packet_ptr);
431 
432     /* Wakeup server thread. */
433     for(i = 0; i < NUM_CLIENTS - 2; i++)
434     {
435 
436         /* Wakeup server thread. */
437         tx_semaphore_put(&sema_1);
438     }
439     tx_semaphore_put(&sema_2);
440 
441 
442     /* Shutdown the socket. */
443     for(i = 0; i < NUM_CLIENTS; i++)
444     {
445         if(i == NUM_CLIENTS / 2)
446             continue;
447 
448         status = nx_tcp_socket_disconnect(&tcp_sockets[i], 1 * NX_IP_PERIODIC_RATE);
449         if(status == NX_NOT_CONNECTED || status == NX_DISCONNECT_FAILED)
450             status = 0;
451 
452         if(tcp_sockets[i].nx_tcp_socket_bound_next)
453             status += nx_tcp_client_socket_unbind(&tcp_sockets[i]);
454 
455 
456         status += nx_tcp_socket_delete(&tcp_sockets[i]);
457 
458         if(status != NX_SUCCESS)
459             error_counter++;
460     }
461 }
462 
463 
ntest_1_entry(ULONG thread_input)464 static void    ntest_1_entry(ULONG thread_input)
465 {
466 
467 UINT            status;
468 ULONG           actual_status;
469 
470 
471 
472     /* Ensure the IP instance has been initialized.  */
473     status =  nx_ip_status_check(&ip_1, NX_IP_INITIALIZE_DONE, &actual_status, 1 * NX_IP_PERIODIC_RATE);
474 
475     /* Check status...  */
476     if (status != NX_SUCCESS)
477     {
478 
479         printf("ERROR!\n");
480         test_control_return(3);
481     }
482 
483     /* Server run first. */
484     tx_semaphore_get(&sema_1, 5 * NX_IP_PERIODIC_RATE);
485 
486     /* Simulate a multiple client conneting to the same server. */
487     multiple_client4();
488 
489     /* Client finished. */
490     tx_semaphore_put(&sema_0);
491 }
492 
493 
494 extern TX_BLOCK_POOL nx_bsd_socket_block_pool;
validate_bsd_structure(void)495 static void validate_bsd_structure(void)
496 {
497 int i;
498     /* Make sure every BSD socket should be free by now. */
499 
500     for(i = 0; i < NX_BSD_MAX_SOCKETS; i++)
501     {
502         if(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)
503         {
504             error_counter++;
505         }
506 
507         if(nx_bsd_socket_array[i].nx_bsd_socket_tcp_socket ||
508            nx_bsd_socket_array[i].nx_bsd_socket_udp_socket)
509         {
510             error_counter++;
511         }
512     }
513 
514     /* Make sure all the NX SOCKET control blocks are released. */
515     if(nx_bsd_socket_block_pool.tx_block_pool_available !=
516        nx_bsd_socket_block_pool.tx_block_pool_total)
517     {
518         error_counter++;
519     }
520 
521     /* Make sure all the sockets are released */
522     if(ip_0.nx_ip_tcp_created_sockets_ptr ||
523        ip_0.nx_ip_udp_created_sockets_ptr)
524     {
525         error_counter++;
526         return;
527     }
528 }
529 
530 #else
531 extern void       test_control_return(UINT status);
532 
533 #ifdef CTEST
test_application_define(void * first_unused_memory)534 VOID test_application_define(void *first_unused_memory)
535 #else
536 void    netx_bsd_tcp_accept_blocking_timeout_test_application_define(void *first_unused_memory)
537 #endif
538 {
539 
540     /* Print out test information banner.  */
541     printf("NetX Test:   Basic BSD TCP Accept Blocking Timeout Test....N/A\n");
542 
543     test_control_return(3);
544 }
545 #endif
546