1 /* echo-client.c - Networking echo client */
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 /*
11  * The echo-client application is acting as a client that is run in Zephyr OS,
12  * and echo-server is run in the host acting as a server. The client will send
13  * either unicast or multicast packets to the server which will reply the packet
14  * back to the originator.
15  *
16  * In this sample application we create four threads that start to send data.
17  * This might not be what you want to do in your app so caveat emptor.
18  */
19 
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_REGISTER(net_echo_client_sample, LOG_LEVEL_DBG);
22 
23 #include <zephyr/kernel.h>
24 #include <errno.h>
25 #include <stdio.h>
26 
27 #include <zephyr/posix/sys/eventfd.h>
28 
29 #include <zephyr/misc/lorem_ipsum.h>
30 #include <zephyr/net/socket.h>
31 #include <zephyr/net/tls_credentials.h>
32 #include <zephyr/net/net_if.h>
33 #include <zephyr/net/net_mgmt.h>
34 #include <zephyr/net/net_event.h>
35 #include <zephyr/net/conn_mgr_monitor.h>
36 
37 #if defined(CONFIG_USERSPACE)
38 #include <zephyr/app_memory/app_memdomain.h>
39 K_APPMEM_PARTITION_DEFINE(app_partition);
40 struct k_mem_domain app_domain;
41 #endif
42 
43 #include "common.h"
44 #include "ca_certificate.h"
45 
46 #define APP_BANNER "Run echo client"
47 
48 #define INVALID_SOCK (-1)
49 
50 #define EVENT_MASK (NET_EVENT_L4_CONNECTED | \
51 		    NET_EVENT_L4_DISCONNECTED)
52 #define IPV6_EVENT_MASK (NET_EVENT_IPV6_ADDR_ADD | \
53 			 NET_EVENT_IPV6_ADDR_DEPRECATED)
54 
55 const char lorem_ipsum[] = LOREM_IPSUM;
56 
57 const int ipsum_len = sizeof(lorem_ipsum) - 1;
58 
59 APP_DMEM struct configs conf = {
60 	.ipv4 = {
61 		.proto = "IPv4",
62 		.udp.sock = INVALID_SOCK,
63 		.tcp.sock = INVALID_SOCK,
64 	},
65 	.ipv6 = {
66 		.proto = "IPv6",
67 		.udp.sock = INVALID_SOCK,
68 		.tcp.sock = INVALID_SOCK,
69 	},
70 };
71 
72 static APP_BMEM struct pollfd fds[1 + 4];
73 static APP_BMEM int nfds;
74 
75 static APP_BMEM bool connected;
76 static APP_BMEM bool need_restart;
77 
78 K_SEM_DEFINE(run_app, 0, 1);
79 
80 static struct net_mgmt_event_callback mgmt_cb;
81 static struct net_mgmt_event_callback ipv6_mgmt_cb;
82 
prepare_fds(void)83 static void prepare_fds(void)
84 {
85 	nfds = 0;
86 
87 	/* eventfd is used to trigger restart */
88 	fds[nfds].fd = eventfd(0, 0);
89 	fds[nfds].events = POLLIN;
90 	nfds++;
91 
92 	if (conf.ipv4.udp.sock >= 0) {
93 		fds[nfds].fd = conf.ipv4.udp.sock;
94 		fds[nfds].events = POLLIN;
95 		nfds++;
96 	}
97 
98 	if (conf.ipv4.tcp.sock >= 0) {
99 		fds[nfds].fd = conf.ipv4.tcp.sock;
100 		fds[nfds].events = POLLIN;
101 		nfds++;
102 	}
103 
104 	if (conf.ipv6.udp.sock >= 0) {
105 		fds[nfds].fd = conf.ipv6.udp.sock;
106 		fds[nfds].events = POLLIN;
107 		nfds++;
108 	}
109 
110 	if (conf.ipv6.tcp.sock >= 0) {
111 		fds[nfds].fd = conf.ipv6.tcp.sock;
112 		fds[nfds].events = POLLIN;
113 		nfds++;
114 	}
115 }
116 
wait(void)117 static void wait(void)
118 {
119 	int ret;
120 
121 	/* Wait for event on any socket used. Once event occurs,
122 	 * we'll check them all.
123 	 */
124 	ret = poll(fds, nfds, -1);
125 	if (ret < 0) {
126 		static bool once;
127 
128 		if (!once) {
129 			once = true;
130 			LOG_ERR("Error in poll:%d", errno);
131 		}
132 
133 		return;
134 	}
135 
136 	if (ret > 0 && fds[0].revents) {
137 		eventfd_t value;
138 
139 		eventfd_read(fds[0].fd, &value);
140 		LOG_DBG("Received restart event.");
141 		return;
142 	}
143 }
144 
start_udp_and_tcp(void)145 static int start_udp_and_tcp(void)
146 {
147 	int ret;
148 
149 	LOG_INF("Starting...");
150 
151 	if (IS_ENABLED(CONFIG_NET_TCP)) {
152 		ret = start_tcp();
153 		if (ret < 0) {
154 			return ret;
155 		}
156 	}
157 
158 	if (IS_ENABLED(CONFIG_NET_UDP)) {
159 		ret = start_udp();
160 		if (ret < 0) {
161 			return ret;
162 		}
163 	}
164 
165 	prepare_fds();
166 
167 	return 0;
168 }
169 
run_udp_and_tcp(void)170 static int run_udp_and_tcp(void)
171 {
172 	int ret;
173 
174 	wait();
175 
176 	if (IS_ENABLED(CONFIG_NET_TCP)) {
177 		ret = process_tcp();
178 		if (ret < 0) {
179 			return ret;
180 		}
181 	}
182 
183 	if (IS_ENABLED(CONFIG_NET_UDP)) {
184 		ret = process_udp();
185 		if (ret < 0) {
186 			return ret;
187 		}
188 	}
189 
190 	return 0;
191 }
192 
stop_udp_and_tcp(void)193 static void stop_udp_and_tcp(void)
194 {
195 	LOG_INF("Stopping...");
196 
197 	if (IS_ENABLED(CONFIG_NET_UDP)) {
198 		stop_udp();
199 	}
200 
201 	if (IS_ENABLED(CONFIG_NET_TCP)) {
202 		stop_tcp();
203 	}
204 }
205 
check_our_ipv6_sockets(int sock,struct in6_addr * deprecated_addr)206 static int check_our_ipv6_sockets(int sock,
207 				  struct in6_addr *deprecated_addr)
208 {
209 	struct sockaddr_in6 addr = { 0 };
210 	socklen_t addrlen = sizeof(addr);
211 	int ret;
212 
213 	if (sock < 0) {
214 		return -EINVAL;
215 	}
216 
217 	ret = getsockname(sock, (struct sockaddr *)&addr, &addrlen);
218 	if (ret != 0) {
219 		return -errno;
220 	}
221 
222 	if (!net_ipv6_addr_cmp(deprecated_addr, &addr.sin6_addr)) {
223 		return -ENOENT;
224 	}
225 
226 	need_restart = true;
227 
228 	return 0;
229 }
230 
ipv6_event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)231 static void ipv6_event_handler(struct net_mgmt_event_callback *cb,
232 			       uint32_t mgmt_event, struct net_if *iface)
233 {
234 	static char addr_str[INET6_ADDRSTRLEN];
235 
236 	if (!IS_ENABLED(CONFIG_NET_IPV6_PE)) {
237 		return;
238 	}
239 
240 	if ((mgmt_event & IPV6_EVENT_MASK) != mgmt_event) {
241 		return;
242 	}
243 
244 	if (cb->info == NULL ||
245 	    cb->info_length != sizeof(struct in6_addr)) {
246 		return;
247 	}
248 
249 	if (mgmt_event == NET_EVENT_IPV6_ADDR_ADD) {
250 		struct net_if_addr *ifaddr;
251 		struct in6_addr added_addr;
252 
253 		memcpy(&added_addr, cb->info, sizeof(struct in6_addr));
254 
255 		ifaddr = net_if_ipv6_addr_lookup(&added_addr, &iface);
256 		if (ifaddr == NULL) {
257 			return;
258 		}
259 
260 		/* Wait until we get a temporary address before continuing after
261 		 * boot.
262 		 */
263 		if (ifaddr->is_temporary) {
264 			static bool once;
265 
266 			LOG_INF("Temporary IPv6 address %s added",
267 				inet_ntop(AF_INET6, &added_addr, addr_str,
268 					  sizeof(addr_str) - 1));
269 
270 			if (!once) {
271 				k_sem_give(&run_app);
272 				once = true;
273 			}
274 		}
275 	}
276 
277 	if (mgmt_event == NET_EVENT_IPV6_ADDR_DEPRECATED) {
278 		struct in6_addr deprecated_addr;
279 
280 		memcpy(&deprecated_addr, cb->info, sizeof(struct in6_addr));
281 
282 		LOG_INF("IPv6 address %s deprecated",
283 			inet_ntop(AF_INET6, &deprecated_addr, addr_str,
284 				  sizeof(addr_str) - 1));
285 
286 		(void)check_our_ipv6_sockets(conf.ipv6.tcp.sock,
287 					     &deprecated_addr);
288 		(void)check_our_ipv6_sockets(conf.ipv6.udp.sock,
289 					     &deprecated_addr);
290 
291 		if (need_restart) {
292 			eventfd_write(fds[0].fd, 1);
293 		}
294 
295 		return;
296 	}
297 }
298 
event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)299 static void event_handler(struct net_mgmt_event_callback *cb,
300 			  uint32_t mgmt_event, struct net_if *iface)
301 {
302 	if ((mgmt_event & EVENT_MASK) != mgmt_event) {
303 		return;
304 	}
305 
306 	if (mgmt_event == NET_EVENT_L4_CONNECTED) {
307 		LOG_INF("Network connected");
308 
309 		connected = true;
310 		conf.ipv4.udp.mtu = net_if_get_mtu(iface);
311 		conf.ipv6.udp.mtu = conf.ipv4.udp.mtu;
312 
313 		if (!IS_ENABLED(CONFIG_NET_IPV6_PE)) {
314 			k_sem_give(&run_app);
315 		}
316 
317 		return;
318 	}
319 
320 	if (mgmt_event == NET_EVENT_L4_DISCONNECTED) {
321 		LOG_INF("Network disconnected");
322 
323 		connected = false;
324 		k_sem_reset(&run_app);
325 
326 		return;
327 	}
328 }
329 
init_app(void)330 static void init_app(void)
331 {
332 	LOG_INF(APP_BANNER);
333 
334 #if defined(CONFIG_USERSPACE)
335 	struct k_mem_partition *parts[] = {
336 #if Z_LIBC_PARTITION_EXISTS
337 		&z_libc_partition,
338 #endif
339 		&app_partition
340 	};
341 
342 	int ret = k_mem_domain_init(&app_domain, ARRAY_SIZE(parts), parts);
343 
344 	__ASSERT(ret == 0, "k_mem_domain_init() failed %d", ret);
345 	ARG_UNUSED(ret);
346 #endif
347 
348 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
349 	int err = tls_credential_add(CA_CERTIFICATE_TAG,
350 				    TLS_CREDENTIAL_CA_CERTIFICATE,
351 				    ca_certificate,
352 				    sizeof(ca_certificate));
353 	if (err < 0) {
354 		LOG_ERR("Failed to register public certificate: %d", err);
355 	}
356 
357 #if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
358 	err = tls_credential_add(PSK_TAG,
359 				TLS_CREDENTIAL_PSK,
360 				psk,
361 				sizeof(psk));
362 	if (err < 0) {
363 		LOG_ERR("Failed to register PSK: %d", err);
364 	}
365 	err = tls_credential_add(PSK_TAG,
366 				TLS_CREDENTIAL_PSK_ID,
367 				psk_id,
368 				sizeof(psk_id) - 1);
369 	if (err < 0) {
370 		LOG_ERR("Failed to register PSK ID: %d", err);
371 	}
372 #endif /* defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) */
373 #endif /* defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) */
374 
375 
376 	if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) {
377 		net_mgmt_init_event_callback(&mgmt_cb,
378 					     event_handler, EVENT_MASK);
379 		net_mgmt_add_event_callback(&mgmt_cb);
380 
381 		conn_mgr_mon_resend_status();
382 	}
383 
384 	net_mgmt_init_event_callback(&ipv6_mgmt_cb,
385 				     ipv6_event_handler, IPV6_EVENT_MASK);
386 	net_mgmt_add_event_callback(&ipv6_mgmt_cb);
387 
388 	init_vlan();
389 	init_udp();
390 }
391 
start_client(void * p1,void * p2,void * p3)392 static void start_client(void *p1, void *p2, void *p3)
393 {
394 	ARG_UNUSED(p1);
395 	ARG_UNUSED(p2);
396 	ARG_UNUSED(p3);
397 
398 	int iterations = CONFIG_NET_SAMPLE_SEND_ITERATIONS;
399 	int i = 0;
400 	int ret;
401 
402 	while (iterations == 0 || i < iterations) {
403 		/* Wait for the connection. */
404 		k_sem_take(&run_app, K_FOREVER);
405 
406 		if (IS_ENABLED(CONFIG_NET_IPV6_PE)) {
407 			/* Make sure that we have a temporary address */
408 			k_sleep(K_SECONDS(1));
409 		}
410 
411 		do {
412 			if (need_restart) {
413 				/* Close all sockets and get a fresh restart */
414 				stop_udp_and_tcp();
415 				need_restart = false;
416 			}
417 
418 			ret = start_udp_and_tcp();
419 
420 			while (connected && (ret == 0)) {
421 				ret = run_udp_and_tcp();
422 
423 				if (iterations > 0) {
424 					i++;
425 					if (i >= iterations) {
426 						break;
427 					}
428 				}
429 
430 				if (need_restart) {
431 					break;
432 				}
433 			}
434 		} while (need_restart);
435 
436 		stop_udp_and_tcp();
437 	}
438 }
439 
main(void)440 int main(void)
441 {
442 	init_app();
443 
444 	if (!IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) {
445 		/* If the config library has not been configured to start the
446 		 * app only after we have a connection, then we can start
447 		 * it right away.
448 		 */
449 		connected = true;
450 		k_sem_give(&run_app);
451 	}
452 
453 	k_thread_priority_set(k_current_get(), THREAD_PRIORITY);
454 
455 #if defined(CONFIG_USERSPACE)
456 	k_thread_access_grant(k_current_get(), &run_app);
457 	k_mem_domain_add_thread(&app_domain, k_current_get());
458 
459 	k_thread_user_mode_enter(start_client, NULL, NULL, NULL);
460 #else
461 	start_client(NULL, NULL, NULL);
462 #endif
463 	return 0;
464 }
465