diff --git a/sys/shell/Makefile.dep b/sys/shell/Makefile.dep index 0254da82b22ae..afed19a84f6e5 100644 --- a/sys/shell/Makefile.dep +++ b/sys/shell/Makefile.dep @@ -284,6 +284,10 @@ endif ifneq (,$(filter shell_cmd_suit,$(USEMODULE))) USEMODULE += suit_transport_worker endif +ifneq (,$(filter shell_cmd_udptty,$(USEMODULE))) + USEMODULE += sock_async + USEMODULE += sock_udp +endif ifneq (,$(filter shell_cmd_vfs,$(USEMODULE))) USEMODULE += vfs USEMODULE += tiny_strerror diff --git a/sys/shell/cmds/udptty.c b/sys/shell/cmds/udptty.c new file mode 100644 index 0000000000000..c3b49fcd0c5b0 --- /dev/null +++ b/sys/shell/cmds/udptty.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2023 ML!PA Consulting GmbH + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for + * more details. + */ + +/** + * @ingroup sys_shell_commands + * @{ + * + * @file + * + * @author Benjamin Valentin + */ + +#include +#include +#include "shell.h" +#include "stdio_base.h" +#include "net/sock/async.h" +#include "net/sock/udp.h" +#include "net/utils.h" +#include "ztimer.h" + +extern int readline(char *buf, size_t size); + +static void _sock_cb(sock_udp_t *sock, sock_async_flags_t flags, void *arg) +{ + (void)arg; + if ((flags & SOCK_ASYNC_MSG_RECV) == 0) { + return; + } + + void *data, *ctx = NULL; + + int res; + while ((res = sock_udp_recv_buf(sock, &data, &ctx, 0, NULL)) > 0) { + stdio_write(data, res); + } +} + +static int _udptty_cmd(int argc, char **argv) +{ + if (argc < 2) { + goto usage; + } + + netif_t *netif = NULL; + sock_udp_ep_t remote = SOCK_IPV6_EP_ANY; + sock_udp_t sock; + int res; + + const sock_udp_ep_t local = { + .family = AF_INET6, + .netif = SOCK_ADDR_ANY_NETIF, + }; + + if (netutils_get_ipv6((ipv6_addr_t *)&remote.addr, &netif, argv[1])) { + goto usage; + } + + if (netif) { + remote.netif = netif_get_id(netif); + } + remote.port = atoi(argv[2]); + + res = sock_udp_create(&sock, &local, &remote, 0); + if (res) { + printf("can't create socket: %d\n", res); + return res; + } + + sock_udp_set_cb(&sock, _sock_cb, NULL); + + do { + char buf[64]; + res = readline(buf, sizeof(buf)); + + if (res > 0) { + buf[res] = '\n'; + sock_udp_send(&sock, buf, res + 1, NULL); + } + +#ifdef CPU_NATIVE + /* readline() on native blocks all other threads - see #19002 */ + ztimer_sleep(ZTIMER_MSEC, 100); +#endif + } while (res != EOF); + + /* send disconnect */ + char eof = EOF; + sock_udp_send(&sock, &eof, sizeof(eof), NULL); + sock_udp_close(&sock); + + return 0; + +usage: + printf("usage: %s \n", argv[0]); + return -1; +} + +SHELL_COMMAND(udptty, "UDP remote shell", _udptty_cmd); +/** @} */