Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c80995256 | |||
| 299cfcabb5 | |||
| b47cb98a69 | |||
| cb6509861f | |||
| 2f0cea6f73 | |||
| 015da8a55e |
@@ -9,11 +9,3 @@ if BUILD_TESTTOOLS
|
||||
SUBDIRS += nvtsrv
|
||||
SUBDIRS += nvttest
|
||||
endif
|
||||
if BUILD_TEST
|
||||
SUBDIRS += test
|
||||
endif
|
||||
|
||||
.PHONY: $(SUBDIRS) test
|
||||
$(SUBDIRS) test:
|
||||
$(MAKE) -C $@
|
||||
test: $(SUBDIRS)
|
||||
|
||||
+2
-5
@@ -1,4 +1,4 @@
|
||||
AC_INIT([ttynvt],[0.17],[frj@thrane.eu])
|
||||
AC_INIT([ttynvt],[0.16],[frj@thrane.eu])
|
||||
AM_INIT_AUTOMAKE([foreign dist-xz])
|
||||
|
||||
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_PROG_CC
|
||||
AC_PROG_CXX
|
||||
|
||||
AC_PROG_INSTALL
|
||||
|
||||
define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
|
||||
define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
|
||||
define([AC_LIBTOOL_LANG_GCJ_CONFIG], [:])dnl
|
||||
|
||||
@@ -31,8 +31,6 @@ AC_ARG_ENABLE(testtools,
|
||||
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"
|
||||
@@ -46,7 +44,6 @@ lib/Makefile
|
||||
src/Makefile
|
||||
nvtsrv/Makefile
|
||||
nvttest/Makefile
|
||||
test/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
|
||||
+15
-83
@@ -7,7 +7,6 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include "nvt_log.h"
|
||||
#include "nvt_socket.h"
|
||||
@@ -19,109 +18,42 @@ typedef struct {
|
||||
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)
|
||||
static int _sa_host_lookup(sa_t * sa, const char *host)
|
||||
{
|
||||
struct addrinfo hint, *adrinf = NULL, *p;
|
||||
int ret = -1;
|
||||
struct hostent *server;
|
||||
|
||||
memset(&hint, 0, sizeof(struct addrinfo));
|
||||
|
||||
if (getaddrinfo(host, port, &hint, &adrinf) != 0)
|
||||
server = gethostbyname(host);
|
||||
if (server == NULL)
|
||||
{
|
||||
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;
|
||||
|
||||
sa->ipv4.sin_family = AF_INET;
|
||||
memcpy(&sa->ipv4.sin_addr.s_addr, server->h_addr, server->h_length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _sa_addr_parse(sa_t *sa, const char *addr)
|
||||
static int _sa_addr_parse(sa_t * sa, const char *addr)
|
||||
{
|
||||
ssize_t host_len;
|
||||
char host[64];
|
||||
const char *port;
|
||||
char host[64], port[64];
|
||||
|
||||
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;
|
||||
}
|
||||
sscanf(addr, "%63[^:]:%63s", host, port);
|
||||
|
||||
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)
|
||||
if (_sa_host_lookup(sa, host) != 0)
|
||||
return -1;
|
||||
|
||||
sa->type = SOCK_STREAM;
|
||||
sa->ipv4.sin_port = htons(atoi(port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -171,7 +103,7 @@ int socket_create_server(const char *addr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sa.gen.sa_family == AF_INET || sa.gen.sa_family == AF_INET6)
|
||||
if (sa.gen.sa_family == AF_INET)
|
||||
{
|
||||
/* Avoid TIME_WAIT state on socket close */
|
||||
opt = 1;
|
||||
|
||||
+11
-17
@@ -14,15 +14,9 @@
|
||||
#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**/
|
||||
#define HELP \
|
||||
"Usage: nvtsrv -deq\n"
|
||||
|
||||
|
||||
struct {
|
||||
unsigned char mline;
|
||||
@@ -36,10 +30,10 @@ int nfds;
|
||||
#define fd_cli pfds[2].fd
|
||||
|
||||
|
||||
static void _usage(int rc)
|
||||
static void _nvtsrv_usage(void)
|
||||
{
|
||||
printf(help_text);
|
||||
exit(rc);
|
||||
printf("Usage:\n" " nvtsrv host:port\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void _tn_cli_close(void)
|
||||
@@ -74,7 +68,7 @@ static void _tn_tx(void *cctx, const void *buf, int len)
|
||||
|
||||
static void _tn_ss(void *cctx, int signal, int value)
|
||||
{
|
||||
DBG("RFC2217 signal %d: %02x", signal, value);
|
||||
nvt_log(LOG_INFO, "RFC2217 signal %d: %02x", signal, value);
|
||||
}
|
||||
|
||||
static void _nvtsrv_init(void)
|
||||
@@ -86,7 +80,7 @@ static void _nvtsrv_init(void)
|
||||
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;
|
||||
|
||||
@@ -133,8 +127,8 @@ int main(int argc, char **argv)
|
||||
switch (opt)
|
||||
{
|
||||
default: /* '?' */
|
||||
_usage(0);
|
||||
break;
|
||||
fprintf(stderr, HELP);
|
||||
exit(EXIT_FAILURE);
|
||||
case 'd':
|
||||
debug += 1;
|
||||
break;
|
||||
@@ -150,7 +144,7 @@ int main(int argc, char **argv)
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (argc <= 0)
|
||||
_usage(1);
|
||||
_nvtsrv_usage();
|
||||
|
||||
nvt_log_level(quiet, debug);
|
||||
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];
|
||||
|
||||
@@ -63,7 +63,7 @@ static void _telnet_handle_req(tn_ctx_t *tcc, int cmd, int opt)
|
||||
telnet_rfc2217_init(tcc, TNI_ON);
|
||||
}
|
||||
|
||||
void telnet_reply_opt(tn_ctx_t *tcc, int opt, int prm,
|
||||
void telnet_reply_opt(tn_ctx_t * tcc, int opt, int prm,
|
||||
const void *val, int len)
|
||||
{
|
||||
unsigned char buf[128], *pu = buf;
|
||||
@@ -94,7 +94,7 @@ void telnet_reply_opt(tn_ctx_t *tcc, int opt, int prm,
|
||||
tcc->cli_tx(tcc->cctx, buf, len);
|
||||
}
|
||||
|
||||
static void _telnet_handle_opt(tn_ctx_t *tcc, int opt,
|
||||
static void _telnet_handle_opt(tn_ctx_t * tcc, int opt,
|
||||
unsigned char *pu, int nd)
|
||||
{
|
||||
DBG2_BUF("opti", pu, nd);
|
||||
@@ -111,7 +111,7 @@ 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;
|
||||
unsigned char *pu;
|
||||
@@ -230,7 +230,7 @@ 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;
|
||||
@@ -260,7 +260,7 @@ int telnet_tx(tn_ctx_t *tcc, const char *buf, int len)
|
||||
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;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "telnet.h"
|
||||
#include "telnet_param.h"
|
||||
|
||||
void telnet_rfc2217_init(tn_ctx_t *tcc, int when)
|
||||
void telnet_rfc2217_init(tn_ctx_t * tcc, int when)
|
||||
{
|
||||
switch (when)
|
||||
{
|
||||
@@ -39,7 +39,7 @@ void telnet_rfc2217_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 int sub, vali, valo, val4;
|
||||
@@ -138,7 +138,8 @@ void telnet_rfc2217_handle_opt(tn_ctx_t *tcc, int opt,
|
||||
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");
|
||||
nvt_log(LOG_INFO, "RFC2217: Set DTR %s",
|
||||
tcc->dtr_state ? "on" : "off");
|
||||
goto do_ctl_reply;
|
||||
|
||||
case 10: /* Request RTS Signal State */
|
||||
@@ -148,7 +149,8 @@ void telnet_rfc2217_handle_opt(tn_ctx_t *tcc, int opt,
|
||||
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");
|
||||
nvt_log(LOG_INFO, "RFC2217: Set RTS %s",
|
||||
tcc->rts_state ? "on" : "off");
|
||||
goto do_ctl_reply;
|
||||
|
||||
case 13: /* Request Com Port Flow Control Setting (inbound) */
|
||||
@@ -218,7 +220,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];
|
||||
|
||||
@@ -236,7 +238,7 @@ void telnet_rfc2217_change_linestate(tn_ctx_t *tcc, int 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];
|
||||
|
||||
|
||||
+1
-1
@@ -6,4 +6,4 @@ nvttest_SOURCES = \
|
||||
|
||||
nvttest_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) $(CFLAGS_WARN)
|
||||
|
||||
nvttest_LDADD = $(top_builddir)/lib/libnvt.la -lpthread
|
||||
nvttest_LDADD = $(top_builddir)/lib/libnvt.la
|
||||
|
||||
+22
-67
@@ -7,7 +7,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
@@ -17,20 +16,10 @@
|
||||
#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**/
|
||||
#define HELP \
|
||||
"Usage: nvttest -dqr [-n loops] [-t threads]\n"
|
||||
|
||||
static char dev[64] = "/dev/ttyNVT0";
|
||||
static const char *dev = "/dev/ttyNVT0";
|
||||
|
||||
typedef struct {
|
||||
int nthread;
|
||||
@@ -39,37 +28,22 @@ typedef struct {
|
||||
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;
|
||||
topts_t *topts = arg;
|
||||
int iloop;
|
||||
int fd, err, nw;
|
||||
struct termios ios;
|
||||
|
||||
for (iloop = 0; iloop < thr->opts.nloop; iloop++)
|
||||
for (iloop = 0; iloop < topts->nloop; iloop++)
|
||||
{
|
||||
nvt_log(LOG_INFO, "Thread %d/%d run %d/%d\n",
|
||||
thr->opts.ithread, thr->opts.nthread,
|
||||
iloop + 1, thr->opts.nloop);
|
||||
topts->ithread, topts->nthread, iloop + 1, topts->nloop);
|
||||
{
|
||||
fd = open(dev, O_RDWR);
|
||||
if (fd < 0)
|
||||
{
|
||||
nvt_log(LOG_ERR, "Open '%s' failed: %m\n", dev);
|
||||
thr->errors++;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -78,14 +52,12 @@ static void *_worker(void *arg)
|
||||
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);
|
||||
@@ -102,7 +74,6 @@ static void *_worker(void *arg)
|
||||
if (fd < 0)
|
||||
{
|
||||
nvt_log(LOG_ERR, "Open '%s' failed: %m\n", dev);
|
||||
thr->errors++;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -113,20 +84,18 @@ static void *_worker(void *arg)
|
||||
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)
|
||||
if (topts->opt_rand_delay)
|
||||
usleep(rand() & 0xfff);
|
||||
}
|
||||
|
||||
@@ -135,28 +104,24 @@ static void *_worker(void *arg)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int err, errors;
|
||||
int err;
|
||||
int opt;
|
||||
int ithr, nthr;
|
||||
thr_t *threads, *thr;
|
||||
topts_t topts = { };
|
||||
topts_t topts = { }, *popts;
|
||||
pthread_t *ptids;
|
||||
int debug, quiet;
|
||||
struct stat st;
|
||||
|
||||
debug = quiet = 0;
|
||||
nthr = 1;
|
||||
topts.nloop = 1;
|
||||
|
||||
while ((opt = getopt(argc, argv, "D:dn:qrt:")) != -1)
|
||||
while ((opt = getopt(argc, argv, "dn:qrt:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
default: /* '?' */
|
||||
_usage(1);
|
||||
break;
|
||||
case 'D':
|
||||
snprintf(dev, sizeof(dev), "/dev/%s", optarg);
|
||||
break;
|
||||
fprintf(stderr, HELP);
|
||||
exit(EXIT_FAILURE);
|
||||
case 'd':
|
||||
debug += 1;
|
||||
break;
|
||||
@@ -175,28 +140,22 @@ 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_dest(NVT_LOG_STDOUT);
|
||||
|
||||
topts.nthread = nthr;
|
||||
|
||||
threads = calloc(nthr, sizeof(thr_t));
|
||||
ptids = malloc(nthr * sizeof(pthread_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;
|
||||
popts = malloc(sizeof(topts_t));
|
||||
*popts = topts;
|
||||
popts->ithread = ithr + 1;
|
||||
|
||||
err = pthread_create(&thr->thr, NULL, _worker, thr);
|
||||
err = pthread_create(&ptids[ithr], NULL, _worker, popts);
|
||||
if (err)
|
||||
{
|
||||
nvt_log(LOG_ERR, "Failed to create thread %d/%d\n", ithr, nthr);
|
||||
@@ -204,17 +163,13 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
errors = 0;
|
||||
for (ithr = 0; ithr < nthr; ithr++)
|
||||
{
|
||||
thr = &threads[ithr];
|
||||
if (thr->thr == 0)
|
||||
if (ptids[ithr] == 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);
|
||||
pthread_join(ptids[ithr], NULL);
|
||||
nvt_log(LOG_INFO, "Joined worker thread %d/%d\n", ithr + 1, nthr);
|
||||
}
|
||||
|
||||
return errors ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+13
-14
@@ -7,7 +7,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "telnet.h"
|
||||
#include "telnet_param.h"
|
||||
@@ -39,7 +38,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 +67,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 +76,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 +106,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,7 +120,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;
|
||||
unsigned char *pu;
|
||||
@@ -234,7 +233,7 @@ 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;
|
||||
@@ -264,7 +263,7 @@ 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, int mode)
|
||||
{
|
||||
time_t t = time(NULL);;
|
||||
char buf[3];
|
||||
@@ -285,17 +284,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;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "telnet.h"
|
||||
#include "telnet_param.h"
|
||||
|
||||
void telnet_rfc2217_handle_opt(tn_ctx_t *tcc, int opt,
|
||||
void telnet_rfc2217_handle_opt(tn_ctx_t * tcc, int opt,
|
||||
unsigned char *pu, int nd)
|
||||
{
|
||||
unsigned int sub;
|
||||
@@ -32,7 +32,7 @@ void telnet_rfc2217_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,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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
+146
-71
@@ -55,14 +55,17 @@ static struct ttynvt_param {
|
||||
typedef struct {
|
||||
pthread_mutex_t tty_lock;
|
||||
pthread_mutex_t poll_lock;
|
||||
pthread_mutex_t read_lock;
|
||||
pthread_mutex_t write_lock;
|
||||
pthread_mutex_t ioctl_lock;
|
||||
pthread_t ptid_poll;
|
||||
pthread_t ptid_read;
|
||||
|
||||
struct fuse_pollhandle *ph;
|
||||
|
||||
volatile int rel_pending;
|
||||
volatile int slave_suspended; /*waiting for application to read data */
|
||||
volatile int master_suspended; /*server is not ready to receive data */
|
||||
volatile int slave_suspended; /* Waiting for application to read data */
|
||||
volatile int master_suspended; /* Server is not ready to receive data */
|
||||
struct pollfd fds[3];
|
||||
|
||||
char net_buf[NET_BUF_SIZE];
|
||||
@@ -80,8 +83,18 @@ typedef struct {
|
||||
int epipe;
|
||||
|
||||
tn_ctx_t *tn;
|
||||
|
||||
int seq;
|
||||
struct ttynvt_cli_s *cli;
|
||||
} ttynvt_t;
|
||||
|
||||
static ttynvt_t *ptty = NULL;
|
||||
|
||||
typedef struct ttynvt_cli_s {
|
||||
int id;
|
||||
ttynvt_t *tty;
|
||||
struct ttynvt_cli_s *next;
|
||||
} ttynvt_cli_t;
|
||||
|
||||
static pthread_mutex_t access_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
@@ -114,7 +127,6 @@ static void ttynvt_interrupted(fuse_req_t req, void *data)
|
||||
pthread_kill(thread, SIGUSR2);
|
||||
}
|
||||
|
||||
|
||||
static void _ttynvt_sleep_us(unsigned int tus)
|
||||
{
|
||||
struct timespec ts;
|
||||
@@ -143,14 +155,13 @@ static int _check_dev(void)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void _fd_close(int fd)
|
||||
{
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void _notify(ttynvt_t *tty)
|
||||
static void _notify(ttynvt_t * tty)
|
||||
{
|
||||
pthread_mutex_lock(&tty->poll_lock);
|
||||
if (tty->ph)
|
||||
@@ -162,7 +173,7 @@ static void _notify(ttynvt_t *tty)
|
||||
pthread_mutex_unlock(&tty->poll_lock);
|
||||
}
|
||||
|
||||
static void _update_notify(ttynvt_t *tty, struct fuse_pollhandle *ph)
|
||||
static void _update_notify(ttynvt_t * tty, struct fuse_pollhandle *ph)
|
||||
{
|
||||
pthread_mutex_lock(&tty->poll_lock);
|
||||
struct fuse_pollhandle *tmp_ph = tty->ph;
|
||||
@@ -173,7 +184,7 @@ static void _update_notify(ttynvt_t *tty, struct fuse_pollhandle *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 &&
|
||||
(tty->smcr_last & TIOCM_CD) != 0 && (tty->smcr & TIOCM_CD) == 0)
|
||||
@@ -397,7 +408,7 @@ static ttynvt_t *_ttynvt_ctx_create(void)
|
||||
return tty;
|
||||
}
|
||||
|
||||
static void _ttynvt_ctx_destroy(ttynvt_t *tty)
|
||||
static void _ttynvt_ctx_destroy(ttynvt_t * tty)
|
||||
{
|
||||
if (tty)
|
||||
free(tty->tn);
|
||||
@@ -406,24 +417,49 @@ static void _ttynvt_ctx_destroy(ttynvt_t *tty)
|
||||
|
||||
static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
||||
{
|
||||
ttynvt_t *tty;
|
||||
ttynvt_t *tty = ptty;
|
||||
ttynvt_cli_t *tty_cli;
|
||||
char *slave_name;
|
||||
struct termios ios;
|
||||
int fd;
|
||||
int res;
|
||||
int n;
|
||||
|
||||
pthread_mutex_lock(&access_lock);
|
||||
|
||||
nvt_log(LOG_INFO, "Connecting to server: %s\n", ttynvt_param.server);
|
||||
|
||||
tty = _ttynvt_ctx_create();
|
||||
if (!tty)
|
||||
tty_cli = calloc(1, sizeof(ttynvt_cli_t));
|
||||
if (!tty_cli)
|
||||
{
|
||||
fuse_reply_err(req, ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&access_lock);
|
||||
|
||||
if (tty == NULL)
|
||||
tty = _ttynvt_ctx_create();
|
||||
if (!tty)
|
||||
{
|
||||
fuse_reply_err(req, ENOMEM);
|
||||
free(tty_cli);
|
||||
pthread_mutex_unlock(&access_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
tty_cli->id = tty->seq++;
|
||||
tty_cli->tty = tty;
|
||||
tty_cli->next = tty->cli;
|
||||
|
||||
tty->cli = tty_cli;
|
||||
|
||||
nvt_log(LOG_INFO, "Client open (%d)\n", tty_cli->id);
|
||||
|
||||
if (ptty)
|
||||
goto out;
|
||||
|
||||
ptty = tty;
|
||||
|
||||
nvt_log(LOG_INFO, "Connecting to server: %s\n", ttynvt_param.server);
|
||||
|
||||
fd = socket_create_client(ttynvt_param.server);
|
||||
if (fd < 0)
|
||||
{
|
||||
@@ -435,7 +471,7 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
||||
tty->fds[FD_NET].events = POLLIN;
|
||||
tty->net_cnt = 0;
|
||||
|
||||
if ((fd = open("/dev/ptmx", O_RDWR)) < 0) /* open master */
|
||||
if ((fd = open("/dev/ptmx", O_RDWR)) < 0) /* Open master */
|
||||
goto open_err;
|
||||
|
||||
tty->fds[FD_MASTER].fd = fd;
|
||||
@@ -453,11 +489,11 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
||||
if (ioctl(fd, TCSETS, &ios) < 0)
|
||||
goto open_err;
|
||||
|
||||
grantpt(fd); /* change permission of slave */
|
||||
unlockpt(fd); /* unlock slave */
|
||||
slave_name = ptsname(fd); /* get name of slave */
|
||||
grantpt(fd); /* Change permission of slave */
|
||||
unlockpt(fd); /* Unlock slave */
|
||||
slave_name = ptsname(fd); /* Get name of slave */
|
||||
|
||||
if ((fd = open(slave_name, O_RDWR | O_NOCTTY)) < 0) /* open slave */
|
||||
if ((fd = open(slave_name, O_RDWR | O_NOCTTY)) < 0) /* Open slave */
|
||||
goto open_err;
|
||||
|
||||
ioctl(fd, TCGETS, &tty->tio);
|
||||
@@ -470,34 +506,42 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
||||
|
||||
res =
|
||||
telnet_open(tty->tn, ttynvt_param.raw ? TN_MODE_RAW : TN_MODE_TELNET);
|
||||
if (res != 0)
|
||||
if (res < 0)
|
||||
{
|
||||
errno = res;
|
||||
errno = EPROTO;
|
||||
goto open_err;
|
||||
}
|
||||
|
||||
if ((res = pthread_mutex_init(&tty->tty_lock, NULL)) ||
|
||||
(res = pthread_mutex_init(&tty->poll_lock, NULL)) ||
|
||||
if ((res = pthread_mutex_init(&tty->tty_lock, NULL) < 0) ||
|
||||
(res = pthread_mutex_init(&tty->poll_lock, NULL) < 0) ||
|
||||
(res = pthread_mutex_init(&tty->ioctl_lock, NULL) < 0) ||
|
||||
(res = pthread_mutex_init(&tty->read_lock, NULL) < 0) ||
|
||||
(res = pthread_mutex_init(&tty->write_lock, NULL) < 0) ||
|
||||
(res = pthread_create(&tty->ptid_poll, NULL, &_read_net, tty)))
|
||||
{
|
||||
errno = res;
|
||||
goto open_err;
|
||||
}
|
||||
|
||||
info->fh = (uintptr_t) tty;
|
||||
nvt_log(LOG_INFO, "Connected to server: %s\n", ttynvt_param.server);
|
||||
|
||||
out:
|
||||
info->fh = (uintptr_t) tty_cli;
|
||||
info->nonseekable = 1;
|
||||
info->direct_io = 1;
|
||||
|
||||
nvt_log(LOG_INFO, "Connected to server: %s\n", ttynvt_param.server);
|
||||
|
||||
fuse_reply_open(req, info);
|
||||
|
||||
pthread_mutex_unlock(&access_lock);
|
||||
return;
|
||||
|
||||
open_err:
|
||||
for (n = 0; n < 3; n++)
|
||||
_fd_close(tty->fds[n].fd);
|
||||
|
||||
free(tty_cli);
|
||||
_ttynvt_ctx_destroy(tty);
|
||||
ptty = NULL;
|
||||
|
||||
fuse_reply_err(req, errno);
|
||||
|
||||
@@ -511,11 +555,14 @@ static void
|
||||
ttynvt_read(fuse_req_t req, size_t size, off_t off,
|
||||
struct fuse_file_info *info)
|
||||
{
|
||||
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||
ttynvt_cli_t *tty_cli = (ttynvt_cli_t *) (uintptr_t) info->fh;
|
||||
ttynvt_t *tty = tty_cli->tty;
|
||||
char buf[TMP_BUF_SIZE];
|
||||
int res, nr;
|
||||
|
||||
DBG2("%s\n", __func__);
|
||||
pthread_mutex_lock(&tty->read_lock);
|
||||
|
||||
DBG2("%s (%d)\n", __func__, tty_cli->id);
|
||||
|
||||
if (tty->error)
|
||||
{
|
||||
@@ -529,7 +576,7 @@ ttynvt_read(fuse_req_t req, size_t size, off_t off,
|
||||
else
|
||||
fuse_reply_err(req, EBADFD);
|
||||
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (size > TMP_BUF_SIZE)
|
||||
@@ -556,36 +603,42 @@ ttynvt_read(fuse_req_t req, size_t size, off_t off,
|
||||
{
|
||||
DBG2("%s: error: %m\n", __func__);
|
||||
fuse_reply_err(req, errno);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
DBG2("%s: fd=%d: sz=%u/%u: '%.*s'\n", __func__,
|
||||
tty->fds[FD_SLAVE].fd, res, (int)size, res, buf);
|
||||
DBG2("%s (%d): fd=%d: sz=%u/%u: '%.*s'\n", __func__,
|
||||
tty_cli->id, tty->fds[FD_SLAVE].fd, res, (int)size, res, buf);
|
||||
|
||||
fuse_reply_buf(req, buf, res);
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&tty->read_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
|
||||
struct fuse_file_info *info)
|
||||
{
|
||||
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||
ttynvt_cli_t *tty_cli = (ttynvt_cli_t *) (uintptr_t) info->fh;
|
||||
ttynvt_t *tty = tty_cli->tty;
|
||||
int res;
|
||||
|
||||
DBG2("%s: fd=%d: sz=%u: '%.*s'\n", __func__,
|
||||
tty->fds[FD_SLAVE].fd, (int)size, (int)size, data);
|
||||
pthread_mutex_lock(&tty->write_lock);
|
||||
|
||||
DBG2("%s (%d): fd=%d: sz=%u: '%.*s'\n", __func__,
|
||||
tty_cli->id, tty->fds[FD_SLAVE].fd, (int)size, (int)size, data);
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
fuse_reply_write(req, 0);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tty->error)
|
||||
{
|
||||
DBG2("%s: tty->error=%d\n", __func__, tty->error);
|
||||
fuse_reply_err(req, EPIPE);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = write(tty->fds[FD_SLAVE].fd, data, size);
|
||||
@@ -594,7 +647,7 @@ ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
|
||||
DBG2("%s: error: %m\n", __func__);
|
||||
tty->error = 1;
|
||||
fuse_reply_err(req, errno);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
else if (res != (int)size)
|
||||
{
|
||||
@@ -603,6 +656,9 @@ ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
|
||||
}
|
||||
|
||||
fuse_reply_write(req, res);
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&tty->write_lock);
|
||||
}
|
||||
|
||||
static int baudrate(speed_t speed)
|
||||
@@ -691,12 +747,10 @@ static unsigned int _tio_parity(const struct termios2 *tio)
|
||||
{
|
||||
unsigned int par;
|
||||
|
||||
if (!(tio->c_cflag & PARENB))
|
||||
{
|
||||
if ((tio->c_cflag & PARENB) && (tio->c_iflag & IGNPAR))
|
||||
par = 1;
|
||||
}
|
||||
#ifdef CMSPAR
|
||||
else if (tio->c_iflag & CMSPAR)
|
||||
else if ((tio->c_cflag & PARENB) && (tio->c_iflag & CMSPAR))
|
||||
{
|
||||
if (tio->c_cflag & PARODD)
|
||||
par = 4;
|
||||
@@ -704,14 +758,10 @@ static unsigned int _tio_parity(const struct termios2 *tio)
|
||||
par = 5;
|
||||
}
|
||||
#endif
|
||||
else if (tio->c_cflag & PARODD)
|
||||
{
|
||||
par = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
else if (tio->c_cflag & PARENB)
|
||||
par = 3;
|
||||
}
|
||||
else
|
||||
par = 1;
|
||||
|
||||
return par;
|
||||
}
|
||||
@@ -786,7 +836,8 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
||||
struct fuse_file_info *info, unsigned int flags,
|
||||
const void *in_buf, size_t in_bufsz, size_t out_bufsz)
|
||||
{
|
||||
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||
ttynvt_cli_t *tty_cli = (ttynvt_cli_t *) (uintptr_t) info->fh;
|
||||
ttynvt_t *tty = tty_cli->tty;
|
||||
struct termios2 *tio = &tty->tio;
|
||||
struct winsize ws;
|
||||
unsigned int tiocm, baud;
|
||||
@@ -796,14 +847,16 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
||||
uint8_t byte;
|
||||
uint32_t byte4;
|
||||
|
||||
DBG("%s: cmd=%s arg=%p ibuf=%p:%u obuf=:%u\n", __func__,
|
||||
_ioctl_name(cmd), arg, in_buf,
|
||||
pthread_mutex_lock(&tty->ioctl_lock);
|
||||
|
||||
DBG("%s (%d): cmd=%s arg=%p ibuf=%p:%u obuf=:%u\n", __func__,
|
||||
tty_cli->id, _ioctl_name(cmd), arg, in_buf,
|
||||
(unsigned int)in_bufsz, (unsigned int)out_bufsz);
|
||||
|
||||
if (ttynvt_param.raw)
|
||||
{
|
||||
fuse_reply_ioctl(req, 0, 0, 0);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (cmd)
|
||||
@@ -824,12 +877,8 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
||||
goto do_tcset;
|
||||
do_tcset:
|
||||
/* BEWARE of termios/termios2 buf structure difference! */
|
||||
|
||||
if (baud != 0)
|
||||
{
|
||||
byte4 = htonl(baud);
|
||||
telnet_rfc2217_cfg(tty->tn, TNS_SET_BAUDRATE, &byte4, 4);
|
||||
}
|
||||
|
||||
byte = _tio_csize(tio);
|
||||
telnet_rfc2217_cfg(tty->tn, TNS_SET_DATASIZE, &byte, 1);
|
||||
@@ -998,7 +1047,7 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
||||
if (res < 0)
|
||||
{
|
||||
fuse_reply_err(req, errno);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
fuse_reply_ioctl(req, 0, &ws, sizeof(struct winsize));
|
||||
break;
|
||||
@@ -1009,7 +1058,7 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
||||
if (res < 0)
|
||||
{
|
||||
fuse_reply_err(req, errno);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
fuse_reply_ioctl(req, 0, &ws, sizeof(struct winsize));
|
||||
break;
|
||||
@@ -1070,17 +1119,21 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&tty->ioctl_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
ttynvt_poll(fuse_req_t req, struct fuse_file_info *info,
|
||||
struct fuse_pollhandle *ph)
|
||||
{
|
||||
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||
ttynvt_cli_t *tty_cli = (ttynvt_cli_t *) (uintptr_t) info->fh;
|
||||
ttynvt_t *tty = tty_cli->tty;
|
||||
int revents = 0;
|
||||
|
||||
DBG2("%s: tty->pollin=%d tty->error/epipe=%d/%d\n",
|
||||
__func__, tty->pollin, tty->error, tty->epipe);
|
||||
DBG2("%s (%d): tty->pollin=%d tty->error/epipe=%d/%d\n",
|
||||
__func__, tty_cli->id, tty->pollin, tty->error, tty->epipe);
|
||||
|
||||
_update_notify(tty, ph);
|
||||
|
||||
@@ -1107,33 +1160,57 @@ ttynvt_poll(fuse_req_t req, struct fuse_file_info *info,
|
||||
|
||||
static void ttynvt_release(fuse_req_t req, struct fuse_file_info *info)
|
||||
{
|
||||
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||
ttynvt_cli_t *tty_cli = (ttynvt_cli_t *) (uintptr_t) info->fh;
|
||||
ttynvt_t *tty = tty_cli->tty;
|
||||
ttynvt_cli_t *tmp, *prev;
|
||||
|
||||
DBG("%s\n", __func__);
|
||||
|
||||
pthread_mutex_lock(&access_lock);
|
||||
|
||||
for (tmp = tty->cli, prev = NULL; tmp; prev = tmp, tmp = tmp->next)
|
||||
if (tmp == tty_cli)
|
||||
{
|
||||
nvt_log(LOG_INFO, "Client release (%d)\n", tmp->id);
|
||||
if (prev)
|
||||
prev->next = tmp->next;
|
||||
else
|
||||
tty->cli = tmp->next;
|
||||
free(tmp);
|
||||
break;
|
||||
}
|
||||
|
||||
if (tty->cli)
|
||||
goto out;
|
||||
|
||||
tty->rel_pending = 1;
|
||||
|
||||
pthread_cancel(tty->ptid_poll);
|
||||
pthread_join(tty->ptid_poll, NULL);
|
||||
pthread_mutex_destroy(&tty->tty_lock);
|
||||
pthread_mutex_destroy(&tty->poll_lock);
|
||||
pthread_mutex_destroy(&tty->ioctl_lock);
|
||||
pthread_mutex_destroy(&tty->read_lock);
|
||||
pthread_mutex_destroy(&tty->write_lock);
|
||||
|
||||
if (ttynvt_param.close_delay_us)
|
||||
_ttynvt_sleep_us(ttynvt_param.close_delay_us);
|
||||
|
||||
_fd_close(tty->fds[FD_NET].fd);
|
||||
_fd_close(tty->fds[FD_MASTER].fd);
|
||||
_fd_close(tty->fds[FD_SLAVE].fd);
|
||||
|
||||
if (ttynvt_param.close_delay_us)
|
||||
_ttynvt_sleep_us(ttynvt_param.close_delay_us);
|
||||
|
||||
if (tty->ph)
|
||||
fuse_pollhandle_destroy(tty->ph);
|
||||
|
||||
_ttynvt_ctx_destroy(tty);
|
||||
|
||||
fuse_reply_err(req, 0);
|
||||
ptty = NULL;
|
||||
|
||||
nvt_log(LOG_INFO, "Disconnected from server: %s\n", ttynvt_param.server);
|
||||
|
||||
out:
|
||||
fuse_reply_err(req, 0);
|
||||
|
||||
pthread_mutex_unlock(&access_lock);
|
||||
}
|
||||
|
||||
@@ -1182,9 +1259,7 @@ static void print_help(void)
|
||||
"\t-q\t\tBe quiet (suppress informational messages)\n"
|
||||
"\t-r\t\tDisable telnet processing\n"
|
||||
"\t-s delay \t\tDelay at close in ms (use u suffix for us)\n"
|
||||
"\t-S server, --server=host:port\n"
|
||||
"\t\t\t[ipv6addr]:port (connect via IPv6)\n"
|
||||
"\t\t\tunix:/path/to.socket (connect via UNIX domain socket)\n");
|
||||
"\t-S server, --server=host:port\n");
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -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)
|
||||
@@ -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
@@ -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 */
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "test.h"
|
||||
|
||||
TEST(Misc, dummy)
|
||||
{
|
||||
EXPECT_EQ(1, 1);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user