chromium/chrome/services/sharing/nearby/platform/wifi_direct_medium.h

// Copyright 2024 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_SERVICES_SHARING_NEARBY_PLATFORM_WIFI_DIRECT_MEDIUM_H_
#define CHROME_SERVICES_SHARING_NEARBY_PLATFORM_WIFI_DIRECT_MEDIUM_H_

#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "chromeos/ash/services/nearby/public/mojom/firewall_hole.mojom.h"
#include "chromeos/ash/services/wifi_direct/public/mojom/wifi_direct_manager.mojom.h"
#include "mojo/public/cpp/bindings/shared_remote.h"
#include "net/socket/socket_descriptor.h"
#include "net/socket/tcp_client_socket.h"
#include "net/socket/tcp_server_socket.h"
#include "third_party/nearby/src/internal/platform/implementation/wifi_direct.h"
#include "third_party/nearby/src/internal/platform/wifi_credential.h"

namespace nearby::chrome {

// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class WifiDirectServiceError {
  kNoConnection = 0,
  kFailedToCreatePlatformSocket = 1,
  kFailedToAssociateSocket = 2,
  kCancelled = 3,
  kFailedToConnectSocket = 4,
  kFailedToOpenFirewallHole = 5,
  kFailedToListenToSocket = 6,
  kMaxValue = kFailedToListenToSocket,
};

class WifiDirectMedium : public api::WifiDirectMedium {
 public:
  explicit WifiDirectMedium(
      const mojo::SharedRemote<ash::wifi_direct::mojom::WifiDirectManager>&
          manager,
      const mojo::SharedRemote<::sharing::mojom::FirewallHoleFactory>&
          firewall_hole_factory);
  ~WifiDirectMedium() override;

  // api::WifiDirectMedium
  bool IsInterfaceValid() const override;
  bool StartWifiDirect(WifiDirectCredentials* credentials) override;
  bool StopWifiDirect() override;
  bool ConnectWifiDirect(WifiDirectCredentials* credentials) override;
  bool DisconnectWifiDirect() override;
  std::unique_ptr<api::WifiDirectSocket> ConnectToService(
      std::string_view ip_address,
      int port,
      CancellationFlag* cancellation_flag) override;
  std::unique_ptr<api::WifiDirectServerSocket> ListenForService(
      int port) override;
  std::optional<std::pair<std::int32_t, std::int32_t>> GetDynamicPortRange()
      override;

 private:
  void GetCapabilities(bool* is_capability_supported,
                       base::WaitableEvent* waitable_event) const;
  void OnCapabilities(
      bool* is_capability_supported,
      base::WaitableEvent* waitable_event,
      ash::wifi_direct::mojom::WifiP2PCapabilitiesPtr capabilities) const;

  void CreateGroup(WifiDirectCredentials* credentials,
                   base::WaitableEvent* waitable_event);
  void OnGroupCreated(
      WifiDirectCredentials* credentials,
      base::WaitableEvent* waitable_event,
      ash::wifi_direct::mojom::WifiDirectOperationResult result,
      mojo::PendingRemote<ash::wifi_direct::mojom::WifiDirectConnection>
          connection);
  void OnProperties(
      WifiDirectCredentials* credentials,
      base::WaitableEvent* waitable_event,
      ash::wifi_direct::mojom::WifiDirectConnectionPropertiesPtr properties);

  void ConnectGroup(WifiDirectCredentials* credentials,
                    base::WaitableEvent* waitable_event);
  void OnGroupConnected(
      base::WaitableEvent* waitable_event,
      ash::wifi_direct::mojom::WifiDirectOperationResult result,
      mojo::PendingRemote<ash::wifi_direct::mojom::WifiDirectConnection>
          connection);

  void AssociateSocket(bool* did_associate,
                       base::WaitableEvent* waitable_event,
                       mojo::PlatformHandle socket_descriptor);
  void OnSocketAssociated(bool* did_associate,
                          base::WaitableEvent* waitable_event,
                          bool success);
  void CreateAndListenToSocket(int16_t port,
                               net::SocketDescriptor socket_descriptor,
                               std::unique_ptr<net::TCPServerSocket>* socket,
                               base::WaitableEvent* waitable_event);
  void CreateAndConnectSocket(const std::string_view& ip_address,
                              int port,
                              int fd,
                              std::unique_ptr<net::TCPClientSocket>* socket,
                              base::WaitableEvent* waitable_event);
  void OnSocketConnected(std::unique_ptr<net::TCPClientSocket>* socket,
                         base::WaitableEvent* waitable_event,
                         std::unique_ptr<net::TCPSocket> tcp_socket,
                         net::IPEndPoint ip_endpoint,
                         int result);

  void OpenFirewallHole(
      ash::nearby::TcpServerSocketPort port,
      mojo::PendingRemote<::sharing::mojom::FirewallHole>* output,
      base::WaitableEvent* waitable_event);
  void OnFirewallHoleCreated(
      mojo::PendingRemote<::sharing::mojom::FirewallHole>* output,
      base::WaitableEvent* waitable_event,
      mojo::PendingRemote<::sharing::mojom::FirewallHole> firewall_hole);

  void OnDisconnect();

  std::unique_ptr<base::Thread> io_thread_;
  mojo::SharedRemote<ash::wifi_direct::mojom::WifiDirectManager>
      wifi_direct_manager_;
  mojo::SharedRemote<::sharing::mojom::FirewallHoleFactory>
      firewall_hole_factory_;
  mojo::SharedRemote<ash::wifi_direct::mojom::WifiDirectConnection> connection_;
  std::string ipv4_address_;
};

}  // namespace nearby::chrome

#endif  // CHROME_SERVICES_SHARING_NEARBY_PLATFORM_WIFI_DIRECT_MEDIUM_H_