blob: 9a42b93f54b9d3bbfb372ea94d42d92aba2572b0 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_DIRECT_SOCKETS_FIREWALL_HOLE_DELEGATE_H_
#define CONTENT_BROWSER_DIRECT_SOCKETS_FIREWALL_HOLE_DELEGATE_H_
#include <cstdint>
#include <memory>
#include <optional>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/functional/callback_forward.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "net/base/ip_address.h"
#include "services/network/public/mojom/socket_connection_tracker.mojom.h"
namespace net {
class IPEndPoint;
} // namespace net
namespace chromeos {
class FirewallHole;
} // namespace chromeos
namespace content {
// For multicast capabilities, the same port of a UDP socket may be reused with
// allowAddressSharing = true. A firewall hole is reused for connections on
// the same port.
struct CONTENT_EXPORT FirewallHoleTracker {
FirewallHoleTracker(const FirewallHoleTracker&) = delete;
FirewallHoleTracker& operator=(const FirewallHoleTracker&) = delete;
FirewallHoleTracker(std::unique_ptr<chromeos::FirewallHole> firewall_hole,
size_t usage_count);
~FirewallHoleTracker();
FirewallHoleTracker(FirewallHoleTracker&&);
FirewallHoleTracker& operator=(FirewallHoleTracker&&);
std::unique_ptr<chromeos::FirewallHole> firewall_hole;
size_t usage_count;
};
// This class inherits from SocketConnectionTracker so that all stored firewall
// hole handles reference |this| in the internal ReceiverSet. It must live for
// the whole browser lifecycle because firewall holes can be requested by
// different web apps.
class CONTENT_EXPORT FirewallHoleDelegate
: public network::mojom::SocketConnectionTracker {
public:
using LocalPort = uint16_t;
using OpenSocketCallback =
base::OnceCallback<void(int32_t, const std::optional<net::IPEndPoint>&)>;
static void SetAlwaysOpenFirewallHoleForTesting(bool value);
FirewallHoleDelegate();
~FirewallHoleDelegate() override;
FirewallHoleDelegate(const FirewallHoleDelegate&) = delete;
FirewallHoleDelegate& operator=(const FirewallHoleDelegate&) = delete;
static void OpenTCPFirewallHole(
mojo::PendingReceiver<network::mojom::SocketConnectionTracker>
connection_tracker,
OpenSocketCallback callback,
int32_t result,
const std::optional<net::IPEndPoint>& local_addr);
static void OpenUDPFirewallHole(
mojo::PendingReceiver<network::mojom::SocketConnectionTracker>
connection_tracker,
OpenSocketCallback callback,
int32_t result,
const std::optional<net::IPEndPoint>& local_addr);
private:
static FirewallHoleDelegate* GetInstance();
bool ShouldOpenFirewallHole(const net::IPAddress& address);
void OpenTCPFirewallHoleImpl(
mojo::PendingReceiver<network::mojom::SocketConnectionTracker>
connection_tracker,
OpenSocketCallback callback,
int32_t result,
const std::optional<net::IPEndPoint>& local_addr);
void OpenUDPFirewallHoleImpl(
mojo::PendingReceiver<network::mojom::SocketConnectionTracker>
connection_tracker,
OpenSocketCallback callback,
int32_t result,
const std::optional<net::IPEndPoint>& local_addr);
void OnUDPFirewallHoleOpened(
mojo::PendingReceiver<network::mojom::SocketConnectionTracker>
connection_tracker,
const net::IPEndPoint& local_addr,
std::unique_ptr<chromeos::FirewallHole> firewall_hole);
void OnTCPFirewallHoleOpened(
mojo::PendingReceiver<network::mojom::SocketConnectionTracker>
connection_tracker,
base::OnceClosure on_success,
base::OnceClosure on_failure,
std::unique_ptr<chromeos::FirewallHole> firewall_hole);
void OnUdpConnectionTrackerDisconnected();
mojo::ReceiverSet<network::mojom::SocketConnectionTracker,
std::unique_ptr<chromeos::FirewallHole>>
tcp_receivers_;
// This map tracks UDP socket callbacks so that
// UDP sockets created in parallel can share the same firewall hole.
base::flat_map<LocalPort, std::vector<OpenSocketCallback>>
pending_udp_open_socket_requests_;
mojo::ReceiverSet<network::mojom::SocketConnectionTracker, LocalPort>
udp_receivers_;
base::flat_map<LocalPort, FirewallHoleTracker> udp_firewall_holes_;
bool always_open_firewall_hole_for_testing = false;
};
} // namespace content
#endif // CONTENT_BROWSER_DIRECT_SOCKETS_FIREWALL_HOLE_DELEGATE_H_