shill: Almost complete support for terminating dhcpcd.
BUG=chromium-os:16365,chromium-os:16013
TEST=unit tests
Change-Id: I00a46e8364fc4de3cc48ef72c1b0a9a88e95e6a0
Reviewed-on: http://gerrit.chromium.org/gerrit/2435
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Chris Masone <cmasone@chromium.org>
diff --git a/dhcp_config.cc b/dhcp_config.cc
index 13d9325..49bc8ff 100644
--- a/dhcp_config.cc
+++ b/dhcp_config.cc
@@ -6,7 +6,9 @@
#include <arpa/inet.h>
+#include <base/file_util.h>
#include <base/logging.h>
+#include <base/stringprintf.h>
#include "shill/dhcpcd_proxy.h"
#include "shill/dhcp_provider.h"
@@ -26,7 +28,8 @@
const char DHCPConfig::kConfigurationKeyRouters[] = "Routers";
const char DHCPConfig::kConfigurationKeySubnetCIDR[] = "SubnetCIDR";
const char DHCPConfig::kDHCPCDPath[] = "/sbin/dhcpcd";
-
+const char DHCPConfig::kDHCPCDPathFormatLease[] = "var/run/dhcpcd-%s.lease";
+const char DHCPConfig::kDHCPCDPathFormatPID[] = "var/run/dhcpcd-%s.pid";
DHCPConfig::DHCPConfig(DHCPProvider *provider,
DeviceConstRefPtr device,
@@ -34,15 +37,32 @@
: IPConfig(device),
provider_(provider),
pid_(0),
+ child_watch_tag_(0),
+ root_("/"),
glib_(glib) {
VLOG(2) << __func__ << ": " << GetDeviceName();
}
DHCPConfig::~DHCPConfig() {
VLOG(2) << __func__ << ": " << GetDeviceName();
+
+ // Don't leave behind dhcpcd running.
+ Stop();
+
+ // Somehow we got destroyed before the client died, most likely at exit. Make
+ // sure we don't get any callbacks to the destroyed instance.
+ if (child_watch_tag_) {
+ glib_->SourceRemove(child_watch_tag_);
+ child_watch_tag_ = 0;
+ }
+ if (pid_) {
+ glib_->SpawnClosePID(pid_);
+ pid_ = 0;
+ }
+ CleanupClientState();
}
-bool DHCPConfig::Request() {
+bool DHCPConfig::RequestIP() {
VLOG(2) << __func__ << ": " << GetDeviceName();
if (!pid_) {
return Start();
@@ -52,10 +72,10 @@
<< "Unable to acquire destination address before receiving request.";
return false;
}
- return Renew();
+ return RenewIP();
}
-bool DHCPConfig::Renew() {
+bool DHCPConfig::RenewIP() {
VLOG(2) << __func__ << ": " << GetDeviceName();
if (!pid_ || !proxy_.get()) {
return false;
@@ -64,6 +84,11 @@
return true;
}
+bool DHCPConfig::ReleaseIP() {
+ VLOG(2) << __func__ << ": " << GetDeviceName();
+ // TODO(petkov): Implement D-Bus calls to Release and stop the process.
+}
+
void DHCPConfig::InitProxy(DBus::Connection *connection, const char *service) {
if (!proxy_.get()) {
proxy_.reset(new DHCPCDProxy(connection, service));
@@ -108,10 +133,17 @@
pid_ = pid;
LOG(INFO) << "Spawned " << kDHCPCDPath << " with pid: " << pid_;
provider_->BindPID(pid_, this);
- // TODO(petkov): Add an exit watch to cleanup w/ g_spawn_close_pid.
+ child_watch_tag_ = glib_->ChildWatchAdd(pid, ChildWatchCallback, this);
return true;
}
+void DHCPConfig::Stop() {
+ if (pid_) {
+ VLOG(2) << "Terminating " << pid_;
+ PLOG_IF(ERROR, kill(pid_, SIGTERM) < 0);
+ }
+}
+
string DHCPConfig::GetIPv4AddressString(unsigned int address) {
char str[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &address, str, arraysize(str))) {
@@ -178,4 +210,28 @@
return true;
}
+void DHCPConfig::ChildWatchCallback(GPid pid, gint status, gpointer data) {
+ VLOG(2) << "pid " << pid << " exit status " << status;
+ DHCPConfig *config = reinterpret_cast<DHCPConfig *>(data);
+ config->child_watch_tag_ = 0;
+
+ CHECK_EQ(pid, config->pid_);
+ config->glib_->SpawnClosePID(pid);
+ config->pid_ = 0;
+
+ config->CleanupClientState();
+
+ // |config| instance may be destroyed after this call.
+ config->provider_->UnbindPID(pid);
+}
+
+void DHCPConfig::CleanupClientState() {
+ file_util::Delete(root_.Append(base::StringPrintf(kDHCPCDPathFormatLease,
+ GetDeviceName().c_str())),
+ false);
+ file_util::Delete(root_.Append(base::StringPrintf(kDHCPCDPathFormatPID,
+ GetDeviceName().c_str())),
+ false);
+}
+
} // namespace shill