%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/quic/
Upload File :
Create Path :
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/quic/session.h

#pragma once

#include <sys/types.h>
#include "quic/tokens.h"
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#if HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC

#include <async_wrap.h>
#include <base_object.h>
#include <env.h>
#include <memory_tracker.h>
#include <ngtcp2/ngtcp2.h>
#include <node_http_common.h>
#include <node_sockaddr.h>
#include <timer_wrap.h>
#include <util.h>
#include <optional>
#include "bindingdata.h"
#include "cid.h"
#include "data.h"
#include "defs.h"
#include "logstream.h"
#include "packet.h"
#include "preferredaddress.h"
#include "sessionticket.h"
#include "streams.h"
#include "tlscontext.h"
#include "transportparams.h"

namespace node {
namespace quic {

class Endpoint;

// A Session represents one half of a persistent connection between two QUIC
// peers. Every Session is established first by performing a TLS handshake in
// which the client sends an initial packet to the server containing a TLS
// client hello. Once the TLS handshake has been completed, the Session can be
// used to open one or more Streams for the actual data flow back and forth.
//
// While client and server Sessions are created in slightly different ways,
// their lifecycles are generally identical:
//
// A Session is either acting as a Client or as a Server.
//
// Client Sessions are always created using Endpoint::Connect()
//
// Server Sessions are always created by an Endpoint receiving a valid initial
// request received from a remote client.
//
// As soon as Sessions of either type are created, they will immediately start
// working through the TLS handshake to establish the crypographic keys used to
// secure the communication. Once those keys are established, the Session can be
// used to open Streams. Based on how the Session is configured, any number of
// Streams can exist concurrently on a single Session.
class Session final : public AsyncWrap, private SessionTicket::AppData::Source {
 public:
  // For simplicity, we use the same Application::Options struct for all
  // Application types. This may change in the future. Not all of the options
  // are going to be relevant for all Application types.
  struct Application_Options final : public MemoryRetainer {
    // The maximum number of header pairs permitted for a Stream.
    // Only relevant if the selected application supports headers.
    uint64_t max_header_pairs = DEFAULT_MAX_HEADER_LIST_PAIRS;

    // The maximum total number of header bytes (including header
    // name and value) permitted for a Stream.
    // Only relevant if the selected application supports headers.
    uint64_t max_header_length = DEFAULT_MAX_HEADER_LENGTH;

    // HTTP/3 specific options.
    uint64_t max_field_section_size = 0;
    uint64_t qpack_max_dtable_capacity = 0;
    uint64_t qpack_encoder_max_dtable_capacity = 0;
    uint64_t qpack_blocked_streams = 0;

    bool enable_connect_protocol = true;
    bool enable_datagrams = true;

    operator const nghttp3_settings() const;

    SET_NO_MEMORY_INFO()
    SET_MEMORY_INFO_NAME(Application::Options)
    SET_SELF_SIZE(Options)

    static v8::Maybe<Application_Options> From(Environment* env,
                                               v8::Local<v8::Value> value);

    std::string ToString() const;

    static const Application_Options kDefault;
  };

  // An Application implements the ALPN-protocol specific semantics on behalf
  // of a QUIC Session.
  class Application;

  // The options used to configure a session. Most of these deal directly with
  // the transport parameters that are exchanged with the remote peer during
  // handshake.
  struct Options final : public MemoryRetainer {
    // The QUIC protocol version requested for the session.
    uint32_t version = NGTCP2_PROTO_VER_MAX;

    // Te minimum QUIC protocol version supported by this session.
    uint32_t min_version = NGTCP2_PROTO_VER_MIN;

    // By default a client session will use the preferred address advertised by
    // the the server. This option is only relevant for client sessions.
    PreferredAddress::Policy preferred_address_strategy =
        PreferredAddress::Policy::USE_PREFERRED_ADDRESS;

    TransportParams::Options transport_params =
        TransportParams::Options::kDefault;
    TLSContext::Options tls_options = TLSContext::Options::kDefault;
    Application_Options application_options = Application_Options::kDefault;

