blob: 0623e6e88ecc10e30bdb1fb0474ffaa80dbb07b3 [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 Qiufb39ba42014-11-21 09:09:59 -080035 config_(new Config(manager, service_path_)) {
Peter Qiu376e4042014-11-13 09:40:28 -080036 SetConfig(config_->dbus_path());
37}
38
39Service::~Service() {
40 // Stop hostapd process if still running.
41 if (IsHostapdRunning()) {
42 StopHostapdProcess();
Peter Qiufb39ba42014-11-21 09:09:59 -080043 // Release device used by this hostapd instance.
44 config_->ReleaseDevice();
Peter Qiu376e4042014-11-13 09:40:28 -080045 }
46}
47
48void Service::RegisterAsync(ExportedObjectManager* object_manager,
49 AsyncEventSequencer* sequencer) {
50 CHECK(!dbus_object_) << "Already registered";
51 dbus_object_.reset(
52 new chromeos::dbus_utils::DBusObject(
53 object_manager,
54 object_manager ? object_manager->GetBus() : nullptr,
55 dbus_path_));
56 RegisterWithDBusObject(dbus_object_.get());
57 dbus_object_->RegisterAsync(
58 sequencer->GetHandler("Service.RegisterAsync() failed.", true));
59
60 // Register Config DBus object.
61 config_->RegisterAsync(object_manager, sequencer);
62}
63
64bool Service::Start(chromeos::ErrorPtr* error) {
65 if (IsHostapdRunning()) {
66 chromeos::Error::AddTo(
67 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
68 "Service already running");
69 return false;
70 }
71
72 // Generate hostapd configuration content.
73 string config_str;
74 if (!config_->GenerateConfigFile(error, &config_str)) {
75 chromeos::Error::AddTo(
76 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
77 "Failed to generate config file");
78 return false;
79 }
80
81 // Write configuration to a file.
82 base::FilePath file_path(base::StringPrintf(kHostapdConfigPathFormat,
83 service_identifier_));
84 if (base::WriteFile(file_path, config_str.c_str(), config_str.size()) == -1) {
85 chromeos::Error::AddTo(
86 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
87 "Failed to write configuration to a file");
88 return false;
89 }
90
Peter Qiufb39ba42014-11-21 09:09:59 -080091 // Claim the device needed for this ap service.
92 if (!config_->ClaimDevice()) {
93 chromeos::Error::AddTo(
94 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
95 "Failed to claim the device for this service");
96 return false;
97 }
98
Peter Qiu376e4042014-11-13 09:40:28 -080099 // Start hostapd process.
100 if (!StartHostapdProcess(file_path.value())) {
101 chromeos::Error::AddTo(
102 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
103 "Failed to start hostapd");
Peter Qiufb39ba42014-11-21 09:09:59 -0800104 // Release the device claimed for this service.
105 config_->ReleaseDevice();
Peter Qiu376e4042014-11-13 09:40:28 -0800106 return false;
107 }
108
109 return true;
110}
111
112bool Service::Stop(chromeos::ErrorPtr* error) {
113 if (!IsHostapdRunning()) {
114 chromeos::Error::AddTo(
115 error, FROM_HERE, chromeos::errors::dbus::kDomain, kServiceError,
116 "Service is not currently running");
117 return false;
118 }
119
120 StopHostapdProcess();
Peter Qiufb39ba42014-11-21 09:09:59 -0800121 // Release the device used by this hostapd instance.
122 config_->ReleaseDevice();
Peter Qiu376e4042014-11-13 09:40:28 -0800123 return true;
124}
125
126bool Service::IsHostapdRunning() {
127 return hostapd_process_ && hostapd_process_->pid() != 0 &&
128 chromeos::Process::ProcessExists(hostapd_process_->pid());
129}
130
131bool Service::StartHostapdProcess(const string& config_file_path) {
132 hostapd_process_.reset(new chromeos::ProcessImpl());
Peter Qiufb39ba42014-11-21 09:09:59 -0800133 hostapd_process_->AddArg(kHostapdPath);
Peter Qiu376e4042014-11-13 09:40:28 -0800134 hostapd_process_->AddArg(config_file_path);
135 if (!hostapd_process_->Start()) {
136 hostapd_process_.reset();
137 return false;
138 }
139 return true;
140}
141
142void Service::StopHostapdProcess() {
143 if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) {
144 hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds);
145 }
146 hostapd_process_.reset();
147}
148
149} // namespace apmanager