Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1081fd9235 | |||
| 72e09527b9 | |||
| 10d5c9cf3b | |||
| 4d3f7d384b | |||
| 1f516288ab | |||
| 55c5d0d226 | |||
| cd5de2fe5d | |||
| da027d4de1 | |||
| 3bcbf9c8c1 | |||
| 611ab3cbf3 | |||
| 6e2e530215 | |||
| 3d5848aff0 | |||
| 4223a4b92a | |||
| 2c090f3721 | |||
| 797ccf08c8 | |||
| 9739087594 | |||
| f41067c3be |
@@ -9,3 +9,11 @@ if BUILD_TESTTOOLS
|
|||||||
SUBDIRS += nvtsrv
|
SUBDIRS += nvtsrv
|
||||||
SUBDIRS += nvttest
|
SUBDIRS += nvttest
|
||||||
endif
|
endif
|
||||||
|
if BUILD_TEST
|
||||||
|
SUBDIRS += test
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: $(SUBDIRS) test
|
||||||
|
$(SUBDIRS) test:
|
||||||
|
$(MAKE) -C $@
|
||||||
|
test: $(SUBDIRS)
|
||||||
|
|||||||
+5
-2
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT([ttynvt],[0.16],[frj@thrane.eu])
|
AC_INIT([ttynvt],[0.17],[frj@thrane.eu])
|
||||||
AM_INIT_AUTOMAKE([foreign dist-xz])
|
AM_INIT_AUTOMAKE([foreign dist-xz])
|
||||||
|
|
||||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||||
@@ -6,10 +6,10 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
|||||||
AC_USE_SYSTEM_EXTENSIONS
|
AC_USE_SYSTEM_EXTENSIONS
|
||||||
|
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
|
AC_PROG_CXX
|
||||||
|
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
|
|
||||||
define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
|
|
||||||
define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
|
define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
|
||||||
define([AC_LIBTOOL_LANG_GCJ_CONFIG], [:])dnl
|
define([AC_LIBTOOL_LANG_GCJ_CONFIG], [:])dnl
|
||||||
|
|
||||||
@@ -31,6 +31,8 @@ AC_ARG_ENABLE(testtools,
|
|||||||
enable_testtools=no)
|
enable_testtools=no)
|
||||||
AM_CONDITIONAL([BUILD_TESTTOOLS], [test "x$enable_testtools" = "xyes"])
|
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 -Wall -Wextra -Werror -Wno-unused-parameter"
|
||||||
CFLAGS_WARN="$CFLAGS_WARN -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes"
|
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 -Waggregate-return -Wpointer-arith -Wshadow -Wwrite-strings"
|
||||||
@@ -44,6 +46,7 @@ lib/Makefile
|
|||||||
src/Makefile
|
src/Makefile
|
||||||
nvtsrv/Makefile
|
nvtsrv/Makefile
|
||||||
nvttest/Makefile
|
nvttest/Makefile
|
||||||
|
test/Makefile
|
||||||
])
|
])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
|
|||||||
+83
-15
@@ -7,6 +7,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
#include "nvt_log.h"
|
#include "nvt_log.h"
|
||||||
#include "nvt_socket.h"
|
#include "nvt_socket.h"
|
||||||
@@ -18,42 +19,109 @@ typedef struct {
|
|||||||
union {
|
union {
|
||||||
struct sockaddr gen;
|
struct sockaddr gen;
|
||||||
struct sockaddr_in ipv4;
|
struct sockaddr_in ipv4;
|
||||||
|
struct sockaddr_in6 ipv6;
|
||||||
|
struct sockaddr_un un;
|
||||||
};
|
};
|
||||||
} sa_t;
|
} 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);
|
memset(&hint, 0, sizeof(struct addrinfo));
|
||||||
if (server == NULL)
|
|
||||||
|
if (getaddrinfo(host, port, &hint, &adrinf) != 0)
|
||||||
{
|
{
|
||||||
nvt_log(LOG_ERR, "Cannot resolve host name: %m\n");
|
nvt_log(LOG_ERR, "Cannot resolve host name: %m\n");
|
||||||
return -1;
|
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);
|
sa->slen = sizeof(sa->ipv4);
|
||||||
|
memcpy(&sa->ipv4, p->ai_addr, sizeof(struct sockaddr_in));
|
||||||
sa->ipv4.sin_family = AF_INET;
|
ret = 0;
|
||||||
memcpy(&sa->ipv4.sin_addr.s_addr, server->h_addr, server->h_length);
|
goto exit_host_lookup;
|
||||||
|
}
|
||||||
return 0;
|
}
|
||||||
|
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));
|
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 (_sa_host_lookup(sa, host) != 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;
|
return -1;
|
||||||
|
|
||||||
sa->type = SOCK_STREAM;
|
sa->type = SOCK_STREAM;
|
||||||
sa->ipv4.sin_port = htons(atoi(port));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -103,7 +171,7 @@ int socket_create_server(const char *addr)
|
|||||||
return -1;
|
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 */
|
/* Avoid TIME_WAIT state on socket close */
|
||||||
opt = 1;
|
opt = 1;
|
||||||
|
|||||||
+17
-11
@@ -14,9 +14,15 @@
|
|||||||
#include "telnet.h"
|
#include "telnet.h"
|
||||||
|
|
||||||
|
|
||||||
#define HELP \
|
/**INDENT-OFF**/
|
||||||
"Usage: nvtsrv -deq\n"
|
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 {
|
struct {
|
||||||
unsigned char mline;
|
unsigned char mline;
|
||||||
@@ -30,10 +36,10 @@ int nfds;
|
|||||||
#define fd_cli pfds[2].fd
|
#define fd_cli pfds[2].fd
|
||||||
|
|
||||||
|
|
||||||
static void _nvtsrv_usage(void)
|
static void _usage(int rc)
|
||||||
{
|
{
|
||||||
printf("Usage:\n" " nvtsrv host:port\n");
|
printf(help_text);
|
||||||
exit(0);
|
exit(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tn_cli_close(void)
|
static void _tn_cli_close(void)
|
||||||
@@ -68,7 +74,7 @@ static void _tn_tx(void *cctx, const void *buf, int len)
|
|||||||
|
|
||||||
static void _tn_ss(void *cctx, int signal, int value)
|
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)
|
static void _nvtsrv_init(void)
|
||||||
@@ -80,7 +86,7 @@ static void _nvtsrv_init(void)
|
|||||||
dd.tnct = telnet_ctx_init(NULL, _tn_tx, _tn_ss);
|
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;
|
int val;
|
||||||
|
|
||||||
@@ -127,8 +133,8 @@ int main(int argc, char **argv)
|
|||||||
switch (opt)
|
switch (opt)
|
||||||
{
|
{
|
||||||
default: /* '?' */
|
default: /* '?' */
|
||||||
fprintf(stderr, HELP);
|
_usage(0);
|
||||||
exit(EXIT_FAILURE);
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
debug += 1;
|
debug += 1;
|
||||||
break;
|
break;
|
||||||
@@ -144,7 +150,7 @@ int main(int argc, char **argv)
|
|||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
if (argc <= 0)
|
if (argc <= 0)
|
||||||
_nvtsrv_usage();
|
_usage(1);
|
||||||
|
|
||||||
nvt_log_level(quiet, debug);
|
nvt_log_level(quiet, debug);
|
||||||
nvt_log_dest(NVT_LOG_STDOUT);
|
nvt_log_dest(NVT_LOG_STDOUT);
|
||||||
|
|||||||
@@ -36,7 +36,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];
|
char buf[3];
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ static void _telnet_handle_req(tn_ctx_t * tcc, int cmd, int opt)
|
|||||||
telnet_rfc2217_init(tcc, TNI_ON);
|
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)
|
const void *val, int len)
|
||||||
{
|
{
|
||||||
unsigned char buf[128], *pu = buf;
|
unsigned char buf[128], *pu = buf;
|
||||||
@@ -94,7 +94,7 @@ void telnet_reply_opt(tn_ctx_t * tcc, int opt, int prm,
|
|||||||
tcc->cli_tx(tcc->cctx, buf, len);
|
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)
|
unsigned char *pu, int nd)
|
||||||
{
|
{
|
||||||
DBG2_BUF("opti", pu, nd);
|
DBG2_BUF("opti", pu, nd);
|
||||||
@@ -111,7 +111,7 @@ 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, int *plen)
|
||||||
{
|
{
|
||||||
char *s, *p;
|
char *s, *p;
|
||||||
unsigned char *pu;
|
unsigned char *pu;
|
||||||
@@ -230,7 +230,7 @@ int telnet_rx(tn_ctx_t * tcc, char *buf, int *plen)
|
|||||||
return 0;
|
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;
|
const char *s, *p;
|
||||||
int rem, nd;
|
int rem, nd;
|
||||||
@@ -260,7 +260,7 @@ int telnet_tx(tn_ctx_t * tcc, const char *buf, int len)
|
|||||||
return 0;
|
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;
|
tn_ctx_t *tcc;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include "telnet.h"
|
#include "telnet.h"
|
||||||
#include "telnet_param.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)
|
switch (when)
|
||||||
{
|
{
|
||||||
@@ -39,7 +39,7 @@ void telnet_rfc2217_init(tn_ctx_t * tcc, int when)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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 char *pu, int nd)
|
||||||
{
|
{
|
||||||
unsigned int sub, vali, valo, val4;
|
unsigned int sub, vali, valo, val4;
|
||||||
@@ -138,8 +138,7 @@ void telnet_rfc2217_handle_opt(tn_ctx_t * tcc, int opt,
|
|||||||
case 9: /* Set DTR Signal State OFF */
|
case 9: /* Set DTR Signal State OFF */
|
||||||
valo = vali;
|
valo = vali;
|
||||||
tcc->dtr_state = (valo == 8) ? 1 : 0;
|
tcc->dtr_state = (valo == 8) ? 1 : 0;
|
||||||
nvt_log(LOG_INFO, "RFC2217: Set DTR %s",
|
DBG("RFC2217: Set DTR %s", tcc->dtr_state ? "on" : "off");
|
||||||
tcc->dtr_state ? "on" : "off");
|
|
||||||
goto do_ctl_reply;
|
goto do_ctl_reply;
|
||||||
|
|
||||||
case 10: /* Request RTS Signal State */
|
case 10: /* Request RTS Signal State */
|
||||||
@@ -149,8 +148,7 @@ void telnet_rfc2217_handle_opt(tn_ctx_t * tcc, int opt,
|
|||||||
case 12: /* Set RTS Signal State OFF */
|
case 12: /* Set RTS Signal State OFF */
|
||||||
valo = vali;
|
valo = vali;
|
||||||
tcc->rts_state = (valo == 11) ? 1 : 0;
|
tcc->rts_state = (valo == 11) ? 1 : 0;
|
||||||
nvt_log(LOG_INFO, "RFC2217: Set RTS %s",
|
DBG("RFC2217: Set RTS %s", tcc->rts_state ? "on" : "off");
|
||||||
tcc->rts_state ? "on" : "off");
|
|
||||||
goto do_ctl_reply;
|
goto do_ctl_reply;
|
||||||
|
|
||||||
case 13: /* Request Com Port Flow Control Setting (inbound) */
|
case 13: /* Request Com Port Flow Control Setting (inbound) */
|
||||||
@@ -220,7 +218,7 @@ void telnet_rfc2217_handle_opt(tn_ctx_t * tcc, int opt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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];
|
unsigned char buf[1];
|
||||||
|
|
||||||
@@ -238,7 +236,7 @@ void telnet_rfc2217_change_linestate(tn_ctx_t * tcc, int mask)
|
|||||||
tcc->linestate = mask;
|
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];
|
unsigned char buf[1];
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -6,4 +6,4 @@ nvttest_SOURCES = \
|
|||||||
|
|
||||||
nvttest_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) $(CFLAGS_WARN)
|
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
|
||||||
|
|||||||
+67
-22
@@ -7,6 +7,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
@@ -16,10 +17,20 @@
|
|||||||
#include "lib/nvt_log.h"
|
#include "lib/nvt_log.h"
|
||||||
|
|
||||||
|
|
||||||
#define HELP \
|
/**INDENT-OFF**/
|
||||||
"Usage: nvttest -dqr [-n loops] [-t threads]\n"
|
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 {
|
typedef struct {
|
||||||
int nthread;
|
int nthread;
|
||||||
@@ -28,22 +39,37 @@ typedef struct {
|
|||||||
bool opt_rand_delay;
|
bool opt_rand_delay;
|
||||||
} topts_t;
|
} 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)
|
static void *_worker(void *arg)
|
||||||
{
|
{
|
||||||
topts_t *topts = arg;
|
thr_t *thr = arg;
|
||||||
int iloop;
|
int iloop;
|
||||||
int fd, err, nw;
|
int fd, err, nw;
|
||||||
struct termios ios;
|
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",
|
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);
|
fd = open(dev, O_RDWR);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
nvt_log(LOG_ERR, "Open '%s' failed: %m\n", dev);
|
nvt_log(LOG_ERR, "Open '%s' failed: %m\n", dev);
|
||||||
|
thr->errors++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,12 +78,14 @@ static void *_worker(void *arg)
|
|||||||
if (err != 0)
|
if (err != 0)
|
||||||
{
|
{
|
||||||
nvt_log(LOG_ERR, "ioctl(TCGETS) failed: %m\n");
|
nvt_log(LOG_ERR, "ioctl(TCGETS) failed: %m\n");
|
||||||
|
thr->errors++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
err = ioctl(fd, TCSETS, &ios);
|
err = ioctl(fd, TCSETS, &ios);
|
||||||
if (err != 0)
|
if (err != 0)
|
||||||
{
|
{
|
||||||
nvt_log(LOG_ERR, "ioctl(TCSETS) failed: %m\n");
|
nvt_log(LOG_ERR, "ioctl(TCSETS) failed: %m\n");
|
||||||
|
thr->errors++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
@@ -74,6 +102,7 @@ static void *_worker(void *arg)
|
|||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
nvt_log(LOG_ERR, "Open '%s' failed: %m\n", dev);
|
nvt_log(LOG_ERR, "Open '%s' failed: %m\n", dev);
|
||||||
|
thr->errors++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,18 +113,20 @@ static void *_worker(void *arg)
|
|||||||
if (nw < 0)
|
if (nw < 0)
|
||||||
{
|
{
|
||||||
nvt_log(LOG_ERR, "write failed: %m\n");
|
nvt_log(LOG_ERR, "write failed: %m\n");
|
||||||
|
thr->errors++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (nw < len)
|
if (nw < len)
|
||||||
{
|
{
|
||||||
nvt_log(LOG_ERR, "write short: %u/%u\n", nw, len);
|
nvt_log(LOG_ERR, "write short: %u/%u\n", nw, len);
|
||||||
|
thr->errors++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (topts->opt_rand_delay)
|
if (thr->opts.opt_rand_delay)
|
||||||
usleep(rand() & 0xfff);
|
usleep(rand() & 0xfff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,24 +135,28 @@ static void *_worker(void *arg)
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int err;
|
int err, errors;
|
||||||
int opt;
|
int opt;
|
||||||
int ithr, nthr;
|
int ithr, nthr;
|
||||||
topts_t topts = { }, *popts;
|
thr_t *threads, *thr;
|
||||||
pthread_t *ptids;
|
topts_t topts = { };
|
||||||
int debug, quiet;
|
int debug, quiet;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
debug = quiet = 0;
|
debug = quiet = 0;
|
||||||
nthr = 1;
|
nthr = 1;
|
||||||
topts.nloop = 1;
|
topts.nloop = 1;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "dn:qrt:")) != -1)
|
while ((opt = getopt(argc, argv, "D:dn:qrt:")) != -1)
|
||||||
{
|
{
|
||||||
switch (opt)
|
switch (opt)
|
||||||
{
|
{
|
||||||
default: /* '?' */
|
default: /* '?' */
|
||||||
fprintf(stderr, HELP);
|
_usage(1);
|
||||||
exit(EXIT_FAILURE);
|
break;
|
||||||
|
case 'D':
|
||||||
|
snprintf(dev, sizeof(dev), "/dev/%s", optarg);
|
||||||
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
debug += 1;
|
debug += 1;
|
||||||
break;
|
break;
|
||||||
@@ -140,22 +175,28 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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_level(quiet, debug);
|
||||||
nvt_log_dest(NVT_LOG_STDOUT);
|
nvt_log_dest(NVT_LOG_STDOUT);
|
||||||
|
|
||||||
topts.nthread = nthr;
|
topts.nthread = nthr;
|
||||||
|
|
||||||
ptids = malloc(nthr * sizeof(pthread_t));
|
threads = calloc(nthr, sizeof(thr_t));
|
||||||
|
|
||||||
for (ithr = 0; ithr < nthr; ithr++)
|
for (ithr = 0; ithr < nthr; ithr++)
|
||||||
{
|
{
|
||||||
nvt_log(LOG_INFO, "Create worker thread %d/%d\n", ithr + 1, nthr);
|
nvt_log(LOG_INFO, "Create worker thread %d/%d\n", ithr + 1, nthr);
|
||||||
|
|
||||||
popts = malloc(sizeof(topts_t));
|
thr = &threads[ithr];
|
||||||
*popts = topts;
|
thr->opts = topts;
|
||||||
popts->ithread = ithr + 1;
|
thr->opts.ithread = ithr + 1;
|
||||||
|
|
||||||
err = pthread_create(&ptids[ithr], NULL, _worker, popts);
|
err = pthread_create(&thr->thr, NULL, _worker, thr);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
nvt_log(LOG_ERR, "Failed to create thread %d/%d\n", ithr, nthr);
|
nvt_log(LOG_ERR, "Failed to create thread %d/%d\n", ithr, nthr);
|
||||||
@@ -163,13 +204,17 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errors = 0;
|
||||||
for (ithr = 0; ithr < nthr; ithr++)
|
for (ithr = 0; ithr < nthr; ithr++)
|
||||||
{
|
{
|
||||||
if (ptids[ithr] == 0)
|
thr = &threads[ithr];
|
||||||
|
if (thr->thr == 0)
|
||||||
break;
|
break;
|
||||||
pthread_join(ptids[ithr], NULL);
|
pthread_join(thr->thr, NULL);
|
||||||
nvt_log(LOG_INFO, "Joined worker thread %d/%d\n", ithr + 1, nthr);
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-13
@@ -7,6 +7,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "telnet.h"
|
#include "telnet.h"
|
||||||
#include "telnet_param.h"
|
#include "telnet_param.h"
|
||||||
@@ -38,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];
|
char buf[3];
|
||||||
|
|
||||||
@@ -67,7 +68,7 @@ static void _telnet_handle_req(tn_ctx_t * tcc, int cmd, int opt)
|
|||||||
tcc->srv_tx(tcc->cctx, buf, 3);
|
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)
|
if (opt == TNO_CPCO)
|
||||||
{
|
{
|
||||||
@@ -76,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;
|
unsigned char buf[128], *pu = buf;
|
||||||
const unsigned char *pv;
|
const unsigned char *pv;
|
||||||
@@ -106,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);
|
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)
|
unsigned char *pu, int nd)
|
||||||
{
|
{
|
||||||
switch (opt)
|
switch (opt)
|
||||||
@@ -120,7 +121,7 @@ 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, int *plen)
|
||||||
{
|
{
|
||||||
char *s, *p;
|
char *s, *p;
|
||||||
unsigned char *pu;
|
unsigned char *pu;
|
||||||
@@ -233,7 +234,7 @@ int telnet_rx(tn_ctx_t * tcc, char *buf, int *plen)
|
|||||||
return 0;
|
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;
|
const char *s, *p;
|
||||||
int rem, nd;
|
int rem, nd;
|
||||||
@@ -263,7 +264,7 @@ int telnet_tx(tn_ctx_t * tcc, const char *buf, int len)
|
|||||||
return 0;
|
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);;
|
time_t t = time(NULL);;
|
||||||
char buf[3];
|
char buf[3];
|
||||||
@@ -284,17 +285,17 @@ int telnet_open(tn_ctx_t * tcc, int mode)
|
|||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
res = tcc->srv_rx(tcc->cctx, 1000);
|
res = tcc->srv_rx(tcc->cctx, 1000);
|
||||||
if (res <= 0)
|
if (res < 0)
|
||||||
return -1;
|
return errno;
|
||||||
else if (tcc->mode_rfc2217)
|
else if (tcc->mode_rfc2217)
|
||||||
return 0;
|
return 0;
|
||||||
else if (t - time(NULL) > 2)
|
else if (time(NULL) - t > 10)
|
||||||
return -1;
|
return EPROTO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tn_ctx_t *telnet_ctx_init(void *cctx, srv_tx_f * ftx,
|
tn_ctx_t *telnet_ctx_init(void *cctx, srv_tx_f *ftx,
|
||||||
srv_rx_f * frx, srv_ms_f * fms)
|
srv_rx_f *frx, srv_ms_f *fms)
|
||||||
{
|
{
|
||||||
tn_ctx_t *tcc;
|
tn_ctx_t *tcc;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "telnet.h"
|
#include "telnet.h"
|
||||||
#include "telnet_param.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 char *pu, int nd)
|
||||||
{
|
{
|
||||||
unsigned int sub;
|
unsigned int sub;
|
||||||
@@ -32,7 +32,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)
|
if (!tcc->mode_rfc2217)
|
||||||
return;
|
return;
|
||||||
@@ -40,7 +40,7 @@ void telnet_rfc2217_cfg(tn_ctx_t * tcc, int cmd, const void *val, int nd)
|
|||||||
telnet_set_opt(tcc, TNO_CPCO, cmd, val, 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, unsigned int val)
|
||||||
{
|
{
|
||||||
unsigned char byte = val;
|
unsigned char byte = val;
|
||||||
|
|
||||||
|
|||||||
+29
-17
@@ -150,7 +150,7 @@ static void _fd_close(int fd)
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _notify(ttynvt_t * tty)
|
static void _notify(ttynvt_t *tty)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&tty->poll_lock);
|
pthread_mutex_lock(&tty->poll_lock);
|
||||||
if (tty->ph)
|
if (tty->ph)
|
||||||
@@ -162,7 +162,7 @@ static void _notify(ttynvt_t * tty)
|
|||||||
pthread_mutex_unlock(&tty->poll_lock);
|
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);
|
pthread_mutex_lock(&tty->poll_lock);
|
||||||
struct fuse_pollhandle *tmp_ph = tty->ph;
|
struct fuse_pollhandle *tmp_ph = tty->ph;
|
||||||
@@ -173,7 +173,7 @@ static void _update_notify(ttynvt_t * tty, struct fuse_pollhandle *ph)
|
|||||||
fuse_pollhandle_destroy(tmp_ph);
|
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 &&
|
if ((tty->tio.c_cflag & CLOCAL) == 0 &&
|
||||||
(tty->smcr_last & TIOCM_CD) != 0 && (tty->smcr & TIOCM_CD) == 0)
|
(tty->smcr_last & TIOCM_CD) != 0 && (tty->smcr & TIOCM_CD) == 0)
|
||||||
@@ -397,7 +397,7 @@ static ttynvt_t *_ttynvt_ctx_create(void)
|
|||||||
return tty;
|
return tty;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _ttynvt_ctx_destroy(ttynvt_t * tty)
|
static void _ttynvt_ctx_destroy(ttynvt_t *tty)
|
||||||
{
|
{
|
||||||
if (tty)
|
if (tty)
|
||||||
free(tty->tn);
|
free(tty->tn);
|
||||||
@@ -470,14 +470,14 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
|||||||
|
|
||||||
res =
|
res =
|
||||||
telnet_open(tty->tn, ttynvt_param.raw ? TN_MODE_RAW : TN_MODE_TELNET);
|
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;
|
goto open_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((res = pthread_mutex_init(&tty->tty_lock, NULL) < 0) ||
|
if ((res = pthread_mutex_init(&tty->tty_lock, NULL)) ||
|
||||||
(res = pthread_mutex_init(&tty->poll_lock, NULL) < 0) ||
|
(res = pthread_mutex_init(&tty->poll_lock, NULL)) ||
|
||||||
(res = pthread_create(&tty->ptid_poll, NULL, &_read_net, tty)))
|
(res = pthread_create(&tty->ptid_poll, NULL, &_read_net, tty)))
|
||||||
{
|
{
|
||||||
errno = res;
|
errno = res;
|
||||||
@@ -691,10 +691,12 @@ static unsigned int _tio_parity(const struct termios2 *tio)
|
|||||||
{
|
{
|
||||||
unsigned int par;
|
unsigned int par;
|
||||||
|
|
||||||
if ((tio->c_cflag & PARENB) && (tio->c_iflag & IGNPAR))
|
if (!(tio->c_cflag & PARENB))
|
||||||
|
{
|
||||||
par = 1;
|
par = 1;
|
||||||
|
}
|
||||||
#ifdef CMSPAR
|
#ifdef CMSPAR
|
||||||
else if ((tio->c_cflag & PARENB) && (tio->c_iflag & CMSPAR))
|
else if (tio->c_iflag & CMSPAR)
|
||||||
{
|
{
|
||||||
if (tio->c_cflag & PARODD)
|
if (tio->c_cflag & PARODD)
|
||||||
par = 4;
|
par = 4;
|
||||||
@@ -702,10 +704,14 @@ static unsigned int _tio_parity(const struct termios2 *tio)
|
|||||||
par = 5;
|
par = 5;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (tio->c_cflag & PARENB)
|
else if (tio->c_cflag & PARODD)
|
||||||
par = 3;
|
{
|
||||||
|
par = 2;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
par = 1;
|
{
|
||||||
|
par = 3;
|
||||||
|
}
|
||||||
|
|
||||||
return par;
|
return par;
|
||||||
}
|
}
|
||||||
@@ -818,8 +824,12 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
|||||||
goto do_tcset;
|
goto do_tcset;
|
||||||
do_tcset:
|
do_tcset:
|
||||||
/* BEWARE of termios/termios2 buf structure difference! */
|
/* BEWARE of termios/termios2 buf structure difference! */
|
||||||
|
|
||||||
|
if (baud != 0)
|
||||||
|
{
|
||||||
byte4 = htonl(baud);
|
byte4 = htonl(baud);
|
||||||
telnet_rfc2217_cfg(tty->tn, TNS_SET_BAUDRATE, &byte4, 4);
|
telnet_rfc2217_cfg(tty->tn, TNS_SET_BAUDRATE, &byte4, 4);
|
||||||
|
}
|
||||||
|
|
||||||
byte = _tio_csize(tio);
|
byte = _tio_csize(tio);
|
||||||
telnet_rfc2217_cfg(tty->tn, TNS_SET_DATASIZE, &byte, 1);
|
telnet_rfc2217_cfg(tty->tn, TNS_SET_DATASIZE, &byte, 1);
|
||||||
@@ -1108,13 +1118,13 @@ static void ttynvt_release(fuse_req_t req, struct fuse_file_info *info)
|
|||||||
pthread_mutex_destroy(&tty->tty_lock);
|
pthread_mutex_destroy(&tty->tty_lock);
|
||||||
pthread_mutex_destroy(&tty->poll_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_NET].fd);
|
||||||
_fd_close(tty->fds[FD_MASTER].fd);
|
_fd_close(tty->fds[FD_MASTER].fd);
|
||||||
_fd_close(tty->fds[FD_SLAVE].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)
|
if (tty->ph)
|
||||||
fuse_pollhandle_destroy(tty->ph);
|
fuse_pollhandle_destroy(tty->ph);
|
||||||
|
|
||||||
@@ -1172,7 +1182,9 @@ static void print_help(void)
|
|||||||
"\t-q\t\tBe quiet (suppress informational messages)\n"
|
"\t-q\t\tBe quiet (suppress informational messages)\n"
|
||||||
"\t-r\t\tDisable telnet processing\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 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
|
static int
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
+25
@@ -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 */
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
TEST(Misc, dummy)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(1, 1);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user