=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/channels.c,v retrieving revision 1.72.2.6 retrieving revision 1.72.2.7 diff -u -r1.72.2.6 -r1.72.2.7 --- src/usr.bin/ssh/channels.c 2001/09/27 00:15:41 1.72.2.6 +++ src/usr.bin/ssh/channels.c 2001/11/15 00:14:59 1.72.2.7 @@ -39,7 +39,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: channels.c,v 1.72.2.6 2001/09/27 00:15:41 miod Exp $"); +RCSID("$OpenBSD: channels.c,v 1.72.2.7 2001/11/15 00:14:59 miod Exp $"); #include "ssh.h" #include "ssh1.h" @@ -133,7 +133,7 @@ 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); @@ -241,6 +241,7 @@ } /* Initialize and return new channel. */ c = channels[found] = xmalloc(sizeof(Channel)); + memset(c, 0, sizeof(Channel)); buffer_init(&c->input); buffer_init(&c->output); buffer_init(&c->extended); @@ -330,10 +331,6 @@ debug3("channel_free: status: %s", s); xfree(s); - 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_close_fds(c); @@ -358,22 +355,6 @@ 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. @@ -429,14 +410,18 @@ 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; } } @@ -970,7 +955,7 @@ int have, ret; have = buffer_len(&c->input); - + c->delayed = 0; debug2("channel %d: pre_dynamic: have %d", c->self, have); /* buffer_dump(&c->input); */ /* check if the fixed size part of the packet is in buffer. */ @@ -1129,11 +1114,18 @@ "to %.100s port %d requested.", c->listening_port, c->path, c->host_port); - rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ? - "forwarded-tcpip" : "direct-tcpip"; - nextstate = (c->host_port == 0 && - c->type != SSH_CHANNEL_RPORT_LISTENER) ? - SSH_CHANNEL_DYNAMIC : SSH_CHANNEL_OPENING; + if (c->type == SSH_CHANNEL_RPORT_LISTENER) { + nextstate = SSH_CHANNEL_OPENING; + rtype = "forwarded-tcpip"; + } else { + if (c->host_port == 0) { + nextstate = SSH_CHANNEL_DYNAMIC; + rtype = "dynamic-tcpip"; + } else { + nextstate = SSH_CHANNEL_OPENING; + rtype = "direct-tcpip"; + } + } addrlen = sizeof(addr); newsock = accept(c->sock, &addr, &addrlen); @@ -1154,8 +1146,16 @@ nc->host_port = c->host_port; strlcpy(nc->path, c->path, sizeof(nc->path)); - if (nextstate != SSH_CHANNEL_DYNAMIC) + if (nextstate == SSH_CHANNEL_DYNAMIC) { + /* + * do not call the channel_post handler until + * this flag has been reset by a pre-handler. + * otherwise the FD_ISSET calls might overflow + */ + nc->delayed = 1; + } else { port_open_helper(nc, rtype); + } } } @@ -1405,6 +1405,8 @@ static void channel_post_open_1(Channel *c, fd_set * readset, fd_set * writeset) { + if (c->delayed) + return; channel_handle_rfd(c, readset, writeset); channel_handle_wfd(c, readset, writeset); } @@ -1412,6 +1414,8 @@ static void channel_post_open_2(Channel *c, fd_set * readset, fd_set * writeset) { + if (c->delayed) + return; channel_handle_rfd(c, readset, writeset); channel_handle_wfd(c, readset, writeset); channel_handle_efd(c, readset, writeset); @@ -1512,7 +1516,29 @@ channel_handler_init_15(); } +/* gc dead channels */ static void +channel_garbage_collect(Channel *c) +{ + if (c == NULL) + return; + if (c->detach_user != NULL) { + if (!chan_is_dead(c, 0)) + return; + debug("channel %d: gc: notify user", c->self); + c->detach_user(c->self, NULL); + /* if we still have a callback */ + if (c->detach_user != NULL) + return; + debug("channel %d: gc: user detached", c->self); + } + if (!chan_is_dead(c, 1)) + return; + debug("channel %d: garbage collecting", c->self); + channel_free(c); +} + +static void channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) { static int did_init = 0; @@ -1529,24 +1555,7 @@ continue; if (ftab[c->type] != NULL) (*ftab[c->type])(c, readset, writeset); - if (chan_is_dead(c)) { - /* - * we have to remove the fd's from the select mask - * before the channels are free'd and the fd's are - * closed - */ - if (c->wfd != -1) - FD_CLR(c->wfd, writeset); - if (c->rfd != -1) - FD_CLR(c->rfd, readset); - if (c->efd != -1) { - if (c->extended_usage == CHAN_EXTENDED_READ) - FD_CLR(c->efd, readset); - if (c->extended_usage == CHAN_EXTENDED_WRITE) - FD_CLR(c->efd, writeset); - } - channel_free(c); - } + channel_garbage_collect(c); } } @@ -1617,7 +1626,7 @@ if (compat20 && (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) { /* XXX is this true? */ - debug2("channel %d: no data after CLOSE", c->self); + debug3("channel %d: will not send data after close", c->self); continue; } @@ -2036,6 +2045,12 @@ /* -- tcp forwarding */ + +void +channel_set_af(int af) +{ + IPv4or6 = af; +} /* * Initiate forwarding of connections to local port "port" through the secure