blob: f00a21e374e969be62a8258c5dad047cbf0b703a [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;
Vitaly Bukaa4630922014-12-11 18:46:46 -080018using org::chromium::apmanager::ManagerAdaptor;
Peter Qiu376e4042014-11-13 09:40:28 -080019using std::string;
20
21namespace apmanager {
22
23// static.
Peter Qiufb39ba42014-11-21 09:09:59 -080024const char Service::kHostapdPath[] = "/usr/sbin/hostapd";
Peter Qiu376e4042014-11-13 09:40:28 -080025const char Service::kHostapdConfigPathFormat[] = "/tmp/hostapd-%d";
26const 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_)),
38 dhcp_server_factory_(DHCPServerFactory::GetInstance()) {
Peter Qiu376e4042014-11-13 09:40:28 -080039 SetConfig(config_->dbus_path());
Peter Qiubf8e36c2014-12-03 22:59:45 -080040 // TODO(zqiu): come up with better server address management. This is good
41 // enough for now.
42 config_->SetServerAddressIndex(service_identifier_ & 0xFF);
Peter Qiu376e4042014-11-13 09:40:28 -080043}
44
45Service::~Service() {
46 // Stop hostapd process if still running.
47 if (IsHostapdRunning()) {
Peter Qiubf8e36c2014-12-03 22:59:45 -080048 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -080049 }
50}
51
52void Service::RegisterAsync(ExportedObjectManager* object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -080053 const scoped_refptr<dbus::Bus>& bus,
Peter Qiu376e4042014-11-13 09:40:28 -080054 AsyncEventSequencer* sequencer) {
55 CHECK(!dbus_object_) << "Already registered";
56 dbus_object_.reset(
57 new chromeos::dbus_utils::DBusObject(
58 object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -080059 bus,
Peter Qiu376e4042014-11-13 09:40:28 -080060 dbus_path_));
61 RegisterWithDBusObject(dbus_object_.get());
62 dbus_object_->RegisterAsync(
63 sequencer->GetHandler("Service.RegisterAsync() failed.", true));
64
65 // Register Config DBus object.
Peter Qiuc9ce1f12014-12-05 11:14:29 -080066 config_->RegisterAsync(object_manager, bus, sequencer);
Peter Qiu376e4042014-11-13 09:40:28 -080067}
68
69bool Service::Start(chromeos::ErrorPtr* error) {
70 if (IsHostapdRunning()) {
71 chromeos::Error::AddTo(
72 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
73 "Service already running");
74 return false;
75 }
76
77 // Generate hostapd configuration content.
78 string config_str;
79 if (!config_->GenerateConfigFile(error, &config_str)) {
80 chromeos::Error::AddTo(
81 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
82 "Failed to generate config file");
83 return false;
84 }
85
86 // Write configuration to a file.
87 base::FilePath file_path(base::StringPrintf(kHostapdConfigPathFormat,
88 service_identifier_));
89 if (base::WriteFile(file_path, config_str.c_str(), config_str.size()) == -1) {
90 chromeos::Error::AddTo(
91 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
92 "Failed to write configuration to a file");
93 return false;
94 }
95
Peter Qiufb39ba42014-11-21 09:09:59 -080096 // Claim the device needed for this ap service.
97 if (!config_->ClaimDevice()) {
98 chromeos::Error::AddTo(
99 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
100 "Failed to claim the device for this service");
101 return false;
102 }
103
Peter Qiu376e4042014-11-13 09:40:28 -0800104 // Start hostapd process.
105 if (!StartHostapdProcess(file_path.value())) {
106 chromeos::Error::AddTo(
107 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
108 "Failed to start hostapd");
Peter Qiufb39ba42014-11-21 09:09:59 -0800109 // Release the device claimed for this service.
110 config_->ReleaseDevice();
Peter Qiu376e4042014-11-13 09:40:28 -0800111 return false;
112 }
113
Peter Qiubf8e36c2014-12-03 22:59:45 -0800114 // Start DHCP server if in server mode.
115 if (config_->GetOperationMode() == kOperationModeServer) {
116 dhcp_server_.reset(
117 dhcp_server_factory_->CreateDHCPServer(config_->GetServerAddressIndex(),
118 config_->selected_interface()));
119 if (!dhcp_server_->Start()) {
120 chromeos::Error::AddTo(
121 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
122 "Failed to start DHCP server");
123 ReleaseResources();
124 return false;
125 }
126 }
127
Peter Qiu376e4042014-11-13 09:40:28 -0800128 return true;
129}
130
131bool Service::Stop(chromeos::ErrorPtr* error) {
132 if (!IsHostapdRunning()) {
133 chromeos::Error::AddTo(
134 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
135 "Service is not currently running");
136 return false;
137 }
138
Peter Qiubf8e36c2014-12-03 22:59:45 -0800139 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -0800140 return true;
141}
142
143bool Service::IsHostapdRunning() {
144 return hostapd_process_ && hostapd_process_->pid() != 0 &&
145 chromeos::Process::ProcessExists(hostapd_process_->pid());
146}
147
148bool Service::StartHostapdProcess(const string& config_file_path) {
149 hostapd_process_.reset(new chromeos::ProcessImpl());
Peter Qiufb39ba42014-11-21 09:09:59 -0800150 hostapd_process_->AddArg(kHostapdPath);
Peter Qiu376e4042014-11-13 09:40:28 -0800151 hostapd_process_->AddArg(config_file_path);
152 if (!hostapd_process_->Start()) {
153 hostapd_process_.reset();
154 return false;
155 }
156 return true;
157}
158
159void Service::StopHostapdProcess() {
160 if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) {
161 hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds);
162 }
163 hostapd_process_.reset();
164}
165
Peter Qiubf8e36c2014-12-03 22:59:45 -0800166void Service::ReleaseResources() {
167 StopHostapdProcess();
168 dhcp_server_.reset();
169 config_->ReleaseDevice();
170}
171
Peter Qiu376e4042014-11-13 09:40:28 -0800172} // namespace apmanager