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