8 Commits

Author SHA1 Message Date
Kim Woelders 3cad2c060d ttynvt version 0.13 2018-10-25 11:24:45 +02:00
Kim Woelders 89f8ec8018 Reorder MCR debug printouts
More logical, IMO...
2018-10-25 11:19:46 +02:00
Kim Woelders de0845a9ce Consistently use DCD, not CD 2018-10-25 11:18:45 +02:00
Kim Woelders 732eb8da25 Refactor termios parsing for rfc2217 and debug
And show the termios on TCGETS too.
2018-10-25 11:18:45 +02:00
Kim Woelders 0f95e0779e Avoid close error on FD_MASTER after DCD drop 2018-10-25 11:18:45 +02:00
Kim Woelders 0cc9b58a65 Close master pty on DCD drop if not CLOCAL 2018-10-25 11:18:24 +02:00
Kim Woelders 314e4b1b99 Flushing ioctl fixups
- Propagate TCFLSH to slave.
- Actually send flush requests to server.
- TCIFLUSH, TCOFLUSH, and TCIOFLUSH are not ioctls but TCFLSH arguments.
- Re-enable read polls if input is flushed.
2018-10-25 07:27:21 +02:00
Kim Woelders effca015a8 Fix running on big endian
RFC2217 options with one byte values were always sent with value = 0.
2018-10-25 07:27:21 +02:00
4 changed files with 145 additions and 94 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
m4_define([pkg_version], [0.12])
m4_define([pkg_version], [0.13])
#m4_define([pkg_revision], [005])
m4_define([pkg_version], m4_ifdef([pkg_revision], [pkg_version.pkg_revision], [pkg_version]))
+2 -2
View File
@@ -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,
const void *val, int nd);
extern void telnet_rfc2217_ctl(tn_ctx_t * tcc, int cmd);
extern void telnet_rfc2217_ctl(tn_ctx_t * tcc, unsigned int val);
/*RFC2217 modem state*/
#define TNS_STATE_CD 0x80
#define TNS_STATE_DCD 0x80
#define TNS_STATE_RI 0x40
#define TNS_STATE_DSR 0x20
#define TNS_STATE_CTS 0x10
+4 -2
View File
@@ -43,10 +43,12 @@ void telnet_rfc2217_cfg(tn_ctx_t * tcc, int cmd, const void *val, int nd)
telnet_set_opt(tcc, TNO_CPCO, cmd, val, nd);
}
void telnet_rfc2217_ctl(tn_ctx_t * tcc, int cmd)
void telnet_rfc2217_ctl(tn_ctx_t * tcc, unsigned int val)
{
unsigned char byte = val;
if (!tcc->mode_rfc2217)
return;
telnet_set_opt(tcc, TNO_CPCO, TNS_SET_CONTROL, &cmd, 1);
telnet_set_opt(tcc, TNO_CPCO, TNS_SET_CONTROL, &byte, 1);
}
+134 -85
View File
@@ -69,8 +69,9 @@ typedef struct {
struct termios tio;
int cmcr;
volatile int smcr;
int cmcr; /* Commanded by ioctl */
volatile int smcr; /* Status from modem */
int smcr_last;
volatile int pollin;
volatile int error;
@@ -131,6 +132,12 @@ void _log_buf(int prio, const char *txt, const void *ptr_, unsigned int len)
#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)
@@ -183,9 +190,9 @@ static void ttynvt_release(fuse_req_t req, struct fuse_file_info *info)
_log(LOG_INFO, "connection closed\n");
tty->n_fds = 0;
close(tty->fds[FD_NET].fd);
close(tty->fds[FD_MASTER].fd);
close(tty->fds[FD_SLAVE].fd);
_fd_close(tty->fds[FD_NET].fd);
_fd_close(tty->fds[FD_MASTER].fd);
_fd_close(tty->fds[FD_SLAVE].fd);
pthread_cancel(tty->ptid_poll);
pthread_join(tty->ptid_poll, NULL);
@@ -223,6 +230,22 @@ static void _update_notify(ttynvt_t * tty, struct fuse_pollhandle *ph)
fuse_pollhandle_destroy(tmp_ph);
}
static int _net_read_check_exit(ttynvt_t * tty)
{
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)
{
ttynvt_t *tty = (ttynvt_t *) arg;
@@ -280,6 +303,8 @@ static void *_read_net(void *arg)
}
tty->net_cnt = 0;
}
if (_net_read_check_exit(tty))
break;
}
if (tty->fds[FD_MASTER].revents & POLLIN)
@@ -404,21 +429,21 @@ static void _modem_status_cb(void *cctx, int status)
ttynvt_t *tty = cctx;
int mcr = 0;
DBG("MCR: DSR=%c CTS=%c RI=%c CD=%c\n",
status & TNS_STATE_DSR ? '1' : '0',
status & TNS_STATE_CTS ? '1' : '0',
status & TNS_STATE_RI ? '1' : '0', status & TNS_STATE_CD ? '1' : '0');
DBG("MCR: CTS=%c DSR=%c RI=%c DCD=%c\n",
status & TNS_STATE_CTS ? '1' : '0', status & TNS_STATE_DSR ? '1' : '0',
status & TNS_STATE_RI ? '1' : '0', status & TNS_STATE_DCD ? '1' : '0');
if (status & TNS_STATE_CD)
if (status & TNS_STATE_DCD)
mcr |= TIOCM_CD;
if (status & TNS_STATE_RI)
mcr |= TIOCM_RI;
if (status & TNS_STATE_CTS)
mcr |= TIOCM_CTS;
if (status & TNS_STATE_DSR)
mcr |= TIOCM_DSR;
if (status & TNS_STATE_CTS)
mcr |= TIOCM_CTS;
pthread_mutex_lock(&tty->tty_lock);
tty->smcr_last = tty->smcr;
tty->smcr = mcr;
pthread_mutex_unlock(&tty->tty_lock);
}
@@ -536,8 +561,7 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
ttynvt_param.host, ttynvt_param.port);
for (n = 0; n < 3; n++)
if (tty->fds[n].fd >= 0)
close(tty->fds[n].fd);
_fd_close(tty->fds[n].fd);
free(tty->tn);
free(tty);
@@ -665,9 +689,6 @@ static const char *_ioctl_name(int cmd)
CASE(TIOCINQ);
CASE(TIOCOUTQ);
CASE(TCFLSH);
CASE(TCIFLUSH);
CASE(TCOFLUSH);
CASE(TCIOFLUSH);
CASE(TIOCMGET);
CASE(TIOCMBIS);
CASE(TIOCMBIC);
@@ -690,6 +711,71 @@ 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) \
if (in_bufsz < sz) do { in_bufsz = sz; goto retry_in; } while(0)
#define CHECK_BUF_OUT(sz) \
@@ -707,6 +793,8 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
int mcr;
int val;
int res;
unsigned char byte;
unsigned int byte4;
DBG("%s: cmd=%s arg=%p ibuf=%p:%u obuf=:%u\n", __func__,
_ioctl_name(cmd), arg, in_buf,
@@ -719,47 +807,19 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
case TCSETS:
CHECK_BUF_IN(sizeof(struct termios));
{
speed_t speed;
int csize, par, sb;
memcpy(tio, in_buf, in_bufsz);
speed = tio->c_cflag & (CBAUD | CBAUDEX);
val = htonl(baudrate(speed));
telnet_rfc2217_cfg(tty->tn, TNS_SET_BAUDRATE, &val, 4);
byte4 = htonl(_tio_baud(tio));
telnet_rfc2217_cfg(tty->tn, TNS_SET_BAUDRATE, &byte4, 4);
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;
telnet_rfc2217_cfg(tty->tn, TNS_SET_DATASIZE, &csize, 1);
byte = _tio_csize(tio);
telnet_rfc2217_cfg(tty->tn, TNS_SET_DATASIZE, &byte, 1);
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;
telnet_rfc2217_cfg(tty->tn, TNS_SET_PARITY, &par, 1);
byte = _tio_parity(tio);
telnet_rfc2217_cfg(tty->tn, TNS_SET_PARITY, &byte, 1);
if (tio->c_cflag & CSTOPB)
sb = 2;
else
sb = 1;
telnet_rfc2217_cfg(tty->tn, TNS_SET_STOPSIZE, &sb, 1);
byte = _tio_stopb(tio);
telnet_rfc2217_cfg(tty->tn, TNS_SET_STOPSIZE, &byte, 1);
if (tio->c_cflag & CRTSCTS)
{
@@ -767,26 +827,25 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
telnet_rfc2217_ctl(tty->tn, TNS_CTL_CTSRTS);
}
if (!(tty->cmcr & TIOCM_DTR) && speed != B0)
if (!(tty->cmcr & TIOCM_DTR) && _tio_baud(tio) != 0)
{
tty->cmcr |= TIOCM_DTR;
telnet_rfc2217_ctl(tty->tn, TNS_CTL_DTR_ON);
}
DBG("termios: %u%c%u%u %cCTSRTS %cCREAD %cHUPCL %cCLOCAL\n",
baudrate(speed), pstr[par], csize, sb,
tio->c_cflag & CRTSCTS ? '+' : '-',
tio->c_cflag & CREAD ? '+' : '-',
tio->c_cflag & HUPCL ? '+' : '-',
tio->c_cflag & CLOCAL ? '+' : '-');
_show_termios("TCSETS", tio);
ioctl(tty->fds[FD_SLAVE].fd, cmd, tio);
if (cmd == TCSETSF)
tty->n_fds = 3; /* Re-enable polling of Slave */
fuse_reply_ioctl(req, 0, 0, 0);
}
break;
case TCGETS:
CHECK_BUF_OUT(sizeof(struct termios));
ioctl(tty->fds[FD_SLAVE].fd, TCGETS, tio);
_show_termios("TCGETS", tio);
fuse_reply_ioctl(req, 0, tio, sizeof(struct termios));
break;
case TIOCINQ: /* Get the number of bytes in the input
@@ -802,33 +861,23 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
fuse_reply_ioctl(req, 0, &val, sizeof(int));
break;
case TCFLSH:
if (arg == TCIFLUSH)
switch ((size_t) arg)
{
/*todo */
}
else if ((size_t) arg == TCOFLUSH)
{
/*todo */
}
else if ((size_t) arg == TCIOFLUSH)
{
/*todo */
}
fuse_reply_ioctl(req, 0, 0, 0);
break;
default:
case TCIFLUSH:
val = 1;
telnet_rfc2217_cfg(tty->tn, TNS_SET_PURGE, &val, 1);
fuse_reply_ioctl(req, 0, 0, 0);
byte = 1;
tty->n_fds = 3; /* Re-enable polling of Slave */
break;
case TCOFLUSH:
val = 2;
telnet_rfc2217_cfg(tty->tn, TNS_SET_PURGE, &val, 1);
fuse_reply_ioctl(req, 0, 0, 0);
byte = 2;
break;
case TCIOFLUSH:
val = 3;
telnet_rfc2217_cfg(tty->tn, TNS_SET_PURGE, &val, 1);
byte = 3;
tty->n_fds = 3; /* Re-enable polling of Slave */
break;
}
telnet_rfc2217_cfg(tty->tn, TNS_SET_PURGE, &byte, 1);
ioctl(tty->fds[FD_SLAVE].fd, TCFLSH, arg);
fuse_reply_ioctl(req, 0, 0, 0);
break;
case TIOCMGET:
@@ -883,9 +932,9 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
TNS_CTL_RTS_ON : TNS_CTL_RTS_OFF);
goto show_mctl;
show_mctl:
DBG("MCR: DTR=%c RTS=%c\n",
tty->cmcr & TIOCM_DTR ? '1' : '0',
tty->cmcr & TIOCM_RTS ? '1' : '0');
DBG("MCR: RTS=%c DTR=%c\n",
tty->cmcr & TIOCM_RTS ? '1' : '0',
tty->cmcr & TIOCM_DTR ? '1' : '0');
break;
case TCSBRK:
fuse_reply_ioctl(req, 0, 0, 0);