Home | History | Annotate | Download | only in apmanager
      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 
     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 
     90 Service::~Service() {
     91   // Stop hostapd process if still running.
     92   if (IsHostapdRunning()) {
     93     ReleaseResources();
     94   }
     95 }
     96 
     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 
    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 
    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__)
    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 
    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 
    269 bool Service::IsHostapdRunning() {
    270   return hostapd_process_ && hostapd_process_->pid() != 0 &&
    271          brillo::Process::ProcessExists(hostapd_process_->pid());
    272 }
    273 
    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 
    285 void Service::StopHostapdProcess() {
    286   if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) {
    287     hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds);
    288   }
    289   hostapd_process_.reset();
    290 }
    291 
    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 
    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