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