chromium/chrome/browser/ash/smb_client/discovery/netbios_host_locator.h

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_ASH_SMB_CLIENT_DISCOVERY_NETBIOS_HOST_LOCATOR_H_
#define CHROME_BROWSER_ASH_SMB_CLIENT_DISCOVERY_NETBIOS_HOST_LOCATOR_H_

#include <list>
#include <string>

#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "chrome/browser/ash/smb_client/discovery/host_locator.h"
#include "chrome/browser/ash/smb_client/discovery/netbios_client_interface.h"
#include "chromeos/ash/components/dbus/smbprovider/smb_provider_client.h"
#include "net/base/network_interfaces.h"

namespace ash::smb_client {

// Calculates the broadcast address of a network interface.
net::IPAddress CalculateBroadcastAddress(
    const net::NetworkInterface& interface);

// Returns true if a network interface should be used for NetBios discovery.
bool ShouldUseInterface(const net::NetworkInterface& interface);

// HostLocator implementation that uses NetBIOS to locate hosts.
class NetBiosHostLocator final : public HostLocator {
 public:
  using GetInterfacesFunction =
      base::RepeatingCallback<net::NetworkInterfaceList()>;
  using NetBiosClientFactory =
      base::RepeatingCallback<std::unique_ptr<NetBiosClientInterface>()>;

  NetBiosHostLocator(GetInterfacesFunction get_interfaces,
                     NetBiosClientFactory client_factory,
                     SmbProviderClient* smb_provider_client);
  NetBiosHostLocator(GetInterfacesFunction get_interfaces,
                     NetBiosClientFactory client_factory,
                     SmbProviderClient* smb_provider_client,
                     std::unique_ptr<base::OneShotTimer> timer);

  NetBiosHostLocator(const NetBiosHostLocator&) = delete;
  NetBiosHostLocator& operator=(const NetBiosHostLocator&) = delete;

  ~NetBiosHostLocator() override;

  // HostLocator override.
  void FindHosts(FindHostsCallback callback) override;

 private:
  // Returns a list of network interfaces on the device.
  net::NetworkInterfaceList GetNetworkInterfaceList();

  // Finds hosts on |interface| by constructing a NetBiosClient, performing a
  // NetBios Name Request for the interface.
  void FindHostsOnInterface(const net::NetworkInterface& interface);

  // Creates a NetBiosClient using the |client_factory_|.
  std::unique_ptr<NetBiosClientInterface> CreateClient() const;

  // Executes a name request transaction for |broadcast_address| using the most
  // recently added NetBiosClient in |netbios_clients_|.
  void ExecuteNameRequest(const net::IPAddress& broadcast_address);

  // Callback handler for packets received by the |netbios_clients_|.
  void PacketReceived(const std::vector<uint8_t>& packet,
                      uint16_t transaction_id,
                      const net::IPEndPoint& sender_ip);

  // Callback handler for a request to parse a packet. Adds
  // <hostname, sender_ip> entries to |results_|.
  void OnPacketParsed(const net::IPEndPoint& sender_ip,
                      const std::vector<std::string>& hostnames);

  // Called upon expiration of |timer_|. Deletes all active netbios clients. If
  // there are no |outstanding_parse_requests_|, FinishFindHosts is called which
  // returns the results to the NetworkScanner.
  void StopDiscovery();

  // Runs |callback_| with |results_|, then calls ResetHostLocator to reset the
  // state.
  void FinishFindHosts();

  // Resets the state of the HostLocator so that it can be resued.
  void ResetHostLocator();

  // Helper function to add a <hostname, sender_ip> pair to |results_|.
  void AddHostToResult(const net::IPEndPoint& sender_ip,
                       const std::string& hostname);

  // Checks whether an entry already exists for |hostname| in |results_| with a
  // different |sender_ip|.
  bool WouldOverwriteResult(const net::IPEndPoint& sender_ip,
                            const std::string& hostname) const;

  bool running_ = false;
  bool discovery_done_ = false;
  uint16_t transaction_id_ = 0;
  int32_t outstanding_parse_requests_ = 0;
  GetInterfacesFunction get_interfaces_;
  NetBiosClientFactory client_factory_;
  raw_ptr<SmbProviderClient> smb_provider_client_;
  FindHostsCallback callback_;
  HostMap results_;
  // |netbios_clients_| is a container for storing NetBios clients that are
  // currently performing a NetBios Name Request so that they do not go out of
  // scope. One NetBiosClient exists for each network interface on the device.
  std::list<std::unique_ptr<NetBiosClientInterface>> netbios_clients_;
  std::unique_ptr<base::OneShotTimer> timer_;
  base::WeakPtrFactory<NetBiosHostLocator> weak_ptr_factory_{this};
};

}  // namespace ash::smb_client

#endif  // CHROME_BROWSER_ASH_SMB_CLIENT_DISCOVERY_NETBIOS_HOST_LOCATOR_H_