11cb0ef41Sopenharmony_ci#if HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci#include "transportparams.h"
41cb0ef41Sopenharmony_ci#include <env-inl.h>
51cb0ef41Sopenharmony_ci#include <memory_tracker-inl.h>
61cb0ef41Sopenharmony_ci#include <node_sockaddr-inl.h>
71cb0ef41Sopenharmony_ci#include <util-inl.h>
81cb0ef41Sopenharmony_ci#include <v8.h>
91cb0ef41Sopenharmony_ci#include "bindingdata.h"
101cb0ef41Sopenharmony_ci#include "defs.h"
111cb0ef41Sopenharmony_ci#include "tokens.h"
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_cinamespace node {
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ciusing v8::ArrayBuffer;
161cb0ef41Sopenharmony_ciusing v8::Just;
171cb0ef41Sopenharmony_ciusing v8::Local;
181cb0ef41Sopenharmony_ciusing v8::Maybe;
191cb0ef41Sopenharmony_ciusing v8::Nothing;
201cb0ef41Sopenharmony_ciusing v8::Object;
211cb0ef41Sopenharmony_ciusing v8::Value;
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_cinamespace quic {
241cb0ef41Sopenharmony_ciTransportParams::Config::Config(Side side,
251cb0ef41Sopenharmony_ci                                const CID& ocid,
261cb0ef41Sopenharmony_ci                                const CID& retry_scid)
271cb0ef41Sopenharmony_ci    : side(side), ocid(ocid), retry_scid(retry_scid) {}
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ciMaybe<const TransportParams::Options> TransportParams::Options::From(
301cb0ef41Sopenharmony_ci    Environment* env, Local<Value> value) {
311cb0ef41Sopenharmony_ci  if (value.IsEmpty() || !value->IsObject()) {
321cb0ef41Sopenharmony_ci    return Nothing<const Options>();
331cb0ef41Sopenharmony_ci  }
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  auto& state = BindingData::Get(env);
361cb0ef41Sopenharmony_ci  auto params = value.As<Object>();
371cb0ef41Sopenharmony_ci  Options options;
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci#define SET(name)                                                              \
401cb0ef41Sopenharmony_ci  SetOption<TransportParams::Options, &TransportParams::Options::name>(        \
411cb0ef41Sopenharmony_ci      env, &options, params, state.name##_string())
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  if (!SET(initial_max_stream_data_bidi_local) ||
441cb0ef41Sopenharmony_ci      !SET(initial_max_stream_data_bidi_remote) ||
451cb0ef41Sopenharmony_ci      !SET(initial_max_stream_data_uni) || !SET(initial_max_data) ||
461cb0ef41Sopenharmony_ci      !SET(initial_max_streams_bidi) || !SET(initial_max_streams_uni) ||
471cb0ef41Sopenharmony_ci      !SET(max_idle_timeout) || !SET(active_connection_id_limit) ||
481cb0ef41Sopenharmony_ci      !SET(ack_delay_exponent) || !SET(max_ack_delay) ||
491cb0ef41Sopenharmony_ci      !SET(max_datagram_frame_size) || !SET(disable_active_migration)) {
501cb0ef41Sopenharmony_ci    return Nothing<const Options>();
511cb0ef41Sopenharmony_ci  }
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci#undef SET
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci  return Just<const Options>(options);
561cb0ef41Sopenharmony_ci}
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ciTransportParams::TransportParams(Type type) : type_(type), ptr_(&params_) {}
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ciTransportParams::TransportParams(Type type, const ngtcp2_transport_params* ptr)
611cb0ef41Sopenharmony_ci    : type_(type), ptr_(ptr) {}
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ciTransportParams::TransportParams(const Config& config, const Options& options)
641cb0ef41Sopenharmony_ci    : TransportParams(Type::ENCRYPTED_EXTENSIONS) {
651cb0ef41Sopenharmony_ci  ngtcp2_transport_params_default(&params_);
661cb0ef41Sopenharmony_ci  params_.active_connection_id_limit = options.active_connection_id_limit;
671cb0ef41Sopenharmony_ci  params_.initial_max_stream_data_bidi_local =
681cb0ef41Sopenharmony_ci      options.initial_max_stream_data_bidi_local;
691cb0ef41Sopenharmony_ci  params_.initial_max_stream_data_bidi_remote =
701cb0ef41Sopenharmony_ci      options.initial_max_stream_data_bidi_remote;
711cb0ef41Sopenharmony_ci  params_.initial_max_stream_data_uni = options.initial_max_stream_data_uni;
721cb0ef41Sopenharmony_ci  params_.initial_max_streams_bidi = options.initial_max_streams_bidi;
731cb0ef41Sopenharmony_ci  params_.initial_max_streams_uni = options.initial_max_streams_uni;
741cb0ef41Sopenharmony_ci  params_.initial_max_data = options.initial_max_data;
751cb0ef41Sopenharmony_ci  params_.max_idle_timeout = options.max_idle_timeout * NGTCP2_SECONDS;
761cb0ef41Sopenharmony_ci  params_.max_ack_delay = options.max_ack_delay;
771cb0ef41Sopenharmony_ci  params_.ack_delay_exponent = options.ack_delay_exponent;
781cb0ef41Sopenharmony_ci  params_.max_datagram_frame_size = options.max_datagram_frame_size;
791cb0ef41Sopenharmony_ci  params_.disable_active_migration = options.disable_active_migration ? 1 : 0;
801cb0ef41Sopenharmony_ci  params_.preferred_address_present = 0;
811cb0ef41Sopenharmony_ci  params_.stateless_reset_token_present = 0;
821cb0ef41Sopenharmony_ci  params_.retry_scid_present = 0;
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci  if (config.side == Side::SERVER) {
851cb0ef41Sopenharmony_ci    // For the server side, the original dcid is always set.
861cb0ef41Sopenharmony_ci    CHECK(config.ocid);
871cb0ef41Sopenharmony_ci    params_.original_dcid = config.ocid;
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci    // The retry_scid is only set if the server validated a retry token.
901cb0ef41Sopenharmony_ci    if (config.retry_scid) {
911cb0ef41Sopenharmony_ci      params_.retry_scid = config.retry_scid;
921cb0ef41Sopenharmony_ci      params_.retry_scid_present = 1;
931cb0ef41Sopenharmony_ci    }
941cb0ef41Sopenharmony_ci  }
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci  if (options.preferred_address_ipv4.has_value())
971cb0ef41Sopenharmony_ci    SetPreferredAddress(options.preferred_address_ipv4.value());
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci  if (options.preferred_address_ipv6.has_value())
1001cb0ef41Sopenharmony_ci    SetPreferredAddress(options.preferred_address_ipv6.value());
1011cb0ef41Sopenharmony_ci}
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ciTransportParams::TransportParams(Type type, const ngtcp2_vec& vec)
1041cb0ef41Sopenharmony_ci    : TransportParams(type) {
1051cb0ef41Sopenharmony_ci  int ret = ngtcp2_decode_transport_params(
1061cb0ef41Sopenharmony_ci      &params_,
1071cb0ef41Sopenharmony_ci      static_cast<ngtcp2_transport_params_type>(type),
1081cb0ef41Sopenharmony_ci      vec.base,
1091cb0ef41Sopenharmony_ci      vec.len);
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci  if (ret != 0) {
1121cb0ef41Sopenharmony_ci    ptr_ = nullptr;
1131cb0ef41Sopenharmony_ci    error_ = QuicError::ForNgtcp2Error(ret);
1141cb0ef41Sopenharmony_ci  }
1151cb0ef41Sopenharmony_ci}
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ciStore TransportParams::Encode(Environment* env) {
1181cb0ef41Sopenharmony_ci  if (ptr_ == nullptr) {
1191cb0ef41Sopenharmony_ci    error_ = QuicError::ForNgtcp2Error(NGTCP2_INTERNAL_ERROR);
1201cb0ef41Sopenharmony_ci    return Store();
1211cb0ef41Sopenharmony_ci  }
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  // Preflight to see how much storage we'll need.
1241cb0ef41Sopenharmony_ci  ssize_t size = ngtcp2_encode_transport_params(
1251cb0ef41Sopenharmony_ci      nullptr, 0, static_cast<ngtcp2_transport_params_type>(type_), &params_);
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci  DCHECK_GT(size, 0);
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  auto result = ArrayBuffer::NewBackingStore(env->isolate(), size);
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci  auto ret = ngtcp2_encode_transport_params(
1321cb0ef41Sopenharmony_ci      static_cast<uint8_t*>(result->Data()),
1331cb0ef41Sopenharmony_ci      size,
1341cb0ef41Sopenharmony_ci      static_cast<ngtcp2_transport_params_type>(type_),
1351cb0ef41Sopenharmony_ci      &params_);
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci  if (ret != 0) {
1381cb0ef41Sopenharmony_ci    error_ = QuicError::ForNgtcp2Error(ret);
1391cb0ef41Sopenharmony_ci    return Store();
1401cb0ef41Sopenharmony_ci  }
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci  return Store(std::move(result), static_cast<size_t>(size));
1431cb0ef41Sopenharmony_ci}
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_civoid TransportParams::SetPreferredAddress(const SocketAddress& address) {
1461cb0ef41Sopenharmony_ci  DCHECK(ptr_ == &params_);
1471cb0ef41Sopenharmony_ci  params_.preferred_address_present = 1;
1481cb0ef41Sopenharmony_ci  switch (address.family()) {
1491cb0ef41Sopenharmony_ci    case AF_INET: {
1501cb0ef41Sopenharmony_ci      const sockaddr_in* src =
1511cb0ef41Sopenharmony_ci          reinterpret_cast<const sockaddr_in*>(address.data());
1521cb0ef41Sopenharmony_ci      memcpy(params_.preferred_address.ipv4_addr,
1531cb0ef41Sopenharmony_ci             &src->sin_addr,
1541cb0ef41Sopenharmony_ci             sizeof(params_.preferred_address.ipv4_addr));
1551cb0ef41Sopenharmony_ci      params_.preferred_address.ipv4_port = address.port();
1561cb0ef41Sopenharmony_ci      return;
1571cb0ef41Sopenharmony_ci    }
1581cb0ef41Sopenharmony_ci    case AF_INET6: {
1591cb0ef41Sopenharmony_ci      const sockaddr_in6* src =
1601cb0ef41Sopenharmony_ci          reinterpret_cast<const sockaddr_in6*>(address.data());
1611cb0ef41Sopenharmony_ci      memcpy(params_.preferred_address.ipv6_addr,
1621cb0ef41Sopenharmony_ci             &src->sin6_addr,
1631cb0ef41Sopenharmony_ci             sizeof(params_.preferred_address.ipv6_addr));
1641cb0ef41Sopenharmony_ci      params_.preferred_address.ipv6_port = address.port();
1651cb0ef41Sopenharmony_ci      return;
1661cb0ef41Sopenharmony_ci    }
1671cb0ef41Sopenharmony_ci  }
1681cb0ef41Sopenharmony_ci  UNREACHABLE();
1691cb0ef41Sopenharmony_ci}
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_civoid TransportParams::GenerateStatelessResetToken(
1721cb0ef41Sopenharmony_ci    const TokenSecret& token_secret, const CID& cid) {
1731cb0ef41Sopenharmony_ci  DCHECK(ptr_ == &params_);
1741cb0ef41Sopenharmony_ci  DCHECK(cid);
1751cb0ef41Sopenharmony_ci  params_.stateless_reset_token_present = 1;
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci  StatelessResetToken token(params_.stateless_reset_token, token_secret, cid);
1781cb0ef41Sopenharmony_ci}
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ciCID TransportParams::GeneratePreferredAddressToken(const Session& session) {
1811cb0ef41Sopenharmony_ci  DCHECK(ptr_ == &params_);
1821cb0ef41Sopenharmony_ci  // DCHECK(pscid);
1831cb0ef41Sopenharmony_ci  // TODO(@jasnell): To be implemented when Session is implemented
1841cb0ef41Sopenharmony_ci  // *pscid = session->cid_factory_.Generate();
1851cb0ef41Sopenharmony_ci  // params_.preferred_address.cid = *pscid;
1861cb0ef41Sopenharmony_ci  // session->endpoint_->AssociateStatelessResetToken(
1871cb0ef41Sopenharmony_ci  //     session->endpoint().GenerateNewStatelessResetToken(
1881cb0ef41Sopenharmony_ci  //       params_.preferred_address.stateless_reset_token, *pscid),
1891cb0ef41Sopenharmony_ci  //     session);
1901cb0ef41Sopenharmony_ci  return CID::kInvalid;
1911cb0ef41Sopenharmony_ci}
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ciTransportParams::Type TransportParams::type() const {
1941cb0ef41Sopenharmony_ci  return type_;
1951cb0ef41Sopenharmony_ci}
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ciTransportParams::operator const ngtcp2_transport_params&() const {
1981cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(ptr_);
1991cb0ef41Sopenharmony_ci  return *ptr_;
2001cb0ef41Sopenharmony_ci}
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ciTransportParams::operator const ngtcp2_transport_params*() const {
2031cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(ptr_);
2041cb0ef41Sopenharmony_ci  return ptr_;
2051cb0ef41Sopenharmony_ci}
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_ciTransportParams::operator bool() const {
2081cb0ef41Sopenharmony_ci  return ptr_ != nullptr;
2091cb0ef41Sopenharmony_ci}
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ciconst QuicError& TransportParams::error() const {
2121cb0ef41Sopenharmony_ci  return error_;
2131cb0ef41Sopenharmony_ci}
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ci}  // namespace quic
2161cb0ef41Sopenharmony_ci}  // namespace node
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci#endif  // HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
219