chromium/chromeos/ash/services/secure_channel/secure_channel_impl.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 CHROMEOS_ASH_SERVICES_SECURE_CHANNEL_SECURE_CHANNEL_IMPL_H_
#define CHROMEOS_ASH_SERVICES_SECURE_CHANNEL_SECURE_CHANNEL_IMPL_H_

#include <memory>
#include <string>
#include <tuple>
#include <vector>

#include "base/containers/flat_map.h"
#include "chromeos/ash/services/secure_channel/active_connection_manager.h"
#include "chromeos/ash/services/secure_channel/connection_attempt_details.h"
#include "chromeos/ash/services/secure_channel/pending_connection_manager.h"
#include "chromeos/ash/services/secure_channel/public/cpp/shared/connection_priority.h"
#include "chromeos/ash/services/secure_channel/public/mojom/secure_channel.mojom.h"

namespace ash::timer_factory {
class TimerFactory;
}  // namespace ash::timer_factory

namespace device {
class BluetoothAdapter;
}

namespace ash {

namespace multidevice {
class RemoteDeviceCache;
}

namespace secure_channel {

class BleConnectionManager;
class BleScanner;
class BleSynchronizerBase;
class BluetoothHelper;
class NearbyConnectionManager;
class SecureChannelDisconnector;
class TimerFactory;

// Concrete SecureChannelImpl implementation, which contains three pieces:
// (1) PendingConnectionManager: Attempts to create connections to remote
//     devices.
// (2) ActiveConnectionManager: Maintains connections to remote devices, sharing
//     a single connection with multiple clients when appropriate.
// (3) RemoteDeviceCache: Caches devices within this service.
class SecureChannelImpl : public mojom::SecureChannel,
                          public ActiveConnectionManager::Delegate,
                          public PendingConnectionManager::Delegate {
 public:
  class Factory {
   public:
    static std::unique_ptr<mojom::SecureChannel> Create(
        scoped_refptr<device::BluetoothAdapter> bluetooth_adapter);
    static void SetFactoryForTesting(Factory* test_factory);

   protected:
    virtual ~Factory();
    virtual std::unique_ptr<mojom::SecureChannel> CreateInstance(
        scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) = 0;

   private:
    static Factory* test_factory_;
  };

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

  ~SecureChannelImpl() override;

 private:
  explicit SecureChannelImpl(
      scoped_refptr<device::BluetoothAdapter> bluetooth_adapter);

  enum class InvalidRemoteDeviceReason {
    kInvalidPublicKey,
    kInvalidPsk,
    kInvalidBluetoothAddress
  };

  enum class ApiFunctionName { kListenForConnection, kInitiateConnection };
  friend std::ostream& operator<<(std::ostream& stream,
                                  const ApiFunctionName& role);

  // Contains metadata related to connection requests that were attempted while
  // an ongoing connection to the same remote device was in the process of
  // disconnecting. When this situation occurs, we must wait for the existing
  // connection to disconnect fully, then initiate a new connection attempt to
  // that device.
  struct ConnectionRequestWaitingForDisconnection {
    ConnectionRequestWaitingForDisconnection(
        std::unique_ptr<ClientConnectionParameters>
            client_connection_parameters,
        ConnectionAttemptDetails connection_attempt_details,
        ConnectionPriority connection_priority);
    ConnectionRequestWaitingForDisconnection(
        ConnectionRequestWaitingForDisconnection&& other) noexcept;
    ConnectionRequestWaitingForDisconnection& operator=(
        ConnectionRequestWaitingForDisconnection&& other) noexcept;
    ~ConnectionRequestWaitingForDisconnection();

    std::unique_ptr<ClientConnectionParameters> client_connection_parameters;
    ConnectionAttemptDetails connection_attempt_details;
    ConnectionPriority connection_priority;
  };

  // mojom::SecureChannel:
  void ListenForConnectionFromDevice(
      const multidevice::RemoteDevice& device_to_connect,
      const multidevice::RemoteDevice& local_device,
      const std::string& feature,
      ConnectionMedium connection_medium,
      ConnectionPriority connection_priority,
      mojo::PendingRemote<mojom::ConnectionDelegate> delegate) override;
  void InitiateConnectionToDevice(
      const multidevice::RemoteDevice& device_to_connect,
      const multidevice::RemoteDevice& local_device,
      const std::string& feature,
      ConnectionMedium connection_medium,
      ConnectionPriority connection_priority,
      mojo::PendingRemote<mojom::ConnectionDelegate> delegate,
      mojo::PendingRemote<mojom::SecureChannelStructuredMetricsLogger>
          secure_channel_structured_metrics_logger) override;
  void SetNearbyConnector(
      mojo::PendingRemote<mojom::NearbyConnector> nearby_connector) override;
  void GetLastSeenTimestamp(const std::string& remote_device_id,
                            GetLastSeenTimestampCallback callback) override;

  // ActiveConnectionManager::Delegate:
  void OnDisconnected(const ConnectionDetails& connection_details) override;

  // PendingConnectionManager::Delegate:
  void OnConnection(
      std::unique_ptr<AuthenticatedChannel> authenticated_channel,
      std::vector<std::unique_ptr<ClientConnectionParameters>> clients,
      const ConnectionDetails& connection_details) override;

  void ProcessConnectionRequest(
      ApiFunctionName api_fn_name,
      const multidevice::RemoteDevice& device_to_connect,
      const multidevice::RemoteDevice& local_device,
      std::unique_ptr<ClientConnectionParameters> client_connection_parameters,
      ConnectionRole connection_role,
      ConnectionPriority connection_priority,
      ConnectionMedium connection_medium);
  void RejectRequestForReason(
      ApiFunctionName api_fn_name,
      mojom::ConnectionAttemptFailureReason reason,
      ClientConnectionParameters* client_connection_parameters);

  // Checks if |client_connection_parameters| is invalid. Returns whether
  // Returns whether the request was rejected.
  bool CheckForInvalidRequest(
      ApiFunctionName api_fn_name,
      ClientConnectionParameters* client_connection_parameters) const;

  // Checks if |device| is invalid, and rejects the connection request if so.
  // Returns whether the request was rejected.
  bool CheckForInvalidInputDevice(
      ApiFunctionName api_fn_name,
      const multidevice::RemoteDevice& device,
      ClientConnectionParameters* client_connection_parameters,
      ConnectionMedium connection_medium,
      bool is_local_device);

  // Checks for whether |connection_role| is valid for a connection via the
  // Nearby Connections library.
  bool CheckForInvalidNearbyRequest(
      ApiFunctionName api_fn_name,
      ClientConnectionParameters* client_connection_parameters,
      ConnectionRole connection_role);

  // Checks if |bluetooth_adapter_| is disabled or not present and rejects the
  // connection request if so. Returns whether the request was rejected.
  bool CheckIfBluetoothAdapterDisabledOrNotPresent(
      ApiFunctionName api_fn_name,
      ClientConnectionParameters* client_connection_parameters);

  // Validates |device| and adds it to the |remote_device_cache_| if it is
  // valid. If it is not valid, the reason is provided as a return type, and the
  // device is not added to the cache.
  std::optional<InvalidRemoteDeviceReason> AddDeviceToCacheIfPossible(
      ApiFunctionName api_fn_name,
      const multidevice::RemoteDevice& device,
      ConnectionMedium connection_medium);

  scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
  std::unique_ptr<ash::timer_factory::TimerFactory> timer_factory_;
  std::unique_ptr<multidevice::RemoteDeviceCache> remote_device_cache_;
  std::unique_ptr<BluetoothHelper> bluetooth_helper_;
  std::unique_ptr<BleSynchronizerBase> ble_synchronizer_;
  std::unique_ptr<BleScanner> ble_scanner_;
  std::unique_ptr<SecureChannelDisconnector> secure_channel_disconnector_;
  std::unique_ptr<BleConnectionManager> ble_connection_manager_;
  std::unique_ptr<NearbyConnectionManager> nearby_connection_manager_;
  std::unique_ptr<PendingConnectionManager> pending_connection_manager_;
  std::unique_ptr<ActiveConnectionManager> active_connection_manager_;

  base::flat_map<ConnectionDetails,
                 std::vector<ConnectionRequestWaitingForDisconnection>>
      disconnecting_details_to_requests_map_;
};

std::ostream& operator<<(std::ostream& stream,
                         const SecureChannelImpl::ApiFunctionName& role);

}  // namespace secure_channel
}  // namespace ash

#endif  // CHROMEOS_ASH_SERVICES_SECURE_CHANNEL_SECURE_CHANNEL_IMPL_H_