    // A reference to the CID::Factory used to generate CID instances
    // for this session.
    const CID::Factory* cid_factory = &CID::Factory::random();
    // If the CID::Factory is a base object, we keep a reference to it
    // so that it cannot be garbage collected.
    BaseObjectPtr<BaseObject> cid_factory_ref = BaseObjectPtr<BaseObject>();

    // When true, QLog output will be enabled for the session.
    bool qlog = false;

    void MemoryInfo(MemoryTracker* tracker) const override;
    SET_MEMORY_INFO_NAME(Session::Options)
    SET_SELF_SIZE(Options)

    static v8::Maybe<Options> From(Environment* env,
                                   v8::Local<v8::Value> value);

    std::string ToString() const;
  };

  // The additional configuration settings used to create a specific session.
  // while the Options above can be used to configure multiple sessions, a
  // single Config is used to create a single session, which is why they are
  // kept separate.
  struct Config final : MemoryRetainer {
    // Is the Session acting as a client or a server?
    Side side;

    // The options to use for this session.
    Options options;

    // The actual QUIC version identified for this session.
    uint32_t version;

    SocketAddress local_address;
    SocketAddress remote_address;

    // The destination CID, identifying the remote peer. This value is always
    // provided by the remote peer.
    CID dcid = CID::kInvalid;

    // The source CID, identifying this session. This value is always created
    // locally.
    CID scid = CID::kInvalid;

    // Used only by client sessions to identify the original DCID
    // used to initiate the connection.
    CID ocid = CID::kInvalid;
    CID retry_scid = CID::kInvalid;
    CID preferred_address_cid = CID::kInvalid;

    // If this is a client session, the session_ticket is used to resume
    // a TLS session using a previously established session ticket.
    std::optional<SessionTicket> session_ticket = std::nullopt;

    ngtcp2_settings settings = {};
    operator ngtcp2_settings*() { return &settings; }
    operator const ngtcp2_settings*() const { return &settings; }

    Config(Side side,
           const Endpoint& endpoint,
           const Options& options,
           uint32_t version,
           const SocketAddress& local_address,
           const SocketAddress& remote_address,
           const CID& dcid,
           const CID& scid,
           std::optional<SessionTicket> session_ticket = std::nullopt,
           const CID& ocid = CID::kInvalid);

    Config(const Endpoint& endpoint,
           const Options& options,
           const SocketAddress& local_address,
           const SocketAddress& remote_address,
           std::optional<SessionTicket> session_ticket = std::nullopt,
           const CID& ocid = CID::kInvalid);

    void set_token(const uint8_t* token,
                   size_t len,
                   ngtcp2_token_type type = NGTCP2_TOKEN_TYPE_UNKNOWN);
    void set_token(const RetryToken& token);
    void set_token(const RegularToken& token);

    void MemoryInfo(MemoryTracker* tracker) const override;
    SET_MEMORY_INFO_NAME(Session::Config)
    SET_SELF_SIZE(Config)

    std::string ToString() const;
  };

  static bool HasInstance(Environment* env, v8::Local<v8::Value> value);
  static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
      Environment* env);
  static void InitPerIsolate(IsolateData* isolate_data,
                             v8::Local<v8::ObjectTemplate> target);
  static void InitPerContext(Realm* env, v8::Local<v8::Object> target);
  static void RegisterExternalReferences(ExternalReferenceRegistry* registry);

  static BaseObjectPtr<Session> Create(Endpoint* endpoint,
                                       const Config& config);

  // Really should be private but MakeDetachedBaseObject needs visibility.
  Session(Endpoint* endpoint,
          v8::Local<v8::Object> object,
          const Config& config);
  ~Session() override;

  uint32_t version() const;
  Endpoint& endpoint() const;
  TLSContext& tls_context();
  Application& application();
  const Config& config() const;
  const Options& options() const;
  const SocketAddress& remote_address() const;
  const SocketAddress& local_address() const;

