1 /*
2  * Copyright (c) 2017 Linaro Limited
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <errno.h>
10 
11 #ifndef __ZEPHYR__
12 
13 #include <netinet/in.h>
14 #include <sys/socket.h>
15 #include <arpa/inet.h>
16 #include <unistd.h>
17 
18 #else
19 
20 #include <zephyr/posix/netinet/in.h>
21 #include <zephyr/posix/sys/socket.h>
22 #include <zephyr/posix/arpa/inet.h>
23 #include <zephyr/posix/unistd.h>
24 #include <zephyr/posix/poll.h>
25 
26 #include <zephyr/net/socket.h>
27 #include <zephyr/kernel.h>
28 
29 #endif
30 
31 #define BIND_PORT 4242
32 
main(void)33 int main(void)
34 {
35 	int opt;
36 	socklen_t optlen = sizeof(int);
37 	int serv, ret;
38 	struct sockaddr_in6 bind_addr = {
39 		.sin6_family = AF_INET6,
40 		.sin6_addr = IN6ADDR_ANY_INIT,
41 		.sin6_port = htons(BIND_PORT),
42 	};
43 	static int counter;
44 
45 	serv = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
46 	if (serv < 0) {
47 		printf("error: socket: %d\n", errno);
48 		exit(1);
49 	}
50 
51 	ret = getsockopt(serv, IPPROTO_IPV6, IPV6_V6ONLY, &opt, &optlen);
52 	if (ret == 0) {
53 		if (opt) {
54 			printf("IPV6_V6ONLY option is on, turning it off.\n");
55 
56 			opt = 0;
57 			ret = setsockopt(serv, IPPROTO_IPV6, IPV6_V6ONLY,
58 					 &opt, optlen);
59 			if (ret < 0) {
60 				printf("Cannot turn off IPV6_V6ONLY option\n");
61 			} else {
62 				printf("Sharing same socket between IPv6 and IPv4\n");
63 			}
64 		}
65 	}
66 
67 	if (bind(serv, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) < 0) {
68 		printf("error: bind: %d\n", errno);
69 		exit(1);
70 	}
71 
72 	if (listen(serv, 5) < 0) {
73 		printf("error: listen: %d\n", errno);
74 		exit(1);
75 	}
76 
77 	printf("Single-threaded TCP echo server waits for a connection on "
78 	       "port %d...\n", BIND_PORT);
79 
80 	while (1) {
81 		struct sockaddr_in6 client_addr;
82 		socklen_t client_addr_len = sizeof(client_addr);
83 		char addr_str[32];
84 		int client = accept(serv, (struct sockaddr *)&client_addr,
85 				    &client_addr_len);
86 
87 		if (client < 0) {
88 			printf("error: accept: %d\n", errno);
89 			continue;
90 		}
91 
92 		inet_ntop(client_addr.sin6_family, &client_addr.sin6_addr,
93 			  addr_str, sizeof(addr_str));
94 		printf("Connection #%d from %s\n", counter++, addr_str);
95 
96 		while (1) {
97 			char buf[128], *p;
98 			int len = recv(client, buf, sizeof(buf), 0);
99 			int out_len;
100 
101 			if (len <= 0) {
102 				if (len < 0) {
103 					printf("error: recv: %d\n", errno);
104 				}
105 				break;
106 			}
107 
108 			p = buf;
109 			do {
110 				out_len = send(client, p, len, 0);
111 				if (out_len < 0) {
112 					printf("error: send: %d\n", errno);
113 					goto error;
114 				}
115 				p += out_len;
116 				len -= out_len;
117 			} while (len);
118 		}
119 
120 error:
121 		close(client);
122 		printf("Connection from %s closed\n", addr_str);
123 	}
124 	return 0;
125 }
126