- markus@cvs.openbsd.org 2001/07/02 22:52:57
     [channels.c channels.h serverloop.c]
     improve cleanup/exit logic in ssh2:
     stop listening to channels, detach channel users (e.g. sessions).
     wait for children (i.e. dying sessions), send exit messages,
     cleanup all channels.
diff --git a/ChangeLog b/ChangeLog
index 211ecb8..aa734bc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -124,6 +124,12 @@
    - markus@cvs.openbsd.org 2001/07/02 22:40:18
      [ssh-keygen.c]
      update for sectok.h interface changes.
+   - markus@cvs.openbsd.org 2001/07/02 22:52:57
+     [channels.c channels.h serverloop.c]
+     improve cleanup/exit logic in ssh2:
+     stop listening to channels, detach channel users (e.g. sessions).
+     wait for children (i.e. dying sessions), send exit messages,
+     cleanup all channels.
  
 20010629
  - (bal) Removed net_aton() since we don't use it any more
@@ -5951,4 +5957,4 @@
  - Wrote replacements for strlcpy and mkdtemp
  - Released 1.0pre1
 
-$Id: ChangeLog,v 1.1375 2001/07/04 05:24:27 mouring Exp $
+$Id: ChangeLog,v 1.1376 2001/07/04 05:26:06 mouring Exp $
diff --git a/channels.c b/channels.c
index 18b6c46..35edff6 100644
--- a/channels.c
+++ b/channels.c
@@ -39,7 +39,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.130 2001/06/30 18:08:39 stevesk Exp $");
+RCSID("$OpenBSD: channels.c,v 1.131 2001/07/02 22:52:56 markus Exp $");
 
 #include "ssh.h"
 #include "ssh1.h"
@@ -260,7 +260,7 @@
 	c->cb_fn = NULL;
 	c->cb_arg = NULL;
 	c->cb_event = 0;
-	c->dettach_user = NULL;
+	c->detach_user = NULL;
 	c->input_filter = NULL;
 	debug("channel %d: new [%s]", found, remote_name);
 	return c;
@@ -310,9 +310,9 @@
 	debug3("channel_free: status: %s", s);
 	xfree(s);
 
-	if (c->dettach_user != NULL) {
-		debug("channel_free: channel %d: dettaching channel user", c->self);
-		c->dettach_user(c->self, NULL);
+	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);
@@ -338,6 +338,22 @@
 			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.
@@ -354,6 +370,32 @@
 }
 
 /*
+ * Stop listening to channels.
+ */
+
+void
+channel_stop_listening(void)
+{
+	int i;
+	Channel *c;
+
+	for (i = 0; i < channels_alloc; i++) {
+		c = channels[i];
+		if (c != NULL) {
+			switch (c->type) {
+			case SSH_CHANNEL_AUTH_SOCKET:
+			case SSH_CHANNEL_PORT_LISTENER:
+			case SSH_CHANNEL_RPORT_LISTENER:
+			case SSH_CHANNEL_X11_LISTENER:
+				close(c->sock);
+				channel_free(c);
+				break;
+			}
+		}
+	}
+}
+
+/*
  * Returns true if no channel has too much buffered data, and false if one or
  * more channel is overfull.
  */
@@ -579,7 +621,7 @@
 		log("channel_register_cleanup: %d: bad id", id);
 		return;
 	}
-	c->dettach_user = fn;
+	c->detach_user = fn;
 }
 void
 channel_cancel_cleanup(int id)
@@ -589,7 +631,7 @@
 		log("channel_cancel_cleanup: %d: bad id", id);
 		return;
 	}
-	c->dettach_user = NULL;
+	c->detach_user = NULL;
 }
 void
 channel_register_filter(int id, channel_filter_fn *fn)
diff --git a/channels.h b/channels.h
index c36f66b..e4146b5 100644
--- a/channels.h
+++ b/channels.h
@@ -32,7 +32,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/* RCSID("$OpenBSD: channels.h,v 1.43 2001/06/30 18:08:40 stevesk Exp $"); */
+/* RCSID("$OpenBSD: channels.h,v 1.44 2001/07/02 22:52:57 markus Exp $"); */
 
 #ifndef CHANNEL_H
 #define CHANNEL_H
@@ -102,7 +102,7 @@
 	channel_callback_fn	*cb_fn;
 	void	*cb_arg;
 	int	cb_event;
-	channel_callback_fn	*dettach_user;
+	channel_callback_fn	*detach_user;
 
 	/* filter */
 	channel_filter_fn	*input_filter;
@@ -140,8 +140,10 @@
 Channel	*channel_lookup(int);
 Channel *channel_new(char *, int, int, int, int, int, int, int, char *, int);
 void	 channel_set_fds(int, int, int, int, int, int);
-void     channel_free(Channel *);
-void     channel_free_all(void);
+void	 channel_free(Channel *);
+void	 channel_free_all(void);
+void	 channel_detach_all(void);
+void	 channel_stop_listening(void);
 
 void	 channel_send_open(int);
 void	 channel_request(int, char *, int);
diff --git a/serverloop.c b/serverloop.c
index 773292a..1db1c72 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -35,7 +35,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: serverloop.c,v 1.73 2001/07/02 13:59:14 markus Exp $");
+RCSID("$OpenBSD: serverloop.c,v 1.74 2001/07/02 22:52:57 markus Exp $");
 
 #include "xmalloc.h"
 #include "packet.h"
@@ -711,7 +711,8 @@
 	 * there is a race between channel_free_all() killing children and
 	 * children dying before kill()
 	 */
-	channel_free_all();
+	channel_detach_all();
+	channel_stop_listening();
 
 	while (session_have_children()) {
 		pid = waitpid(-1, &status, 0);
@@ -722,6 +723,7 @@
 			break;
 		}
 	}
+	channel_free_all();
 }
 
 static void