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 	/* Note that in this application we receive / send data from
42 	 * system work queue. In proper application the socket reading and data
43 	 * sending should be done so that the system work queue is not blocked.
44 	 * It is possible to create a socket service that uses own work queue.
45 	 */
46 	receive_data(false, pev, buf, sizeof(buf));
47 }
48 
udp_service_handler(struct net_socket_service_event * pev)49 static void udp_service_handler(struct net_socket_service_event *pev)
50 {
51 	static char buf[1500];
52 
53 	receive_data(true, pev, buf, sizeof(buf));
54 }
55 
56 NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(service_udp, udp_service_handler, MAX_SERVICES);
57 NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(service_tcp, tcp_service_handler, MAX_SERVICES);
58 
receive_data(bool is_udp,struct net_socket_service_event * pev,char * buf,size_t buflen)59 static void receive_data(bool is_udp, struct net_socket_service_event *pev,
60 			 char *buf, size_t buflen)
61 {
62 	struct pollfd *pfd = &pev->event;
63 	int client = pfd->fd;
64 	struct sockaddr_in6 addr;
65 	socklen_t addrlen = sizeof(addr);
66 	int len, out_len;
67 	char *p;
68 
69 	len = recvfrom(client, buf, buflen, 0,
70 		       (struct sockaddr *)&addr, &addrlen);
71 	if (len <= 0) {
72 		if (len < 0) {
73 			LOG_ERR("recv: %d", -errno);
74 		}
75 
76 		/* If the TCP socket is closed, mark it as non pollable */
77 		if (!is_udp && sockfd_tcp[0].fd == client) {
78 			sockfd_tcp[0].fd = -1;
79 
80 			/* Update the handler so that client connection is
81 			 * not monitored any more.
82 			 */
83 			(void)net_socket_service_register(&service_tcp, sockfd_tcp,
84 							  ARRAY_SIZE(sockfd_tcp), NULL);
85 			close(client);
86 
87 			LOG_INF("Connection from %s closed", addr_str);
88 		}
89 
90 		return;
91 	}
92 
93 	p = buf;
94 	do {
95 		if (is_udp) {
96 			out_len = sendto(client, p, len, 0,
97 					 (struct sockaddr *)&addr, addrlen);
98 		} else {
99 			out_len = send(client, p, len, 0);
100 		}
101 
102 		if (out_len < 0) {
103 			LOG_ERR("sendto: %d", -errno);
104 			break;
105 		}
106 
107 		p += out_len;
108 		len -= out_len;
109 	} while (len);
110 }
111 
setup_tcp_socket(struct sockaddr_in6 * addr)112 static int setup_tcp_socket(struct sockaddr_in6 *addr)
113 {
114 	socklen_t optlen = sizeof(int);
115 	int ret, sock, opt;
116 
117 	sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
118 	if (sock < 0) {
119 		LOG_ERR("socket: %d", -errno);
120 		return -errno;
121 	}
122 
123 	ret = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, &optlen);
124 	if (ret == 0 && opt) {
125 		LOG_INF("IPV6_V6ONLY option is on, turning it off.");
126 
127 		opt = 0;
128 		ret = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, optlen);
129 		if (ret < 0) {
130 			LOG_WRN("Cannot turn off IPV6_V6ONLY option");
131 		} else {
132 			LOG_INF("Sharing same socket between IPv6 and IPv4");
133 		}
134 	}
135 
136 	if (bind(sock, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
137 		LOG_ERR("bind: %d", -errno);
138 		return -errno;
139 	}
140 
141 	if (listen(sock, 5) < 0) {
142 		LOG_ERR("listen: %d", -errno);
143 		return -errno;
144 	}
145 
146 	return sock;
147 }
148 
setup_udp_socket(struct sockaddr_in6 * addr)149 static int setup_udp_socket(struct sockaddr_in6 *addr)
150 {
151 	socklen_t optlen = sizeof(int);
152 	int ret, sock, opt;
153 
154 	sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
155 	if (sock < 0) {
156 		LOG_ERR("socket: %d", -errno);
157 		return -errno;
158 	}
159 
160 	ret = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, &optlen);
161 	if (ret == 0 && opt) {
162 		LOG_INF("IPV6_V6ONLY option is on, turning it off.");
163 
164 		opt = 0;
165 		ret = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, optlen);
166 		if (ret < 0) {
167 			LOG_WRN("Cannot turn off IPV6_V6ONLY option");
168 		} else {
169 			LOG_INF("Sharing same socket between IPv6 and IPv4");
170 		}
171 	}
172 
173 	if (bind(sock, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
174 		LOG_ERR("bind: %d", -errno);
175 		return -errno;
176 	}
177 
178 	return sock;
179 }
180 
main(void)181 int main(void)
182 {
183 	int tcp_sock, udp_sock, ret;
184 	struct sockaddr_in6 addr = {
185 		.sin6_family = AF_INET6,
186 		.sin6_addr = IN6ADDR_ANY_INIT,
187 		.sin6_port = htons(MY_PORT),
188 	};
189 	static int counter;
190 
191 	tcp_sock = setup_tcp_socket(&addr);
192 	if (tcp_sock < 0) {
193 		return tcp_sock;
194 	}
195 
196 	udp_sock = setup_udp_socket(&addr);
197 	if (udp_sock < 0) {
198 		return udp_sock;
199 	}
200 
201 	sockfd_udp[0].fd = udp_sock;
202 	sockfd_udp[0].events = POLLIN;
203 
204 	/* Register UDP socket to service handler */
205 	ret = net_socket_service_register(&service_udp, sockfd_udp,
206 					  ARRAY_SIZE(sockfd_udp), NULL);
207 	if (ret < 0) {
208 		LOG_ERR("Cannot register socket service handler (%d)", ret);
209 	}
210 
211 	LOG_INF("Single-threaded TCP/UDP echo server waits "
212 		"for a connection on port %d", MY_PORT);
213 
214 	while (1) {
215 		struct sockaddr_in6 client_addr;
216 		socklen_t client_addr_len = sizeof(client_addr);
217 		int client;
218 
219 		client = accept(tcp_sock, (struct sockaddr *)&client_addr,
220 				&client_addr_len);
221 		if (client < 0) {
222 			LOG_ERR("accept: %d", -errno);
223 			continue;
224 		}
225 
226 		inet_ntop(client_addr.sin6_family, &client_addr.sin6_addr,
227 			  addr_str, sizeof(addr_str));
228 		LOG_INF("Connection #%d from %s (%d)", counter++, addr_str, client);
229 
230 		sockfd_tcp[0].fd = client;
231 		sockfd_tcp[0].events = POLLIN;
232 
233 		/* Register all the sockets to service handler */
234 		ret = net_socket_service_register(&service_tcp, sockfd_tcp,
235 						  ARRAY_SIZE(sockfd_tcp), NULL);
236 		if (ret < 0) {
237 			LOG_ERR("Cannot register socket service handler (%d)",
238 				ret);
239 			break;
240 		}
241 	}
242 
243 	(void)net_socket_service_unregister(&service_tcp);
244 	(void)net_socket_service_unregister(&service_udp);
245 
246 	close(tcp_sock);
247 	close(udp_sock);
248 
249 	return 0;
250 }
251