SSH connection hanging on logout
John Bowman
bowman at math.ualberta.ca
Tue May 15 12:55:37 EST 2001
Here is a new version of the hang-on-exit patch, which:
1. fixes the hang-on-exit bug (without data loss);
2. does not exit if there are unterminated X applications;
3. exits the session when all X applications have closed.
Of these three tests, Openssh-2.9p1 only passes the second one. The
third one is another type of hanging bug in Openssh, as is demonstrated by
the following test:
ssh host
xterm -e sleep 20 &
exit
Even after the xsession terminates, the ssh session is left hanging forever.
The correct behaviour is to wait 20 seconds for the X application to close
and then exit.
-- John Bowman
University of Alberta
http://www.math.ualberta.ca/~bowman
diff -ur openssh-2.9p1/channels.c openssh-2.9p1J/channels.c
--- openssh-2.9p1/channels.c Tue Apr 17 12:14:35 2001
+++ openssh-2.9p1J/channels.c Mon May 14 20:51:14 2001
@@ -1137,6 +1137,10 @@
continue;
if (ftab[c->type] == NULL)
continue;
+ if(c->type == SSH_CHANNEL_OPEN && c->rfd == -1) {
+ c->type = SSH_CHANNEL_FREE;
+ continue;
+ }
(*ftab[c->type])(c, readset, writeset);
if (chan_is_dead(c)) {
/*
@@ -1639,6 +1643,47 @@
for (i = 0; i < channels_alloc; i++)
if (channels[i].type != SSH_CHANNEL_FREE)
channel_close_fds(&channels[i]);
+}
+
+/* Returns true if session is inactive. */
+
+int
+channel_inactive_session()
+{
+ u_int i;
+ if(channels_alloc == 0) return 0;
+
+ for (i = 0; i < channels_alloc; i++) {
+ switch (channels[i].type) {
+ case SSH_CHANNEL_FREE:
+ case SSH_CHANNEL_X11_LISTENER:
+ case SSH_CHANNEL_CLOSED:
+ break;
+ case SSH_CHANNEL_PORT_LISTENER:
+ case SSH_CHANNEL_RPORT_LISTENER:
+ case SSH_CHANNEL_AUTH_SOCKET:
+ case SSH_CHANNEL_DYNAMIC:
+ case SSH_CHANNEL_CONNECTING: /* XXX ??? */
+ return 0;
+ case SSH_CHANNEL_LARVAL:
+ if (!compat20)
+ fatal("cannot happen: SSH_CHANNEL_LARVAL");
+ return 0;
+ case SSH_CHANNEL_OPENING:
+ case SSH_CHANNEL_OPEN:
+ case SSH_CHANNEL_X11_OPEN:
+ return 0;
+ case SSH_CHANNEL_INPUT_DRAINING:
+ case SSH_CHANNEL_OUTPUT_DRAINING:
+ if (!compat13)
+ fatal("cannot happen: OUT_DRAIN");
+ return 0;
+ default:
+ fatal("channel_inactive_session: bad channel type %d", channels[i].type);
+ /* NOTREACHED */
+ }
+ }
+ return 1;
}
/* Returns true if any channel is still open. */
diff -ur openssh-2.9p1/channels.h openssh-2.9p1J/channels.h
--- openssh-2.9p1/channels.h Fri Apr 13 17:28:02 2001
+++ openssh-2.9p1J/channels.h Mon May 14 20:51:14 2001
@@ -197,6 +197,9 @@
*/
void channel_close_all(void);
+/* Returns true if session is inactive. */
+int channel_inactive_session();
+
/* Returns true if there is still an open channel over the connection. */
int channel_still_open(void);
diff -ur openssh-2.9p1/clientloop.c openssh-2.9p1J/clientloop.c
--- openssh-2.9p1/clientloop.c Fri Apr 20 06:50:51 2001
+++ openssh-2.9p1J/clientloop.c Mon May 14 20:51:14 2001
@@ -440,9 +440,13 @@
len = read(connection_in, buf, sizeof(buf));
if (len == 0) {
/* Received EOF. The remote host has closed the connection. */
- snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
- host);
- buffer_append(&stderr_buffer, buf, strlen(buf));
+/*
+ * This message duplicates the one already in client_loop().
+ *
+ * snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
+ * host);
+ * buffer_append(&stderr_buffer, buf, strlen(buf));
+ */
quit_pending = 1;
return;
}
diff -ur openssh-2.9p1/nchan.c openssh-2.9p1J/nchan.c
--- openssh-2.9p1/nchan.c Tue Apr 3 07:02:48 2001
+++ openssh-2.9p1J/nchan.c Mon May 14 20:51:14 2001
@@ -56,7 +56,7 @@
/* helper */
static void chan_shutdown_write(Channel *c);
-static void chan_shutdown_read(Channel *c);
+void chan_shutdown_read(Channel *c);
/*
* SSH1 specific implementation of event functions
@@ -479,7 +479,7 @@
c->wfd = -1;
}
}
-static void
+void
chan_shutdown_read(Channel *c)
{
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
diff -ur openssh-2.9p1/nchan.h openssh-2.9p1J/nchan.h
--- openssh-2.9p1/nchan.h Sun Mar 4 23:16:12 2001
+++ openssh-2.9p1J/nchan.h Mon May 14 20:51:14 2001
@@ -88,4 +88,5 @@
void chan_init_iostates(Channel * c);
void chan_init(void);
+void chan_shutdown_read(Channel *c);
#endif
diff -ur openssh-2.9p1/serverloop.c openssh-2.9p1J/serverloop.c
--- openssh-2.9p1/serverloop.c Fri Apr 13 17:28:03 2001
+++ openssh-2.9p1J/serverloop.c Mon May 14 20:51:14 2001
@@ -726,7 +726,7 @@
if (!rekeying)
channel_after_select(readset, writeset);
process_input(readset);
- if (connection_closed)
+ if (connection_closed || channel_inactive_session())
break;
process_output(writeset);
}
diff -ur openssh-2.9p1/session.c openssh-2.9p1J/session.c
--- openssh-2.9p1/session.c Wed Apr 18 09:29:34 2001
+++ openssh-2.9p1J/session.c Mon May 14 20:51:14 2001
@@ -1960,6 +1960,9 @@
*/
if (c->ostate != CHAN_OUTPUT_CLOSED)
chan_write_failed(c);
+ if (c->istate == CHAN_INPUT_OPEN && compat20) {
+ chan_shutdown_read(c);
+ }
s->chanid = -1;
}
More information about the openssh-unix-dev
mailing list