]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Added --connect-timeout option to control the timeout
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Fri, 25 Nov 2005 00:05:56 +0000 (00:05 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Fri, 25 Nov 2005 00:05:56 +0000 (00:05 +0000)
on TCP client connection attempts (doesn't work on all
OSes).  This patch also makes OpenVPN signalable during
TCP connection attempts.

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@823 e7ae566f-a301-0410-adde-c780ea21d3b5

ChangeLog
init.c
options.c
options.h
socket.c
socket.h
syshead.h

index f871d8ead487a2a989054f70874cc9695090e7c1..e02b4d619610b60885eb9467167ca555e9d333b1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,7 +7,10 @@ $Id$
 
 * --remap-usr1 will now also remap signals thrown during
   initialization.
-
+* Added --connect-timeout option to control the timeout
+  on TCP client connection attempts (doesn't work on all
+  OSes).  This patch also makes OpenVPN signalable during
+  TCP connection attempts.
 2005.11.12 -- Version 2.1-beta7
 
 * Allow blank passwords to be passed via the management
diff --git a/init.c b/init.c
index b3a999e72724fd116e9c9df33121061724410531..d6699e2d21caf1553a4b79c862486a33f67c0c48 100644 (file)
--- a/init.c
+++ b/init.c
@@ -1673,7 +1673,11 @@ do_option_warnings (struct context *c)
       && !(o->ns_cert_type & NS_SSL_SERVER))
     msg (M_WARN, "WARNING: No server certificate verification method has been enabled.  See http://openvpn.net/howto.html#mitm for more info.");
 #endif
+#endif
 
+#ifndef CONNECT_NONBLOCK
+  if (o->connect_timeout_defined)
+    msg (M_WARN, "NOTE: --connect-timeout option is not supported on this OS");
 #endif
 }
 
@@ -1813,6 +1817,7 @@ do_init_socket_1 (struct context *c, int mode)
                           c->plugins,
                           c->options.resolve_retry_seconds,
                           c->options.connect_retry_seconds,
+                          c->options.connect_timeout,
                           c->options.connect_retry_max,
                           c->options.mtu_discover_type,
                           c->options.rcvbuf,
index b825a1a1e262d88cf9283055de0d3975cccefd2c..72e2f4fa57d8d7aa495d133c615ee02d876b7381 100644 (file)
--- a/options.c
+++ b/options.c
@@ -94,7 +94,8 @@ static const char usage_message[] =
   "--proto p       : Use protocol p for communicating with peer.\n"
   "                  p = udp (default), tcp-server, or tcp-client\n"
   "--connect-retry n : For --proto tcp-client, number of seconds to wait\n"
-  "                  between connection retries (default=%d).\n"
+  "                    between connection retries (default=%d).\n"
+  "--connect-timeout n : For --proto tcp-client, connection timeout (in seconds).\n"
   "--connect-retry-max n : Maximum connection attempt retries, default infinite.\n"
 #ifdef ENABLE_HTTP_PROXY
   "--http-proxy s p [up] [auth] : Connect to remote host through an HTTP proxy at\n"
@@ -598,6 +599,7 @@ init_options (struct options *o)
   o->topology = TOP_NET30;
   o->proto = PROTO_UDPv4;
   o->connect_retry_seconds = 5;
+  o->connect_timeout = 10;
   o->connect_retry_max = 0;
   o->local_port = o->remote_port = OPENVPN_PORT;
   o->verbosity = 1;
@@ -1099,6 +1101,7 @@ show_settings (const struct options *o)
 
   SHOW_INT (resolve_retry_seconds);
   SHOW_INT (connect_retry_seconds);
+  SHOW_INT (connect_timeout);
   SHOW_INT (connect_retry_max);
 
   SHOW_STR (username);
@@ -1381,6 +1384,9 @@ options_postprocess (struct options *options, bool first_time)
   if (options->connect_retry_defined && options->proto != PROTO_TCPv4_CLIENT)
     msg (M_USAGE, "--connect-retry doesn't make sense unless also used with --proto tcp-client");
 
