summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog2
-rw-r--r--TODO16
-rw-r--r--serverloop.c17
3 files changed, 17 insertions, 18 deletions
diff --git a/ChangeLog b/ChangeLog
index 8c182d6c..0366d260 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -12,6 +12,8 @@
- Fix rresvport_af failure errors (logic error in bsd-bindresvport.c)
- Fix --with-ipaddr-display option test. Fix from Jarno Huuskonen
<jhuuskon@hytti.uku.fi>
+ - Fix hang on logout if processes are still using the pty. Needs
+ further testing.
20000116
- Renamed --with-xauth-path to --with-xauth
diff --git a/TODO b/TODO
index 0eccc9be..785b4906 100644
--- a/TODO
+++ b/TODO
@@ -8,19 +8,3 @@
lack of u_intXX_t types. There must be a better way.
- Move all compatability cruft (bsd-*, fake-*) into subordinate library
-
-- Hanging on logout:
-
-localhost$ ssh remotehost
-remotehost$ sleep 20 &
-remotehost$ logout
-(ssh hangs at logout for 20 seconds)
-
-Worse:
-
-localhost$ ssh root@remotehost
-remotehost# httpd
-remotehost# logout
-(ssh hangs at logout forever)
-
-This appears to be a problem in the server.
diff --git a/serverloop.c b/serverloop.c
index a5ecfe97..2afca763 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -36,10 +36,15 @@ static int max_fd; /* Max file descriptor number for select(). */
/*
* This SIGCHLD kludge is used to detect when the child exits. The server
* will exit after that, as soon as forwarded connections have terminated.
+ *
+ * After SIGCHLD child_has_selected is set to 1 after the first pass
+ * through the wait_until_can_do_something() select(). This ensures
+ * that the child's output gets a chance to drain before it is yanked.
*/
static int child_pid; /* Pid of the child. */
static volatile int child_terminated; /* The child has terminated. */
+static volatile int child_has_selected; /* Child has had chance to drain. */
static volatile int child_wait_status; /* Status from wait(). */
void
@@ -56,6 +61,7 @@ sigchld_handler(int sig)
if (WIFEXITED(child_wait_status) ||
WIFSIGNALED(child_wait_status))
child_terminated = 1;
+ child_has_selected = 0;
}
signal(SIGCHLD, sigchld_handler);
errno = save_errno;
@@ -300,6 +306,9 @@ retry_select:
else
goto retry_select;
}
+
+ if (child_terminated)
+ child_has_selected = 1;
}
/*
@@ -438,6 +447,7 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
/* Initialize the SIGCHLD kludge. */
child_pid = pid;
child_terminated = 0;
+ child_has_selected = 0;
signal(SIGCHLD, sigchld_handler);
/* Initialize our global variables. */
@@ -533,8 +543,11 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
* descriptors, and we have no more data to send to the
* client, and there is no pending buffered data.
*/
- if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
- buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
+ if (((fdout_eof && fderr_eof) ||
+ (child_terminated && child_has_selected)) &&
+ !packet_have_data_to_write() &&
+ (buffer_len(&stdout_buffer) == 0) &&
+ (buffer_len(&stderr_buffer) == 0)) {
if (!channel_still_open())
goto quit;
if (!waiting_termination) {