chromium/chrome/browser/nearby_sharing/tcp_socket/nearby_connections_tcp_socket_factory.h

// Copyright 2021 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_NEARBY_SHARING_TCP_SOCKET_NEARBY_CONNECTIONS_TCP_SOCKET_FACTORY_H_
#define CHROME_BROWSER_NEARBY_SHARING_TCP_SOCKET_NEARBY_CONNECTIONS_TCP_SOCKET_FACTORY_H_

#include <optional>

#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h"
#include "chromeos/ash/services/nearby/public/mojom/tcp_socket_factory.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/address_list.h"
#include "net/base/ip_endpoint.h"
#include "services/network/public/cpp/network_context_getter.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/tcp_socket.mojom.h"

namespace ash {
namespace nearby {
class TcpServerSocketPort;
}  // namespace nearby
}  // namespace ash

namespace net {
class AddressList;
struct MutableNetworkTrafficAnnotationTag;
class IPAddress;
}  // namespace net

// An implementation of the mojo service used to create TCP sockets for the
// Nearby Connections WifiLan medium. We guarantee that callbacks will not be
// invoked after this class is destroyed.
class NearbyConnectionsTcpSocketFactory
    : public sharing::mojom::TcpSocketFactory {
 public:

  // A class used to run NetworkContext::CreateTCPConnectedSocket with a
  // user-defined |timeout|. There is timeout logic in the networking stack, but
  // it is not configurable and can be too long in practice (over 2 minutes).
  // The networking stack timeout can still be triggered if |timeout| is too
  // long.
  class ConnectTask {
   public:
    ConnectTask(
        network::mojom::NetworkContext* network_context,
        const std::optional<net::IPEndPoint>& local_addr,
        const net::AddressList& remote_addr_list,
        network::mojom::TCPConnectedSocketOptionsPtr
            tcp_connected_socket_options,
        const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
        mojo::PendingReceiver<network::mojom::TCPConnectedSocket> receiver,
        mojo::PendingRemote<network::mojom::SocketObserver> observer,
        CreateTCPConnectedSocketCallback callback);
    ~ConnectTask();

    // Can only be called once.
    void Run(base::TimeDelta timeout);

   private:
    void OnFinished(int32_t result,
                    const std::optional<net::IPEndPoint>& local_addr,
                    const std::optional<net::IPEndPoint>& peer_addr,
                    mojo::ScopedDataPipeConsumerHandle receive_stream,
                    mojo::ScopedDataPipeProducerHandle send_stream);
    void OnTimeout();

    CreateTCPConnectedSocketCallback callback_;
    base::OnceClosure task_;
    base::OneShotTimer timer_;
    base::TimeTicks start_time_;
    SEQUENCE_CHECKER(sequence_checker_);
    base::WeakPtrFactory<ConnectTask> weak_ptr_factory_{this};
  };

  explicit NearbyConnectionsTcpSocketFactory(
      network::NetworkContextGetter network_context_getter);
  NearbyConnectionsTcpSocketFactory(const NearbyConnectionsTcpSocketFactory&) =
      delete;
  NearbyConnectionsTcpSocketFactory& operator=(
      const NearbyConnectionsTcpSocketFactory&) = delete;
  ~NearbyConnectionsTcpSocketFactory() override;

  // sharing::mojom:TcpSocketFactory:
  void CreateTCPServerSocket(
      const net::IPAddress& local_addr,
      const ash::nearby::TcpServerSocketPort& port,
      uint32_t backlog,
      const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
      mojo::PendingReceiver<network::mojom::TCPServerSocket> receiver,
      CreateTCPServerSocketCallback callback) override;
  void CreateTCPConnectedSocket(
      base::TimeDelta timeout,
      const std::optional<net::IPEndPoint>& local_addr,
      const net::AddressList& remote_addr_list,
      network::mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options,
      const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
      mojo::PendingReceiver<network::mojom::TCPConnectedSocket> receiver,
      mojo::PendingRemote<network::mojom::SocketObserver> observer,
      CreateTCPConnectedSocketCallback callback) override;

 private:
  // Wrapper callbacks that are bound with weak pointers. Used to guarantee that
  // input callbacks are not invoked after this class is destroyed.
  void OnTcpServerSocketCreated(
      CreateTCPServerSocketCallback callback,
      int32_t result,
      const std::optional<net::IPEndPoint>& local_addr);
  void OnTcpConnectedSocketCreated(
      base::UnguessableToken task_id,
      CreateTCPConnectedSocketCallback callback,
      int32_t result,
      const std::optional<net::IPEndPoint>& local_addr,
      const std::optional<net::IPEndPoint>& peer_addr,
      mojo::ScopedDataPipeConsumerHandle receive_stream,
      mojo::ScopedDataPipeProducerHandle send_stream);

  network::NetworkContextGetter network_context_getter_;
  base::flat_map<base::UnguessableToken, std::unique_ptr<ConnectTask>>
      connect_tasks_;
  base::WeakPtrFactory<NearbyConnectionsTcpSocketFactory> weak_ptr_factory_{
      this};
};

#endif  // CHROME_BROWSER_NEARBY_SHARING_TCP_SOCKET_NEARBY_CONNECTIONS_TCP_SOCKET_FACTORY_H_