Connect timeout patch

Jean-Charles Longuet jclonguet at free.fr
Wed Apr 16 07:40:33 EST 2003


This patch avoids spending too much time during connect() when doing an
ssh()/scp() on a down host. It uses a new client option called
ConnectTimeout and is useful for rsync or rdist commands using ssh().

See http://bugzilla.mindrot.org/show_bug.cgi?id=207 for detailled info.
-------------- next part --------------
--- openssh-3.6.1p1/readconf.c.ORIG	Tue Apr 15 23:06:30 2003
+++ openssh-3.6.1p1/readconf.c	Tue Apr 15 23:09:43 2003
@@ -114,7 +114,7 @@
 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
-	oEnableSSHKeysign,
+	oEnableSSHKeysign, oConnectTimeout,
 	oDeprecated
 } OpCodes;
 
@@ -188,6 +188,7 @@
 	{ "clearallforwardings", oClearAllForwardings },
 	{ "enablesshkeysign", oEnableSSHKeysign },
 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
+	{ "connecttimeout", oConnectTimeout },
 	{ NULL, oBadOption }
 };
 
@@ -297,6 +298,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:
@@ -770,6 +783,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.6.1p1/readconf.h.ORIG	Tue Apr 15 23:06:30 2003
+++ openssh-3.6.1p1/readconf.h	Tue Apr 15 23:08:28 2003
@@ -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.6.1p1/ssh.c.ORIG	Tue Apr 15 23:06:30 2003
+++ openssh-3.6.1p1/ssh.c	Tue Apr 15 23:08:28 2003
@@ -619,7 +619,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.6.1p1/ssh_config.0.ORIG	Tue Apr 15 23:06:30 2003
+++ openssh-3.6.1p1/ssh_config.0	Tue Apr 15 23:11:06 2003
@@ -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.
 
+     ^[[1mConnectTimeout^[[0m
+             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.
+
      ^[[1mDynamicForward^[[0m
              Specifies that a TCP/IP port on the local machine be forwarded
              over the secure channel, and the application protocol is then
--- openssh-3.6.1p1/ssh_config.5.ORIG	Tue Apr 15 23:06:30 2003
+++ openssh-3.6.1p1/ssh_config.5	Tue Apr 15 23:08:28 2003
@@ -227,6 +227,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.6.1p1/sshconnect.c.ORIG	Tue Apr 15 23:06:30 2003
+++ openssh-3.6.1p1/sshconnect.c	Tue Apr 15 23:08:28 2003
@@ -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.6.1p1/sshconnect.h.ORIG	Tue Apr 15 23:06:30 2003
+++ openssh-3.6.1p1/sshconnect.h	Tue Apr 15 23:08:28 2003
@@ -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