+  if (options->connect_timeout_defined && options->proto != PROTO_TCPv4_CLIENT)
+    msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with --proto tcp-client");
+
   /*
    * Sanity check on MTU parameters
    */
@@ -3240,6 +3246,12 @@ add_option (struct options *options,
       options->connect_retry_seconds = positive_atoi (p[1]);
       options->connect_retry_defined = true;
     }
+  else if (streq (p[0], "connect-timeout") && p[1])
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      options->connect_timeout = positive_atoi (p[1]);
+      options->connect_timeout_defined = true;
+    }
   else if (streq (p[0], "connect-retry-max") && p[1])
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
index 6d7b7858b3a6d954e8ebba9ab30feb1c49e38aea..32e511c68c2c4d26b1d9f58ef34cb2fdee8e36d5 100644 (file)
--- a/options.h
+++ b/options.h
@@ -149,6 +149,8 @@ struct options
   int connect_retry_seconds;
   int connect_retry_max;
   bool connect_retry_defined;
+  int connect_timeout;
+  bool connect_timeout_defined;
 
   /* Advanced MTU negotiation and datagram fragmentation options */
   int mtu_discover_type; /* used if OS supports setting Path MTU discovery options on socket */
index ab6d6eeac5e7f2864ed900fea90ff442a0042519..2a85191fc7d19f770f8b7a12a3a5728eebc37caa 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -712,6 +712,79 @@ socket_bind (socket_descriptor_t sd,
   gc_free (&gc);
 }
 
+static int
+openvpn_connect (socket_descriptor_t sd,
+                struct openvpn_sockaddr *remote,
+                int connect_timeout,
+                volatile int *signal_received)
+{
+  int status = 0;
+
+#ifdef CONNECT_NONBLOCK
+  set_nonblock (sd);
+  status = connect (sd, (struct sockaddr *) &remote->sa, sizeof (remote->sa));
+  if (status)
+    status = openvpn_errno_socket ();
+  if (status == EINPROGRESS)
+    {
+      while (true)
+       {
+         fd_set writes;
+         struct timeval tv;
+
+         FD_ZERO (&writes);
+         FD_SET (sd, &writes);
+         tv.tv_sec = 0;
+         tv.tv_usec = 0;
+
+         status = select (sd + 1, NULL, &writes, NULL, &tv);
+
+         get_signal (signal_received);
+         if (*signal_received)
+           {
+             status = 0;
+             break;
+           }
+         if (status < 0)
+           {
+             status = openvpn_errno_socket ();
+             break;
+           }
+         if (status <= 0)
+           {
+             if (--connect_timeout < 0)
+               {
+                 status = ETIMEDOUT;
+                 break;
+               }
+             openvpn_sleep (1);
+             continue;
+           }
+
+         /* got it */
+         {
+           int val = 0;
+           socklen_t len;
+
+           len = sizeof (val);
+           if (getsockopt (sd, SOL_SOCKET, SO_ERROR, (void *) &val, &len) == 0
+               && len == sizeof (val))
+             status = val;
+           else
+             status = openvpn_errno_socket ();
+           break;
+         }
+       }
+    }
+#else
+  status = connect (sd, (struct sockaddr *) &remote->sa, sizeof (remote->sa));
+  if (status)
+    status = openvpn_errno_socket ();
+#endif
+
+  return status;
+}
+
 static void
 socket_connect (socket_descriptor_t *sd,
                 struct openvpn_sockaddr *local,
@@ -721,18 +794,24 @@ socket_connect (socket_descriptor_t *sd,
                const char *remote_dynamic,
                bool *remote_changed,
                const int connect_retry_seconds,
+               const int connect_timeout,
                const int connect_retry_max,
                volatile int *signal_received)
 {
   struct gc_arena gc = gc_new ();
   int retry = 0;
 
+#ifdef CONNECT_NONBLOCK
+  msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]", 
+       print_sockaddr (remote, &gc));
+#else
   msg (M_INFO, "Attempting to establish TCP connection with %s", 
        print_sockaddr (remote, &gc));
