*/
#include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.129 2001/06/29 18:40:28 stevesk Exp $");
+RCSID("$OpenBSD: channels.c,v 1.136 2001/10/04 15:05:40 markus Exp $");
#include "ssh.h"
#include "ssh1.h"
static char *auth_sock_dir = NULL;
/* AF_UNSPEC or AF_INET or AF_INET6 */
-extern int IPv4or6;
+static int IPv4or6 = AF_UNSPEC;
/* helper */
static void port_open_helper(Channel *c, char *rtype);
c->cb_fn = NULL;
c->cb_arg = NULL;
c->cb_event = 0;
- c->dettach_user = NULL;
+ c->force_drain = 0;
+ c->detach_user = NULL;
c->input_filter = NULL;
debug("channel %d: new [%s]", found, remote_name);
return c;
}
+static int
+channel_find_maxfd(void)
+{
+ int i, max = 0;
+ Channel *c;
+
+ for (i = 0; i < channels_alloc; i++) {
+ c = channels[i];
+ if (c != NULL) {
+ max = MAX(max, c->rfd);
+ max = MAX(max, c->wfd);
+ max = MAX(max, c->efd);
+ }
+ }
+ return max;
+}
+
+int
+channel_close_fd(int *fdp)
+{
+ int ret = 0, fd = *fdp;
+
+ if (fd != -1) {
+ ret = close(fd);
+ *fdp = -1;
+ if (fd == channel_max_fd)
+ channel_max_fd = channel_find_maxfd();
+ }
+ return ret;
+}
+
/* Close all channel fd/socket. */
static void
debug3("channel_close_fds: channel %d: r %d w %d e %d",
c->self, c->rfd, c->wfd, c->efd);
- if (c->sock != -1) {
- close(c->sock);
- c->sock = -1;
- }
- if (c->rfd != -1) {
- close(c->rfd);
- c->rfd = -1;
- }
- if (c->wfd != -1) {
- close(c->wfd);
- c->wfd = -1;
- }
- if (c->efd != -1) {
- close(c->efd);
- c->efd = -1;
- }
+ channel_close_fd(&c->sock);
+ channel_close_fd(&c->rfd);
+ channel_close_fd(&c->wfd);
+ channel_close_fd(&c->efd);
}
/* Free the channel and close its fd/socket. */
debug3("channel_free: status: %s", s);
xfree(s);
- if (c->dettach_user != NULL) {
- debug("channel_free: channel %d: dettaching channel user", c->self);
- c->dettach_user(c->self, NULL);
+ if (c->detach_user != NULL) {
+ debug("channel_free: channel %d: detaching channel user", c->self);
+ c->detach_user(c->self, NULL);
}
if (c->sock != -1)
shutdown(c->sock, SHUT_RDWR);
channel_free(channels[i]);
}
+void
+channel_detach_all(void)
+{
+ int i;
+ Channel *c;
+
+ for (i = 0; i < channels_alloc; i++) {
+ c = channels[i];
+ if (c != NULL && c->detach_user != NULL) {
+ debug("channel_detach_all: channel %d", c->self);
+ c->detach_user(c->self, NULL);
+ c->detach_user = NULL;
+ }
+ }
+}
+
/*
* Closes the sockets/fds of all channels. This is used to close extra file
* descriptors after a fork.
channel_close_fds(channels[i]);
}
+/*
+ * Stop listening to channels.
+ */
+
+void
+channel_stop_listening(void)
+{
+ int i;
+ Channel *c;
+
+ for (i = 0; i < channels_alloc; i++) {
+ c = channels[i];
+ if (c != NULL) {
+ switch (c->type) {
+ case SSH_CHANNEL_AUTH_SOCKET:
+ case SSH_CHANNEL_PORT_LISTENER:
+ case SSH_CHANNEL_RPORT_LISTENER:
+ case SSH_CHANNEL_X11_LISTENER:
+ channel_close_fd(&c->sock);
+ channel_free(c);
+ break;
+ }
+ }
+ }
+}
+
/*
* Returns true if no channel has too much buffered data, and false if one or
* more channel is overfull.
for (i = 0; i < channels_alloc; i++) {
c = channels[i];
if (c != NULL && c->type == SSH_CHANNEL_OPEN) {
- if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) {
+#if 0
+ if (!compat20 &&
+ buffer_len(&c->input) > packet_get_maxsize()) {
debug("channel %d: big input buffer %d",
c->self, buffer_len(&c->input));
return 0;
}
+#endif
if (buffer_len(&c->output) > packet_get_maxsize()) {
- debug("channel %d: big output buffer %d",
- c->self, buffer_len(&c->output));
+ debug("channel %d: big output buffer %d > %d",
+ c->self, buffer_len(&c->output),
+ packet_get_maxsize());
return 0;
}
}
log("channel_register_cleanup: %d: bad id", id);
return;
}
- c->dettach_user = fn;
+ c->detach_user = fn;
}
void
channel_cancel_cleanup(int id)
log("channel_cancel_cleanup: %d: bad id", id);
return;
}
- c->dettach_user = NULL;
+ c->detach_user = NULL;
}
void
channel_register_filter(int id, channel_filter_fn *fn)
log("X11 connection rejected because of wrong authentication.");
buffer_clear(&c->input);
buffer_clear(&c->output);
- close(c->sock);
+ channel_close_fd(&c->sock);
c->sock = -1;
c->type = SSH_CHANNEL_CLOSED;
packet_start(SSH_MSG_CHANNEL_CLOSE);
channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset)
{
int ret = x11_open_helper(&c->output);
+
+ /* c->force_drain = 1; */
+
if (ret == 1) {
c->type = SSH_CHANNEL_OPEN;
if (compat20)
channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset)
{
struct termios tio;
+ u_char *data;
+ u_int dlen;
int len;
/* Send buffered output data to the socket. */
if (c->wfd != -1 &&
FD_ISSET(c->wfd, writeset) &&
buffer_len(&c->output) > 0) {
- len = write(c->wfd, buffer_ptr(&c->output),
- buffer_len(&c->output));
+ data = buffer_ptr(&c->output);
+ dlen = buffer_len(&c->output);
+ len = write(c->wfd, data, dlen);
if (len < 0 && (errno == EINTR || errno == EAGAIN))
return 1;
if (len <= 0) {
}
return -1;
}
- if (compat20 && c->isatty) {
+ if (compat20 && c->isatty && dlen >= 1 && data[0] != '\r') {
if (tcgetattr(c->wfd, &tio) == 0 &&
!(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
/*
if (len <= 0) {
debug2("channel %d: closing write-efd %d",
c->self, c->efd);
- close(c->efd);
- c->efd = -1;
+ channel_close_fd(&c->efd);
} else {
buffer_consume(&c->extended, len);
c->local_consumed += len;
if (len <= 0) {
debug2("channel %d: closing read-efd %d",
c->self, c->efd);
- close(c->efd);
- c->efd = -1;
+ channel_close_fd(&c->efd);
} else {
buffer_append(&c->extended, buf, len);
}
*/
void
channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
- int rekeying)
+ int *nallocp, int rekeying)
{
int n;
u_int sz;
n = MAX(*maxfdp, channel_max_fd);
sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
- if (*readsetp == NULL || n > *maxfdp) {
- if (*readsetp)
- xfree(*readsetp);
- if (*writesetp)
- xfree(*writesetp);
- *readsetp = xmalloc(sz);
- *writesetp = xmalloc(sz);
- *maxfdp = n;
+ /* perhaps check sz < nalloc/2 and shrink? */
+ if (*readsetp == NULL || sz > *nallocp) {
+ *readsetp = xrealloc(*readsetp, sz);
+ *writesetp = xrealloc(*writesetp, sz);
+ *nallocp = sz;
}
+ *maxfdp = n;
memset(*readsetp, 0, sz);
memset(*writesetp, 0, sz);
if (c == NULL)
packet_disconnect("Received ieof for nonexistent channel %d.", id);
chan_rcvd_ieof(c);
+
+ /* XXX force input close */
+ if (c->force_drain) {
+ debug("channel %d: FORCE input drain", c->self);
+ c->istate = CHAN_INPUT_WAIT_DRAIN;
+ }
+
}
void
/* -- tcp forwarding */
+void
+channel_set_af(int af)
+{
+ IPv4or6 = af;
+}
+
/*
* Initiate forwarding of connections to local port "port" through the secure
* channel to host:port from remote side.
}
int
-channel_connect_by_listen_adress(u_short listen_port)
+channel_connect_by_listen_address(u_short listen_port)
{
int i;
close(sock);
} else {
c->remote_id = remote_id;
+ c->force_drain = 1;
}
}
if (c == NULL) {
close(sock);
} else {
c->remote_id = remote_id;
+ c->force_drain = 1;
}
}
if (c == NULL) {