SSH connection hanging on logout
John Bowman
bowman at math.ualberta.ca
Fri May 18 14:52:38 EST 2001
> continue;
> if (ftab[c->type] == NULL)
> continue;
> + if(c->istate == CHAN_INPUT_OPEN && c->rfd == -1) {
> + int type=c->type;
> + c->type=SSH_CHANNEL_CLOSED;
> + if(channel_find_open() == -1)
> + shutdown(packet_get_connection_out(),
> + SHUT_RDWR);
^^^^^^^^
this cannot be correct. you may _not_ shutdown
the TCP connection. this breaks
ssh -N -L 1234:hostb:5678 hosta
> + c->type=type;
> + continue;
> + }
Ah yes, now I see what you mean...
The OpenSSH -N extension to SSH is supposed to hold the connection open
indefinitely (BTW, the man page doesn't make this explicit). That certainly
seems useful. Thanks, for pointing this out, Markus; I didn't understand
at first what you meant by "break".
Making use of the sleep (-S) option from the patch submitted earlier today,
this feature turned out to be easy to add to the hang-on-exit patch for Linux.
All I had to do was add the line
if(no_tty_flag && options.sleep < 0) options.sleep=0;
after the options are read in in ssh.c.
Here is the complete patch to 2.9p1 to fix all known hanging problems and
restore the desired behaviour with -N, without data loss, on Linux systems.
This includes my sleep patch and Markus' X-hang patch:
-- 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 Thu May 17 22:21:05 2001
@@ -1137,6 +1137,15 @@
continue;
if (ftab[c->type] == NULL)
continue;
+ if(c->istate == CHAN_INPUT_OPEN && c->rfd == -1) {
+ int type=c->type;
+ c->type=SSH_CHANNEL_CLOSED;
+ if(channel_find_open() == -1)
+ shutdown(packet_get_connection_out(),
+ SHUT_RDWR);
+ c->type=type;
+ continue;
+ }
(*ftab[c->type])(c, readset, writeset);
if (chan_is_dead(c)) {
/*
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 Thu May 17 22:25:45 2001
@@ -121,8 +121,8 @@
static int connection_in; /* Connection to server (input). */
static int connection_out; /* Connection to server (output). */
static int need_rekeying; /* Set to non-zero if rekeying is requested. */
-static int session_closed = 0; /* In SSH2: login session closed. */
-
+enum SessionStatus {SessionOpen, SessionClose, SessionWait};
+static int session_status = SessionOpen; /* In SSH2: login session closed. */
void client_init_dispatch(void);
int session_ident = -1;
@@ -324,6 +324,10 @@
client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
int *maxfdp, int rekeying)
{
+ struct timeval timer;
+ struct timeval *timerp;
+ int rc;
+
/* Add any selections by the channel mechanism. */
channel_prepare_select(readsetp, writesetp, maxfdp, rekeying);
@@ -346,7 +350,14 @@
if (buffer_len(&stderr_buffer) > 0)
FD_SET(fileno(stderr), *writesetp);
} else {
- FD_SET(connection_in, *readsetp);
+ /* channel_prepare_select could have closed the last channel */
+ if ((session_status == SessionClose)
+ && !channel_still_open()) {
+ if (!packet_have_data_to_write())
+ return;
+ } else {
+ FD_SET(connection_in, *readsetp);
+ }
}
/* Select server connection if have data to write to the server. */
@@ -362,7 +374,16 @@
* SSH_MSG_IGNORE packet when the timeout expires.
*/
- if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) {
+ if(session_status == SessionWait && options.sleep > 0) {
+ timer.tv_sec=options.sleep;
+ timer.tv_usec=0;
+ timerp=&timer;
+ } else {
+ timerp=NULL;
+ }
+
+ rc=select((*maxfdp)+1, *readsetp, *writesetp, NULL, timerp);
+ if (rc < 0) {
char buf[100];
/*
@@ -379,7 +400,8 @@
snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
buffer_append(&stderr_buffer, buf, strlen(buf));
quit_pending = 1;
- }
+ } else if (rc == 0 && session_status == SessionWait)
+ session_status=SessionClose;
}
void
@@ -440,9 +462,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;
}
@@ -751,7 +777,7 @@
if (id != session_ident)
error("client_channel_closed: id %d != session_ident %d",
id, session_ident);
- session_closed = 1;
+ session_status = (options.sleep >= 0) ? SessionWait : SessionClose;
if (in_raw_mode())
leave_raw_mode();
}
@@ -776,6 +802,7 @@
start_time = get_current_time();
/* Initialize variables. */
+ if(!have_pty) session_status=SessionWait;
escape_pending = 0;
last_was_cr = 1;
exit_status = -1;
@@ -840,7 +867,8 @@
/* Process buffered packets sent by the server. */
client_process_buffered_input_packets();
- if (compat20 && session_closed && !channel_still_open())
+ if (compat20 && (session_status == SessionClose)
+ && !channel_still_open())
break;
rekeying = (xxx_kex != NULL && !xxx_kex->done);
Only in openssh-2.9p1J: clientloop.c.orig
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 Thu May 17 22:21:05 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 Thu May 17 22:21:05 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/readconf.c openssh-2.9p1J/readconf.c
--- openssh-2.9p1/readconf.c Tue Apr 17 12:11:37 2001
+++ openssh-2.9p1J/readconf.c Thu May 17 22:21:05 2001
@@ -111,7 +111,7 @@
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
- oHostKeyAlgorithms
+ oHostKeyAlgorithms, oSleep
} OpCodes;
/* Textual representations of the tokens. */
@@ -177,6 +177,7 @@
{ "dynamicforward", oDynamicForward },
{ "preferredauthentications", oPreferredAuthentications },
{ "hostkeyalgorithms", oHostKeyAlgorithms },
+ { "sleep", oSleep },
{ NULL, 0 }
};
@@ -494,6 +495,10 @@
intptr = &options->connection_attempts;
goto parse_int;
+ case oSleep:
+ intptr = &options->sleep;
+ goto parse_int;
+
case oCipher:
intptr = &options->cipher;
arg = strdelim(&s);
@@ -761,6 +766,7 @@
options->num_remote_forwards = 0;
options->log_level = (LogLevel) - 1;
options->preferred_authentications = NULL;
+ options->sleep = -1;
}
/*
diff -ur openssh-2.9p1/readconf.h openssh-2.9p1J/readconf.h
--- openssh-2.9p1/readconf.h Tue Apr 17 12:11:37 2001
+++ openssh-2.9p1J/readconf.h Thu May 17 22:21:05 2001
@@ -97,6 +97,7 @@
/* Remote TCP/IP forward requests. */
int num_remote_forwards;
Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
+ int sleep; /* Exit delay in seconds */
} Options;
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 Thu May 17 22:21:05 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;
}
diff -ur openssh-2.9p1/ssh.c openssh-2.9p1J/ssh.c
--- openssh-2.9p1/ssh.c Tue Apr 17 12:14:35 2001
+++ openssh-2.9p1J/ssh.c Thu May 17 22:21:05 2001
@@ -182,6 +182,7 @@
fprintf(stderr, " -R listen-port:host:port Forward remote port to local address\n");
fprintf(stderr, " These cause %s to listen for connections on a port, and\n", __progname);
fprintf(stderr, " forward them to the other side by connecting to host:port.\n");
+ fprintf(stderr, " -S delay Set exit delay (in seconds; 0 means wait forever).\n");
fprintf(stderr, " -C Enable compression.\n");
fprintf(stderr, " -N Do not execute a shell or command.\n");
fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n");
@@ -318,7 +319,7 @@
opt = av[optind][1];
if (!opt)
usage();
- if (strchr("eilcmpLRDo", opt)) { /* options with arguments */
+ if (strchr("eilcmpLRSDo", opt)) { /* options with arguments */
optarg = av[optind] + 2;
if (strcmp(optarg, "") == 0) {
if (optind >= ac - 1)
@@ -488,7 +489,13 @@
}
add_local_forward(&options, fwd_port, buf, fwd_host_port);
break;
-
+ case 'S':
+ options.sleep = atoi(optarg);
+ if (options.sleep < 0) {
+ fprintf(stderr, "Bad delay value '%s'\n", optarg);
+ exit(1);
+ }
+ break;
case 'D':
fwd_port = a2port(optarg);
if (fwd_port == 0) {
@@ -526,6 +533,8 @@
if (!host)
usage();
+ if(no_tty_flag && options.sleep < 0) options.sleep=0;
+
SSLeay_add_all_algorithms();
ERR_load_crypto_strings();
More information about the openssh-unix-dev
mailing list