[openssh-commits] [openssh] 03/03: upstream: convert channel timeouts to use floating points, allows

git+noreply at mindrot.org git+noreply at mindrot.org
Wed Sep 16 16:29:26 AEST 2026


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit a253258c6d9ed991d7390f0d5569f83f189eab75
Author: djm at openbsd.org <djm at openbsd.org>
AuthorDate: Wed Sep 16 06:23:15 2026 +0000

    upstream: convert channel timeouts to use floating points, allows
    
    fractional and subsecond timeouts; ok markus, deraadt
    
    OpenBSD-Commit-ID: f25665fc4e734ade36f6cb631dc28c6c54bb9e76
---
 channels.c     | 64 +++++++++++++++++++++++++++++-----------------------------
 channels.h     | 12 +++++------
 misc.c         | 31 ++++++++++++++++++++++++----
 misc.h         |  6 ++++--
 monitor_wrap.c |  5 +++--
 ssh.c          |  8 +++++---
 6 files changed, 77 insertions(+), 49 deletions(-)

diff --git a/channels.c b/channels.c
index e1c98d756..ad380dbe4 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.469 2026/09/16 05:00:51 djm Exp $ */
+/* $OpenBSD: channels.c,v 1.470 2026/09/16 06:23:15 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -147,7 +147,7 @@ struct permission_set {
 /* Used to record timeouts per channel type */
 struct ssh_channel_timeout {
 	char *type_pattern;
-	int timeout_secs;
+	double timeout_secs;
 };
 
 /* Master structure for channels state */