  bool is_closing() const;
  bool is_graceful_closing() const;
  bool is_silent_closing() const;
  bool is_destroyed() const;
  bool is_server() const;

  void set_priority_supported(bool on = true);

  std::string diagnostic_name() const override;

  // Use the configured CID::Factory to generate a new CID.
  CID new_cid(size_t len = CID::kMaxLength) const;

  void HandleQlog(uint32_t flags, const void* data, size_t len);

  TransportParams GetLocalTransportParams() const;
  TransportParams GetRemoteTransportParams() const;

  void MemoryInfo(MemoryTracker* tracker) const override;
  SET_MEMORY_INFO_NAME(Session)
  SET_SELF_SIZE(Session)

  struct State;
  struct Stats;

  operator ngtcp2_conn*() const;

  BaseObjectPtr<Stream> FindStream(int64_t id) const;
  BaseObjectPtr<Stream> CreateStream(int64_t id);
  BaseObjectPtr<Stream> OpenStream(Direction direction);
  void ExtendStreamOffset(int64_t id, size_t amount);
  void ExtendOffset(size_t amount);
  void SetLastError(QuicError&& error);
  uint64_t max_data_left() const;

  enum class CloseMethod {
    // Roundtrip through JavaScript, causing all currently opened streams
    // to be closed. An attempt will be made to send a CONNECTION_CLOSE
    // frame to the peer. If closing while within the ngtcp2 callback scope,
    // sending the CONNECTION_CLOSE will be deferred until the scope exits.
    DEFAULT,
    // The connected peer will not be notified.
    SILENT,
    // Closing gracefully disables the ability to open or accept new streams for
    // this Session. Existing streams are allowed to close naturally on their
    // own.
    // Once called, the Session will be immediately closed once there are no
    // remaining streams. No notification is given to the connected peer that we
    // are in a graceful closing state. A CONNECTION_CLOSE will be sent only
    // once
    // Close() is called.
    GRACEFUL
  };
  void Close(CloseMethod method = CloseMethod::DEFAULT);

  struct SendPendingDataScope {
    Session* session;
    explicit SendPendingDataScope(Session* session);
    explicit SendPendingDataScope(const BaseObjectPtr<Session>& session);
    SendPendingDataScope(const SendPendingDataScope&) = delete;
    SendPendingDataScope(SendPendingDataScope&&) = delete;
    SendPendingDataScope& operator=(const SendPendingDataScope&) = delete;
    SendPendingDataScope& operator=(SendPendingDataScope&&) = delete;
    ~SendPendingDataScope();
  };

 private:
  struct Impl;
  struct MaybeCloseConnectionScope;

  using StreamsMap = std::unordered_map<int64_t, BaseObjectPtr<Stream>>;
  using QuicConnectionPointer = DeleteFnPtr<ngtcp2_conn, ngtcp2_conn_del>;

  struct PathValidationFlags {
    bool preferredAddress = false;
  };

  struct DatagramReceivedFlags {
    bool early = false;
  };

  void Destroy();

  bool Receive(Store&& store,
               const SocketAddress& local_address,
               const SocketAddress& remote_address);

  void Send(Packet* packet);
  void Send(Packet* packet, const PathStorage& path);
  uint64_t SendDatagram(Store&& data);

  void AddStream(const BaseObjectPtr<Stream>& stream);
  void RemoveStream(int64_t id);
  void ResumeStream(int64_t id);
  void ShutdownStream(int64_t id, QuicError error);
  void StreamDataBlocked(int64_t id);
  void ShutdownStreamWrite(int64_t id, QuicError code = QuicError());

  // Implementation of SessionTicket::AppData::Source
  void CollectSessionTicketAppData(
      SessionTicket::AppData* app_data) const override;
  SessionTicket::AppData::Status ExtractSessionTicketAppData(
      const SessionTicket::AppData& app_data,
      SessionTicket::AppData::Source::Flag flag) override;

