Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c80995256 | |||
| 299cfcabb5 | |||
| b47cb98a69 | |||
| cb6509861f | |||
| 2f0cea6f73 | |||
| 015da8a55e |
@@ -9,11 +9,3 @@ 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)
|
|
||||||
|
|||||||
+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])
|
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,8 +31,6 @@ 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"
|
||||||
@@ -46,7 +44,6 @@ lib/Makefile
|
|||||||
src/Makefile
|
src/Makefile
|
||||||
nvtsrv/Makefile
|
nvtsrv/Makefile
|
||||||
nvttest/Makefile
|
nvttest/Makefile
|
||||||
test/Makefile
|
|
||||||
])
|
])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
|
|||||||
+15
-83
@@ -7,7 +7,6 @@
|
|||||||
#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"
|
||||||
@@ -19,109 +18,42 @@ 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, const char *port)
|
static int _sa_host_lookup(sa_t * sa, const char *host)
|
||||||
{
|
{
|
||||||
struct addrinfo hint, *adrinf = NULL, *p;
|
struct hostent *server;
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
memset(&hint, 0, sizeof(struct addrinfo));
|
server = gethostbyname(host);
|
||||||
|
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));
|
|
||||||
ret = 0;
|
sa->ipv4.sin_family = AF_INET;
|
||||||
goto exit_host_lookup;
|
memcpy(&sa->ipv4.sin_addr.s_addr, server->h_addr, server->h_length);
|
||||||
}
|
|
||||||
}
|
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)
|
||||||
{
|
{
|
||||||
ssize_t host_len;
|
char host[64], port[64];
|
||||||
char host[64];
|
|
||||||
const char *port;
|
|
||||||
|
|
||||||
memset(sa, 0, sizeof(sa_t));
|
memset(sa, 0, sizeof(sa_t));
|
||||||
|
|
||||||
if (strncmp(addr, "unix:", 5) == 0)
|
sscanf(addr, "%63[^:]:%63s", host, port);
|
||||||
{ // 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, ':')))
|
if (_sa_host_lookup(sa, host) != 0)
|
||||||
{
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -171,7 +103,7 @@ int socket_create_server(const char *addr)
|
|||||||
return -1;
|
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 */
|
/* Avoid TIME_WAIT state on socket close */
|
||||||
opt = 1;
|
opt = 1;
|
||||||
|
|||||||
+11
-17
@@ -14,15 +14,9 @@
|
|||||||
#include "telnet.h"
|
#include "telnet.h"
|
||||||
|
|
||||||
|
|
||||||
/**INDENT-OFF**/
|
#define HELP \
|
||||||
static const char help_text[] =
|
"Usage: nvtsrv -deq\n"
|
||||||
"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;
|
||||||
@@ -36,10 +30,10 @@ int nfds;
|
|||||||
#define fd_cli pfds[2].fd
|
#define fd_cli pfds[2].fd
|
||||||
|
|
||||||
|
|
||||||
static void _usage(int rc)
|
static void _nvtsrv_usage(void)
|
||||||
{
|
{
|
||||||
printf(help_text);
|
printf("Usage:\n" " nvtsrv host:port\n");
|
||||||
exit(rc);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tn_cli_close(void)
|
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)
|
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)
|
static void _nvtsrv_init(void)
|
||||||
@@ -86,7 +80,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;
|
||||||
|
|
||||||
@@ -133,8 +127,8 @@ int main(int argc, char **argv)
|
|||||||
switch (opt)
|
switch (opt)
|
||||||
{
|
{
|
||||||
default: /* '?' */
|
default: /* '?' */
|
||||||
_usage(0);
|
fprintf(stderr, HELP);
|
||||||
break;
|
exit(EXIT_FAILURE);
|
||||||
case 'd':
|
case 'd':
|
||||||
debug += 1;
|
debug += 1;
|
||||||
break;
|
break;
|
||||||
@@ -150,7 +144,7 @@ int main(int argc, char **argv)
|
|||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
if (argc <= 0)
|
if (argc <= 0)
|
||||||
_usage(1);
|
_nvtsrv_usage();
|
||||||
|
|
||||||
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,7 +138,8 @@ 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;
|
||||||
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;
|
goto do_ctl_reply;
|
||||||
|
|
||||||
case 10: /* Request RTS Signal State */
|
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 */
|
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;
|
||||||
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;
|
goto do_ctl_reply;
|
||||||
|
|
||||||
case 13: /* Request Com Port Flow Control Setting (inbound) */
|
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];
|
unsigned char buf[1];
|
||||||
|
|
||||||
@@ -236,7 +238,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 -lpthread
|
nvttest_LDADD = $(top_builddir)/lib/libnvt.la
|
||||||
|
|||||||
+22
-67
@@ -7,7 +7,6 @@
|
|||||||
#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>
|
||||||
|
|
||||||
@@ -17,20 +16,10 @@
|
|||||||
#include "lib/nvt_log.h"
|
#include "lib/nvt_log.h"
|
||||||
|
|
||||||
|
|
||||||
/**INDENT-OFF**/
|
#define HELP \
|
||||||
static const char help_text[] =
|
"Usage: nvttest -dqr [-n loops] [-t threads]\n"
|
||||||
"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";
|
static const char *dev = "/dev/ttyNVT0";
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int nthread;
|
int nthread;
|
||||||
@@ -39,37 +28,22 @@ 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)
|
||||||
{
|
{
|
||||||
thr_t *thr = arg;
|
topts_t *topts = arg;
|
||||||
int iloop;
|
int iloop;
|
||||||
int fd, err, nw;
|
int fd, err, nw;
|
||||||
struct termios ios;
|
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",
|
nvt_log(LOG_INFO, "Thread %d/%d run %d/%d\n",
|
||||||
thr->opts.ithread, thr->opts.nthread,
|
topts->ithread, topts->nthread, iloop + 1, topts->nloop);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,14 +52,12 @@ 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);
|
||||||
@@ -102,7 +74,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,20 +84,18 @@ 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 (thr->opts.opt_rand_delay)
|
if (topts->opt_rand_delay)
|
||||||
usleep(rand() & 0xfff);
|
usleep(rand() & 0xfff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,28 +104,24 @@ static void *_worker(void *arg)
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int err, errors;
|
int err;
|
||||||
int opt;
|
int opt;
|
||||||
int ithr, nthr;
|
int ithr, nthr;
|
||||||
thr_t *threads, *thr;
|
topts_t topts = { }, *popts;
|
||||||
topts_t topts = { };
|
pthread_t *ptids;
|
||||||
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, "D:dn:qrt:")) != -1)
|
while ((opt = getopt(argc, argv, "dn:qrt:")) != -1)
|
||||||
{
|
{
|
||||||
switch (opt)
|
switch (opt)
|
||||||
{
|
{
|
||||||
default: /* '?' */
|
default: /* '?' */
|
||||||
_usage(1);
|
fprintf(stderr, HELP);
|
||||||
break;
|
exit(EXIT_FAILURE);
|
||||||
case 'D':
|
|
||||||
snprintf(dev, sizeof(dev), "/dev/%s", optarg);
|
|
||||||
break;
|
|
||||||
case 'd':
|
case 'd':
|
||||||
debug += 1;
|
debug += 1;
|
||||||
break;
|
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_level(quiet, debug);
|
||||||
nvt_log_dest(NVT_LOG_STDOUT);
|
nvt_log_dest(NVT_LOG_STDOUT);
|
||||||
|
|
||||||
topts.nthread = nthr;
|
topts.nthread = nthr;
|
||||||
|
|
||||||
threads = calloc(nthr, sizeof(thr_t));
|
ptids = malloc(nthr * sizeof(pthread_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);
|
||||||
|
|
||||||
thr = &threads[ithr];
|
popts = malloc(sizeof(topts_t));
|
||||||
thr->opts = topts;
|
*popts = topts;
|
||||||
thr->opts.ithread = ithr + 1;
|
popts->ithread = ithr + 1;
|
||||||
|
|
||||||
err = pthread_create(&thr->thr, NULL, _worker, thr);
|
err = pthread_create(&ptids[ithr], NULL, _worker, popts);
|
||||||
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);
|
||||||
@@ -204,17 +163,13 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errors = 0;
|
|
||||||
for (ithr = 0; ithr < nthr; ithr++)
|
for (ithr = 0; ithr < nthr; ithr++)
|
||||||
{
|
{
|
||||||
thr = &threads[ithr];
|
if (ptids[ithr] == 0)
|
||||||
if (thr->thr == 0)
|
|
||||||
break;
|
break;
|
||||||
pthread_join(thr->thr, NULL);
|
pthread_join(ptids[ithr], NULL);
|
||||||
errors += thr->errors;
|
nvt_log(LOG_INFO, "Joined worker thread %d/%d\n", ithr + 1, nthr);
|
||||||
nvt_log(LOG_INFO, "Joined worker thread %d/%d (err=%d)\n",
|
|
||||||
ithr + 1, nthr, thr->errors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors ? 1 : 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-14
@@ -7,7 +7,6 @@
|
|||||||
#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"
|
||||||
@@ -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];
|
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);
|
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)
|
||||||
{
|
{
|
||||||
@@ -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;
|
unsigned char buf[128], *pu = buf;
|
||||||
const unsigned char *pv;
|
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);
|
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)
|
||||||
@@ -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;
|
char *s, *p;
|
||||||
unsigned char *pu;
|
unsigned char *pu;
|
||||||
@@ -234,7 +233,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;
|
||||||
@@ -264,7 +263,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];
|
||||||
@@ -285,17 +284,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 errno;
|
return -1;
|
||||||
else if (tcc->mode_rfc2217)
|
else if (tcc->mode_rfc2217)
|
||||||
return 0;
|
return 0;
|
||||||
else if (time(NULL) - t > 10)
|
else if (t - time(NULL) > 2)
|
||||||
return EPROTO;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
|||||||
+146
-71
@@ -55,14 +55,17 @@ static struct ttynvt_param {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
pthread_mutex_t tty_lock;
|
pthread_mutex_t tty_lock;
|
||||||
pthread_mutex_t poll_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_poll;
|
||||||
pthread_t ptid_read;
|
pthread_t ptid_read;
|
||||||
|
|
||||||
struct fuse_pollhandle *ph;
|
struct fuse_pollhandle *ph;
|
||||||
|
|
||||||
volatile int rel_pending;
|
volatile int rel_pending;
|
||||||
volatile int slave_suspended; /*waiting for application to read data */
|
volatile int slave_suspended; /* Waiting for application to read data */
|
||||||
volatile int master_suspended; /*server is not ready to receive data */
|
volatile int master_suspended; /* Server is not ready to receive data */
|
||||||
struct pollfd fds[3];
|
struct pollfd fds[3];
|
||||||
|
|
||||||
char net_buf[NET_BUF_SIZE];
|
char net_buf[NET_BUF_SIZE];
|
||||||
@@ -80,8 +83,18 @@ typedef struct {
|
|||||||
int epipe;
|
int epipe;
|
||||||
|
|
||||||
tn_ctx_t *tn;
|
tn_ctx_t *tn;
|
||||||
|
|
||||||
|
int seq;
|
||||||
|
struct ttynvt_cli_s *cli;
|
||||||
} ttynvt_t;
|
} 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;
|
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);
|
pthread_kill(thread, SIGUSR2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _ttynvt_sleep_us(unsigned int tus)
|
static void _ttynvt_sleep_us(unsigned int tus)
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
@@ -143,14 +155,13 @@ static int _check_dev(void)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _fd_close(int fd)
|
static void _fd_close(int fd)
|
||||||
{
|
{
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
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 +173,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 +184,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 +408,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);
|
||||||
@@ -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)
|
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;
|
char *slave_name;
|
||||||
struct termios ios;
|
struct termios ios;
|
||||||
int fd;
|
int fd;
|
||||||
int res;
|
int res;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
pthread_mutex_lock(&access_lock);
|
|
||||||
|
|
||||||
nvt_log(LOG_INFO, "Connecting to server: %s\n", ttynvt_param.server);
|
tty_cli = calloc(1, sizeof(ttynvt_cli_t));
|
||||||
|
if (!tty_cli)
|
||||||
tty = _ttynvt_ctx_create();
|
|
||||||
if (!tty)
|
|
||||||
{
|
{
|
||||||
fuse_reply_err(req, ENOMEM);
|
fuse_reply_err(req, ENOMEM);
|
||||||
return;
|
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);
|
fd = socket_create_client(ttynvt_param.server);
|
||||||
if (fd < 0)
|
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->fds[FD_NET].events = POLLIN;
|
||||||
tty->net_cnt = 0;
|
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;
|
goto open_err;
|
||||||
|
|
||||||
tty->fds[FD_MASTER].fd = fd;
|
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)
|
if (ioctl(fd, TCSETS, &ios) < 0)
|
||||||
goto open_err;
|
goto open_err;
|
||||||
|
|
||||||
grantpt(fd); /* change permission of slave */
|
grantpt(fd); /* Change permission of slave */
|
||||||
unlockpt(fd); /* unlock slave */
|
unlockpt(fd); /* Unlock slave */
|
||||||
slave_name = ptsname(fd); /* get name of 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;
|
goto open_err;
|
||||||
|
|
||||||
ioctl(fd, TCGETS, &tty->tio);
|
ioctl(fd, TCGETS, &tty->tio);
|
||||||
@@ -470,34 +506,42 @@ 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 = res;
|
errno = EPROTO;
|
||||||
goto open_err;
|
goto open_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((res = pthread_mutex_init(&tty->tty_lock, NULL)) ||
|
if ((res = pthread_mutex_init(&tty->tty_lock, NULL) < 0) ||
|
||||||
(res = pthread_mutex_init(&tty->poll_lock, NULL)) ||
|
(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)))
|
(res = pthread_create(&tty->ptid_poll, NULL, &_read_net, tty)))
|
||||||
{
|
{
|
||||||
errno = res;
|
errno = res;
|
||||||
goto open_err;
|
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->nonseekable = 1;
|
||||||
info->direct_io = 1;
|
info->direct_io = 1;
|
||||||
|
|
||||||
nvt_log(LOG_INFO, "Connected to server: %s\n", ttynvt_param.server);
|
|
||||||
|
|
||||||
fuse_reply_open(req, info);
|
fuse_reply_open(req, info);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&access_lock);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
open_err:
|
open_err:
|
||||||
for (n = 0; n < 3; n++)
|
for (n = 0; n < 3; n++)
|
||||||
_fd_close(tty->fds[n].fd);
|
_fd_close(tty->fds[n].fd);
|
||||||
|
|
||||||
|
free(tty_cli);
|
||||||
_ttynvt_ctx_destroy(tty);
|
_ttynvt_ctx_destroy(tty);
|
||||||
|
ptty = NULL;
|
||||||
|
|
||||||
fuse_reply_err(req, errno);
|
fuse_reply_err(req, errno);
|
||||||
|
|
||||||
@@ -511,11 +555,14 @@ static void
|
|||||||
ttynvt_read(fuse_req_t req, size_t size, off_t off,
|
ttynvt_read(fuse_req_t req, size_t size, off_t off,
|
||||||
struct fuse_file_info *info)
|
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];
|
char buf[TMP_BUF_SIZE];
|
||||||
int res, nr;
|
int res, nr;
|
||||||
|
|
||||||
DBG2("%s\n", __func__);
|
pthread_mutex_lock(&tty->read_lock);
|
||||||
|
|
||||||
|
DBG2("%s (%d)\n", __func__, tty_cli->id);
|
||||||
|
|
||||||
if (tty->error)
|
if (tty->error)
|
||||||
{
|
{
|
||||||
@@ -529,7 +576,7 @@ ttynvt_read(fuse_req_t req, size_t size, off_t off,
|
|||||||
else
|
else
|
||||||
fuse_reply_err(req, EBADFD);
|
fuse_reply_err(req, EBADFD);
|
||||||
|
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size > TMP_BUF_SIZE)
|
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__);
|
DBG2("%s: error: %m\n", __func__);
|
||||||
fuse_reply_err(req, errno);
|
fuse_reply_err(req, errno);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG2("%s: fd=%d: sz=%u/%u: '%.*s'\n", __func__,
|
DBG2("%s (%d): fd=%d: sz=%u/%u: '%.*s'\n", __func__,
|
||||||
tty->fds[FD_SLAVE].fd, res, (int)size, res, buf);
|
tty_cli->id, tty->fds[FD_SLAVE].fd, res, (int)size, res, buf);
|
||||||
|
|
||||||
fuse_reply_buf(req, buf, res);
|
fuse_reply_buf(req, buf, res);
|
||||||
|
|
||||||
|
out:
|
||||||
|
pthread_mutex_unlock(&tty->read_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
|
ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
|
||||||
struct fuse_file_info *info)
|
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;
|
int res;
|
||||||
|
|
||||||
DBG2("%s: fd=%d: sz=%u: '%.*s'\n", __func__,
|
pthread_mutex_lock(&tty->write_lock);
|
||||||
tty->fds[FD_SLAVE].fd, (int)size, (int)size, data);
|
|
||||||
|
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)
|
if (size == 0)
|
||||||
{
|
{
|
||||||
fuse_reply_write(req, 0);
|
fuse_reply_write(req, 0);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tty->error)
|
if (tty->error)
|
||||||
{
|
{
|
||||||
DBG2("%s: tty->error=%d\n", __func__, tty->error);
|
DBG2("%s: tty->error=%d\n", __func__, tty->error);
|
||||||
fuse_reply_err(req, EPIPE);
|
fuse_reply_err(req, EPIPE);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = write(tty->fds[FD_SLAVE].fd, data, size);
|
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__);
|
DBG2("%s: error: %m\n", __func__);
|
||||||
tty->error = 1;
|
tty->error = 1;
|
||||||
fuse_reply_err(req, errno);
|
fuse_reply_err(req, errno);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
else if (res != (int)size)
|
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);
|
fuse_reply_write(req, res);
|
||||||
|
|
||||||
|
out:
|
||||||
|
pthread_mutex_unlock(&tty->write_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int baudrate(speed_t speed)
|
static int baudrate(speed_t speed)
|
||||||
@@ -691,12 +747,10 @@ static unsigned int _tio_parity(const struct termios2 *tio)
|
|||||||
{
|
{
|
||||||
unsigned int par;
|
unsigned int par;
|
||||||
|
|
||||||
if (!(tio->c_cflag & PARENB))
|
if ((tio->c_cflag & PARENB) && (tio->c_iflag & IGNPAR))
|
||||||
{
|
|
||||||
par = 1;
|
par = 1;
|
||||||
}
|
|
||||||
#ifdef CMSPAR
|
#ifdef CMSPAR
|
||||||
else if (tio->c_iflag & CMSPAR)
|
else if ((tio->c_cflag & PARENB) && (tio->c_iflag & CMSPAR))
|
||||||
{
|
{
|
||||||
if (tio->c_cflag & PARODD)
|
if (tio->c_cflag & PARODD)
|
||||||
par = 4;
|
par = 4;
|
||||||
@@ -704,14 +758,10 @@ static unsigned int _tio_parity(const struct termios2 *tio)
|
|||||||
par = 5;
|
par = 5;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (tio->c_cflag & PARODD)
|
else if (tio->c_cflag & PARENB)
|
||||||
{
|
|
||||||
par = 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
par = 3;
|
par = 3;
|
||||||
}
|
else
|
||||||
|
par = 1;
|
||||||
|
|
||||||
return par;
|
return par;
|
||||||
}
|
}
|
||||||
@@ -786,7 +836,8 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
|||||||
struct fuse_file_info *info, unsigned int flags,
|
struct fuse_file_info *info, unsigned int flags,
|
||||||
const void *in_buf, size_t in_bufsz, size_t out_bufsz)
|
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 termios2 *tio = &tty->tio;
|
||||||
struct winsize ws;
|
struct winsize ws;
|
||||||
unsigned int tiocm, baud;
|
unsigned int tiocm, baud;
|
||||||
@@ -796,14 +847,16 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
|||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
uint32_t byte4;
|
uint32_t byte4;
|
||||||
|
|
||||||
DBG("%s: cmd=%s arg=%p ibuf=%p:%u obuf=:%u\n", __func__,
|
pthread_mutex_lock(&tty->ioctl_lock);
|
||||||
_ioctl_name(cmd), arg, in_buf,
|
|
||||||
|
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);
|
(unsigned int)in_bufsz, (unsigned int)out_bufsz);
|
||||||
|
|
||||||
if (ttynvt_param.raw)
|
if (ttynvt_param.raw)
|
||||||
{
|
{
|
||||||
fuse_reply_ioctl(req, 0, 0, 0);
|
fuse_reply_ioctl(req, 0, 0, 0);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
@@ -824,12 +877,8 @@ 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);
|
||||||
@@ -998,7 +1047,7 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
|||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
fuse_reply_err(req, errno);
|
fuse_reply_err(req, errno);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
fuse_reply_ioctl(req, 0, &ws, sizeof(struct winsize));
|
fuse_reply_ioctl(req, 0, &ws, sizeof(struct winsize));
|
||||||
break;
|
break;
|
||||||
@@ -1009,7 +1058,7 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
|||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
fuse_reply_err(req, errno);
|
fuse_reply_err(req, errno);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
fuse_reply_ioctl(req, 0, &ws, sizeof(struct winsize));
|
fuse_reply_ioctl(req, 0, &ws, sizeof(struct winsize));
|
||||||
break;
|
break;
|
||||||
@@ -1070,17 +1119,21 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
pthread_mutex_unlock(&tty->ioctl_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ttynvt_poll(fuse_req_t req, struct fuse_file_info *info,
|
ttynvt_poll(fuse_req_t req, struct fuse_file_info *info,
|
||||||
struct fuse_pollhandle *ph)
|
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;
|
int revents = 0;
|
||||||
|
|
||||||
DBG2("%s: tty->pollin=%d tty->error/epipe=%d/%d\n",
|
DBG2("%s (%d): tty->pollin=%d tty->error/epipe=%d/%d\n",
|
||||||
__func__, tty->pollin, tty->error, tty->epipe);
|
__func__, tty_cli->id, tty->pollin, tty->error, tty->epipe);
|
||||||
|
|
||||||
_update_notify(tty, ph);
|
_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)
|
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__);
|
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;
|
tty->rel_pending = 1;
|
||||||
|
|
||||||
pthread_cancel(tty->ptid_poll);
|
pthread_cancel(tty->ptid_poll);
|
||||||
pthread_join(tty->ptid_poll, NULL);
|
pthread_join(tty->ptid_poll, NULL);
|
||||||
pthread_mutex_destroy(&tty->tty_lock);
|
pthread_mutex_destroy(&tty->tty_lock);
|
||||||
pthread_mutex_destroy(&tty->poll_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_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);
|
||||||
|
|
||||||
_ttynvt_ctx_destroy(tty);
|
_ttynvt_ctx_destroy(tty);
|
||||||
|
ptty = NULL;
|
||||||
fuse_reply_err(req, 0);
|
|
||||||
|
|
||||||
nvt_log(LOG_INFO, "Disconnected from server: %s\n", ttynvt_param.server);
|
nvt_log(LOG_INFO, "Disconnected from server: %s\n", ttynvt_param.server);
|
||||||
|
|
||||||
|
out:
|
||||||
|
fuse_reply_err(req, 0);
|
||||||
|
|
||||||
pthread_mutex_unlock(&access_lock);
|
pthread_mutex_unlock(&access_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1182,9 +1259,7 @@ 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
|
||||||
|
|||||||
@@ -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