blob: 4b5a02631095147cc50f27859ccb1eaba454f0d1 [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 Qiucbbefa22015-10-27 12:05:34 -070030#if defined(__BRILLO__)
31#include <base/bind.h>
32
33#include "apmanager/event_dispatcher.h"
34#endif // __BRILLO__
35
Peter Qiud9c79aa2015-11-19 15:36:00 -080036#include "apmanager/error.h"
Peter Qiufb39ba42014-11-21 09:09:59 -080037#include "apmanager/manager.h"
Peter Qiu376e4042014-11-13 09:40:28 -080038
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -070039using brillo::dbus_utils::AsyncEventSequencer;
Peter Qiu682a9322015-10-27 09:41:52 -070040using brillo::dbus_utils::DBusMethodResponse;
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -070041using brillo::dbus_utils::ExportedObjectManager;
Vitaly Bukaa4630922014-12-11 18:46:46 -080042using org::chromium::apmanager::ManagerAdaptor;
Peter Qiu376e4042014-11-13 09:40:28 -080043using std::string;
44
45namespace apmanager {
46
47// static.
Peter Qiufc980572015-09-24 10:11:26 -070048#if !defined(__ANDROID__)
Peter Qiufb39ba42014-11-21 09:09:59 -080049const char Service::kHostapdPath[] = "/usr/sbin/hostapd";
Peter Qiu77517302015-01-08 16:22:16 -080050const char Service::kHostapdConfigPathFormat[] =
51 "/var/run/apmanager/hostapd/hostapd-%d.conf";
Peter Qiu1dbf9fd2015-01-09 13:36:55 -080052const char Service::kHostapdControlInterfacePath[] =
53 "/var/run/apmanager/hostapd/ctrl_iface";
Peter Qiufc980572015-09-24 10:11:26 -070054#else
55const char Service::kHostapdPath[] = "/system/bin/hostapd";
56const char Service::kHostapdConfigPathFormat[] =
57 "/data/misc/apmanager/hostapd/hostapd-%d.conf";
58const char Service::kHostapdControlInterfacePath[] =
59 "/data/misc/apmanager/hostapd/ctrl_iface";
60#endif // __ANDROID__
61
Peter Qiucbbefa22015-10-27 12:05:34 -070062#if defined(__BRILLO__)
63const int Service::kAPInterfaceCheckIntervalMilliseconds = 200;
64const int Service::kAPInterfaceCheckMaxAttempts = 5;
65#endif // __BRILLO__
66
Peter Qiu376e4042014-11-13 09:40:28 -080067const int Service::kTerminationTimeoutSeconds = 2;
68
Peter Qiue2657852015-02-03 11:33:11 -080069// static. Service state definitions.
70const char Service::kStateIdle[] = "Idle";
71const char Service::kStateStarting[] = "Starting";
72const char Service::kStateStarted[] = "Started";
73const char Service::kStateFailed[] = "Failed";
74
Peter Qiufb39ba42014-11-21 09:09:59 -080075Service::Service(Manager* manager, int service_identifier)
Peter Qiu376e4042014-11-13 09:40:28 -080076 : org::chromium::apmanager::ServiceAdaptor(this),
Peter Qiufb39ba42014-11-21 09:09:59 -080077 manager_(manager),
Peter Qiufd02b6f2015-02-27 09:55:11 -080078 identifier_(service_identifier),
Vitaly Bukaa4630922014-12-11 18:46:46 -080079 service_path_(
80 base::StringPrintf("%s/services/%d",
81 ManagerAdaptor::GetObjectPath().value().c_str(),
82 service_identifier)),
Peter Qiu376e4042014-11-13 09:40:28 -080083 dbus_path_(dbus::ObjectPath(service_path_)),
Peter Qiud9c79aa2015-11-19 15:36:00 -080084 config_(new Config(manager, service_identifier)),
Peter Qiu77517302015-01-08 16:22:16 -080085 dhcp_server_factory_(DHCPServerFactory::GetInstance()),
Peter Qiu1dbf9fd2015-01-09 13:36:55 -080086 file_writer_(FileWriter::GetInstance()),
87 process_factory_(ProcessFactory::GetInstance()) {
Peter Qiud9c79aa2015-11-19 15:36:00 -080088 SetConfig(config_->adaptor()->GetRpcObjectIdentifier());
Peter Qiue2657852015-02-03 11:33:11 -080089 SetState(kStateIdle);
Peter Qiubf8e36c2014-12-03 22:59:45 -080090 // TODO(zqiu): come up with better server address management. This is good
91 // enough for now.
Peter Qiufd02b6f2015-02-27 09:55:11 -080092 config_->SetServerAddressIndex(identifier_ & 0xFF);
Peter Qiucbbefa22015-10-27 12:05:34 -070093
94#if defined(__BRILLO__)
95 event_dispatcher_ = EventDispatcher::GetInstance();
96 start_in_progress_ = false;
97#endif
Peter Qiu376e4042014-11-13 09:40:28 -080098}
99
100Service::~Service() {
101 // Stop hostapd process if still running.
102 if (IsHostapdRunning()) {
Peter Qiubf8e36c2014-12-03 22:59:45 -0800103 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -0800104 }
105}
106
107void Service::RegisterAsync(ExportedObjectManager* object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -0800108 const scoped_refptr<dbus::Bus>& bus,
Peter Qiu376e4042014-11-13 09:40:28 -0800109 AsyncEventSequencer* sequencer) {
110 CHECK(!dbus_object_) << "Already registered";
111 dbus_object_.reset(
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700112 new brillo::dbus_utils::DBusObject(
Peter Qiu376e4042014-11-13 09:40:28 -0800113 object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -0800114 bus,
Peter Qiu376e4042014-11-13 09:40:28 -0800115 dbus_path_));
116 RegisterWithDBusObject(dbus_object_.get());
117 dbus_object_->RegisterAsync(
118 sequencer->GetHandler("Service.RegisterAsync() failed.", true));
Peter Qiu376e4042014-11-13 09:40:28 -0800119}
120
Peter Qiu682a9322015-10-27 09:41:52 -0700121bool Service::StartInternal(brillo::ErrorPtr* error) {
Peter Qiu376e4042014-11-13 09:40:28 -0800122 if (IsHostapdRunning()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700123 brillo::Error::AddTo(
124 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800125 "Service already running");
126 return false;
127 }
128
Peter Qiubfd410e2015-01-09 15:14:20 -0800129 // Setup hostapd control interface path.
130 config_->set_control_interface(kHostapdControlInterfacePath);
131
Peter Qiu376e4042014-11-13 09:40:28 -0800132 // Generate hostapd configuration content.
133 string config_str;
Peter Qiud9c79aa2015-11-19 15:36:00 -0800134 Error internal_error;
135 if (!config_->GenerateConfigFile(&internal_error, &config_str)) {
136 // TODO(zqiu): temporary until D-Bus is decoupled from this class.
137 internal_error.ToDBusError(error);
Peter Qiu376e4042014-11-13 09:40:28 -0800138 return false;
139 }
140
141 // Write configuration to a file.
Peter Qiu77517302015-01-08 16:22:16 -0800142 string config_file_name = base::StringPrintf(kHostapdConfigPathFormat,
Peter Qiufd02b6f2015-02-27 09:55:11 -0800143 identifier_);
Peter Qiu77517302015-01-08 16:22:16 -0800144 if (!file_writer_->Write(config_file_name, config_str)) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700145 brillo::Error::AddTo(
146 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800147 "Failed to write configuration to a file");
148 return false;
149 }
150
Peter Qiufb39ba42014-11-21 09:09:59 -0800151 // Claim the device needed for this ap service.
152 if (!config_->ClaimDevice()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700153 brillo::Error::AddTo(
154 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiufb39ba42014-11-21 09:09:59 -0800155 "Failed to claim the device for this service");
156 return false;
157 }
158
Peter Qiu376e4042014-11-13 09:40:28 -0800159 // Start hostapd process.
Peter Qiu77517302015-01-08 16:22:16 -0800160 if (!StartHostapdProcess(config_file_name)) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700161 brillo::Error::AddTo(
162 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800163 "Failed to start hostapd");
Peter Qiufb39ba42014-11-21 09:09:59 -0800164 // Release the device claimed for this service.
165 config_->ReleaseDevice();
Peter Qiu376e4042014-11-13 09:40:28 -0800166 return false;
167 }
168
Peter Qiubf8e36c2014-12-03 22:59:45 -0800169 // Start DHCP server if in server mode.
170 if (config_->GetOperationMode() == kOperationModeServer) {
171 dhcp_server_.reset(
172 dhcp_server_factory_->CreateDHCPServer(config_->GetServerAddressIndex(),
173 config_->selected_interface()));
174 if (!dhcp_server_->Start()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700175 brillo::Error::AddTo(
176 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiubf8e36c2014-12-03 22:59:45 -0800177 "Failed to start DHCP server");
178 ReleaseResources();
179 return false;
180 }
Peter Qiu943cf3a2015-02-24 10:59:17 -0800181 manager_->RequestDHCPPortAccess(config_->selected_interface());
Peter Qiubf8e36c2014-12-03 22:59:45 -0800182 }
183
Peter Qiufda548c2015-01-13 14:39:19 -0800184 // Start monitoring hostapd.
185 if (!hostapd_monitor_) {
186 hostapd_monitor_.reset(
187 new HostapdMonitor(base::Bind(&Service::HostapdEventCallback,
Peter Qiucbbefa22015-10-27 12:05:34 -0700188 weak_factory_.GetWeakPtr()),
Peter Qiufda548c2015-01-13 14:39:19 -0800189 config_->control_interface(),
190 config_->selected_interface()));
191 }
192 hostapd_monitor_->Start();
193
Peter Qiue2657852015-02-03 11:33:11 -0800194 // Update service state.
195 SetState(kStateStarting);
196
Peter Qiu376e4042014-11-13 09:40:28 -0800197 return true;
198}
199
Peter Qiu682a9322015-10-27 09:41:52 -0700200void Service::Start(std::unique_ptr<DBusMethodResponse<>> response) {
201 brillo::ErrorPtr error;
202
Peter Qiucbbefa22015-10-27 12:05:34 -0700203#if !defined(__BRILLO__)
Peter Qiu682a9322015-10-27 09:41:52 -0700204 if (!StartInternal(&error)) {
205 response->ReplyWithError(error.get());
206 } else {
207 response->Return();
208 }
Peter Qiucbbefa22015-10-27 12:05:34 -0700209#else
210 if (start_in_progress_) {
211 brillo::Error::AddTo(
212 &error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
213 "Start already in progress");
214 response->ReplyWithError(error.get());
215 return;
216 }
217
218 string interface_name;
219 if (!manager_->SetupApModeInterface(&interface_name)) {
220 brillo::Error::AddTo(
221 &error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
222 "Failed to setup AP mode interface");
223 response->ReplyWithError(error.get());
224 return;
225 }
226
227 event_dispatcher_->PostDelayedTask(
228 base::Bind(&Service::APInterfaceCheckTask,
229 weak_factory_.GetWeakPtr(),
230 interface_name,
231 0, // Initial check count.
232 base::Passed(&response)),
233 kAPInterfaceCheckIntervalMilliseconds);
234#endif
Peter Qiu682a9322015-10-27 09:41:52 -0700235}
236
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700237bool Service::Stop(brillo::ErrorPtr* error) {
Peter Qiu376e4042014-11-13 09:40:28 -0800238 if (!IsHostapdRunning()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700239 brillo::Error::AddTo(
240 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800241 "Service is not currently running");
242 return false;
243 }
244
Peter Qiubf8e36c2014-12-03 22:59:45 -0800245 ReleaseResources();
Peter Qiue2657852015-02-03 11:33:11 -0800246 SetState(kStateIdle);
Peter Qiu376e4042014-11-13 09:40:28 -0800247 return true;
248}
249
Peter Qiucbbefa22015-10-27 12:05:34 -0700250#if defined(__BRILLO__)
251void Service::HandleStartFailure() {
252 // Restore station mode interface.
253 string station_mode_interface;
254 manager_->SetupStationModeInterface(&station_mode_interface);
255
256 // Reset state variables.
257 start_in_progress_ = false;
258}
259
260void Service::APInterfaceCheckTask(
261 const string& interface_name,
262 int check_count,
263 std::unique_ptr<DBusMethodResponse<>> response) {
264 brillo::ErrorPtr error;
265
266 // Check if the AP interface is enumerated.
267 if (manager_->GetDeviceFromInterfaceName(interface_name)) {
268 // Explicitly set the interface name to avoid picking other interface.
269 config_->SetInterfaceName(interface_name);
270 if (!StartInternal(&error)) {
271 HandleStartFailure();
272 response->ReplyWithError(error.get());
273 } else {
274 response->Return();
275 }
276 return;
277 }
278
279 check_count++;
280 if (check_count >= kAPInterfaceCheckMaxAttempts) {
281 brillo::Error::AddTo(
282 &error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
283 "Timeout waiting for AP interface to be enumerated");
284 HandleStartFailure();
285 response->ReplyWithError(error.get());
286 return;
287 }
288
289 event_dispatcher_->PostDelayedTask(
290 base::Bind(&Service::APInterfaceCheckTask,
291 weak_factory_.GetWeakPtr(),
292 interface_name,
293 check_count,
294 base::Passed(&response)),
295 kAPInterfaceCheckIntervalMilliseconds);
296}
297#endif // __BRILLO__
298
Peter Qiu376e4042014-11-13 09:40:28 -0800299bool Service::IsHostapdRunning() {
300 return hostapd_process_ && hostapd_process_->pid() != 0 &&
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700301 brillo::Process::ProcessExists(hostapd_process_->pid());
Peter Qiu376e4042014-11-13 09:40:28 -0800302}
303
304bool Service::StartHostapdProcess(const string& config_file_path) {
Peter Qiu1dbf9fd2015-01-09 13:36:55 -0800305 hostapd_process_.reset(process_factory_->CreateProcess());
Peter Qiufb39ba42014-11-21 09:09:59 -0800306 hostapd_process_->AddArg(kHostapdPath);
Peter Qiu376e4042014-11-13 09:40:28 -0800307 hostapd_process_->AddArg(config_file_path);
308 if (!hostapd_process_->Start()) {
309 hostapd_process_.reset();
310 return false;
311 }
312 return true;
313}
314
315void Service::StopHostapdProcess() {
316 if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) {
317 hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds);
318 }
319 hostapd_process_.reset();
320}
321
Peter Qiubf8e36c2014-12-03 22:59:45 -0800322void Service::ReleaseResources() {
Peter Qiue2657852015-02-03 11:33:11 -0800323 hostapd_monitor_.reset();
Peter Qiubf8e36c2014-12-03 22:59:45 -0800324 StopHostapdProcess();
325 dhcp_server_.reset();
Peter Qiu943cf3a2015-02-24 10:59:17 -0800326 manager_->ReleaseDHCPPortAccess(config_->selected_interface());
Peter Qiucbbefa22015-10-27 12:05:34 -0700327#if defined(__BRILLO__)
328 // Restore station mode interface.
329 string station_mode_interface;
330 manager_->SetupStationModeInterface(&station_mode_interface);
331#endif // __BRILLO__
Peter Qiu31f70862015-11-16 09:22:34 -0800332 // Only release device after mode switching had completed, to
333 // make sure the station mode interface gets enumerated by
334 // shill.
335 config_->ReleaseDevice();
Peter Qiubf8e36c2014-12-03 22:59:45 -0800336}
337
Peter Qiufda548c2015-01-13 14:39:19 -0800338void Service::HostapdEventCallback(HostapdMonitor::Event event,
339 const std::string& data) {
340 switch (event) {
Peter Qiue2657852015-02-03 11:33:11 -0800341 case HostapdMonitor::kHostapdFailed:
342 SetState(kStateFailed);
343 break;
344 case HostapdMonitor::kHostapdStarted:
345 SetState(kStateStarted);
346 break;
Peter Qiufda548c2015-01-13 14:39:19 -0800347 case HostapdMonitor::kStationConnected:
348 LOG(INFO) << "Station connected: " << data;
349 break;
350 case HostapdMonitor::kStationDisconnected:
351 LOG(INFO) << "Station disconnected: " << data;
352 break;
353 default:
354 LOG(ERROR) << "Unknown event: " << event;
355 break;
356 }
357}
358
Peter Qiu376e4042014-11-13 09:40:28 -0800359} // namespace apmanager