New forkoff() and chan_wont_read/write() API

Nicolas Williams Nicolas.Williams at ubsw.com
Wed Feb 6 03:26:08 EST 2002


Markus,

How's this patch?

 - a chan_wont_read()/chan_wont_write() API is added that is very much
   like chan_read_failed()/chan_write_failed(), but for the debug
   messages and chan_wont_*() don't ever call error()

   The 3.0.2p1 channel_pre_x11_open() uses chan_*_failed() but looks
   like it ought to use chan_wont_*() instead :)

 - forkoff() no longer fakes EOF for SSHv2 (still does for SSHv1 - dunno
   what to do there)

 - the session channel lookup, chan_wont_*(), chan_close_fds(), detach
   bit is only done for SSHv2

Nico
-- 
-DISCLAIMER: an automatically appended disclaimer may follow. By posting-
-to a public e-mail mailing list I hereby grant permission to distribute-
-and copy this message.-
-------------- next part --------------
Index: 3_0_2p1.1/nchan.c
--- 3_0_2p1.1/nchan.c Wed, 21 Nov 2001 10:38:46 -0500 jd (OpenSSH/i/40_nchan.c 1.1.1.1 644)
+++ 3_0_2p1_w_gssk5_ubsw_experimental.6/nchan.c Tue, 05 Feb 2002 11:25:25 -0500 willian (OpenSSH/i/40_nchan.c 1.1.1.4 644)
@@ -66,10 +66,12 @@
 /* events concerning the INPUT from socket for channel (istate) */
 chan_event_fn *chan_rcvd_oclose			= NULL;
 chan_event_fn *chan_read_failed			= NULL;
+chan_event_fn *chan_wont_read			= NULL;
 chan_event_fn *chan_ibuf_empty			= NULL;
 /* events concerning the OUTPUT from channel for socket (ostate) */
 chan_event_fn *chan_rcvd_ieof			= NULL;
 chan_event_fn *chan_write_failed		= NULL;
+chan_event_fn *chan_wont_write			= NULL;
 chan_event_fn *chan_obuf_empty			= NULL;
 /*
  * ACTIONS: should never update the channel states
@@ -137,6 +139,28 @@
 	}
 }
 static void
+chan_wont_read_12(Channel *c)
+{
+	debug("channel %d: wont read", c->self);
+	switch (c->istate) {
+	case CHAN_INPUT_OPEN:
+		debug("channel %d: input open -> drain", c->self);
+		chan_shutdown_read(c);
+		c->istate = CHAN_INPUT_WAIT_DRAIN;
+#if 0
+		if (buffer_len(&c->input) == 0) {
+			debug("channel %d: input: no drain shortcut", c->self);
+			chan_ibuf_empty(c);
+		}
+#endif
+		break;
+	default:
+		debug("channel %d: chan_wont_read for istate %d",
+		    c->self, c->istate);
+		break;
+	}
+}
+static void
 chan_ibuf_empty1(Channel *c)
 {
 	debug("channel %d: ibuf empty", c->self);
@@ -221,6 +245,27 @@
 	}
 }
 static void
+chan_wont_write1(Channel *c)
+{
+	debug("channel %d: wont write", c->self);
+	switch (c->ostate) {
+	case CHAN_OUTPUT_OPEN:
+		debug("channel %d: output open -> wait_ieof", c->self);
+		chan_send_oclose1(c);
+		c->ostate = CHAN_OUTPUT_WAIT_IEOF;
+		break;
+	case CHAN_OUTPUT_WAIT_DRAIN:
+		debug("channel %d: output wait_drain -> closed", c->self);
+		chan_send_oclose1(c);
+		c->ostate = CHAN_OUTPUT_CLOSED;
+		break;
+	default:
+		debug("channel %d: chan_wont_write for ostate %d",
+		    c->self, c->ostate);
+		break;
+	}
+}
+static void
 chan_obuf_empty1(Channel *c)
 {
 	debug("channel %d: obuf empty", c->self);
@@ -369,6 +414,27 @@
 	}
 }
 static void
+chan_wont_write2(Channel *c)
+{
+	debug("channel %d: wont write", c->self);
+	switch (c->ostate) {
+	case CHAN_OUTPUT_OPEN:
+		debug("channel %d: output open -> closed", c->self);
+		chan_shutdown_write(c); /* ?? */
+		c->ostate = CHAN_OUTPUT_CLOSED;
+		break;
+	case CHAN_OUTPUT_WAIT_DRAIN:
+		debug("channel %d: output drain -> closed", c->self);
+		chan_shutdown_write(c);
+		c->ostate = CHAN_OUTPUT_CLOSED;
+		break;
+	default:
+		debug("channel %d: chan_wont_write for ostate %d",
+		    c->self, c->ostate);
+		break;
+	}
+}
+static void
 chan_obuf_empty2(Channel *c)
 {
 	debug("channel %d: obuf empty", c->self);
@@ -496,18 +562,22 @@
 	if (compat20) {
 		chan_rcvd_oclose		= chan_rcvd_oclose2;
 		chan_read_failed		= chan_read_failed_12;
+		chan_wont_read			= chan_wont_read_12;
 		chan_ibuf_empty			= chan_ibuf_empty2;
 
 		chan_rcvd_ieof			= chan_rcvd_ieof2;
 		chan_write_failed		= chan_write_failed2;
+		chan_wont_write			= chan_wont_write2;
 		chan_obuf_empty			= chan_obuf_empty2;
 	} else {
 		chan_rcvd_oclose		= chan_rcvd_oclose1;
 		chan_read_failed		= chan_read_failed_12;
+		chan_wont_read			= chan_wont_read_12;
 		chan_ibuf_empty			= chan_ibuf_empty1;
 
 		chan_rcvd_ieof			= chan_rcvd_ieof1;
 		chan_write_failed		= chan_write_failed1;
+		chan_wont_write			= chan_wont_write2;
 		chan_obuf_empty			= chan_obuf_empty1;
 	}
 }
