blob: 5caa4490f3da504d369c0279b77fe253affb3eae [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
Peter Qiu376e4042014-11-13 09:40:28 -08009#include <base/strings/stringprintf.h>
10#include <chromeos/dbus/service_constants.h>
11#include <chromeos/errors/error.h>
12
Peter Qiufb39ba42014-11-21 09:09:59 -080013#include "apmanager/manager.h"
Peter Qiu376e4042014-11-13 09:40:28 -080014
15using chromeos::dbus_utils::AsyncEventSequencer;
16using chromeos::dbus_utils::ExportedObjectManager;
Vitaly Bukaa4630922014-12-11 18:46:46 -080017using org::chromium::apmanager::ManagerAdaptor;
Peter Qiu376e4042014-11-13 09:40:28 -080018using std::string;
19
20namespace apmanager {
21
22// static.
Peter Qiufb39ba42014-11-21 09:09:59 -080023const char Service::kHostapdPath[] = "/usr/sbin/hostapd";
Peter Qiu77517302015-01-08 16:22:16 -080024const char Service::kHostapdConfigPathFormat[] =
25 "/var/run/apmanager/hostapd/hostapd-%d.conf";
Peter Qiu376e4042014-11-13 09:40:28 -080026const int Service::kTerminationTimeoutSeconds = 2;
27
Peter Qiufb39ba42014-11-21 09:09:59 -080028Service::Service(Manager* manager, int service_identifier)
Peter Qiu376e4042014-11-13 09:40:28 -080029 : org::chromium::apmanager::ServiceAdaptor(this),
Peter Qiufb39ba42014-11-21 09:09:59 -080030 manager_(manager),
Peter Qiu376e4042014-11-13 09:40:28 -080031 service_identifier_(service_identifier),
Vitaly Bukaa4630922014-12-11 18:46:46 -080032 service_path_(
33 base::StringPrintf("%s/services/%d",
34 ManagerAdaptor::GetObjectPath().value().c_str(),
35 service_identifier)),
Peter Qiu376e4042014-11-13 09:40:28 -080036 dbus_path_(dbus::ObjectPath(service_path_)),
Peter Qiubf8e36c2014-12-03 22:59:45 -080037 config_(new Config(manager, service_path_)),
Peter Qiu77517302015-01-08 16:22:16 -080038 dhcp_server_factory_(DHCPServerFactory::GetInstance()),
39 file_writer_(FileWriter::GetInstance()) {
Peter Qiu376e4042014-11-13 09:40:28 -080040 SetConfig(config_->dbus_path());
Peter Qiubf8e36c2014-12-03 22:59:45 -080041 // TODO(zqiu): come up with better server address management. This is good
42 // enough for now.
43 config_->SetServerAddressIndex(service_identifier_ & 0xFF);
Peter Qiu376e4042014-11-13 09:40:28 -080044}
45
46Service::~Service() {
47 // Stop hostapd process if still running.
48 if (IsHostapdRunning()) {
Peter Qiubf8e36c2014-12-03 22:59:45 -080049 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -080050 }
51}
52
53void Service::RegisterAsync(ExportedObjectManager* object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -080054 const scoped_refptr<dbus::Bus>& bus,
Peter Qiu376e4042014-11-13 09:40:28 -080055 AsyncEventSequencer* sequencer) {
56 CHECK(!dbus_object_) << "Already registered";
57 dbus_object_.reset(
58 new chromeos::dbus_utils::DBusObject(
59 object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -080060 bus,
Peter Qiu376e4042014-11-13 09:40:28 -080061 dbus_path_));
62 RegisterWithDBusObject(dbus_object_.get());
63 dbus_object_->RegisterAsync(
64 sequencer->GetHandler("Service.RegisterAsync() failed.", true));
65
66 // Register Config DBus object.
Peter Qiuc9ce1f12014-12-05 11:14:29 -080067 config_->RegisterAsync(object_manager, bus, sequencer);
Peter Qiu376e4042014-11-13 09:40:28 -080068}
69
70bool Service::Start(chromeos::ErrorPtr* error) {
71 if (IsHostapdRunning()) {
72 chromeos::Error::AddTo(
73 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
74 "Service already running");
75 return false;
76 }
77
78 // Generate hostapd configuration content.
79 string config_str;
80 if (!config_->GenerateConfigFile(error, &config_str)) {
81 chromeos::Error::AddTo(
82 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
83 "Failed to generate config file");
84 return false;
85 }
86
87 // Write configuration to a file.
Peter Qiu77517302015-01-08 16:22:16 -080088 string config_file_name = base::StringPrintf(kHostapdConfigPathFormat,
89 service_identifier_);
90 if (!file_writer_->Write(config_file_name, config_str)) {
Peter Qiu376e4042014-11-13 09:40:28 -080091 chromeos::Error::AddTo(
92 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
93 "Failed to write configuration to a file");
94 return false;
95 }
96
Peter Qiufb39ba42014-11-21 09:09:59 -080097 // Claim the device needed for this ap service.
98 if (!config_->ClaimDevice()) {
99 chromeos::Error::AddTo(
100 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
101 "Failed to claim the device for this service");
102 return false;
103 }
104
Peter Qiu376e4042014-11-13 09:40:28 -0800105 // Start hostapd process.
Peter Qiu77517302015-01-08 16:22:16 -0800106 if (!StartHostapdProcess(config_file_name)) {
Peter Qiu376e4042014-11-13 09:40:28 -0800107 chromeos::Error::AddTo(
108 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
109 "Failed to start hostapd");
Peter Qiufb39ba42014-11-21 09:09:59 -0800110 // Release the device claimed for this service.
111 config_->ReleaseDevice();
Peter Qiu376e4042014-11-13 09:40:28 -0800112 return false;
113 }
114
Peter Qiubf8e36c2014-12-03 22:59:45 -0800115 // Start DHCP server if in server mode.
116 if (config_->GetOperationMode() == kOperationModeServer) {
117 dhcp_server_.reset(
118 dhcp_server_factory_->CreateDHCPServer(config_->GetServerAddressIndex(),
119 config_->selected_interface()));
120 if (!dhcp_server_->Start()) {
121 chromeos::Error::AddTo(
122 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
123 "Failed to start DHCP server");
124 ReleaseResources();
125 return false;
126 }
127 }
128
Peter Qiu376e4042014-11-13 09:40:28 -0800129 return true;
130}
131
132bool Service::Stop(chromeos::ErrorPtr* error) {
133 if (!IsHostapdRunning()) {
134 chromeos::Error::AddTo(
135 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
136 "Service is not currently running");
137 return false;
138 }
139
Peter Qiubf8e36c2014-12-03 22:59:45 -0800140 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -0800141 return true;
142}
143
144bool Service::IsHostapdRunning() {
145 return hostapd_process_ && hostapd_process_->pid() != 0 &&
146 chromeos::Process::ProcessExists(hostapd_process_->pid());
147}
148
149bool Service::StartHostapdProcess(const string& config_file_path) {
150 hostapd_process_.reset(new chromeos::ProcessImpl());
Peter Qiufb39ba42014-11-21 09:09:59 -0800151 hostapd_process_->AddArg(kHostapdPath);
Peter Qiu376e4042014-11-13 09:40:28 -0800152 hostapd_process_->AddArg(config_file_path);
153 if (!hostapd_process_->Start()) {
154 hostapd_process_.reset();
155 return false;
156 }
157 return true;
158}
159
160void Service::StopHostapdProcess() {
161 if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) {
162 hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds);
163 }
164 hostapd_process_.reset();
165}
166
Peter Qiubf8e36c2014-12-03 22:59:45 -0800167void Service::ReleaseResources() {
168 StopHostapdProcess();
169 dhcp_server_.reset();
170 config_->ReleaseDevice();
171}
172
Peter Qiu376e4042014-11-13 09:40:28 -0800173} // namespace apmanager