1 /* This is a small demo of BSD Wrapper for the high-performance NetX TCP/IP stack.
2    This demo used standard BSD services for TCP connection, disconnection, sending, and
3    receiving using a simulated Ethernet driver.  */
4 
5 
6 #include         "tx_api.h"
7 #include         "nx_api.h"
8 #include         "nxd_bsd.h"
9 #include         <string.h>
10 #include         <stdlib.h>
11 
12 #define          DEMO_STACK_SIZE     (16*1024)
13 #define          SERVER_PORT          87
14 #define          CLIENT_PORT          77
15 #define          SERVER_RCV_BUFFER_SIZE 100
16 
17 
18 /* Define the ThreadX and NetX object control blocks... */
19 
20 TX_THREAD        thread_server;
21 TX_THREAD        thread_client;
22 NX_PACKET_POOL   bsd_pool;
23 NX_IP            bsd_ip;
24 
25 /* Define some global data. */
26 INT      maxfd;
27 
28 /* Define the counters used in the demo application...  */
29 
30 ULONG            error_counter;
31 
32 /* Define fd_sets for the BSD server socket.  */
33 fd_set           master_list, read_ready;
34 
35 #ifdef NX_DISABLE_IPV4
36 /* To send IPv6 packets, define DUO.  */
37 #define  DUO
38 #endif
39 
40 
41 /* Define thread prototypes.  */
42 
43 VOID        thread_server_entry(ULONG thread_input);
44 VOID        thread_client_entry(ULONG thread_input);
45 void        _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
46 
47 
48 /* Define main entry point.  */
49 
main()50 int main()
51 {
52 
53     /* Enter the ThreadX kernel.  */
54     tx_kernel_enter();
55 }
56 
57 /* Define what the initial system looks like.  */
58 
tx_application_define(void * first_unused_memory)59 void    tx_application_define(void *first_unused_memory)
60 {
61 CHAR    *pointer;
62 UINT    status;
63 
64 
65     /* Setup the working pointer.  */
66     pointer =  (CHAR *) first_unused_memory;
67 
68     /* Create a server thread.  */
69     tx_thread_create(&thread_server, "Server", thread_server_entry, 0,
70                           pointer, DEMO_STACK_SIZE, 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
71 
72     pointer =  pointer + DEMO_STACK_SIZE;
73 
74     /* Create a Client thread.  */
75     tx_thread_create(&thread_client, "Client", thread_client_entry, 0,
76                           pointer, DEMO_STACK_SIZE, 16, 16, TX_NO_TIME_SLICE, TX_AUTO_START);
77 
78     pointer =  pointer + DEMO_STACK_SIZE;
79 
80 
81     /* Initialize the NetX system.  */
82     nx_system_initialize();
83 
84     /* Create a BSD packet pool.  */
85     status =  nx_packet_pool_create(&bsd_pool, "NetX BSD Packet Pool", 128, pointer, 16384);
86     pointer = pointer + 16384;
87     if (status)
88     {
89     error_counter++;
90         printf("Error in creating BSD packet pool\n!");
91     }
92 
93     /* Create an IP instance for BSD.  */
94     status = nx_ip_create(&bsd_ip, "BSD IP Instance", IP_ADDRESS(1,2,3,4), 0xFFFFFF00UL,  &bsd_pool, _nx_ram_network_driver,
95                     pointer, 2048, 1);
96     pointer =  pointer + 2048;
97 
98     if (status)
99     {
100     error_counter++;
101         printf("Error creating BSD IP instance\n!");
102     }
103 
104 #ifndef NX_DISABLE_IPV4
105     /* Enable ARP and supply ARP cache memory for BSD IP Instance */
106     status =  nx_arp_enable(&bsd_ip, (void *) pointer, 1024);
107     pointer = pointer + 1024;
108 
109     /* Check ARP enable status.  */
110     if (status)
111     {
112         error_counter++;
113         printf("Error in Enable ARP and supply ARP cache memory to BSD IP instance\n");
114     }
115 #endif /* NX_DISABLE_IPV4 */
116 
117     /* Enable TCP processing for BSD IP instances.  */
118 
119     status = nx_tcp_enable(&bsd_ip);
120 
121     /* Check TCP enable status.  */
122     if (status)
123     {
124         error_counter++;
125         printf("Error in Enable TCP \n");
126     }
127 
128     /* Now initialize BSD Scoket Wrapper */
129     status = (UINT)bsd_initialize (&bsd_ip, &bsd_pool,pointer, 2048, 2);
130 }
131 
132 
133 /* Define the Server thread.  */
134 CHAR        Server_Rcv_Buffer[SERVER_RCV_BUFFER_SIZE];
135 
thread_server_entry(ULONG thread_input)136 VOID  thread_server_entry(ULONG thread_input)
137 {
138 
139 
140 INT         status,  sock, sock_tcp_server;
141 ULONG       actual_status;
142 INT         Clientlen;
143 INT         i;
144 INT         is_set = 0;
145 #ifdef DUO
146 NXD_ADDRESS ip_address;
147 struct      sockaddr_in6 serverAddr;
148 struct      sockaddr_in6 ClientAddr;
149 UINT        iface_index, address_index;
150 #else
151 struct      sockaddr_in serverAddr;
152 struct      sockaddr_in ClientAddr;
153 #endif
154 
155     NX_PARAMETER_NOT_USED(thread_input);
156 
157     status =  (INT)nx_ip_status_check(&bsd_ip, NX_IP_INITIALIZE_DONE, &actual_status, NX_IP_PERIODIC_RATE);
158 
159     /* Check status...  */
160     if (status != NX_SUCCESS)
161     {
162         return;
163     }
164 
165 #ifdef DUO
166     /* Enable IPv6 */
167     status = (INT)nxd_ipv6_enable(&bsd_ip);
168     if(status != NX_SUCCESS)
169     {
170         printf("Error with IPv6 enable 0x%x\n", status);
171         return;
172     }
173 
174     /* Enable ICMPv6 */
175     status = (INT)nxd_icmp_enable(&bsd_ip);
176     if(status)
177     {
178         printf("Error with ECMPv6 enable 0x%x\n", status);
179         return;
180     }
181 
182     /* Set the primary interface for our DNS IPv6 addresses. */
183     iface_index = 0;
184 
185     /* This assumes we are using the primary network interface (index 0). */
186     status = (INT)nxd_ipv6_address_set(&bsd_ip, iface_index, NX_NULL, 10, &address_index);
187 
188     if (status)
189         return;
190 
191 
192     /* Set ip_0 interface address. */
193     ip_address.nxd_ip_version = NX_IP_VERSION_V6;
194     ip_address.nxd_ip_address.v6[0] = 0x20010db8;
195     ip_address.nxd_ip_address.v6[1] = 0x0000f101;
196     ip_address.nxd_ip_address.v6[2] = 0;
197     ip_address.nxd_ip_address.v6[3] = 0x101;
198 
199     /* Set the host global IP address. We are assuming a 64
200        bit prefix here but this can be any value (< 128). */
201     status = (INT)nxd_ipv6_address_set(&bsd_ip, iface_index, &ip_address, 64, &address_index);
202 
203     if (status)
204         return;
205 
206     /* Wait for IPv6 stack to finish DAD process. */
207     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
208 
209 #endif
210 
211     /* Create BSD TCP Socket */
212 #ifdef DUO
213     sock_tcp_server = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
214 #else
215     sock_tcp_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
216 #endif
217 
218     if (sock_tcp_server == -1)
219     {
220         printf("\nError: BSD TCP Server socket create \n");
221         return;
222     }
223 
224     printf("\nBSD TCP Server socket created %lu \n", (ULONG)sock_tcp_server);
225 
226     /* Set the server port and IP address */
227 #ifdef DUO
228     memset(&serverAddr, 0, sizeof(serverAddr));
229     serverAddr.sin6_addr._S6_un._S6_u32[0] = htonl(0x20010db8u);
230     serverAddr.sin6_addr._S6_un._S6_u32[1] = htonl(0xf101u);
231     serverAddr.sin6_addr._S6_un._S6_u32[2] = 0x0;
232     serverAddr.sin6_addr._S6_un._S6_u32[3] = htonl(0x0101u);
233     serverAddr.sin6_port = htons(SERVER_PORT);
234     serverAddr.sin6_family = AF_INET6;
235 
236 #else
237     memset(&serverAddr, 0, sizeof(serverAddr));
238     serverAddr.sin_family = AF_INET;
239     serverAddr.sin_addr.s_addr = htonl(IP_ADDRESS(1,2,3,4));
240     serverAddr.sin_port = htons(SERVER_PORT);
241 #endif
242 
243     /* Bind this server socket */
244     status = bind (sock_tcp_server, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
245 
246     if (status < 0)
247     {
248         printf("Error: Server Socket Bind \n");
249         return;
250     }
251 
252     FD_ZERO(&master_list);
253     FD_ZERO(&read_ready);
254     FD_SET(sock_tcp_server,&master_list);
255     maxfd = sock_tcp_server;
256 
257     /* Now listen for any client connections for this server socket */
258     status = listen (sock_tcp_server, 5);
259     if (status < 0)
260     {
261         printf("Error: Server Socket Listen\n");
262         return;
263     }
264     else
265         printf("Server Listen complete\n");
266 
267     /* All set to accept client connections */
268     printf("Now accepting client connections\n");
269 
270     /* Loop to create and establish server connections.  */
271     while(1)
272     {
273 
274         printf("\n");
275 
276         read_ready = master_list;
277 
278         tx_thread_sleep(20);   /* Allow some time to other threads too */
279 
280         /* Let the underlying TCP stack determine the timeout. */
281         status = select(maxfd + 1, &read_ready, 0, 0, 0);
282 
283         if ( (status == ERROR) || (status == 0) )
284         {
285 
286             printf("Error with select? Status 0x%x. Try again\n", status);
287 
288             continue;
289         }
290 
291         /* Detected a connection request. */
292         is_set = FD_ISSET(sock_tcp_server,&read_ready);
293 
294         if(is_set)
295         {
296 
297             Clientlen = sizeof(ClientAddr);
298 
299             sock = accept(sock_tcp_server,(struct sockaddr*)&ClientAddr, &Clientlen);
300 
301             /* Add this new connection to our master list */
302             FD_SET(sock, &master_list);
303 
304             if ( sock > maxfd)
305             {
306                 printf("New connection %d\n", sock);
307 
308                 maxfd = sock;
309             }
310 
311             continue;
312         }
313 
314         /* Check the set of 'ready' sockets, e.g connected to remote host and waiting for
315            notice of packets received. */
316         for (i = 0; i < (maxfd+1); i++)
317         {
318 
319             if (((i+ NX_BSD_SOCKFD_START) != sock_tcp_server) &&
320                  (FD_ISSET(i + NX_BSD_SOCKFD_START, &master_list)) &&
321                  (FD_ISSET(i + NX_BSD_SOCKFD_START, &read_ready)))
322             {
323 
324                 while(1)
325                 {
326 
327                     status = recv(i + NX_BSD_SOCKFD_START, (VOID *)Server_Rcv_Buffer, SERVER_RCV_BUFFER_SIZE, 0);
328 
329                     if (status == ERROR)
330                     {
331                         /* This is a blocking socket. If no data is received, but the connection is still good,
332                            the EAGAIN error is set. If it was a non blocking socket, the EWOULDBLOCK socket
333                            error is set. */
334                         if (errno == EAGAIN)
335                         {
336                             printf("No error received. Try again later\n");
337                             continue;
338                         }
339                         else if (errno == ENOTCONN)
340                         {
341                             /* If the socket connection is terminated, the socket error will be ENOTCONN. */
342                             printf("Connection is broken.  Close the socket.\n");
343                             break;
344                         }
345                         else
346                         {
347                             /* Another error has occurred...probably an internal error of some kind
348                                so best to terminate the connection. */
349                             printf("Error on Client Socket %d receiving data: 0x%x \n", i, errno);
350                             break;
351                         }
352                     }
353                     /* recv returns with message.  Make sure Server_Rcv_Buffer is NULL-terminated. */
354                     if(status == SERVER_RCV_BUFFER_SIZE)
355                         status--;
356                     Server_Rcv_Buffer[status] = 0;
357 
358                     printf("Server socket received from Client on socket %d %lu bytes: %s\n ",
359                            i+ NX_BSD_SOCKFD_START, (ULONG)status, Server_Rcv_Buffer);
360 
361 
362                     status = send(i + NX_BSD_SOCKFD_START, "Hello\n", sizeof("Hello\n"), 0);
363 
364                     if (status == ERROR)
365                     {
366                         printf("Error on Server sending to Client on socket %d\n", i+ NX_BSD_SOCKFD_START);
367                     }
368                     else
369                     {
370                         printf("Server socket message sent to Client on socket %d: Hello\n", i+ NX_BSD_SOCKFD_START);
371                     }
372                 }
373 
374                 /* Close this socket */
375                 status = soc_close(i+ NX_BSD_SOCKFD_START);
376 
377                 if (status != ERROR)
378                 {
379                     printf("Socket closing socket connected to Client on %d \n", i+ NX_BSD_SOCKFD_START);
380                 }
381                 else
382                 {
383 
384                     printf("Error on Server closing socket %d connected to Client \n", i+ NX_BSD_SOCKFD_START);
385                 }
386             }
387         }
388 
389         /* Loop back to check any next client connection */
390     }
391 }
392 
393 CHAR        Client_Rcv_Buffer[100];
394 
thread_client_entry(ULONG thread_input)395 VOID  thread_client_entry(ULONG thread_input)
396 {
397 
398 
399 INT         status;
400 ULONG       actual_status;
401 INT         sock_tcp_client, length;
402 #ifdef DUO
403 struct      sockaddr_in6 echoServAddr6;               /* Echo server address */
404 struct      sockaddr_in6 localAddr6;                  /* Local address */
405 struct      sockaddr_in6 remoteAddr6;                 /* Remote address */
406 #else
407 struct      sockaddr_in echoServAddr;               /* Echo server address */
408 struct      sockaddr_in localAddr;                  /* Local address */
409 struct      sockaddr_in remoteAddr;                 /* Remote address */
410 #endif
411 
412     NX_PARAMETER_NOT_USED(thread_input);
413 
414     status =  (INT)nx_ip_status_check(&bsd_ip, NX_IP_INITIALIZE_DONE, &actual_status, NX_IP_PERIODIC_RATE);
415 
416     /* Check status...  */
417     if (status != NX_SUCCESS)
418     {
419         return;
420     }
421 
422 #ifdef DUO
423     /* Wait for IPv6 stack to finish DAD process. */
424     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
425 
426     /* Fill Local and Server port and IP address */
427     memset(&localAddr6, 0, sizeof(localAddr6));
428     localAddr6.sin6_addr._S6_un._S6_u32[0] = htonl(0x20010db8u);
429     localAddr6.sin6_addr._S6_un._S6_u32[1] = htonl(0xf101u);
430     localAddr6.sin6_addr._S6_un._S6_u32[2] = 0x0;
431     localAddr6.sin6_addr._S6_un._S6_u32[3] = htonl(0x0101u);
432     localAddr6.sin6_port = htons(CLIENT_PORT);
433     localAddr6.sin6_family = AF_INET6;
434 
435     memset(&echoServAddr6, 0, sizeof(echoServAddr6));
436     echoServAddr6.sin6_addr._S6_un._S6_u32[0] = htonl(0x20010db8u);
437     echoServAddr6.sin6_addr._S6_un._S6_u32[1] = htonl(0xf101u);
438     echoServAddr6.sin6_addr._S6_un._S6_u32[2] = 0x0;
439     echoServAddr6.sin6_addr._S6_un._S6_u32[3] = htonl(0x0101u);
440     echoServAddr6.sin6_port = htons(SERVER_PORT);
441     echoServAddr6.sin6_family = AF_INET6;
442 
443 #else
444     memset(&localAddr, 0, sizeof(localAddr));
445     localAddr.sin_family = AF_INET;
446     localAddr.sin_addr.s_addr = htonl(IP_ADDRESS(1,2,3,4));
447     localAddr.sin_port = htons(CLIENT_PORT);
448 
449     memset(&echoServAddr, 0, sizeof(echoServAddr));
450     echoServAddr.sin_family = AF_INET;
451     echoServAddr.sin_addr.s_addr = htonl(IP_ADDRESS(1,2,3,4));
452     echoServAddr.sin_port = htons(SERVER_PORT);
453 #endif  /* DUO */
454 
455     /* Now make client connections with the server. */
456     while (1)
457     {
458 
459          printf("\n");
460         /* Create BSD TCP Socket */
461 #ifdef DUO
462         sock_tcp_client = socket( AF_INET6, SOCK_STREAM, IPPROTO_TCP);
463 #else
464         sock_tcp_client = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP);
465 #endif
466 
467         if (sock_tcp_client == -1)
468         {
469             printf("Error: BSD TCP Client socket create \n");
470             return;
471         }
472 
473         printf("Client socket created %lu \n", (ULONG)sock_tcp_client);
474 
475         /* Now connect this client to the server */
476 #ifdef DUO
477         status = connect(sock_tcp_client, (struct sockaddr *)&echoServAddr6, sizeof(echoServAddr6));
478 #else
479         status = connect(sock_tcp_client, (struct sockaddr *)&echoServAddr, sizeof(echoServAddr));
480 #endif
481 
482         /* Check for error.  */
483         if (status != OK)
484         {
485             printf("\nError: BSD TCP Client socket Connect\n");
486             status = soc_close(sock_tcp_client);
487             return;
488 
489         }
490         /* Get and print source and destination information */
491         printf("Client socket %d connected \n", sock_tcp_client);
492 
493 #ifdef DUO
494         length = sizeof(struct sockaddr_in6);
495         status = getsockname(sock_tcp_client, (struct sockaddr *)&localAddr6, &length);
496         printf("Client port = %u , Client = 0x%x 0x%x 0x%x 0x%x,",
497                             localAddr6.sin6_port,
498                             (UINT)localAddr6.sin6_addr._S6_un._S6_u32[0],
499                             (UINT)localAddr6.sin6_addr._S6_un._S6_u32[1],
500                             (UINT)localAddr6.sin6_addr._S6_un._S6_u32[2],
501                             (UINT)localAddr6.sin6_addr._S6_un._S6_u32[3]);
502 
503         length = sizeof(struct sockaddr_in6);
504         status = getpeername( sock_tcp_client, (struct sockaddr *) &remoteAddr6, &length);
505         printf("Remote port = %u, Remote IP = 0x%x 0x%x 0x%x 0x%x \n",
506                             remoteAddr6.sin6_port,
507                             (UINT)remoteAddr6.sin6_addr._S6_un._S6_u32[0],
508                             (UINT)remoteAddr6.sin6_addr._S6_un._S6_u32[1],
509                             (UINT)remoteAddr6.sin6_addr._S6_un._S6_u32[2],
510                             (UINT)remoteAddr6.sin6_addr._S6_un._S6_u32[3]);
511 #else
512         length = sizeof(struct sockaddr_in);
513         status = getsockname(sock_tcp_client, (struct sockaddr *)&localAddr, &length);
514         printf("Client port = %lu , Client = 0x%x,", (ULONG)localAddr.sin_port, (UINT)localAddr.sin_addr.s_addr);
515         length = sizeof(struct sockaddr_in);
516         status = getpeername( sock_tcp_client, (struct sockaddr *) &remoteAddr, &length);
517         printf("Remote port = %lu, Remote IP = 0x%x \n", (ULONG)remoteAddr.sin_port, (UINT)remoteAddr.sin_addr.s_addr);
518 #endif
519 
520         /* Now receive the echoed packet from the server */
521         while(1)
522         {
523 
524             printf("Client sock %d sending packet to server\n", sock_tcp_client);
525 
526             status = send(sock_tcp_client, "Hello", (sizeof("Hello")), 0);
527 
528             if (status == ERROR)
529             {
530                 printf("Error: Client Socket (%d) send \n", sock_tcp_client);
531             }
532             else
533             {
534                 printf("Client socket %d sent message Hello\n", sock_tcp_client);
535             }
536 
537             status = recv(sock_tcp_client, (VOID *)Client_Rcv_Buffer, 100, 0);
538 
539             if (status < 0)
540             {
541 
542                 printf("Connection terminated or error on receiving data on socket %d \n", sock_tcp_client);
543 
544                 break;
545             }
546             else
547             {
548                 printf("Client socket %d received %d bytes and this message: %s\n", sock_tcp_client, status, Client_Rcv_Buffer);
549             }
550 
551         }
552 
553         /* close this client socket */
554         status = soc_close(sock_tcp_client);
555 
556         if (status != ERROR)
557         {
558             printf("Client Socket %d closed\n", sock_tcp_client);
559         }
560         else
561         {
562             printf("Error: Client Socket %d on close \n", sock_tcp_client);
563         }
564 
565         /* Make another Client connection...*/
566 
567     }
568 }
569 
570 
571