Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c80995256 | |||
| 299cfcabb5 | |||
| b47cb98a69 | |||
| cb6509861f | |||
| 2f0cea6f73 | |||
| 015da8a55e |
+129
-42
@@ -55,14 +55,17 @@ static struct ttynvt_param {
|
||||
typedef struct {
|
||||
pthread_mutex_t tty_lock;
|
||||
pthread_mutex_t poll_lock;
|
||||
pthread_mutex_t read_lock;
|
||||
pthread_mutex_t write_lock;
|
||||
pthread_mutex_t ioctl_lock;
|
||||
pthread_t ptid_poll;
|
||||
pthread_t ptid_read;
|
||||
|
||||
struct fuse_pollhandle *ph;
|
||||
|
||||
volatile int rel_pending;
|
||||
volatile int slave_suspended; /*waiting for application to read data */
|
||||
volatile int master_suspended; /*server is not ready to receive data */
|
||||
volatile int slave_suspended; /* Waiting for application to read data */
|
||||
volatile int master_suspended; /* Server is not ready to receive data */
|
||||
struct pollfd fds[3];
|
||||
|
||||
char net_buf[NET_BUF_SIZE];
|
||||
@@ -80,8 +83,18 @@ typedef struct {
|
||||
int epipe;
|
||||
|
||||
tn_ctx_t *tn;
|
||||
|
||||
int seq;
|
||||
struct ttynvt_cli_s *cli;
|
||||
} ttynvt_t;
|
||||
|
||||
static ttynvt_t *ptty = NULL;
|
||||
|
||||
typedef struct ttynvt_cli_s {
|
||||
int id;
|
||||
ttynvt_t *tty;
|
||||
struct ttynvt_cli_s *next;
|
||||
} ttynvt_cli_t;
|
||||
|
||||
static pthread_mutex_t access_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
@@ -114,7 +127,6 @@ static void ttynvt_interrupted(fuse_req_t req, void *data)
|
||||
pthread_kill(thread, SIGUSR2);
|
||||
}
|
||||
|
||||
|
||||
static void _ttynvt_sleep_us(unsigned int tus)
|
||||
{
|
||||
struct timespec ts;
|
||||
@@ -143,7 +155,6 @@ static int _check_dev(void)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void _fd_close(int fd)
|
||||
{
|
||||
if (fd >= 0)
|
||||
@@ -406,24 +417,49 @@ static void _ttynvt_ctx_destroy(ttynvt_t * tty)
|
||||
|
||||
static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
||||
{
|
||||
ttynvt_t *tty;
|
||||
ttynvt_t *tty = ptty;
|
||||
ttynvt_cli_t *tty_cli;
|
||||
char *slave_name;
|
||||
struct termios ios;
|
||||
int fd;
|
||||
int res;
|
||||
int n;
|
||||
|
||||
pthread_mutex_lock(&access_lock);
|
||||
|
||||
nvt_log(LOG_INFO, "Connecting to server: %s\n", ttynvt_param.server);
|
||||
|
||||
tty = _ttynvt_ctx_create();
|
||||
if (!tty)
|
||||
tty_cli = calloc(1, sizeof(ttynvt_cli_t));
|
||||
if (!tty_cli)
|
||||
{
|
||||
fuse_reply_err(req, ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&access_lock);
|
||||
|
||||
if (tty == NULL)
|
||||
tty = _ttynvt_ctx_create();
|
||||
if (!tty)
|
||||
{
|
||||
fuse_reply_err(req, ENOMEM);
|
||||
free(tty_cli);
|
||||
pthread_mutex_unlock(&access_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
tty_cli->id = tty->seq++;
|
||||
tty_cli->tty = tty;
|
||||
tty_cli->next = tty->cli;
|
||||
|
||||
tty->cli = tty_cli;
|
||||
|
||||
nvt_log(LOG_INFO, "Client open (%d)\n", tty_cli->id);
|
||||
|
||||
if (ptty)
|
||||
goto out;
|
||||
|
||||
ptty = tty;
|
||||
|
||||
nvt_log(LOG_INFO, "Connecting to server: %s\n", ttynvt_param.server);
|
||||
|
||||
fd = socket_create_client(ttynvt_param.server);
|
||||
if (fd < 0)
|
||||
{
|
||||
@@ -435,7 +471,7 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
||||
tty->fds[FD_NET].events = POLLIN;
|
||||
tty->net_cnt = 0;
|
||||
|
||||
if ((fd = open("/dev/ptmx", O_RDWR)) < 0) /* open master */
|
||||
if ((fd = open("/dev/ptmx", O_RDWR)) < 0) /* Open master */
|
||||
goto open_err;
|
||||
|
||||
tty->fds[FD_MASTER].fd = fd;
|
||||
@@ -453,11 +489,11 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
||||
if (ioctl(fd, TCSETS, &ios) < 0)
|
||||
goto open_err;
|
||||
|
||||
grantpt(fd); /* change permission of slave */
|
||||
unlockpt(fd); /* unlock slave */
|
||||
slave_name = ptsname(fd); /* get name of slave */
|
||||
grantpt(fd); /* Change permission of slave */
|
||||
unlockpt(fd); /* Unlock slave */
|
||||
slave_name = ptsname(fd); /* Get name of slave */
|
||||
|
||||
if ((fd = open(slave_name, O_RDWR | O_NOCTTY)) < 0) /* open slave */
|
||||
if ((fd = open(slave_name, O_RDWR | O_NOCTTY)) < 0) /* Open slave */
|
||||
goto open_err;
|
||||
|
||||
ioctl(fd, TCGETS, &tty->tio);
|
||||
@@ -478,26 +514,34 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
|
||||
|
||||
if ((res = pthread_mutex_init(&tty->tty_lock, NULL) < 0) ||
|
||||
(res = pthread_mutex_init(&tty->poll_lock, NULL) < 0) ||
|
||||
(res = pthread_mutex_init(&tty->ioctl_lock, NULL) < 0) ||
|
||||
(res = pthread_mutex_init(&tty->read_lock, NULL) < 0) ||
|
||||
(res = pthread_mutex_init(&tty->write_lock, NULL) < 0) ||
|
||||
(res = pthread_create(&tty->ptid_poll, NULL, &_read_net, tty)))
|
||||
{
|
||||
errno = res;
|
||||
goto open_err;
|
||||
}
|
||||
|
||||
info->fh = (uintptr_t) tty;
|
||||
nvt_log(LOG_INFO, "Connected to server: %s\n", ttynvt_param.server);
|
||||
|
||||
out:
|
||||
info->fh = (uintptr_t) tty_cli;
|
||||
info->nonseekable = 1;
|
||||
info->direct_io = 1;
|
||||
|
||||
nvt_log(LOG_INFO, "Connected to server: %s\n", ttynvt_param.server);
|
||||
|
||||
fuse_reply_open(req, info);
|
||||
|
||||
pthread_mutex_unlock(&access_lock);
|
||||
return;
|
||||
|
||||
open_err:
|
||||
for (n = 0; n < 3; n++)
|
||||
_fd_close(tty->fds[n].fd);
|
||||
|
||||
free(tty_cli);
|
||||
_ttynvt_ctx_destroy(tty);
|
||||
ptty = NULL;
|
||||
|
||||
fuse_reply_err(req, errno);
|
||||
|
||||
@@ -511,11 +555,14 @@ static void
|
||||
ttynvt_read(fuse_req_t req, size_t size, off_t off,
|
||||
struct fuse_file_info *info)
|
||||
{
|
||||
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||
ttynvt_cli_t *tty_cli = (ttynvt_cli_t *) (uintptr_t) info->fh;
|
||||
ttynvt_t *tty = tty_cli->tty;
|
||||
char buf[TMP_BUF_SIZE];
|
||||
int res, nr;
|
||||
|
||||
DBG2("%s\n", __func__);
|
||||
pthread_mutex_lock(&tty->read_lock);
|
||||
|
||||
DBG2("%s (%d)\n", __func__, tty_cli->id);
|
||||
|
||||
if (tty->error)
|
||||
{
|
||||
@@ -529,7 +576,7 @@ ttynvt_read(fuse_req_t req, size_t size, off_t off,
|
||||
else
|
||||
fuse_reply_err(req, EBADFD);
|
||||
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (size > TMP_BUF_SIZE)
|
||||
@@ -556,36 +603,42 @@ ttynvt_read(fuse_req_t req, size_t size, off_t off,
|
||||
{
|
||||
DBG2("%s: error: %m\n", __func__);
|
||||
fuse_reply_err(req, errno);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
DBG2("%s: fd=%d: sz=%u/%u: '%.*s'\n", __func__,
|
||||
tty->fds[FD_SLAVE].fd, res, (int)size, res, buf);
|
||||
DBG2("%s (%d): fd=%d: sz=%u/%u: '%.*s'\n", __func__,
|
||||
tty_cli->id, tty->fds[FD_SLAVE].fd, res, (int)size, res, buf);
|
||||
|
||||
fuse_reply_buf(req, buf, res);
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&tty->read_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
|
||||
struct fuse_file_info *info)
|
||||
{
|
||||
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||
ttynvt_cli_t *tty_cli = (ttynvt_cli_t *) (uintptr_t) info->fh;
|
||||
ttynvt_t *tty = tty_cli->tty;
|
||||
int res;
|
||||
|
||||
DBG2("%s: fd=%d: sz=%u: '%.*s'\n", __func__,
|
||||
tty->fds[FD_SLAVE].fd, (int)size, (int)size, data);
|
||||
pthread_mutex_lock(&tty->write_lock);
|
||||
|
||||
DBG2("%s (%d): fd=%d: sz=%u: '%.*s'\n", __func__,
|
||||
tty_cli->id, tty->fds[FD_SLAVE].fd, (int)size, (int)size, data);
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
fuse_reply_write(req, 0);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tty->error)
|
||||
{
|
||||
DBG2("%s: tty->error=%d\n", __func__, tty->error);
|
||||
fuse_reply_err(req, EPIPE);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = write(tty->fds[FD_SLAVE].fd, data, size);
|
||||
@@ -594,7 +647,7 @@ ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
|
||||
DBG2("%s: error: %m\n", __func__);
|
||||
tty->error = 1;
|
||||
fuse_reply_err(req, errno);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
else if (res != (int)size)
|
||||
{
|
||||
@@ -603,6 +656,9 @@ ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
|
||||
}
|
||||
|
||||
fuse_reply_write(req, res);
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&tty->write_lock);
|
||||
}
|
||||
|
||||
static int baudrate(speed_t speed)
|
||||
@@ -780,7 +836,8 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
||||
struct fuse_file_info *info, unsigned int flags,
|
||||
const void *in_buf, size_t in_bufsz, size_t out_bufsz)
|
||||
{
|
||||
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||
ttynvt_cli_t *tty_cli = (ttynvt_cli_t *) (uintptr_t) info->fh;
|
||||
ttynvt_t *tty = tty_cli->tty;
|
||||
struct termios2 *tio = &tty->tio;
|
||||
struct winsize ws;
|
||||
unsigned int tiocm, baud;
|
||||
@@ -790,14 +847,16 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
||||
uint8_t byte;
|
||||
uint32_t byte4;
|
||||
|
||||
DBG("%s: cmd=%s arg=%p ibuf=%p:%u obuf=:%u\n", __func__,
|
||||
_ioctl_name(cmd), arg, in_buf,
|
||||
pthread_mutex_lock(&tty->ioctl_lock);
|
||||
|
||||
DBG("%s (%d): cmd=%s arg=%p ibuf=%p:%u obuf=:%u\n", __func__,
|
||||
tty_cli->id, _ioctl_name(cmd), arg, in_buf,
|
||||
(unsigned int)in_bufsz, (unsigned int)out_bufsz);
|
||||
|
||||
if (ttynvt_param.raw)
|
||||
{
|
||||
fuse_reply_ioctl(req, 0, 0, 0);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (cmd)
|
||||
@@ -988,7 +1047,7 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
||||
if (res < 0)
|
||||
{
|
||||
fuse_reply_err(req, errno);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
fuse_reply_ioctl(req, 0, &ws, sizeof(struct winsize));
|
||||
break;
|
||||
@@ -999,7 +1058,7 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
||||
if (res < 0)
|
||||
{
|
||||
fuse_reply_err(req, errno);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
fuse_reply_ioctl(req, 0, &ws, sizeof(struct winsize));
|
||||
break;
|
||||
@@ -1060,17 +1119,21 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&tty->ioctl_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
ttynvt_poll(fuse_req_t req, struct fuse_file_info *info,
|
||||
struct fuse_pollhandle *ph)
|
||||
{
|
||||
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||
ttynvt_cli_t *tty_cli = (ttynvt_cli_t *) (uintptr_t) info->fh;
|
||||
ttynvt_t *tty = tty_cli->tty;
|
||||
int revents = 0;
|
||||
|
||||
DBG2("%s: tty->pollin=%d tty->error/epipe=%d/%d\n",
|
||||
__func__, tty->pollin, tty->error, tty->epipe);
|
||||
DBG2("%s (%d): tty->pollin=%d tty->error/epipe=%d/%d\n",
|
||||
__func__, tty_cli->id, tty->pollin, tty->error, tty->epipe);
|
||||
|
||||
_update_notify(tty, ph);
|
||||
|
||||
@@ -1097,16 +1160,38 @@ ttynvt_poll(fuse_req_t req, struct fuse_file_info *info,
|
||||
|
||||
static void ttynvt_release(fuse_req_t req, struct fuse_file_info *info)
|
||||
{
|
||||
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
|
||||
ttynvt_cli_t *tty_cli = (ttynvt_cli_t *) (uintptr_t) info->fh;
|
||||
ttynvt_t *tty = tty_cli->tty;
|
||||
ttynvt_cli_t *tmp, *prev;
|
||||
|
||||
DBG("%s\n", __func__);
|
||||
|
||||
pthread_mutex_lock(&access_lock);
|
||||
|
||||
for (tmp = tty->cli, prev = NULL; tmp; prev = tmp, tmp = tmp->next)
|
||||
if (tmp == tty_cli)
|
||||
{
|
||||
nvt_log(LOG_INFO, "Client release (%d)\n", tmp->id);
|
||||
if (prev)
|
||||
prev->next = tmp->next;
|
||||
else
|
||||
tty->cli = tmp->next;
|
||||
free(tmp);
|
||||
break;
|
||||
}
|
||||
|
||||
if (tty->cli)
|
||||
goto out;
|
||||
|
||||
tty->rel_pending = 1;
|
||||
|
||||
pthread_cancel(tty->ptid_poll);
|
||||
pthread_join(tty->ptid_poll, NULL);
|
||||
pthread_mutex_destroy(&tty->tty_lock);
|
||||
pthread_mutex_destroy(&tty->poll_lock);
|
||||
pthread_mutex_destroy(&tty->ioctl_lock);
|
||||
pthread_mutex_destroy(&tty->read_lock);
|
||||
pthread_mutex_destroy(&tty->write_lock);
|
||||
|
||||
if (ttynvt_param.close_delay_us)
|
||||
_ttynvt_sleep_us(ttynvt_param.close_delay_us);
|
||||
@@ -1119,11 +1204,13 @@ static void ttynvt_release(fuse_req_t req, struct fuse_file_info *info)
|
||||
fuse_pollhandle_destroy(tty->ph);
|
||||
|
||||
_ttynvt_ctx_destroy(tty);
|
||||
|
||||
fuse_reply_err(req, 0);
|
||||
ptty = NULL;
|
||||
|
||||
nvt_log(LOG_INFO, "Disconnected from server: %s\n", ttynvt_param.server);
|
||||
|
||||
out:
|
||||
fuse_reply_err(req, 0);
|
||||
|
||||
pthread_mutex_unlock(&access_lock);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user