blob: ced17dc1dc2a105d773d18ac46d1db2440a12cd9 [file] [log] [blame]
Peter Qiu376e4042014-11-13 09:40:28 -08001// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "apmanager/service.h"
6
7#include <signal.h>
8
9#include <base/files/file_util.h>
10#include <base/strings/stringprintf.h>
11#include <chromeos/dbus/service_constants.h>
12#include <chromeos/errors/error.h>
13
Peter Qiufb39ba42014-11-21 09:09:59 -080014#include "apmanager/manager.h"
Peter Qiu376e4042014-11-13 09:40:28 -080015
16using chromeos::dbus_utils::AsyncEventSequencer;
17using chromeos::dbus_utils::ExportedObjectManager;
18using std::string;
19
20namespace apmanager {
21
22// static.
Peter Qiufb39ba42014-11-21 09:09:59 -080023const char Service::kHostapdPath[] = "/usr/sbin/hostapd";
Peter Qiu376e4042014-11-13 09:40:28 -080024const char Service::kHostapdConfigPathFormat[] = "/tmp/hostapd-%d";
25const int Service::kTerminationTimeoutSeconds = 2;
26
Peter Qiufb39ba42014-11-21 09:09:59 -080027Service::Service(Manager* manager, int service_identifier)
Peter Qiu376e4042014-11-13 09:40:28 -080028 : org::chromium::apmanager::ServiceAdaptor(this),
Peter Qiufb39ba42014-11-21 09:09:59 -080029 manager_(manager),
Peter Qiu376e4042014-11-13 09:40:28 -080030 service_identifier_(service_identifier),
31 service_path_(base::StringPrintf("%s/services/%d",
32 kManagerPath,
33 service_identifier)),
34 dbus_path_(dbus::ObjectPath(service_path_)),
Peter Qiubf8e36c2014-12-03 22:59:45 -080035 config_(new Config(manager, service_path_)),
36 dhcp_server_factory_(DHCPServerFactory::GetInstance()) {
Peter Qiu376e4042014-11-13 09:40:28 -080037 SetConfig(config_->dbus_path());
Peter Qiubf8e36c2014-12-03 22:59:45 -080038 // TODO(zqiu): come up with better server address management. This is good
39 // enough for now.
40 config_->SetServerAddressIndex(service_identifier_ & 0xFF);
Peter Qiu376e4042014-11-13 09:40:28 -080041}
42
43Service::~Service() {
44 // Stop hostapd process if still running.
45 if (IsHostapdRunning()) {
Peter Qiubf8e36c2014-12-03 22:59:45 -080046 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -080047 }
48}
49
50void Service::RegisterAsync(ExportedObjectManager* object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -080051 const scoped_refptr<dbus::Bus>& bus,
Peter Qiu376e4042014-11-13 09:40:28 -080052 AsyncEventSequencer* sequencer) {
53 CHECK(!dbus_object_) << "Already registered";
54 dbus_object_.reset(
55 new chromeos::dbus_utils::DBusObject(
56 object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -080057 bus,
Peter Qiu376e4042014-11-13 09:40:28 -080058 dbus_path_));
59 RegisterWithDBusObject(dbus_object_.get());
60 dbus_object_->RegisterAsync(
61 sequencer->GetHandler("Service.RegisterAsync() failed.", true));
62
63 // Register Config DBus object.
Peter Qiuc9ce1f12014-12-05 11:14:29 -080064 config_->RegisterAsync(object_manager, bus, sequencer);
Peter Qiu376e4042014-11-13 09:40:28 -080065}
66
67bool Service::Start(chromeos::ErrorPtr* error) {
68 if (IsHostapdRunning()) {
69 chromeos::Error::AddTo(
70 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
71 "Service already running");
72 return false;
73 }
74
75 // Generate hostapd configuration content.
76 string config_str;
77 if (!config_->GenerateConfigFile(error, &config_str)) {
78 chromeos::Error::AddTo(
79 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
80 "Failed to generate config file");
81 return false;
82 }
83
84 // Write configuration to a file.
85 base::FilePath file_path(base::StringPrintf(kHostapdConfigPathFormat,
86 service_identifier_));
87 if (base::WriteFile(file_path, config_str.c_str(), config_str.size()) == -1) {
88 chromeos::Error::AddTo(
89 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
90 "Failed to write configuration to a file");
91 return false;
92 }
93
Peter Qiufb39ba42014-11-21 09:09:59 -080094 // Claim the device needed for this ap service.
95 if (!config_->ClaimDevice()) {
96 chromeos::Error::AddTo(
97 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
98 "Failed to claim the device for this service");
99 return false;
100 }
101
Peter Qiu376e4042014-11-13 09:40:28 -0800102 // Start hostapd process.
103 if (!StartHostapdProcess(file_path.value())) {
104 chromeos::Error::AddTo(
105 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
106 "Failed to start hostapd");
Peter Qiufb39ba42014-11-21 09:09:59 -0800107 // Release the device claimed for this service.
108 config_->ReleaseDevice();
Peter Qiu376e4042014-11-13 09:40:28 -0800109 return false;
110 }
111
Peter Qiubf8e36c2014-12-03 22:59:45 -0800112 // Start DHCP server if in server mode.
113 if (config_->GetOperationMode() == kOperationModeServer) {
114 dhcp_server_.reset(
115 dhcp_server_factory_->CreateDHCPServer(config_->GetServerAddressIndex(),
116 config_->selected_interface()));
117 if (!dhcp_server_->Start()) {
118 chromeos::Error::AddTo(
119 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
120 "Failed to start DHCP server");
121 ReleaseResources();
122 return false;
123 }
124 }
125
Peter Qiu376e4042014-11-13 09:40:28 -0800126 return true;
127}
128
129bool Service::Stop(chromeos::ErrorPtr* error) {
130 if (!IsHostapdRunning()) {
131 chromeos::Error::AddTo(
132 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
133 "Service is not currently running");
134 return false;
135 }
136
Peter Qiubf8e36c2014-12-03 22:59:45 -0800137 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -0800138 return true;
139}
140
141bool Service::IsHostapdRunning() {
142 return hostapd_process_ && hostapd_process_->pid() != 0 &&
143 chromeos::Process::ProcessExists(hostapd_process_->pid());
144}
145
146bool Service::StartHostapdProcess(const string& config_file_path) {
147 hostapd_process_.reset(new chromeos::ProcessImpl());
Peter Qiufb39ba42014-11-21 09:09:59 -0800148 hostapd_process_->AddArg(kHostapdPath);
Peter Qiu376e4042014-11-13 09:40:28 -0800149 hostapd_process_->AddArg(config_file_path);
150 if (!hostapd_process_->Start()) {
151 hostapd_process_.reset();
152 return false;
153 }
154 return true;
155}
156
157void Service::StopHostapdProcess() {
158 if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) {
159 hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds);
160 }
161 hostapd_process_.reset();
162}
163
Peter Qiubf8e36c2014-12-03 22:59:45 -0800164void Service::ReleaseResources() {
165 StopHostapdProcess();
166 dhcp_server_.reset();
167 config_->ReleaseDevice();
168}
169
Peter Qiu376e4042014-11-13 09:40:28 -0800170} // namespace apmanager