blob: a235381857a6245816b17881e7044e635600d6e4 [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
9#include <base/files/file_util.h>
10#include <base/strings/stringprintf.h>
11#include <chromeos/dbus/service_constants.h>
12#include <chromeos/errors/error.h>
13
Peter Qiufb39ba42014-11-21 09:09:59 -080014#include "apmanager/manager.h"
Peter Qiu376e4042014-11-13 09:40:28 -080015
16using chromeos::dbus_utils::AsyncEventSequencer;
17using chromeos::dbus_utils::ExportedObjectManager;
18using std::string;
19
20namespace apmanager {
21
22// static.
Peter Qiufb39ba42014-11-21 09:09:59 -080023const char Service::kHostapdPath[] = "/usr/sbin/hostapd";
Peter Qiu376e4042014-11-13 09:40:28 -080024const char Service::kHostapdConfigPathFormat[] = "/tmp/hostapd-%d";
25const int Service::kTerminationTimeoutSeconds = 2;
26
Peter Qiufb39ba42014-11-21 09:09:59 -080027Service::Service(Manager* manager, int service_identifier)
Peter Qiu376e4042014-11-13 09:40:28 -080028 : org::chromium::apmanager::ServiceAdaptor(this),
Peter Qiufb39ba42014-11-21 09:09:59 -080029 manager_(manager),
Peter Qiu376e4042014-11-13 09:40:28 -080030 service_identifier_(service_identifier),
31 service_path_(base::StringPrintf("%s/services/%d",
32 kManagerPath,
33 service_identifier)),
34 dbus_path_(dbus::ObjectPath(service_path_)),
Peter Qiubf8e36c2014-12-03 22:59:45 -080035 config_(new Config(manager, service_path_)),
36 dhcp_server_factory_(DHCPServerFactory::GetInstance()) {
Peter Qiu376e4042014-11-13 09:40:28 -080037 SetConfig(config_->dbus_path());
Peter Qiubf8e36c2014-12-03 22:59:45 -080038 // TODO(zqiu): come up with better server address management. This is good
39 // enough for now.
40 config_->SetServerAddressIndex(service_identifier_ & 0xFF);
Peter Qiu376e4042014-11-13 09:40:28 -080041}
42
43Service::~Service() {
44 // Stop hostapd process if still running.
45 if (IsHostapdRunning()) {
Peter Qiubf8e36c2014-12-03 22:59:45 -080046 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -080047 }
48}
49
50void Service::RegisterAsync(ExportedObjectManager* object_manager,
51 AsyncEventSequencer* sequencer) {
52 CHECK(!dbus_object_) << "Already registered";
53 dbus_object_.reset(
54 new chromeos::dbus_utils::DBusObject(
55 object_manager,
56 object_manager ? object_manager->GetBus() : nullptr,
57 dbus_path_));
58 RegisterWithDBusObject(dbus_object_.get());
59 dbus_object_->RegisterAsync(
60 sequencer->GetHandler("Service.RegisterAsync() failed.", true));
61
62 // Register Config DBus object.
63 config_->RegisterAsync(object_manager, sequencer);
64}
65
66bool Service::Start(chromeos::ErrorPtr* error) {
67 if (IsHostapdRunning()) {
68 chromeos::Error::AddTo(
69 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
70 "Service already running");
71 return false;
72 }
73
74 // Generate hostapd configuration content.
75 string config_str;
76 if (!config_->GenerateConfigFile(error, &config_str)) {
77 chromeos::Error::AddTo(
78 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
79 "Failed to generate config file");
80 return false;
81 }
82
83 // Write configuration to a file.
84 base::FilePath file_path(base::StringPrintf(kHostapdConfigPathFormat,
85 service_identifier_));
86 if (base::WriteFile(file_path, config_str.c_str(), config_str.size()) == -1) {
87 chromeos::Error::AddTo(
88 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
89 "Failed to write configuration to a file");
90 return false;
91 }
92
Peter Qiufb39ba42014-11-21 09:09:59 -080093 // Claim the device needed for this ap service.
94 if (!config_->ClaimDevice()) {
95 chromeos::Error::AddTo(
96 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
97 "Failed to claim the device for this service");
98 return false;
99 }
100
Peter Qiu376e4042014-11-13 09:40:28 -0800101 // Start hostapd process.
102 if (!StartHostapdProcess(file_path.value())) {
103 chromeos::Error::AddTo(
104 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
105 "Failed to start hostapd");
Peter Qiufb39ba42014-11-21 09:09:59 -0800106 // Release the device claimed for this service.
107 config_->ReleaseDevice();
Peter Qiu376e4042014-11-13 09:40:28 -0800108 return false;
109 }
110
Peter Qiubf8e36c2014-12-03 22:59:45 -0800111 // Start DHCP server if in server mode.
112 if (config_->GetOperationMode() == kOperationModeServer) {
113 dhcp_server_.reset(
114 dhcp_server_factory_->CreateDHCPServer(config_->GetServerAddressIndex(),
115 config_->selected_interface()));
116 if (!dhcp_server_->Start()) {
117 chromeos::Error::AddTo(
118 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
119 "Failed to start DHCP server");
120 ReleaseResources();
121 return false;
122 }
123 }
124
Peter Qiu376e4042014-11-13 09:40:28 -0800125 return true;
126}
127
128bool Service::Stop(chromeos::ErrorPtr* error) {
129 if (!IsHostapdRunning()) {
130 chromeos::Error::AddTo(
131 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
132 "Service is not currently running");
133 return false;
134 }
135
Peter Qiubf8e36c2014-12-03 22:59:45 -0800136 ReleaseResources();
Peter Qiu376e4042014-11-13 09:40:28 -0800137 return true;
138}
139
140bool Service::IsHostapdRunning() {
141 return hostapd_process_ && hostapd_process_->pid() != 0 &&
142 chromeos::Process::ProcessExists(hostapd_process_->pid());
143}
144
145bool Service::StartHostapdProcess(const string& config_file_path) {
146 hostapd_process_.reset(new chromeos::ProcessImpl());
Peter Qiufb39ba42014-11-21 09:09:59 -0800147 hostapd_process_->AddArg(kHostapdPath);
Peter Qiu376e4042014-11-13 09:40:28 -0800148 hostapd_process_->AddArg(config_file_path);
149 if (!hostapd_process_->Start()) {
150 hostapd_process_.reset();
151 return false;
152 }
153 return true;
154}
155
156void Service::StopHostapdProcess() {
157 if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) {
158 hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds);
159 }
160 hostapd_process_.reset();
161}
162
Peter Qiubf8e36c2014-12-03 22:59:45 -0800163void Service::ReleaseResources() {
164 StopHostapdProcess();
165 dhcp_server_.reset();
166 config_->ReleaseDevice();
167}
168
Peter Qiu376e4042014-11-13 09:40:28 -0800169} // namespace apmanager