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_(¶ms_) {} 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(¶ms_); 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 ¶ms_, 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_), ¶ms_); 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 ¶ms_); 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_ == ¶ms_); 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_ == ¶ms_); 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_ == ¶ms_); 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