blob: b3a6cd9c7e69567c72112b031c76071f07264df6 [file] [log] [blame]
Peter Qiu326b6cf2015-09-02 11:11:42 -07001//
2// Copyright (C) 2014 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
Peter Qiu376e4042014-11-13 09:40:28 -080016
17#include "apmanager/service.h"
18
19#include <signal.h>
20
Peter Qiu376e4042014-11-13 09:40:28 -080021#include <base/strings/stringprintf.h>
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -070022#include <brillo/errors/error.h>
Peter Qiu376e4042014-11-13 09:40:28 -080023
Peter Qiu7a420d32015-09-22 11:25:15 -070024#if !defined(__ANDROID__)
25#include <chromeos/dbus/service_constants.h>
26#else
27#include "dbus/apmanager/dbus-constants.h"
28#endif // __ANDROID__
29
Peter Qiufb39ba42014-11-21 09:09:59 -080030#include "apmanager/manager.h"
Peter Qiu376e4042014-11-13 09:40:28 -080031
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -070032using brillo::dbus_utils::AsyncEventSequencer;
33using brillo::dbus_utils::ExportedObjectManager;
Vitaly Bukaa4630922014-12-11 18:46:46 -080034using org::chromium::apmanager::ManagerAdaptor;
Peter Qiu376e4042014-11-13 09:40:28 -080035using std::string;
36
37namespace apmanager {
38
39// static.
Peter Qiufc980572015-09-24 10:11:26 -070040#if !defined(__ANDROID__)
Peter Qiufb39ba42014-11-21 09:09:59 -080041const char Service::kHostapdPath[] = "/usr/sbin/hostapd";
Peter Qiu77517302015-01-08 16:22:16 -080042const char Service::kHostapdConfigPathFormat[] =
43 "/var/run/apmanager/hostapd/hostapd-%d.conf";
Peter Qiu1dbf9fd2015-01-09 13:36:55 -080044const char Service::kHostapdControlInterfacePath[] =
45 "/var/run/apmanager/hostapd/ctrl_iface";
Peter Qiufc980572015-09-24 10:11:26 -070046#else
47const char Service::kHostapdPath[] = "/system/bin/hostapd";
48const char Service::kHostapdConfigPathFormat[] =
49 "/data/misc/apmanager/hostapd/hostapd-%d.conf";
50const char Service::kHostapdControlInterfacePath[] =
51 "/data/misc/apmanager/hostapd/ctrl_iface";
52#endif // __ANDROID__
53
Peter Qiu376e4042014-11-13 09:40:28 -080054const int Service::kTerminationTimeoutSeconds = 2;
55
Peter Qiue2657852015-02-03 11:33:11 -080056// static. Service state definitions.
57const char Service::kStateIdle[] = "Idle";
58const char Service::kStateStarting[] = "Starting";
59const char Service::kStateStarted[] = "Started";
60const char Service::kStateFailed[] = "Failed";
61
Peter Qiufb39ba42014-11-21 09:09:59 -080062Service::Service(Manager* manager, int service_identifier)
Peter Qiu376e4042014-11-13 09:40:28 -080063 : org::chromium::apmanager::ServiceAdaptor(this),
Peter Qiufb39ba42014-11-21 09:09:59 -080064 manager_(manager),
Peter Qiufd02b6f2015-02-27 09:55:11 -080065 identifier_(service_identifier),
Vitaly Bukaa4630922014-12-11 18:46:46 -080066 service_path_(
67 base::StringPrintf("%s/services/%d",
68 ManagerAdaptor::GetObjectPath().value().c_str(),
69 service_identifier)),
Peter Qiu376e4042014-11-13 09:40:28 -080070 dbus_path_(dbus::ObjectPath(service_path_)),
Peter Qiubf8e36c2014-12-03 22:59:45 -080071 config_(new Config(manager, service_path_)),
Peter Qiu77517302015-01-08 16:22:16 -080072 dhcp_server_factory_(DHCPServerFactory::GetInstance()),
Peter Qiu1dbf9fd2015-01-09 13:36:55 -080073 file_writer_(FileWriter::GetInstance()),
74 process_factory_(ProcessFactory::GetInstance()) {
Peter Qiu376e4042014-11-13 09:40:28 -080075 SetConfig(config_->dbus_path());
Peter Qiue2657852015-02-03 11:33:11 -080076 SetState(kStateIdle);
Peter Qiubf8e36c2014-12-03 22:59:45 -080077 // TODO(zqiu): come up with better server address management. This is good
78 // enough for now.
Peter Qiufd02b6f2015-02-27 09:55:11 -080079 config_->SetServerAddressIndex(identifier_ & 0xFF);
Peter Qiu376e4042014-11-13 09:40:28 -080080}
81
82Service::~Service() {
83 // Stop hostapd process if still running.
84 if (IsHostapdRunning()) {
Peter Qiubf8e36c2014-12-03 22:59:45 -080085 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -080086 }
87}
88
89void Service::RegisterAsync(ExportedObjectManager* object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -080090 const scoped_refptr<dbus::Bus>& bus,
Peter Qiu376e4042014-11-13 09:40:28 -080091 AsyncEventSequencer* sequencer) {
92 CHECK(!dbus_object_) << "Already registered";
93 dbus_object_.reset(
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -070094 new brillo::dbus_utils::DBusObject(
Peter Qiu376e4042014-11-13 09:40:28 -080095 object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -080096 bus,
Peter Qiu376e4042014-11-13 09:40:28 -080097 dbus_path_));
98 RegisterWithDBusObject(dbus_object_.get());
99 dbus_object_->RegisterAsync(
100 sequencer->GetHandler("Service.RegisterAsync() failed.", true));
101
102 // Register Config DBus object.
Peter Qiuc9ce1f12014-12-05 11:14:29 -0800103 config_->RegisterAsync(object_manager, bus, sequencer);
Peter Qiu376e4042014-11-13 09:40:28 -0800104}
105
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700106bool Service::Start(brillo::ErrorPtr* error) {
Peter Qiu376e4042014-11-13 09:40:28 -0800107 if (IsHostapdRunning()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700108 brillo::Error::AddTo(
109 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800110 "Service already running");
111 return false;
112 }
113
Peter Qiubfd410e2015-01-09 15:14:20 -0800114 // Setup hostapd control interface path.
115 config_->set_control_interface(kHostapdControlInterfacePath);
116
Peter Qiu376e4042014-11-13 09:40:28 -0800117 // Generate hostapd configuration content.
118 string config_str;
119 if (!config_->GenerateConfigFile(error, &config_str)) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700120 brillo::Error::AddTo(
121 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800122 "Failed to generate config file");
123 return false;
124 }
125
126 // Write configuration to a file.
Peter Qiu77517302015-01-08 16:22:16 -0800127 string config_file_name = base::StringPrintf(kHostapdConfigPathFormat,
Peter Qiufd02b6f2015-02-27 09:55:11 -0800128 identifier_);
Peter Qiu77517302015-01-08 16:22:16 -0800129 if (!file_writer_->Write(config_file_name, config_str)) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700130 brillo::Error::AddTo(
131 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800132 "Failed to write configuration to a file");
133 return false;
134 }
135
Peter Qiufb39ba42014-11-21 09:09:59 -0800136 // Claim the device needed for this ap service.
137 if (!config_->ClaimDevice()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700138 brillo::Error::AddTo(
139 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiufb39ba42014-11-21 09:09:59 -0800140 "Failed to claim the device for this service");
141 return false;
142 }
143
Peter Qiu376e4042014-11-13 09:40:28 -0800144 // Start hostapd process.
Peter Qiu77517302015-01-08 16:22:16 -0800145 if (!StartHostapdProcess(config_file_name)) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700146 brillo::Error::AddTo(
147 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800148 "Failed to start hostapd");
Peter Qiufb39ba42014-11-21 09:09:59 -0800149 // Release the device claimed for this service.
150 config_->ReleaseDevice();
Peter Qiu376e4042014-11-13 09:40:28 -0800151 return false;
152 }
153
Peter Qiubf8e36c2014-12-03 22:59:45 -0800154 // Start DHCP server if in server mode.
155 if (config_->GetOperationMode() == kOperationModeServer) {
156 dhcp_server_.reset(
157 dhcp_server_factory_->CreateDHCPServer(config_->GetServerAddressIndex(),
158 config_->selected_interface()));
159 if (!dhcp_server_->Start()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700160 brillo::Error::AddTo(
161 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiubf8e36c2014-12-03 22:59:45 -0800162 "Failed to start DHCP server");
163 ReleaseResources();
164 return false;
165 }
Peter Qiu943cf3a2015-02-24 10:59:17 -0800166 manager_->RequestDHCPPortAccess(config_->selected_interface());
Peter Qiubf8e36c2014-12-03 22:59:45 -0800167 }
168
Peter Qiufda548c2015-01-13 14:39:19 -0800169 // Start monitoring hostapd.
170 if (!hostapd_monitor_) {
171 hostapd_monitor_.reset(
172 new HostapdMonitor(base::Bind(&Service::HostapdEventCallback,
173 base::Unretained(this)),
174 config_->control_interface(),
175 config_->selected_interface()));
176 }
177 hostapd_monitor_->Start();
178
Peter Qiue2657852015-02-03 11:33:11 -0800179 // Update service state.
180 SetState(kStateStarting);
181
Peter Qiu376e4042014-11-13 09:40:28 -0800182 return true;
183}
184
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700185bool Service::Stop(brillo::ErrorPtr* error) {
Peter Qiu376e4042014-11-13 09:40:28 -0800186 if (!IsHostapdRunning()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700187 brillo::Error::AddTo(
188 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800189 "Service is not currently running");
190 return false;
191 }
192
Peter Qiubf8e36c2014-12-03 22:59:45 -0800193 ReleaseResources();
Peter Qiue2657852015-02-03 11:33:11 -0800194 SetState(kStateIdle);
Peter Qiu376e4042014-11-13 09:40:28 -0800195 return true;
196}
197
198bool Service::IsHostapdRunning() {
199 return hostapd_process_ && hostapd_process_->pid() != 0 &&
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700200 brillo::Process::ProcessExists(hostapd_process_->pid());
Peter Qiu376e4042014-11-13 09:40:28 -0800201}
202
203bool Service::StartHostapdProcess(const string& config_file_path) {
Peter Qiu1dbf9fd2015-01-09 13:36:55 -0800204 hostapd_process_.reset(process_factory_->CreateProcess());
Peter Qiufb39ba42014-11-21 09:09:59 -0800205 hostapd_process_->AddArg(kHostapdPath);
Peter Qiu376e4042014-11-13 09:40:28 -0800206 hostapd_process_->AddArg(config_file_path);
207 if (!hostapd_process_->Start()) {
208 hostapd_process_.reset();
209 return false;
210 }
211 return true;
212}
213
214void Service::StopHostapdProcess() {
215 if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) {
216 hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds);
217 }
218 hostapd_process_.reset();
219}
220
Peter Qiubf8e36c2014-12-03 22:59:45 -0800221void Service::ReleaseResources() {
Peter Qiue2657852015-02-03 11:33:11 -0800222 hostapd_monitor_.reset();
Peter Qiubf8e36c2014-12-03 22:59:45 -0800223 StopHostapdProcess();
224 dhcp_server_.reset();
225 config_->ReleaseDevice();
Peter Qiu943cf3a2015-02-24 10:59:17 -0800226 manager_->ReleaseDHCPPortAccess(config_->selected_interface());
Peter Qiubf8e36c2014-12-03 22:59:45 -0800227}
228
Peter Qiufda548c2015-01-13 14:39:19 -0800229void Service::HostapdEventCallback(HostapdMonitor::Event event,
230 const std::string& data) {
231 switch (event) {
Peter Qiue2657852015-02-03 11:33:11 -0800232 case HostapdMonitor::kHostapdFailed:
233 SetState(kStateFailed);
234 break;
235 case HostapdMonitor::kHostapdStarted:
236 SetState(kStateStarted);
237 break;
Peter Qiufda548c2015-01-13 14:39:19 -0800238 case HostapdMonitor::kStationConnected:
239 LOG(INFO) << "Station connected: " << data;
240 break;
241 case HostapdMonitor::kStationDisconnected:
242 LOG(INFO) << "Station disconnected: " << data;
243 break;
244 default:
245 LOG(ERROR) << "Unknown event: " << event;
246 break;
247 }
248}
249
Peter Qiu376e4042014-11-13 09:40:28 -0800250} // namespace apmanager