blob: e973da9d64b9dbb4bb2bd428229e7a9b76ef780e [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 Qiu2ea547f2015-11-20 14:18:11 -080021#include <base/bind.h>
Peter Qiu376e4042014-11-13 09:40:28 -080022#include <base/strings/stringprintf.h>
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -070023#include <brillo/errors/error.h>
Peter Qiu376e4042014-11-13 09:40:28 -080024
Peter Qiu7a420d32015-09-22 11:25:15 -070025#if !defined(__ANDROID__)
26#include <chromeos/dbus/service_constants.h>
27#else
Peter Qiu2ea547f2015-11-20 14:18:11 -080028#include <dbus/apmanager/dbus-constants.h>
Peter Qiu7a420d32015-09-22 11:25:15 -070029#endif // __ANDROID__
30
Peter Qiucbbefa22015-10-27 12:05:34 -070031#if defined(__BRILLO__)
Peter Qiucbbefa22015-10-27 12:05:34 -070032#include "apmanager/event_dispatcher.h"
33#endif // __BRILLO__
34
Peter Qiu2ea547f2015-11-20 14:18:11 -080035#include "apmanager/control_interface.h"
Peter Qiufb39ba42014-11-21 09:09:59 -080036#include "apmanager/manager.h"
Peter Qiu376e4042014-11-13 09:40:28 -080037
Peter Qiu376e4042014-11-13 09:40:28 -080038using std::string;
39
40namespace apmanager {
41
42// static.
Peter Qiufc980572015-09-24 10:11:26 -070043#if !defined(__ANDROID__)
Peter Qiufb39ba42014-11-21 09:09:59 -080044const char Service::kHostapdPath[] = "/usr/sbin/hostapd";
Peter Qiu77517302015-01-08 16:22:16 -080045const char Service::kHostapdConfigPathFormat[] =
46 "/var/run/apmanager/hostapd/hostapd-%d.conf";
Peter Qiu1dbf9fd2015-01-09 13:36:55 -080047const char Service::kHostapdControlInterfacePath[] =
48 "/var/run/apmanager/hostapd/ctrl_iface";
Peter Qiufc980572015-09-24 10:11:26 -070049#else
50const char Service::kHostapdPath[] = "/system/bin/hostapd";
51const char Service::kHostapdConfigPathFormat[] =
52 "/data/misc/apmanager/hostapd/hostapd-%d.conf";
53const char Service::kHostapdControlInterfacePath[] =
54 "/data/misc/apmanager/hostapd/ctrl_iface";
55#endif // __ANDROID__
56
Peter Qiucbbefa22015-10-27 12:05:34 -070057#if defined(__BRILLO__)
58const int Service::kAPInterfaceCheckIntervalMilliseconds = 200;
59const int Service::kAPInterfaceCheckMaxAttempts = 5;
60#endif // __BRILLO__
61
Peter Qiu376e4042014-11-13 09:40:28 -080062const int Service::kTerminationTimeoutSeconds = 2;
63
Peter Qiue2657852015-02-03 11:33:11 -080064// static. Service state definitions.
65const char Service::kStateIdle[] = "Idle";
66const char Service::kStateStarting[] = "Starting";
67const char Service::kStateStarted[] = "Started";
68const char Service::kStateFailed[] = "Failed";
69
Peter Qiufb39ba42014-11-21 09:09:59 -080070Service::Service(Manager* manager, int service_identifier)
Peter Qiu2ea547f2015-11-20 14:18:11 -080071 : manager_(manager),
Peter Qiufd02b6f2015-02-27 09:55:11 -080072 identifier_(service_identifier),
Peter Qiud9c79aa2015-11-19 15:36:00 -080073 config_(new Config(manager, service_identifier)),
Peter Qiu2ea547f2015-11-20 14:18:11 -080074 adaptor_(manager->control_interface()->CreateServiceAdaptor(this)),
Peter Qiu77517302015-01-08 16:22:16 -080075 dhcp_server_factory_(DHCPServerFactory::GetInstance()),
Peter Qiu1dbf9fd2015-01-09 13:36:55 -080076 file_writer_(FileWriter::GetInstance()),
77 process_factory_(ProcessFactory::GetInstance()) {
Peter Qiu2ea547f2015-11-20 14:18:11 -080078 adaptor_->SetConfig(config_.get());
79 adaptor_->SetState(kStateIdle);
Peter Qiubf8e36c2014-12-03 22:59:45 -080080 // TODO(zqiu): come up with better server address management. This is good
81 // enough for now.
Peter Qiufd02b6f2015-02-27 09:55:11 -080082 config_->SetServerAddressIndex(identifier_ & 0xFF);
Peter Qiucbbefa22015-10-27 12:05:34 -070083
84#if defined(__BRILLO__)
85 event_dispatcher_ = EventDispatcher::GetInstance();
86 start_in_progress_ = false;
87#endif
Peter Qiu376e4042014-11-13 09:40:28 -080088}
89
90Service::~Service() {
91 // Stop hostapd process if still running.
92 if (IsHostapdRunning()) {
Peter Qiubf8e36c2014-12-03 22:59:45 -080093 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -080094 }
95}
96
Peter Qiu2ea547f2015-11-20 14:18:11 -080097bool Service::StartInternal(Error* error) {
Peter Qiu376e4042014-11-13 09:40:28 -080098 if (IsHostapdRunning()) {
Peter Qiu2ea547f2015-11-20 14:18:11 -080099 Error::PopulateAndLog(
100 error, Error::kInternalError, "Service already running", FROM_HERE);
Peter Qiu376e4042014-11-13 09:40:28 -0800101 return false;
102 }
103
Peter Qiubfd410e2015-01-09 15:14:20 -0800104 // Setup hostapd control interface path.
105 config_->set_control_interface(kHostapdControlInterfacePath);
106
Peter Qiu376e4042014-11-13 09:40:28 -0800107 // Generate hostapd configuration content.
108 string config_str;
Peter Qiu2ea547f2015-11-20 14:18:11 -0800109 if (!config_->GenerateConfigFile(error, &config_str)) {
Peter Qiu376e4042014-11-13 09:40:28 -0800110 return false;
111 }
112
113 // Write configuration to a file.
Peter Qiu77517302015-01-08 16:22:16 -0800114 string config_file_name = base::StringPrintf(kHostapdConfigPathFormat,
Peter Qiufd02b6f2015-02-27 09:55:11 -0800115 identifier_);
Peter Qiu77517302015-01-08 16:22:16 -0800116 if (!file_writer_->Write(config_file_name, config_str)) {
Peter Qiu2ea547f2015-11-20 14:18:11 -0800117 Error::PopulateAndLog(error,
118 Error::kInternalError,
119 "Failed to write configuration to a file",
120 FROM_HERE);
Peter Qiu376e4042014-11-13 09:40:28 -0800121 return false;
122 }
123
Peter Qiufb39ba42014-11-21 09:09:59 -0800124 // Claim the device needed for this ap service.
125 if (!config_->ClaimDevice()) {
Peter Qiu2ea547f2015-11-20 14:18:11 -0800126 Error::PopulateAndLog(error,
127 Error::kInternalError,
128 "Failed to claim the device for this service",
129 FROM_HERE);
Peter Qiufb39ba42014-11-21 09:09:59 -0800130 return false;
131 }
132
Peter Qiu376e4042014-11-13 09:40:28 -0800133 // Start hostapd process.
Peter Qiu77517302015-01-08 16:22:16 -0800134 if (!StartHostapdProcess(config_file_name)) {
Peter Qiu2ea547f2015-11-20 14:18:11 -0800135 Error::PopulateAndLog(
136 error, Error::kInternalError, "Failed to start hostapd", FROM_HERE);
Peter Qiufb39ba42014-11-21 09:09:59 -0800137 // Release the device claimed for this service.
138 config_->ReleaseDevice();
Peter Qiu376e4042014-11-13 09:40:28 -0800139 return false;
140 }
141
Peter Qiubf8e36c2014-12-03 22:59:45 -0800142 // Start DHCP server if in server mode.
143 if (config_->GetOperationMode() == kOperationModeServer) {
144 dhcp_server_.reset(
145 dhcp_server_factory_->CreateDHCPServer(config_->GetServerAddressIndex(),
146 config_->selected_interface()));
147 if (!dhcp_server_->Start()) {
Peter Qiu2ea547f2015-11-20 14:18:11 -0800148 Error::PopulateAndLog(error,
149 Error::kInternalError,
150 "Failed to start DHCP server",
151 FROM_HERE);
Peter Qiubf8e36c2014-12-03 22:59:45 -0800152 ReleaseResources();
153 return false;
154 }
Peter Qiu943cf3a2015-02-24 10:59:17 -0800155 manager_->RequestDHCPPortAccess(config_->selected_interface());
Peter Qiubf8e36c2014-12-03 22:59:45 -0800156 }
157
Peter Qiufda548c2015-01-13 14:39:19 -0800158 // Start monitoring hostapd.
159 if (!hostapd_monitor_) {
160 hostapd_monitor_.reset(
161 new HostapdMonitor(base::Bind(&Service::HostapdEventCallback,
Peter Qiucbbefa22015-10-27 12:05:34 -0700162 weak_factory_.GetWeakPtr()),
Peter Qiufda548c2015-01-13 14:39:19 -0800163 config_->control_interface(),
164 config_->selected_interface()));
165 }
166 hostapd_monitor_->Start();
167
Peter Qiue2657852015-02-03 11:33:11 -0800168 // Update service state.
Peter Qiu2ea547f2015-11-20 14:18:11 -0800169 adaptor_->SetState(kStateStarting);
Peter Qiue2657852015-02-03 11:33:11 -0800170
Peter Qiu376e4042014-11-13 09:40:28 -0800171 return true;
172}
173
Peter Qiu2ea547f2015-11-20 14:18:11 -0800174void Service::Start(const base::Callback<void(const Error&)>& result_callback) {
175 Error error;
Peter Qiu682a9322015-10-27 09:41:52 -0700176
Peter Qiucbbefa22015-10-27 12:05:34 -0700177#if !defined(__BRILLO__)
Peter Qiu2ea547f2015-11-20 14:18:11 -0800178 StartInternal(&error);
179 result_callback.Run(error);
Peter Qiucbbefa22015-10-27 12:05:34 -0700180#else
181 if (start_in_progress_) {
Peter Qiu2ea547f2015-11-20 14:18:11 -0800182 Error::PopulateAndLog(
183 &error, Error::kInternalError, "Start already in progress", FROM_HERE);
184 result_callback.Run(error);
Peter Qiucbbefa22015-10-27 12:05:34 -0700185 return;
186 }
187
188 string interface_name;
189 if (!manager_->SetupApModeInterface(&interface_name)) {
Peter Qiu2ea547f2015-11-20 14:18:11 -0800190 Error::PopulateAndLog(&error,
191 Error::kInternalError,
192 "Failed to setup AP mode interface",
193 FROM_HERE);
194 result_callback.Run(error);
Peter Qiucbbefa22015-10-27 12:05:34 -0700195 return;
196 }
197
198 event_dispatcher_->PostDelayedTask(
199 base::Bind(&Service::APInterfaceCheckTask,
200 weak_factory_.GetWeakPtr(),
201 interface_name,
202 0, // Initial check count.
Peter Qiu2ea547f2015-11-20 14:18:11 -0800203 result_callback),
Peter Qiucbbefa22015-10-27 12:05:34 -0700204 kAPInterfaceCheckIntervalMilliseconds);
205#endif
Peter Qiu682a9322015-10-27 09:41:52 -0700206}
207
Peter Qiu2ea547f2015-11-20 14:18:11 -0800208bool Service::Stop(Error* error) {
Peter Qiu376e4042014-11-13 09:40:28 -0800209 if (!IsHostapdRunning()) {
Peter Qiu2ea547f2015-11-20 14:18:11 -0800210 Error::PopulateAndLog(error,
211 Error::kInternalError,
212 "Service is not currently running", FROM_HERE);
Peter Qiu376e4042014-11-13 09:40:28 -0800213 return false;
214 }
215
Peter Qiubf8e36c2014-12-03 22:59:45 -0800216 ReleaseResources();
Peter Qiu2ea547f2015-11-20 14:18:11 -0800217 adaptor_->SetState(kStateIdle);
Peter Qiu376e4042014-11-13 09:40:28 -0800218 return true;
219}
220
Peter Qiucbbefa22015-10-27 12:05:34 -0700221#if defined(__BRILLO__)
222void Service::HandleStartFailure() {
223 // Restore station mode interface.
224 string station_mode_interface;
225 manager_->SetupStationModeInterface(&station_mode_interface);
226
227 // Reset state variables.
228 start_in_progress_ = false;
229}
230
231void Service::APInterfaceCheckTask(
232 const string& interface_name,
233 int check_count,
Peter Qiu2ea547f2015-11-20 14:18:11 -0800234 const base::Callback<void(const Error&)>& result_callback) {
235 Error error;
Peter Qiucbbefa22015-10-27 12:05:34 -0700236
237 // Check if the AP interface is enumerated.
238 if (manager_->GetDeviceFromInterfaceName(interface_name)) {
239 // Explicitly set the interface name to avoid picking other interface.
240 config_->SetInterfaceName(interface_name);
241 if (!StartInternal(&error)) {
242 HandleStartFailure();
Peter Qiucbbefa22015-10-27 12:05:34 -0700243 }
Peter Qiu2ea547f2015-11-20 14:18:11 -0800244 result_callback.Run(error);
Peter Qiucbbefa22015-10-27 12:05:34 -0700245 return;
246 }
247
248 check_count++;
249 if (check_count >= kAPInterfaceCheckMaxAttempts) {
Peter Qiu2ea547f2015-11-20 14:18:11 -0800250 Error::PopulateAndLog(&error,
251 Error::kInternalError,
252 "Timeout waiting for AP interface to be enumerated",
253 FROM_HERE);
Peter Qiucbbefa22015-10-27 12:05:34 -0700254 HandleStartFailure();
Peter Qiu2ea547f2015-11-20 14:18:11 -0800255 result_callback.Run(error);
Peter Qiucbbefa22015-10-27 12:05:34 -0700256 return;
257 }
258
259 event_dispatcher_->PostDelayedTask(
260 base::Bind(&Service::APInterfaceCheckTask,
261 weak_factory_.GetWeakPtr(),
262 interface_name,
263 check_count,
Peter Qiu2ea547f2015-11-20 14:18:11 -0800264 result_callback),
Peter Qiucbbefa22015-10-27 12:05:34 -0700265 kAPInterfaceCheckIntervalMilliseconds);
266}
267#endif // __BRILLO__
268
Peter Qiu376e4042014-11-13 09:40:28 -0800269bool Service::IsHostapdRunning() {
270 return hostapd_process_ && hostapd_process_->pid() != 0 &&
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700271 brillo::Process::ProcessExists(hostapd_process_->pid());
Peter Qiu376e4042014-11-13 09:40:28 -0800272}
273
274bool Service::StartHostapdProcess(const string& config_file_path) {
Peter Qiu1dbf9fd2015-01-09 13:36:55 -0800275 hostapd_process_.reset(process_factory_->CreateProcess());
Peter Qiufb39ba42014-11-21 09:09:59 -0800276 hostapd_process_->AddArg(kHostapdPath);
Peter Qiu376e4042014-11-13 09:40:28 -0800277 hostapd_process_->AddArg(config_file_path);
278 if (!hostapd_process_->Start()) {
279 hostapd_process_.reset();
280 return false;
281 }
282 return true;
283}
284
285void Service::StopHostapdProcess() {
286 if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) {
287 hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds);
288 }
289 hostapd_process_.reset();
290}
291
Peter Qiubf8e36c2014-12-03 22:59:45 -0800292void Service::ReleaseResources() {
Peter Qiue2657852015-02-03 11:33:11 -0800293 hostapd_monitor_.reset();
Peter Qiubf8e36c2014-12-03 22:59:45 -0800294 StopHostapdProcess();
295 dhcp_server_.reset();
Peter Qiu943cf3a2015-02-24 10:59:17 -0800296 manager_->ReleaseDHCPPortAccess(config_->selected_interface());
Peter Qiucbbefa22015-10-27 12:05:34 -0700297#if defined(__BRILLO__)
298 // Restore station mode interface.
299 string station_mode_interface;
300 manager_->SetupStationModeInterface(&station_mode_interface);
301#endif // __BRILLO__
Peter Qiu31f70862015-11-16 09:22:34 -0800302 // Only release device after mode switching had completed, to
303 // make sure the station mode interface gets enumerated by
304 // shill.
305 config_->ReleaseDevice();
Peter Qiubf8e36c2014-12-03 22:59:45 -0800306}
307
Peter Qiufda548c2015-01-13 14:39:19 -0800308void Service::HostapdEventCallback(HostapdMonitor::Event event,
309 const std::string& data) {
310 switch (event) {
Peter Qiue2657852015-02-03 11:33:11 -0800311 case HostapdMonitor::kHostapdFailed:
Peter Qiu2ea547f2015-11-20 14:18:11 -0800312 adaptor_->SetState(kStateFailed);
Peter Qiue2657852015-02-03 11:33:11 -0800313 break;
314 case HostapdMonitor::kHostapdStarted:
Peter Qiu2ea547f2015-11-20 14:18:11 -0800315 adaptor_->SetState(kStateStarted);
Peter Qiue2657852015-02-03 11:33:11 -0800316 break;
Peter Qiufda548c2015-01-13 14:39:19 -0800317 case HostapdMonitor::kStationConnected:
318 LOG(INFO) << "Station connected: " << data;
319 break;
320 case HostapdMonitor::kStationDisconnected:
321 LOG(INFO) << "Station disconnected: " << data;
322 break;
323 default:
324 LOG(ERROR) << "Unknown event: " << event;
325 break;
326 }
327}
328
Peter Qiu376e4042014-11-13 09:40:28 -0800329} // namespace apmanager