diff options
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | TODO | 16 | ||||
-rw-r--r-- | serverloop.c | 17 |
3 files changed, 17 insertions, 18 deletions
@@ -12,6 +12,8 @@ | |||
12 | - Fix rresvport_af failure errors (logic error in bsd-bindresvport.c) | 12 | - Fix rresvport_af failure errors (logic error in bsd-bindresvport.c) |
13 | - Fix --with-ipaddr-display option test. Fix from Jarno Huuskonen | 13 | - Fix --with-ipaddr-display option test. Fix from Jarno Huuskonen |
14 | <jhuuskon@hytti.uku.fi> | 14 | <jhuuskon@hytti.uku.fi> |
15 | - Fix hang on logout if processes are still using the pty. Needs | ||
16 | further testing. | ||
15 | 17 | ||
16 | 20000116 | 18 | 20000116 |
17 | - Renamed --with-xauth-path to --with-xauth | 19 | - Renamed --with-xauth-path to --with-xauth |
@@ -8,19 +8,3 @@ | |||
8 | lack of u_intXX_t types. There must be a better way. | 8 | lack of u_intXX_t types. There must be a better way. |
9 | 9 | ||
10 | - Move all compatability cruft (bsd-*, fake-*) into subordinate library | 10 | - Move all compatability cruft (bsd-*, fake-*) into subordinate library |
11 | |||
12 | - Hanging on logout: | ||
13 | |||
14 | localhost$ ssh remotehost | ||
15 | remotehost$ sleep 20 & | ||
16 | remotehost$ logout | ||
17 | (ssh hangs at logout for 20 seconds) | ||
18 | |||
19 | Worse: | ||
20 | |||
21 | localhost$ ssh root@remotehost | ||
22 | remotehost# httpd | ||
23 | remotehost# logout | ||
24 | (ssh hangs at logout forever) | ||
25 | |||
26 | This appears to be a problem in the server. | ||
diff --git a/serverloop.c b/serverloop.c index a5ecfe97d..2afca7637 100644 --- a/serverloop.c +++ b/serverloop.c | |||
@@ -36,10 +36,15 @@ static int max_fd; /* Max file descriptor number for select(). */ | |||
36 | /* | 36 | /* |
37 | * This SIGCHLD kludge is used to detect when the child exits. The server | 37 | * This SIGCHLD kludge is used to detect when the child exits. The server |
38 | * will exit after that, as soon as forwarded connections have terminated. | 38 | * will exit after that, as soon as forwarded connections have terminated. |
39 | * | ||
40 | * After SIGCHLD child_has_selected is set to 1 after the first pass | ||
41 | * through the wait_until_can_do_something() select(). This ensures | ||
42 | * that the child's output gets a chance to drain before it is yanked. | ||
39 | */ | 43 | */ |
40 | 44 | ||
41 | static int child_pid; /* Pid of the child. */ | 45 | static int child_pid; /* Pid of the child. */ |
42 | static volatile int child_terminated; /* The child has terminated. */ | 46 | static volatile int child_terminated; /* The child has terminated. */ |
47 | static volatile int child_has_selected; /* Child has had chance to drain. */ | ||
43 | static volatile int child_wait_status; /* Status from wait(). */ | 48 | static volatile int child_wait_status; /* Status from wait(). */ |
44 | 49 | ||
45 | void | 50 | void |
@@ -56,6 +61,7 @@ sigchld_handler(int sig) | |||
56 | if (WIFEXITED(child_wait_status) || | 61 | if (WIFEXITED(child_wait_status) || |
57 | WIFSIGNALED(child_wait_status)) | 62 | WIFSIGNALED(child_wait_status)) |
58 | child_terminated = 1; | 63 | child_terminated = 1; |
64 | child_has_selected = 0; | ||
59 | } | 65 | } |
60 | signal(SIGCHLD, sigchld_handler); | 66 | signal(SIGCHLD, sigchld_handler); |
61 | errno = save_errno; | 67 | errno = save_errno; |
@@ -300,6 +306,9 @@ retry_select: | |||
300 | else | 306 | else |
301 | goto retry_select; | 307 | goto retry_select; |
302 | } | 308 | } |
309 | |||
310 | if (child_terminated) | ||
311 | child_has_selected = 1; | ||
303 | } | 312 | } |
304 | 313 | ||
305 | /* | 314 | /* |
@@ -438,6 +447,7 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
438 | /* Initialize the SIGCHLD kludge. */ | 447 | /* Initialize the SIGCHLD kludge. */ |
439 | child_pid = pid; | 448 | child_pid = pid; |
440 | child_terminated = 0; | 449 | child_terminated = 0; |
450 | child_has_selected = 0; | ||
441 | signal(SIGCHLD, sigchld_handler); | 451 | signal(SIGCHLD, sigchld_handler); |
442 | 452 | ||
443 | /* Initialize our global variables. */ | 453 | /* Initialize our global variables. */ |
@@ -533,8 +543,11 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
533 | * descriptors, and we have no more data to send to the | 543 | * descriptors, and we have no more data to send to the |
534 | * client, and there is no pending buffered data. | 544 | * client, and there is no pending buffered data. |
535 | */ | 545 | */ |
536 | if (fdout_eof && fderr_eof && !packet_have_data_to_write() && | 546 | if (((fdout_eof && fderr_eof) || |
537 | buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) { | 547 | (child_terminated && child_has_selected)) && |
548 | !packet_have_data_to_write() && | ||
549 | (buffer_len(&stdout_buffer) == 0) && | ||
550 | (buffer_len(&stderr_buffer) == 0)) { | ||
538 | if (!channel_still_open()) | 551 | if (!channel_still_open()) |
539 | goto quit; | 552 | goto quit; |
540 | if (!waiting_termination) { | 553 | if (!waiting_termination) { |