[PATCH] connect() timeout
Jean-Charles Longuet
jclonguet at free.fr
Thu May 23 05:10:47 EST 2002
Here are the new versions of this widely used patch for OpenSSH 3.2.2p1
and 3.2.3p1.
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.2.2p1/readconf.c.ORIG Tue Feb 5 02:26:35 2002
+++ openssh-3.2.2p1/readconf.c Tue May 21 15:40:06 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.2.2p1/readconf.h.ORIG Tue Mar 5 02:53:05 2002
+++ openssh-3.2.2p1/readconf.h Tue May 21 15:40:06 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.2.2p1/ssh.1.ORIG Wed May 15 23:36:46 2002
+++ openssh-3.2.2p1/ssh.1 Tue May 21 15:40:06 2002
@@ -813,6 +813,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.2.2p1/ssh.c.ORIG Tue Apr 23 13:09:46 2002
+++ openssh-3.2.2p1/ssh.c Tue May 21 15:40:06 2002
@@ -677,7 +677,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.2.2p1/sshconnect.c.ORIG Tue Mar 5 19:59:46 2002
+++ openssh-3.2.2p1/sshconnect.c Tue May 21 15:40:06 2002
@@ -222,6 +222,63 @@
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.
@@ -241,7 +298,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 +380,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.2.2p1/sshconnect.h.ORIG Wed Oct 10 07:07:45 2001
+++ openssh-3.2.2p1/sshconnect.h Tue May 21 15:40:06 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 *);
-------------- next part --------------
--- openssh-3.2.3p1/readconf.c.ORIG Tue Feb 5 02:26:35 2002
+++ openssh-3.2.3p1/readconf.c Wed May 22 19:45:13 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.2.3p1/readconf.h.ORIG Tue Mar 5 02:53:05 2002
+++ openssh-3.2.3p1/readconf.h Wed May 22 19:45:13 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.2.3p1/ssh.1.ORIG Wed May 15 23:36:46 2002
+++ openssh-3.2.3p1/ssh.1 Wed May 22 19:45:13 2002
@@ -813,6 +813,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.2.3p1/ssh.c.ORIG Tue Apr 23 13:09:46 2002
+++ openssh-3.2.3p1/ssh.c Wed May 22 19:45:13 2002
@@ -677,7 +677,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.2.3p1/sshconnect.c.ORIG Tue Mar 5 19:59:46 2002
+++ openssh-3.2.3p1/sshconnect.c Wed May 22 19:45:13 2002
@@ -222,6 +222,63 @@
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.
@@ -241,7 +298,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 +380,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.2.3p1/sshconnect.h.ORIG Wed Oct 10 07:07:45 2001
+++ openssh-3.2.3p1/sshconnect.h Wed May 22 19:45:13 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