// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdio.h>
#include <memory>
#include <string>
#include <utility>
#include "base/at_exit.h"
#include "base/cancelable_callback.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_pump_type.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/current_thread.h"
#include "base/task/single_thread_task_executor.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/wifi/wifi_service.h"
#if BUILDFLAG(IS_APPLE)
#include "base/apple/scoped_nsautorelease_pool.h"
#endif
namespace wifi {
class WiFiTest {
public:
WiFiTest() {}
~WiFiTest() {}
enum Result {
RESULT_ERROR = -2,
RESULT_WRONG_USAGE = -1,
RESULT_OK = 0,
RESULT_PENDING = 1,
};
Result Main(int argc, const char* argv[]);
private:
bool ParseCommandLine(int argc, const char* argv[]);
void Start() {}
void Finish(Result result) {
DCHECK_NE(RESULT_PENDING, result);
result_ = result;
if (base::CurrentThread::Get())
loop_.QuitWhenIdle();
}
void OnNetworksChanged(
const WiFiService::NetworkGuidList& network_guid_list) {
VLOG(0) << "Networks Changed: " << network_guid_list[0];
base::Value::Dict properties;
std::string error;
wifi_service_->GetProperties(network_guid_list[0], &properties, &error);
VLOG(0) << error << ":\n" << properties;
}
void OnNetworkListChanged(
const WiFiService::NetworkGuidList& network_guid_list) {
VLOG(0) << "Network List Changed: " << network_guid_list.size();
}
std::unique_ptr<WiFiService> wifi_service_;
// Need AtExitManager to support AsWeakPtr (in NetLog).
base::AtExitManager exit_manager_;
Result result_;
base::RunLoop loop_;
};
WiFiTest::Result WiFiTest::Main(int argc, const char* argv[]) {
if (!ParseCommandLine(argc, argv)) {
VLOG(0) << "Usage: " << argv[0]
<< " [--list]"
" [--get_connected_ssid]"
" [--get_key]"
" [--get_properties]"
" [--create]"
" [--connect]"
" [--disconnect]"
" [--scan]"
" [--network_guid=<network_guid>]"
" [--frequency=0|2400|5000]"
" [--security=none|WEP-PSK|WPA-PSK|WPA2-PSK]"
" [--password=<wifi_password>]"
" [<network_guid>]\n";
return RESULT_WRONG_USAGE;
}
result_ = RESULT_PENDING;
return result_;
}
bool WiFiTest::ParseCommandLine(int argc, const char* argv[]) {
base::CommandLine::Init(argc, argv);
const base::CommandLine& parsed_command_line =
*base::CommandLine::ForCurrentProcess();
std::string network_guid =
parsed_command_line.GetSwitchValueASCII("network_guid");
std::string frequency =
parsed_command_line.GetSwitchValueASCII("frequency");
std::string password =
parsed_command_line.GetSwitchValueASCII("password");
std::string security =
parsed_command_line.GetSwitchValueASCII("security");
if (parsed_command_line.GetArgs().size() == 1) {
#if BUILDFLAG(IS_WIN)
network_guid = base::WideToASCII(parsed_command_line.GetArgs()[0]);
#else
network_guid = parsed_command_line.GetArgs()[0];
#endif
}
#if BUILDFLAG(IS_WIN)
if (parsed_command_line.HasSwitch("debug"))
MessageBoxA(nullptr, __FUNCTION__, "Debug Me!", MB_OK);
#endif
base::SingleThreadTaskExecutor executor(base::MessagePumpType::IO);
wifi_service_.reset(WiFiService::Create());
wifi_service_->Initialize(executor.task_runner());
if (parsed_command_line.HasSwitch("list")) {
base::Value::List network_list;
wifi_service_->GetVisibleNetworks(std::string(), /*include_details=*/true,
&network_list);
VLOG(0) << network_list;
return true;
}
if (parsed_command_line.HasSwitch("get_properties")) {
if (network_guid.length() > 0) {
base::Value::Dict properties;
std::string error;
wifi_service_->GetProperties(network_guid, &properties, &error);
VLOG(0) << error << ":\n" << properties;
return true;
}
}
// Optional properties (frequency, password) to use for connect or create.
base::Value::Dict properties;
if (!frequency.empty()) {
int value = 0;
if (base::StringToInt(frequency, &value)) {
properties.Set("WiFi.Frequency", value);
// fall through to connect.
}
}
if (!password.empty())
properties.Set("WiFi.Passphrase", password);
if (!security.empty())
properties.Set("WiFi.Security", security);
if (parsed_command_line.HasSwitch("create")) {
if (!network_guid.empty()) {
std::string error;
std::string new_network_guid;
properties.Set("WiFi.SSID", network_guid);
VLOG(0) << "Creating Network: " << properties;
wifi_service_->CreateNetwork(false, std::move(properties),
&new_network_guid, &error);
VLOG(0) << error << ":\n" << new_network_guid;
return true;
}
}
if (parsed_command_line.HasSwitch("connect")) {
if (!network_guid.empty()) {
std::string error;
if (!properties.empty()) {
VLOG(0) << "Using connect properties: " << properties;
wifi_service_->SetProperties(network_guid, std::move(properties),
&error);
}
wifi_service_->SetEventObservers(
executor.task_runner(),
base::BindRepeating(&WiFiTest::OnNetworksChanged,
base::Unretained(this)),
base::BindRepeating(&WiFiTest::OnNetworkListChanged,
base::Unretained(this)));
wifi_service_->StartConnect(network_guid, &error);
VLOG(0) << error;
if (error.empty())
loop_.Run();
return true;
}
}
if (parsed_command_line.HasSwitch("disconnect")) {
if (network_guid.length() > 0) {
std::string error;
wifi_service_->StartDisconnect(network_guid, &error);
VLOG(0) << error;
return true;
}
}
if (parsed_command_line.HasSwitch("get_key")) {
if (network_guid.length() > 0) {
std::string error;
std::string key_data;
wifi_service_->GetKeyFromSystem(network_guid, &key_data, &error);
VLOG(0) << key_data << error;
return true;
}
}
if (parsed_command_line.HasSwitch("scan")) {
wifi_service_->SetEventObservers(
executor.task_runner(),
base::BindRepeating(&WiFiTest::OnNetworksChanged,
base::Unretained(this)),
base::BindRepeating(&WiFiTest::OnNetworkListChanged,
base::Unretained(this)));
wifi_service_->RequestNetworkScan();
loop_.Run();
return true;
}
if (parsed_command_line.HasSwitch("get_connected_ssid")) {
std::string ssid;
std::string error;
wifi_service_->GetConnectedNetworkSSID(&ssid, &error);
if (error.length() > 0)
VLOG(0) << error;
else
VLOG(0) << "Network SSID: " << ssid;
return true;
}
return false;
}
} // namespace wifi
int main(int argc, const char* argv[]) {
base::CommandLine::Init(argc, argv);
logging::LoggingSettings settings;
settings.logging_dest =
logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
logging::InitLogging(settings);
#if BUILDFLAG(IS_APPLE)
// Without this there will be a memory leak on the Mac.
base::apple::ScopedNSAutoreleasePool pool;
#endif
wifi::WiFiTest wifi_test;
return wifi_test.Main(argc, argv);
}