Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ce6164d20 | |||
| cc95ed0ad2 | |||
| 3231247534 | |||
| c4c25d7dda | |||
| b2747cf886 | |||
| c5ca50b654 | |||
| 96329fc290 | |||
| 568f5ca733 | |||
| 6bfdd85cfb | |||
| 7f4d2f3a51 | |||
| 3cae838cf0 | |||
| 16825bd70e | |||
| 5520722723 | |||
| a68edc5e57 | |||
| 2c3441dda5 | |||
| 45e73de4b9 | |||
| 778242986f | |||
| 137418ad1e | |||
| 9057376656 | |||
| cbbb0cd225 | |||
| 2fb5ad2599 | |||
| 4988368662 | |||
| f0697e83f3 | |||
| 0f879c8b61 | |||
| 5ca23ce107 | |||
| b3f6d61edf | |||
| 7a424bc10d | |||
| 8956f3f851 | |||
| ac76071e0e | |||
| 6337ac09eb | |||
| fd4313745f | |||
| a7d760d719 | |||
| 9ca94921c8 | |||
| cf678db1fd | |||
| 6556a2ec50 |
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
m4_define([pkg_version], [0.14])
|
m4_define([pkg_version], [0.10])
|
||||||
#m4_define([pkg_revision], [005])
|
#m4_define([pkg_revision], [005])
|
||||||
m4_define([pkg_version], m4_ifdef([pkg_revision], [pkg_version.pkg_revision], [pkg_version]))
|
m4_define([pkg_version], m4_ifdef([pkg_revision], [pkg_version.pkg_revision], [pkg_version]))
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ extern tn_ctx_t *telnet_ctx_init(void *cctx, srv_tx_f * ftx, srv_rx_f * frx,
|
|||||||
|
|
||||||
extern int telnet_open(tn_ctx_t * tcc);
|
extern int telnet_open(tn_ctx_t * tcc);
|
||||||
|
|
||||||
extern int telnet_rx(tn_ctx_t * tcc, char *buf, int *plen);
|
extern int telnet_rx(tn_ctx_t * tcc, char *buf, size_t * plen);
|
||||||
extern int telnet_tx(tn_ctx_t * tcc, const char *buf, int len);
|
extern int telnet_tx(tn_ctx_t * tcc, const char *buf, int len);
|
||||||
|
|
||||||
extern void telnet_set_opt(tn_ctx_t * tcc, int opt, int prm,
|
extern void telnet_set_opt(tn_ctx_t * tcc, int opt, int prm,
|
||||||
@@ -42,10 +42,10 @@ extern void telnet_rfc2217_handle_opt(tn_ctx_t * tcc, int opt,
|
|||||||
|
|
||||||
extern void telnet_rfc2217_cfg(tn_ctx_t * tcc, int cmd,
|
extern void telnet_rfc2217_cfg(tn_ctx_t * tcc, int cmd,
|
||||||
const void *val, int nd);
|
const void *val, int nd);
|
||||||
extern void telnet_rfc2217_ctl(tn_ctx_t * tcc, unsigned int val);
|
extern void telnet_rfc2217_ctl(tn_ctx_t * tcc, int cmd);
|
||||||
|
|
||||||
/*RFC2217 modem state*/
|
/*RFC2217 modem state*/
|
||||||
#define TNS_STATE_DCD 0x80
|
#define TNS_STATE_CD 0x80
|
||||||
#define TNS_STATE_RI 0x40
|
#define TNS_STATE_RI 0x40
|
||||||
#define TNS_STATE_DSR 0x20
|
#define TNS_STATE_DSR 0x20
|
||||||
#define TNS_STATE_CTS 0x10
|
#define TNS_STATE_CTS 0x10
|
||||||
|
|||||||
+3
-3
@@ -121,18 +121,18 @@ static void _telnet_handle_opt(tn_ctx_t * tcc, int opt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int telnet_rx(tn_ctx_t * tcc, char *buf, int *plen)
|
int telnet_rx(tn_ctx_t * tcc, char *buf, size_t * plen)
|
||||||
{
|
{
|
||||||
char *s, *p;
|
char *s, *p;
|
||||||
unsigned char *pu;
|
unsigned char *pu;
|
||||||
int len, rem;
|
size_t len, rem;
|
||||||
int np, nd;
|
int np, nd;
|
||||||
int b1, b2;
|
int b1, b2;
|
||||||
|
|
||||||
len = *plen;
|
len = *plen;
|
||||||
tcc->bytes_rx += len;
|
tcc->bytes_rx += len;
|
||||||
|
|
||||||
if (len < (int)tcc->off_rx)
|
if (len < (size_t) tcc->off_rx)
|
||||||
tcc->off_rx = 0;
|
tcc->off_rx = 0;
|
||||||
|
|
||||||
for (s = buf + tcc->off_rx, rem = len - tcc->off_rx; rem > 0; s = p)
|
for (s = buf + tcc->off_rx, rem = len - tcc->off_rx; rem > 0; s = p)
|
||||||
|
|||||||
+2
-4
@@ -43,12 +43,10 @@ void telnet_rfc2217_cfg(tn_ctx_t * tcc, int cmd, const void *val, int nd)
|
|||||||
telnet_set_opt(tcc, TNO_CPCO, cmd, val, nd);
|
telnet_set_opt(tcc, TNO_CPCO, cmd, val, nd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void telnet_rfc2217_ctl(tn_ctx_t * tcc, unsigned int val)
|
void telnet_rfc2217_ctl(tn_ctx_t * tcc, int cmd)
|
||||||
{
|
{
|
||||||
unsigned char byte = val;
|
|
||||||
|
|
||||||
if (!tcc->mode_rfc2217)
|
if (!tcc->mode_rfc2217)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
telnet_set_opt(tcc, TNO_CPCO, TNS_SET_CONTROL, &byte, 1);
|
telnet_set_opt(tcc, TNO_CPCO, TNS_SET_CONTROL, &cmd, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "telnet.h"
|
#include "telnet.h"
|
||||||
@@ -33,8 +32,8 @@
|
|||||||
#define TMP_BUF_SIZE 1024
|
#define TMP_BUF_SIZE 1024
|
||||||
|
|
||||||
#define FD_NET 0
|
#define FD_NET 0
|
||||||
#define FD_MASTER 1
|
#define FD_SLAVE 1
|
||||||
#define FD_SLAVE 2
|
#define FD_MASTER 2
|
||||||
|
|
||||||
#define _PRF_N_(no) __attribute__((__format__(__printf__, (no), (no) + 1)))
|
#define _PRF_N_(no) __attribute__((__format__(__printf__, (no), (no) + 1)))
|
||||||
#define _PRF2_ _PRF_N_(2)
|
#define _PRF2_ _PRF_N_(2)
|
||||||
@@ -46,7 +45,6 @@ static struct ttynvt_param {
|
|||||||
const char *dev_name;
|
const char *dev_name;
|
||||||
char *server;
|
char *server;
|
||||||
unsigned int debug;
|
unsigned int debug;
|
||||||
int logstd;
|
|
||||||
/* Derived */
|
/* Derived */
|
||||||
char host[64];
|
char host[64];
|
||||||
unsigned int port;
|
unsigned int port;
|
||||||
@@ -57,121 +55,53 @@ 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_t ptid_poll;
|
pthread_t thread_id;
|
||||||
pthread_t ptid_read;
|
|
||||||
|
|
||||||
struct fuse_pollhandle *ph;
|
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 */
|
|
||||||
struct pollfd fds[3];
|
struct pollfd fds[3];
|
||||||
|
|
||||||
char net_buf[NET_BUF_SIZE];
|
char net_buf[NET_BUF_SIZE];
|
||||||
int net_cnt;
|
size_t net_cnt;
|
||||||
|
char tmp_buf[TMP_BUF_SIZE];
|
||||||
|
|
||||||
struct termios tio;
|
struct termios tio;
|
||||||
|
int cmcr;
|
||||||
int cmcr; /* Commanded by ioctl */
|
|
||||||
volatile int smcr; /* Status from modem */
|
|
||||||
int smcr_last;
|
|
||||||
|
|
||||||
volatile int pollin;
|
|
||||||
volatile int pollout;
|
|
||||||
volatile int error;
|
|
||||||
int epipe;
|
int epipe;
|
||||||
|
|
||||||
|
volatile int smcr;
|
||||||
|
volatile int error;
|
||||||
|
volatile int pollin;
|
||||||
|
|
||||||
tn_ctx_t *tn;
|
tn_ctx_t *tn;
|
||||||
} ttynvt_t;
|
} ttynvt_t;
|
||||||
|
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#define gettid() (pid_t)syscall(__NR_gettid)
|
#define gettid() (pid_t)syscall(__NR_gettid)
|
||||||
|
|
||||||
static const char *_hms_txt(char *buf, unsigned int len)
|
|
||||||
{
|
|
||||||
struct timeval tv;
|
|
||||||
unsigned int sod, hh, mm, ss;
|
|
||||||
|
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
|
|
||||||
sod = tv.tv_sec % (24 * 3600);
|
|
||||||
hh = sod / 3600;
|
|
||||||
mm = (sod - hh * 3600) / 60;
|
|
||||||
ss = sod - hh * 3600 - mm * 60;
|
|
||||||
snprintf(buf, len, "%02d:%02d:%02d.%06d",
|
|
||||||
hh, mm, ss, (unsigned int)tv.tv_usec);
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
_PRF2_ static void _log(int prio, const char *fmt, ...)
|
_PRF2_ static void _log(int prio, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list arg;
|
va_list arg;
|
||||||
char buf[256], buft[64];
|
char buf[256];
|
||||||
|
|
||||||
va_start(arg, fmt);
|
va_start(arg, fmt);
|
||||||
|
#if 0
|
||||||
|
vsyslog(prio, fmt, arg);
|
||||||
|
#else
|
||||||
vsnprintf(buf, sizeof(buf), fmt, arg);
|
vsnprintf(buf, sizeof(buf), fmt, arg);
|
||||||
|
syslog(prio, "[%d] %s", gettid(), buf);
|
||||||
if (ttynvt_param.logstd)
|
#endif
|
||||||
{
|
|
||||||
printf("%s: [%d] %d: %s",
|
|
||||||
_hms_txt(buft, sizeof(buft)), gettid(), prio, buf);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
syslog(prio, "[%d] %s", gettid(), buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BPL 16 /* Bytes per line */
|
|
||||||
|
|
||||||
void _log_buf(int prio, const char *txt, const void *ptr_, unsigned int len)
|
|
||||||
{
|
|
||||||
unsigned int ix, i, imax;
|
|
||||||
int l, n;
|
|
||||||
char buf[128];
|
|
||||||
const unsigned char *ptr = ptr_;
|
|
||||||
|
|
||||||
for (ix = 0; ix < len || (len == 0 && ix == 0); ix += BPL)
|
|
||||||
{
|
|
||||||
n = snprintf(buf, sizeof(buf), "%s: %04x:", txt, ix);
|
|
||||||
if (n <= 0)
|
|
||||||
return; /* Just playing it safe */
|
|
||||||
imax = (len - ix < BPL) ? len - ix : BPL;
|
|
||||||
for (i = 0; i < imax; i++)
|
|
||||||
{
|
|
||||||
l = snprintf(buf + n, sizeof(buf) - n, " %02x", *ptr++);
|
|
||||||
if (l <= 0)
|
|
||||||
return; /* Just playing it safe */
|
|
||||||
n += l;
|
|
||||||
}
|
|
||||||
_log(prio, "%s\n", buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DBG(...) \
|
#define DBG(...) \
|
||||||
if (ttynvt_param.debug > 0) _log(LOG_DEBUG, __VA_ARGS__)
|
if (ttynvt_param.debug > 0) _log(LOG_DEBUG, __VA_ARGS__)
|
||||||
#define DBG2(...) \
|
#define DBG2(...) \
|
||||||
if (ttynvt_param.debug > 1) _log(LOG_DEBUG, __VA_ARGS__)
|
if (ttynvt_param.debug > 1) _log(LOG_DEBUG, __VA_ARGS__)
|
||||||
#define DBG2_BUF(txt, ptr, len) \
|
|
||||||
if (ttynvt_param.debug > 1) _log_buf(LOG_DEBUG, txt, ptr, len)
|
|
||||||
|
|
||||||
static void _fd_close(int fd)
|
|
||||||
{
|
|
||||||
if (fd >= 0)
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static volatile char _is_interrupted = 0;
|
|
||||||
|
|
||||||
static void sig_handler(int sig)
|
static void sig_handler(int sig)
|
||||||
{
|
{
|
||||||
DBG("Interruped, signal = %d\n", sig);
|
|
||||||
_is_interrupted = 1;
|
|
||||||
if (sig != SIGUSR2)
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_signal_handler(void)
|
static void set_signal_handler(void)
|
||||||
@@ -183,7 +113,6 @@ static void set_signal_handler(void)
|
|||||||
sigemptyset(&(sa.sa_mask));
|
sigemptyset(&(sa.sa_mask));
|
||||||
sa.sa_flags = 0;
|
sa.sa_flags = 0;
|
||||||
sigaction(SIGUSR2, &sa, NULL);
|
sigaction(SIGUSR2, &sa, NULL);
|
||||||
sigaction(SIGTERM, &sa, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ttynvt_interrupted(fuse_req_t req, void *data)
|
static void ttynvt_interrupted(fuse_req_t req, void *data)
|
||||||
@@ -215,13 +144,12 @@ static void ttynvt_release(fuse_req_t req, struct fuse_file_info *info)
|
|||||||
|
|
||||||
_log(LOG_INFO, "connection closed\n");
|
_log(LOG_INFO, "connection closed\n");
|
||||||
|
|
||||||
tty->rel_pending = 1;
|
close(tty->fds[FD_NET].fd);
|
||||||
_fd_close(tty->fds[FD_NET].fd);
|
close(tty->fds[FD_MASTER].fd);
|
||||||
_fd_close(tty->fds[FD_MASTER].fd);
|
close(tty->fds[FD_SLAVE].fd);
|
||||||
_fd_close(tty->fds[FD_SLAVE].fd);
|
|
||||||
|
|
||||||
pthread_cancel(tty->ptid_poll);
|
pthread_cancel(tty->thread_id);
|
||||||
pthread_join(tty->ptid_poll, NULL);
|
pthread_join(tty->thread_id, 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);
|
||||||
|
|
||||||
@@ -256,117 +184,68 @@ 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)
|
|
||||||
{
|
|
||||||
if ((tty->tio.c_cflag & CLOCAL) == 0 &&
|
|
||||||
(tty->smcr_last & TIOCM_CD) != 0 && (tty->smcr & TIOCM_CD) == 0)
|
|
||||||
{
|
|
||||||
/* CLOCAL is not set (i.e. do not ignore modem control lines) AND
|
|
||||||
* DCD dropped */
|
|
||||||
DBG("GOT DCD DROP\n");
|
|
||||||
close(tty->fds[FD_MASTER].fd);
|
|
||||||
tty->fds[FD_MASTER].fd = -1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *_read_net(void *arg)
|
static void *_read_net(void *arg)
|
||||||
{
|
{
|
||||||
ttynvt_t *tty = (ttynvt_t *) arg;
|
ttynvt_t *tty = (ttynvt_t *) arg;
|
||||||
char buf[TMP_BUF_SIZE];
|
ssize_t res;
|
||||||
int res;
|
|
||||||
|
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||||
DBG2("%s: net_cnt=%d\n", __func__, tty->net_cnt);
|
|
||||||
|
|
||||||
while (!tty->rel_pending)
|
while (1)
|
||||||
{
|
{
|
||||||
tty->fds[FD_NET].revents = tty->fds[FD_MASTER].revents =
|
|
||||||
tty->fds[FD_SLAVE].revents = 0;
|
|
||||||
tty->fds[FD_SLAVE].events = tty->slave_suspended ? POLLPRI : POLLIN;
|
|
||||||
tty->fds[FD_MASTER].events = tty->master_suspended ? POLLPRI : POLLIN;
|
|
||||||
|
|
||||||
res = poll(tty->fds, 3, -1);
|
res = poll(tty->fds, 3, -1);
|
||||||
DBG2("%s: res=%d events-N/M/S=%x:%x/%x:%x/%x:%x SS=%d MS=%d\n",
|
|
||||||
__func__, res, tty->fds[FD_NET].events, tty->fds[FD_NET].revents,
|
|
||||||
tty->fds[FD_MASTER].events, tty->fds[FD_MASTER].revents,
|
|
||||||
tty->fds[FD_SLAVE].events, tty->fds[FD_SLAVE].revents,
|
|
||||||
tty->slave_suspended, tty->master_suspended);
|
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
break;
|
else
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (tty->rel_pending)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (tty->fds[FD_NET].revents & POLLIN)
|
if (tty->fds[FD_NET].revents & POLLIN)
|
||||||
{
|
{
|
||||||
res = read(tty->fds[FD_NET].fd, tty->net_buf + tty->net_cnt,
|
res = read(tty->fds[FD_NET].fd, tty->net_buf + tty->net_cnt,
|
||||||
NET_BUF_SIZE - tty->net_cnt);
|
NET_BUF_SIZE - tty->net_cnt);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
_log(LOG_ERR, "net read error: %m\n");
|
_log(LOG_ERR, "net read error: %s\n", strerror(errno));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (res == 0)
|
else if (res == 0)
|
||||||
{
|
{
|
||||||
_log(LOG_INFO, "Connection closed by remote host\n");
|
_log(LOG_INFO, "Connection closed by remote host\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tty->net_cnt += res;
|
tty->net_cnt += res;
|
||||||
DBG2_BUF("Serv in A", tty->net_buf, tty->net_cnt);
|
|
||||||
res = telnet_rx(tty->tn, tty->net_buf, &tty->net_cnt);
|
res = telnet_rx(tty->tn, tty->net_buf, &tty->net_cnt);
|
||||||
DBG2_BUF("Serv in B", tty->net_buf, tty->net_cnt);
|
|
||||||
if (tty->net_cnt > 0 && res == 0)
|
if (tty->net_cnt > 0 && res == 0)
|
||||||
{
|
{
|
||||||
DBG2_BUF("TtyM out ", tty->net_buf, tty->net_cnt);
|
|
||||||
res =
|
res =
|
||||||
write(tty->fds[FD_MASTER].fd, tty->net_buf, tty->net_cnt);
|
write(tty->fds[FD_MASTER].fd, tty->net_buf, tty->net_cnt);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
_log(LOG_ERR, "master write error: %m\n");
|
_log(LOG_ERR, "master write error:%s\n", strerror(errno));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tty->net_cnt = 0;
|
tty->net_cnt = 0;
|
||||||
}
|
}
|
||||||
if (_net_read_check_exit(tty))
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
if (tty->fds[FD_MASTER].revents & POLLIN)
|
||||||
if ((tty->fds[FD_MASTER].revents & POLLIN) && !tty->master_suspended)
|
|
||||||
{
|
{
|
||||||
res = read(tty->fds[FD_MASTER].fd, buf, TMP_BUF_SIZE);
|
res = read(tty->fds[FD_MASTER].fd, tty->tmp_buf, TMP_BUF_SIZE);
|
||||||
DBG("%s: read res=%d pollout=%d\n", __func__, res, tty->pollout);
|
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
_log(LOG_ERR, "master read error: %m\n");
|
_log(LOG_ERR, "master read error:%s\n", strerror(errno));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (tty->pollout == 0)
|
telnet_tx(tty->tn, tty->tmp_buf, res);
|
||||||
{
|
|
||||||
tty->pollout = 1;
|
|
||||||
_notify(tty);
|
|
||||||
}
|
|
||||||
DBG2_BUF("TtyM in ", buf, res);
|
|
||||||
telnet_tx(tty->tn, buf, res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tty->fds[FD_SLAVE].revents & POLLIN)
|
if (tty->fds[FD_SLAVE].revents & POLLIN)
|
||||||
{
|
{
|
||||||
tty->pollin = 1;
|
tty->pollin = 1;
|
||||||
tty->slave_suspended = 1; /* Disable polling of Slave */
|
|
||||||
_notify(tty);
|
_notify(tty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG2("%s: done\n", __func__);
|
|
||||||
if (tty->ptid_read)
|
|
||||||
pthread_kill(tty->ptid_read, SIGUSR2);
|
|
||||||
|
|
||||||
tty->error = 1;
|
tty->error = 1;
|
||||||
_notify(tty);
|
_notify(tty);
|
||||||
|
|
||||||
@@ -382,14 +261,14 @@ static int _srv_connect(const char *host, unsigned int port)
|
|||||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (sockfd < 0)
|
if (sockfd < 0)
|
||||||
{
|
{
|
||||||
_log(LOG_ERR, "Socket open failed: %m\n");
|
_log(LOG_ERR, "Socket open failed: %s\n", strerror(errno));
|
||||||
return sockfd;
|
return sockfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
server = gethostbyname(host);
|
server = gethostbyname(host);
|
||||||
if (server == NULL)
|
if (server == NULL)
|
||||||
{
|
{
|
||||||
_log(LOG_ERR, "Cannot resolve host name: %m\n");
|
_log(LOG_ERR, "Cannot resolve host name: %s\n", strerror(errno));
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -403,7 +282,8 @@ static int _srv_connect(const char *host, unsigned int port)
|
|||||||
err = connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
|
err = connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
{
|
{
|
||||||
_log(LOG_ERR, "Failed to connect to: %s:%u: %m\n", host, port);
|
_log(LOG_ERR, "Failed to connect to: %s:%u:%s\n",
|
||||||
|
host, port, strerror(errno));
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -416,13 +296,8 @@ static int _srv_write(void *cctx, const void *buf, int len)
|
|||||||
ttynvt_t *tty = cctx;
|
ttynvt_t *tty = cctx;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
DBG2_BUF("Serv out ", buf, len);
|
|
||||||
|
|
||||||
res = write(tty->fds[FD_NET].fd, buf, len);
|
res = write(tty->fds[FD_NET].fd, buf, len);
|
||||||
|
|
||||||
DBG2("%s: fd=%d: len=%u: res=%d\n", __func__,
|
|
||||||
tty->fds[FD_NET].fd, len, res);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,12 +306,9 @@ static int _srv_read(void *cctx, int timeout)
|
|||||||
ttynvt_t *tty = cctx;
|
ttynvt_t *tty = cctx;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
DBG2("%s: net_cnt=%d\n", __func__, tty->net_cnt);
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
res = poll(&tty->fds[FD_NET], 1, timeout);
|
res = poll(&tty->fds[FD_NET], 1, timeout);
|
||||||
DBG("%s: res=%d events-N=%#x\n",
|
|
||||||
__func__, res, tty->fds[FD_NET].revents);
|
|
||||||
if (res <= 0)
|
if (res <= 0)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
@@ -444,15 +316,10 @@ static int _srv_read(void *cctx, int timeout)
|
|||||||
{
|
{
|
||||||
res = read(tty->fds[FD_NET].fd, tty->net_buf + tty->net_cnt,
|
res = read(tty->fds[FD_NET].fd, tty->net_buf + tty->net_cnt,
|
||||||
NET_BUF_SIZE - tty->net_cnt);
|
NET_BUF_SIZE - tty->net_cnt);
|
||||||
DBG2("%s: fd=%d: res=%d net_cnt=%d\n", __func__,
|
|
||||||
tty->fds[FD_NET].fd, res, tty->net_cnt);
|
|
||||||
if (res <= 0)
|
if (res <= 0)
|
||||||
return res;
|
return res;
|
||||||
tty->net_cnt += res;
|
tty->net_cnt += (size_t) res;
|
||||||
DBG2_BUF("Serv in a", tty->net_buf, tty->net_cnt);
|
|
||||||
res = telnet_rx(tty->tn, tty->net_buf, &tty->net_cnt);
|
res = telnet_rx(tty->tn, tty->net_buf, &tty->net_cnt);
|
||||||
DBG2_BUF("Serv in b", tty->net_buf, tty->net_cnt);
|
|
||||||
DBG2("%s: res=%d net_cnt=%d\n", __func__, res, tty->net_cnt);
|
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -465,25 +332,21 @@ static void _modem_status_cb(void *cctx, int status)
|
|||||||
ttynvt_t *tty = cctx;
|
ttynvt_t *tty = cctx;
|
||||||
int mcr = 0;
|
int mcr = 0;
|
||||||
|
|
||||||
DBG("MCR: CTS=%c DSR=%c RI=%c DCD=%c\n",
|
DBG("MCR: DSR=%c CTS=%c RI=%c CD=%c\n",
|
||||||
status & TNS_STATE_CTS ? '1' : '0', status & TNS_STATE_DSR ? '1' : '0',
|
status & TNS_STATE_DSR ? '1' : '0',
|
||||||
status & TNS_STATE_RI ? '1' : '0', status & TNS_STATE_DCD ? '1' : '0');
|
status & TNS_STATE_CTS ? '1' : '0',
|
||||||
|
status & TNS_STATE_RI ? '1' : '0', status & TNS_STATE_CD ? '1' : '0');
|
||||||
|
|
||||||
if (status & TNS_STATE_DCD)
|
if (status & TNS_STATE_CD)
|
||||||
mcr |= TIOCM_CD;
|
mcr |= TIOCM_CD;
|
||||||
if (status & TNS_STATE_RI)
|
if (status & TNS_STATE_RI)
|
||||||
mcr |= TIOCM_RI;
|
mcr |= TIOCM_RI;
|
||||||
if (status & TNS_STATE_DSR)
|
|
||||||
mcr |= TIOCM_DSR;
|
|
||||||
if (status & TNS_STATE_CTS)
|
if (status & TNS_STATE_CTS)
|
||||||
mcr |= TIOCM_CTS;
|
mcr |= TIOCM_CTS;
|
||||||
|
if (status & TNS_STATE_DSR)
|
||||||
tty->master_suspended = (mcr & TIOCM_CTS) ? 0 : 1;
|
mcr |= TIOCM_DSR;
|
||||||
DBG("%s: tty=%p mcr=%x MS=%d\n", __func__, tty, mcr,
|
|
||||||
tty->master_suspended);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&tty->tty_lock);
|
pthread_mutex_lock(&tty->tty_lock);
|
||||||
tty->smcr_last = tty->smcr;
|
|
||||||
tty->smcr = mcr;
|
tty->smcr = mcr;
|
||||||
pthread_mutex_unlock(&tty->tty_lock);
|
pthread_mutex_unlock(&tty->tty_lock);
|
||||||
}
|
}
|
||||||
@@ -503,7 +366,7 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
|||||||
int res;
|
int res;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
DBG("%s\n", __func__);
|
DBG2("open: thread:%lu\n", pthread_self());
|
||||||
|
|
||||||
tty = calloc(1, sizeof(*tty));
|
tty = calloc(1, sizeof(*tty));
|
||||||
if (!tty)
|
if (!tty)
|
||||||
@@ -514,8 +377,6 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
|||||||
for (n = 0; n < 3; n++)
|
for (n = 0; n < 3; n++)
|
||||||
tty->fds[n].fd = -1;
|
tty->fds[n].fd = -1;
|
||||||
|
|
||||||
tty->pollout = 1;
|
|
||||||
|
|
||||||
tty->tn = telnet_ctx_init(tty, _srv_write, _srv_read, _modem_status_cb);
|
tty->tn = telnet_ctx_init(tty, _srv_write, _srv_read, _modem_status_cb);
|
||||||
if (!tty->tn)
|
if (!tty->tn)
|
||||||
{
|
{
|
||||||
@@ -543,8 +404,6 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
|||||||
tty->fds[FD_MASTER].fd = fd;
|
tty->fds[FD_MASTER].fd = fd;
|
||||||
tty->fds[FD_MASTER].events = POLLIN;
|
tty->fds[FD_MASTER].events = POLLIN;
|
||||||
|
|
||||||
memset(&ios, 0, sizeof(ios));
|
|
||||||
|
|
||||||
ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
|
ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
|
||||||
| INLCR | IGNCR | ICRNL | IXON);
|
| INLCR | IGNCR | ICRNL | IXON);
|
||||||
ios.c_oflag &= ~OPOST;
|
ios.c_oflag &= ~OPOST;
|
||||||
@@ -562,11 +421,6 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
|||||||
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);
|
|
||||||
tty->tio.c_cflag &= ~(CSIZE | PARENB);
|
|
||||||
tty->tio.c_cflag |= B115200 | CS8 | CREAD | CLOCAL;
|
|
||||||
ioctl(fd, TCSETS, &tty->tio);
|
|
||||||
|
|
||||||
tty->fds[FD_SLAVE].fd = fd;
|
tty->fds[FD_SLAVE].fd = fd;
|
||||||
tty->fds[FD_SLAVE].events = POLLIN;
|
tty->fds[FD_SLAVE].events = POLLIN;
|
||||||
|
|
||||||
@@ -578,7 +432,7 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
|||||||
}
|
}
|
||||||
if ((res = pthread_mutex_init(&tty->tty_lock, NULL) < 0) ||
|
if ((res = pthread_mutex_init(&tty->tty_lock, NULL) < 0) ||
|
||||||
(res = pthread_mutex_init(&tty->poll_lock, NULL) < 0) ||
|
(res = pthread_mutex_init(&tty->poll_lock, NULL) < 0) ||
|
||||||
(res = pthread_create(&tty->ptid_poll, NULL, &_read_net, tty)))
|
(res = pthread_create(&tty->thread_id, NULL, &_read_net, tty)))
|
||||||
{
|
{
|
||||||
errno = res;
|
errno = res;
|
||||||
goto open_err;
|
goto open_err;
|
||||||
@@ -597,11 +451,12 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
|||||||
|
|
||||||
open_err:
|
open_err:
|
||||||
|
|
||||||
_log(LOG_INFO, "Connection to server: %s:%d failed: %m\n",
|
_log(LOG_INFO, "Connection to server: %s:%d failed:%s\n",
|
||||||
ttynvt_param.host, ttynvt_param.port);
|
ttynvt_param.host, ttynvt_param.port, strerror(errno));
|
||||||
|
|
||||||
for (n = 0; n < 3; n++)
|
for (n = 0; n < 3; n++)
|
||||||
_fd_close(tty->fds[n].fd);
|
if (tty->fds[n].fd >= 0)
|
||||||
|
close(tty->fds[n].fd);
|
||||||
|
|
||||||
free(tty->tn);
|
free(tty->tn);
|
||||||
free(tty);
|
free(tty);
|
||||||
@@ -613,19 +468,16 @@ 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_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||||
char buf[TMP_BUF_SIZE];
|
int res;
|
||||||
int res, nr;
|
|
||||||
|
|
||||||
DBG2("%s\n", __func__);
|
|
||||||
|
|
||||||
if (tty->error)
|
if (tty->error)
|
||||||
{
|
{
|
||||||
DBG2("%s: tty->error=%d\n", __func__, tty->error);
|
DBG2("read (slave) in error state, thread:%lu\n", pthread_self());
|
||||||
if (tty->epipe == 0)
|
if (tty->epipe == 0)
|
||||||
{
|
{
|
||||||
_log(LOG_WARNING, "Rx EPIPE\n");
|
_log(LOG_WARNING, "Rx EPIPE\n");
|
||||||
tty->epipe = 1;
|
tty->epipe = 1;
|
||||||
fuse_reply_buf(req, NULL, 0);
|
fuse_reply_buf(req, tty->tmp_buf, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fuse_reply_err(req, EBADFD);
|
fuse_reply_err(req, EBADFD);
|
||||||
@@ -636,34 +488,19 @@ ttynvt_read(fuse_req_t req, size_t size, off_t off,
|
|||||||
if (size > TMP_BUF_SIZE)
|
if (size > TMP_BUF_SIZE)
|
||||||
size = TMP_BUF_SIZE;
|
size = TMP_BUF_SIZE;
|
||||||
|
|
||||||
tty->ptid_read = pthread_self();
|
fuse_req_interrupt_func(req, ttynvt_interrupted, (void *)pthread_self());
|
||||||
fuse_req_interrupt_func(req, ttynvt_interrupted, (void *)tty->ptid_read);
|
res = read(tty->fds[FD_SLAVE].fd, tty->tmp_buf, size);
|
||||||
res = _is_interrupted ? -2 : read(tty->fds[FD_SLAVE].fd, buf, size);
|
|
||||||
_is_interrupted = 0;
|
|
||||||
tty->ptid_read = 0;
|
|
||||||
tty->slave_suspended = 0; /* Enable polling of Slave */
|
|
||||||
fuse_req_interrupt_func(req, NULL, NULL);
|
fuse_req_interrupt_func(req, NULL, NULL);
|
||||||
if (res < (int)size)
|
|
||||||
{
|
|
||||||
tty->pollin = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nr = 0;
|
|
||||||
ioctl(tty->fds[FD_SLAVE].fd, FIONREAD, &nr);
|
|
||||||
tty->pollin = nr > 0;
|
|
||||||
}
|
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
DBG2("%s: error: %m\n", __func__);
|
DBG2("read (slave) error: %s\n", strerror(errno));
|
||||||
fuse_reply_err(req, errno);
|
fuse_reply_err(req, errno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG2("%s: fd=%d: sz=%u/%u: '%.*s'\n", __func__,
|
DBG2("read (slave): size:%d, thread:%lu\n", res, pthread_self());
|
||||||
tty->fds[FD_SLAVE].fd, res, (int)size, res, buf);
|
|
||||||
|
|
||||||
fuse_reply_buf(req, buf, res);
|
fuse_reply_buf(req, tty->tmp_buf, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -671,10 +508,8 @@ 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_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||||
int res;
|
ssize_t res;
|
||||||
|
|
||||||
DBG2("%s: fd=%d: sz=%u: '%.*s'\n", __func__,
|
|
||||||
tty->fds[FD_SLAVE].fd, (int)size, (int)size, data);
|
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
{
|
{
|
||||||
@@ -684,7 +519,6 @@ ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
|
|||||||
|
|
||||||
if (tty->error)
|
if (tty->error)
|
||||||
{
|
{
|
||||||
DBG2("%s: tty->error=%d\n", __func__, tty->error);
|
|
||||||
fuse_reply_err(req, EPIPE);
|
fuse_reply_err(req, EPIPE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -692,15 +526,13 @@ ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
|
|||||||
res = write(tty->fds[FD_SLAVE].fd, data, size);
|
res = write(tty->fds[FD_SLAVE].fd, data, size);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
DBG2("%s: error: %m\n", __func__);
|
DBG2("write (slave) error: %s\n", strerror(errno));
|
||||||
tty->error = 1;
|
tty->error = 1;
|
||||||
fuse_reply_err(req, errno);
|
fuse_reply_err(req, errno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (res != (int)size)
|
|
||||||
{
|
DBG2("write (slave): size:%d, thread:%lu\n", (int)size, pthread_self());
|
||||||
tty->pollout = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fuse_reply_write(req, res);
|
fuse_reply_write(req, res);
|
||||||
}
|
}
|
||||||
@@ -743,6 +575,9 @@ static const char *_ioctl_name(int cmd)
|
|||||||
CASE(TIOCINQ);
|
CASE(TIOCINQ);
|
||||||
CASE(TIOCOUTQ);
|
CASE(TIOCOUTQ);
|
||||||
CASE(TCFLSH);
|
CASE(TCFLSH);
|
||||||
|
CASE(TCIFLUSH);
|
||||||
|
CASE(TCOFLUSH);
|
||||||
|
CASE(TCIOFLUSH);
|
||||||
CASE(TIOCMGET);
|
CASE(TIOCMGET);
|
||||||
CASE(TIOCMBIS);
|
CASE(TIOCMBIS);
|
||||||
CASE(TIOCMBIC);
|
CASE(TIOCMBIC);
|
||||||
@@ -750,9 +585,6 @@ static const char *_ioctl_name(int cmd)
|
|||||||
CASE(TCSBRK);
|
CASE(TCSBRK);
|
||||||
CASE(TIOCGWINSZ);
|
CASE(TIOCGWINSZ);
|
||||||
CASE(TIOCSWINSZ);
|
CASE(TIOCSWINSZ);
|
||||||
/* Controlling terminal */
|
|
||||||
CASE(TIOCSCTTY);
|
|
||||||
CASE(TIOCNOTTY);
|
|
||||||
/* Exclusive mode */
|
/* Exclusive mode */
|
||||||
CASE(TIOCEXCL);
|
CASE(TIOCEXCL);
|
||||||
CASE(TIOCGEXCL);
|
CASE(TIOCGEXCL);
|
||||||
@@ -765,71 +597,6 @@ static const char *_ioctl_name(int cmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int _tio_parity(const struct termios *tio)
|
|
||||||
{
|
|
||||||
unsigned int par;
|
|
||||||
|
|
||||||
if (tio->c_cflag & PARENB && tio->c_iflag & IGNPAR)
|
|
||||||
par = 1;
|
|
||||||
#ifdef CMSPAR
|
|
||||||
else if (tio->c_cflag & PARENB && tio->c_iflag & CMSPAR)
|
|
||||||
{
|
|
||||||
if (tio->c_cflag & PARODD)
|
|
||||||
par = 4;
|
|
||||||
else
|
|
||||||
par = 5;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else if (tio->c_cflag & PARENB)
|
|
||||||
par = 3;
|
|
||||||
else
|
|
||||||
par = 1;
|
|
||||||
|
|
||||||
return par;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int _tio_baud(const struct termios *tio)
|
|
||||||
{
|
|
||||||
return baudrate(tio->c_cflag & (CBAUD | CBAUDEX));
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int _tio_csize(const struct termios *tio)
|
|
||||||
{
|
|
||||||
unsigned int csize;
|
|
||||||
|
|
||||||
if ((tio->c_cflag & CSIZE) == CS5)
|
|
||||||
csize = 5;
|
|
||||||
else if ((tio->c_cflag & CSIZE) == CS6)
|
|
||||||
csize = 6;
|
|
||||||
else if ((tio->c_cflag & CSIZE) == CS7)
|
|
||||||
csize = 7;
|
|
||||||
else
|
|
||||||
csize = 8;
|
|
||||||
|
|
||||||
return csize;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int _tio_stopb(const struct termios *tio)
|
|
||||||
{
|
|
||||||
unsigned int stopb;
|
|
||||||
|
|
||||||
if (tio->c_cflag & CSTOPB)
|
|
||||||
stopb = 2;
|
|
||||||
else
|
|
||||||
stopb = 1;
|
|
||||||
|
|
||||||
return stopb;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _show_termios(const char *txt, const struct termios *tio)
|
|
||||||
{
|
|
||||||
DBG("%s: %u%c%u%u %cCTSRTS %cCREAD %cHUPCL %cCLOCAL\n", txt,
|
|
||||||
_tio_baud(tio), pstr[_tio_parity(tio)], _tio_csize(tio),
|
|
||||||
_tio_stopb(tio),
|
|
||||||
tio->c_cflag & CRTSCTS ? '+' : '-', tio->c_cflag & CREAD ? '+' : '-',
|
|
||||||
tio->c_cflag & HUPCL ? '+' : '-', tio->c_cflag & CLOCAL ? '+' : '-');
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CHECK_BUF_IN(sz) \
|
#define CHECK_BUF_IN(sz) \
|
||||||
if (in_bufsz < sz) do { in_bufsz = sz; goto retry_in; } while(0)
|
if (in_bufsz < sz) do { in_bufsz = sz; goto retry_in; } while(0)
|
||||||
#define CHECK_BUF_OUT(sz) \
|
#define CHECK_BUF_OUT(sz) \
|
||||||
@@ -841,14 +608,14 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
|||||||
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_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||||
struct termios *tio = &tty->tio;
|
|
||||||
struct winsize ws;
|
struct winsize ws;
|
||||||
unsigned int tiocm = 0;
|
unsigned int tiocm = 0;
|
||||||
int mcr;
|
int mcr;
|
||||||
|
static struct termios tio = {
|
||||||
|
.c_cflag = B115200 | CS8 | PARODD | CREAD | CLOCAL,
|
||||||
|
};
|
||||||
int val;
|
int val;
|
||||||
int res;
|
int res;
|
||||||
unsigned char byte;
|
|
||||||
unsigned int byte4;
|
|
||||||
|
|
||||||
DBG("%s: cmd=%s arg=%p ibuf=%p:%u obuf=:%u\n", __func__,
|
DBG("%s: cmd=%s arg=%p ibuf=%p:%u obuf=:%u\n", __func__,
|
||||||
_ioctl_name(cmd), arg, in_buf,
|
_ioctl_name(cmd), arg, in_buf,
|
||||||
@@ -861,46 +628,72 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
|||||||
case TCSETS:
|
case TCSETS:
|
||||||
CHECK_BUF_IN(sizeof(struct termios));
|
CHECK_BUF_IN(sizeof(struct termios));
|
||||||
{
|
{
|
||||||
memcpy(tio, in_buf, in_bufsz);
|
speed_t speed;
|
||||||
|
int csize, par, sb;
|
||||||
|
|
||||||
byte4 = htonl(_tio_baud(tio));
|
memcpy(&tio, in_buf, in_bufsz);
|
||||||
telnet_rfc2217_cfg(tty->tn, TNS_SET_BAUDRATE, &byte4, 4);
|
|
||||||
|
|
||||||
byte = _tio_csize(tio);
|
speed = tio.c_cflag & (CBAUD | CBAUDEX);
|
||||||
telnet_rfc2217_cfg(tty->tn, TNS_SET_DATASIZE, &byte, 1);
|
val = htonl(baudrate(speed));
|
||||||
|
telnet_rfc2217_cfg(tty->tn, TNS_SET_BAUDRATE, &val, 4);
|
||||||
|
|
||||||
byte = _tio_parity(tio);
|
if ((tio.c_cflag & CSIZE) == CS5)
|
||||||
telnet_rfc2217_cfg(tty->tn, TNS_SET_PARITY, &byte, 1);
|
csize = 5;
|
||||||
|
else if ((tio.c_cflag & CSIZE) == CS6)
|
||||||
|
csize = 6;
|
||||||
|
else if ((tio.c_cflag & CSIZE) == CS7)
|
||||||
|
csize = 7;
|
||||||
|
else
|
||||||
|
csize = 8;
|
||||||
|
telnet_rfc2217_cfg(tty->tn, TNS_SET_DATASIZE, &csize, 1);
|
||||||
|
|
||||||
byte = _tio_stopb(tio);
|
if (tio.c_cflag & PARENB && tio.c_iflag & IGNPAR)
|
||||||
telnet_rfc2217_cfg(tty->tn, TNS_SET_STOPSIZE, &byte, 1);
|
par = 1;
|
||||||
|
#ifdef CMSPAR
|
||||||
if (tio->c_cflag & CRTSCTS)
|
else if (tio.c_cflag & PARENB && tio.c_iflag & CMSPAR)
|
||||||
{
|
{
|
||||||
tty->cmcr |= TIOCM_RTS;
|
if (tio.c_cflag & PARODD)
|
||||||
telnet_rfc2217_ctl(tty->tn, TNS_CTL_CTSRTS);
|
par = 4;
|
||||||
|
else
|
||||||
|
par = 5;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
else if (tio.c_cflag & PARENB)
|
||||||
|
par = 3;
|
||||||
|
else
|
||||||
|
par = 1;
|
||||||
|
telnet_rfc2217_cfg(tty->tn, TNS_SET_PARITY, &par, 1);
|
||||||
|
|
||||||
if (!(tty->cmcr & TIOCM_DTR) && _tio_baud(tio) != 0)
|
if (tio.c_cflag & CSTOPB)
|
||||||
|
sb = 2;
|
||||||
|
else
|
||||||
|
sb = 1;
|
||||||
|
telnet_rfc2217_cfg(tty->tn, TNS_SET_STOPSIZE, &sb, 1);
|
||||||
|
|
||||||
|
if (tio.c_cflag & CRTSCTS)
|
||||||
|
telnet_rfc2217_ctl(tty->tn, TNS_CTL_CTSRTS);
|
||||||
|
|
||||||
|
if (!(tty->cmcr & TIOCM_DTR) && speed != B0)
|
||||||
{
|
{
|
||||||
tty->cmcr |= TIOCM_DTR;
|
tty->cmcr |= TIOCM_DTR;
|
||||||
telnet_rfc2217_ctl(tty->tn, TNS_CTL_DTR_ON);
|
telnet_rfc2217_ctl(tty->tn, TNS_CTL_DTR_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
_show_termios("TCSETS", tio);
|
DBG("termios: %u%c%u%u %cCTSRTS %cCREAD %cHUPCL %cCLOCAL\n",
|
||||||
ioctl(tty->fds[FD_SLAVE].fd, cmd, tio);
|
baudrate(speed), pstr[par], csize, sb,
|
||||||
|
tio.c_cflag & CRTSCTS ? '+' : '-',
|
||||||
|
tio.c_cflag & CREAD ? '+' : '-',
|
||||||
|
tio.c_cflag & HUPCL ? '+' : '-',
|
||||||
|
tio.c_cflag & CLOCAL ? '+' : '-');
|
||||||
|
|
||||||
if (cmd == TCSETSF)
|
ioctl(tty->fds[FD_SLAVE].fd, cmd, &tio);
|
||||||
tty->slave_suspended = 0; /* Re-enable polling of Slave */
|
|
||||||
|
|
||||||
fuse_reply_ioctl(req, 0, 0, 0);
|
fuse_reply_ioctl(req, 0, 0, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TCGETS:
|
case TCGETS:
|
||||||
CHECK_BUF_OUT(sizeof(struct termios));
|
CHECK_BUF_OUT(sizeof(struct termios));
|
||||||
ioctl(tty->fds[FD_SLAVE].fd, TCGETS, tio);
|
fuse_reply_ioctl(req, 0, &tio, sizeof(struct termios));
|
||||||
_show_termios("TCGETS", tio);
|
|
||||||
fuse_reply_ioctl(req, 0, tio, sizeof(struct termios));
|
|
||||||
break;
|
break;
|
||||||
case TIOCINQ: /* Get the number of bytes in the input
|
case TIOCINQ: /* Get the number of bytes in the input
|
||||||
* buffer */
|
* buffer */
|
||||||
@@ -915,25 +708,33 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
|||||||
fuse_reply_ioctl(req, 0, &val, sizeof(int));
|
fuse_reply_ioctl(req, 0, &val, sizeof(int));
|
||||||
break;
|
break;
|
||||||
case TCFLSH:
|
case TCFLSH:
|
||||||
switch ((size_t) arg)
|
if (arg == TCIFLUSH)
|
||||||
{
|
{
|
||||||
default:
|
/*todo */
|
||||||
case TCIFLUSH:
|
|
||||||
byte = 1;
|
|
||||||
tty->slave_suspended = 0; /* Re-enable polling of Slave */
|
|
||||||
break;
|
|
||||||
case TCOFLUSH:
|
|
||||||
byte = 2;
|
|
||||||
tty->pollout = 1;
|
|
||||||
break;
|
|
||||||
case TCIOFLUSH:
|
|
||||||
byte = 3;
|
|
||||||
tty->slave_suspended = 0; /* Re-enable polling of Slave */
|
|
||||||
tty->pollout = 1;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
telnet_rfc2217_cfg(tty->tn, TNS_SET_PURGE, &byte, 1);
|
else if ((size_t) arg == TCOFLUSH)
|
||||||
ioctl(tty->fds[FD_SLAVE].fd, TCFLSH, arg);
|
{
|
||||||
|
/*todo */
|
||||||
|
}
|
||||||
|
else if ((size_t) arg == TCIOFLUSH)
|
||||||
|
{
|
||||||
|
/*todo */
|
||||||
|
}
|
||||||
|
fuse_reply_ioctl(req, 0, 0, 0);
|
||||||
|
break;
|
||||||
|
case TCIFLUSH:
|
||||||
|
val = 1;
|
||||||
|
telnet_rfc2217_cfg(tty->tn, TNS_SET_PURGE, &val, 1);
|
||||||
|
fuse_reply_ioctl(req, 0, 0, 0);
|
||||||
|
break;
|
||||||
|
case TCOFLUSH:
|
||||||
|
val = 2;
|
||||||
|
telnet_rfc2217_cfg(tty->tn, TNS_SET_PURGE, &val, 1);
|
||||||
|
fuse_reply_ioctl(req, 0, 0, 0);
|
||||||
|
break;
|
||||||
|
case TCIOFLUSH:
|
||||||
|
val = 3;
|
||||||
|
telnet_rfc2217_cfg(tty->tn, TNS_SET_PURGE, &val, 1);
|
||||||
fuse_reply_ioctl(req, 0, 0, 0);
|
fuse_reply_ioctl(req, 0, 0, 0);
|
||||||
break;
|
break;
|
||||||
case TIOCMGET:
|
case TIOCMGET:
|
||||||
@@ -988,9 +789,9 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
|||||||
TNS_CTL_RTS_ON : TNS_CTL_RTS_OFF);
|
TNS_CTL_RTS_ON : TNS_CTL_RTS_OFF);
|
||||||
goto show_mctl;
|
goto show_mctl;
|
||||||
show_mctl:
|
show_mctl:
|
||||||
DBG("MCR: RTS=%c DTR=%c\n",
|
DBG("MCR: DTR=%c RTS=%c\n",
|
||||||
tty->cmcr & TIOCM_RTS ? '1' : '0',
|
tty->cmcr & TIOCM_DTR ? '1' : '0',
|
||||||
tty->cmcr & TIOCM_DTR ? '1' : '0');
|
tty->cmcr & TIOCM_RTS ? '1' : '0');
|
||||||
break;
|
break;
|
||||||
case TCSBRK:
|
case TCSBRK:
|
||||||
fuse_reply_ioctl(req, 0, 0, 0);
|
fuse_reply_ioctl(req, 0, 0, 0);
|
||||||
@@ -1032,6 +833,7 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
|||||||
case TIOCSETD:
|
case TIOCSETD:
|
||||||
CHECK_BUF_IN(sizeof(int));
|
CHECK_BUF_IN(sizeof(int));
|
||||||
val = *(int *)in_buf;
|
val = *(int *)in_buf;
|
||||||
|
|
||||||
res = ioctl(tty->fds[FD_SLAVE].fd, TIOCSETD, &val);
|
res = ioctl(tty->fds[FD_SLAVE].fd, TIOCSETD, &val);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
fuse_reply_err(req, errno);
|
fuse_reply_err(req, errno);
|
||||||
@@ -1081,47 +883,34 @@ ttynvt_poll(fuse_req_t req, struct fuse_file_info *info,
|
|||||||
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||||
int revents = 0;
|
int revents = 0;
|
||||||
|
|
||||||
DBG2("%s: tty->pollin=%d tty->error/epipe=%d/%d\n",
|
|
||||||
__func__, tty->pollin, tty->error, tty->epipe);
|
|
||||||
|
|
||||||
_update_notify(tty, ph);
|
_update_notify(tty, ph);
|
||||||
|
|
||||||
if (tty->pollout)
|
|
||||||
{
|
|
||||||
revents = POLLOUT;
|
|
||||||
}
|
|
||||||
if (tty->pollin)
|
if (tty->pollin)
|
||||||
{
|
{
|
||||||
|
tty->pollin = 0;
|
||||||
revents |= POLLIN;
|
revents |= POLLIN;
|
||||||
}
|
}
|
||||||
if (tty->error)
|
if (tty->error)
|
||||||
{
|
{
|
||||||
if (tty->epipe == 0)
|
if (tty->epipe == 0)
|
||||||
revents |= POLLHUP | POLLIN;
|
revents = POLLHUP | POLLIN;
|
||||||
else
|
else
|
||||||
revents = 0;
|
revents = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG2("%s: revents=%#x\n", __func__, revents);
|
|
||||||
|
|
||||||
fuse_reply_poll(req, revents);
|
fuse_reply_poll(req, revents);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct cuse_lowlevel_ops ttynvt_op = {
|
static const struct cuse_lowlevel_ops ttynvt_op = {
|
||||||
.init = ttynvt_init,
|
.init = ttynvt_init,
|
||||||
.open = ttynvt_open,
|
.open = ttynvt_open,.read = ttynvt_read,.write = ttynvt_write,.ioctl =
|
||||||
.read = ttynvt_read,
|
ttynvt_ioctl,.poll = ttynvt_poll,.release = ttynvt_release,
|
||||||
.write = ttynvt_write,
|
|
||||||
.ioctl = ttynvt_ioctl,
|
|
||||||
.poll = ttynvt_poll,
|
|
||||||
.release = ttynvt_release,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TTYNET_OPT(t, p, v) { t, offsetof(struct ttynvt_param, p), v }
|
#define TTYNET_OPT(t, p, v) { t, offsetof(struct ttynvt_param, p), v }
|
||||||
|
|
||||||
static const struct fuse_opt ttynvt_opts[] = {
|
static const struct fuse_opt ttynvt_opts[] = {
|
||||||
TTYNET_OPT("-D %d", debug, 1),
|
TTYNET_OPT("-D %d", debug, 1),
|
||||||
TTYNET_OPT("-E", logstd, 1),
|
|
||||||
TTYNET_OPT("-M %u", major, 1),
|
TTYNET_OPT("-M %u", major, 1),
|
||||||
TTYNET_OPT("--maj=%u", major, 1),
|
TTYNET_OPT("--maj=%u", major, 1),
|
||||||
TTYNET_OPT("-m %u", minor, 1),
|
TTYNET_OPT("-m %u", minor, 1),
|
||||||
@@ -1139,7 +928,6 @@ static void print_help(void)
|
|||||||
{
|
{
|
||||||
fprintf(stderr, "ttynvt Usage:\n"
|
fprintf(stderr, "ttynvt Usage:\n"
|
||||||
"\t-D level\tEnable debug\n"
|
"\t-D level\tEnable debug\n"
|
||||||
"\t-E\t\tPrint debug to stdout (default is syslog)\n"
|
|
||||||
"\t-M major, --maj=major\n"
|
"\t-M major, --maj=major\n"
|
||||||
"\t-m minor, --min=minor\n"
|
"\t-m minor, --min=minor\n"
|
||||||
"\t-n name, --name=name (default: ttyNVT0)\n"
|
"\t-n name, --name=name (default: ttyNVT0)\n"
|
||||||
@@ -1221,14 +1009,14 @@ int main(int argc, char *argv[])
|
|||||||
switch (cpid)
|
switch (cpid)
|
||||||
{
|
{
|
||||||
case -1:
|
case -1:
|
||||||
_log(LOG_ERR, "fork(): %m\n");
|
_log(LOG_ERR, "fork(): %m");
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
case 0: /* Child */
|
case 0: /* Child */
|
||||||
DBG("Child proceeding...\n");
|
DBG("Child proceeding...\n");
|
||||||
rc = cuse_lowlevel_main(args.argc, args.argv, &ci, &ttynvt_op, NULL);
|
rc = cuse_lowlevel_main(args.argc, args.argv, &ci, &ttynvt_op, NULL);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
_log(LOG_ERR, "ttynvt failed rc=%d\n", rc);
|
_log(LOG_ERR, "ttynvt failed rc=%d", rc);
|
||||||
else
|
else
|
||||||
DBG("Child exited\n");
|
DBG("Child exited\n");
|
||||||
return rc;
|
return rc;
|
||||||
|
|||||||
Reference in New Issue
Block a user