@@ -191,7 +191,7 @@ struct ssh_channels {
 	u_int x11_saved_data_len;
 
 	/* Deadline after which all X11 connections are refused */
-	time_t x11_refuse_time;
+	double x11_refuse_time;
 
 	/*
 	 * Fake X11 authentication data.  This is what the server will be
@@ -211,8 +211,8 @@ struct ssh_channels {
 	struct ssh_channel_timeout *timeouts;
 	size_t ntimeouts;
 	/* Global timeout for all OPEN channels */
-	int global_deadline;
-	time_t lastused;
+	double global_deadline;
+	double lastused;
 	/* pattern-lists used to classify channels as bulk */
 	char *bulk_classifier_tty, *bulk_classifier_notty;
 	/* Number of active bulk channels (set by channel_handler) */
@@ -346,16 +346,16 @@ channel_set_tcp_keepalives(struct ssh *ssh, int on)
  */
 void
 channel_add_timeout(struct ssh *ssh, const char *type_pattern,
-    int timeout_secs)
+    double timeout_secs)
 {
 	struct ssh_channels *sc = ssh->chanctxt;
 
 	if (strcmp(type_pattern, "global") == 0) {
-		debug2_f("global channel timeout %d seconds", timeout_secs);
+		debug2_f("global channel timeout %f seconds", timeout_secs);
 		sc->global_deadline = timeout_secs;
 		return;
 	}
-	debug2_f("channel type \"%s\" timeout %d seconds",
+	debug2_f("channel type \"%s\" timeout %f seconds",
 	    type_pattern, timeout_secs);
 	sc->timeouts = xrecallocarray(sc->timeouts, sc->ntimeouts,
 	    sc->ntimeouts + 1, sizeof(*sc->timeouts));
@@ -379,7 +379,7 @@ channel_clear_timeouts(struct ssh *ssh)
 	sc->ntimeouts = 0;
 }
 
-static int
+static double
 lookup_timeout(struct ssh *ssh, const char *type)
 {
 	struct ssh_channels *sc = ssh->chanctxt;
@@ -426,13 +426,13 @@ channel_set_xtype(struct ssh *ssh, int id, const char *xctype)
 		free(c->xctype);
 	c->xctype = xstrdup(xctype);
 	/* Only override deadline if xctype has a more specific match. */
-	int xtype_deadline = lookup_timeout(ssh, c->xctype);
+	double xtype_deadline = lookup_timeout(ssh, c->xctype);
 	if (xtype_deadline != 0)
 		c->inactive_deadline = xtype_deadline;
 	channel_classify(ssh, c);
 	/* report effective timeout: per-channel if set, else global */
-	debug2_f("labeled channel %d as %s (inactive timeout %d)", id, xctype,
-	    c->inactive_deadline != 0 ?
+	debug2_f("labeled channel %d as %s (inactive timeout %f)", id, xctype,
+	    c->inactive_deadline != 0.0 ?
 	    c->inactive_deadline : sc->global_deadline);
 }
 
@@ -443,7 +443,7 @@ channel_set_xtype(struct ssh *ssh, int id, const char *xctype)
 static void
 channel_set_used_time(struct ssh *ssh, Channel *c)
 {
-	ssh->chanctxt->lastused = monotime();
+	ssh->chanctxt->lastused = monotime_double();
 	if (c != NULL)
 		c->lastused = ssh->chanctxt->lastused;
 }
@@ -452,11 +452,11 @@ channel_set_used_time(struct ssh *ssh, Channel *c)
  * Get the time at which a channel is due to time out for inactivity.
  * Returns 0 if the channel is not due to time out ever.
  */
-static time_t
+static double
 channel_get_expiry(struct ssh *ssh, Channel *c)
 {
 	struct ssh_channels *sc = ssh->chanctxt;
-	time_t expiry = 0, channel_expiry;
+	double expiry = 0, channel_expiry;
 
 	if (sc->lastused != 0 && sc->global_deadline != 0)
 		expiry = sc->lastused + sc->global_deadline;
@@ -603,8 +603,8 @@ channel_new(struct ssh *ssh, char *ctype, int type, int rfd, int wfd, int efd,
 	c->inactive_deadline = lookup_timeout(ssh, c->ctype);
 	TAILQ_INIT(&c->status_confirms);
 	channel_classify(ssh, c);
-	debug("channel %d: new %s [%s] (inactive timeout: %d)",
-	    found, c->ctype, remote_name, c->inactive_deadline != 0 ?
+	debug("channel %d: new %s [%s] (inactive timeout: %f)",
+	    found, c->ctype, remote_name, c->inactive_deadline != 0.0 ?
 	    c->inactive_deadline : sc->global_deadline);
 	return c;
 }
@@ -1432,8 +1432,8 @@ x11_open_helper(struct ssh *ssh, struct sshbuf *b)
 	}
 
 	/* Is this being called after the refusal deadline? */
-	if (sc->x11_refuse_time != 0 &&
-	    monotime() >= sc->x11_refuse_time) {
+	if (sc->x11_refuse_time != 0.0 &&
+	    monotime_double() >= sc->x11_refuse_time) {
 		verbose("Rejected X11 connection after ForwardX11Timeout "
 		    "expired");
 		return -1;
@@ -1980,7 +1980,7 @@ channel_post_x11_listener(struct ssh *ssh, Channel *c)
 		    errno != ECONNABORTED)
 			error("accept: %.100s", strerror(errno));
 		if (errno == EMFILE || errno == ENFILE)
-			c->notbefore = monotime() + 1;
+			c->notbefore = monotime_double() + 1.0;
 		return;
 	}
 	set_nodelay(newsock);
@@ -2064,7 +2064,7 @@ port_open_helper(struct ssh *ssh, Channel *c, char *rtype)
 }
 
 void
-channel_set_x11_refuse_time(struct ssh *ssh, time_t refuse_time)
+channel_set_x11_refuse_time(struct ssh *ssh, double refuse_time)
 {
 	ssh->chanctxt->x11_refuse_time = refuse_time;
 }
@@ -2111,7 +2111,7 @@ channel_post_port_listener(struct ssh *ssh, Channel *c)
 		    errno != ECONNABORTED)
 			error("accept: %.100s", strerror(errno));
 		if (errno == EMFILE || errno == ENFILE)
-			c->notbefore = monotime() + 1;
+			c->notbefore = monotime_double() + 1.0;
 		return;
 	}
 	if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) {
@@ -2150,7 +2150,7 @@ channel_post_auth_listener(struct ssh *ssh, Channel *c)
 	if (newsock == -1) {
 		error("accept from auth socket: %.100s", strerror(errno));
 		if (errno == EMFILE || errno == ENFILE)
-			c->notbefore = monotime() + 1;
+			c->notbefore = monotime_double() + 1.0;
 		return;
 	}
 	nc = channel_new(ssh, "agent-connection",
@@ -2640,7 +2640,7 @@ channel_post_mux_listener(struct ssh *ssh, Channel *c)
 	    &addrlen)) == -1) {
 		error_f("accept: %s", strerror(errno));
 		if (errno == EMFILE || errno == ENFILE)
-			c->notbefore = monotime() + 1;
+			c->notbefore = monotime_double() + 1.0;
 		return;
 	}
 
@@ -2738,9 +2738,9 @@ channel_handler(struct ssh *ssh, int table, struct timespec *timeout)
 	chan_fn **ftab = table == CHAN_PRE ? sc->channel_pre : sc->channel_post;
 	u_int i, oalloc;
 	Channel *c;
-	time_t now;
+	double now;
 
