Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ttynvt for openSUSE:Factory checked in at 2025-06-30 13:04:57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ttynvt (Old) and /work/SRC/openSUSE:Factory/.ttynvt.new.7067 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ttynvt" Mon Jun 30 13:04:57 2025 rev:3 rq:1288925 version:0.17 Changes: -------- --- /work/SRC/openSUSE:Factory/ttynvt/ttynvt.changes 2023-03-21 17:44:55.638805352 +0100 +++ /work/SRC/openSUSE:Factory/.ttynvt.new.7067/ttynvt.changes 2025-06-30 13:06:25.293744534 +0200 @@ -1,0 +2,20 @@ +Thu Jun 26 13:49:48 UTC 2025 - Martin Hauke <mar...@gmx.de> + +- Update to version 0.17 + * Handling of initial protocol error changed + * Handling of pthread_mutex_init failure fixed + * nvttest: Add missing -lpthread + * ttynvt: On TCSET* skip rfc2217 baud rate change if zero + * nvtsrv: Fix inconsistent help + * nvttest: Improve help + * nvttest: Enable specifying device + * nvttest: Rework thread handling + * nvttest: Return error if anything fails + * nvtsrv: Change some log messages to debug + * test: Initial testing framework + * ttynvt: Move optional delay during close + * Support odd parity. + * support TCP/IPv6 address and UNIX domain socket path as + rfc2217 server + +------------------------------------------------------------------- Old: ---- ttynvt-v0.16.tar.bz2 New: ---- ttynvt-v0.17.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ttynvt.spec ++++++ --- /var/tmp/diff_new_pack.Q5p3vy/_old 2025-06-30 13:06:26.517795250 +0200 +++ /var/tmp/diff_new_pack.Q5p3vy/_new 2025-06-30 13:06:26.521795416 +0200 @@ -1,8 +1,8 @@ # # spec file for package ttynvt # -# Copyright (c) 2023 SUSE LLC -# Copyright (c) 2021-2023, Martin Hauke <mar...@gmx.de> +# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2021-2024, Martin Hauke <mar...@gmx.de> # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,26 +18,29 @@ Name: ttynvt -Version: 0.16 +Version: 0.17 Release: 0 Summary: Virtual Network Terminal supporting the Com Port Control Option (RFC2217) License: GPL-3.0-or-later +# FIXME: use correct group or remove it, see "https://en.opensuse.org/openSUSE:Package_group_guidelines" Group: System/Utilities URL: https://gitlab.com/lars-thrane-as/ttynvt #Git-Clone: https://gitlab.com/lars-thrane-as/ttynvt.git Source: https://gitlab.com/lars-thrane-as/ttynvt/-/archive/v%{version}/%{name}-v%{version}.tar.bz2 BuildRequires: autoconf BuildRequires: automake +BuildRequires: gcc-c++ BuildRequires: libtool BuildRequires: pkgconfig BuildRequires: pkgconfig(fuse) +BuildRequires: pkgconfig(gtest) %description ttynvt makes a virtual serial device (tty) and connects the device to a Network Virtual Terminal (NVT). %prep -%setup -q -n %{name}-v%{version} +%autosetup -n %{name}-v%{version} %build autoreconf -fiv @@ -47,6 +50,10 @@ %install %make_install +%check +# disabled since tests need root permission +#%%make_build test + %files %license COPYING %doc AUTHORS README ++++++ ttynvt-v0.16.tar.bz2 -> ttynvt-v0.17.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/Makefile.am new/ttynvt-v0.17/Makefile.am --- old/ttynvt-v0.16/Makefile.am 2023-03-13 09:40:44.000000000 +0100 +++ new/ttynvt-v0.17/Makefile.am 2025-06-25 17:32:41.000000000 +0200 @@ -9,3 +9,11 @@ SUBDIRS += nvtsrv SUBDIRS += nvttest endif +if BUILD_TEST +SUBDIRS += test +endif + +.PHONY: $(SUBDIRS) test +$(SUBDIRS) test: + $(MAKE) -C $@ +test: $(SUBDIRS) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/configure.ac new/ttynvt-v0.17/configure.ac --- old/ttynvt-v0.16/configure.ac 2023-03-13 09:40:44.000000000 +0100 +++ new/ttynvt-v0.17/configure.ac 2025-06-25 17:32:41.000000000 +0200 @@ -1,4 +1,4 @@ -AC_INIT([ttynvt],[0.16],[f...@thrane.eu]) +AC_INIT([ttynvt],[0.17],[f...@thrane.eu]) AM_INIT_AUTOMAKE([foreign dist-xz]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) @@ -6,10 +6,10 @@ AC_USE_SYSTEM_EXTENSIONS AC_PROG_CC +AC_PROG_CXX AC_PROG_INSTALL -define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl define([AC_LIBTOOL_LANG_GCJ_CONFIG], [:])dnl @@ -31,6 +31,8 @@ enable_testtools=no) AM_CONDITIONAL([BUILD_TESTTOOLS], [test "x$enable_testtools" = "xyes"]) +AM_CONDITIONAL(BUILD_TEST, false) + CFLAGS_WARN="$CFLAGS_WARN -Wall -Wextra -Werror -Wno-unused-parameter" CFLAGS_WARN="$CFLAGS_WARN -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes" CFLAGS_WARN="$CFLAGS_WARN -Waggregate-return -Wpointer-arith -Wshadow -Wwrite-strings" @@ -44,6 +46,7 @@ src/Makefile nvtsrv/Makefile nvttest/Makefile +test/Makefile ]) AC_OUTPUT diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/lib/nvt_socket.c new/ttynvt-v0.17/lib/nvt_socket.c --- old/ttynvt-v0.16/lib/nvt_socket.c 2023-03-13 09:40:44.000000000 +0100 +++ new/ttynvt-v0.17/lib/nvt_socket.c 2025-06-25 17:32:41.000000000 +0200 @@ -7,6 +7,7 @@ #include <string.h> #include <unistd.h> #include <sys/socket.h> +#include <sys/un.h> #include "nvt_log.h" #include "nvt_socket.h" @@ -18,42 +19,109 @@ union { struct sockaddr gen; struct sockaddr_in ipv4; + struct sockaddr_in6 ipv6; + struct sockaddr_un un; }; } sa_t; -static int _sa_host_lookup(sa_t * sa, const char *host) +static int _sa_host_lookup(sa_t *sa, const char *host, const char *port) { - struct hostent *server; + struct addrinfo hint, *adrinf = NULL, *p; + int ret = -1; - server = gethostbyname(host); - if (server == NULL) + memset(&hint, 0, sizeof(struct addrinfo)); + + if (getaddrinfo(host, port, &hint, &adrinf) != 0) { nvt_log(LOG_ERR, "Cannot resolve host name: %m\n"); return -1; } - sa->slen = sizeof(sa->ipv4); - - sa->ipv4.sin_family = AF_INET; - memcpy(&sa->ipv4.sin_addr.s_addr, server->h_addr, server->h_length); - - return 0; + // Priority is given to the use of IPv4 + // This code must be modified if the preffered protocol is changed or varied. + for (p = adrinf; p; p = p->ai_next) + { + if (p->ai_family == AF_INET) + { + sa->slen = sizeof(sa->ipv4); + memcpy(&sa->ipv4, p->ai_addr, sizeof(struct sockaddr_in)); + ret = 0; + goto exit_host_lookup; + } + } + for (p = adrinf; p; p = p->ai_next) + { + if (p->ai_family == AF_INET6) + { + sa->slen = sizeof(sa->ipv6); + memcpy(&sa->ipv6, p->ai_addr, sizeof(struct sockaddr_in6)); + ret = 0; + goto exit_host_lookup; + } + } + exit_host_lookup: + freeaddrinfo(adrinf); + return ret; } -static int _sa_addr_parse(sa_t * sa, const char *addr) +static int _sa_addr_parse(sa_t *sa, const char *addr) { - char host[64], port[64]; + ssize_t host_len; + char host[64]; + const char *port; memset(sa, 0, sizeof(sa_t)); - sscanf(addr, "%63[^:]:%63s", host, port); + if (strncmp(addr, "unix:", 5) == 0) + { // case of unix domain sockets ... + addr += 5; // skip "unix:" prefix + if (strlen(addr) > sizeof(sa->un.sun_path) - 1) + { + nvt_log(LOG_ERR, "UNIX domain socket path is too long.\n"); + return -1; + } + sa->slen = sizeof(sa->un); + sa->un.sun_family = AF_UNIX; + strcpy(sa->un.sun_path, addr); + sa->type = SOCK_STREAM; + return 0; + } + + if (!(port = strrchr(addr, ':'))) + { + nvt_log(LOG_ERR, "bad server address format.\n"); + return -1; + } + host_len = (port++) - addr; + // *port indicates the last ':', its next is 1st char of the port number + if (host_len >= 2 && addr[0] == '[' && addr[host_len - 1] == ']') + { + // IPv6 addresses are enclosed in pair of square brackets. + addr += 1; + host_len -= 2; + } + else + { + if (strchr(addr, ':') != port - 1) + { + nvt_log(LOG_ERR, + "addresses containing colons must be enclosed in square brackets.\n"); + return -1; + } + } + if ((ssize_t) sizeof(host) <= host_len) + { + nvt_log(LOG_ERR, "host name is too long.\n"); + return -1; + } + strncpy(host, addr, host_len); + host[host_len] = '\0'; // strncpy doesn't add null char - if (_sa_host_lookup(sa, host) != 0) + if (_sa_host_lookup(sa, host, port) != 0) return -1; sa->type = SOCK_STREAM; - sa->ipv4.sin_port = htons(atoi(port)); return 0; } @@ -103,7 +171,7 @@ return -1; } - if (sa.gen.sa_family == AF_INET) + if (sa.gen.sa_family == AF_INET || sa.gen.sa_family == AF_INET6) { /* Avoid TIME_WAIT state on socket close */ opt = 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/nvtsrv/nvtsrv.c new/ttynvt-v0.17/nvtsrv/nvtsrv.c --- old/ttynvt-v0.16/nvtsrv/nvtsrv.c 2023-03-13 09:40:44.000000000 +0100 +++ new/ttynvt-v0.17/nvtsrv/nvtsrv.c 2025-06-25 17:32:41.000000000 +0200 @@ -14,9 +14,15 @@ #include "telnet.h" -#define HELP \ - "Usage: nvtsrv -deq\n" - +/**INDENT-OFF**/ +static const char help_text[] = + "Usage: nvtsrv OPTIONS... HOST:PORT\n" + "OPTIONS:\n" + " -d : Enable debug\n" + " -e : Echo received data\n" + " -q : Quiet\n" + ; +/**INDENT-ON**/ struct { unsigned char mline; @@ -30,10 +36,10 @@ #define fd_cli pfds[2].fd -static void _nvtsrv_usage(void) +static void _usage(int rc) { - printf("Usage:\n" " nvtsrv host:port\n"); - exit(0); + printf(help_text); + exit(rc); } static void _tn_cli_close(void) @@ -68,7 +74,7 @@ static void _tn_ss(void *cctx, int signal, int value) { - nvt_log(LOG_INFO, "RFC2217 signal %d: %02x", signal, value); + DBG("RFC2217 signal %d: %02x", signal, value); } static void _nvtsrv_init(void) @@ -80,7 +86,7 @@ dd.tnct = telnet_ctx_init(NULL, _tn_tx, _tn_ss); } -static void _nvtsrv_cmd(tn_ctx_t * tcc, const char *line, int len) +static void _nvtsrv_cmd(tn_ctx_t *tcc, const char *line, int len) { int val; @@ -127,8 +133,8 @@ switch (opt) { default: /* '?' */ - fprintf(stderr, HELP); - exit(EXIT_FAILURE); + _usage(0); + break; case 'd': debug += 1; break; @@ -144,7 +150,7 @@ argc -= optind; argv += optind; if (argc <= 0) - _nvtsrv_usage(); + _usage(1); nvt_log_level(quiet, debug); nvt_log_dest(NVT_LOG_STDOUT); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/nvtsrv/telnet_basic.c new/ttynvt-v0.17/nvtsrv/telnet_basic.c --- old/ttynvt-v0.16/nvtsrv/telnet_basic.c 2023-03-13 09:40:44.000000000 +0100 +++ new/ttynvt-v0.17/nvtsrv/telnet_basic.c 2025-06-25 17:32:41.000000000 +0200 @@ -36,7 +36,7 @@ }; -static void _telnet_handle_req(tn_ctx_t * tcc, int cmd, int opt) +static void _telnet_handle_req(tn_ctx_t *tcc, int cmd, int opt) { char buf[3]; @@ -63,7 +63,7 @@ telnet_rfc2217_init(tcc, TNI_ON); } -void telnet_reply_opt(tn_ctx_t * tcc, int opt, int prm, +void telnet_reply_opt(tn_ctx_t *tcc, int opt, int prm, const void *val, int len) { unsigned char buf[128], *pu = buf; @@ -94,7 +94,7 @@ tcc->cli_tx(tcc->cctx, buf, len); } -static void _telnet_handle_opt(tn_ctx_t * tcc, int opt, +static void _telnet_handle_opt(tn_ctx_t *tcc, int opt, unsigned char *pu, int nd) { DBG2_BUF("opti", pu, nd); @@ -111,7 +111,7 @@ } } -int telnet_rx(tn_ctx_t * tcc, char *buf, int *plen) +int telnet_rx(tn_ctx_t *tcc, char *buf, int *plen) { char *s, *p; unsigned char *pu; @@ -230,7 +230,7 @@ return 0; } -int telnet_tx(tn_ctx_t * tcc, const char *buf, int len) +int telnet_tx(tn_ctx_t *tcc, const char *buf, int len) { const char *s, *p; int rem, nd; @@ -260,7 +260,7 @@ return 0; } -tn_ctx_t *telnet_ctx_init(void *cctx, cli_tx_f * ftx, cli_ss_f * fss) +tn_ctx_t *telnet_ctx_init(void *cctx, cli_tx_f *ftx, cli_ss_f *fss) { tn_ctx_t *tcc; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/nvtsrv/telnet_server_rfc2217.c new/ttynvt-v0.17/nvtsrv/telnet_server_rfc2217.c --- old/ttynvt-v0.16/nvtsrv/telnet_server_rfc2217.c 2023-03-13 09:40:44.000000000 +0100 +++ new/ttynvt-v0.17/nvtsrv/telnet_server_rfc2217.c 2025-06-25 17:32:41.000000000 +0200 @@ -10,7 +10,7 @@ #include "telnet.h" #include "telnet_param.h" -void telnet_rfc2217_init(tn_ctx_t * tcc, int when) +void telnet_rfc2217_init(tn_ctx_t *tcc, int when) { switch (when) { @@ -39,7 +39,7 @@ } -void telnet_rfc2217_handle_opt(tn_ctx_t * tcc, int opt, +void telnet_rfc2217_handle_opt(tn_ctx_t *tcc, int opt, unsigned char *pu, int nd) { unsigned int sub, vali, valo, val4; @@ -138,8 +138,7 @@ case 9: /* Set DTR Signal State OFF */ valo = vali; tcc->dtr_state = (valo == 8) ? 1 : 0; - nvt_log(LOG_INFO, "RFC2217: Set DTR %s", - tcc->dtr_state ? "on" : "off"); + DBG("RFC2217: Set DTR %s", tcc->dtr_state ? "on" : "off"); goto do_ctl_reply; case 10: /* Request RTS Signal State */ @@ -149,8 +148,7 @@ case 12: /* Set RTS Signal State OFF */ valo = vali; tcc->rts_state = (valo == 11) ? 1 : 0; - nvt_log(LOG_INFO, "RFC2217: Set RTS %s", - tcc->rts_state ? "on" : "off"); + DBG("RFC2217: Set RTS %s", tcc->rts_state ? "on" : "off"); goto do_ctl_reply; case 13: /* Request Com Port Flow Control Setting (inbound) */ @@ -220,7 +218,7 @@ } } -void telnet_rfc2217_change_linestate(tn_ctx_t * tcc, int mask) +void telnet_rfc2217_change_linestate(tn_ctx_t *tcc, int mask) { unsigned char buf[1]; @@ -238,7 +236,7 @@ tcc->linestate = mask; } -void telnet_rfc2217_change_modemstate(tn_ctx_t * tcc, int mask) +void telnet_rfc2217_change_modemstate(tn_ctx_t *tcc, int mask) { unsigned char buf[1]; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/nvttest/Makefile.am new/ttynvt-v0.17/nvttest/Makefile.am --- old/ttynvt-v0.16/nvttest/Makefile.am 2023-03-13 09:40:44.000000000 +0100 +++ new/ttynvt-v0.17/nvttest/Makefile.am 2025-06-25 17:32:41.000000000 +0200 @@ -6,4 +6,4 @@ nvttest_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) $(CFLAGS_WARN) -nvttest_LDADD = $(top_builddir)/lib/libnvt.la +nvttest_LDADD = $(top_builddir)/lib/libnvt.la -lpthread diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/nvttest/nvttest.c new/ttynvt-v0.17/nvttest/nvttest.c --- old/ttynvt-v0.16/nvttest/nvttest.c 2023-03-13 09:40:44.000000000 +0100 +++ new/ttynvt-v0.17/nvttest/nvttest.c 2025-06-25 17:32:41.000000000 +0200 @@ -7,6 +7,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <sys/stat.h> #include <fcntl.h> @@ -16,10 +17,20 @@ #include "lib/nvt_log.h" -#define HELP \ - "Usage: nvttest -dqr [-n loops] [-t threads]\n" +/**INDENT-OFF**/ +static const char help_text[] = + "Usage: nvttest OPTIONS...\n" + "OPTIONS:\n" + " -D name : Specify device name (/dev/name, default /dev/ttyNVT0)\n" + " -d : Enable debug\n" + " -n loops : Test loops per thread\n" + " -q : Quiet\n" + " -r : Insert random delay in loops\n" + " -t threads : N. threads\n" + ; +/**INDENT-ON**/ -static const char *dev = "/dev/ttyNVT0"; +static char dev[64] = "/dev/ttyNVT0"; typedef struct { int nthread; @@ -28,22 +39,37 @@ bool opt_rand_delay; } topts_t; +typedef struct { + pthread_t thr; + topts_t opts; + int errors; +} thr_t; + + +static void _usage(int rc) +{ + printf(help_text); + exit(rc); +} + static void *_worker(void *arg) { - topts_t *topts = arg; + thr_t *thr = arg; int iloop; int fd, err, nw; struct termios ios; - for (iloop = 0; iloop < topts->nloop; iloop++) + for (iloop = 0; iloop < thr->opts.nloop; iloop++) { nvt_log(LOG_INFO, "Thread %d/%d run %d/%d\n", - topts->ithread, topts->nthread, iloop + 1, topts->nloop); + thr->opts.ithread, thr->opts.nthread, + iloop + 1, thr->opts.nloop); { fd = open(dev, O_RDWR); if (fd < 0) { nvt_log(LOG_ERR, "Open '%s' failed: %m\n", dev); + thr->errors++; break; } @@ -52,12 +78,14 @@ if (err != 0) { nvt_log(LOG_ERR, "ioctl(TCGETS) failed: %m\n"); + thr->errors++; break; } err = ioctl(fd, TCSETS, &ios); if (err != 0) { nvt_log(LOG_ERR, "ioctl(TCSETS) failed: %m\n"); + thr->errors++; break; } close(fd); @@ -74,6 +102,7 @@ if (fd < 0) { nvt_log(LOG_ERR, "Open '%s' failed: %m\n", dev); + thr->errors++; break; } @@ -84,18 +113,20 @@ if (nw < 0) { nvt_log(LOG_ERR, "write failed: %m\n"); + thr->errors++; break; } if (nw < len) { nvt_log(LOG_ERR, "write short: %u/%u\n", nw, len); + thr->errors++; break; } } close(fd); } - if (topts->opt_rand_delay) + if (thr->opts.opt_rand_delay) usleep(rand() & 0xfff); } @@ -104,24 +135,28 @@ int main(int argc, char **argv) { - int err; + int err, errors; int opt; int ithr, nthr; - topts_t topts = { }, *popts; - pthread_t *ptids; + thr_t *threads, *thr; + topts_t topts = { }; int debug, quiet; + struct stat st; debug = quiet = 0; nthr = 1; topts.nloop = 1; - while ((opt = getopt(argc, argv, "dn:qrt:")) != -1) + while ((opt = getopt(argc, argv, "D:dn:qrt:")) != -1) { switch (opt) { default: /* '?' */ - fprintf(stderr, HELP); - exit(EXIT_FAILURE); + _usage(1); + break; + case 'D': + snprintf(dev, sizeof(dev), "/dev/%s", optarg); + break; case 'd': debug += 1; break; @@ -140,22 +175,28 @@ } } + if (stat(dev, &st) || !S_ISCHR(st.st_mode)) + { + fprintf(stderr, "Invalid device file: '%s'\n", dev); + exit(EXIT_FAILURE); + } + nvt_log_level(quiet, debug); nvt_log_dest(NVT_LOG_STDOUT); topts.nthread = nthr; - ptids = malloc(nthr * sizeof(pthread_t)); + threads = calloc(nthr, sizeof(thr_t)); for (ithr = 0; ithr < nthr; ithr++) { nvt_log(LOG_INFO, "Create worker thread %d/%d\n", ithr + 1, nthr); - popts = malloc(sizeof(topts_t)); - *popts = topts; - popts->ithread = ithr + 1; + thr = &threads[ithr]; + thr->opts = topts; + thr->opts.ithread = ithr + 1; - err = pthread_create(&ptids[ithr], NULL, _worker, popts); + err = pthread_create(&thr->thr, NULL, _worker, thr); if (err) { nvt_log(LOG_ERR, "Failed to create thread %d/%d\n", ithr, nthr); @@ -163,13 +204,17 @@ } } + errors = 0; for (ithr = 0; ithr < nthr; ithr++) { - if (ptids[ithr] == 0) + thr = &threads[ithr]; + if (thr->thr == 0) break; - pthread_join(ptids[ithr], NULL); - nvt_log(LOG_INFO, "Joined worker thread %d/%d\n", ithr + 1, nthr); + pthread_join(thr->thr, NULL); + errors += thr->errors; + nvt_log(LOG_INFO, "Joined worker thread %d/%d (err=%d)\n", + ithr + 1, nthr, thr->errors); } - return 0; + return errors ? 1 : 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/src/telnet_basic.c new/ttynvt-v0.17/src/telnet_basic.c --- old/ttynvt-v0.16/src/telnet_basic.c 2023-03-13 09:40:44.000000000 +0100 +++ new/ttynvt-v0.17/src/telnet_basic.c 2025-06-25 17:32:41.000000000 +0200 @@ -7,6 +7,7 @@ #include <stdlib.h> #include <string.h> #include <time.h> +#include <errno.h> #include "telnet.h" #include "telnet_param.h" @@ -38,7 +39,7 @@ }; -static void _telnet_handle_req(tn_ctx_t * tcc, int cmd, int opt) +static void _telnet_handle_req(tn_ctx_t *tcc, int cmd, int opt) { char buf[3]; @@ -67,7 +68,7 @@ tcc->srv_tx(tcc->cctx, buf, 3); } -static void _telnet_handle_resp(tn_ctx_t * tcc, int cmd, int opt) +static void _telnet_handle_resp(tn_ctx_t *tcc, int cmd, int opt) { if (opt == TNO_CPCO) { @@ -76,7 +77,7 @@ } } -void telnet_set_opt(tn_ctx_t * tcc, int opt, int prm, const void *val, int len) +void telnet_set_opt(tn_ctx_t *tcc, int opt, int prm, const void *val, int len) { unsigned char buf[128], *pu = buf; const unsigned char *pv; @@ -106,7 +107,7 @@ tcc->srv_tx(tcc->cctx, buf, len); } -static void _telnet_handle_opt(tn_ctx_t * tcc, int opt, +static void _telnet_handle_opt(tn_ctx_t *tcc, int opt, unsigned char *pu, int nd) { switch (opt) @@ -120,7 +121,7 @@ } } -int telnet_rx(tn_ctx_t * tcc, char *buf, int *plen) +int telnet_rx(tn_ctx_t *tcc, char *buf, int *plen) { char *s, *p; unsigned char *pu; @@ -233,7 +234,7 @@ return 0; } -int telnet_tx(tn_ctx_t * tcc, const char *buf, int len) +int telnet_tx(tn_ctx_t *tcc, const char *buf, int len) { const char *s, *p; int rem, nd; @@ -263,7 +264,7 @@ return 0; } -int telnet_open(tn_ctx_t * tcc, int mode) +int telnet_open(tn_ctx_t *tcc, int mode) { time_t t = time(NULL);; char buf[3]; @@ -284,17 +285,17 @@ while (1) { res = tcc->srv_rx(tcc->cctx, 1000); - if (res <= 0) - return -1; + if (res < 0) + return errno; else if (tcc->mode_rfc2217) return 0; - else if (t - time(NULL) > 2) - return -1; + else if (time(NULL) - t > 10) + return EPROTO; } } -tn_ctx_t *telnet_ctx_init(void *cctx, srv_tx_f * ftx, - srv_rx_f * frx, srv_ms_f * fms) +tn_ctx_t *telnet_ctx_init(void *cctx, srv_tx_f *ftx, + srv_rx_f *frx, srv_ms_f *fms) { tn_ctx_t *tcc; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/src/telnet_client_rfc2217.c new/ttynvt-v0.17/src/telnet_client_rfc2217.c --- old/ttynvt-v0.16/src/telnet_client_rfc2217.c 2023-03-13 09:40:44.000000000 +0100 +++ new/ttynvt-v0.17/src/telnet_client_rfc2217.c 2025-06-25 17:32:41.000000000 +0200 @@ -7,7 +7,7 @@ #include "telnet.h" #include "telnet_param.h" -void telnet_rfc2217_handle_opt(tn_ctx_t * tcc, int opt, +void telnet_rfc2217_handle_opt(tn_ctx_t *tcc, int opt, unsigned char *pu, int nd) { unsigned int sub; @@ -32,7 +32,7 @@ } } -void telnet_rfc2217_cfg(tn_ctx_t * tcc, int cmd, const void *val, int nd) +void telnet_rfc2217_cfg(tn_ctx_t *tcc, int cmd, const void *val, int nd) { if (!tcc->mode_rfc2217) return; @@ -40,7 +40,7 @@ telnet_set_opt(tcc, TNO_CPCO, cmd, val, nd); } -void telnet_rfc2217_ctl(tn_ctx_t * tcc, unsigned int val) +void telnet_rfc2217_ctl(tn_ctx_t *tcc, unsigned int val) { unsigned char byte = val; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/src/ttynvt.c new/ttynvt-v0.17/src/ttynvt.c --- old/ttynvt-v0.16/src/ttynvt.c 2023-03-13 09:40:44.000000000 +0100 +++ new/ttynvt-v0.17/src/ttynvt.c 2025-06-25 17:32:41.000000000 +0200 @@ -150,7 +150,7 @@ close(fd); } -static void _notify(ttynvt_t * tty) +static void _notify(ttynvt_t *tty) { pthread_mutex_lock(&tty->poll_lock); if (tty->ph) @@ -162,7 +162,7 @@ pthread_mutex_unlock(&tty->poll_lock); } -static void _update_notify(ttynvt_t * tty, struct fuse_pollhandle *ph) +static void _update_notify(ttynvt_t *tty, struct fuse_pollhandle *ph) { pthread_mutex_lock(&tty->poll_lock); struct fuse_pollhandle *tmp_ph = tty->ph; @@ -173,7 +173,7 @@ fuse_pollhandle_destroy(tmp_ph); } -static int _net_read_check_exit(ttynvt_t * tty) +static int _net_read_check_exit(ttynvt_t *tty) { if ((tty->tio.c_cflag & CLOCAL) == 0 && (tty->smcr_last & TIOCM_CD) != 0 && (tty->smcr & TIOCM_CD) == 0) @@ -397,7 +397,7 @@ return tty; } -static void _ttynvt_ctx_destroy(ttynvt_t * tty) +static void _ttynvt_ctx_destroy(ttynvt_t *tty) { if (tty) free(tty->tn); @@ -470,14 +470,14 @@ res = telnet_open(tty->tn, ttynvt_param.raw ? TN_MODE_RAW : TN_MODE_TELNET); - if (res < 0) + if (res != 0) { - errno = EPROTO; + errno = res; goto open_err; } - if ((res = pthread_mutex_init(&tty->tty_lock, NULL) < 0) || - (res = pthread_mutex_init(&tty->poll_lock, NULL) < 0) || + if ((res = pthread_mutex_init(&tty->tty_lock, NULL)) || + (res = pthread_mutex_init(&tty->poll_lock, NULL)) || (res = pthread_create(&tty->ptid_poll, NULL, &_read_net, tty))) { errno = res; @@ -691,10 +691,12 @@ { unsigned int par; - if ((tio->c_cflag & PARENB) && (tio->c_iflag & IGNPAR)) + if (!(tio->c_cflag & PARENB)) + { par = 1; + } #ifdef CMSPAR - else if ((tio->c_cflag & PARENB) && (tio->c_iflag & CMSPAR)) + else if (tio->c_iflag & CMSPAR) { if (tio->c_cflag & PARODD) par = 4; @@ -702,10 +704,14 @@ par = 5; } #endif - else if (tio->c_cflag & PARENB) - par = 3; + else if (tio->c_cflag & PARODD) + { + par = 2; + } else - par = 1; + { + par = 3; + } return par; } @@ -818,8 +824,12 @@ goto do_tcset; do_tcset: /* BEWARE of termios/termios2 buf structure difference! */ - byte4 = htonl(baud); - telnet_rfc2217_cfg(tty->tn, TNS_SET_BAUDRATE, &byte4, 4); + + if (baud != 0) + { + byte4 = htonl(baud); + telnet_rfc2217_cfg(tty->tn, TNS_SET_BAUDRATE, &byte4, 4); + } byte = _tio_csize(tio); telnet_rfc2217_cfg(tty->tn, TNS_SET_DATASIZE, &byte, 1); @@ -1108,13 +1118,13 @@ pthread_mutex_destroy(&tty->tty_lock); pthread_mutex_destroy(&tty->poll_lock); - if (ttynvt_param.close_delay_us) - _ttynvt_sleep_us(ttynvt_param.close_delay_us); - _fd_close(tty->fds[FD_NET].fd); _fd_close(tty->fds[FD_MASTER].fd); _fd_close(tty->fds[FD_SLAVE].fd); + if (ttynvt_param.close_delay_us) + _ttynvt_sleep_us(ttynvt_param.close_delay_us); + if (tty->ph) fuse_pollhandle_destroy(tty->ph); @@ -1172,7 +1182,9 @@ "\t-q\t\tBe quiet (suppress informational messages)\n" "\t-r\t\tDisable telnet processing\n" "\t-s delay \t\tDelay at close in ms (use u suffix for us)\n" - "\t-S server, --server=host:port\n"); + "\t-S server, --server=host:port\n" + "\t\t\t[ipv6addr]:port (connect via IPv6)\n" + "\t\t\tunix:/path/to.socket (connect via UNIX domain socket)\n"); } static int diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/test/Makefile.am new/ttynvt-v0.17/test/Makefile.am --- old/ttynvt-v0.16/test/Makefile.am 1970-01-01 01:00:00.000000000 +0100 +++ new/ttynvt-v0.17/test/Makefile.am 2025-06-25 17:32:41.000000000 +0200 @@ -0,0 +1,48 @@ +# Unit test makefile +# +.NOTPARALLEL: + +noinst_PROGRAMS = $(GTESTS) + + GTEST_LIBS = -lgtest -lstdc++ + + GTESTS = test_misc test_nvttest + + AM_CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter + AM_CFLAGS += $(CFLAGS_ASAN) + + AM_CXXFLAGS = $(AM_CFLAGS) + + AM_CPPFLAGS = -I $(top_builddir) + AM_CPPFLAGS += -D TOP_SRC_DIR='"$(top_srcdir)"' -D TOP_BLD_DIR='"$(top_builddir)"' + AM_CPPFLAGS += -D BUILD_TEST=1 + + LIBS += $(GTEST_LIBS) + + TEST_COMMON = test.cpp test.h + +test_misc_SOURCES = $(TEST_COMMON) test_misc.cpp +test_misc_LDADD = $(LIBS) + +test_nvttest_SOURCES = $(TEST_COMMON) test_nvttest.cpp +test_nvttest_LDADD = $(LIBS) + + TESTS_RUN = $(addprefix run-, $(GTESTS)) + + VG_PROG = valgrind --leak-check=full + +all-local: run + +.PHONY: run $(TESTS_RUN) +run: $(TESTS_RUN) +$(TESTS_RUN): run-%: % +# $(TEST_ENV) ./.libs/$* $(RUN_OPTS) + $(TEST_ENV) ./$* $(RUN_OPTS) + + TESTS_RUN_VG = $(addprefix run-vg-, $(GTESTS)) + +.PHONY: run-vg $(TESTS_RUN_VG) +run-vg: $(TESTS_RUN_VG) +$(TESTS_RUN_VG): run-vg-%: % +# $(TEST_ENV) $(VG_PROG) ./.libs/$* $(RUN_OPTS) + $(TEST_ENV) $(VG_PROG) ./$* $(RUN_OPTS) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/test/test.cpp new/ttynvt-v0.17/test/test.cpp --- old/ttynvt-v0.16/test/test.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/ttynvt-v0.17/test/test.cpp 2025-06-25 17:32:41.000000000 +0200 @@ -0,0 +1,70 @@ +/* + * General test stuff + * + * - The main() function + * - Some printing functions + */ +#include "test.h" + +int debug = 0; + +static bool ttyout = false; + +int main(int argc, char **argv) +{ + const char *s; + + ttyout = isatty(STDOUT_FILENO); + + ::testing::InitGoogleTest(&argc, argv); + + for (argc--, argv++; argc > 0; argc--, argv++) + { + s = argv[0]; + if (*s++ != '-') + break; + again: + switch (*s++) + { + case 'd': + debug++; + goto again; + } + } + + return RUN_ALL_TESTS(); +} + +#include <stdarg.h> + +void _pr_text(const char *col, const char *fmt, va_list args) +{ + char fmtx[1024]; + + if (ttyout) + snprintf(fmtx, sizeof(fmtx), "%s[ ] - %s%s\n", + col, fmt, COL_RST); + else + snprintf(fmtx, sizeof(fmtx), "[ ] - %s\n", fmt); + fmt = fmtx; + + vprintf(fmt, args); +} + +void pr_text(const char *col, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + _pr_text(col, fmt, args); + va_end(args); +} + +void pr_info(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + _pr_text(COL_YEL, fmt, args); + va_end(args); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/test/test.h new/ttynvt-v0.17/test/test.h --- old/ttynvt-v0.16/test/test.h 1970-01-01 01:00:00.000000000 +0100 +++ new/ttynvt-v0.17/test/test.h 2025-06-25 17:32:41.000000000 +0200 @@ -0,0 +1,25 @@ +#ifndef TEST_H +#define TEST_H 1 + +#include <gtest/gtest.h> + +#include "config.h" + +#define D(...) do{ if (debug) printf(__VA_ARGS__); }while(0) +#define D2(...) do{ if (debug > 1) printf(__VA_ARGS__); }while(0) + +extern int debug; + +#define COL_RST "\x1B[0m" +#define COL_RED "\x1B[31m" +#define COL_GRN "\x1B[32m" +#define COL_YEL "\x1B[33m" +#define COL_BLU "\x1B[34m" +#define COL_MAG "\x1B[35m" +#define COL_CYN "\x1B[36m" +#define COL_WHT "\x1B[37m" + +void pr_text(const char *col, const char *fmt, ...); +void pr_info(const char *fmt, ...); + +#endif /* TEST_H */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/test/test_misc.cpp new/ttynvt-v0.17/test/test_misc.cpp --- old/ttynvt-v0.16/test/test_misc.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/ttynvt-v0.17/test/test_misc.cpp 2025-06-25 17:32:41.000000000 +0200 @@ -0,0 +1,6 @@ +#include "test.h" + +TEST(Misc, dummy) +{ + EXPECT_EQ(1, 1); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttynvt-v0.16/test/test_nvttest.cpp new/ttynvt-v0.17/test/test_nvttest.cpp --- old/ttynvt-v0.16/test/test_nvttest.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/ttynvt-v0.17/test/test_nvttest.cpp 2025-06-25 17:32:41.000000000 +0200 @@ -0,0 +1,216 @@ +#include "test.h" + +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#define NVT_NAME "ttyNVT99" +#define NVT_DEV "/dev/" NVT_NAME + +#define NVT_SRV TOP_BLD_DIR "/nvtsrv/nvtsrv" +#define NVT_TEST TOP_BLD_DIR "/nvttest/nvttest" + +#define NVT_OPTS "-D" NVT_NAME + +#define LAUNCH_NVTTEST(...) proc_launch(NVT_TEST, NVT_OPTS, __VA_ARGS__) + +pid_t proc_spawn(char **argv) +{ + pid_t pid; + char buf[1024]; + + for (int i = 0, len = 0; argv[i]; i++) + len += snprintf(buf + len, sizeof(buf) - len, "%s ", argv[i]); + pr_info("Launching: %s", buf); + + pid = fork(); + if (pid > 0) + { + pr_info("... ok, pid = %d", pid); + return pid; + } + + // Child + + execv(argv[0], argv); + + pr_info("Launch failed: %m"); + + EXPECT_EQ(1, 0); + exit(1); +} + +void proc_waitfor(const char *name, pid_t pid) +{ + int err, wstatus; + + pr_info("Wait for %s (pid %d) to finish", name, pid); + + wstatus = 0; + err = waitpid(pid, &wstatus, 0); + if (err > 0) + pr_info("... ok, status = %x", wstatus); + else + pr_info("... error: %m"); + + EXPECT_GT(err, 0); + EXPECT_EQ(WEXITSTATUS(wstatus), 0); +} + +static pid_t proc_launch(const char *prog, ...) +{ + char *argv[16], *arg; + int i; + pid_t pid; + va_list args; + + va_start(args, prog); + + arg = (char *)prog; + i = 0; + argv[i++] = arg; + for (; arg != NULL;) + { + arg = va_arg(args, char *); + + argv[i++] = arg; + } + + va_end(args); + + pid = proc_spawn(argv); + + return pid; +} + +bool ttynvt_check() +{ + struct stat st; + bool ok; + + ok = stat(NVT_DEV, &st) == 0 && S_ISCHR(st.st_mode); + if (!ok) + { + fprintf(stderr, "\n%s" + "************************************************************\n" + "*** Invalid device file: '%s'\n" + "*** Ensure that ttynvt is launched correcly, e.g.:\n" + "# ttynvt -d -E -S localhost:1234 -n %s\n" + "*** ttynvt must run as root, and the device and server names\n" + "*** must be as shown above.\n" + "************************************************************\n" + "%s\n", COL_CYN, NVT_DEV, NVT_NAME, COL_RST); + } + return ok; +} + + + +TEST(Test1, t1) +{ + int err; + pid_t pid_srv, pid; + + ASSERT_TRUE(ttynvt_check()); + + pid_srv = proc_launch(NVT_SRV, "-de", "localhost:1234", NULL); + ASSERT_GT(pid_srv, 0); + + usleep(100000); + + pid = LAUNCH_NVTTEST(NULL); + ASSERT_GT(pid, 0); + + proc_waitfor("nvttest", pid); + + pr_info("Terminate nvtsrv"); + err = kill(pid_srv, SIGTERM); + EXPECT_EQ(err, 0); + + proc_waitfor("nvtsrv", pid_srv); +} + + + +/* Using fixture */ + +/**INDENT-OFF**/ +class Test2:public::testing::Test { + pid_t pid_srv; + + protected: + Test2() { } + virtual ~Test2() { } + + virtual void SetUp() { + + // Ensure ttynvt is running + ASSERT_TRUE(ttynvt_check()); + + // NB! Quiet nvtsrv + pid_srv = proc_launch(NVT_SRV, "-qe", "localhost:1234", NULL); + ASSERT_GT(pid_srv, 0); + + usleep(100000); + } + + virtual void TearDown() { + int err; + + pr_info("Terminate nvtsrv"); + err = kill(pid_srv, SIGTERM); + EXPECT_EQ(err, 0); + + proc_waitfor("nvtsrv", pid_srv); + } +}; +/**INDENT-ON**/ + +TEST_F(Test2, t1) +{ + pid_t pid; + + pid = LAUNCH_NVTTEST(NULL); + ASSERT_GT(pid, 0); + + proc_waitfor("nvttest", pid); +} + +// Multiple threads +TEST_F(Test2, t2) +{ + pid_t pid; + + // NB! Quiet nvttest + pid = LAUNCH_NVTTEST("-t5", "-q", NULL); + ASSERT_GT(pid, 0); + + proc_waitfor("nvttest", pid); +} + +// Multiple loops +TEST_F(Test2, t3) +{ + pid_t pid; + + // NB! Quiet nvttest + pid = LAUNCH_NVTTEST("-n5", "-q", NULL); + ASSERT_GT(pid, 0); + + proc_waitfor("nvttest", pid); +} + +// Multiple threads and loops +TEST_F(Test2, t4) +{ + pid_t pid; + + // NB! Quiet nvttest + pid = LAUNCH_NVTTEST("-n5", "-t5", "-q", NULL); + ASSERT_GT(pid, 0); + + proc_waitfor("nvttest", pid); +}