[PATCH] connect() timeout for OpenSSH-3.5p1

Jean-Charles Longuet jclonguet at free.fr
Thu Oct 17 20:44:27 EST 2002


Here is the version of this patch for the last portable version of
OpenSSH (3.5p1), as it is not included in the main tree.

The patch avoids waiting to long when using ssh() or scp() on a down host,
it is usefull when you have to update many hosts via rsync or rdist themselves
relying upon ssh(). It enables a new option 'ConnectTimeout' to control
exactly the timeout value, so that it can be used even on slow links.

 These patches can also be found on http://charts.free.fr/

 If you think this patch is worth to be included in the main tree, then you
can vote for it on http://bugzilla.mindrot.org/showvotes.cgi?voteon=207 but
this requires a login. You can also just browse the case at
http://bugzilla.mindrot.org/show_bug.cgi?id=207

 Hope this patch help you.

--
        Jean-Charles
-------------- next part --------------
--- openssh-3.5p1/readconf.c.ORIG	Tue Jul  9 16:06:40 2002
+++ openssh-3.5p1/readconf.c	Wed Oct 16 14:59:12 2002
@@ -114,7 +114,7 @@
 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
-	oDeprecated
+	oConnectTimeout, oDeprecated
 } OpCodes;
 
 /* Textual representations of the tokens. */
@@ -186,6 +186,7 @@
 	{ "smartcarddevice", oSmartcardDevice },
 	{ "clearallforwardings", oClearAllForwardings },
 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
+	{ "connecttimeout", oConnectTimeout },
 	{ NULL, oBadOption }
 };
 
@@ -293,6 +294,18 @@
 		/* don't panic, but count bad options */
 		return -1;
 		/* NOTREACHED */
+	case oConnectTimeout:
+		intptr = &options->connection_timeout;
+parse_time:
+		arg = strdelim(&s);
+		if (!arg || *arg == '\0')
+			fatal("%.200s line %d: Missing time argument.", filename, linenum);
+		if ((value = convtime(arg)) == -1)
+			fatal("%.200s line %d: Invalid time argument.", filename, linenum);
+		if (*intptr == -1)
+			*intptr = value;
+		break;
+
 	case oForwardAgent:
 		intptr = &options->forward_agent;
 parse_flag:
@@ -769,6 +782,7 @@
 	options->compression_level = -1;
 	options->port = -1;
 	options->connection_attempts = -1;
+	options->connection_timeout = -1;
 	options->number_of_password_prompts = -1;
 	options->cipher = -1;
 	options->ciphers = NULL;
--- openssh-3.5p1/readconf.h.ORIG	Sun Jun  9 22:04:03 2002
+++ openssh-3.5p1/readconf.h	Wed Oct 16 14:59:12 2002
@@ -66,6 +66,8 @@
 	int     port;		/* Port to connect. */
 	int     connection_attempts;	/* Max attempts (seconds) before
 					 * giving up */
+	int     connection_timeout;	/* Max time (seconds) before
+				 	 * aborting connection attempt */
 	int     number_of_password_prompts;	/* Max number of password
 						 * prompts. */
 	int     cipher;		/* Cipher to use. */