-	now = monotime();
+	now = monotime_double();
 	for (sc->nbulk = i = 0, oalloc = sc->channels_alloc; i < oalloc; i++) {
 		c = sc->channels[i];
 		if (c == NULL)
@@ -2762,10 +2762,10 @@ channel_handler(struct ssh *ssh, int table, struct timespec *timeout)
 			    channel_get_expiry(ssh, c) != 0 &&
 			    now >= channel_get_expiry(ssh, c)) {
 				/* channel closed for inactivity */
-				int fired_deadline = c->inactive_deadline != 0 ?
+				double deadline = c->inactive_deadline != 0.0 ?
 				    c->inactive_deadline : sc->global_deadline;
-				verbose("channel %d: closing after %d seconds "
-				    "of inactivity", c->self, fired_deadline);
+				verbose("channel %d: closing after %f seconds "
+				    "of inactivity", c->self, deadline);
 				channel_force_close(ssh, c, 1);
 			} else if (c->notbefore <= now) {
 				/* Run handlers that are not paused. */
@@ -5485,15 +5485,15 @@ int
 x11_channel_used_recently(struct ssh *ssh) {
 	u_int i;
 	Channel *c;
-	time_t lastused = 0;
+	double lastused = 0;
 
 	for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
 		c = ssh->chanctxt->channels[i];
-		if (c == NULL || c->ctype == NULL || c->lastused == 0 ||
+		if (c == NULL || c->ctype == NULL || c->lastused == 0.0 ||
 		    strcmp(c->ctype, "x11-connection") != 0)
 			continue;
 		if (c->lastused > lastused)
 			lastused = c->lastused;
 	}
-	return lastused != 0 && monotime() <= lastused + 1;
+	return lastused != 0.0 && monotime_double() <= lastused + 1.0;
 }
diff --git a/channels.h b/channels.h
index 8311749e2..cc520ba13 100644
--- a/channels.h
+++ b/channels.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.h,v 1.168 2026/09/16 00:13:58 djm Exp $ */
+/* $OpenBSD: channels.h,v 1.169 2026/09/16 06:23:15 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -147,7 +147,7 @@ struct Channel {
 #endif
 	int	client_tty;	/* (client) TTY has been requested */
 	int     force_drain;	/* force close on iEOF */
-	time_t	notbefore;	/* Pause IO until deadline (time_t) */
+	double	notbefore;	/* Pause IO until deadline (time_t) */
 	int     delayed;	/* post-IO handlers for newly created
 				 * channels are delayed until the first call
 				 * to a matching pre-IO handler.
@@ -211,9 +211,9 @@ struct Channel {
 	/* Inactivity timeouts */
 
 	/* Last traffic seen for OPEN channels */
-	time_t			lastused;
+	double			lastused;
 	/* Inactivity timeout deadline in seconds (0 = no timeout) */
-	int			inactive_deadline;
+	double			inactive_deadline;
 };
 
 #define CHAN_EXTENDED_IGNORE		0
@@ -315,7 +315,7 @@ int	 channel_has_bulk(struct ssh *);
 void	 channel_set_tcp_keepalives(struct ssh *, int);
 
 /* channel inactivity timeouts */
-void channel_add_timeout(struct ssh *, const char *, int);
+void channel_add_timeout(struct ssh *, const char *, double);
 void channel_clear_timeouts(struct ssh *);
 
 /* mux proxy support */
@@ -383,7 +383,7 @@ int	 permitopen_port(const char *);
 
 /* x11 forwarding */
 
-void	 channel_set_x11_refuse_time(struct ssh *, time_t);
+void	 channel_set_x11_refuse_time(struct ssh *, double);
 int	 x11_connect_display(struct ssh *);
 int	 x11_create_display_inet(struct ssh *, int, int, int, u_int *, int **);
 void	 x11_request_forwarding_with_spoofing(struct ssh *, int,
diff --git a/misc.c b/misc.c
index b6e05461b..33d9d7061 100644
--- a/misc.c
+++ b/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.219 2026/09/16 00:13:58 djm Exp $ */
+/* $OpenBSD: misc.c,v 1.220 2026/09/16 06:23:15 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2005-2020 Damien Miller.  All rights reserved.
@@ -2633,10 +2633,10 @@ format_absolute_time(uint64_t t, char *buf, size_t len)
  * Caller must free *typep.
  */
 int
-parse_pattern_interval(const char *s, char **typep, int *secsp)
+parse_pattern_interval(const char *s, char **typep, double *secsp)
 {
 	char *cp, *sdup;
-	int secs;
+	double secs;
 
 	if (typep != NULL)
 		*typep = NULL;
@@ -2651,7 +2651,7 @@ parse_pattern_interval(const char *s, char **typep, int *secsp)
 		return -1;
 	}
 	*cp++ = '\0';
-	if ((secs = convtime(cp)) < 0) {
+	if ((secs = convtime_double(cp)) < 0.0) {
 		free(sdup);
 		return -1;
 	}
@@ -3085,6 +3085,22 @@ ptimeout_deadline_ms(struct timespec *pt, long ms)
 	ptimeout_deadline_tsp(pt, &p);
 }
 
+/* Specify a poll/ppoll deadline of at most 'sec' seconds (double) */
+void
+ptimeout_deadline_sec_double(struct timespec *pt, double sec)
+{
+	struct timespec t;
+
+	memset(&t, 0, sizeof(t));
+	if ((int64_t)sec > SSH_TIME_T_MAX)
+		t.tv_sec = SSH_TIME_T_MAX;
+	else if (sec > 0) {
+		t.tv_sec = sec;
+		t.tv_nsec = (sec - (double)t.tv_sec) * 1000000000.0;
+	}
+	ptimeout_deadline_tsp(pt, &t);
+}
+
 /* Specify a poll/ppoll deadline at wall clock monotime 'when' (timespec) */
 void
 ptimeout_deadline_monotime_tsp(struct timespec *pt, struct timespec *when)
@@ -3103,6 +3119,13 @@ ptimeout_deadline_monotime_tsp(struct timespec *pt, struct timespec *when)
 	}
 }
 