  // Returns true if the Session has entered the closing period after sending a
  // CONNECTION_CLOSE. While true, the Session is only permitted to transmit
  // CONNECTION_CLOSE frames until either the idle timeout period elapses or
  // until the Session is explicitly destroyed.
  bool is_in_closing_period() const;

  // Returns true if the Session has received a CONNECTION_CLOSE frame from the
  // peer. Once in the draining period, the Session is not permitted to send any
  // frames to the peer. The Session will be silently closed after either the
  // idle timeout period elapses or until the Session is explicitly destroyed.
  bool is_in_draining_period() const;

  // Returns false if the Session is currently in a state where it is unable to
  // transmit any packets.
  bool can_send_packets() const;

  // Returns false if the Session is currently in a state where it cannot create
  // new streams.
  bool can_create_streams() const;
  uint64_t max_local_streams_uni() const;
  uint64_t max_local_streams_bidi() const;

  bool wants_session_ticket() const;
  void SetStreamOpenAllowed();

  // It's a terrible name but "wrapped" here means that the Session has been
  // passed out to JavaScript and should be "wrapped" by whatever handler is
  // defined there to manage it.
  void set_wrapped();

  void DoClose(bool silent = false);
  void UpdateDataStats();
  void SendConnectionClose();
  void OnTimeout();
  void UpdateTimer();
  bool StartClosingPeriod();

  // JavaScript callouts

  void EmitClose(const QuicError& error = QuicError());
  void EmitDatagram(Store&& datagram, DatagramReceivedFlags flag);
  void EmitDatagramStatus(uint64_t id, DatagramStatus status);
  void EmitHandshakeComplete();
  void EmitKeylog(const char* line);

  struct ValidatedPath {
    std::shared_ptr<SocketAddress> local;
    std::shared_ptr<SocketAddress> remote;
  };

  void EmitPathValidation(PathValidationResult result,
                          PathValidationFlags flags,
                          const ValidatedPath& newPath,
                          const std::optional<ValidatedPath>& oldPath);
  void EmitSessionTicket(Store&& ticket);
  void EmitStream(BaseObjectPtr<Stream> stream);
  void EmitVersionNegotiation(const ngtcp2_pkt_hd& hd,
                              const uint32_t* sv,
                              size_t nsv);

  void DatagramStatus(uint64_t datagramId, DatagramStatus status);
  void DatagramReceived(const uint8_t* data,
                        size_t datalen,
                        DatagramReceivedFlags flag);
  bool GenerateNewConnectionId(ngtcp2_cid* cid, size_t len, uint8_t* token);
  bool HandshakeCompleted();
  void HandshakeConfirmed();
  void SelectPreferredAddress(PreferredAddress* preferredAddress);
  void UpdatePath(const PathStorage& path);

  QuicConnectionPointer InitConnection();

  std::unique_ptr<Application> select_application();

  AliasedStruct<Stats> stats_;
  AliasedStruct<State> state_;
  ngtcp2_mem allocator_;
  BaseObjectWeakPtr<Endpoint> endpoint_;
  Config config_;
  SocketAddress local_address_;
  SocketAddress remote_address_;
  QuicConnectionPointer connection_;
  TLSContext tls_context_;
  std::unique_ptr<Application> application_;
  StreamsMap streams_;
  TimerWrapHandle timer_;
  size_t send_scope_depth_ = 0;
  size_t connection_close_depth_ = 0;
  QuicError last_error_;
  Packet* conn_closebuf_;
  BaseObjectPtr<LogStream> qlog_stream_;
  BaseObjectPtr<LogStream> keylog_stream_;

  friend class Application;
  friend class DefaultApplication;
  friend class Endpoint;
  friend struct Impl;
  friend struct MaybeCloseConnectionScope;
  friend struct SendPendingDataScope;
  friend class Stream;
  friend class TLSContext;
  friend class TransportParams;
};

}  // namespace quic
}  // namespace node

#endif  // HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

Zerion Mini Shell 1.0