--- openssh-3.5p1/ssh.c.ORIG	Thu Sep 19 04:05:04 2002
+++ openssh-3.5p1/ssh.c	Wed Oct 16 14:59:12 2002
@@ -616,7 +616,7 @@
 	/* Open a connection to the remote host. */
 
 	if (ssh_connect(host, &hostaddr, options.port, IPv4or6,
-	    options.connection_attempts,
+	    options.connection_attempts, options.connection_timeout,
 #ifdef HAVE_CYGWIN
 	    options.use_privileged_port,
 #else
--- openssh-3.5p1/ssh_config.0.ORIG	Fri Oct  4 03:31:47 2002
+++ openssh-3.5p1/ssh_config.0	Wed Oct 16 14:59:12 2002
@@ -112,6 +112,13 @@
              exiting.  The argument must be an integer.  This may be useful in
              scripts if the connection sometimes fails.  The default is 1.
 
+     ConnectTimeout
+             Specifies the timeout used when connecting to the ssh server,
+             instead of using default system values. This value is used only 
+             when the target is down or really unreachable, not when it refuses
+             the connection. This may be usefull for tools using ssh for
+             communication, as it avoid long TCP timeouts.
+
      DynamicForward
              Specifies that a TCP/IP port on the local machine be forwarded
              over the secure channel, and the application protocol is then
--- openssh-3.5p1/ssh_config.5.ORIG	Wed Sep  4 08:51:05 2002
+++ openssh-3.5p1/ssh_config.5	Wed Oct 16 14:59:12 2002
@@ -226,6 +226,12 @@
 The argument must be an integer.
 This may be useful in scripts if the connection sometimes fails.
 The default is 1.
+.It Cm ConnectTimeout
+Specifies the timeout used when connecting to the ssh
+server, instead of using default system values. This value is used
+only when the target is down or really unreachable, not when it
+refuses the connection. This may be usefull for tools using ssh
+for communication, as it avoid long TCP timeouts.
 .It Cm DynamicForward
 Specifies that a TCP/IP port on the local machine be forwarded
 over the secure channel, and the application
--- openssh-3.5p1/sshconnect.c.ORIG	Thu Sep 19 04:05:04 2002
+++ openssh-3.5p1/sshconnect.c	Wed Oct 16 14:59:12 2002
@@ -212,6 +212,61 @@
 	return sock;
 }
 
+int
+timeout_connect(int sockfd, const struct sockaddr *serv_addr,
+	socklen_t addrlen, int timeout)
+{
+	fd_set *fdset;
+	struct timeval tv;
+	socklen_t optlen;
+	int fdsetsz, optval, rc;
+
+	if (timeout <= 0)
+		return(connect(sockfd, serv_addr, addrlen));
+
+	if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0)
+		return -1;
+
+	rc = connect(sockfd, serv_addr, addrlen);
+	if (rc == 0)
+		return 0;
+	if (errno != EINPROGRESS)
+		return -1;
+
+	fdsetsz = howmany(sockfd+1, NFDBITS) * sizeof(fd_mask);
+	fdset = (fd_set *)xmalloc(fdsetsz);
+	memset(fdset, 0, fdsetsz);
+	FD_SET(sockfd, fdset);
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
+	rc=select(sockfd+1, NULL, fdset, NULL, &tv);
+
+	switch(rc) {
+	case 0:
+		errno = ETIMEDOUT;
+	case -1:
+		return -1;
+		break;
+	case 1:
+		optval = 0;
+		optlen = sizeof(optval);
+		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1)
+			return -1;
+		if (optval != 0)
+		{
+			errno = optval;
+			return -1;
+		}
+		return 0;
+
+	default:
+		/* Should not occur */
+		return -1;
+		break;
+	}
+	return -1;
+}
+
 /*
  * Opens a TCP/IP connection to the remote server on the given host.
  * The address of the remote host will be returned in hostaddr.
@@ -231,7 +286,7 @@
  */
 int
 ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
-    u_short port, int family, int connection_attempts,
+    u_short port, int family, int connection_attempts, int connection_timeout,
     int needpriv, const char *proxy_command)
 {
 	int gaierr;
@@ -300,7 +355,8 @@
 				/* Any error is already output */
 				continue;
 
-			if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) {
+			if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen,
+					connection_timeout) >= 0) {
 				/* Successful connection. */
 				memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
 				break;
--- openssh-3.5p1/sshconnect.h.ORIG	Fri Jun 21 02:41:53 2002
+++ openssh-3.5p1/sshconnect.h	Wed Oct 16 14:59:12 2002
@@ -35,7 +35,7 @@
 
 int
 ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int,
-    int, const char *);
+    int, int, const char *);
 
 void
 ssh_login(Sensitive *, const char *, struct sockaddr *, struct passwd *);


More information about the openssh-unix-dev mailing list