[PATCH] connect() timeout

Jean-Charles Longuet jclonguet at free.fr
Thu Apr 4 07:58:25 EST 2002


Here is a version of this widely used patch specific for OpenSSH 3.1p1,
as it is still not in the main tree (perhap one day...)

The patch avoids spending too much time when doing an ssh()/scp() on a
down host, as it does not depend off the default TCP timeout used
by connect().


 Patch was tested on Linux, Solaris and HP-UX.

 The patch can also be found on:
http://charts.free.fr/openssh-3.1p1-timeout.patch


 Hope it will help you...

--
        Jean-Charles Longuet
-------------- next part --------------
--- openssh-3.1p1/readconf.c.ORIG	Tue Feb  5 02:26:35 2002
+++ openssh-3.1p1/readconf.c	Wed Apr  3 23:34:34 2002
@@ -115,7 +115,8 @@
 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
-	oClearAllForwardings, oNoHostAuthenticationForLocalhost
+	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
+	oConnectTimeout
 } OpCodes;
 
 /* Textual representations of the tokens. */
@@ -187,6 +188,7 @@
 	{ "smartcarddevice", oSmartcardDevice },
 	{ "clearallforwardings", oClearAllForwardings },
 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
+	{ "connecttimeout", oConnectTimeout },
 	{ NULL, oBadOption }
 };
 
@@ -294,6 +296,19 @@
 		/* 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:
@@ -775,6 +790,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.1p1/readconf.h.ORIG	Tue Mar  5 02:53:05 2002
+++ openssh-3.1p1/readconf.h	Wed Apr  3 23:33:48 2002
@@ -68,6 +68,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.1p1/ssh.1.ORIG	Tue Feb 19 05:27:24 2002
+++ openssh-3.1p1/ssh.1	Wed Apr  3 23:33:48 2002
@@ -807,6 +807,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.1p1/ssh.c.ORIG	Tue Feb 19 05:20:58 2002
+++ openssh-3.1p1/ssh.c	Wed Apr  3 23:33:48 2002
@@ -674,7 +674,7 @@
 	/* Open a connection to the remote host. */
 
 	cerr = ssh_connect(host, &hostaddr, options.port, IPv4or6,
-	    options.connection_attempts,
+	    options.connection_attempts, options.connection_timeout,
 	    original_effective_uid != 0 || !options.use_privileged_port,
 	    pw, options.proxy_command);
 
--- openssh-3.1p1/sshconnect.c.ORIG	Tue Mar  5 19:59:46 2002
+++ openssh-3.1p1/sshconnect.c	Wed Apr  3 23:33:48 2002
@@ -222,6 +222,64 @@
 	return sock;
 }
 
+int
+timeout_connect(int sockfd, const struct sockaddr *serv_addr,
+    socklen_t addrlen, int timeout)
+{
+	int rc;
+	fd_set fds;
+
+        int optval = 0;
+        socklen_t optlen = sizeof(optval);
+	struct timeval tv;
+
+
+	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;
+
+	FD_ZERO(&fds);
+	FD_SET(sockfd, &fds);
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
+	rc=select(sockfd+1, NULL, &fds, NULL, &tv);
+
+	switch(rc) {
+	case 0:
+		errno = ETIMEDOUT;
+	case -1:
+		return -1;
+		break;
+	case 1:
+		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.
@@ -241,7 +299,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 anonymous, struct passwd *pw, const char *proxy_command)
 {
 	int gaierr;
@@ -323,7 +381,8 @@
 			 * the remote uid as root.
 			 */
 			temporarily_use_uid(pw);
-			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);
 				restore_uid();
--- openssh-3.1p1/sshconnect.h.ORIG	Wed Oct 10 07:07:45 2001
+++ openssh-3.1p1/sshconnect.h	Wed Apr  3 23:33:48 2002
@@ -28,7 +28,7 @@
 
 int
 ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int,
-    int, struct passwd *, const char *);
+    int, int, struct passwd *, const char *);
 
 void
 ssh_login(Key **, int, const char *, struct sockaddr *, struct passwd *);


More information about the openssh-unix-dev mailing list