35 Commits

Author SHA1 Message Date
Kim Woelders 9ce6164d20 Bump version to 0.10 2018-09-12 13:13:09 +02:00
Kim Woelders cc95ed0ad2 Trivial cleanups 2018-09-12 12:14:47 +02:00
Kim Woelders 3231247534 Documentation stuff
- README:  Add notes on configure for cross-build
- AUTHORS: Added
- COPYING: Added (GPLv2)
2018-09-12 12:05:48 +02:00
Frank Rolsted Jensen c4c25d7dda version 0.9.005 2018-09-11 10:21:35 +02:00
Frank Rolsted Jensen b2747cf886 typo in README file 2018-09-11 10:17:36 +02:00
Frank Rolsted Jensen c5ca50b654 improved handling of modem/line status 2018-09-06 09:07:35 +02:00
Frank Rolsted Jensen 96329fc290 fix wrong decoding of the IAC escape char 2018-09-06 09:06:02 +02:00
Frank Rolsted Jensen 568f5ca733 version 0.9.004 2018-07-25 09:05:21 +02:00
Frank Rolsted Jensen 6bfdd85cfb fix compiler warnings(errors) 2018-07-25 09:03:42 +02:00
Frank Rolsted Jensen 7f4d2f3a51 support for line disciplines (TTY, PPP)
ttynvt now uses pseudoterminal (pty) to be able to get use of
the tty line disciplines.
Currently only the line discipline: TTY and PPP are supported.
2018-07-24 13:57:05 +02:00
Kim Woelders 3cae838cf0 Use kernel termios struct (?!?) 2018-07-18 11:43:44 +02:00
Kim Woelders 16825bd70e Add some more modem line control ioctl debug 2018-07-17 15:55:27 +02:00
Kim Woelders 5520722723 Add TIOCGETD/TIOCSETD in ioctl name decoder 2018-07-17 15:47:50 +02:00
Kim Woelders a68edc5e57 Add exclusive mode ioctls 2018-07-17 15:42:56 +02:00
Kim Woelders 2c3441dda5 Refactor ioctl input/output buffer size handling 2018-07-17 15:37:11 +02:00
Kim Woelders 45e73de4b9 Debug: Show ioctl names 2018-07-17 14:34:54 +02:00
Kim Woelders 778242986f Debug tweaks
- Add gcc printf format check to _log()
- Show thread ids
- Enable setting debug level
2018-07-17 14:08:01 +02:00
Kim Woelders 137418ad1e When running in daemon mode, delay parent exit until device is created
Doing this is somewhat elaborate because cuse_lowlevel_main() when
daemonizing, the parent (the calling thread) calls _exit(0) instead of
returning.
2018-07-17 13:53:23 +02:00
Kim Woelders 9057376656 Fix -D option, add DBG() for debug 2018-07-05 09:26:19 +02:00
Kim Woelders cbbb0cd225 Tweak options
- Change -s to -S to avoid clash with fuses singlethread option
  (mostly for testing).
- Merge port option with server option (server = host:port)
  (simpler).
2018-07-05 09:26:12 +02:00
Kim Woelders 2fb5ad2599 Drop ttynvt prefix from "local" functions
Only keep it on ones that are direct cuse_lowlevel_ops.

Makes it easier to understand things, IMO.
2018-07-05 08:38:36 +02:00
Kim Woelders 4988368662 Cosmetics of various sorts
Also in srv_connect() (renamed from ttynvt_connect()), close newly
crated socket in a couple of error paths.
2018-07-05 08:38:36 +02:00
Kim Woelders f0697e83f3 v0.9.003 2018-07-02 13:53:52 +02:00
Kim Woelders 0f879c8b61 Fix zero size reads
In certain cases we may get zero size reads (e.g. if the server sends an
rfc2217 notification without any other data).
In this situation we must not propagate the zero size read to user space
as it may be interpreted as end of input.

I haven't found a way to tell fuse that it should just ignore this read
but passing EINTR seems to work.
2018-07-02 12:40:27 +02:00
Kim Woelders 5ca23ce107 Correct write size
ttynvt_write() must on succesful writes return the number of bytes
written.

