shill: openvpn: Hold connect/reconnect until a new service is online.

Use OpenVPN's management hold API to prevent the client from
connecting/reconnecting until an underlying connection becomes
available. The hold is released only when a new default service is
connected. This ensures, for example, that the openvpn client will not
use stale network configuration on reconnect. Also, add API to Manager
to register and deregister callbacks to monitor for default service
changes.

BUG=chromium-os:31572
TEST=unit tests, tested on device with inactivity restart/reconnect

Change-Id: I6d6d63a03ee92aaa18b7a2cca9462a8ea1e5a931
Reviewed-on: https://gerrit.chromium.org/gerrit/26920
Commit-Ready: Darin Petkov <petkov@chromium.org>
Reviewed-by: Darin Petkov <petkov@chromium.org>
Tested-by: Darin Petkov <petkov@chromium.org>
diff --git a/openvpn_management_server.h b/openvpn_management_server.h
index 14e4376..025560c 100644
--- a/openvpn_management_server.h
+++ b/openvpn_management_server.h
@@ -35,8 +35,19 @@
 
   virtual void Stop();
 
+  // Releases openvpn's hold if it's waiting for a hold release (i.e., if
+  // |hold_waiting_| is true). Otherwise, sets |hold_release_| to true
+  // indicating that the hold can be released as soon as openvpn requests.
+  virtual void ReleaseHold();
+
+  // Holds openvpn so that it doesn't connect or reconnect automatically (i.e.,
+  // sets |hold_release_| to false). Note that this method neither drops an
+  // existing connection, nor sends any commands to the openvpn client.
+  virtual void Hold();
+
  private:
   friend class OpenVPNManagementServerTest;
+  FRIEND_TEST(OpenVPNManagementServerTest, Hold);
   FRIEND_TEST(OpenVPNManagementServerTest, OnInput);
   FRIEND_TEST(OpenVPNManagementServerTest, OnInputStop);
   FRIEND_TEST(OpenVPNManagementServerTest, OnReady);
@@ -45,6 +56,7 @@
   FRIEND_TEST(OpenVPNManagementServerTest, PerformStaticChallenge);
   FRIEND_TEST(OpenVPNManagementServerTest, PerformStaticChallengeNoCreds);
   FRIEND_TEST(OpenVPNManagementServerTest, ProcessFailedPasswordMessage);
+  FRIEND_TEST(OpenVPNManagementServerTest, ProcessHoldMessage);
   FRIEND_TEST(OpenVPNManagementServerTest, ProcessInfoMessage);
   FRIEND_TEST(OpenVPNManagementServerTest, ProcessMessage);
   FRIEND_TEST(OpenVPNManagementServerTest, ProcessNeedPasswordMessageAuthSC);
@@ -52,6 +64,7 @@
   FRIEND_TEST(OpenVPNManagementServerTest, ProcessNeedPasswordMessageUnknown);
   FRIEND_TEST(OpenVPNManagementServerTest, ProcessStateMessage);
   FRIEND_TEST(OpenVPNManagementServerTest, Send);
+  FRIEND_TEST(OpenVPNManagementServerTest, SendHoldRelease);
   FRIEND_TEST(OpenVPNManagementServerTest, SendPassword);
   FRIEND_TEST(OpenVPNManagementServerTest, SendState);
   FRIEND_TEST(OpenVPNManagementServerTest, SendUsername);
@@ -68,12 +81,14 @@
   void SendState(const std::string &state);
   void SendUsername(const std::string &tag, const std::string &username);
   void SendPassword(const std::string &tag, const std::string &password);
+  void SendHoldRelease();
 
   void ProcessMessage(const std::string &message);
   bool ProcessInfoMessage(const std::string &message);
   bool ProcessNeedPasswordMessage(const std::string &message);
   bool ProcessFailedPasswordMessage(const std::string &message);
   bool ProcessStateMessage(const std::string &message);
+  bool ProcessHoldMessage(const std::string &message);
 
   void PerformStaticChallenge(const std::string &tag);
   void SupplyTPMToken(const std::string &tag);
@@ -95,6 +110,9 @@
   int connected_socket_;
   scoped_ptr<IOHandler> input_handler_;
 
+  bool hold_waiting_;
+  bool hold_release_;
+
   DISALLOW_COPY_AND_ASSIGN(OpenVPNManagementServer);
 };