summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--init.c5
-rw-r--r--options.c14
-rw-r--r--options.h2
-rw-r--r--socket.c94
-rw-r--r--socket.h2
-rw-r--r--syshead.h7
7 files changed, 122 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index f871d8e..e02b4d6 100644
--- 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 b3a999e..d6699e2 100644
--- 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,
diff --git a/options.c b/options.c
index b825a1a..72e2f4f 100644
--- 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);
diff --git a/options.h b/options.h
index 6d7b785..32e511c 100644
--- 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 */
diff --git a/socket.c b/socket.c
index ab6d6ee..2a85191 100644
--- 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);
diff --git a/socket.h b/socket.h
index 9083fca..b1a4aaa 100644
--- 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,
diff --git a/syshead.h b/syshead.h
index 9737a4b..d25b82c 100644
--- 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