Index: 3_0_2p1.1/clientloop.c
--- 3_0_2p1.1/clientloop.c Wed, 21 Nov 2001 10:38:46 -0500 jd (OpenSSH/j/41_clientloop 1.1.2.1 644)
+++ 3_0_2p1_w_gssk5_ubsw_experimental.6/clientloop.c Tue, 05 Feb 2002 11:16:16 -0500 willian (OpenSSH/j/41_clientloop 1.1.2.7 644)
@@ -1007,6 +1051,81 @@
 
 /*********/
 
+/*
+ * Detach the program (continue to serve connections,
+ * but put in background and no more new connections).
+ */
+static
+void
+forkoff(int stop_listening, int detach)
+{
+	pid_t pid;
+	int fd;
+	Channel *c;
+
+	/* Restore tty modes. */
+	leave_raw_mode();
+
+	/* Stop listening for new connections. */
+	if (stop_listening)
+		channel_stop_listening();
+
+	fprintf(stderr, "Forking off into the background - %s, %s",
+		stop_listening ? "no longer listening" : "still listening",
+		detach ? "detaching" : "not detaching");
+
+	/* Fork into background. */
+	pid = fork();
+	if (pid < 0) {
+		error("fork: %.100s", strerror(errno));
+		return;
+	}
+	if (pid != 0) {	/* This is the parent. */
+		/* The parent just exits. */
+		exit(0);
+	}
+
+	/* fake EOF on stdin for SSHv1 */
+	if (!compat20 && !stdin_eof) {
+		/*
+		 * Sending SSH_CMSG_EOF alone does not always appear
+		 * to be enough.  So we try to send an EOF character
+		 * first.
+		 */
+		packet_start(SSH_CMSG_STDIN_DATA);
+		packet_put_string("\004", 1);
+		packet_send();
+		/* Close stdin. */
+		stdin_eof = 1;
+		if (buffer_len(&stdin_buffer) == 0) {
+			packet_start(SSH_CMSG_EOF);
+			packet_send();
+		}
+	}
+
+	if (!compat20)
+		return;
+
+	c = channel_lookup(session_ident);
+	if (c == NULL)
+		error("couldn't lookup session channel");
+
+	if (detach) {
+		chan_wont_read(c);
+		chan_wont_write(c);
+		channel_close_fds(c);
+		fd = open(_PATH_DEVNULL, O_RDWR, 0);
+		if (fd < 0)
+			return;
+		(void) dup2(fd, STDIN_FILENO);
+		(void) dup2(fd, STDOUT_FILENO);
+		(void) dup2(fd, STDERR_FILENO);
+		if (fd > 2)
+			(void) close(fd);
+		(void) setsid();
+	}
+}
+
 static void
 client_input_stdout_data(int type, int plen, void *ctxt)
 {
Index: 3_0_2p1.1/channels.h
--- 3_0_2p1.1/channels.h Wed, 21 Nov 2001 10:38:46 -0500 jd (OpenSSH/j/46_channels.h 1.2.1.1 644)
+++ 3_0_2p1_w_gssk5_ubsw_experimental.6/channels.h Tue, 05 Feb 2002 11:04:53 -0500 willian (OpenSSH/j/46_channels.h 1.2.1.3 644)
@@ -153,6 +153,7 @@
 void	 channel_register_filter(int, channel_filter_fn *);
 void	 channel_cancel_cleanup(int);
 int	 channel_close_fd(int *);
+void	 channel_close_fds(Channel *);
 
 /* protocol handler */
 
@@ -224,11 +225,13 @@
 /* for the input state */
 extern chan_event_fn	*chan_rcvd_oclose;
 extern chan_event_fn	*chan_read_failed;
+extern chan_event_fn	*chan_wont_read;
 extern chan_event_fn	*chan_ibuf_empty;
 
 /* for the output state */
 extern chan_event_fn	*chan_rcvd_ieof;
 extern chan_event_fn	*chan_write_failed;
+extern chan_event_fn	*chan_wont_write;
 extern chan_event_fn	*chan_obuf_empty;
 
 #endif
Index: 3_0_2p1.1/channels.c
--- 3_0_2p1.1/channels.c Wed, 21 Nov 2001 10:38:46 -0500 jd (OpenSSH/j/47_channels.c 1.2.2.1 644)
+++ 3_0_2p1_w_gssk5_ubsw_experimental.6/channels.c Thu, 17 Jan 2002 14:17:25 -0500 willian (OpenSSH/j/47_channels.c 1.2.2.2 644)
@@ -301,7 +301,7 @@
 
 /* Close all channel fd/socket. */
 
-static void
+void
 channel_close_fds(Channel *c)
 {
 	debug3("channel_close_fds: channel %d: r %d w %d e %d",
-------------- next part --------------

Visit our website at http://www.ubswarburg.com

This message contains confidential information and is intended only 
for the individual named.  If you are not the named addressee you 
should not disseminate, distribute or copy this e-mail.  Please 
notify the sender immediately by e-mail if you have received this 
e-mail by mistake and delete this e-mail from your system.

E-mail transmission cannot be guaranteed to be secure or error-free 
as information could be intercepted, corrupted, lost, destroyed, 
arrive late or incomplete, or contain viruses.  The sender therefore 
does not accept liability for any errors or omissions in the contents 
of this message which arise as a result of e-mail transmission.  If 
verification is required please request a hard-copy version.  This 
message is provided for informational purposes and should not be 
construed as a solicitation or offer to buy or sell any securities or 
related financial instruments.


More information about the openssh-unix-dev mailing list