* --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
&& !(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
}
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,
"--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"
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;
SHOW_INT (resolve_retry_seconds);
SHOW_INT (connect_retry_seconds);
+ SHOW_INT (connect_timeout);
SHOW_INT (connect_retry_max);
SHOW_STR (username);
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
*/
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);
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 */
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,
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;
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);
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,
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;
remote_dynamic,
&remote_changed,
sock->connect_retry_seconds,
+ sock->connect_timeout,
sock->connect_retry_max,
signal_received);
remote_dynamic,
&remote_changed,
sock->connect_retry_seconds,
+ sock->connect_timeout,
sock->connect_retry_max,
signal_received);
int resolve_retry_seconds;
int connect_retry_seconds;
+ int connect_timeout;
int connect_retry_max;
int mtu_discover_type;
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,
*/
#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