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 *);