1 /* udp.c - UDP specific code for echo server */
2 
3 /*
4  * Copyright (c) 2017 Intel Corporation.
5  * Copyright (c) 2018 Nordic Semiconductor ASA.
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_DECLARE(net_echo_server_sample, LOG_LEVEL_DBG);
12 
13 #include <zephyr/kernel.h>
14 #include <errno.h>
15 #include <stdio.h>
16 
17 #include <zephyr/net/socket.h>
18 #include <zephyr/net/tls_credentials.h>
19 
20 #include "common.h"
21 #include "certificate.h"
22 
23 static void process_udp4(void);
24 static void process_udp6(void);
25 
26 K_THREAD_DEFINE(udp4_thread_id, STACK_SIZE,
27 		process_udp4, NULL, NULL, NULL,
28 		THREAD_PRIORITY,
29 		IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0, -1);
30 
31 K_THREAD_DEFINE(udp6_thread_id, STACK_SIZE,
32 		process_udp6, NULL, NULL, NULL,
33 		THREAD_PRIORITY,
34 		IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0, -1);
35 
start_udp_proto(struct data * data,struct sockaddr * bind_addr,socklen_t bind_addrlen)36 static int start_udp_proto(struct data *data, struct sockaddr *bind_addr,
37 			   socklen_t bind_addrlen)
38 {
39 	int ret;
40 
41 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
42 	data->udp.sock = socket(bind_addr->sa_family, SOCK_DGRAM,
43 				IPPROTO_DTLS_1_2);
44 #else
45 	data->udp.sock = socket(bind_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
46 #endif
47 	if (data->udp.sock < 0) {
48 		NET_ERR("Failed to create UDP socket (%s): %d", data->proto,
49 			errno);
50 		return -errno;
51 	}
52 
53 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
54 	sec_tag_t sec_tag_list[] = {
55 		SERVER_CERTIFICATE_TAG,
56 #if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
57 		PSK_TAG,
58 #endif
59 	};
60 	int role = TLS_DTLS_ROLE_SERVER;
61 
62 	ret = setsockopt(data->udp.sock, SOL_TLS, TLS_SEC_TAG_LIST,
63 			 sec_tag_list, sizeof(sec_tag_list));
64 	if (ret < 0) {
65 		NET_ERR("Failed to set UDP secure option (%s): %d", data->proto,
66 			errno);
67 		ret = -errno;
68 	}
69 
70 	/* Set role to DTLS server. */
71 	ret = setsockopt(data->udp.sock, SOL_TLS, TLS_DTLS_ROLE,
72 			 &role, sizeof(role));
73 	if (ret < 0) {
74 		NET_ERR("Failed to set DTLS role secure option (%s): %d",
75 			data->proto, errno);
76 		ret = -errno;
77 	}
78 #endif
79 
80 	ret = bind(data->udp.sock, bind_addr, bind_addrlen);
81 	if (ret < 0) {
82 		NET_ERR("Failed to bind UDP socket (%s): %d", data->proto,
83 			errno);
84 		ret = -errno;
85 	}
86 
87 	return ret;
88 }
89 
process_udp(struct data * data)90 static int process_udp(struct data *data)
91 {
92 	int ret = 0;
93 	int received;
94 	struct sockaddr client_addr;
95 	socklen_t client_addr_len;
96 
97 	NET_INFO("Waiting for UDP packets on port %d (%s)...",
98 		 MY_PORT, data->proto);
99 
100 	do {
101 		client_addr_len = sizeof(client_addr);
102 		received = recvfrom(data->udp.sock, data->udp.recv_buffer,
103 				    sizeof(data->udp.recv_buffer), 0,
104 				    &client_addr, &client_addr_len);
105 
106 		if (received < 0) {
107 			/* Socket error */
108 			NET_ERR("UDP (%s): Connection error %d", data->proto,
109 				errno);
110 			ret = -errno;
111 			break;
112 		} else if (received) {
113 			atomic_add(&data->udp.bytes_received, received);
114 		}
115 
116 		ret = sendto(data->udp.sock, data->udp.recv_buffer, received, 0,
117 			     &client_addr, client_addr_len);
118 		if (ret < 0) {
119 			NET_ERR("UDP (%s): Failed to send %d", data->proto,
120 				errno);
121 			ret = -errno;
122 			break;
123 		}
124 
125 		if (++data->udp.counter % 1000 == 0U) {
126 			NET_INFO("%s UDP: Sent %u packets", data->proto,
127 				 data->udp.counter);
128 		}
129 
130 		NET_DBG("UDP (%s): Received and replied with %d bytes",
131 			data->proto, received);
132 	} while (true);
133 
134 	return ret;
135 }
136 
process_udp4(void)137 static void process_udp4(void)
138 {
139 	int ret;
140 	struct sockaddr_in addr4;
141 
142 	(void)memset(&addr4, 0, sizeof(addr4));
143 	addr4.sin_family = AF_INET;
144 	addr4.sin_port = htons(MY_PORT);
145 
146 	ret = start_udp_proto(&conf.ipv4, (struct sockaddr *)&addr4,
147 			      sizeof(addr4));
148 	if (ret < 0) {
149 		quit();
150 		return;
151 	}
152 
153 	while (ret == 0) {
154 		ret = process_udp(&conf.ipv4);
155 		if (ret < 0) {
156 			quit();
157 		}
158 	}
159 }
160 
process_udp6(void)161 static void process_udp6(void)
162 {
163 	int ret;
164 	struct sockaddr_in6 addr6;
165 
166 	(void)memset(&addr6, 0, sizeof(addr6));
167 	addr6.sin6_family = AF_INET6;
168 	addr6.sin6_port = htons(MY_PORT);
169 
170 	ret = start_udp_proto(&conf.ipv6, (struct sockaddr *)&addr6,
171 			      sizeof(addr6));
172 	if (ret < 0) {
173 		quit();
174 		return;
175 	}
176 
177 	while (ret == 0) {
178 		ret = process_udp(&conf.ipv6);
179 		if (ret < 0) {
180 			quit();
181 		}
182 	}
183 }
184 
print_stats(struct k_work * work)185 static void print_stats(struct k_work *work)
186 {
187 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
188 	struct data *data = CONTAINER_OF(dwork, struct data, udp.stats_print);
189 	int total_received = atomic_get(&data->udp.bytes_received);
190 
191 	if (total_received) {
192 		if ((total_received / STATS_TIMER) < 1024) {
193 			LOG_INF("%s UDP: Received %d B/sec", data->proto,
194 				total_received / STATS_TIMER);
195 		} else {
196 			LOG_INF("%s UDP: Received %d KiB/sec", data->proto,
197 				total_received / 1024 / STATS_TIMER);
198 		}
199 
200 		atomic_set(&data->udp.bytes_received, 0);
201 	}
202 
203 	k_work_reschedule(&data->udp.stats_print, K_SECONDS(STATS_TIMER));
204 }
205 
start_udp(void)206 void start_udp(void)
207 {
208 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
209 #if defined(CONFIG_USERSPACE)
210 		k_mem_domain_add_thread(&app_domain, udp6_thread_id);
211 #endif
212 
213 		k_work_init_delayable(&conf.ipv6.udp.stats_print, print_stats);
214 		k_thread_name_set(udp6_thread_id, "udp6");
215 		k_thread_start(udp6_thread_id);
216 		k_work_reschedule(&conf.ipv6.udp.stats_print,
217 				  K_SECONDS(STATS_TIMER));
218 	}
219 
220 	if (IS_ENABLED(CONFIG_NET_IPV4)) {
221 #if defined(CONFIG_USERSPACE)
222 		k_mem_domain_add_thread(&app_domain, udp4_thread_id);
223 #endif
224 
225 		k_work_init_delayable(&conf.ipv4.udp.stats_print, print_stats);
226 		k_thread_name_set(udp4_thread_id, "udp4");
227 		k_thread_start(udp4_thread_id);
228 		k_work_reschedule(&conf.ipv4.udp.stats_print,
229 				  K_SECONDS(STATS_TIMER));
230 	}
231 }
232 
stop_udp(void)233 void stop_udp(void)
234 {
235 	/* Not very graceful way to close a thread, but as we may be blocked
236 	 * in recvfrom call it seems to be necessary
237 	 */
238 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
239 		k_thread_abort(udp6_thread_id);
240 		if (conf.ipv6.udp.sock >= 0) {
241 			(void)close(conf.ipv6.udp.sock);
242 		}
243 	}
244 
245 	if (IS_ENABLED(CONFIG_NET_IPV4)) {
246 		k_thread_abort(udp4_thread_id);
247 		if (conf.ipv4.udp.sock >= 0) {
248 			(void)close(conf.ipv4.udp.sock);
249 		}
250 	}
251 }
252