telnet_tx() always returns 0 (implicitly assuming srv_write() always
succeeds).
2018-07-02 12:39:56 +02:00
Kim Woelders b3f6d61edf Use syslog instead of logfile 2018-06-28 13:41:57 +02:00
Kim Woelders 7a424bc10d Make ttynvt_param global struct and avoid secondary variables 2018-06-28 13:38:27 +02:00
Kim Woelders 8956f3f851 Cleanups
- Consequently use "unsigned int", not "unsigned"
- Indent
- Sort headers
2018-06-28 13:37:25 +02:00
Kim Woelders ac76071e0e Autotoolify 2018-06-28 11:58:03 +02:00
Frank Rolsted Jensen 6337ac09eb support for blocking devices.
- and better handling of broken network connections.
2018-06-21 16:20:28 +02:00
Frank Rolsted Jensen fd4313745f logging connection error messages 2018-06-20 10:10:42 +02:00
Frank Rolsted Jensen a7d760d719 compiler warnings/errors fixed 2018-06-20 08:49:16 +02:00
Frank Rolsted Jensen 9ca94921c8 Description changed (minor) 2018-06-19 16:11:28 +02:00
Frank Rolsted Jensen cf678db1fd version information added to log file 2018-06-19 16:05:45 +02:00
Frank Rolsted Jensen 6556a2ec50 initial 2018-06-19 15:38:46 +02:00
29 changed files with 482 additions and 2725 deletions
+2 -4
View File
@@ -3,12 +3,10 @@
/autom4te.cache/
/compile
/config.h.in
/config.guess
/config.sub
/config.h.in~
/configure
/depcomp
/install-sh
/ltmain.sh
/missing
Makefile.in
@@ -22,7 +20,7 @@ Makefile
# build
*.o
/src/ttynvt
/ttynvt
/ttynvt-*.tar.gz
/ttynvt-*.tar.xz
Vendored
-6
View File
@@ -1,6 +0,0 @@
-kr -i4 --no-tabs --line-length79 -di16
--braces-after-if-line --brace-indent0 --dont-cuddle-else --cuddle-do-while
--blank-lines-after-declarations --blank-lines-after-procedures
--break-after-boolean-operator
--no-space-after-casts
--else-endif-column0
+14 -13
View File
@@ -1,19 +1,20 @@
# Build ttynvt
#
MAINTAINERCLEANFILES = \
aclocal.m4 autom4te.cache compile config.h.in config.h.in~ configure \
depcomp install-sh missing \
Makefile.in */Makefile.in
Makefile.in
SUBDIRS = lib src
if BUILD_TESTTOOLS
SUBDIRS += nvtsrv
SUBDIRS += nvttest
endif
if BUILD_TEST
SUBDIRS += test
endif
CFLAGS_OPT = -O3
CFLAGS_WARN = -Wall -Wextra -Werror -Wno-unused-parameter
.PHONY: $(SUBDIRS) test
$(SUBDIRS) test:
$(MAKE) -C $@
test: $(SUBDIRS)
bin_PROGRAMS = ttynvt
ttynvt_SOURCES = \
ttynvt.c \
telnet_basic.c telnet_rfc2217.c telnet.h telnet_param.h
ttynvt_CPPFLAGS = -I$(top_builddir) $(FUSE_CFLAGS) $(CFLAGS_OPT) $(CFLAGS_WARN)
ttynvt_LDADD = $(FUSE_LIBS)
+8 -23
View File
@@ -1,20 +1,23 @@
AC_INIT([ttynvt],[0.17],[frj@thrane.eu])
AM_INIT_AUTOMAKE([foreign dist-xz])
m4_define([pkg_version], [0.10])
#m4_define([pkg_revision], [005])
m4_define([pkg_version], m4_ifdef([pkg_revision], [pkg_version.pkg_revision], [pkg_version]))
AC_INIT([ttynvt],[pkg_version],[frj@thrane.eu])
AM_INIT_AUTOMAKE([foreign dist-xz])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_HEADER_STDC
define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
define([AC_LIBTOOL_LANG_GCJ_CONFIG], [:])dnl
LT_INIT()
AC_C_BIGENDIAN
AC_C_CONST
AC_C_INLINE
@@ -26,27 +29,9 @@ PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES(FUSE, fuse)
AC_ARG_ENABLE(testtools,
AS_HELP_STRING([--enable-testtools], [Build test tools @<:@default=no@:>@]),,
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"
CFLAGS_WARN="$CFLAGS_WARN -Wcast-align -Wcast-qual"
AC_SUBST(CFLAGS_WARN)
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
Makefile
lib/Makefile
src/Makefile
nvtsrv/Makefile
nvttest/Makefile
test/Makefile
])
AC_OUTPUT
-6
View File
@@ -1,6 +0,0 @@
noinst_LTLIBRARIES = libnvt.la
libnvt_la_CFLAGS = $(CFLAGS_WARN)
libnvt_la_SOURCES = nvt_log.c nvt_log.h
libnvt_la_SOURCES += nvt_socket.c nvt_socket.h
-114
View File
@@ -1,114 +0,0 @@
/*
* Logging functions
*/
#include <stdarg.h>
#include <stdio.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include "nvt_log.h"
#include <sys/syscall.h>
#define gettid() (pid_t)syscall(__NR_gettid)
char log_level = 0;
static char log_threshold = LOG_DEBUG;
static FILE *log_dest = NULL;
void nvt_log_dest(int dest)
{
switch (dest)
{
default:
case NVT_LOG_SYSLOG:
log_dest = NULL;
break;
case NVT_LOG_STDOUT:
log_dest = stdout;
break;
case NVT_LOG_STDERR:
log_dest = stderr;
break;
}
}
void nvt_log_level(int quiet, int level)
{
if (quiet)
log_threshold = LOG_NOTICE;
log_level = level;
}
static const char *_hms_txt(char *buf, unsigned int len)
{
struct timeval tv;
unsigned int sod, hh, mm, ss;
gettimeofday(&tv, NULL);
sod = tv.tv_sec % (24 * 3600);
hh = sod / 3600;
mm = (sod - hh * 3600) / 60;
ss = sod - hh * 3600 - mm * 60;
snprintf(buf, len, "%02d:%02d:%02d.%06d",
hh, mm, ss, (unsigned int)tv.tv_usec);
return buf;
}
void nvt_log(int prio, const char *fmt, ...)
{
va_list arg;
char buf[256], buft[64];
const char *eol;
int len;
if (prio > log_threshold)
return;
va_start(arg, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, arg);
if (log_dest)
{
eol = (len > 0 && buf[len - 1] != '\n') ? "\n" : "";
fprintf(log_dest, "%s: [%d] %d: %s%s",
_hms_txt(buft, sizeof(buft)), gettid(), prio, buf, eol);
}
else
{
syslog(prio, "[%d] %s", gettid(), buf);
}
va_end(arg);
}
#define BPL 16 /* Bytes per line */
void nvt_log_buf(int prio, const char *txt, const void *ptr_, unsigned int len)
{
unsigned int ix, i, imax;
int l, n;
char buf[128];
const unsigned char *ptr = ptr_;
for (ix = 0; ix < len || (len == 0 && ix == 0); ix += BPL)
{
n = snprintf(buf, sizeof(buf), "%s: %04x:", txt, ix);
if (n <= 0)
return; /* Just playing it safe */
imax = (len - ix < BPL) ? len - ix : BPL;
for (i = 0; i < imax; i++)
{
l = snprintf(buf + n, sizeof(buf) - n, " %02x", *ptr++);
if (l <= 0)
return; /* Just playing it safe */
n += l;
}
nvt_log(prio, "%s\n", buf);
}
}
-31
View File
@@ -1,31 +0,0 @@
/*
* Logging functions
*/
#ifndef NVT_LOG_H
#define NVT_LOG_H
#include <syslog.h>
#define _PRF_N_(no) __attribute__((__format__(__printf__, (no), (no) + 1)))
#define _PRF2_ _PRF_N_(2)
void nvt_log_dest(int dest);
void nvt_log_level(int quiet, int level);
_PRF2_ void nvt_log(int prio, const char *fmt, ...);
void nvt_log_buf(int prio, const char *txt,
const void *ptr, unsigned int len);
#define NVT_LOG_SYSLOG 0
#define NVT_LOG_STDOUT 1
#define NVT_LOG_STDERR 2
extern char log_level;
#define DBG(...) \
if (log_level > 0) nvt_log(LOG_DEBUG, __VA_ARGS__)
#define DBG2(...) \
if (log_level > 1) nvt_log(LOG_DEBUG, __VA_ARGS__)
#define DBG2_BUF(txt, ptr, len) \
if (log_level > 1) nvt_log_buf(LOG_DEBUG, txt, ptr, len)
#endif /* NVT_LOG_H */
-217
View File
@@ -1,217 +0,0 @@
/*
* Socket interface API
*/
#include <netdb.h> /* getaddrinfo() */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "nvt_log.h"
#include "nvt_socket.h"
typedef struct {
unsigned short type; // socket type
unsigned short slen; // sockaddr length
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, const char *port)
{
struct addrinfo hint, *adrinf = NULL, *p;
int ret = -1;
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;
}
// 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)
{
ssize_t host_len;
char host[64];
const char *port;
memset(sa, 0, sizeof(sa_t));
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, port) != 0)
return -1;
sa->type = SOCK_STREAM;
return 0;
}
int socket_create_client(const char *addr)
{
sa_t sa;
int fd, err;
if (_sa_addr_parse(&sa, addr) != 0)
return -1;
fd = socket(sa.gen.sa_family, sa.type, 0);
if (fd < 0)
{
nvt_log(LOG_ERR, "%s: Could not find address: '%s'", __func__, addr);
return fd;
}
err = connect(fd, &sa.gen, sa.slen);
if (err < 0)
{
nvt_log(LOG_ERR, "Failed to connect to: %s: %m\n", addr);
close(fd);
return -1;
}
return fd;
}
int socket_create_server(const char *addr)
{
sa_t sa;
int err, fd, opt;
err = _sa_addr_parse(&sa, addr);
if (err != 0)
{
nvt_log(LOG_ERR, "%s: Could not find address: '%s'", __func__, addr);
return -1;
}
fd = socket(sa.gen.sa_family, sa.type, 0);
if (fd < 0)
{
nvt_log(LOG_ERR, "%s: *** socket(%s): %m", __func__, addr);
return -1;
}
if (sa.gen.sa_family == AF_INET || sa.gen.sa_family == AF_INET6)
{
/* Avoid TIME_WAIT state on socket close */
opt = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
}
err = bind(fd, &sa.gen, sa.slen);
if (err != 0)
{
nvt_log(LOG_ERR, "%s: *** bind(%s): %m", __func__, addr);
close(fd);
return -1;
}
if (sa.type == SOCK_STREAM)
{
err = listen(fd, 5);
if (err != 0)
{
nvt_log(LOG_ERR, "%s: *** listen(%s): %m", __func__, addr);
close(fd);
return -1;
}
}
return fd;
}
int socket_create_server_client(int sfd)
{
int cfd;
socklen_t slen;
slen = 0;
cfd = accept(sfd, NULL, &slen);
if (cfd < 0)
{
nvt_log(LOG_ERR, "%s: *** accept(): %m", __func__);
return -1;
}
return cfd;
}
-12
View File
@@ -1,12 +0,0 @@
/*
* Socket functions
*/
#ifndef NVT_SOCKET_H
#define NVT_SOCKET_H
int socket_create_client(const char *addr);
int socket_create_server(const char *addr);
int socket_create_server_client(int sfd);
#endif /* NVT_SOCKET_H */
-10
View File
@@ -1,10 +0,0 @@
bin_PROGRAMS = nvtsrv
nvtsrv_SOURCES = \
nvtsrv.c \
telnet_basic.c telnet_server_rfc2217.c telnet.h telnet_param.h
nvtsrv_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) $(CFLAGS_WARN)
nvtsrv_LDADD = $(top_builddir)/lib/libnvt.la
-246
View File
@@ -1,246 +0,0 @@
/*
* RFC2217 test server
*/
#include <poll.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "lib/nvt_log.h"
#include "lib/nvt_socket.h"
#include "telnet.h"
/**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;
tn_ctx_t *tnct;
} dd;
struct pollfd pfds[3];
int nfds;
#define fd_srv pfds[1].fd
#define fd_cli pfds[2].fd
static void _usage(int rc)
{
printf(help_text);
exit(rc);
}
static void _tn_cli_close(void)
{
int i = 2;
nvt_log(LOG_INFO, "%d: fd=%d: Closed\n", i, pfds[i].fd);
close(pfds[i].fd);
pfds[i].fd = -1;
nfds = 2;
}
static void _tn_tx(void *cctx, const void *buf, int len)
{
int nw;
DBG2_BUF("Tx", buf, len);
if (fd_cli < 0)
{
nvt_log(LOG_NOTICE, "Write fd is closed - drop Tx\n");
return;
}
nw = write(fd_cli, buf, len);
if (nw != len)
{
nvt_log(LOG_ERR, "Write failed %d != %d\n", nw, len);
_tn_cli_close();
}
}
static void _tn_ss(void *cctx, int signal, int value)
{
DBG("RFC2217 signal %d: %02x", signal, value);
}
static void _nvtsrv_init(void)
{
free(dd.tnct);
memset(&dd, 0, sizeof(dd));
dd.tnct = telnet_ctx_init(NULL, _tn_tx, _tn_ss);
}
static void _nvtsrv_cmd(tn_ctx_t *tcc, const char *line, int len)
{
int val;
if (line[0] == '*' && len > 2)
{
/* Special features */
if (line[1] == 'm')
{
sscanf(line + 2, "%x", &val);
telnet_rfc2217_change_modemstate(tcc, val);
}
}
else
{
/* Send all input */
_tn_tx(NULL, line, len);
}
}
static void _nvtsrv_set_signal_handlers(void)
{
struct sigaction sa = {
.sa_handler = SIG_IGN,
.sa_flags = SA_RESTART,
};
sigemptyset(&sa.sa_mask);
sigaction(SIGPIPE, &sa, NULL);
}
int main(int argc, char **argv)
{
int opt;
char buf[128];
int rc, nr, i, len;
int debug, quiet;
bool do_echo;
debug = quiet = 0;
do_echo = false;
while ((opt = getopt(argc, argv, "deq")) != -1)
{
switch (opt)
{
default: /* '?' */
_usage(0);
break;
case 'd':
debug += 1;
break;
case 'e': /* Echo received data */
do_echo = true;
break;
case 'q':
quiet = 1;
break;
}
}
argc -= optind;
argv += optind;
if (argc <= 0)
_usage(1);
nvt_log_level(quiet, debug);
nvt_log_dest(NVT_LOG_STDOUT);
_nvtsrv_set_signal_handlers();
memset(pfds, 0, sizeof(pfds));
pfds[0].fd = STDIN_FILENO;
pfds[0].events = POLLIN;
pfds[1].fd = socket_create_server(argv[0]);
pfds[1].events = POLLIN;
pfds[2].fd = -1;
pfds[2].events = POLLIN;
nfds = 2;
for (;;)
{
for (i = 0; i < 3; i++)
pfds[i].revents = 0;
rc = poll(pfds, nfds, -1);
if (rc < 0)
{
nvt_log(LOG_ERR, "poll failed: %m\n");
break;
}
i = 0;
if (pfds[i].revents)
{
nr = read(pfds[i].fd, buf, sizeof(buf) - 1);
if (nr <= 0)
break;
buf[nr] = 0;
DBG2_BUF("Con Rx", buf, nr);
_nvtsrv_cmd(dd.tnct, buf, nr);
}
i = 2;
if (pfds[i].revents)
{
nr = 0;
if (pfds[i].revents & POLLIN)
{
nr = read(pfds[i].fd, buf, sizeof(buf));
if (nr <= 0)
{
_tn_cli_close();
continue;
}
}
if (pfds[i].revents & (POLLERR | POLLHUP))
{
_tn_cli_close();
}
if (nr > 0)
{
buf[nr] = 0;
DBG2_BUF("Rx", buf, nr);
len = nr;
rc = telnet_rx(dd.tnct, buf, &len);
if (do_echo)
{
/* Echo received */
_tn_tx(NULL, buf, len);
}
}
}
i = 1;
if (pfds[i].revents)
{
if (pfds[2].fd >= 0)
{
nvt_log(LOG_NOTICE, "Client already connected on fd=%d\n",
pfds[2].fd);
break;
}
pfds[2].fd = socket_create_server_client(pfds[i].fd);
nvt_log(LOG_INFO, "%d: fd=%d: Connected\n", 2, pfds[2].fd);
pfds[2].events = POLLIN;
nfds = 3;
_nvtsrv_init();
}
}
return 0;
}
-63
View File
@@ -1,63 +0,0 @@
/*
* Copyright (c) 2018 Lars Thrane A/S
* SPDX-License-Identifier: GPL-2.0
*
* Telnet interface - server
*/
#ifndef TELNET_SERVER_H
#define TELNET_SERVER_H
typedef void (cli_tx_f) (void *cctx, const void *buf, int len);
typedef void (cli_ss_f) (void *cctx, int signal, int value);
/* Telnet context */
typedef struct {
void *cctx; /* Client context */
cli_tx_f *cli_tx; /* Write to client */
cli_ss_f *cli_ss; /* Signal from client */
unsigned int bytes_rx; /* Rx byte count */
unsigned int off_rx; /* Rx buffer offset */
unsigned char mode_telnet; /* Telnet mode */
unsigned char mode_rfc2217; /* RFC-2217 mode */
unsigned int baudrate;
unsigned char datasize;
unsigned char parity;
unsigned char stopsize;
unsigned char linestate;
unsigned char modemstate;
unsigned char linestate_mask;
unsigned char modemstate_mask;
char dtr_state;
char rts_state;
} tn_ctx_t;
extern tn_ctx_t *telnet_ctx_init(void *cctx, cli_tx_f * ftx, cli_ss_f * fss);
extern int telnet_rx(tn_ctx_t * tcc, char *buf, int *plen);
extern int telnet_tx(tn_ctx_t * tcc, const char *buf, int len);
extern void telnet_reply_opt(tn_ctx_t * tcc, int opt, int prm,
const void *val, int len);
extern void telnet_rfc2217_init(tn_ctx_t * tcc, int when);
extern void telnet_rfc2217_handle_opt(tn_ctx_t * tcc, int opt,
unsigned char *pu, int nd);
extern void telnet_rfc2217_change_linestate(tn_ctx_t * tcc, int mask);
extern void telnet_rfc2217_change_modemstate(tn_ctx_t * tcc, int mask);
/* Init modes */
#define TNI_INIT 0 /* Init context */
#define TNI_ON 1 /* Option activated */
/* Signals that may be passed to cli_ss_f() */
#define TNS_DTR 1
#define TNS_RTS 2
#endif /* TELNET_SERVER_H */
-275
View File
@@ -1,275 +0,0 @@
/*
* Copyright (c) 2018 Lars Thrane A/S
* SPDX-License-Identifier: GPL-2.0
*
* Telnet protocol handling - server
*/
#include <stdlib.h>
#include <string.h>
#include "lib/nvt_log.h"
#include "telnet.h"
#include "telnet_param.h"
/* Telnet commands */
static const char *const tn_cmd[] = {
"SE", "NOP", "MARK", "BRK", "IP", "AO", "AYT", "EC",
"EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC"
};
#define OPT_NACK 0 /* Reject (DONT/WONT) */
#define OPT_IGNORE 1 /* Ignore the command (?) */
#define OPT_ACK 2 /* Acknowledge (DO /WILL) */
/* Telnet option support */
static const unsigned char tn_opt[256] = {
/* *INDENT-OFF* */
[TNO_BINARY] = OPT_ACK,
[TNO_SUPP_GA] = OPT_ACK,
// [TNO_TTYP] = OPT_NACK,
// [TNO_NAWS] = OPT_NACK,
// [TNO_NEO] = OPT_NACK,
[TNO_CPCO] = OPT_ACK,
// [TNO_KERMIT] = OPT_NACK,
/* *INDENT-ON* */
};
static void _telnet_handle_req(tn_ctx_t *tcc, int cmd, int opt)
{
char buf[3];
switch (tn_opt[opt])
{
default:
case OPT_IGNORE:
return;
case OPT_ACK:
cmd = (cmd == TNC_FB_WILL) ? TNC_FD_DO : TNC_FB_WILL;
break;
case OPT_NACK:
cmd = (cmd == TNC_FB_WILL) ? TNC_FE_DONT : TNC_FC_WONT;
break;
}
buf[0] = TNC_FF_IAC;
buf[1] = cmd;
buf[2] = opt;
DBG("TNo: Op2 %02x %02x: %-4s %d", cmd, opt, tn_cmd[cmd & 0xf], opt);
tcc->cli_tx(tcc->cctx, buf, 3);
if (opt == TNO_CPCO && (cmd == TNC_FB_WILL || cmd == TNC_FD_DO))
telnet_rfc2217_init(tcc, TNI_ON);
}
void telnet_reply_opt(tn_ctx_t *tcc, int opt, int prm,
const void *val, int len)
{
unsigned char buf[128], *pu = buf;
const unsigned char *pv;
int i;
*pu++ = TNC_FF_IAC;
*pu++ = TNC_FA_SB;
*pu++ = opt;
*pu++ = prm;
if (len > 0 && len <= 32)
{
pv = val;
for (i = 0; i < len; i++)
{
*pu++ = *pv;
if (*pv++ == TNC_FF_IAC)
*pu++ = TNC_FF_IAC;
}
}
*pu++ = TNC_FF_IAC;
*pu++ = TNC_F0_SE;
len = pu - buf;
DBG2_BUF("opto", buf, len);
tcc->cli_tx(tcc->cctx, buf, len);
}
static void _telnet_handle_opt(tn_ctx_t *tcc, int opt,
unsigned char *pu, int nd)
{
DBG2_BUF("opti", pu, nd);
switch (opt)
{
default:
nvt_log(LOG_WARNING, "Unexpected SB: Opt = %d", opt);
break;
case TNO_CPCO: /* RFC 2217 */
tcc->mode_rfc2217 = 1;
telnet_rfc2217_handle_opt(tcc, opt, pu, nd);
break;
}
}
int telnet_rx(tn_ctx_t *tcc, char *buf, int *plen)
{
char *s, *p;
unsigned char *pu;
int len, rem;
int np, nd;
int b1, b2;
/* Drop telnet processing entirely if we haven't seen any telnet
* negotiation in the beginning */
if (tcc->bytes_rx >= 32 && !tcc->mode_telnet)
return 0;
len = *plen;
tcc->bytes_rx += len;
if (len < (int)tcc->off_rx)
tcc->off_rx = 0;
for (s = buf + tcc->off_rx, rem = len - tcc->off_rx; rem > 0; s = p)
{
DBG2_BUF("****", s, rem);
p = memchr(s, TNC_FF_IAC, rem);
if (!p)
break;
/* We have IAC (= 0xff) */
np = rem - (p - s); /* N. chars available incl. IAC */
if (np < 2)
goto tn_more;
pu = (unsigned char *)p;
b1 = pu[1];
switch (b1)
{
default:
case TNC_F0_SE:
case TNC_F1_NOP:
case TNC_F2_MARK:
case TNC_F3_BRK:
case TNC_F4_IP:
case TNC_F5_AO:
case TNC_F6_AYT:
case TNC_F7_EC:
case TNC_F8_EL:
case TNC_F9_GA:
DBG("TNi: Op1 %02x : %s", b1, tn_cmd[b1 & 0xf]);
nd = 2; /* Drop 2 bytes */
goto tn_drop;
case TNC_FB_WILL:
case TNC_FC_WONT:
case TNC_FD_DO:
case TNC_FE_DONT:
if (np < 3)
goto tn_more; /* Need more */
tcc->mode_telnet = 1; /* Any such sequence activates TN */
b2 = pu[2];
DBG("TNi: Op2 %02x %02x: %-4s %d", b1, b2, tn_cmd[b1 & 0xf], b2);
if (b1 == TNC_FB_WILL || b1 == TNC_FD_DO)
_telnet_handle_req(tcc, b1, b2);
nd = 3; /* Drop 3 bytes */
goto tn_drop;
case TNC_FA_SB:
for (nd = 2; nd < np - 1; nd++)
{
if (pu[nd] == TNC_FF_IAC && pu[nd + 1] == TNC_F0_SE)
{
nd -= 2;
if (nd <= 0)
break;
b2 = pu[2];
tcc->mode_telnet = 1; /* Any such sequence activates TN */
DBG("TNi: Op2 %02x %02x: %-4s %d",
b1, b2, tn_cmd[b1 & 0xf], b2);
_telnet_handle_opt(tcc, b2, pu + 3, nd - 1);
nd += 4;
goto tn_drop;
}
}
if (np < 16)
goto tn_more; /* Not done */
/* This does not look right */
nvt_log_buf(LOG_WARNING, "tnrx", p, np);
rem = 0; /* Quit loop */
break;
case TNC_FF_IAC:
p++;
nd = 1; /* Drop 1 bytes */
goto tn_drop;
tn_drop:
if (!tcc->mode_telnet)
goto tn_break;
DBG2_BUF("drop", p, nd);
rem -= nd + (p - s);
len -= nd;
memmove(p, p + nd, rem);
break;
tn_break:
rem = 0; /* Quit loop */
break;
tn_more: /* Request more data */
tcc->off_rx = len - np;
*plen = len;
return 1;
}
}
tcc->off_rx = 0;
*plen = len;
return 0;
}
int telnet_tx(tn_ctx_t *tcc, const char *buf, int len)
{
const char *s, *p;
int rem, nd;
for (s = buf, rem = len; rem > 0; s = p)
{
if (tcc->mode_telnet)
p = memchr(s, TNC_FF_IAC, rem);
else
p = NULL;
if (!p)
{
/* Send the rest */
nd = rem;
tcc->cli_tx(tcc->cctx, s, nd);
}
else
{
nd = p - s + 1;
tcc->cli_tx(tcc->cctx, s, nd);
tcc->cli_tx(tcc->cctx, p, 1); /* One TNC_FF_IAC */
p++;
}
rem -= nd;
}
return 0;
}
tn_ctx_t *telnet_ctx_init(void *cctx, cli_tx_f *ftx, cli_ss_f *fss)
{
tn_ctx_t *tcc;
tcc = calloc(1, sizeof(tn_ctx_t));
tcc->cctx = cctx;
tcc->cli_tx = ftx; /* Write to client */
tcc->cli_ss = fss; /* Set state (line/modem) */
telnet_rfc2217_init(tcc, TNI_INIT);
return tcc;
}
-123
View File
@@ -1,123 +0,0 @@
/*
* Copyright (c) 2018 Lars Thrane A/S
* SPDX-License-Identifier: GPL-2.0
*
* Telnet parameters
*/
#ifndef TELNET_PARAM_H
#define TELNET_PARAM_H
/*
* Telnet commands
*/
#define TNC_F0_SE (0xf0) /* End of subnegotiation parameters */
#define TNC_F1_NOP (0xf1) /* No operation */
#define TNC_F2_MARK (0xf2) /* The data stream portion of a Synch.
This should always be accompanied
by a TCP Urgent notification. */
#define TNC_F3_BRK (0xf3) /* NVT character BRK. */
#define TNC_F4_IP (0xf4) /* The function IP (interrupt process) */
#define TNC_F5_AO (0xf5) /* The function AO (abort output) */
#define TNC_F6_AYT (0xf6) /* The function AYT (are you there) */
#define TNC_F7_EC (0xf7) /* The function EC (erase charceter) */
#define TNC_F8_EL (0xf8) /* The function EL (erase line) */
#define TNC_F9_GA (0xf9) /* The GA signal (go ahead) */
#define TNC_FA_SB (0xfa) /* Subnegotiation begin */
#define TNC_FB_WILL (0xfb) /* Indicates the desire to begin
performing, or confirmation that
you are now performing, the
indicated option. */
#define TNC_FC_WONT (0xfc) /* Indicates the refusal to perform,
or continue performing, the
indicated option. */
#define TNC_FD_DO (0xfd) /* Indicates the request that the
other party perform, or
confirmation that you are expecting
the other party to perform, the
indicated option. */
#define TNC_FE_DONT (0xfe) /* Indicates the demand that the
other party stop performing,
or confirmation that you are no
longer expecting the other party
to perform, the indicated option. */
#define TNC_FF_IAC (0xff) /* Interpret as Command / data byte */
/*
* Telnet options
*/
/*
* https://www.iana.org/assignments/telnet-options/telnet-options.xhtml
*
* 0 00 Binary Transmission [RFC856]
* 1 01 Echo [RFC857]
* 2 02 Reconnection [DDN Protocol Handbook, ... ]
* 3 03 Suppress Go Ahead [RFC858]
* 4 04 Approx Message Size Negotiation ["The Ethernet, ..." ]
* 5 05 Status [RFC859]
* 6 06 Timing Mark [RFC860]
* 7 07 Remote Controlled Trans and Echo [RFC726]
* 8 08 Output Line Width [DDN Protocol Handbook, ... ]
* 9 09 Output Page Size [DDN Protocol Handbook, ... ]
* 10 0a Output Carriage-Return Disposition [RFC652]
* 11 0b Output Horizontal Tab Stops [RFC653]
* 12 0c Output Horizontal Tab Disposition [RFC654]
* 13 0d Output Formfeed Disposition [RFC655]
* 14 0e Output Vertical Tabstops [RFC656]
* 15 0f Output Vertical Tab Disposition [RFC657]
* 16 10 Output Linefeed Disposition [RFC658]
* 17 11 Extended ASCII [RFC698]
* 18 12 Logout [RFC727]
* 19 13 Byte Macro [RFC735]
* 20 14 Data Entry Terminal [RFC1043][RFC732]
* 21 15 SUPDUP [RFC736][RFC734]
* 22 16 SUPDUP Output [RFC749]
* 23 17 Send Location [RFC779]
* 24 18 Terminal Type [RFC1091]
* 25 19 End of Record [RFC885]
* 26 1a TACACS User Identification [RFC927]
* 27 1b Output Marking [RFC933]
* 28 1c Terminal Location Number [RFC946]
* 29 1d Telnet 3270 Regime [RFC1041]
* 30 1e X.3 PAD [RFC1053]
* 31 1f Negotiate About Window Size [RFC1073]
* 32 20 Terminal Speed [RFC1079]
* 33 21 Remote Flow Control [RFC1372]
* 34 22 Linemode [RFC1184]
* 35 23 X Display Location [RFC1096]
* 36 24 Environment Option [RFC1408]
* 37 25 Authentication Option [RFC2941]
* 38 26 Encryption Option [RFC2946]
* 39 27 New Environment Option [RFC1572]
* 40 28 TN3270E [RFC2355]
* 41 29 XAUTH [Rob_Earhart]
* 42 2a CHARSET [RFC2066]
* 43 2b Telnet Remote Serial Port (RSP) [Robert_Barnes]
* 44 2c Com Port Control Option [RFC2217]
* 45 2d Telnet Suppress Local Echo [Wirt_Atmar]
* 46 2e Telnet Start TLS [Michael_Boe]
* 47 2f KERMIT [RFC2840]
* 48 30 SEND-URL [David_Croft]
* 49 31 FORWARD_X [Jeffrey_Altman]
* 50-137 32-89 Unassigned [IANA]
* 138 8a TELOPT PRAGMA LOGON [Steve_McGregory]
* 139 8b TELOPT SSPI LOGON [Steve_McGregory]
* 140 8c TELOPT PRAGMA HEARTBEAT [Steve_McGregory]
* 141-254 8d-fe Unassigned
* 255 ff Extended-Options-List [RFC861]
*/
#define TNO_BINARY 0 /* 00 Binary Transmission */
#define TNO_ECHO 1 /* 01 Echo */
#define TNO_SUPP_GA 3 /* 03 Suppress Go Ahead */
#define TNO_LOGOUT 18 /* 12 Logout */
#define TNO_TTYP 24 /* 18 Terminal Type */
#define TNO_NAWS 31 /* 1f Negotiate About Window Size */
#define TNO_NEO 39 /* 27 New Environment Option */
#define TNO_CPCO 44 /* 2c RFC 2217 */
#define TNO_KERMIT 47 /* 2f Kermit */
#endif /* TELNET_PARAM_H */
-254
View File
@@ -1,254 +0,0 @@
/*
* Copyright (c) 2018 Lars Thrane A/S
* SPDX-License-Identifier: GPL-2.0
*
* Telnet RFC-2217 handling - server
*/
#include <arpa/inet.h>
#include "lib/nvt_log.h"
#include "telnet.h"
#include "telnet_param.h"
void telnet_rfc2217_init(tn_ctx_t *tcc, int when)
{
switch (when)
{
default: /* Ignore */
break;
case TNI_INIT: /* Init context */
tcc->baudrate = 115200;
tcc->datasize = 8; /* 8 bit */
tcc->parity = 1; /* None */
tcc->stopsize = 1; /* 1 bit */
tcc->linestate = 0;
tcc->modemstate = 0;
tcc->linestate_mask = 0;
tcc->modemstate_mask = 0xff;
tcc->dtr_state = 0;
tcc->rts_state = 0;
break;
case TNI_ON: /* RFC-2217 activated */
tcc->mode_rfc2217 = 1;
telnet_rfc2217_change_modemstate(tcc, tcc->modemstate);
break;
}
}
void telnet_rfc2217_handle_opt(tn_ctx_t *tcc, int opt,
unsigned char *pu, int nd)
{
unsigned int sub, vali, valo, val4;
sub = pu[0];
switch (sub)
{
default:
// case 20-127: /* Available for Future Use */
nvt_log(LOG_WARNING, "Unhandled SB: Opt/prm = %d/%d", opt, sub);
break;
case 0: /* SIGNATURE */
telnet_reply_opt(tcc, opt, 100 + sub, "LT", 2);
DBG("RFC2217: Set signature");
break;
case 1: /* SET-BAUDRATE */
if (nd < 4)
break; /* Incorrect */
vali = (pu[1] << 24) | (pu[2] << 16) | (pu[3] << 8) | pu[4];
if (vali != 0) /* Set value */
tcc->baudrate = vali;
valo = tcc->baudrate;
DBG("RFC2217: Set baud %u -> %u", vali, valo);
val4 = htonl(valo);
telnet_reply_opt(tcc, opt, 100 + sub, &val4, 4);
break;
case 2: /* SET-DATASIZE */
valo = vali = pu[1];
#if 0 /* Request only */
if (vali != 0) /* Set value */
tcc->datasize = vali;
else /* Request value */
#endif
valo = tcc->datasize;
DBG("RFC2217: Set data %u -> %u", vali, valo);
telnet_reply_opt(tcc, opt, 100 + sub, &valo, 1);
break;
case 3: /* SET-PARITY */
valo = vali = pu[1];
#if 0 /* Request only */
if (vali != 0) /* Set value */
tcc->parity = vali;
else
#endif
valo = tcc->parity;
DBG("RFC2217: Set parity %u -> %u", vali, valo);
telnet_reply_opt(tcc, opt, 100 + sub, &valo, 1);
break;
case 4: /* SET-STOPSIZE */
valo = vali = pu[1];
#if 0 /* Request only */
if (vali != 0) /* Set value */
tcc->stopsize = vali;
else
#endif
valo = tcc->stopsize;
DBG("RFC2217: Set stop %u -> %u", vali, valo);
telnet_reply_opt(tcc, opt, 100 + sub, &valo, 1);
break;
case 5: /* SET-CONTROL */
vali = pu[1];
valo = 0;
switch (vali)
{
default:
nvt_log(LOG_WARNING, "Unexpected SB: Opt/prm/val = %d/%d/%u",
opt, sub, vali);
break;
case 0: /* Request Com Port Flow Control Setting
(outbound/both) */
case 1: /* Use No Flow Control (outbound/both) */
valo = 1; /* No flow control */
goto do_ctl_reply;
case 2: /* Use XON/XOFF Flow Control (outbound/both) */
valo = 1; /* No flow control */
nvt_log(LOG_WARNING, "RFC2217: Flow O %d -> %d", vali, valo);
goto do_ctl_reply;
case 3: /* Use HARDWARE Flow Control (outbound/both) */
valo = 3; /* HW flow control */
goto do_ctl_reply;
case 4: /* Request BREAK State */
valo = 6; /* BREAK off */
nvt_log(LOG_WARNING, "RFC2217: Break st %d -> %d", vali, valo);
goto do_ctl_reply;
case 5: /* Set BREAK State ON */
case 6: /* Set BREAK State OFF */
valo = 6; /* BREAK off */
goto do_ctl_reply;
case 7: /* Request DTR Signal State */
valo = (tcc->dtr_state) ? 8 : 9;
goto do_ctl_reply;
case 8: /* Set DTR Signal State ON */
case 9: /* Set DTR Signal State OFF */
valo = vali;
tcc->dtr_state = (valo == 8) ? 1 : 0;
DBG("RFC2217: Set DTR %s", tcc->dtr_state ? "on" : "off");
goto do_ctl_reply;
case 10: /* Request RTS Signal State */
valo = (tcc->rts_state) ? 11 : 12;
goto do_ctl_reply;
case 11: /* Set RTS Signal State ON */
case 12: /* Set RTS Signal State OFF */
valo = vali;
tcc->rts_state = (valo == 11) ? 1 : 0;
DBG("RFC2217: Set RTS %s", tcc->rts_state ? "on" : "off");
goto do_ctl_reply;
case 13: /* Request Com Port Flow Control Setting (inbound) */
case 14: /* Use No Flow Control (inbound) */
valo = 14; /* No flow control */
goto do_ctl_reply;
case 16: /* Use HARDWARE Flow Control (inbound) */
valo = 16; /* HW flow control */
goto do_ctl_reply;
case 15: /* Use XON/XOFF Flow Control (inbound) */
case 17: /* Use DCD Flow Control (outbound/both) */
case 18: /* Use DTR Flow Control (inbound) */
case 19: /* Use DSR Flow Control (outbound/both) */
valo = 14; /* No flow control */
nvt_log(LOG_WARNING, "RFC2217: Flow I %d -> %d", vali, valo);
goto do_ctl_reply;
do_ctl_reply:
DBG("RFC2217: Set control %u -> %u", vali, valo);
telnet_reply_opt(tcc, opt, 100 + sub, &valo, 1);
switch (vali)
{
default: /* Do noting */
break;
case 8: /* Set DTR Signal State ON */
case 9: /* Set DTR Signal State OFF */
if (tcc->cli_ss)
tcc->cli_ss(tcc->cctx, TNS_DTR, tcc->dtr_state);
break;
case 11: /* Set RTS Signal State ON */
case 12: /* Set RTS Signal State OFF */
if (tcc->cli_ss)
tcc->cli_ss(tcc->cctx, TNS_RTS, tcc->rts_state);
break;
}
break;
}
break;
#if 0 /* Server -> client only */
case 6: /* NOTIFY-LINESTATE */
case 7: /* NOTIFY-MODEMSTATE */
break;
#endif
case 8: /* FLOWCONTROL-SUSPEND */
case 9: /* FLOWCONTROL-RESUME */
nvt_log(LOG_WARNING, "RFC2217: Flowcontrol %s",
(sub == 8) ? "suspend" : "resume");
/* NB! Do not reply */
break;
case 10: /* SET-LINESTATE-MASK */
valo = vali = pu[1];
tcc->linestate_mask = vali;
DBG("RFC2217: Set linestate mask 0x%02x", vali);
telnet_reply_opt(tcc, opt, 100 + sub, &valo, 1);
break;
case 11: /* SET-MODEMSTATE-MASK */
valo = vali = pu[1];
tcc->modemstate_mask = vali;
DBG("RFC2217: Set modemstate mask 0x%02x", vali);
telnet_reply_opt(tcc, opt, 100 + sub, &valo, 1);
break;
case 12: /* PURGE-DATA */
valo = vali = pu[1];
DBG("RFC2217: Purge %d", vali);
telnet_reply_opt(tcc, opt, 100 + sub, &valo, 1);
break;
}
}
void telnet_rfc2217_change_linestate(tn_ctx_t *tcc, int mask)
{
unsigned char buf[1];
if (!tcc->mode_rfc2217)
goto done;
buf[0] = mask & tcc->linestate_mask;
buf[0] &= 0xf0; /* Drop change bits */
DBG("RFC2217: Notify linestate 0x%02x->0x%02x: 0x%02x",
tcc->linestate, mask, buf[0]);
telnet_reply_opt(tcc, TNO_CPCO, 100 + 6, buf, 1);
done:
tcc->linestate = mask;
}
void telnet_rfc2217_change_modemstate(tn_ctx_t *tcc, int mask)
{
unsigned char buf[1];
if (!tcc->mode_rfc2217)
goto done;
buf[0] = mask & tcc->modemstate_mask;
DBG("RFC2217: Notify modemstate 0x%02x->0x%02x: 0x%02x",
tcc->modemstate, mask, buf[0]);
telnet_reply_opt(tcc, TNO_CPCO, 100 + 7, buf, 1);
done:
tcc->modemstate = mask;
}
-9
View File
@@ -1,9 +0,0 @@
bin_PROGRAMS = nvttest
nvttest_SOURCES = \
nvttest.c
nvttest_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) $(CFLAGS_WARN)
nvttest_LDADD = $(top_builddir)/lib/libnvt.la -lpthread
-220
View File
@@ -1,220 +0,0 @@
/*
* ttynvt stress tool
*/
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <asm/termbits.h>
#include "lib/nvt_log.h"
/**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 char dev[64] = "/dev/ttyNVT0";
typedef struct {
int nthread;
int ithread;
int nloop;
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)
{
thr_t *thr = arg;
int iloop;
int fd, err, nw;
struct termios ios;
for (iloop = 0; iloop < thr->opts.nloop; iloop++)
{
nvt_log(LOG_INFO, "Thread %d/%d run %d/%d\n",
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;
}
memset(&ios, 0, sizeof(ios));
err = ioctl(fd, TCGETS, &ios);
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);
}
{
int i, len;
char buf[1024];
for (i = 0; i < (int)sizeof(buf); i++)
buf[i] = '0' + i % 10;
fd = open(dev, O_RDWR);
if (fd < 0)
{
nvt_log(LOG_ERR, "Open '%s' failed: %m\n", dev);
thr->errors++;
break;
}
for (i = 0; i < 10; i++)
{
len = rand() & 0xff;
nw = write(fd, buf, len);
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 (thr->opts.opt_rand_delay)
usleep(rand() & 0xfff);
}
return NULL;
}
int main(int argc, char **argv)
{
int err, errors;
int opt;
int ithr, nthr;
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, "D:dn:qrt:")) != -1)
{
switch (opt)
{
default: /* '?' */
_usage(1);
break;
case 'D':
snprintf(dev, sizeof(dev), "/dev/%s", optarg);
break;
case 'd':
debug += 1;
break;
case 'n':
topts.nloop = atoi(optarg);
break;
case 'q':
quiet = 1;
break;
case 'r':
topts.opt_rand_delay = true;
break;
case 't':
nthr = atoi(optarg);
break;
}
}
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;
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);
thr = &threads[ithr];
thr->opts = topts;
thr->opts.ithread = ithr + 1;
err = pthread_create(&thr->thr, NULL, _worker, thr);
if (err)
{
nvt_log(LOG_ERR, "Failed to create thread %d/%d\n", ithr, nthr);
break;
}
}
errors = 0;
for (ithr = 0; ithr < nthr; ithr++)
{
thr = &threads[ithr];
if (thr->thr == 0)
break;
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 errors ? 1 : 0;
}
-10
View File
@@ -1,10 +0,0 @@
bin_PROGRAMS = ttynvt
ttynvt_SOURCES = \
ttynvt.c \
telnet_basic.c telnet_client_rfc2217.c telnet.h telnet_param.h
ttynvt_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) $(FUSE_CFLAGS) $(CFLAGS_WARN)
ttynvt_LDADD = $(top_builddir)/lib/libnvt.la $(FUSE_LIBS)
-123
View File
@@ -1,123 +0,0 @@
/*
* Copyright (c) 2018 Lars Thrane A/S
* SPDX-License-Identifier: GPL-2.0
*
* Telnet parameters
*/
#ifndef TELNET_PARAM_H
#define TELNET_PARAM_H
/*
* Telnet commands
*/
#define TNC_F0_SE (0xf0) /* End of subnegotiation parameters */
#define TNC_F1_NOP (0xf1) /* No operation */
#define TNC_F2_MARK (0xf2) /* The data stream portion of a Synch.
This should always be accompanied
by a TCP Urgent notification. */
#define TNC_F3_BRK (0xf3) /* NVT character BRK. */
#define TNC_F4_IP (0xf4) /* The function IP (interrupt process) */
#define TNC_F5_AO (0xf5) /* The function AO (abort output) */
#define TNC_F6_AYT (0xf6) /* The function AYT (are you there) */
#define TNC_F7_EC (0xf7) /* The function EC (erase charceter) */
#define TNC_F8_EL (0xf8) /* The function EL (erase line) */
#define TNC_F9_GA (0xf9) /* The GA signal (go ahead) */
#define TNC_FA_SB (0xfa) /* Subnegotiation begin */
#define TNC_FB_WILL (0xfb) /* Indicates the desire to begin
performing, or confirmation that
you are now performing, the
indicated option. */
#define TNC_FC_WONT (0xfc) /* Indicates the refusal to perform,
or continue performing, the
indicated option. */
#define TNC_FD_DO (0xfd) /* Indicates the request that the
other party perform, or
confirmation that you are expecting
the other party to perform, the
indicated option. */
#define TNC_FE_DONT (0xfe) /* Indicates the demand that the
other party stop performing,
or confirmation that you are no
longer expecting the other party
to perform, the indicated option. */
#define TNC_FF_IAC (0xff) /* Interpret as Command / data byte */
/*
* Telnet options
*/
/*
* https://www.iana.org/assignments/telnet-options/telnet-options.xhtml
*
* 0 00 Binary Transmission [RFC856]
* 1 01 Echo [RFC857]
* 2 02 Reconnection [DDN Protocol Handbook, ... ]
* 3 03 Suppress Go Ahead [RFC858]
* 4 04 Approx Message Size Negotiation ["The Ethernet, ..." ]
* 5 05 Status [RFC859]
* 6 06 Timing Mark [RFC860]
* 7 07 Remote Controlled Trans and Echo [RFC726]
* 8 08 Output Line Width [DDN Protocol Handbook, ... ]
* 9 09 Output Page Size [DDN Protocol Handbook, ... ]
* 10 0a Output Carriage-Return Disposition [RFC652]
* 11 0b Output Horizontal Tab Stops [RFC653]
* 12 0c Output Horizontal Tab Disposition [RFC654]
* 13 0d Output Formfeed Disposition [RFC655]
* 14 0e Output Vertical Tabstops [RFC656]
* 15 0f Output Vertical Tab Disposition [RFC657]
* 16 10 Output Linefeed Disposition [RFC658]
* 17 11 Extended ASCII [RFC698]
* 18 12 Logout [RFC727]
* 19 13 Byte Macro [RFC735]
* 20 14 Data Entry Terminal [RFC1043][RFC732]
* 21 15 SUPDUP [RFC736][RFC734]
* 22 16 SUPDUP Output [RFC749]
* 23 17 Send Location [RFC779]
* 24 18 Terminal Type [RFC1091]
* 25 19 End of Record [RFC885]
* 26 1a TACACS User Identification [RFC927]
* 27 1b Output Marking [RFC933]
* 28 1c Terminal Location Number [RFC946]
* 29 1d Telnet 3270 Regime [RFC1041]
* 30 1e X.3 PAD [RFC1053]
* 31 1f Negotiate About Window Size [RFC1073]
* 32 20 Terminal Speed [RFC1079]
* 33 21 Remote Flow Control [RFC1372]
* 34 22 Linemode [RFC1184]
* 35 23 X Display Location [RFC1096]
* 36 24 Environment Option [RFC1408]
* 37 25 Authentication Option [RFC2941]
* 38 26 Encryption Option [RFC2946]
* 39 27 New Environment Option [RFC1572]
* 40 28 TN3270E [RFC2355]
* 41 29 XAUTH [Rob_Earhart]
* 42 2a CHARSET [RFC2066]
* 43 2b Telnet Remote Serial Port (RSP) [Robert_Barnes]
* 44 2c Com Port Control Option [RFC2217]
* 45 2d Telnet Suppress Local Echo [Wirt_Atmar]
* 46 2e Telnet Start TLS [Michael_Boe]
* 47 2f KERMIT [RFC2840]
* 48 30 SEND-URL [David_Croft]
* 49 31 FORWARD_X [Jeffrey_Altman]
* 50-137 32-89 Unassigned [IANA]
* 138 8a TELOPT PRAGMA LOGON [Steve_McGregory]
* 139 8b TELOPT SSPI LOGON [Steve_McGregory]
* 140 8c TELOPT PRAGMA HEARTBEAT [Steve_McGregory]
* 141-254 8d-fe Unassigned
* 255 ff Extended-Options-List [RFC861]
*/
#define TNO_BINARY 0 /* 00 Binary Transmission */
#define TNO_ECHO 1 /* 01 Echo */
#define TNO_SUPP_GA 3 /* 03 Suppress Go Ahead */
#define TNO_LOGOUT 18 /* 12 Logout */
#define TNO_TTYP 24 /* 18 Terminal Type */
#define TNO_NAWS 31 /* 1f Negotiate About Window Size */
#define TNO_NEO 39 /* 27 New Environment Option */
#define TNO_CPCO 44 /* 2c RFC 2217 */
#define TNO_KERMIT 47 /* 2f Kermit */
#endif /* TELNET_PARAM_H */
+10 -15
View File
@@ -2,10 +2,10 @@
* Copyright (c) 2018 Lars Thrane A/S
* SPDX-License-Identifier: GPL-2.0
*
* Telnet interface - client
* Telnet interface
*/
#ifndef TELNET_CLIENT_H
#define TELNET_CLIENT_H
#ifndef TELNET_H
#define TELNET_H
typedef int (srv_tx_f) (void *cctx, const void *buf, int len);
typedef int (srv_rx_f) (void *cctx, int timeout);
@@ -21,7 +21,7 @@ typedef struct {
unsigned int bytes_rx; /* Rx byte count */
unsigned int off_rx; /* Rx buffer offset */
signed char mode_telnet; /* Telnet mode */
unsigned char mode_telnet; /* Telnet mode */
unsigned char mode_rfc2217; /* RFC-2217 mode */
unsigned char telnet_ack[256]; /* telnet option ack counter */
} tn_ctx_t;
@@ -29,9 +29,9 @@ typedef struct {
extern tn_ctx_t *telnet_ctx_init(void *cctx, srv_tx_f * ftx, srv_rx_f * frx,
srv_ms_f * fss);
extern int telnet_open(tn_ctx_t * tcc, int mode);
extern int telnet_open(tn_ctx_t * tcc);
extern int telnet_rx(tn_ctx_t * tcc, char *buf, int *plen);
extern int telnet_rx(tn_ctx_t * tcc, char *buf, size_t * plen);
extern int telnet_tx(tn_ctx_t * tcc, const char *buf, int len);
extern void telnet_set_opt(tn_ctx_t * tcc, int opt, int prm,
@@ -42,14 +42,10 @@ extern void telnet_rfc2217_handle_opt(tn_ctx_t * tcc, int opt,
extern void telnet_rfc2217_cfg(tn_ctx_t * tcc, int cmd,
const void *val, int nd);
extern void telnet_rfc2217_ctl(tn_ctx_t * tcc, unsigned int val);
/* Telnet mode */
#define TN_MODE_RAW 0 /* Telnet processing off */
#define TN_MODE_TELNET 1 /* Telnet mode */
extern void telnet_rfc2217_ctl(tn_ctx_t * tcc, int cmd);
/*RFC2217 modem state*/
#define TNS_STATE_DCD 0x80
#define TNS_STATE_CD 0x80
#define TNS_STATE_RI 0x40
#define TNS_STATE_DSR 0x20
#define TNS_STATE_CTS 0x10
@@ -64,12 +60,11 @@ extern void telnet_rfc2217_ctl(tn_ctx_t * tcc, unsigned int val);
/*RFC2217 control commands*/
#define TNS_CTL_NOFLOW 1
#define TNS_CTL_XONOFF_OUT 2
#define TNS_CTL_XONOFF 2
#define TNS_CTL_CTSRTS 3
#define TNS_CTL_DTR_ON 8
#define TNS_CTL_DTR_OFF 9
#define TNS_CTL_RTS_ON 11
#define TNS_CTL_RTS_OFF 12
#define TNS_CTL_XONOFF_IN 15
#endif /* TELNET_CLIENT_H */
#endif /*TELNET_H */
+19 -29
View File
@@ -2,12 +2,12 @@
* Copyright (c) 2018 Lars Thrane A/S
* SPDX-License-Identifier: GPL-2.0
*
* Telnet protocol handling - client
* Telnet server - Telnet protocol handling
*/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include "telnet.h"
#include "telnet_param.h"
@@ -39,7 +39,7 @@ static const unsigned char tn_opt[256] = {
};
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];
@@ -68,7 +68,7 @@ static void _telnet_handle_req(tn_ctx_t *tcc, int cmd, int opt)
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)
{
@@ -77,7 +77,7 @@ static void _telnet_handle_resp(tn_ctx_t *tcc, int cmd, int opt)
}
}
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;
@@ -107,7 +107,7 @@ void telnet_set_opt(tn_ctx_t *tcc, int opt, int prm, const void *val, int len)
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)
@@ -121,22 +121,18 @@ static void _telnet_handle_opt(tn_ctx_t *tcc, int opt,
}
}
int telnet_rx(tn_ctx_t *tcc, char *buf, int *plen)
int telnet_rx(tn_ctx_t * tcc, char *buf, size_t * plen)
{
char *s, *p;
unsigned char *pu;
int len, rem;
size_t len, rem;
int np, nd;
int b1, b2;
/* Skip telnet processing entirely in raw mode */
if (tcc->mode_telnet < 0)
return 0;
len = *plen;
tcc->bytes_rx += len;
if (len < (int)tcc->off_rx)
if (len < (size_t) tcc->off_rx)
tcc->off_rx = 0;
for (s = buf + tcc->off_rx, rem = len - tcc->off_rx; rem > 0; s = p)
@@ -148,7 +144,7 @@ int telnet_rx(tn_ctx_t *tcc, char *buf, int *plen)
/* We have IAC (= 0xff) */
np = rem - (p - s); /* N. chars available incl. IAC */
if (np < 2)
goto tn_more;
return 1;
pu = (unsigned char *)p;
b1 = pu[1];
@@ -234,14 +230,14 @@ int telnet_rx(tn_ctx_t *tcc, char *buf, int *plen)
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;
for (s = buf, rem = len; rem > 0; s = p)
{
if (tcc->mode_telnet > 0)
if (tcc->mode_telnet)
p = memchr(s, TNC_FF_IAC, rem);
else
p = NULL;
@@ -264,18 +260,12 @@ int telnet_tx(tn_ctx_t *tcc, const char *buf, int len)
return 0;
}
int telnet_open(tn_ctx_t *tcc, int mode)
int telnet_open(tn_ctx_t * tcc)
{
time_t t = time(NULL);;
char buf[3];
int res;
if (mode == TN_MODE_RAW)
{
tcc->mode_telnet = -1; /* Raw mode - no telnet processing */
return 0;
}
buf[0] = TNC_FF_IAC;
buf[1] = TNC_FB_WILL;
buf[2] = TNO_CPCO;
@@ -285,17 +275,17 @@ int telnet_open(tn_ctx_t *tcc, int mode)
while (1)
{
res = tcc->srv_rx(tcc->cctx, 1000);
if (res < 0)
return errno;
if (res <= 0)
return -1;
else if (tcc->mode_rfc2217)
return 0;
else if (time(NULL) - t > 10)
return EPROTO;
else if (t - time(NULL) > 2)
return -1;
}
}
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;
+123
View File
@@ -0,0 +1,123 @@
/*
* Copyright (c) 2018 Lars Thrane A/S
* SPDX-License-Identifier: GPL-2.0
*
* Telnet parameters
*/
#ifndef TELNET_PARAM_H
#define TELNET_PARAM_H
/*
* Telnet commands
*/
#define TNC_F0_SE (0xf0) /* End of subnegotiation parameters */
#define TNC_F1_NOP (0xf1) /* No operation */
#define TNC_F2_MARK (0xf2) /* The data stream portion of a Synch.
This should always be accompanied
by a TCP Urgent notification. */
#define TNC_F3_BRK (0xf3) /* NVT character BRK. */
#define TNC_F4_IP (0xf4) /* The function IP (interrupt process) */
#define TNC_F5_AO (0xf5) /* The function AO (abort output) */
#define TNC_F6_AYT (0xf6) /* The function AYT (are you there) */
#define TNC_F7_EC (0xf7) /* The function EC (erase charceter) */
#define TNC_F8_EL (0xf8) /* The function EL (erase line) */
#define TNC_F9_GA (0xf9) /* The GA signal (go ahead) */
#define TNC_FA_SB (0xfa) /* Subnegotiation begin */
#define TNC_FB_WILL (0xfb) /* Indicates the desire to begin
performing, or confirmation that
you are now performing, the
indicated option. */
#define TNC_FC_WONT (0xfc) /* Indicates the refusal to perform,
or continue performing, the
indicated option. */
#define TNC_FD_DO (0xfd) /* Indicates the request that the
other party perform, or
confirmation that you are expecting
the other party to perform, the
indicated option. */
#define TNC_FE_DONT (0xfe) /* Indicates the demand that the
other party stop performing,
or confirmation that you are no
longer expecting the other party
to perform, the indicated option. */
#define TNC_FF_IAC (0xff) /* Interpret as Command / data byte */
/*
* Telnet options
*/
/*
* https://www.iana.org/assignments/telnet-options/telnet-options.xhtml
*
* 0 Binary Transmission [RFC856]
* 1 Echo [RFC857]
* 2 Reconnection [DDN Protocol Handbook, ... ]
* 3 Suppress Go Ahead [RFC858]
* 4 Approx Message Size Negotiation ["The Ethernet, ... ]
* 5 Status [RFC859]
* 6 Timing Mark [RFC860]
* 7 Remote Controlled Trans and Echo [RFC726]
* 8 Output Line Width [DDN Protocol Handbook, ... ]
* 9 Output Page Size [DDN Protocol Handbook, ... ]
* 10 Output Carriage-Return Disposition [RFC652]
* 11 Output Horizontal Tab Stops [RFC653]
* 12 Output Horizontal Tab Disposition [RFC654]
* 13 Output Formfeed Disposition [RFC655]
* 14 Output Vertical Tabstops [RFC656]
* 15 Output Vertical Tab Disposition [RFC657]
* 16 Output Linefeed Disposition [RFC658]
* 17 Extended ASCII [RFC698]
* 18 Logout [RFC727]
* 19 Byte Macro [RFC735]
* 20 Data Entry Terminal [RFC1043][RFC732]
* 21 SUPDUP [RFC736][RFC734]
* 22 SUPDUP Output [RFC749]
* 23 Send Location [RFC779]
* 24 Terminal Type [RFC1091]
* 25 End of Record [RFC885]
* 26 TACACS User Identification [RFC927]
* 27 Output Marking [RFC933]
* 28 Terminal Location Number [RFC946]
* 29 Telnet 3270 Regime [RFC1041]
* 30 X.3 PAD [RFC1053]
* 31 Negotiate About Window Size [RFC1073]
* 32 Terminal Speed [RFC1079]
* 33 Remote Flow Control [RFC1372]
* 34 Linemode [RFC1184]
* 35 X Display Location [RFC1096]
* 36 Environment Option [RFC1408]
* 37 Authentication Option [RFC2941]
* 38 Encryption Option [RFC2946]
* 39 New Environment Option [RFC1572]
* 40 TN3270E [RFC2355]
* 41 XAUTH [Rob_Earhart]
* 42 CHARSET [RFC2066]
* 43 Telnet Remote Serial Port (RSP) [Robert_Barnes]
* 44 Com Port Control Option [RFC2217]
* 45 Telnet Suppress Local Echo [Wirt_Atmar]
* 46 Telnet Start TLS [Michael_Boe]
* 47 KERMIT [RFC2840]
* 48 SEND-URL [David_Croft]
* 49 FORWARD_X [Jeffrey_Altman]
* 50-137 Unassigned [IANA]
* 138 TELOPT PRAGMA LOGON [Steve_McGregory]
* 139 TELOPT SSPI LOGON [Steve_McGregory]
* 140 TELOPT PRAGMA HEARTBEAT [Steve_McGregory]
* 141-254 Unassigned
* 255 Extended-Options-List [RFC861]
*/
#define TNO_BINARY 0 /* Binary Transmission */
#define TNO_ECHO 1 /* Echo */
#define TNO_SUPP_GA 3 /* Suppress Go Ahead */
#define TNO_LOGOUT 18 /* Logout */
#define TNO_TTYP 24 /* Terminal Type */
#define TNO_NAWS 31 /* Negotiate About Window Size */
#define TNO_NEO 39 /* New Environment Option */
#define TNO_CPCO 44 /* RFC 2217 */
#define TNO_KERMIT 47 /* Kermit */
#endif /* TELNET_PARAM_H */
@@ -2,12 +2,15 @@
* Copyright (c) 2018 Lars Thrane A/S
* SPDX-License-Identifier: GPL-2.0
*
* Telnet RFC-2217 handling - client
* Telnet server - RFC-2217 handling
*/
#include <stddef.h>
#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 +35,7 @@ void telnet_rfc2217_handle_opt(tn_ctx_t *tcc, int opt,
}
}
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,12 +43,10 @@ void telnet_rfc2217_cfg(tn_ctx_t *tcc, int cmd, const void *val, int nd)
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, int cmd)
{
unsigned char byte = val;
if (!tcc->mode_rfc2217)
return;
telnet_set_opt(tcc, TNO_CPCO, TNS_SET_CONTROL, &byte, 1);
telnet_set_opt(tcc, TNO_CPCO, TNS_SET_CONTROL, &cmd, 1);
}
-48
View File
@@ -1,48 +0,0 @@
# 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)
-70
View File
@@ -1,70 +0,0 @@
/*
* 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);
}
-25
View File
@@ -1,25 +0,0 @@
#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 */
-6
View File
@@ -1,6 +0,0 @@
#include "test.h"
TEST(Misc, dummy)
{
EXPECT_EQ(1, 1);
}
-216
View File
@@ -1,216 +0,0 @@
#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);
}
+298 -550
View File
File diff suppressed because it is too large Load Diff