1 /*
2  * Copyright (c) 2023 Nordic Semiconductor
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_echo_server_svc_sample, LOG_LEVEL_DBG);
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <errno.h>
13 
14 #include <zephyr/kernel.h>
15 #include <zephyr/posix/unistd.h>
16 #include <zephyr/posix/poll.h>
17 #include <zephyr/posix/arpa/inet.h>
18 #include <zephyr/posix/sys/socket.h>
19 #include <zephyr/net/socket_service.h>
20 
21 #define MY_PORT 4242
22 
23 static char addr_str[INET6_ADDRSTRLEN];
24 
25 static struct pollfd sockfd_udp[1] = {
26 	[0] = { .fd = -1 }, /* UDP socket */
27 };
28 static struct pollfd sockfd_tcp[1] = {
29 	[0] = { .fd = -1 }, /* TCP socket */
30 };
31 
32 #define MAX_SERVICES 1
33 
34 static void receive_data(bool is_udp, struct net_socket_service_event *pev,
35 			 char *buf, size_t buflen);
36 
tcp_service_handler(struct net_socket_service_event * pev)37 static void tcp_service_handler(struct net_socket_service_event *pev)
38 {
39 	static char buf[1500];
40 
41 	receive_data(false, pev, buf, sizeof(buf));
42 }
43 
udp_service_handler(struct net_socket_service_event * pev)44 static void udp_service_handler(struct net_socket_service_event *pev)
45 {
46 	static char buf[1500];
47 
48 	receive_data(true, pev, buf, sizeof(buf));
49 }
50 
51 NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(service_udp, udp_service_handler, MAX_SERVICES);
52 NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(service_tcp, tcp_service_handler, MAX_SERVICES);
53 
receive_data(bool is_udp,struct net_socket_service_event * pev,char * buf,size_t buflen)54 static void receive_data(bool is_udp, struct net_socket_service_event *pev,
55 			 char *buf, size_t buflen)
56 {
57 	struct pollfd *pfd = &pev->event;
58 	int client = pfd->fd;
59 	struct sockaddr_in6 addr;
60 	socklen_t addrlen = sizeof(addr);
61 	int len, out_len;
62 	char *p;
63 
64 	len = recvfrom(client, buf, buflen, 0,
65 		       (struct sockaddr *)&addr, &addrlen);
66 	if (len <= 0) {
67 		if (len < 0) {
68 			LOG_ERR("recv: %d", -errno);
69 		}
70 
71 		/* If the TCP socket is closed, mark it as non pollable */
72 		if (!is_udp && sockfd_tcp[0].fd == client) {
73 			sockfd_tcp[0].fd = -1;
74 
75 			/* Update the handler so that client connection is
76 			 * not monitored any more.
77 			 */
78 			(void)net_socket_service_register(&service_tcp, sockfd_tcp,
79 							  ARRAY_SIZE(sockfd_tcp), NULL);
80 			close(client);
81 
82 			LOG_INF("Connection from %s closed", addr_str);
83 		}
84 
85 		return;
86 	}
87 
88 	p = buf;
89 	do {
90 		if (is_udp) {
91 			out_len = sendto(client, p, len, 0,
92 					 (struct sockaddr *)&addr, addrlen);
93 		} else {
94 			out_len = send(client, p, len, 0);
95 		}
96 
97 		if (out_len < 0) {
98 			LOG_ERR("sendto: %d", -errno);
99 			break;
100 		}
101 
102 		p += out_len;
103 		len -= out_len;
104 	} while (len);
105 }
106 
setup_tcp_socket(struct sockaddr_in6 * addr)107 static int setup_tcp_socket(struct sockaddr_in6 *addr)
108 {
109 	socklen_t optlen = sizeof(int);
110 	int ret, sock, opt;
111 
112 	sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
113 	if (sock < 0) {
114 		LOG_ERR("socket: %d", -errno);
115 		return -errno;
116 	}
117 
118 	ret = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, &optlen);
119 	if (ret == 0 && opt) {
120 		LOG_INF("IPV6_V6ONLY option is on, turning it off.");
121 
122 		opt = 0;
123 		ret = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, optlen);
124 		if (ret < 0) {
125 			LOG_WRN("Cannot turn off IPV6_V6ONLY option");
126 		} else {
127 			LOG_INF("Sharing same socket between IPv6 and IPv4");
128 		}
129 	}
130 
131 	if (bind(sock, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
132 		LOG_ERR("bind: %d", -errno);
133 		return -errno;
134 	}
135 
136 	if (listen(sock, 5) < 0) {
137 		LOG_ERR("listen: %d", -errno);
138 		return -errno;
139 	}
140 
141 	return sock;
142 }
143 
setup_udp_socket(struct sockaddr_in6 * addr)144 static int setup_udp_socket(struct sockaddr_in6 *addr)
145 {
146 	socklen_t optlen = sizeof(int);
147 	int ret, sock, opt;
148 
149 	sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
150 	if (sock < 0) {
151 		LOG_ERR("socket: %d", -errno);
152 		return -errno;
153 	}
154 
155 	ret = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, &optlen);
156 	if (ret == 0 && opt) {
157 		LOG_INF("IPV6_V6ONLY option is on, turning it off.");
158 
159 		opt = 0;
160 		ret = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, optlen);
161 		if (ret < 0) {
162 			LOG_WRN("Cannot turn off IPV6_V6ONLY option");
163 		} else {
164 			LOG_INF("Sharing same socket between IPv6 and IPv4");
165 		}
166 	}
167 
168 	if (bind(sock, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
169 		LOG_ERR("bind: %d", -errno);
170 		return -errno;
171 	}
172 
173 	return sock;
174 }
175 
main(void)176 int main(void)
177 {
178 	int tcp_sock, udp_sock, ret;
179 	struct sockaddr_in6 addr = {
180 		.sin6_family = AF_INET6,
181 		.sin6_addr = IN6ADDR_ANY_INIT,
182 		.sin6_port = htons(MY_PORT),
183 	};
184 	static int counter;
185 
186 	tcp_sock = setup_tcp_socket(&addr);
187 	if (tcp_sock < 0) {
188 		return tcp_sock;
189 	}
190 
191 	udp_sock = setup_udp_socket(&addr);
192 	if (udp_sock < 0) {
193 		return udp_sock;
194 	}
195 
196 	sockfd_udp[0].fd = udp_sock;
197 	sockfd_udp[0].events = POLLIN;
198 
199 	/* Register UDP socket to service handler */
200 	ret = net_socket_service_register(&service_udp, sockfd_udp,
201 					  ARRAY_SIZE(sockfd_udp), NULL);
202 	if (ret < 0) {
203 		LOG_ERR("Cannot register socket service handler (%d)", ret);
204 	}
205 
206 	LOG_INF("Single-threaded TCP/UDP echo server waits "
207 		"for a connection on port %d", MY_PORT);
208 
209 	while (1) {
210 		struct sockaddr_in6 client_addr;
211 		socklen_t client_addr_len = sizeof(client_addr);
212 		int client;
213 
214 		client = accept(tcp_sock, (struct sockaddr *)&client_addr,
215 				&client_addr_len);
216 		if (client < 0) {
217 			LOG_ERR("accept: %d", -errno);
218 			continue;
219 		}
220 
221 		inet_ntop(client_addr.sin6_family, &client_addr.sin6_addr,
222 			  addr_str, sizeof(addr_str));
223 		LOG_INF("Connection #%d from %s (%d)", counter++, addr_str, client);
224 
225 		sockfd_tcp[0].fd = client;
226 		sockfd_tcp[0].events = POLLIN;
227 
228 		/* Register all the sockets to service handler */
229 		ret = net_socket_service_register(&service_tcp, sockfd_tcp,
230 						  ARRAY_SIZE(sockfd_tcp), NULL);
231 		if (ret < 0) {
232 			LOG_ERR("Cannot register socket service handler (%d)",
233 				ret);
234 			break;
235 		}
236 	}
237 
238 	(void)net_socket_service_unregister(&service_tcp);
239 	(void)net_socket_service_unregister(&service_udp);
240 
241 	close(tcp_sock);
242 	close(udp_sock);
243 
244 	return 0;
245 }
246