blob: b1edc3c4e8b45acbb50bf4d00d6473372c35dbf4 [file] [log] [blame]
//
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include <sysexits.h>
#include <map>
#include <memory>
#include <string>
#include <base/command_line.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <brillo/any.h>
#include <brillo/daemons/dbus_daemon.h>
#include <chromeos/dbus/service_constants.h>
#include <shill/dbus-proxies.h>
namespace {
namespace switches {
static const char kHelp[] = "help";
static const char kPassphrase[] = "passphrase";
static const char kHexSsid[] = "hex-ssid";
static const char kSSID[] = "ssid";
static const char kTimeOut[] = "wait-for-online-seconds";
static const char kHelpMessage[] = "\n"
"Available Switches: \n"
" --ssid=<ssid>\n"
" Set the SSID to configure (mandatory).\n"
" --hex-ssid\n"
" SSID is provided in hexadecimal\n"
" --passphrase=<passprhase>\n"
" Set the passphrase for PSK networks\n"
" --wait-for-online-seconds=<seconds>\n"
" Number of seconds to wait to connect the SSID\n";
} // namespace switches
static const char kOnlineState[] = "online";
static const int kTimeoutBetweenStateChecksMs = 100;
} // namespace
class MyClient : public brillo::DBusDaemon {
public:
MyClient(std::string ssid, bool is_hex_ssid, std::string psk, int timeout)
: ssid_(ssid), is_hex_ssid_(is_hex_ssid), psk_(psk), timeout_(timeout) {}
~MyClient() override = default;
protected:
int OnInit() override {
int ret = DBusDaemon::OnInit();
if (ret != EX_OK) {
return ret;
}
ConfigureAndConnect();
// Timeout if we can't get online.
brillo::MessageLoop::current()->PostDelayedTask(
base::Bind(&MyClient::Quit, base::Unretained(this)),
base::TimeDelta::FromSeconds(timeout_));
return EX_OK;
}
bool ConfigureAndConnect() {
auto shill_manager_proxy =
std::make_unique<org::chromium::flimflam::ManagerProxy>(bus_);
dbus::ObjectPath created_service;
brillo::ErrorPtr configure_error;
if (!shill_manager_proxy->ConfigureService(
GetServiceConfig(), &created_service, &configure_error)) {
LOG(ERROR) << "Configure service failed";
return false;
}
brillo::ErrorPtr connect_error;
shill_service_proxy_ =
std::make_unique<org::chromium::flimflam::ServiceProxy>(
bus_, created_service);
if (!shill_service_proxy_->Connect(&connect_error)) {
LOG(ERROR) << "Connect service failed";
return false;
}
PostCheckWifiStatusTask();
return true;
}
void PostCheckWifiStatusTask() {
LOG(INFO) << "Sleeping now. Will check wifi status in 100 ms.";
brillo::MessageLoop::current()->PostDelayedTask(
base::Bind(&MyClient::QuitIfOnline, base::Unretained(this)),
base::TimeDelta::FromMilliseconds(kTimeoutBetweenStateChecksMs));
}
// Check if the device is online. If it is, quit.
void QuitIfOnline() {
if (IsOnline())
Quit();
else
PostCheckWifiStatusTask();
}
bool IsOnline() {
brillo::VariantDictionary properties;
if (!shill_service_proxy_->GetProperties(&properties, nullptr)) {
LOG(ERROR) << "Cannot get properties.";
PostCheckWifiStatusTask();
return false;
}
auto property_it = properties.find(shill::kStateProperty);
if (property_it == properties.end()) {
PostCheckWifiStatusTask();
return false;
}
std::string state = property_it->second.TryGet<std::string>();
return state == kOnlineState;
}
std::map<std::string, brillo::Any> GetServiceConfig() {
std::map<std::string, brillo::Any> configure_dict;
configure_dict[shill::kTypeProperty] = shill::kTypeWifi;
if (is_hex_ssid_) {
configure_dict[shill::kWifiHexSsid] = ssid_;
} else {
configure_dict[shill::kSSIDProperty] = ssid_;
}
if (!psk_.empty()) {
configure_dict[shill::kPassphraseProperty] = psk_;
configure_dict[shill::kSecurityProperty] = shill::kSecurityPsk;
}
return configure_dict;
}
std::unique_ptr<org::chromium::flimflam::ServiceProxy> shill_service_proxy_;
std::string ssid_;
bool is_hex_ssid_;
std::string psk_;
int timeout_;
};
int main(int argc, char** argv) {
base::CommandLine::Init(argc, argv);
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
if (cl->HasSwitch(switches::kHelp)) {
LOG(INFO) << switches::kHelpMessage;
return EXIT_SUCCESS;
}
if (!cl->HasSwitch(switches::kSSID)) {
LOG(ERROR) << "ssid switch is mandatory.";
LOG(ERROR) << switches::kHelpMessage;
return EXIT_FAILURE;
}
std::string ssid = cl->GetSwitchValueASCII(switches::kSSID);
std::string psk;
if (cl->HasSwitch(switches::kPassphrase)) {
psk = cl->GetSwitchValueASCII(switches::kPassphrase);
}
bool hex_ssid = cl->HasSwitch(switches::kHexSsid);
int timeout = 0;
if (cl->HasSwitch(switches::kTimeOut)) {
auto value = cl->GetSwitchValueASCII(switches::kTimeOut);
if (!base::StringToInt(value, &timeout)) {
LOG(ERROR) << "Timeout value invalid";
return EXIT_FAILURE;
}
}
MyClient client(ssid, hex_ssid, psk, timeout);
client.Run();
LOG(INFO) << "Process exiting.";
return EXIT_SUCCESS;
}