shill: openvpn: Use different reconnect timeouts for tls-error and offline.
When the system goes offline, use reconnect timeout of 2 minutes rather than one
to allow the user more time to reconnect. When the connect attempt fails due to
tls-error, limit the timeout to 20 seconds because it's most likely due to bad
certificates and 20 seconds should be enough to adjust for intermittent
failures.
Also, cleanup some FRIEND_TESTs for unit tests that this patch touches.
BUG=chromium-os:36355,chromium-os:38674
TEST=unit tests; tested by connecting to corp VPN, disconnect WiFi, re-connect
WiFi after a minute, observe VPN reconnect; tested by connecting test OpenVPN
with bad CA certificate and observe reduced reconnect timeout; inspected logs.
Change-Id: I2e7c7b34fbe46355a34f2c9a3b3125e25950bb3e
Reviewed-on: https://gerrit.chromium.org/gerrit/43036
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Commit-Queue: Darin Petkov <petkov@chromium.org>
diff --git a/l2tp_ipsec_driver.cc b/l2tp_ipsec_driver.cc
index fdd18d4..0451bf5 100644
--- a/l2tp_ipsec_driver.cc
+++ b/l2tp_ipsec_driver.cc
@@ -96,7 +96,7 @@
}
void L2TPIPSecDriver::Connect(const VPNServiceRefPtr &service, Error *error) {
- StartConnectTimeout();
+ StartConnectTimeout(kDefaultConnectTimeoutSeconds);
service_ = service;
service_->SetState(Service::kStateConfiguring);
rpc_task_.reset(new RPCTask(control_, this));
diff --git a/l2tp_ipsec_driver.h b/l2tp_ipsec_driver.h
index 60722cf..12d38e1 100644
--- a/l2tp_ipsec_driver.h
+++ b/l2tp_ipsec_driver.h
@@ -72,7 +72,6 @@
FRIEND_TEST(L2TPIPSecDriverTest, InitOptions);
FRIEND_TEST(L2TPIPSecDriverTest, InitOptionsNoHost);
FRIEND_TEST(L2TPIPSecDriverTest, InitPSKOptions);
- FRIEND_TEST(L2TPIPSecDriverTest, Notify);
FRIEND_TEST(L2TPIPSecDriverTest, NotifyDisconnected);
FRIEND_TEST(L2TPIPSecDriverTest, OnConnectionDisconnected);
FRIEND_TEST(L2TPIPSecDriverTest, OnL2TPIPSecVPNDied);
diff --git a/l2tp_ipsec_driver_unittest.cc b/l2tp_ipsec_driver_unittest.cc
index 9f2b9b6..9791ee5 100644
--- a/l2tp_ipsec_driver_unittest.cc
+++ b/l2tp_ipsec_driver_unittest.cc
@@ -88,6 +88,10 @@
return driver_->GetProviderType();
}
+ void SetDevice(const VPNRefPtr &device) {
+ driver_->device_ = device;
+ }
+
void SetService(const VPNServiceRefPtr &service) {
driver_->service_ = service;
}
@@ -100,8 +104,8 @@
driver_->OnConnectTimeout();
}
- void StartConnectTimeout() {
- driver_->StartConnectTimeout();
+ void StartConnectTimeout(int timeout_seconds) {
+ driver_->StartConnectTimeout(timeout_seconds);
}
bool IsConnectTimeoutStarted() {
@@ -114,6 +118,12 @@
FilePath SetupPSKFile();
+ FilePath GetPSKFile() { return driver_->psk_file_; }
+
+ void InvokeNotify(const string &reason, const map<string, string> &dict) {
+ driver_->Notify(reason, dict);
+ }
+
// Inherited from RPCTaskDelegate.
virtual void GetLogin(string *user, string *password);
virtual void Notify(const string &reason, const map<string, string> &dict);
@@ -209,7 +219,7 @@
EXPECT_CALL(*service_, SetState(Service::kStateFailure));
driver_->rpc_task_.reset(new RPCTask(&control_, this));
FilePath psk_file = SetupPSKFile();
- driver_->StartConnectTimeout();
+ StartConnectTimeout(0);
driver_->Cleanup(Service::kStateFailure);
EXPECT_FALSE(file_util::PathExists(psk_file));
EXPECT_TRUE(driver_->psk_file_.empty());
@@ -483,7 +493,7 @@
}
TEST_F(L2TPIPSecDriverTest, OnConnectTimeout) {
- StartConnectTimeout();
+ StartConnectTimeout(0);
SetService(service_);
EXPECT_CALL(*service_, SetState(Service::kStateFailure));
OnConnectTimeout();
@@ -572,13 +582,13 @@
.WillOnce(Return(kInterfaceIndex));
EXPECT_CALL(*device_, SetEnabled(true));
EXPECT_CALL(*device_, UpdateIPConfig(_));
- driver_->device_ = device_;
+ SetDevice(device_);
FilePath psk_file = SetupPSKFile();
- driver_->StartConnectTimeout();
- driver_->Notify(kL2TPIPSecReasonConnect, config);
+ StartConnectTimeout(0);
+ InvokeNotify(kL2TPIPSecReasonConnect, config);
EXPECT_FALSE(file_util::PathExists(psk_file));
- EXPECT_TRUE(driver_->psk_file_.empty());
- EXPECT_FALSE(driver_->IsConnectTimeoutStarted());
+ EXPECT_TRUE(GetPSKFile().empty());
+ EXPECT_FALSE(IsConnectTimeoutStarted());
}
TEST_F(L2TPIPSecDriverTest, NotifyDisconnected) {
diff --git a/mock_openvpn_driver.h b/mock_openvpn_driver.h
index 7bc6a89..33bfd4a 100644
--- a/mock_openvpn_driver.h
+++ b/mock_openvpn_driver.h
@@ -16,7 +16,7 @@
MockOpenVPNDriver();
virtual ~MockOpenVPNDriver();
- MOCK_METHOD0(OnReconnecting, void());
+ MOCK_METHOD1(OnReconnecting, void(ReconnectReason reason));
MOCK_METHOD1(Cleanup, void(Service::ConnectState state));
private:
diff --git a/openvpn_driver.cc b/openvpn_driver.cc
index 5551baf..c3c9afb 100644
--- a/openvpn_driver.cc
+++ b/openvpn_driver.cc
@@ -119,13 +119,12 @@
{ flimflam::kOpenVPNMgmtEnableProperty, 0 },
};
-// static
const char OpenVPNDriver::kLSBReleaseFile[] = "/etc/lsb-release";
-// static
const char OpenVPNDriver::kChromeOSReleaseName[] = "CHROMEOS_RELEASE_NAME";
-//static
const char OpenVPNDriver::kChromeOSReleaseVersion[] =
"CHROMEOS_RELEASE_VERSION";
+const int OpenVPNDriver::kReconnectOfflineTimeoutSeconds = 2 * 60;
+const int OpenVPNDriver::kReconnectTLSErrorTimeoutSeconds = 20;
OpenVPNDriver::OpenVPNDriver(ControlInterface *control,
EventDispatcher *dispatcher,
@@ -470,7 +469,7 @@
}
void OpenVPNDriver::Connect(const VPNServiceRefPtr &service, Error *error) {
- StartConnectTimeout();
+ StartConnectTimeout(kDefaultConnectTimeoutSeconds);
service_ = service;
service_->SetState(Service::kStateConfiguring);
if (!device_info_->CreateTunnelInterface(&tunnel_interface_)) {
@@ -745,7 +744,7 @@
// and openvpn will not lead to a permanently stale connectivity state. Note
// that a subsequent invocation of OnReconnecting due to a RECONNECTING
// message will essentially be a no-op.
- OnReconnecting();
+ OnReconnecting(kReconnectReasonOffline);
}
void OpenVPNDriver::OnConnectTimeout() {
@@ -753,9 +752,16 @@
Cleanup(Service::kStateFailure);
}
-void OpenVPNDriver::OnReconnecting() {
- SLOG(VPN, 2) << __func__;
- StartConnectTimeout();
+void OpenVPNDriver::OnReconnecting(ReconnectReason reason) {
+ LOG(INFO) << __func__ << "(" << reason << ")";
+ int timeout_seconds = GetReconnectTimeoutSeconds(reason);
+ if (reason == kReconnectReasonTLSError &&
+ timeout_seconds < connect_timeout_seconds()) {
+ // Reconnect due to TLS error happens during connect so we need to cancel
+ // the original connect timeout first and then reduce the time limit.
+ StopConnectTimeout();
+ }
+ StartConnectTimeout(timeout_seconds);
// On restart/reconnect, drop the VPN connection, if any. The openvpn client
// might be in hold state if the VPN connection was previously established
// successfully. The hold will be released by OnDefaultServiceChanged when a
@@ -769,6 +775,19 @@
}
}
+// static
+int OpenVPNDriver::GetReconnectTimeoutSeconds(ReconnectReason reason) {
+ switch (reason) {
+ case kReconnectReasonOffline:
+ return kReconnectOfflineTimeoutSeconds;
+ case kReconnectReasonTLSError:
+ return kReconnectTLSErrorTimeoutSeconds;
+ default:
+ break;
+ }
+ return kDefaultConnectTimeoutSeconds;
+}
+
string OpenVPNDriver::GetProviderType() const {
return flimflam::kProviderOpenVpn;
}
diff --git a/openvpn_driver.h b/openvpn_driver.h
index dc85576..72784ba 100644
--- a/openvpn_driver.h
+++ b/openvpn_driver.h
@@ -41,6 +41,12 @@
class OpenVPNDriver : public VPNDriver,
public RPCTaskDelegate {
public:
+ enum ReconnectReason {
+ kReconnectReasonUnknown,
+ kReconnectReasonOffline,
+ kReconnectReasonTLSError,
+ };
+
OpenVPNDriver(ControlInterface *control,
EventDispatcher *dispatcher,
Metrics *metrics,
@@ -49,7 +55,7 @@
GLib *glib);
virtual ~OpenVPNDriver();
- virtual void OnReconnecting();
+ virtual void OnReconnecting(ReconnectReason reason);
virtual void Cleanup(Service::ConnectState state);
@@ -99,7 +105,6 @@
FRIEND_TEST(OpenVPNDriverTest, NotifyFail);
FRIEND_TEST(OpenVPNDriverTest, OnDefaultServiceChanged);
FRIEND_TEST(OpenVPNDriverTest, OnOpenVPNDied);
- FRIEND_TEST(OpenVPNDriverTest, OnReconnecting);
FRIEND_TEST(OpenVPNDriverTest, ParseForeignOption);
FRIEND_TEST(OpenVPNDriverTest, ParseForeignOptions);
FRIEND_TEST(OpenVPNDriverTest, ParseIPConfiguration);
@@ -110,6 +115,11 @@
FRIEND_TEST(OpenVPNDriverTest, SplitPortFromHost);
FRIEND_TEST(OpenVPNDriverTest, VerifyPaths);
+ // The map is a sorted container that allows us to iterate through the options
+ // in order.
+ typedef std::map<int, std::string> ForeignOptions;
+ typedef std::map<int, IPConfig::Route> RouteOptions;
+
static const char kOpenVPNCertProperty[];
static const char kOpenVPNKeyProperty[];
@@ -123,10 +133,8 @@
static const char kChromeOSReleaseName[];
static const char kChromeOSReleaseVersion[];
- // The map is a sorted container that allows us to iterate through the options
- // in order.
- typedef std::map<int, std::string> ForeignOptions;
- typedef std::map<int, IPConfig::Route> RouteOptions;
+ static const int kReconnectOfflineTimeoutSeconds;
+ static const int kReconnectTLSErrorTimeoutSeconds;
static void ParseIPConfiguration(
const std::map<std::string, std::string> &configuration,
@@ -164,6 +172,8 @@
bool SpawnOpenVPN();
+ static int GetReconnectTimeoutSeconds(ReconnectReason reason);
+
// Called when the openpvn process exits.
static void OnOpenVPNDied(GPid pid, gint status, gpointer data);
diff --git a/openvpn_driver_unittest.cc b/openvpn_driver_unittest.cc
index 900dfa6..268e9ce 100644
--- a/openvpn_driver_unittest.cc
+++ b/openvpn_driver_unittest.cc
@@ -18,6 +18,7 @@
#include "shill/logging.h"
#include "shill/mock_adaptors.h"
#include "shill/mock_device_info.h"
+#include "shill/mock_event_dispatcher.h"
#include "shill/mock_glib.h"
#include "shill/mock_manager.h"
#include "shill/mock_metrics.h"
@@ -143,14 +144,30 @@
driver_->OnConnectTimeout();
}
- void StartConnectTimeout() {
- driver_->StartConnectTimeout();
+ void StartConnectTimeout(int timeout_seconds) {
+ driver_->StartConnectTimeout(timeout_seconds);
}
bool IsConnectTimeoutStarted() {
return driver_->IsConnectTimeoutStarted();
}
+ static int GetDefaultConnectTimeoutSeconds() {
+ return OpenVPNDriver::kDefaultConnectTimeoutSeconds;
+ }
+
+ static int GetReconnectOfflineTimeoutSeconds() {
+ return OpenVPNDriver::kReconnectOfflineTimeoutSeconds;
+ }
+
+ static int GetReconnectTLSErrorTimeoutSeconds() {
+ return OpenVPNDriver::kReconnectTLSErrorTimeoutSeconds;
+ }
+
+ static int GetReconnectTimeoutSeconds(OpenVPNDriver::ReconnectReason reason) {
+ return OpenVPNDriver::GetReconnectTimeoutSeconds(reason);
+ }
+
// Used to assert that a flag appears in the options.
void ExpectInFlags(const vector<string> &options, const string &flag,
const string &value);
@@ -165,7 +182,7 @@
NiceMockControl control_;
NiceMock<MockDeviceInfo> device_info_;
- EventDispatcher dispatcher_;
+ MockEventDispatcher dispatcher_;
MockMetrics metrics_;
MockGLib glib_;
MockManager manager_;
@@ -283,7 +300,7 @@
map<string, string> config;
driver_->service_ = service_;
driver_->device_ = device_;
- driver_->StartConnectTimeout();
+ StartConnectTimeout(0);
EXPECT_CALL(*device_,
UpdateIPConfig(Field(&IPConfig::Properties::address, "")));
driver_->Notify("up", config);
@@ -300,7 +317,7 @@
TEST_F(OpenVPNDriverTest, NotifyFail) {
map<string, string> dict;
driver_->device_ = device_;
- driver_->StartConnectTimeout();
+ StartConnectTimeout(0);
EXPECT_CALL(*device_, OnDisconnected());
driver_->Notify("fail", dict);
EXPECT_TRUE(driver_->IsConnectTimeoutStarted());
@@ -792,7 +809,7 @@
driver_->device_ = device_;
driver_->service_ = service_;
driver_->ip_properties_.address = "1.2.3.4";
- driver_->StartConnectTimeout();
+ StartConnectTimeout(0);
FilePath tls_auth_file;
EXPECT_TRUE(file_util::CreateTemporaryFile(&tls_auth_file));
EXPECT_FALSE(tls_auth_file.empty());
@@ -896,7 +913,7 @@
}
TEST_F(OpenVPNDriverTest, OnConnectTimeout) {
- StartConnectTimeout();
+ StartConnectTimeout(0);
SetService(service_);
EXPECT_CALL(*service_, SetState(Service::kStateFailure));
OnConnectTimeout();
@@ -904,14 +921,39 @@
EXPECT_FALSE(IsConnectTimeoutStarted());
}
-TEST_F(OpenVPNDriverTest, OnReconnecting) {
- driver_->OnReconnecting(); // Expect no crash.
- driver_->device_ = device_;
- driver_->service_ = service_;
+TEST_F(OpenVPNDriverTest, OnReconnectingUnknown) {
+ EXPECT_FALSE(IsConnectTimeoutStarted());
+ EXPECT_CALL(dispatcher_,
+ PostDelayedTask(_, GetDefaultConnectTimeoutSeconds() * 1000))
+ .WillOnce(Return(true));
+ SetDevice(device_);
+ SetService(service_);
EXPECT_CALL(*device_, OnDisconnected());
EXPECT_CALL(*service_, SetState(Service::kStateAssociating));
- driver_->OnReconnecting();
- EXPECT_TRUE(driver_->IsConnectTimeoutStarted());
+ driver_->OnReconnecting(OpenVPNDriver::kReconnectReasonUnknown);
+ EXPECT_TRUE(IsConnectTimeoutStarted());
+}
+
+TEST_F(OpenVPNDriverTest, OnReconnectingTLSError) {
+ EXPECT_CALL(dispatcher_,
+ PostDelayedTask(_, GetReconnectOfflineTimeoutSeconds() * 1000))
+ .WillOnce(Return(true));
+ EXPECT_CALL(dispatcher_,
+ PostDelayedTask(_, GetReconnectTLSErrorTimeoutSeconds() * 1000))
+ .WillOnce(Return(true));
+
+ driver_->OnReconnecting(OpenVPNDriver::kReconnectReasonOffline);
+ EXPECT_TRUE(IsConnectTimeoutStarted());
+
+ // The scheduled timeout should not be affected for unknown reason.
+ driver_->OnReconnecting(OpenVPNDriver::kReconnectReasonUnknown);
+ EXPECT_TRUE(IsConnectTimeoutStarted());
+
+ // Reconnect on TLS error reschedules the timeout once.
+ driver_->OnReconnecting(OpenVPNDriver::kReconnectReasonTLSError);
+ EXPECT_TRUE(IsConnectTimeoutStarted());
+ driver_->OnReconnecting(OpenVPNDriver::kReconnectReasonTLSError);
+ EXPECT_TRUE(IsConnectTimeoutStarted());
}
TEST_F(OpenVPNDriverTest, VerifyPaths) {
@@ -1030,4 +1072,14 @@
driver_->OnDefaultServiceChanged(mock_service);
}
+TEST_F(OpenVPNDriverTest, GetReconnectTimeoutSeconds) {
+ EXPECT_EQ(GetDefaultConnectTimeoutSeconds(),
+ GetReconnectTimeoutSeconds(OpenVPNDriver::kReconnectReasonUnknown));
+ EXPECT_EQ(GetReconnectOfflineTimeoutSeconds(),
+ GetReconnectTimeoutSeconds(OpenVPNDriver::kReconnectReasonOffline));
+ EXPECT_EQ(GetReconnectTLSErrorTimeoutSeconds(),
+ GetReconnectTimeoutSeconds(
+ OpenVPNDriver::kReconnectReasonTLSError));
+}
+
} // namespace shill
diff --git a/openvpn_management_server.cc b/openvpn_management_server.cc
index ff1955a..4b0092d 100644
--- a/openvpn_management_server.cc
+++ b/openvpn_management_server.cc
@@ -318,11 +318,17 @@
vector<string> details;
SplitString(message, ',', &details);
if (details.size() > 1) {
- LOG(INFO) << "Processing state message: " << details[1];
if (details[1] == "RECONNECTING") {
- driver_->OnReconnecting();
+ OpenVPNDriver::ReconnectReason reason =
+ OpenVPNDriver::kReconnectReasonUnknown;
+ if (details.size() > 2 && details[2] == "tls-error") {
+ reason = OpenVPNDriver::kReconnectReasonTLSError;
+ }
+ driver_->OnReconnecting(reason);
+ } else {
+ // The rest of the states are currently ignored.
+ LOG(INFO) << "Ignoring state message: " << details[1];
}
- // The rest of the states are currently ignored.
}
return true;
}
diff --git a/openvpn_management_server.h b/openvpn_management_server.h
index 5e7ef2d..72e0f74 100644
--- a/openvpn_management_server.h
+++ b/openvpn_management_server.h
@@ -52,7 +52,6 @@
friend class OpenVPNManagementServerTest;
FRIEND_TEST(OpenVPNManagementServerTest, EscapeToQuote);
FRIEND_TEST(OpenVPNManagementServerTest, Hold);
- FRIEND_TEST(OpenVPNManagementServerTest, OnInput);
FRIEND_TEST(OpenVPNManagementServerTest, OnInputStop);
FRIEND_TEST(OpenVPNManagementServerTest, OnReady);
FRIEND_TEST(OpenVPNManagementServerTest, OnReadyAcceptFail);
@@ -64,12 +63,10 @@
FRIEND_TEST(OpenVPNManagementServerTest, ProcessFailedPasswordMessage);
FRIEND_TEST(OpenVPNManagementServerTest, ProcessHoldMessage);
FRIEND_TEST(OpenVPNManagementServerTest, ProcessInfoMessage);
- FRIEND_TEST(OpenVPNManagementServerTest, ProcessMessage);
FRIEND_TEST(OpenVPNManagementServerTest, ProcessNeedPasswordMessageAuth);
FRIEND_TEST(OpenVPNManagementServerTest, ProcessNeedPasswordMessageAuthSC);
FRIEND_TEST(OpenVPNManagementServerTest, ProcessNeedPasswordMessageTPMToken);
FRIEND_TEST(OpenVPNManagementServerTest, ProcessNeedPasswordMessageUnknown);
- FRIEND_TEST(OpenVPNManagementServerTest, ProcessStateMessage);
FRIEND_TEST(OpenVPNManagementServerTest, Send);
FRIEND_TEST(OpenVPNManagementServerTest, SendHoldRelease);
FRIEND_TEST(OpenVPNManagementServerTest, SendPassword);
diff --git a/openvpn_management_server_unittest.cc b/openvpn_management_server_unittest.cc
index c26ffaa..99295bc 100644
--- a/openvpn_management_server_unittest.cc
+++ b/openvpn_management_server_unittest.cc
@@ -19,6 +19,7 @@
using std::vector;
using testing::_;
using testing::Assign;
+using testing::InSequence;
using testing::Return;
using testing::ReturnNew;
@@ -103,10 +104,24 @@
server_.SendSignal(signal);
}
+ void OnInput(InputData *data) {
+ server_.OnInput(data);
+ }
+
+ void ProcessMessage(const string &message) {
+ server_.ProcessMessage(message);
+ }
+
bool ProcessSuccessMessage(const string &message) {
return server_.ProcessSuccessMessage(message);
}
+ bool ProcessStateMessage(const string &message) {
+ return server_.ProcessStateMessage(message);
+ }
+
+ bool GetHoldWaiting() { return server_.hold_waiting_; }
+
GLib glib_;
MockOpenVPNDriver driver_;
OpenVPNManagementServer server_;
@@ -211,7 +226,7 @@
{
string s;
InputData data = CreateInputDataFromString(s);
- server_.OnInput(&data);
+ OnInput(&data);
}
{
string s = "foo\n"
@@ -226,10 +241,10 @@
ExpectStaticChallengeResponse();
ExpectPINResponse();
EXPECT_CALL(driver_, Cleanup(Service::kStateFailure));
- EXPECT_CALL(driver_, OnReconnecting());
- EXPECT_FALSE(server_.hold_waiting_);
- server_.OnInput(&data);
- EXPECT_TRUE(server_.hold_waiting_);
+ EXPECT_CALL(driver_, OnReconnecting(_));
+ EXPECT_FALSE(GetHoldWaiting());
+ OnInput(&data);
+ EXPECT_TRUE(GetHoldWaiting());
}
}
@@ -243,16 +258,16 @@
EXPECT_CALL(driver_, Cleanup(Service::kStateFailure))
.WillOnce(Assign(&server_.sockets_, reinterpret_cast<Sockets *>(NULL)));
// The second message should not be processed.
- EXPECT_CALL(driver_, OnReconnecting()).Times(0);
- server_.OnInput(&data);
+ EXPECT_CALL(driver_, OnReconnecting(_)).Times(0);
+ OnInput(&data);
}
TEST_F(OpenVPNManagementServerTest, ProcessMessage) {
- server_.ProcessMessage("foo");
- server_.ProcessMessage(">INFO:");
+ ProcessMessage("foo");
+ ProcessMessage(">INFO:");
- EXPECT_CALL(driver_, OnReconnecting());
- server_.ProcessMessage(">STATE:123,RECONNECTING,detail,...,...");
+ EXPECT_CALL(driver_, OnReconnecting(_));
+ ProcessMessage(">STATE:123,RECONNECTING,detail,...,...");
}
TEST_F(OpenVPNManagementServerTest, ProcessSuccessMessage) {
@@ -266,11 +281,17 @@
}
TEST_F(OpenVPNManagementServerTest, ProcessStateMessage) {
- EXPECT_FALSE(server_.ProcessStateMessage("foo"));
- EXPECT_TRUE(server_.ProcessStateMessage(">STATE:123,WAIT,detail,...,..."));
- EXPECT_CALL(driver_, OnReconnecting());
- EXPECT_TRUE(
- server_.ProcessStateMessage(">STATE:123,RECONNECTING,detail,...,..."));
+ EXPECT_FALSE(ProcessStateMessage("foo"));
+ EXPECT_TRUE(ProcessStateMessage(">STATE:123,WAIT,detail,...,..."));
+ {
+ InSequence seq;
+ EXPECT_CALL(driver_,
+ OnReconnecting(OpenVPNDriver::kReconnectReasonUnknown));
+ EXPECT_CALL(driver_,
+ OnReconnecting(OpenVPNDriver::kReconnectReasonTLSError));
+ }
+ EXPECT_TRUE(ProcessStateMessage(">STATE:123,RECONNECTING,detail,...,..."));
+ EXPECT_TRUE(ProcessStateMessage(">STATE:123,RECONNECTING,tls-error,...,..."));
}
TEST_F(OpenVPNManagementServerTest, ProcessNeedPasswordMessageAuthSC) {
diff --git a/vpn_driver.cc b/vpn_driver.cc
index c6fbf72..4705c8a 100644
--- a/vpn_driver.cc
+++ b/vpn_driver.cc
@@ -31,7 +31,7 @@
manager_(manager),
properties_(properties),
property_count_(property_count),
- connect_timeout_seconds_(kDefaultConnectTimeoutSeconds) {}
+ connect_timeout_seconds_(0) {}
VPNDriver::~VPNDriver() {}
@@ -160,20 +160,23 @@
return provider_properties;
}
-void VPNDriver::StartConnectTimeout() {
- SLOG(VPN, 2) << __func__;
+void VPNDriver::StartConnectTimeout(int timeout_seconds) {
if (IsConnectTimeoutStarted()) {
return;
}
+ LOG(INFO) << "Schedule VPN connect timeout: "
+ << timeout_seconds << " seconds.";
+ connect_timeout_seconds_ = timeout_seconds;
connect_timeout_callback_.Reset(
Bind(&VPNDriver::OnConnectTimeout, weak_ptr_factory_.GetWeakPtr()));
dispatcher_->PostDelayedTask(
- connect_timeout_callback_.callback(), connect_timeout_seconds_ * 1000);
+ connect_timeout_callback_.callback(), timeout_seconds * 1000);
}
void VPNDriver::StopConnectTimeout() {
SLOG(VPN, 2) << __func__;
connect_timeout_callback_.Cancel();
+ connect_timeout_seconds_ = 0;
}
bool VPNDriver::IsConnectTimeoutStarted() const {
diff --git a/vpn_driver.h b/vpn_driver.h
index 4200b7a..ea6bb82 100644
--- a/vpn_driver.h
+++ b/vpn_driver.h
@@ -59,6 +59,8 @@
int flags;
};
+ static const int kDefaultConnectTimeoutSeconds;
+
VPNDriver(EventDispatcher *dispatcher,
Manager *manager,
const Property *properties,
@@ -69,9 +71,10 @@
virtual KeyValueStore GetProvider(Error *error);
- // Initializes a callback that will invoke OnConnectTimeout. The timeout will
- // not be restarted if it's already scheduled.
- void StartConnectTimeout();
+ // Initializes a callback that will invoke OnConnectTimeout after
+ // |timeout_seconds|. The timeout will not be restarted if it's already
+ // scheduled.
+ void StartConnectTimeout(int timeout_seconds);
// Cancels the connect timeout callback, if any, previously scheduled through
// StartConnectTimeout.
void StopConnectTimeout();
@@ -82,10 +85,10 @@
// fires. Cancels the timeout callback.
virtual void OnConnectTimeout();
- private:
- FRIEND_TEST(VPNDriverTest, ConnectTimeout);
+ int connect_timeout_seconds() const { return connect_timeout_seconds_; }
- static const int kDefaultConnectTimeoutSeconds;
+ private:
+ friend class VPNDriverTest;
void ClearMappedProperty(const size_t &index, Error *error);
std::string GetMappedProperty(const size_t &index, Error *error);
diff --git a/vpn_driver_unittest.cc b/vpn_driver_unittest.cc
index 951e17b..94d556b 100644
--- a/vpn_driver_unittest.cc
+++ b/vpn_driver_unittest.cc
@@ -94,6 +94,24 @@
virtual ~VPNDriverTest() {}
protected:
+ EventDispatcher *dispatcher() { return driver_.dispatcher_; }
+ void set_dispatcher(EventDispatcher *dispatcher) {
+ driver_.dispatcher_ = dispatcher;
+ }
+
+ const base::CancelableClosure &connect_timeout_callback() {
+ return driver_.connect_timeout_callback_;
+ }
+
+ bool IsConnectTimeoutStarted() { return driver_.IsConnectTimeoutStarted(); }
+ int connect_timeout_seconds() { return driver_.connect_timeout_seconds(); }
+
+ void StartConnectTimeout(int timeout_seconds) {
+ driver_.StartConnectTimeout(timeout_seconds);
+ }
+
+ void StopConnectTimeout() { driver_.StopConnectTimeout(); }
+
void SetArg(const string &arg, const string &value) {
driver_.args()->SetString(arg, value);
}
@@ -281,20 +299,31 @@
}
TEST_F(VPNDriverTest, ConnectTimeout) {
- EXPECT_EQ(&dispatcher_, driver_.dispatcher_);
- EXPECT_TRUE(driver_.connect_timeout_callback_.IsCancelled());
- EXPECT_FALSE(driver_.IsConnectTimeoutStarted());
- EXPECT_EQ(VPNDriver::kDefaultConnectTimeoutSeconds,
- driver_.connect_timeout_seconds_);
- driver_.connect_timeout_seconds_ = 0;
- driver_.StartConnectTimeout();
- EXPECT_FALSE(driver_.connect_timeout_callback_.IsCancelled());
- EXPECT_TRUE(driver_.IsConnectTimeoutStarted());
- driver_.dispatcher_ = NULL;
- driver_.StartConnectTimeout(); // Expect no crash.
+ EXPECT_EQ(&dispatcher_, dispatcher());
+ EXPECT_TRUE(connect_timeout_callback().IsCancelled());
+ EXPECT_FALSE(IsConnectTimeoutStarted());
+ StartConnectTimeout(0);
+ EXPECT_FALSE(connect_timeout_callback().IsCancelled());
+ EXPECT_TRUE(IsConnectTimeoutStarted());
+ set_dispatcher(NULL);
+ StartConnectTimeout(0); // Expect no crash.
dispatcher_.DispatchPendingEvents();
- EXPECT_TRUE(driver_.connect_timeout_callback_.IsCancelled());
- EXPECT_FALSE(driver_.IsConnectTimeoutStarted());
+ EXPECT_TRUE(connect_timeout_callback().IsCancelled());
+ EXPECT_FALSE(IsConnectTimeoutStarted());
+}
+
+TEST_F(VPNDriverTest, StartStopConnectTimeout) {
+ EXPECT_FALSE(IsConnectTimeoutStarted());
+ EXPECT_EQ(0, connect_timeout_seconds());
+ const int kTimeout = 123;
+ StartConnectTimeout(kTimeout);
+ EXPECT_TRUE(IsConnectTimeoutStarted());
+ EXPECT_EQ(kTimeout, connect_timeout_seconds());
+ StartConnectTimeout(kTimeout - 20);
+ EXPECT_EQ(kTimeout, connect_timeout_seconds());
+ StopConnectTimeout();
+ EXPECT_FALSE(IsConnectTimeoutStarted());
+ EXPECT_EQ(0, connect_timeout_seconds());
}
} // namespace shill