+/* Specify a poll/ppoll deadline at wall clock monotime 'when' (double) */
+void
+ptimeout_deadline_monotime_double(struct timespec *pt, double when)
+{
+	ptimeout_deadline_sec_double(pt, when - monotime_double());
+}
+
 /* Specify a poll/ppoll deadline at wall clock monotime 'when' */
 void
 ptimeout_deadline_monotime(struct timespec *pt, time_t when)
diff --git a/misc.h b/misc.h
index 589213f21..0784f379b 100644
--- a/misc.h
+++ b/misc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.h,v 1.119 2026/09/16 00:25:50 djm Exp $ */
+/* $OpenBSD: misc.h,v 1.120 2026/09/16 06:23:16 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -109,7 +109,7 @@ int	 valid_env_name(const char *);
 const char *atoi_err(const char *, int *);
 int	 parse_absolute_time(const char *, uint64_t *);
 void	 format_absolute_time(uint64_t, char *, size_t);
-int	 parse_pattern_interval(const char *, char **, int *);
+int	 parse_pattern_interval(const char *, char **, double *);
 int	 path_absolute(const char *);
 int	 stdfd_devnull(int, int, int);
 int	 lib_contains_symbol(const char *, const char *);
@@ -234,8 +234,10 @@ struct timespec;
 void ptimeout_init(struct timespec *pt);
 void ptimeout_deadline_sec(struct timespec *pt, long sec);
 void ptimeout_deadline_ms(struct timespec *pt, long ms);
+void ptimeout_deadline_sec_double(struct timespec *pt, double sec);
 void ptimeout_deadline_monotime_tsp(struct timespec *pt, struct timespec *when);
 void ptimeout_deadline_monotime(struct timespec *pt, time_t when);
+void ptimeout_deadline_monotime_double(struct timespec *pt, double when);
 int ptimeout_get_ms(struct timespec *pt);
 struct timespec *ptimeout_get_tsp(struct timespec *pt);
 int ptimeout_isset(struct timespec *pt);
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 3d68f804f..c828fce04 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor_wrap.c,v 1.150 2026/09/16 00:29:44 djm Exp $ */
+/* $OpenBSD: monitor_wrap.c,v 1.151 2026/09/16 06:23:16 djm Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos at citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus at openbsd.org>
@@ -1171,7 +1171,8 @@ server_process_permitopen(struct ssh *ssh)
 void
 server_process_channel_timeouts(struct ssh *ssh)
 {
-	u_int i, secs;
+	u_int i;
+	double secs;
 	char *type;
 
 	debug3_f("setting %u timeouts", options.num_channel_timeouts);
diff --git a/ssh.c b/ssh.c
index b87d4c1cc..3eb721211 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.638 2026/09/16 00:13:58 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.639 2026/09/16 06:23:16 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -1693,14 +1693,16 @@ main(int ac, char **av)
 	/* Apply channels timeouts, if set */
 	channel_clear_timeouts(ssh);
 	for (j = 0; j < options.num_channel_timeouts; j++) {
+		double timeout;
+
 		debug3("applying channel timeout %s",
 		    options.channel_timeouts[j]);
 		if (parse_pattern_interval(options.channel_timeouts[j],
-		    &cp, &i) != 0) {
+		    &cp, &timeout) != 0) {
 			fatal_f("internal error: bad timeout %s",
 			    options.channel_timeouts[j]);
 		}
-		channel_add_timeout(ssh, cp, i);
+		channel_add_timeout(ssh, cp, timeout);
 		free(cp);
 	}
 	channel_set_tcp_keepalives(ssh,

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list