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