%PDF- %PDF-
Direktori : /home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/quic/ |
Current File : //home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/quic/transportparams.cc |
#if HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC #include "transportparams.h" #include <env-inl.h> #include <memory_tracker-inl.h> #include <node_sockaddr-inl.h> #include <util-inl.h> #include <v8.h> #include "bindingdata.h" #include "defs.h" #include "endpoint.h" #include "session.h" #include "tokens.h" namespace node { using v8::ArrayBuffer; using v8::Just; using v8::Local; using v8::Maybe; using v8::Nothing; using v8::Object; using v8::Value; namespace quic { const TransportParams::Options TransportParams::Options::kDefault = {}; TransportParams::Config::Config(Side side, const CID& ocid, const CID& retry_scid) : side(side), ocid(ocid), retry_scid(retry_scid) {} Maybe<TransportParams::Options> TransportParams::Options::From( Environment* env, Local<Value> value) { if (value.IsEmpty()) { THROW_ERR_INVALID_ARG_TYPE(env, "options must be an object"); return Nothing<Options>(); } Options options; auto& state = BindingData::Get(env); if (value->IsUndefined()) { return Just<Options>(options); } if (!value->IsObject()) { THROW_ERR_INVALID_ARG_TYPE(env, "options must be an object"); return Nothing<Options>(); } auto params = value.As<Object>(); #define SET(name) \ SetOption<TransportParams::Options, &TransportParams::Options::name>( \ env, &options, params, state.name##_string()) if (!SET(initial_max_stream_data_bidi_local) || !SET(initial_max_stream_data_bidi_remote) || !SET(initial_max_stream_data_uni) || !SET(initial_max_data) || !SET(initial_max_streams_bidi) || !SET(initial_max_streams_uni) || !SET(max_idle_timeout) || !SET(active_connection_id_limit) || !SET(ack_delay_exponent) || !SET(max_ack_delay) || !SET(max_datagram_frame_size) || !SET(disable_active_migration)) { return Nothing<Options>(); } #undef SET return Just<Options>(options); } std::string TransportParams::Options::ToString() const { DebugIndentScope indent; auto prefix = indent.Prefix(); std::string res("{"); res += prefix + "version: " + std::to_string(transportParamsVersion); if (preferred_address_ipv4.has_value()) { res += prefix + "preferred_address_ipv4: " + preferred_address_ipv4.value().ToString(); } else { res += prefix + "preferred_address_ipv4: <none>"; } if (preferred_address_ipv6.has_value()) { res += prefix + "preferred_address_ipv6: " + preferred_address_ipv6.value().ToString(); } else { res += prefix + "preferred_address_ipv6: <none>"; } res += prefix + "initial max stream data bidi local: " + std::to_string(initial_max_stream_data_bidi_local); res += prefix + "initial max stream data bidi remote: " + std::to_string(initial_max_stream_data_bidi_remote); res += prefix + "initial max stream data uni: " + std::to_string(initial_max_stream_data_uni); res += prefix + "tinitial max data: " + std::to_string(initial_max_data); res += prefix + "initial max streams bidi: " + std::to_string(initial_max_streams_bidi); res += prefix + "initial max streams uni: " + std::to_string(initial_max_streams_uni); res += prefix + "max idle timeout: " + std::to_string(max_idle_timeout); res += prefix + "active connection id limit: " + std::to_string(active_connection_id_limit); res += prefix + "ack delay exponent: " + std::to_string(ack_delay_exponent); res += prefix + "max ack delay: " + std::to_string(max_ack_delay); res += prefix + "max datagram frame size: " + std::to_string(max_datagram_frame_size); res += prefix + "disable active migration: " + (disable_active_migration ? std::string("yes") : std::string("no")); res += indent.Close(); return res; } void TransportParams::Options::MemoryInfo(MemoryTracker* tracker) const { if (preferred_address_ipv4.has_value()) { tracker->TrackField("preferred_address_ipv4", preferred_address_ipv4.value()); } if (preferred_address_ipv6.has_value()) { tracker->TrackField("preferred_address_ipv6", preferred_address_ipv6.value()); } } TransportParams::TransportParams() : ptr_(¶ms_) {} TransportParams::TransportParams(const ngtcp2_transport_params* ptr) : ptr_(ptr) {} TransportParams::TransportParams(const Config& config, const Options& options) : TransportParams() { ngtcp2_transport_params_default(¶ms_); params_.active_connection_id_limit = options.active_connection_id_limit; params_.initial_max_stream_data_bidi_local = options.initial_max_stream_data_bidi_local; params_.initial_max_stream_data_bidi_remote = options.initial_max_stream_data_bidi_remote; params_.initial_max_stream_data_uni = options.initial_max_stream_data_uni; params_.initial_max_streams_bidi = options.initial_max_streams_bidi; params_.initial_max_streams_uni = options.initial_max_streams_uni; params_.initial_max_data = options.initial_max_data; params_.max_idle_timeout = options.max_idle_timeout * NGTCP2_SECONDS; params_.max_ack_delay = options.max_ack_delay; params_.ack_delay_exponent = options.ack_delay_exponent; params_.max_datagram_frame_size = options.max_datagram_frame_size; params_.disable_active_migration = options.disable_active_migration ? 1 : 0; params_.preferred_addr_present = 0; params_.stateless_reset_token_present = 0; params_.retry_scid_present = 0; if (config.side == Side::SERVER) { // For the server side, the original dcid is always set. CHECK(config.ocid); params_.original_dcid = config.ocid; // The retry_scid is only set if the server validated a retry token. if (config.retry_scid) { params_.retry_scid = config.retry_scid; params_.retry_scid_present = 1; } } if (options.preferred_address_ipv4.has_value()) SetPreferredAddress(options.preferred_address_ipv4.value()); if (options.preferred_address_ipv6.has_value()) SetPreferredAddress(options.preferred_address_ipv6.value()); } TransportParams::TransportParams(const ngtcp2_vec& vec, int version) : TransportParams() { int ret = ngtcp2_transport_params_decode_versioned( version, ¶ms_, vec.base, vec.len); if (ret != 0) { ptr_ = nullptr; error_ = QuicError::ForNgtcp2Error(ret); } } Store TransportParams::Encode(Environment* env, int version) { if (ptr_ == nullptr) { error_ = QuicError::ForNgtcp2Error(NGTCP2_INTERNAL_ERROR); return Store(); } // Preflight to see how much storage we'll need. ssize_t size = ngtcp2_transport_params_encode_versioned(nullptr, 0, version, ¶ms_); DCHECK_GT(size, 0); auto result = ArrayBuffer::NewBackingStore(env->isolate(), size); auto ret = ngtcp2_transport_params_encode_versioned( static_cast<uint8_t*>(result->Data()), size, version, ¶ms_); if (ret != 0) { error_ = QuicError::ForNgtcp2Error(ret); return Store(); } return Store(std::move(result), static_cast<size_t>(size)); } void TransportParams::SetPreferredAddress(const SocketAddress& address) { DCHECK(ptr_ == ¶ms_); params_.preferred_addr_present = 1; switch (address.family()) { case AF_INET: { const sockaddr_in* src = reinterpret_cast<const sockaddr_in*>(address.data()); memcpy(¶ms_.preferred_addr.ipv4.sin_addr, &src->sin_addr, sizeof(params_.preferred_addr.ipv4.sin_addr)); params_.preferred_addr.ipv4.sin_port = address.port(); return; } case AF_INET6: { const sockaddr_in6* src = reinterpret_cast<const sockaddr_in6*>(address.data()); memcpy(¶ms_.preferred_addr.ipv6.sin6_addr, &src->sin6_addr, sizeof(params_.preferred_addr.ipv6.sin6_addr)); params_.preferred_addr.ipv6.sin6_port = address.port(); return; } } UNREACHABLE(); } void TransportParams::GenerateSessionTokens(Session* session) { if (session->is_server()) { GenerateStatelessResetToken(session->endpoint(), session->config_.scid); GeneratePreferredAddressToken(session); } } void TransportParams::GenerateStatelessResetToken(const Endpoint& endpoint, const CID& cid) { DCHECK(ptr_ == ¶ms_); DCHECK(cid); params_.stateless_reset_token_present = 1; endpoint.GenerateNewStatelessResetToken(params_.stateless_reset_token, cid); } void TransportParams::GeneratePreferredAddressToken(Session* session) { DCHECK(ptr_ == ¶ms_); if (params_.preferred_addr_present) { session->config_.preferred_address_cid = session->new_cid(); params_.preferred_addr.cid = session->config_.preferred_address_cid; auto& endpoint = session->endpoint(); endpoint.AssociateStatelessResetToken( endpoint.GenerateNewStatelessResetToken( params_.preferred_addr.stateless_reset_token, session->config_.preferred_address_cid), session); } } TransportParams::operator const ngtcp2_transport_params&() const { DCHECK_NOT_NULL(ptr_); return *ptr_; } TransportParams::operator const ngtcp2_transport_params*() const { DCHECK_NOT_NULL(ptr_); return ptr_; } TransportParams::operator bool() const { return ptr_ != nullptr; } const QuicError& TransportParams::error() const { return error_; } void TransportParams::Initialize(Environment* env, v8::Local<v8::Object> target) { NODE_DEFINE_CONSTANT(target, DEFAULT_MAX_STREAM_DATA); NODE_DEFINE_CONSTANT(target, DEFAULT_MAX_DATA); NODE_DEFINE_CONSTANT(target, DEFAULT_MAX_IDLE_TIMEOUT); NODE_DEFINE_CONSTANT(target, DEFAULT_MAX_STREAMS_BIDI); NODE_DEFINE_CONSTANT(target, DEFAULT_MAX_STREAMS_UNI); NODE_DEFINE_CONSTANT(target, DEFAULT_ACTIVE_CONNECTION_ID_LIMIT); } } // namespace quic } // namespace node #endif // HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC