blob: e7a44228fba7e0fbe2fd72dde6aa95feef09f674 [file] [log] [blame]
Peter Qiu376e4042014-11-13 09:40:28 -08001// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "apmanager/service.h"
6
7#include <signal.h>
8
Peter Qiu376e4042014-11-13 09:40:28 -08009#include <base/strings/stringprintf.h>
10#include <chromeos/dbus/service_constants.h>
11#include <chromeos/errors/error.h>
12
Peter Qiufb39ba42014-11-21 09:09:59 -080013#include "apmanager/manager.h"
Peter Qiu376e4042014-11-13 09:40:28 -080014
15using chromeos::dbus_utils::AsyncEventSequencer;
16using chromeos::dbus_utils::ExportedObjectManager;
Vitaly Bukaa4630922014-12-11 18:46:46 -080017using org::chromium::apmanager::ManagerAdaptor;
Peter Qiu376e4042014-11-13 09:40:28 -080018using std::string;
19
20namespace apmanager {
21
22// static.
Peter Qiufb39ba42014-11-21 09:09:59 -080023const char Service::kHostapdPath[] = "/usr/sbin/hostapd";
Peter Qiu77517302015-01-08 16:22:16 -080024const char Service::kHostapdConfigPathFormat[] =
25 "/var/run/apmanager/hostapd/hostapd-%d.conf";
Peter Qiu1dbf9fd2015-01-09 13:36:55 -080026const char Service::kHostapdControlInterfacePath[] =
27 "/var/run/apmanager/hostapd/ctrl_iface";
Peter Qiu376e4042014-11-13 09:40:28 -080028const int Service::kTerminationTimeoutSeconds = 2;
29
Peter Qiufb39ba42014-11-21 09:09:59 -080030Service::Service(Manager* manager, int service_identifier)
Peter Qiu376e4042014-11-13 09:40:28 -080031 : org::chromium::apmanager::ServiceAdaptor(this),
Peter Qiufb39ba42014-11-21 09:09:59 -080032 manager_(manager),
Peter Qiu376e4042014-11-13 09:40:28 -080033 service_identifier_(service_identifier),
Vitaly Bukaa4630922014-12-11 18:46:46 -080034 service_path_(
35 base::StringPrintf("%s/services/%d",
36 ManagerAdaptor::GetObjectPath().value().c_str(),
37 service_identifier)),
Peter Qiu376e4042014-11-13 09:40:28 -080038 dbus_path_(dbus::ObjectPath(service_path_)),
Peter Qiubf8e36c2014-12-03 22:59:45 -080039 config_(new Config(manager, service_path_)),
Peter Qiu77517302015-01-08 16:22:16 -080040 dhcp_server_factory_(DHCPServerFactory::GetInstance()),
Peter Qiu1dbf9fd2015-01-09 13:36:55 -080041 file_writer_(FileWriter::GetInstance()),
42 process_factory_(ProcessFactory::GetInstance()) {
Peter Qiu376e4042014-11-13 09:40:28 -080043 SetConfig(config_->dbus_path());
Peter Qiubf8e36c2014-12-03 22:59:45 -080044 // TODO(zqiu): come up with better server address management. This is good
45 // enough for now.
46 config_->SetServerAddressIndex(service_identifier_ & 0xFF);
Peter Qiu376e4042014-11-13 09:40:28 -080047}
48
49Service::~Service() {
50 // Stop hostapd process if still running.
51 if (IsHostapdRunning()) {
Peter Qiubf8e36c2014-12-03 22:59:45 -080052 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -080053 }
54}
55
56void Service::RegisterAsync(ExportedObjectManager* object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -080057 const scoped_refptr<dbus::Bus>& bus,
Peter Qiu376e4042014-11-13 09:40:28 -080058 AsyncEventSequencer* sequencer) {
59 CHECK(!dbus_object_) << "Already registered";
60 dbus_object_.reset(
61 new chromeos::dbus_utils::DBusObject(
62 object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -080063 bus,
Peter Qiu376e4042014-11-13 09:40:28 -080064 dbus_path_));
65 RegisterWithDBusObject(dbus_object_.get());
66 dbus_object_->RegisterAsync(
67 sequencer->GetHandler("Service.RegisterAsync() failed.", true));
68
69 // Register Config DBus object.
Peter Qiuc9ce1f12014-12-05 11:14:29 -080070 config_->RegisterAsync(object_manager, bus, sequencer);
Peter Qiu376e4042014-11-13 09:40:28 -080071}
72
73bool Service::Start(chromeos::ErrorPtr* error) {
74 if (IsHostapdRunning()) {
75 chromeos::Error::AddTo(
76 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
77 "Service already running");
78 return false;
79 }
80
Peter Qiubfd410e2015-01-09 15:14:20 -080081 // Setup hostapd control interface path.
82 config_->set_control_interface(kHostapdControlInterfacePath);
83
Peter Qiu376e4042014-11-13 09:40:28 -080084 // Generate hostapd configuration content.
85 string config_str;
86 if (!config_->GenerateConfigFile(error, &config_str)) {
87 chromeos::Error::AddTo(
88 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
89 "Failed to generate config file");
90 return false;
91 }
92
93 // Write configuration to a file.
Peter Qiu77517302015-01-08 16:22:16 -080094 string config_file_name = base::StringPrintf(kHostapdConfigPathFormat,
95 service_identifier_);
96 if (!file_writer_->Write(config_file_name, config_str)) {
Peter Qiu376e4042014-11-13 09:40:28 -080097 chromeos::Error::AddTo(
98 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
99 "Failed to write configuration to a file");
100 return false;
101 }
102
Peter Qiufb39ba42014-11-21 09:09:59 -0800103 // Claim the device needed for this ap service.
104 if (!config_->ClaimDevice()) {
105 chromeos::Error::AddTo(
106 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
107 "Failed to claim the device for this service");
108 return false;
109 }
110
Peter Qiu376e4042014-11-13 09:40:28 -0800111 // Start hostapd process.
Peter Qiu77517302015-01-08 16:22:16 -0800112 if (!StartHostapdProcess(config_file_name)) {
Peter Qiu376e4042014-11-13 09:40:28 -0800113 chromeos::Error::AddTo(
114 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
115 "Failed to start hostapd");
Peter Qiufb39ba42014-11-21 09:09:59 -0800116 // Release the device claimed for this service.
117 config_->ReleaseDevice();
Peter Qiu376e4042014-11-13 09:40:28 -0800118 return false;
119 }
120
Peter Qiubf8e36c2014-12-03 22:59:45 -0800121 // Start DHCP server if in server mode.
122 if (config_->GetOperationMode() == kOperationModeServer) {
123 dhcp_server_.reset(
124 dhcp_server_factory_->CreateDHCPServer(config_->GetServerAddressIndex(),
125 config_->selected_interface()));
126 if (!dhcp_server_->Start()) {
127 chromeos::Error::AddTo(
128 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
129 "Failed to start DHCP server");
130 ReleaseResources();
131 return false;
132 }
133 }
134
Peter Qiubfd410e2015-01-09 15:14:20 -0800135 // TODO(zqiu): Start monitoring hostapd.
Peter Qiu376e4042014-11-13 09:40:28 -0800136 return true;
137}
138
139bool Service::Stop(chromeos::ErrorPtr* error) {
140 if (!IsHostapdRunning()) {
141 chromeos::Error::AddTo(
142 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
143 "Service is not currently running");
144 return false;
145 }
146
Peter Qiubf8e36c2014-12-03 22:59:45 -0800147 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -0800148 return true;
149}
150
151bool Service::IsHostapdRunning() {
152 return hostapd_process_ && hostapd_process_->pid() != 0 &&
153 chromeos::Process::ProcessExists(hostapd_process_->pid());
154}
155
156bool Service::StartHostapdProcess(const string& config_file_path) {
Peter Qiu1dbf9fd2015-01-09 13:36:55 -0800157 hostapd_process_.reset(process_factory_->CreateProcess());
Peter Qiufb39ba42014-11-21 09:09:59 -0800158 hostapd_process_->AddArg(kHostapdPath);
Peter Qiu376e4042014-11-13 09:40:28 -0800159 hostapd_process_->AddArg(config_file_path);
160 if (!hostapd_process_->Start()) {
161 hostapd_process_.reset();
162 return false;
163 }
164 return true;
165}
166
167void Service::StopHostapdProcess() {
168 if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) {
169 hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds);
170 }
171 hostapd_process_.reset();
172}
173
Peter Qiubf8e36c2014-12-03 22:59:45 -0800174void Service::ReleaseResources() {
175 StopHostapdProcess();
176 dhcp_server_.reset();
177 config_->ReleaseDevice();
178}
179
Peter Qiu376e4042014-11-13 09:40:28 -0800180} // namespace apmanager