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