blob: 99073fb649c479e32e152edd44c3b36ed9b4cae9 [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;
Peter Qiu682a9322015-10-27 09:41:52 -070033using brillo::dbus_utils::DBusMethodResponse;
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -070034using brillo::dbus_utils::ExportedObjectManager;
Vitaly Bukaa4630922014-12-11 18:46:46 -080035using org::chromium::apmanager::ManagerAdaptor;
Peter Qiu376e4042014-11-13 09:40:28 -080036using std::string;
37
38namespace apmanager {
39
40// static.
Peter Qiufc980572015-09-24 10:11:26 -070041#if !defined(__ANDROID__)
Peter Qiufb39ba42014-11-21 09:09:59 -080042const char Service::kHostapdPath[] = "/usr/sbin/hostapd";
Peter Qiu77517302015-01-08 16:22:16 -080043const char Service::kHostapdConfigPathFormat[] =
44 "/var/run/apmanager/hostapd/hostapd-%d.conf";
Peter Qiu1dbf9fd2015-01-09 13:36:55 -080045const char Service::kHostapdControlInterfacePath[] =
46 "/var/run/apmanager/hostapd/ctrl_iface";
Peter Qiufc980572015-09-24 10:11:26 -070047#else
48const char Service::kHostapdPath[] = "/system/bin/hostapd";
49const char Service::kHostapdConfigPathFormat[] =
50 "/data/misc/apmanager/hostapd/hostapd-%d.conf";
51const char Service::kHostapdControlInterfacePath[] =
52 "/data/misc/apmanager/hostapd/ctrl_iface";
53#endif // __ANDROID__
54
Peter Qiu376e4042014-11-13 09:40:28 -080055const int Service::kTerminationTimeoutSeconds = 2;
56
Peter Qiue2657852015-02-03 11:33:11 -080057// static. Service state definitions.
58const char Service::kStateIdle[] = "Idle";
59const char Service::kStateStarting[] = "Starting";
60const char Service::kStateStarted[] = "Started";
61const char Service::kStateFailed[] = "Failed";
62
Peter Qiufb39ba42014-11-21 09:09:59 -080063Service::Service(Manager* manager, int service_identifier)
Peter Qiu376e4042014-11-13 09:40:28 -080064 : org::chromium::apmanager::ServiceAdaptor(this),
Peter Qiufb39ba42014-11-21 09:09:59 -080065 manager_(manager),
Peter Qiufd02b6f2015-02-27 09:55:11 -080066 identifier_(service_identifier),
Vitaly Bukaa4630922014-12-11 18:46:46 -080067 service_path_(
68 base::StringPrintf("%s/services/%d",
69 ManagerAdaptor::GetObjectPath().value().c_str(),
70 service_identifier)),
Peter Qiu376e4042014-11-13 09:40:28 -080071 dbus_path_(dbus::ObjectPath(service_path_)),
Peter Qiubf8e36c2014-12-03 22:59:45 -080072 config_(new Config(manager, service_path_)),
Peter Qiu77517302015-01-08 16:22:16 -080073 dhcp_server_factory_(DHCPServerFactory::GetInstance()),
Peter Qiu1dbf9fd2015-01-09 13:36:55 -080074 file_writer_(FileWriter::GetInstance()),
75 process_factory_(ProcessFactory::GetInstance()) {
Peter Qiu376e4042014-11-13 09:40:28 -080076 SetConfig(config_->dbus_path());
Peter Qiue2657852015-02-03 11:33:11 -080077 SetState(kStateIdle);
Peter Qiubf8e36c2014-12-03 22:59:45 -080078 // TODO(zqiu): come up with better server address management. This is good
79 // enough for now.
Peter Qiufd02b6f2015-02-27 09:55:11 -080080 config_->SetServerAddressIndex(identifier_ & 0xFF);
Peter Qiu376e4042014-11-13 09:40:28 -080081}
82
83Service::~Service() {
84 // Stop hostapd process if still running.
85 if (IsHostapdRunning()) {
Peter Qiubf8e36c2014-12-03 22:59:45 -080086 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -080087 }
88}
89
90void Service::RegisterAsync(ExportedObjectManager* object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -080091 const scoped_refptr<dbus::Bus>& bus,
Peter Qiu376e4042014-11-13 09:40:28 -080092 AsyncEventSequencer* sequencer) {
93 CHECK(!dbus_object_) << "Already registered";
94 dbus_object_.reset(
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -070095 new brillo::dbus_utils::DBusObject(
Peter Qiu376e4042014-11-13 09:40:28 -080096 object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -080097 bus,
Peter Qiu376e4042014-11-13 09:40:28 -080098 dbus_path_));
99 RegisterWithDBusObject(dbus_object_.get());
100 dbus_object_->RegisterAsync(
101 sequencer->GetHandler("Service.RegisterAsync() failed.", true));
102
103 // Register Config DBus object.
Peter Qiuc9ce1f12014-12-05 11:14:29 -0800104 config_->RegisterAsync(object_manager, bus, sequencer);
Peter Qiu376e4042014-11-13 09:40:28 -0800105}
106
Peter Qiu682a9322015-10-27 09:41:52 -0700107bool Service::StartInternal(brillo::ErrorPtr* error) {
Peter Qiu376e4042014-11-13 09:40:28 -0800108 if (IsHostapdRunning()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700109 brillo::Error::AddTo(
110 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800111 "Service already running");
112 return false;
113 }
114
Peter Qiubfd410e2015-01-09 15:14:20 -0800115 // Setup hostapd control interface path.
116 config_->set_control_interface(kHostapdControlInterfacePath);
117
Peter Qiu376e4042014-11-13 09:40:28 -0800118 // Generate hostapd configuration content.
119 string config_str;
120 if (!config_->GenerateConfigFile(error, &config_str)) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700121 brillo::Error::AddTo(
122 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800123 "Failed to generate config file");
124 return false;
125 }
126
127 // Write configuration to a file.
Peter Qiu77517302015-01-08 16:22:16 -0800128 string config_file_name = base::StringPrintf(kHostapdConfigPathFormat,
Peter Qiufd02b6f2015-02-27 09:55:11 -0800129 identifier_);
Peter Qiu77517302015-01-08 16:22:16 -0800130 if (!file_writer_->Write(config_file_name, config_str)) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700131 brillo::Error::AddTo(
132 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800133 "Failed to write configuration to a file");
134 return false;
135 }
136
Peter Qiufb39ba42014-11-21 09:09:59 -0800137 // Claim the device needed for this ap service.
138 if (!config_->ClaimDevice()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700139 brillo::Error::AddTo(
140 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiufb39ba42014-11-21 09:09:59 -0800141 "Failed to claim the device for this service");
142 return false;
143 }
144
Peter Qiu376e4042014-11-13 09:40:28 -0800145 // Start hostapd process.
Peter Qiu77517302015-01-08 16:22:16 -0800146 if (!StartHostapdProcess(config_file_name)) {
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 start hostapd");
Peter Qiufb39ba42014-11-21 09:09:59 -0800150 // Release the device claimed for this service.
151 config_->ReleaseDevice();
Peter Qiu376e4042014-11-13 09:40:28 -0800152 return false;
153 }
154
Peter Qiubf8e36c2014-12-03 22:59:45 -0800155 // Start DHCP server if in server mode.
156 if (config_->GetOperationMode() == kOperationModeServer) {
157 dhcp_server_.reset(
158 dhcp_server_factory_->CreateDHCPServer(config_->GetServerAddressIndex(),
159 config_->selected_interface()));
160 if (!dhcp_server_->Start()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700161 brillo::Error::AddTo(
162 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiubf8e36c2014-12-03 22:59:45 -0800163 "Failed to start DHCP server");
164 ReleaseResources();
165 return false;
166 }
Peter Qiu943cf3a2015-02-24 10:59:17 -0800167 manager_->RequestDHCPPortAccess(config_->selected_interface());
Peter Qiubf8e36c2014-12-03 22:59:45 -0800168 }
169
Peter Qiufda548c2015-01-13 14:39:19 -0800170 // Start monitoring hostapd.
171 if (!hostapd_monitor_) {
172 hostapd_monitor_.reset(
173 new HostapdMonitor(base::Bind(&Service::HostapdEventCallback,
174 base::Unretained(this)),
175 config_->control_interface(),
176 config_->selected_interface()));
177 }
178 hostapd_monitor_->Start();
179
Peter Qiue2657852015-02-03 11:33:11 -0800180 // Update service state.
181 SetState(kStateStarting);
182
Peter Qiu376e4042014-11-13 09:40:28 -0800183 return true;
184}
185
Peter Qiu682a9322015-10-27 09:41:52 -0700186void Service::Start(std::unique_ptr<DBusMethodResponse<>> response) {
187 brillo::ErrorPtr error;
188
189 if (!StartInternal(&error)) {
190 response->ReplyWithError(error.get());
191 } else {
192 response->Return();
193 }
194}
195
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700196bool Service::Stop(brillo::ErrorPtr* error) {
Peter Qiu376e4042014-11-13 09:40:28 -0800197 if (!IsHostapdRunning()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700198 brillo::Error::AddTo(
199 error, FROM_HERE, brillo::errors::dbus::kDomain, kServiceError,
Peter Qiu376e4042014-11-13 09:40:28 -0800200 "Service is not currently running");
201 return false;
202 }
203
Peter Qiubf8e36c2014-12-03 22:59:45 -0800204 ReleaseResources();
Peter Qiue2657852015-02-03 11:33:11 -0800205 SetState(kStateIdle);
Peter Qiu376e4042014-11-13 09:40:28 -0800206 return true;
207}
208
209bool Service::IsHostapdRunning() {
210 return hostapd_process_ && hostapd_process_->pid() != 0 &&
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700211 brillo::Process::ProcessExists(hostapd_process_->pid());
Peter Qiu376e4042014-11-13 09:40:28 -0800212}
213
214bool Service::StartHostapdProcess(const string& config_file_path) {
Peter Qiu1dbf9fd2015-01-09 13:36:55 -0800215 hostapd_process_.reset(process_factory_->CreateProcess());
Peter Qiufb39ba42014-11-21 09:09:59 -0800216 hostapd_process_->AddArg(kHostapdPath);
Peter Qiu376e4042014-11-13 09:40:28 -0800217 hostapd_process_->AddArg(config_file_path);
218 if (!hostapd_process_->Start()) {
219 hostapd_process_.reset();
220 return false;
221 }
222 return true;
223}
224
225void Service::StopHostapdProcess() {
226 if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) {
227 hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds);
228 }
229 hostapd_process_.reset();
230}
231
Peter Qiubf8e36c2014-12-03 22:59:45 -0800232void Service::ReleaseResources() {
Peter Qiue2657852015-02-03 11:33:11 -0800233 hostapd_monitor_.reset();
Peter Qiubf8e36c2014-12-03 22:59:45 -0800234 StopHostapdProcess();
235 dhcp_server_.reset();
236 config_->ReleaseDevice();
Peter Qiu943cf3a2015-02-24 10:59:17 -0800237 manager_->ReleaseDHCPPortAccess(config_->selected_interface());
Peter Qiubf8e36c2014-12-03 22:59:45 -0800238}
239
Peter Qiufda548c2015-01-13 14:39:19 -0800240void Service::HostapdEventCallback(HostapdMonitor::Event event,
241 const std::string& data) {
242 switch (event) {
Peter Qiue2657852015-02-03 11:33:11 -0800243 case HostapdMonitor::kHostapdFailed:
244 SetState(kStateFailed);
245 break;
246 case HostapdMonitor::kHostapdStarted:
247 SetState(kStateStarted);
248 break;
Peter Qiufda548c2015-01-13 14:39:19 -0800249 case HostapdMonitor::kStationConnected:
250 LOG(INFO) << "Station connected: " << data;
251 break;
252 case HostapdMonitor::kStationDisconnected:
253 LOG(INFO) << "Station disconnected: " << data;
254 break;
255 default:
256 LOG(ERROR) << "Unknown event: " << event;
257 break;
258 }
259}
260
Peter Qiu376e4042014-11-13 09:40:28 -0800261} // namespace apmanager