• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
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 //
16 
17 #include "apmanager/service.h"
18 
19 #include <signal.h>
20 
21 #include <base/bind.h>
22 #include <base/strings/stringprintf.h>
23 #include <brillo/errors/error.h>
24 
25 #if !defined(__ANDROID__)
26 #include <chromeos/dbus/service_constants.h>
27 #else
28 #include <dbus/apmanager/dbus-constants.h>
29 #endif  // __ANDROID__
30 
31 #if defined(__BRILLO__)
32 #include "apmanager/event_dispatcher.h"
33 #endif  // __BRILLO__
34 
35 #include "apmanager/control_interface.h"
36 #include "apmanager/manager.h"
37 
38 using std::string;
39 
40 namespace apmanager {
41 
42 // static.
43 #if !defined(__ANDROID__)
44 const char Service::kHostapdPath[] = "/usr/sbin/hostapd";
45 const char Service::kHostapdConfigPathFormat[] =
46     "/var/run/apmanager/hostapd/hostapd-%d.conf";
47 const char Service::kHostapdControlInterfacePath[] =
48     "/var/run/apmanager/hostapd/ctrl_iface";
49 #else
50 const char Service::kHostapdPath[] = "/system/bin/hostapd";
51 const char Service::kHostapdConfigPathFormat[] =
52     "/data/misc/apmanager/hostapd/hostapd-%d.conf";
53 const char Service::kHostapdControlInterfacePath[] =
54     "/data/misc/apmanager/hostapd/ctrl_iface";
55 #endif  // __ANDROID__
56 
57 #if defined(__BRILLO__)
58 const int Service::kAPInterfaceCheckIntervalMilliseconds = 200;
59 const int Service::kAPInterfaceCheckMaxAttempts = 5;
60 #endif  // __BRILLO__
61 
62 const int Service::kTerminationTimeoutSeconds = 2;
63 
64 // static. Service state definitions.
65 const char Service::kStateIdle[] = "Idle";
66 const char Service::kStateStarting[] = "Starting";
67 const char Service::kStateStarted[] = "Started";
68 const char Service::kStateFailed[] = "Failed";
69 
Service(Manager * manager,int service_identifier)70 Service::Service(Manager* manager, int service_identifier)
71     : manager_(manager),
72       identifier_(service_identifier),
73       config_(new Config(manager, service_identifier)),
74       adaptor_(manager->control_interface()->CreateServiceAdaptor(this)),
75       dhcp_server_factory_(DHCPServerFactory::GetInstance()),
76       file_writer_(FileWriter::GetInstance()),
77       process_factory_(ProcessFactory::GetInstance()) {
78   adaptor_->SetConfig(config_.get());
79   adaptor_->SetState(kStateIdle);
80   // TODO(zqiu): come up with better server address management. This is good
81   // enough for now.
82   config_->SetServerAddressIndex(identifier_ & 0xFF);
83 
84 #if defined(__BRILLO__)
85   event_dispatcher_ = EventDispatcher::GetInstance();
86   start_in_progress_ = false;
87 #endif
88 }
89 
~Service()90 Service::~Service() {
91   // Stop hostapd process if still running.
92   if (IsHostapdRunning()) {
93     ReleaseResources();
94   }
95 }
96 
StartInternal(Error * error)97 bool Service::StartInternal(Error* error) {
98   if (IsHostapdRunning()) {
99     Error::PopulateAndLog(
100         error, Error::kInternalError, "Service already running", FROM_HERE);
101     return false;
102   }
103 
104   // Setup hostapd control interface path.
105   config_->set_control_interface(kHostapdControlInterfacePath);
106 
107   // Generate hostapd configuration content.
108   string config_str;
109   if (!config_->GenerateConfigFile(error, &config_str)) {
110     return false;
111   }
112 
113   // Write configuration to a file.
114   string config_file_name = base::StringPrintf(kHostapdConfigPathFormat,
115                                                identifier_);
116   if (!file_writer_->Write(config_file_name, config_str)) {
117     Error::PopulateAndLog(error,
118                           Error::kInternalError,
119                           "Failed to write configuration to a file",
120                           FROM_HERE);
121     return false;
122   }
123 
124   // Claim the device needed for this ap service.
125   if (!config_->ClaimDevice()) {
126     Error::PopulateAndLog(error,
127                           Error::kInternalError,
128                           "Failed to claim the device for this service",
129                           FROM_HERE);
130     return false;
131   }
132 
133   // Start hostapd process.
134   if (!StartHostapdProcess(config_file_name)) {
135     Error::PopulateAndLog(
136         error, Error::kInternalError, "Failed to start hostapd", FROM_HERE);
137     // Release the device claimed for this service.
138     config_->ReleaseDevice();
139     return false;
140   }
141 
142   // 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()) {
148       Error::PopulateAndLog(error,
149                             Error::kInternalError,
150                             "Failed to start DHCP server",
151                             FROM_HERE);
152       ReleaseResources();
153       return false;
154     }
155     manager_->RequestDHCPPortAccess(config_->selected_interface());
156   }
157 
158   // Start monitoring hostapd.
159   if (!hostapd_monitor_) {
160     hostapd_monitor_.reset(
161         new HostapdMonitor(base::Bind(&Service::HostapdEventCallback,
162                                       weak_factory_.GetWeakPtr()),
163                            config_->control_interface(),
164                            config_->selected_interface()));
165   }
166   hostapd_monitor_->Start();
167 
168   // Update service state.
169   adaptor_->SetState(kStateStarting);
170 
171   return true;
172 }
173 
Start(const base::Callback<void (const Error &)> & result_callback)174 void Service::Start(const base::Callback<void(const Error&)>& result_callback) {
175   Error error;
176 
177 #if !defined(__BRILLO__)
178   StartInternal(&error);
179   result_callback.Run(error);
180 #else
181   if (start_in_progress_) {
182     Error::PopulateAndLog(
183         &error, Error::kInternalError, "Start already in progress", FROM_HERE);
184     result_callback.Run(error);
185     return;
186   }
187 
188   string interface_name;
189   if (!manager_->SetupApModeInterface(&interface_name)) {
190     Error::PopulateAndLog(&error,
191                           Error::kInternalError,
192                           "Failed to setup AP mode interface",
193                           FROM_HERE);
194     result_callback.Run(error);
195     return;
196   }
197 
198   event_dispatcher_->PostDelayedTask(
199       base::Bind(&Service::APInterfaceCheckTask,
200                  weak_factory_.GetWeakPtr(),
201                  interface_name,
202                  0,    // Initial check count.
203                  result_callback),
204       kAPInterfaceCheckIntervalMilliseconds);
205 #endif
206 }
207 
Stop(Error * error)208 bool Service::Stop(Error* error) {
209   if (!IsHostapdRunning()) {
210     Error::PopulateAndLog(error,
211                           Error::kInternalError,
212                           "Service is not currently running", FROM_HERE);
213     return false;
214   }
215 
216   ReleaseResources();
217   adaptor_->SetState(kStateIdle);
218   return true;
219 }
220 
221 #if defined(__BRILLO__)
HandleStartFailure()222 void 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 
APInterfaceCheckTask(const string & interface_name,int check_count,const base::Callback<void (const Error &)> & result_callback)231 void Service::APInterfaceCheckTask(
232     const string& interface_name,
233     int check_count,
234     const base::Callback<void(const Error&)>& result_callback) {
235   Error error;
236 
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();
243     }
244     result_callback.Run(error);
245     return;
246   }
247 
248   check_count++;
249   if (check_count >= kAPInterfaceCheckMaxAttempts) {
250     Error::PopulateAndLog(&error,
251                           Error::kInternalError,
252                           "Timeout waiting for AP interface to be enumerated",
253                           FROM_HERE);
254     HandleStartFailure();
255     result_callback.Run(error);
256     return;
257   }
258 
259   event_dispatcher_->PostDelayedTask(
260       base::Bind(&Service::APInterfaceCheckTask,
261                  weak_factory_.GetWeakPtr(),
262                  interface_name,
263                  check_count,
264                  result_callback),
265       kAPInterfaceCheckIntervalMilliseconds);
266 }
267 #endif  // __BRILLO__
268 
IsHostapdRunning()269 bool Service::IsHostapdRunning() {
270   return hostapd_process_ && hostapd_process_->pid() != 0 &&
271          brillo::Process::ProcessExists(hostapd_process_->pid());
272 }
273 
StartHostapdProcess(const string & config_file_path)274 bool Service::StartHostapdProcess(const string& config_file_path) {
275   hostapd_process_.reset(process_factory_->CreateProcess());
276   hostapd_process_->AddArg(kHostapdPath);
277   hostapd_process_->AddArg(config_file_path);
278   if (!hostapd_process_->Start()) {
279     hostapd_process_.reset();
280     return false;
281   }
282   return true;
283 }
284 
StopHostapdProcess()285 void Service::StopHostapdProcess() {
286   if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) {
287     hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds);
288   }
289   hostapd_process_.reset();
290 }
291 
ReleaseResources()292 void Service::ReleaseResources() {
293   hostapd_monitor_.reset();
294   StopHostapdProcess();
295   dhcp_server_.reset();
296   manager_->ReleaseDHCPPortAccess(config_->selected_interface());
297 #if defined(__BRILLO__)
298   // Restore station mode interface.
299   string station_mode_interface;
300   manager_->SetupStationModeInterface(&station_mode_interface);
301 #endif  // __BRILLO__
302   // Only release device after mode switching had completed, to
303   // make sure the station mode interface gets enumerated by
304   // shill.
305   config_->ReleaseDevice();
306 }
307 
HostapdEventCallback(HostapdMonitor::Event event,const std::string & data)308 void Service::HostapdEventCallback(HostapdMonitor::Event event,
309                                    const std::string& data) {
310   switch (event) {
311     case HostapdMonitor::kHostapdFailed:
312       adaptor_->SetState(kStateFailed);
313       break;
314     case HostapdMonitor::kHostapdStarted:
315       adaptor_->SetState(kStateStarted);
316       break;
317     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 
329 }  // namespace apmanager
330