+#endif
+
   while (true)
     {
-      const int status = connect (*sd, (struct sockaddr *) &remote->sa,
-                                 sizeof (remote->sa));
+      const int status = openvpn_connect (*sd, remote, connect_timeout, signal_received);
 
       if (connect_retry_max != 0 && retry++ >= connect_retry_max)
        *signal_received = SIGUSR1;
@@ -744,10 +823,11 @@ socket_connect (socket_descriptor_t *sd,
       if (!status)
        break;
 
-      msg (D_LINK_ERRORS | M_ERRNO_SOCK,
-          "TCP: connect to %s failed, will try again in %d seconds",
+      msg (D_LINK_ERRORS,
+          "TCP: connect to %s failed, will try again in %d seconds: %s",
           print_sockaddr (remote, &gc),
-          connect_retry_seconds);
+          connect_retry_seconds,
+          strerror_ts (status, &gc));
 
       openvpn_close_socket (*sd);
       openvpn_sleep (connect_retry_seconds);
@@ -992,6 +1072,7 @@ link_socket_init_phase1 (struct link_socket *sock,
                         const struct plugin_list *plugins,
                         int resolve_retry_seconds,
                         int connect_retry_seconds,
+                        int connect_timeout,
                         int connect_retry_max,
                         int mtu_discover_type,
                         int rcvbuf,
@@ -1023,6 +1104,7 @@ link_socket_init_phase1 (struct link_socket *sock,
   sock->inetd = inetd;
   sock->resolve_retry_seconds = resolve_retry_seconds;
   sock->connect_retry_seconds = connect_retry_seconds;
+  sock->connect_timeout = connect_timeout;
   sock->connect_retry_max = connect_retry_max;
   sock->mtu_discover_type = mtu_discover_type;
 
@@ -1222,6 +1304,7 @@ link_socket_init_phase2 (struct link_socket *sock,
                          remote_dynamic,
                          &remote_changed,
                          sock->connect_retry_seconds,
+                         sock->connect_timeout,
                          sock->connect_retry_max,
                          signal_received);
 
@@ -1263,6 +1346,7 @@ link_socket_init_phase2 (struct link_socket *sock,
                          remote_dynamic,
                          &remote_changed,
                          sock->connect_retry_seconds,
+                         sock->connect_timeout,
                          sock->connect_retry_max,
                          signal_received);
 
index 9083fcae82cf03da642e8307bb74f3d03f0fe910..b1a4aaa5065c17bb6f1fac89d273df000f76e391 100644 (file)
--- a/socket.h
+++ b/socket.h
@@ -189,6 +189,7 @@ struct link_socket
 
   int resolve_retry_seconds;
   int connect_retry_seconds;
+  int connect_timeout;
   int connect_retry_max;
   int mtu_discover_type;
 
@@ -300,6 +301,7 @@ link_socket_init_phase1 (struct link_socket *sock,
                         const struct plugin_list *plugins,
                         int resolve_retry_seconds,
                         int connect_retry_seconds,
+                        int connect_timeout,
                         int connect_retry_max,
                         int mtu_discover_type,
                         int rcvbuf,
index 9737a4b690dfa0748eb5b7289f9e1a845bd7f406..d25b82c809ba015ffe82c53730f01f2f93c86d67 100644 (file)
--- a/syshead.h
+++ b/syshead.h
@@ -478,4 +478,11 @@ socket_defined (const socket_descriptor_t sd)
  */
 #define TIME_BACKTRACK_PROTECTION 1
 
+/*
+ * Is non-blocking connect() supported?
+ */
+#if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_ERROR) && defined(EINPROGRESS) && defined(ETIMEDOUT)
+#define CONNECT_NONBLOCK
+#endif
+
 #endif