Commit d784a163 authored by Allen Vicencio's avatar Allen Vicencio Committed by Commit Bot

Implement NetworkScanner and add tests

This CL implements NetworkScanner and adds tests. This allows the use of
multiple HostLocators by registering it with NetworkScanner.

Bug: chromium:757625
Change-Id: I5c607450196f3f1751cab44ff42b94057d142442
Reviewed-on: https://chromium-review.googlesource.com/952369Reviewed-by: default avatarZentaro Kavanagh <zentaro@chromium.org>
Commit-Queue: Allen Vicencio <allenvic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#542657}
parent 9018df6a
...@@ -1542,6 +1542,8 @@ source_set("chromeos") { ...@@ -1542,6 +1542,8 @@ source_set("chromeos") {
"smb_client/discovery/host_locator.h", "smb_client/discovery/host_locator.h",
"smb_client/discovery/in_memory_host_locator.cc", "smb_client/discovery/in_memory_host_locator.cc",
"smb_client/discovery/in_memory_host_locator.h", "smb_client/discovery/in_memory_host_locator.h",
"smb_client/discovery/network_scanner.cc",
"smb_client/discovery/network_scanner.h",
"smb_client/smb_file_system.cc", "smb_client/smb_file_system.cc",
"smb_client/smb_file_system.h", "smb_client/smb_file_system.h",
"smb_client/smb_provider.cc", "smb_client/smb_provider.cc",
...@@ -2038,6 +2040,7 @@ source_set("unit_tests") { ...@@ -2038,6 +2040,7 @@ source_set("unit_tests") {
"settings/shutdown_policy_handler_unittest.cc", "settings/shutdown_policy_handler_unittest.cc",
"settings/stub_cros_settings_provider_unittest.cc", "settings/stub_cros_settings_provider_unittest.cc",
"smb_client/discovery/in_memory_host_locator_unittest.cc", "smb_client/discovery/in_memory_host_locator_unittest.cc",
"smb_client/discovery/network_scanner_unittest.cc",
"smb_client/smb_service_unittest.cc", "smb_client/smb_service_unittest.cc",
"smb_client/temp_file_manager_unittest.cc", "smb_client/temp_file_manager_unittest.cc",
"system/automatic_reboot_manager_unittest.cc", "system/automatic_reboot_manager_unittest.cc",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/smb_client/discovery/network_scanner.h"
#include <map>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "chrome/browser/chromeos/smb_client/discovery/host_locator.h"
namespace chromeos {
namespace smb_client {
namespace {
// Returns true if the host with |host_name| already exists in |host_map|.
bool HostExists(const HostMap& host_map, const Hostname& host_name) {
return host_map.count(host_name);
}
} // namespace
RequestInfo::RequestInfo(uint32_t remaining_requests,
FindHostsCallback callback)
: remaining_requests(remaining_requests), callback(std::move(callback)) {}
RequestInfo::RequestInfo(RequestInfo&& other) = default;
RequestInfo::~RequestInfo() = default;
NetworkScanner::NetworkScanner() = default;
NetworkScanner::~NetworkScanner() = default;
void NetworkScanner::FindHostsInNetwork(FindHostsCallback callback) {
if (locators_.empty()) {
// Fire the callback immediately if there are no registered HostLocators.
std::move(callback).Run(HostMap());
return;
}
const uint32_t request_id = AddNewRequest(std::move(callback));
for (const auto& locator : locators_) {
locator->FindHosts(
base::BindOnce(&NetworkScanner::OnHostsFound, AsWeakPtr(), request_id));
}
}
void NetworkScanner::RegisterHostLocator(std::unique_ptr<HostLocator> locator) {
locators_.push_back(std::move(locator));
}
void NetworkScanner::OnHostsFound(uint32_t request_id,
const HostMap& host_map) {
DCHECK_GT(requests_.count(request_id), 0u);
AddHostsToResults(request_id, host_map);
FireCallbackIfFinished(request_id);
}
void NetworkScanner::AddHostsToResults(uint32_t request_id,
const HostMap& new_hosts) {
auto request_iter = requests_.find(request_id);
DCHECK(request_iter != requests_.end());
HostMap& existing_hosts = request_iter->second.hosts_found;
for (const auto& new_host : new_hosts) {
const Hostname& new_hostname = new_host.first;
const Address& new_ip = new_host.second;
if (!HostExists(existing_hosts, new_hostname)) {
existing_hosts.insert(new_host);
} else if (existing_hosts[new_hostname] != new_ip) {
LOG(WARNING) << "Different addresses found for host: " << new_hostname;
LOG(WARNING) << existing_hosts[new_hostname] << ":" << new_ip;
}
}
}
uint32_t NetworkScanner::AddNewRequest(FindHostsCallback callback) {
const uint32_t request_id = next_request_id_++;
requests_.emplace(request_id,
RequestInfo(locators_.size(), std::move(callback)));
return request_id;
}
void NetworkScanner::FireCallbackIfFinished(uint32_t request_id) {
auto request_iter = requests_.find(request_id);
DCHECK(request_iter != requests_.end());
uint32_t& remaining_requests = request_iter->second.remaining_requests;
DCHECK_GT(remaining_requests, 0u);
if (--remaining_requests == 0) {
RequestInfo info = std::move(request_iter->second);
requests_.erase(request_iter);
std::move(info.callback).Run(info.hosts_found);
}
}
} // namespace smb_client
} // namespace chromeos
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_SMB_CLIENT_DISCOVERY_NETWORK_SCANNER_H_
#define CHROME_BROWSER_CHROMEOS_SMB_CLIENT_DISCOVERY_NETWORK_SCANNER_H_
#include <map>
#include <vector>
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/chromeos/smb_client/discovery/host_locator.h"
namespace chromeos {
namespace smb_client {
// Holds the number of in-flight requests and the callback to call once all the
// HostLocators are finished. Also holds the hosts found from the HostLocators
// that have already returned.
struct RequestInfo {
uint32_t remaining_requests;
FindHostsCallback callback;
HostMap hosts_found;
RequestInfo(uint32_t remaining_requests, FindHostsCallback callback);
RequestInfo(RequestInfo&& other);
~RequestInfo();
DISALLOW_COPY_AND_ASSIGN(RequestInfo);
};
// NetworkScanner discovers SMB hosts in the local network by querying
// registered HostLocators and aggregating their results.
class NetworkScanner : public base::SupportsWeakPtr<NetworkScanner> {
public:
NetworkScanner();
~NetworkScanner();
// Query the registered HostLocators and return all the hosts found.
// |callback| is called once all the HostLocators have responded with their
// results. If there are no locators, the callback is fired immediately with
// an empty result.
void FindHostsInNetwork(FindHostsCallback callback);
// Registeres a |locator| to be queried when FindHostsInNetwork() is called.
void RegisterHostLocator(std::unique_ptr<HostLocator> locator);
private:
// Callback handler for HostLocator::FindHosts().
void OnHostsFound(uint32_t request_id, const HostMap& host_map);
// Adds |host_map| hosts to current results. The host will not be added if the
// hostname already exists in results, and if the IP address does not match,
// it will be logged.
void AddHostsToResults(uint32_t request_id, const HostMap& host_map);
// Adds a new request to track and saves |callback| to be called when the
// request is finished. Returns the request id.
uint32_t AddNewRequest(FindHostsCallback callback);
// Called after a HostLocator returns with results and decrements the count of
// requests in RequestInfo for |request_id|. Fires the callback for if
// there are no more requests and deletes the corresponding RequestInfo.
void FireCallbackIfFinished(uint32_t request_id);
std::vector<std::unique_ptr<HostLocator>> locators_;
// Used for tracking in-flight requests to HostLocators. The key is the
// request id, and the value is the RequestInfo struct.
std::map<uint32_t, RequestInfo> requests_;
uint32_t next_request_id_ = 0;
DISALLOW_COPY_AND_ASSIGN(NetworkScanner);
};
} // namespace smb_client
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_SMB_CLIENT_DISCOVERY_NETWORK_SCANNER_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/smb_client/discovery/network_scanner.h"
#include <map>
#include <string>
#include <utility>
#include "base/bind.h"
#include "chrome/browser/chromeos/smb_client/discovery/in_memory_host_locator.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace smb_client {
namespace {
// Expects |actual_hosts| to equal |expected_hosts|.
void ExpectMapEntriesEqual(const HostMap& expected_hosts,
const HostMap& actual_hosts) {
EXPECT_EQ(expected_hosts, actual_hosts);
}
} // namespace
class NetworkScannerTest : public testing::Test {
public:
NetworkScannerTest() = default;
~NetworkScannerTest() override = default;
protected:
void RegisterHostLocatorWithHosts(const HostMap& hosts) {
std::unique_ptr<InMemoryHostLocator> host_locator =
std::make_unique<InMemoryHostLocator>();
host_locator->AddHosts(hosts);
scanner_.RegisterHostLocator(std::move(host_locator));
}
void ExpectHostMapEqual(const HostMap& expected_hosts) {
scanner_.FindHostsInNetwork(
base::BindOnce(&ExpectMapEntriesEqual, expected_hosts));
}
private:
NetworkScanner scanner_;
DISALLOW_COPY_AND_ASSIGN(NetworkScannerTest);
};
TEST_F(NetworkScannerTest, ShouldFindNoHostsWithNoLocator) {
ExpectHostMapEqual(HostMap());
}
TEST_F(NetworkScannerTest, ShouldFindNoHostsWithOneLocator) {
RegisterHostLocatorWithHosts(HostMap());
ExpectHostMapEqual(HostMap());
}
TEST_F(NetworkScannerTest, ShouldFindNoHostsWithMultipleLocators) {
RegisterHostLocatorWithHosts(HostMap());
RegisterHostLocatorWithHosts(HostMap());
ExpectHostMapEqual(HostMap());
}
TEST_F(NetworkScannerTest, ShouldFindOneHostWithOneLocator) {
HostMap hosts;
hosts["share1"] = "1.2.3.4";
RegisterHostLocatorWithHosts(hosts);
ExpectHostMapEqual(hosts);
}
TEST_F(NetworkScannerTest, ShouldFindMultipleHostsWithOneLocator) {
HostMap hosts;
hosts["share1"] = "1.2.3.4";
hosts["share2"] = "5.6.7.8";
RegisterHostLocatorWithHosts(hosts);
ExpectHostMapEqual(hosts);
}
TEST_F(NetworkScannerTest, ShouldFindMultipleHostsWithMultipleLocators) {
HostMap hosts1;
hosts1["share1"] = "1.2.3.4";
hosts1["share2"] = "5.6.7.8";
RegisterHostLocatorWithHosts(hosts1);
HostMap hosts2;
hosts2["share3"] = "11.12.13.14";
hosts2["share4"] = "15.16.17.18";
RegisterHostLocatorWithHosts(hosts2);
HostMap expected;
expected["share1"] = "1.2.3.4";
expected["share2"] = "5.6.7.8";
expected["share3"] = "11.12.13.14";
expected["share4"] = "15.16.17.18";
ExpectHostMapEqual(expected);
}
TEST_F(NetworkScannerTest, ShouldResolveMultipleHostsWithSameAddress) {
HostMap hosts1;
hosts1["share1"] = "1.2.3.4";
hosts1["share2"] = "5.6.7.8";
RegisterHostLocatorWithHosts(hosts1);
HostMap hosts2;
hosts2["share2"] = "11.12.13.14";
hosts2["share3"] = "15.16.17.18";
RegisterHostLocatorWithHosts(hosts2);
// share2 should have the value from host1 since it is found first.
HostMap expected;
expected["share1"] = "1.2.3.4";
expected["share2"] = "5.6.7.8";
expected["share3"] = "15.16.17.18";
ExpectHostMapEqual(expected);
}
} // namespace smb_client
} // namespace chromeos
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment