-/* $OpenBSD: channels.c,v 1.414 2022/03/15 05:27:37 djm Exp $ */
+/* $OpenBSD: channels.c,v 1.415 2022/03/30 21:10:25 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
c->io_want &= ~SSH_CHAN_IO_RFD;
c->io_ready &= ~SSH_CHAN_IO_RFD;
c->rfd = -1;
+ c->pfds[0] = -1;
}
if (*fdp == c->wfd) {
c->io_want &= ~SSH_CHAN_IO_WFD;
c->io_ready &= ~SSH_CHAN_IO_WFD;
c->wfd = -1;
+ c->pfds[1] = -1;
}
if (*fdp == c->efd) {
c->io_want &= ~SSH_CHAN_IO_EFD;
c->io_ready &= ~SSH_CHAN_IO_EFD;
c->efd = -1;
+ c->pfds[2] = -1;
}
if (*fdp == c->sock) {
c->io_want &= ~SSH_CHAN_IO_SOCK;
c->io_ready &= ~SSH_CHAN_IO_SOCK;
c->sock = -1;
+ c->pfds[3] = -1;
}
ret = close(fd);
u_int pollfd_offset, struct pollfd *pfd)
{
#ifdef DEBUG_CHANNEL_POLL
- debug3("%s: channel %d: rfd r%d w%d e%d s%d pfd[%u].fd=%d "
- "io_want 0x%02x pfd.ev 0x%02x io_ready 0x%02x pfd.rev 0x%02x",
- func, c->self, c->rfd, c->wfd, c->efd, c->sock, pollfd_offset,
- pfd->fd, c->io_want, pfd->events, c->io_ready, pfd->revents);
+ debug3("%s: channel %d: %s r%d w%d e%d s%d c->pfds [ %d %d %d %d ] "
+ "io_want 0x%02x io_ready 0x%02x pfd[%u].fd=%d "
+ "pfd.ev 0x%02x pfd.rev 0x%02x", func, c->self, what,
+ c->rfd, c->wfd, c->efd, c->sock,
+ c->pfds[0], c->pfds[1], c->pfds[2], c->pfds[3],
+ c->io_want, c->io_ready,
+ pollfd_offset, pfd->fd, pfd->events, pfd->revents);
#endif
}
channel_prepare_pollfd(Channel *c, u_int *next_pollfd,
struct pollfd *pfd, u_int npfd)
{
- u_int p = *next_pollfd;
+ u_int ev, p = *next_pollfd;
if (c == NULL)
return;
fatal_f("channel %d: bad pfd offset %u (max %u)",
c->self, p, npfd);
}
- c->pollfd_offset = -1;
+ c->pfds[0] = c->pfds[1] = c->pfds[2] = c->pfds[3] = -1;
/*
* prepare c->rfd
*
* IO too.
*/
if (c->rfd != -1) {
- if (c->pollfd_offset == -1)
- c->pollfd_offset = p;
- pfd[p].fd = c->rfd;
- pfd[p].events = 0;
+ ev = 0;
if ((c->io_want & SSH_CHAN_IO_RFD) != 0)
- pfd[p].events |= POLLIN;
+ ev |= POLLIN;
/* rfd == wfd */
- if (c->wfd == c->rfd &&
- (c->io_want & SSH_CHAN_IO_WFD) != 0)
- pfd[p].events |= POLLOUT;
+ if (c->wfd == c->rfd) {
+ if ((c->io_want & SSH_CHAN_IO_WFD) != 0)
+ ev |= POLLOUT;
+ }
/* rfd == efd */
- if (c->efd == c->rfd &&
- (c->io_want & SSH_CHAN_IO_EFD_R) != 0)
- pfd[p].events |= POLLIN;
- if (c->efd == c->rfd &&
- (c->io_want & SSH_CHAN_IO_EFD_W) != 0)
- pfd[p].events |= POLLOUT;
+ if (c->efd == c->rfd) {
+ if ((c->io_want & SSH_CHAN_IO_EFD_R) != 0)
+ ev |= POLLIN;
+ if ((c->io_want & SSH_CHAN_IO_EFD_W) != 0)
+ ev |= POLLOUT;
+ }
/* rfd == sock */
- if (c->sock == c->rfd &&
- (c->io_want & SSH_CHAN_IO_SOCK_R) != 0)
- pfd[p].events |= POLLIN;
- if (c->sock == c->rfd &&
- (c->io_want & SSH_CHAN_IO_SOCK_W) != 0)
- pfd[p].events |= POLLOUT;
- dump_channel_poll(__func__, "rfd", c, p, &pfd[p]);
- p++;
- }
- /* prepare c->wfd (if not already handled above) */
+ if (c->sock == c->rfd) {
+ if ((c->io_want & SSH_CHAN_IO_SOCK_R) != 0)
+ ev |= POLLIN;
+ if ((c->io_want & SSH_CHAN_IO_SOCK_W) != 0)
+ ev |= POLLOUT;
+ }
+ /* Pack a pfd entry if any event armed for this fd */
+ if (ev != 0) {
+ c->pfds[0] = p;
+ pfd[p].fd = c->rfd;
+ pfd[p].events = ev;
+ dump_channel_poll(__func__, "rfd", c, p, &pfd[p]);
+ p++;
+ }
+ }
+ /* prepare c->wfd if wanting IO and not already handled above */
if (c->wfd != -1 && c->rfd != c->wfd) {
- if (c->pollfd_offset == -1)
- c->pollfd_offset = p;
- pfd[p].fd = c->wfd;
- pfd[p].events = 0;
- if ((c->io_want & SSH_CHAN_IO_WFD) != 0)
- pfd[p].events = POLLOUT;
- dump_channel_poll(__func__, "wfd", c, p, &pfd[p]);
- p++;
- }
- /* prepare c->efd (if not already handled above) */
+ ev = 0;
+ if ((c->io_want & SSH_CHAN_IO_WFD))
+ ev |= POLLOUT;
+ /* Pack a pfd entry if any event armed for this fd */
+ if (ev != 0) {
+ c->pfds[1] = p;
+ pfd[p].fd = c->wfd;
+ pfd[p].events = ev;
+ dump_channel_poll(__func__, "wfd", c, p, &pfd[p]);
+ p++;
+ }
+ }
+ /* prepare c->efd if wanting IO and not already handled above */
if (c->efd != -1 && c->rfd != c->efd) {
- if (c->pollfd_offset == -1)
- c->pollfd_offset = p;
- pfd[p].fd = c->efd;
- pfd[p].events = 0;
+ ev = 0;
if ((c->io_want & SSH_CHAN_IO_EFD_R) != 0)
- pfd[p].events |= POLLIN;
+ ev |= POLLIN;
if ((c->io_want & SSH_CHAN_IO_EFD_W) != 0)
- pfd[p].events |= POLLOUT;
- dump_channel_poll(__func__, "efd", c, p, &pfd[p]);
- p++;
+ ev |= POLLOUT;
+ /* Pack a pfd entry if any event armed for this fd */
+ if (ev != 0) {
+ c->pfds[2] = p;
+ pfd[p].fd = c->efd;
+ pfd[p].events = ev;
+ dump_channel_poll(__func__, "efd", c, p, &pfd[p]);
+ p++;
+ }
}
- /* prepare c->sock (if not already handled above) */
+ /* prepare c->sock if wanting IO and not already handled above */
if (c->sock != -1 && c->rfd != c->sock) {
- if (c->pollfd_offset == -1)
- c->pollfd_offset = p;
- pfd[p].fd = c->sock;
- pfd[p].events = 0;
+ ev = 0;
if ((c->io_want & SSH_CHAN_IO_SOCK_R) != 0)
- pfd[p].events |= POLLIN;
+ ev |= POLLIN;
if ((c->io_want & SSH_CHAN_IO_SOCK_W) != 0)
- pfd[p].events |= POLLOUT;
- dump_channel_poll(__func__, "sock", c, p, &pfd[p]);
- p++;
+ ev |= POLLOUT;
+ /* Pack a pfd entry if any event armed for this fd */
+ if (ev != 0) {
+ c->pfds[3] = p;
+ pfd[p].fd = c->sock;
+ pfd[p].events = 0;
+ dump_channel_poll(__func__, "sock", c, p, &pfd[p]);
+ p++;
+ }
}
*next_pollfd = p;
}
}
static void
-fd_ready(Channel *c, u_int p, struct pollfd *pfds, int fd,
+fd_ready(Channel *c, int p, struct pollfd *pfds, u_int npfd, int fd,
const char *what, u_int revents_mask, u_int ready)
{
struct pollfd *pfd = &pfds[p];
if (fd == -1)
return;
+ if (p == -1 || (u_int)p >= npfd)
+ fatal_f("channel %d: bad pfd %d (max %u)", c->self, p, npfd);
dump_channel_poll(__func__, what, c, p, pfd);
if (pfd->fd != fd) {
fatal("channel %d: inconsistent %s fd=%d pollfd[%u].fd %d "
channel_after_poll(struct ssh *ssh, struct pollfd *pfd, u_int npfd)
{
struct ssh_channels *sc = ssh->chanctxt;
- u_int i, p;
+ u_int i;
+ int p;
Channel *c;
#ifdef DEBUG_CHANNEL_POLL
- for (p = 0; p < npfd; p++) {
+ for (p = 0; p < (int)npfd; p++) {
if (pfd[p].revents == 0)
continue;
debug_f("pfd[%u].fd %d rev 0x%04x",
/* Convert pollfd into c->io_ready */
for (i = 0; i < sc->channels_alloc; i++) {
c = sc->channels[i];
- if (c == NULL || c->pollfd_offset < 0)
+ if (c == NULL)
continue;
- if ((u_int)c->pollfd_offset >= npfd) {
- /* shouldn't happen */
- fatal_f("channel %d: (before) bad pfd %u (max %u)",
- c->self, c->pollfd_offset, npfd);
- }
/* if rfd is shared with efd/sock then wfd should be too */
if (c->rfd != -1 && c->wfd != -1 && c->rfd != c->wfd &&
(c->rfd == c->efd || c->rfd == c->sock)) {
c->self, c->rfd, c->wfd, c->efd, c->sock);
}
c->io_ready = 0;
- p = c->pollfd_offset;
/* rfd, potentially shared with wfd, efd and sock */
- if (c->rfd != -1) {
- fd_ready(c, p, pfd, c->rfd, "rfd", POLLIN,
- SSH_CHAN_IO_RFD);
+ if (c->rfd != -1 && (p = c->pfds[0]) != -1) {
+ fd_ready(c, p, pfd, npfd, c->rfd,
+ "rfd", POLLIN, SSH_CHAN_IO_RFD);
if (c->rfd == c->wfd) {
- fd_ready(c, p, pfd, c->wfd, "wfd/r", POLLOUT,
- SSH_CHAN_IO_WFD);
+ fd_ready(c, p, pfd, npfd, c->wfd,
+ "wfd/r", POLLOUT, SSH_CHAN_IO_WFD);
}
if (c->rfd == c->efd) {
- fd_ready(c, p, pfd, c->efd, "efdr/r", POLLIN,
- SSH_CHAN_IO_EFD_R);
- fd_ready(c, p, pfd, c->efd, "efdw/r", POLLOUT,
- SSH_CHAN_IO_EFD_W);
+ fd_ready(c, p, pfd, npfd, c->efd,
+ "efdr/r", POLLIN, SSH_CHAN_IO_EFD_R);
+ fd_ready(c, p, pfd, npfd, c->efd,
+ "efdw/r", POLLOUT, SSH_CHAN_IO_EFD_W);
}
if (c->rfd == c->sock) {
- fd_ready(c, p, pfd, c->sock, "sockr/r", POLLIN,
- SSH_CHAN_IO_SOCK_R);
- fd_ready(c, p, pfd, c->sock, "sockw/r", POLLOUT,
- SSH_CHAN_IO_SOCK_W);
+ fd_ready(c, p, pfd, npfd, c->sock,
+ "sockr/r", POLLIN, SSH_CHAN_IO_SOCK_R);
+ fd_ready(c, p, pfd, npfd, c->sock,
+ "sockw/r", POLLOUT, SSH_CHAN_IO_SOCK_W);
}
- p++;
+ dump_channel_poll(__func__, "rfd", c, p, pfd);
}
/* wfd */
- if (c->wfd != -1 && c->wfd != c->rfd) {
- fd_ready(c, p, pfd, c->wfd, "wfd", POLLOUT,
- SSH_CHAN_IO_WFD);
- p++;
+ if (c->wfd != -1 && c->wfd != c->rfd &&
+ (p = c->pfds[1]) != -1) {
+ fd_ready(c, p, pfd, npfd, c->wfd,
+ "wfd", POLLOUT, SSH_CHAN_IO_WFD);
+ dump_channel_poll(__func__, "wfd", c, p, pfd);
}
/* efd */
- if (c->efd != -1 && c->efd != c->rfd) {
- fd_ready(c, p, pfd, c->efd, "efdr", POLLIN,
- SSH_CHAN_IO_EFD_R);
- fd_ready(c, p, pfd, c->efd, "efdw", POLLOUT,
- SSH_CHAN_IO_EFD_W);
- p++;
+ if (c->efd != -1 && c->efd != c->rfd &&
+ (p = c->pfds[2]) != -1) {
+ fd_ready(c, p, pfd, npfd, c->efd,
+ "efdr", POLLIN, SSH_CHAN_IO_EFD_R);
+ fd_ready(c, p, pfd, npfd, c->efd,
+ "efdw", POLLOUT, SSH_CHAN_IO_EFD_W);
+ dump_channel_poll(__func__, "efd", c, p, pfd);
}
/* sock */
- if (c->sock != -1 && c->sock != c->rfd) {
- fd_ready(c, p, pfd, c->sock, "sockr", POLLIN,
- SSH_CHAN_IO_SOCK_R);
- fd_ready(c, p, pfd, c->sock, "sockw", POLLOUT,
- SSH_CHAN_IO_SOCK_W);
- p++;
- }
-
- if (p > npfd) {
- /* shouldn't happen */
- fatal_f("channel %d: (after) bad pfd %u (max %u)",
- c->self, c->pollfd_offset, npfd);
+ if (c->sock != -1 && c->sock != c->rfd &&
+ (p = c->pfds[3]) != -1) {
+ fd_ready(c, p, pfd, npfd, c->sock,
+ "sockr", POLLIN, SSH_CHAN_IO_SOCK_R);
+ fd_ready(c, p, pfd, npfd, c->sock,
+ "sockw", POLLOUT, SSH_CHAN_IO_SOCK_W);
+ dump_channel_poll(__func__, "sock", c, p, pfd);
}
}
channel_handler(ssh, CHAN_POST, NULL);