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 #define MAX_SERVICES (CONFIG_ZVFS_POLL_MAX - 3)
24
25 BUILD_ASSERT(MAX_SERVICES > 0, "Need at least 4 poll fds, increase CONFIG_ZVFS_POLL_MAX");
26
27 K_MUTEX_DEFINE(lock);
28 static struct pollfd sockfd_tcp[MAX_SERVICES];
29 static int tcp_socket = -1;
30 static int udp_socket = -1;
31
32 static void receive_data(bool is_udp, struct net_socket_service_event *pev,
33 char *buf, size_t buflen);
34 static void tcp_accept_handler(struct net_socket_service_event *pev);
35 static void restart_echo_service(void);
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, 1);
52 NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(service_accept, tcp_accept_handler, 1);
53 NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(service_tcp, tcp_service_handler, MAX_SERVICES);
54
client_list_init(void)55 static void client_list_init(void)
56 {
57 k_mutex_lock(&lock, K_FOREVER);
58 ARRAY_FOR_EACH_PTR(sockfd_tcp, sockfd) {
59 sockfd->fd = -1;
60 }
61 k_mutex_unlock(&lock);
62 }
63
client_list_deinit(void)64 static void client_list_deinit(void)
65 {
66 (void)net_socket_service_unregister(&service_tcp);
67
68 k_mutex_lock(&lock, K_FOREVER);
69 ARRAY_FOR_EACH_PTR(sockfd_tcp, sockfd) {
70 if (sockfd->fd != -1) {
71 close(sockfd->fd);
72 sockfd->fd = -1;
73 }
74 }
75 k_mutex_unlock(&lock);
76 }
77
client_list_try_add(int sock)78 static void client_list_try_add(int sock)
79 {
80 int ret;
81
82 k_mutex_lock(&lock, K_FOREVER);
83 ARRAY_FOR_EACH_PTR(sockfd_tcp, sockfd) {
84 if (sockfd->fd == -1) {
85 sockfd->fd = sock;
86 sockfd->events = POLLIN;
87
88 ret = net_socket_service_register(&service_tcp, sockfd_tcp,
89 ARRAY_SIZE(sockfd_tcp), NULL);
90 if (ret < 0) {
91 LOG_ERR("Cannot register socket service handler (%d). "
92 "Attempting to restart service.", ret);
93 restart_echo_service();
94 }
95 k_mutex_unlock(&lock);
96 return;
97 }
98 }
99 k_mutex_unlock(&lock);
100 LOG_WRN("Max capacity reached");
101 close(sock);
102 }
103
client_list_remove(int client)104 static void client_list_remove(int client)
105 {
106 int ret;
107
108 k_mutex_lock(&lock, K_FOREVER);
109 ARRAY_FOR_EACH_PTR(sockfd_tcp, sockfd) {
110 if (sockfd->fd == client) {
111 close(client);
112 sockfd->fd = -1;
113 ret = net_socket_service_register(&service_tcp, sockfd_tcp,
114 ARRAY_SIZE(sockfd_tcp), NULL);
115 if (ret < 0) {
116 LOG_ERR("Cannot register socket service handler (%d). "
117 "Attempting to restart service.", ret);
118 restart_echo_service();
119 }
120 break;
121 }
122 }
123 k_mutex_unlock(&lock);
124 }
125
receive_data(bool is_udp,struct net_socket_service_event * pev,char * buf,size_t buflen)126 static void receive_data(bool is_udp, struct net_socket_service_event *pev,
127 char *buf, size_t buflen)
128 {
129 struct pollfd *pfd = &pev->event;
130 int client = pfd->fd;
131 struct sockaddr_in6 addr;
132 char addr_str[INET6_ADDRSTRLEN];
133 socklen_t addrlen = sizeof(addr);
134 int len, out_len;
135 char *p;
136
137 len = recvfrom(client, buf, buflen, 0,
138 (struct sockaddr *)&addr, &addrlen);
139 if (len <= 0) {
140 if (len < 0) {
141 LOG_ERR("recv: %d", -errno);
142 }
143 if (!is_udp) {
144 client_list_remove(client);
145 inet_ntop(addr.sin6_family, &addr.sin6_addr, addr_str, sizeof(addr_str));
146 LOG_INF("Connection from %s closed", addr_str);
147 }
148 return;
149 }
150
151 p = buf;
152 do {
153 if (is_udp) {
154 out_len = sendto(client, p, len, 0,
155 (struct sockaddr *)&addr, addrlen);
156 } else {
157 out_len = send(client, p, len, 0);
158 }
159
160 if (out_len < 0) {
161 LOG_ERR("sendto: %d", -errno);
162 break;
163 }
164
165 p += out_len;
166 len -= out_len;
167 } while (len);
168 }
169
tcp_accept_handler(struct net_socket_service_event * pev)170 static void tcp_accept_handler(struct net_socket_service_event *pev)
171 {
172 int client;
173 int sock = pev->event.fd;
174 char addr_str[INET6_ADDRSTRLEN];
175 struct sockaddr_in6 client_addr;
176 socklen_t client_addr_len = sizeof(client_addr);
177
178 client = accept(sock, (struct sockaddr *)&client_addr, &client_addr_len);
179 if (client < 0) {
180 LOG_ERR("accept: %d. Restarting service.", -errno);
181 restart_echo_service();
182 return;
183 }
184
185 inet_ntop(client_addr.sin6_family, &client_addr.sin6_addr, addr_str, sizeof(addr_str));
186 LOG_INF("Connection from %s (%d)", addr_str, client);
187
188 client_list_try_add(client);
189 }
190
setup_tcp_socket(struct sockaddr_in6 * addr)191 static int setup_tcp_socket(struct sockaddr_in6 *addr)
192 {
193 socklen_t optlen = sizeof(int);
194 int ret, sock, opt;
195
196 sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
197 if (sock < 0) {
198 LOG_ERR("socket: %d", -errno);
199 return -errno;
200 }
201
202 ret = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, &optlen);
203 if (ret == 0 && opt) {
204 LOG_INF("IPV6_V6ONLY option is on, turning it off.");
205
206 opt = 0;
207 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, optlen);
208 if (ret < 0) {
209 LOG_WRN("Cannot turn off IPV6_V6ONLY option");
210 } else {
211 LOG_INF("Sharing same socket between IPv6 and IPv4");
212 }
213 }
214
215 if (bind(sock, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
216 LOG_ERR("bind: %d", -errno);
217 close(sock);
218 return -errno;
219 }
220
221 if (listen(sock, 5) < 0) {
222 LOG_ERR("listen: %d", -errno);
223 close(sock);
224 return -errno;
225 }
226
227 return sock;
228 }
229
setup_udp_socket(struct sockaddr_in6 * addr)230 static int setup_udp_socket(struct sockaddr_in6 *addr)
231 {
232 socklen_t optlen = sizeof(int);
233 int ret, sock, opt;
234
235 sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
236 if (sock < 0) {
237 LOG_ERR("socket: %d", -errno);
238 return -errno;
239 }
240
241 ret = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, &optlen);
242 if (ret == 0 && opt) {
243 LOG_INF("IPV6_V6ONLY option is on, turning it off.");
244
245 opt = 0;
246 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, optlen);
247 if (ret < 0) {
248 LOG_WRN("Cannot turn off IPV6_V6ONLY option");
249 } else {
250 LOG_INF("Sharing same socket between IPv6 and IPv4");
251 }
252 }
253
254 if (bind(sock, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
255 LOG_ERR("bind: %d", -errno);
256 close(sock);
257 return -errno;
258 }
259
260 return sock;
261 }
262
start_echo_service(void)263 static int start_echo_service(void)
264 {
265 struct pollfd sockfd_accept, sockfd_udp;
266 int tcp_sock, udp_sock, ret;
267 struct sockaddr_in6 addr = {
268 .sin6_family = AF_INET6,
269 .sin6_addr = IN6ADDR_ANY_INIT,
270 .sin6_port = htons(MY_PORT),
271 };
272
273 client_list_init();
274
275 tcp_sock = setup_tcp_socket(&addr);
276 if (tcp_sock < 0) {
277 LOG_ERR("Failed to setup tcp listening socket");
278 return tcp_sock;
279 }
280
281 udp_sock = setup_udp_socket(&addr);
282 if (udp_sock < 0) {
283 LOG_ERR("Failed to setup udp socket");
284 ret = udp_sock;
285 goto cleanup_tcp;
286 }
287
288 /* Register TCP listening socket to service handler */
289 sockfd_accept = (struct pollfd){ .fd = tcp_sock, .events = POLLIN };
290 ret = net_socket_service_register(&service_accept, &sockfd_accept, 1, NULL);
291 if (ret < 0) {
292 LOG_ERR("Cannot register socket service handler (%d)", ret);
293 goto cleanup_sockets;
294 }
295
296 /* Register UDP socket to service handler */
297 sockfd_udp = (struct pollfd){ .fd = udp_sock, .events = POLLIN };
298 ret = net_socket_service_register(&service_udp, &sockfd_udp, 1, NULL);
299 if (ret < 0) {
300 LOG_ERR("Cannot register socket service handler (%d)", ret);
301 goto cleanup_sockets;
302 }
303
304 k_mutex_lock(&lock, K_FOREVER);
305 tcp_socket = tcp_sock;
306 udp_socket = udp_sock;
307 k_mutex_unlock(&lock);
308
309 LOG_INF("Single-threaded TCP/UDP echo server waits "
310 "for a connection on port %d", MY_PORT);
311
312 return 0;
313
314 cleanup_sockets:
315 close(udp_sock);
316 cleanup_tcp:
317 close(tcp_sock);
318 return -1;
319
320 }
321
stop_echo_service(void)322 static int stop_echo_service(void)
323 {
324 client_list_deinit();
325 (void)net_socket_service_unregister(&service_udp);
326 (void)net_socket_service_unregister(&service_accept);
327
328 k_mutex_lock(&lock, K_FOREVER);
329 if (tcp_socket >= 0) {
330 close(tcp_socket);
331 tcp_socket = -1;
332 }
333 if (udp_socket >= 0) {
334 close(udp_socket);
335 udp_socket = -1;
336 }
337 k_mutex_unlock(&lock);
338
339 return 0;
340 }
341
restart_echo_service(void)342 static void restart_echo_service(void)
343 {
344 stop_echo_service();
345 start_echo_service();
346 }
347
348 SYS_INIT(start_echo_service, APPLICATION, 99);
349