shill: implement timeout for DHCP requests

BUG=chromium-os:30689
TEST=new unit tests, manual (see below)

Manual testing:
- Start shill.
- ff_debug +dhcp
- Plug USB-Ethernet into a switch (to get carrier), but without
  an upstream connection for the switch. Plug dongle into USB
  port.
- Wait 30 seconds.
- Check log file, find "Timed out waiting for DHCP lease on eth0",
  and "Service Ethernet state Configuring -> Disconnected".

Change-Id: Ifc27539ec7191b060f615eb9dec61c9fdab07267
Reviewed-on: https://gerrit.chromium.org/gerrit/22302
Commit-Ready: mukesh agrawal <quiche@chromium.org>
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Tested-by: mukesh agrawal <quiche@chromium.org>
diff --git a/dhcp_config.h b/dhcp_config.h
index 429e15e..e66ee98 100644
--- a/dhcp_config.h
+++ b/dhcp_config.h
@@ -5,8 +5,10 @@
 #ifndef SHILL_DHCP_CONFIG_
 #define SHILL_DHCP_CONFIG_
 
+#include <base/cancelable_callback.h>
 #include <base/file_path.h>
 #include <base/memory/scoped_ptr.h>
+#include <base/memory/weak_ptr.h>
 #include <dbus-c++/types.h>
 #include <glib.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
@@ -61,6 +63,10 @@
   void ProcessEventSignal(const std::string &reason,
                           const Configuration &configuration);
 
+ protected:
+  // Overrides base clase implementation.
+  virtual void UpdateProperties(const Properties &properties, bool success);
+
  private:
   friend class DHCPConfigTest;
   FRIEND_TEST(DHCPConfigTest, GetIPv4AddressString);
@@ -72,14 +78,17 @@
   FRIEND_TEST(DHCPConfigTest, ReleaseIP);
   FRIEND_TEST(DHCPConfigTest, RenewIP);
   FRIEND_TEST(DHCPConfigTest, RequestIP);
+  FRIEND_TEST(DHCPConfigTest, RequestIPTimeout);
   FRIEND_TEST(DHCPConfigTest, Restart);
   FRIEND_TEST(DHCPConfigTest, RestartNoClient);
   FRIEND_TEST(DHCPConfigTest, StartFail);
+  FRIEND_TEST(DHCPConfigTest, StartTimeout);
   FRIEND_TEST(DHCPConfigTest, StartWithHostname);
   FRIEND_TEST(DHCPConfigTest, StartWithoutArpGateway);
   FRIEND_TEST(DHCPConfigTest, StartWithoutHostname);
   FRIEND_TEST(DHCPConfigTest, StartWithoutLeaseSuffix);
   FRIEND_TEST(DHCPConfigTest, Stop);
+  FRIEND_TEST(DHCPConfigTest, StopDuringRequestIP);
   FRIEND_TEST(DHCPProviderTest, CreateConfig);
 
   static const char kConfigurationKeyBroadcastAddress[];
@@ -96,6 +105,7 @@
   static const char kDHCPCDPath[];
   static const char kDHCPCDPathFormatLease[];
   static const char kDHCPCDPathFormatPID[];
+  static const int kDHCPTimeoutSeconds;
 
   static const char kReasonBound[];
   static const char kReasonFail[];
@@ -131,6 +141,16 @@
   // its GPid, exit watch callback, and state files.
   void CleanupClientState();
 
+  // Initialize a callback that will invoke ProcessDHCPTimeout if we
+  // do not get a lease in a reasonable amount of time.
+  void StartDHCPTimeout();
+  // Cancel callback created by StartDHCPTimeout. One-liner included
+  // for symmetry.
+  void StopDHCPTimeout();
+  // Called if we do not get a DHCP lease in a reasonable amount of time.
+  // Informs upper layers of the failure.
+  void ProcessDHCPTimeout();
+
   // Store cached copies of singletons for speed/ease of testing.
   ProxyFactory *proxy_factory_;
 
@@ -158,9 +178,17 @@
   // The proxy for communicating with the DHCP client.
   scoped_ptr<DHCPProxyInterface> proxy_;
 
+  // Called if we fail to get a DHCP lease in a timely manner.
+  base::CancelableClosure lease_acquisition_timeout_callback_;
+
+  // Time to wait for a DHCP lease. Represented as field so that it
+  // can be overriden in tests.
+  unsigned int lease_acquisition_timeout_seconds_;
+
   // Root file path, used for testing.
   FilePath root_;
 
+  base::WeakPtrFactory<DHCPConfig> weak_ptr_factory_;
   EventDispatcher *dispatcher_;
   GLib *glib_;