blob: cd8a0e128768f0fa9b0f5b681c2124031cdbaf69 [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 Qiufb39ba42014-11-21 09:09:59 -080036#include "apmanager/manager.h"
Peter Qiu376e4042014-11-13 09:40:28 -080037
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -070038using brillo::dbus_utils::AsyncEventSequencer;
Peter Qiu682a9322015-10-27 09:41:52 -070039using brillo::dbus_utils::DBusMethodResponse;
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -070040using brillo::dbus_utils::ExportedObjectManager;
Vitaly Bukaa4630922014-12-11 18:46:46 -080041using org::chromium::apmanager::ManagerAdaptor;
Peter Qiu376e4042014-11-13 09:40:28 -080042using std::string;
43
44namespace apmanager {
45
46// static.
Peter Qiufc980572015-09-24 10:11:26 -070047#if !defined(__ANDROID__)
Peter Qiufb39ba42014-11-21 09:09:59 -080048const char Service::kHostapdPath[] = "/usr/sbin/hostapd";
Peter Qiu77517302015-01-08 16:22:16 -080049const char Service::kHostapdConfigPathFormat[] =
50 "/var/run/apmanager/hostapd/hostapd-%d.conf";
Peter Qiu1dbf9fd2015-01-09 13:36:55 -080051const char Service::kHostapdControlInterfacePath[] =
52 "/var/run/apmanager/hostapd/ctrl_iface";
Peter Qiufc980572015-09-24 10:11:26 -070053#else
54const char Service::kHostapdPath[] = "/system/bin/hostapd";
55const char Service::kHostapdConfigPathFormat[] =
56 "/data/misc/apmanager/hostapd/hostapd-%d.conf";
57const char Service::kHostapdControlInterfacePath[] =
58 "/data/misc/apmanager/hostapd/ctrl_iface";
59#endif // __ANDROID__
60
Peter Qiucbbefa22015-10-27 12:05:34 -070061#if defined(__BRILLO__)
62const int Service::kAPInterfaceCheckIntervalMilliseconds = 200;
63const int Service::kAPInterfaceCheckMaxAttempts = 5;
64#endif // __BRILLO__
65
Peter Qiu376e4042014-11-13 09:40:28 -080066const int Service::kTerminationTimeoutSeconds = 2;
67
Peter Qiue2657852015-02-03 11:33:11 -080068// static. Service state definitions.
69const char Service::kStateIdle[] = "Idle";
70const char Service::kStateStarting[] = "Starting";
71const char Service::kStateStarted[] = "Started";
72const char Service::kStateFailed[] = "Failed";
73
Peter Qiufb39ba42014-11-21 09:09:59 -080074Service::Service(Manager* manager, int service_identifier)
Peter Qiu376e4042014-11-13 09:40:28 -080075 : org::chromium::apmanager::ServiceAdaptor(this),
Peter Qiufb39ba42014-11-21 09:09:59 -080076 manager_(manager),
Peter Qiufd02b6f2015-02-27 09:55:11 -080077 identifier_(service_identifier),
Vitaly Bukaa4630922014-12-11 18:46:46 -080078 service_path_(
79 base::StringPrintf("%s/services/%d",
80 ManagerAdaptor::GetObjectPath().value().c_str(),
81 service_identifier)),
Peter Qiu376e4042014-11-13 09:40:28 -080082 dbus_path_(dbus::ObjectPath(service_path_)),
Peter Qiubf8e36c2014-12-03 22:59:45 -080083 config_(new Config(manager, service_path_)),
Peter Qiu77517302015-01-08 16:22:16 -080084 dhcp_server_factory_(DHCPServerFactory::GetInstance()),
Peter Qiu1dbf9fd2015-01-09 13:36:55 -080085 file_writer_(FileWriter::GetInstance()),
86 process_factory_(ProcessFactory::GetInstance()) {
Peter Qiu376e4042014-11-13 09:40:28 -080087 SetConfig(config_->dbus_path());
Peter Qiue2657852015-02-03 11:33:11 -080088 SetState(kStateIdle);
Peter Qiubf8e36c2014-12-03 22:59:45 -080089 // TODO(zqiu): come up with better server address management. This is good
90 // enough for now.
Peter Qiufd02b6f2015-02-27 09:55:11 -080091 config_->SetServerAddressIndex(identifier_ & 0xFF);
Peter Qiucbbefa22015-10-27 12:05:34 -070092
93#if defined(__BRILLO__)
94 event_dispatcher_ = EventDispatcher::GetInstance();
95 start_in_progress_ = false;
96#endif
Peter Qiu376e4042014-11-13 09:40:28 -080097}
98
99Service::~Service() {
100 // Stop hostapd process if still running.
101 if (IsHostapdRunning()) {
Peter Qiubf8e36c2014-12-03 22:59:45 -0800102 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -0800103 }
104}
105
106void Service::RegisterAsync(ExportedObjectManager* object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -0800107 const scoped_refptr<dbus::Bus>& bus,
Peter Qiu376e4042014-11-13 09:40:28 -0800108 AsyncEventSequencer* sequencer) {
109 CHECK(!dbus_object_) << "Already registered";
110 dbus_object_.reset(
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700111 new brillo::dbus_utils::DBusObject(
Peter Qiu376e4042014-11-13 09:40:28 -0800112 object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -0800113 bus,
Peter Qiu376e4042014-11-13 09:40:28 -0800114 dbus_path_));
115 RegisterWithDBusObject(dbus_object_.get());
116 dbus_object_->RegisterAsync(
117 sequencer->GetHandler("Service.RegisterAsync() failed.", true));
118
119 // Register Config DBus object.
Peter Qiuc9ce1f12014-12-05 11:14:29 -0800120 config_->RegisterAsync(object_manager, bus, sequencer);
Peter Qiu376e4042014-11-13 09:40:28 -0800121}
122
Peter Qiu682a9322015-10-27 09:41:52 -0700123bool Service::StartInternal(brillo::ErrorPtr* error) {
Peter Qiu376e4042014-11-13 09:40:28 -0800124 if (IsHostapdRunning()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700125 brillo::Error::AddTo(
126 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800127 "Service already running");
128 return false;
129 }
130
Peter Qiubfd410e2015-01-09 15:14:20 -0800131 // Setup hostapd control interface path.
132 config_->set_control_interface(kHostapdControlInterfacePath);
133
Peter Qiu376e4042014-11-13 09:40:28 -0800134 // Generate hostapd configuration content.
135 string config_str;
136 if (!config_->GenerateConfigFile(error, &config_str)) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700137 brillo::Error::AddTo(
138 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800139 "Failed to generate config file");
140 return false;
141 }
142
143 // Write configuration to a file.
Peter Qiu77517302015-01-08 16:22:16 -0800144 string config_file_name = base::StringPrintf(kHostapdConfigPathFormat,
Peter Qiufd02b6f2015-02-27 09:55:11 -0800145 identifier_);
Peter Qiu77517302015-01-08 16:22:16 -0800146 if (!file_writer_->Write(config_file_name, config_str)) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700147 brillo::Error::AddTo(
148 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800149 "Failed to write configuration to a file");
150 return false;
151 }
152
Peter Qiufb39ba42014-11-21 09:09:59 -0800153 // Claim the device needed for this ap service.
154 if (!config_->ClaimDevice()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700155 brillo::Error::AddTo(
156 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiufb39ba42014-11-21 09:09:59 -0800157 "Failed to claim the device for this service");
158 return false;
159 }
160
Peter Qiu376e4042014-11-13 09:40:28 -0800161 // Start hostapd process.
Peter Qiu77517302015-01-08 16:22:16 -0800162 if (!StartHostapdProcess(config_file_name)) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700163 brillo::Error::AddTo(
164 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800165 "Failed to start hostapd");
Peter Qiufb39ba42014-11-21 09:09:59 -0800166 // Release the device claimed for this service.
167 config_->ReleaseDevice();
Peter Qiu376e4042014-11-13 09:40:28 -0800168 return false;
169 }
170
Peter Qiubf8e36c2014-12-03 22:59:45 -0800171 // Start DHCP server if in server mode.
172 if (config_->GetOperationMode() == kOperationModeServer) {
173 dhcp_server_.reset(
174 dhcp_server_factory_->CreateDHCPServer(config_->GetServerAddressIndex(),
175 config_->selected_interface()));
176 if (!dhcp_server_->Start()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700177 brillo::Error::AddTo(
178 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiubf8e36c2014-12-03 22:59:45 -0800179 "Failed to start DHCP server");
180 ReleaseResources();
181 return false;
182 }
Peter Qiu943cf3a2015-02-24 10:59:17 -0800183 manager_->RequestDHCPPortAccess(config_->selected_interface());
Peter Qiubf8e36c2014-12-03 22:59:45 -0800184 }
185
Peter Qiufda548c2015-01-13 14:39:19 -0800186 // Start monitoring hostapd.
187 if (!hostapd_monitor_) {
188 hostapd_monitor_.reset(
189 new HostapdMonitor(base::Bind(&Service::HostapdEventCallback,
Peter Qiucbbefa22015-10-27 12:05:34 -0700190 weak_factory_.GetWeakPtr()),
Peter Qiufda548c2015-01-13 14:39:19 -0800191 config_->control_interface(),
192 config_->selected_interface()));
193 }
194 hostapd_monitor_->Start();
195
Peter Qiue2657852015-02-03 11:33:11 -0800196 // Update service state.
197 SetState(kStateStarting);
198
Peter Qiu376e4042014-11-13 09:40:28 -0800199 return true;
200}
201
Peter Qiu682a9322015-10-27 09:41:52 -0700202void Service::Start(std::unique_ptr<DBusMethodResponse<>> response) {
203 brillo::ErrorPtr error;
204
Peter Qiucbbefa22015-10-27 12:05:34 -0700205#if !defined(__BRILLO__)
Peter Qiu682a9322015-10-27 09:41:52 -0700206 if (!StartInternal(&error)) {
207 response->ReplyWithError(error.get());
208 } else {
209 response->Return();
210 }
Peter Qiucbbefa22015-10-27 12:05:34 -0700211#else
212 if (start_in_progress_) {
213 brillo::Error::AddTo(
214 &error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
215 "Start already in progress");
216 response->ReplyWithError(error.get());
217 return;
218 }
219
220 string interface_name;
221 if (!manager_->SetupApModeInterface(&interface_name)) {
222 brillo::Error::AddTo(
223 &error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
224 "Failed to setup AP mode interface");
225 response->ReplyWithError(error.get());
226 return;
227 }
228
229 event_dispatcher_->PostDelayedTask(
230 base::Bind(&Service::APInterfaceCheckTask,
231 weak_factory_.GetWeakPtr(),
232 interface_name,
233 0, // Initial check count.
234 base::Passed(&response)),
235 kAPInterfaceCheckIntervalMilliseconds);
236#endif
Peter Qiu682a9322015-10-27 09:41:52 -0700237}
238
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700239bool Service::Stop(brillo::ErrorPtr* error) {
Peter Qiu376e4042014-11-13 09:40:28 -0800240 if (!IsHostapdRunning()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700241 brillo::Error::AddTo(
242 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800243 "Service is not currently running");
244 return false;
245 }
246
Peter Qiubf8e36c2014-12-03 22:59:45 -0800247 ReleaseResources();
Peter Qiue2657852015-02-03 11:33:11 -0800248 SetState(kStateIdle);
Peter Qiu376e4042014-11-13 09:40:28 -0800249 return true;
250}
251
Peter Qiucbbefa22015-10-27 12:05:34 -0700252#if defined(__BRILLO__)
253void Service::HandleStartFailure() {
254 // Restore station mode interface.
255 string station_mode_interface;
256 manager_->SetupStationModeInterface(&station_mode_interface);
257
258 // Reset state variables.
259 start_in_progress_ = false;
260}
261
262void Service::APInterfaceCheckTask(
263 const string& interface_name,
264 int check_count,
265 std::unique_ptr<DBusMethodResponse<>> response) {
266 brillo::ErrorPtr error;
267
268 // Check if the AP interface is enumerated.
269 if (manager_->GetDeviceFromInterfaceName(interface_name)) {
270 // Explicitly set the interface name to avoid picking other interface.
271 config_->SetInterfaceName(interface_name);
272 if (!StartInternal(&error)) {
273 HandleStartFailure();
274 response->ReplyWithError(error.get());
275 } else {
276 response->Return();
277 }
278 return;
279 }
280
281 check_count++;
282 if (check_count >= kAPInterfaceCheckMaxAttempts) {
283 brillo::Error::AddTo(
284 &error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
285 "Timeout waiting for AP interface to be enumerated");
286 HandleStartFailure();
287 response->ReplyWithError(error.get());
288 return;
289 }
290
291 event_dispatcher_->PostDelayedTask(
292 base::Bind(&Service::APInterfaceCheckTask,
293 weak_factory_.GetWeakPtr(),
294 interface_name,
295 check_count,
296 base::Passed(&response)),
297 kAPInterfaceCheckIntervalMilliseconds);
298}
299#endif // __BRILLO__
300
Peter Qiu376e4042014-11-13 09:40:28 -0800301bool Service::IsHostapdRunning() {
302 return hostapd_process_ && hostapd_process_->pid() != 0 &&
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700303 brillo::Process::ProcessExists(hostapd_process_->pid());
Peter Qiu376e4042014-11-13 09:40:28 -0800304}
305
306bool Service::StartHostapdProcess(const string& config_file_path) {
Peter Qiu1dbf9fd2015-01-09 13:36:55 -0800307 hostapd_process_.reset(process_factory_->CreateProcess());
Peter Qiufb39ba42014-11-21 09:09:59 -0800308 hostapd_process_->AddArg(kHostapdPath);
Peter Qiu376e4042014-11-13 09:40:28 -0800309 hostapd_process_->AddArg(config_file_path);
310 if (!hostapd_process_->Start()) {
311 hostapd_process_.reset();
312 return false;
313 }
314 return true;
315}
316
317void Service::StopHostapdProcess() {
318 if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) {
319 hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds);
320 }
321 hostapd_process_.reset();
322}
323
Peter Qiubf8e36c2014-12-03 22:59:45 -0800324void Service::ReleaseResources() {
Peter Qiue2657852015-02-03 11:33:11 -0800325 hostapd_monitor_.reset();
Peter Qiubf8e36c2014-12-03 22:59:45 -0800326 StopHostapdProcess();
327 dhcp_server_.reset();
Peter Qiu943cf3a2015-02-24 10:59:17 -0800328 manager_->ReleaseDHCPPortAccess(config_->selected_interface());
Peter Qiucbbefa22015-10-27 12:05:34 -0700329#if defined(__BRILLO__)
330 // Restore station mode interface.
331 string station_mode_interface;
332 manager_->SetupStationModeInterface(&station_mode_interface);
333#endif // __BRILLO__
Peter Qiu31f70862015-11-16 09:22:34 -0800334 // Only release device after mode switching had completed, to
335 // make sure the station mode interface gets enumerated by
336 // shill.
337 config_->ReleaseDevice();
Peter Qiubf8e36c2014-12-03 22:59:45 -0800338}
339
Peter Qiufda548c2015-01-13 14:39:19 -0800340void Service::HostapdEventCallback(HostapdMonitor::Event event,
341 const std::string& data) {
342 switch (event) {
Peter Qiue2657852015-02-03 11:33:11 -0800343 case HostapdMonitor::kHostapdFailed:
344 SetState(kStateFailed);
345 break;
346 case HostapdMonitor::kHostapdStarted:
347 SetState(kStateStarted);
348 break;
Peter Qiufda548c2015-01-13 14:39:19 -0800349 case HostapdMonitor::kStationConnected:
350 LOG(INFO) << "Station connected: " << data;
351 break;
352 case HostapdMonitor::kStationDisconnected:
353 LOG(INFO) << "Station disconnected: " << data;
354 break;
355 default:
356 LOG(ERROR) << "Unknown event: " << event;
357 break;
358 }
359}
360
Peter Qiu376e4042014-11-13 09:40:28 -0800361} // namespace apmanager