blob: 2b48e49404fd2ffd80cc02dd51fa39f348a8cf36 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef QUICHE_QUIC_MASQUE_MASQUE_CLIENT_SESSION_H_
#define QUICHE_QUIC_MASQUE_MASQUE_CLIENT_SESSION_H_
#include <string>
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "quiche/quic/core/http/quic_spdy_client_session.h"
#include "quiche/quic/masque/masque_utils.h"
#include "quiche/quic/platform/api/quic_export.h"
#include "quiche/quic/platform/api/quic_socket_address.h"
namespace quic {
// QUIC client session for connection to MASQUE proxy. This session establishes
// a connection to a MASQUE proxy and handles sending and receiving DATAGRAM
// frames for operation of the MASQUE protocol. Multiple end-to-end encapsulated
// sessions can then coexist inside this session. Once these are created, they
// need to be registered with this session.
class QUIC_NO_EXPORT MasqueClientSession : public QuicSpdyClientSession {
public:
// Interface meant to be implemented by the owner of the
// MasqueClientSession instance.
class QUIC_NO_EXPORT Owner {
public:
virtual ~Owner() {}
// Notifies the owner that a settings frame has been received.
virtual void OnSettingsReceived() = 0;
};
// Interface meant to be implemented by client sessions encapsulated inside
// CONNECT-UDP, i.e. the end-to-end QUIC client sessions that run inside
// CONNECT-UDP encapsulation.
class QUIC_NO_EXPORT EncapsulatedClientSession {
public:
virtual ~EncapsulatedClientSession() {}
// Process UDP packet that was just decapsulated. |packet| contains the UDP
// payload.
virtual void ProcessPacket(absl::string_view packet,
QuicSocketAddress target_server_address) = 0;
// Close the encapsulated connection.
virtual void CloseConnection(
QuicErrorCode error, const std::string& details,
ConnectionCloseBehavior connection_close_behavior) = 0;
};
// Interface meant to be implemented by client sessions encapsulated inside
// CONNECT-IP, i.e. the end-to-end QUIC client sessions that run inside
// CONNECT-IP encapsulation.
class QUIC_NO_EXPORT EncapsulatedIpSession {
public:
virtual ~EncapsulatedIpSession() {}
// Process packet that was just decapsulated. |packet| contains the IP
// header and payload.
virtual void ProcessIpPacket(absl::string_view packet) = 0;
// Close the encapsulated connection.
virtual void CloseIpSession(const std::string& details) = 0;
virtual bool OnAddressAssignCapsule(
const AddressAssignCapsule& capsule) = 0;
virtual bool OnAddressRequestCapsule(
const AddressRequestCapsule& capsule) = 0;
virtual bool OnRouteAdvertisementCapsule(
const RouteAdvertisementCapsule& capsule) = 0;
};
// Takes ownership of |connection|, but not of |crypto_config| or
// |push_promise_index| or |owner|. All pointers must be non-null. Caller
// must ensure that |push_promise_index| and |owner| stay valid for the
// lifetime of the newly created MasqueClientSession.
MasqueClientSession(MasqueMode masque_mode, const std::string& uri_template,
const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
QuicConnection* connection, const QuicServerId& server_id,
QuicCryptoClientConfig* crypto_config,
QuicClientPushPromiseIndex* push_promise_index,
Owner* owner);
// Disallow copy and assign.
MasqueClientSession(const MasqueClientSession&) = delete;
MasqueClientSession& operator=(const MasqueClientSession&) = delete;
// From QuicSession.
void OnMessageAcked(QuicMessageId message_id,
QuicTime receive_timestamp) override;
void OnMessageLost(QuicMessageId message_id) override;
void OnConnectionClosed(const QuicConnectionCloseFrame& frame,
ConnectionCloseSource source) override;
void OnStreamClosed(QuicStreamId stream_id) override;
// From QuicSpdySession.
bool OnSettingsFrame(const SettingsFrame& frame) override;
// Send encapsulated UDP packet. |packet| contains the UDP payload.
void SendPacket(absl::string_view packet,
const QuicSocketAddress& target_server_address,
EncapsulatedClientSession* encapsulated_client_session);
// Send encapsulated IP packet. |packet| contains the IP header and payload.
void SendIpPacket(absl::string_view packet,
EncapsulatedIpSession* encapsulated_ip_session);
// Close CONNECT-UDP stream tied to this encapsulated client session.
void CloseConnectUdpStream(
EncapsulatedClientSession* encapsulated_client_session);
// Close CONNECT-IP stream tied to this encapsulated client session.
void CloseConnectIpStream(EncapsulatedIpSession* encapsulated_ip_session);
private:
// State that the MasqueClientSession keeps for each CONNECT-UDP request.
class QUIC_NO_EXPORT ConnectUdpClientState
: public QuicSpdyStream::Http3DatagramVisitor {
public:
// |stream| and |encapsulated_client_session| must be valid for the lifetime
// of the ConnectUdpClientState.
explicit ConnectUdpClientState(
QuicSpdyClientStream* stream,
EncapsulatedClientSession* encapsulated_client_session,
MasqueClientSession* masque_session,
const QuicSocketAddress& target_server_address);
~ConnectUdpClientState();
// Disallow copy but allow move.
ConnectUdpClientState(const ConnectUdpClientState&) = delete;
ConnectUdpClientState(ConnectUdpClientState&&);
ConnectUdpClientState& operator=(const ConnectUdpClientState&) = delete;
ConnectUdpClientState& operator=(ConnectUdpClientState&&);
QuicSpdyClientStream* stream() const { return stream_; }
EncapsulatedClientSession* encapsulated_client_session() const {
return encapsulated_client_session_;
}
const QuicSocketAddress& target_server_address() const {
return target_server_address_;
}
// From QuicSpdyStream::Http3DatagramVisitor.
void OnHttp3Datagram(QuicStreamId stream_id,
absl::string_view payload) override;
private:
QuicSpdyClientStream* stream_; // Unowned.
EncapsulatedClientSession* encapsulated_client_session_; // Unowned.
MasqueClientSession* masque_session_; // Unowned.
QuicSocketAddress target_server_address_;
};
// State that the MasqueClientSession keeps for each CONNECT-IP request.
class QUIC_NO_EXPORT ConnectIpClientState
: public QuicSpdyStream::Http3DatagramVisitor,
public QuicSpdyStream::ConnectIpVisitor {
public:
// |stream| and |encapsulated_client_session| must be valid for the lifetime
// of the ConnectUdpClientState.
explicit ConnectIpClientState(
QuicSpdyClientStream* stream,
EncapsulatedIpSession* encapsulated_ip_session,
MasqueClientSession* masque_session);
~ConnectIpClientState();
// Disallow copy but allow move.
ConnectIpClientState(const ConnectIpClientState&) = delete;
ConnectIpClientState(ConnectIpClientState&&);
ConnectIpClientState& operator=(const ConnectIpClientState&) = delete;
ConnectIpClientState& operator=(ConnectIpClientState&&);
QuicSpdyClientStream* stream() const { return stream_; }
EncapsulatedIpSession* encapsulated_ip_session() const {
return encapsulated_ip_session_;
}
// From QuicSpdyStream::Http3DatagramVisitor.
void OnHttp3Datagram(QuicStreamId stream_id,
absl::string_view payload) override;
// From QuicSpdyStream::ConnectIpVisitor.
bool OnAddressAssignCapsule(const AddressAssignCapsule& capsule) override;
bool OnAddressRequestCapsule(const AddressRequestCapsule& capsule) override;
bool OnRouteAdvertisementCapsule(
const RouteAdvertisementCapsule& capsule) override;
void OnHeadersWritten() override;
private:
QuicSpdyClientStream* stream_; // Unowned.
EncapsulatedIpSession* encapsulated_ip_session_; // Unowned.
MasqueClientSession* masque_session_; // Unowned.
};
HttpDatagramSupport LocalHttpDatagramSupport() override {
return HttpDatagramSupport::kRfc;
}
const ConnectUdpClientState* GetOrCreateConnectUdpClientState(
const QuicSocketAddress& target_server_address,
EncapsulatedClientSession* encapsulated_client_session);
const ConnectIpClientState* GetOrCreateConnectIpClientState(
EncapsulatedIpSession* encapsulated_ip_session);
MasqueMode masque_mode_;
std::string uri_template_;
std::list<ConnectUdpClientState> connect_udp_client_states_;
std::list<ConnectIpClientState> connect_ip_client_states_;
Owner* owner_; // Unowned;
};
} // namespace quic
#endif // QUICHE_QUIC_MASQUE_MASQUE_CLIENT_SESSION_H_