1 #pragma once 2 3 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 4 #if HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC 5 6 #include <base_object.h> 7 #include <env.h> 8 #include <memory_tracker.h> 9 #include <nghttp3/nghttp3.h> 10 #include <ngtcp2/ngtcp2.h> 11 #include <ngtcp2/ngtcp2_crypto.h> 12 #include <node.h> 13 #include <node_mem.h> 14 #include <v8.h> 15 #include <vector> 16 17 namespace node { 18 namespace quic { 19 20 class Endpoint; 21 class Packet; 22 23 enum class Side { 24 CLIENT = NGTCP2_CRYPTO_SIDE_CLIENT, 25 SERVER = NGTCP2_CRYPTO_SIDE_SERVER, 26 }; 27 28 constexpr size_t kDefaultMaxPacketLength = NGTCP2_MAX_UDP_PAYLOAD_SIZE; 29 30 // ============================================================================ 31 32 // The FunctionTemplates the BindingData will store for us. 33 #define QUIC_CONSTRUCTORS(V) \ 34 V(endpoint) \ 35 V(logstream) \ 36 V(packet) \ 37 V(session) \ 38 V(stream) \ 39 V(udp) 40 41 // The callbacks are persistent v8::Function references that are set in the 42 // quic::BindingState used to communicate data and events back out to the JS 43 // environment. They are set once from the JavaScript side when the 44 // internalBinding('quic') is first loaded. 45 #define QUIC_JS_CALLBACKS(V) \ 46 V(endpoint_close, EndpointClose) \ 47 V(endpoint_error, EndpointError) \ 48 V(session_new, SessionNew) \ 49 V(session_close, SessionClose) \ 50 V(session_error, SessionError) \ 51 V(session_datagram, SessionDatagram) \ 52 V(session_datagram_status, SessionDatagramStatus) \ 53 V(session_handshake, SessionHandshake) \ 54 V(session_ticket, SessionTicket) \ 55 V(session_version_negotiation, SessionVersionNegotiation) \ 56 V(session_path_validation, SessionPathValidation) \ 57 V(stream_close, StreamClose) \ 58 V(stream_error, StreamError) \ 59 V(stream_created, StreamCreated) \ 60 V(stream_reset, StreamReset) \ 61 V(stream_headers, StreamHeaders) \ 62 V(stream_blocked, StreamBlocked) \ 63 V(stream_trailers, StreamTrailers) 64 65 // The various JS strings the implementation uses. 66 #define QUIC_STRINGS(V) \ 67 V(ack_delay_exponent, "ackDelayExponent") \ 68 V(active_connection_id_limit, "activeConnectionIDLimit") \ 69 V(alpn, "alpn") \ 70 V(ca, "ca") \ 71 V(certs, "certs") \ 72 V(crl, "crl") \ 73 V(ciphers, "ciphers") \ 74 V(disable_active_migration, "disableActiveMigration") \ 75 V(enable_tls_trace, "tlsTrace") \ 76 V(endpoint, "Endpoint") \ 77 V(endpoint_udp, "Endpoint::UDP") \ 78 V(groups, "groups") \ 79 V(hostname, "hostname") \ 80 V(http3_alpn, &NGHTTP3_ALPN_H3[1]) \ 81 V(initial_max_data, "initialMaxData") \ 82 V(initial_max_stream_data_bidi_local, "initialMaxStreamDataBidiLocal") \ 83 V(initial_max_stream_data_bidi_remote, "initialMaxStreamDataBidiRemote") \ 84 V(initial_max_stream_data_uni, "initialMaxStreamDataUni") \ 85 V(initial_max_streams_bidi, "initialMaxStreamsBidi") \ 86 V(initial_max_streams_uni, "initialMaxStreamsUni") \ 87 V(keylog, "keylog") \ 88 V(keys, "keys") \ 89 V(logstream, "LogStream") \ 90 V(max_ack_delay, "maxAckDelay") \ 91 V(max_datagram_frame_size, "maxDatagramFrameSize") \ 92 V(max_idle_timeout, "maxIdleTimeout") \ 93 V(packetwrap, "PacketWrap") \ 94 V(reject_unauthorized, "rejectUnauthorized") \ 95 V(request_peer_certificate, "requestPeerCertificate") \ 96 V(session, "Session") \ 97 V(session_id_ctx, "sessionIDContext") \ 98 V(stream, "Stream") \ 99 V(verify_hostname_identity, "verifyHostnameIdentity") 100 101 // ============================================================================= 102 // The BindingState object holds state for the internalBinding('quic') binding 103 // instance. It is mostly used to hold the persistent constructors, strings, and 104 // callback references used for the rest of the implementation. 105 // 106 // TODO(@jasnell): Make this snapshotable? 107 class BindingData final 108 : public BaseObject, 109 public mem::NgLibMemoryManager<BindingData, ngtcp2_mem> { 110 public: 111 SET_BINDING_ID(quic_binding_data) 112 static void Initialize(Environment* env, v8::Local<v8::Object> target); 113 static void RegisterExternalReferences(ExternalReferenceRegistry* registry); 114 115 static BindingData& Get(Environment* env); 116 117 BindingData(Realm* realm, v8::Local<v8::Object> object); 118 119 void MemoryInfo(MemoryTracker* tracker) const override; 120 SET_MEMORY_INFO_NAME(BindingData) 121 SET_SELF_SIZE(BindingData) 122 123 // NgLibMemoryManager 124 operator ngtcp2_mem(); 125 operator nghttp3_mem(); 126 void CheckAllocatedSize(size_t previous_size) const; 127 void IncreaseAllocatedSize(size_t size); 128 void DecreaseAllocatedSize(size_t size); 129 130 // Installs the set of JavaScript callback functions that are used to 131 // bridge out to the JS API. 132 static void SetCallbacks(const v8::FunctionCallbackInfo<v8::Value>& args); 133 134 std::vector<BaseObjectPtr<BaseObject>> packet_freelist; 135 136 // Purge the packet free list to free up memory. 137 static void FlushPacketFreelist( 138 const v8::FunctionCallbackInfo<v8::Value>& args); 139 140 bool in_ngtcp2_callback_scope = false; 141 bool in_nghttp3_callback_scope = false; 142 143 // The following set up various storage and accessors for common strings, 144 // construction templates, and callbacks stored on the BindingData. These 145 // are all defined in defs.h 146 147 #define V(name) \ 148 void set_##name##_constructor_template( \ 149 v8::Local<v8::FunctionTemplate> tmpl); \ 150 v8::Local<v8::FunctionTemplate> name##_constructor_template() const; 151 QUIC_CONSTRUCTORS(V) 152 #undef V 153 154 #define V(name, _) \ 155 void set_##name##_callback(v8::Local<v8::Function> fn); \ 156 v8::Local<v8::Function> name##_callback() const; 157 QUIC_JS_CALLBACKS(V) 158 #undef V 159 160 #define V(name, _) v8::Local<v8::String> name##_string() const; 161 QUIC_STRINGS(V) 162 #undef V 163 164 #define V(name, _) v8::Local<v8::String> on_##name##_string() const; 165 QUIC_JS_CALLBACKS(V) 166 #undef V 167 168 size_t current_ngtcp2_memory_ = 0; 169 170 #define V(name) v8::Global<v8::FunctionTemplate> name##_constructor_template_; 171 QUIC_CONSTRUCTORS(V) 172 #undef V 173 174 #define V(name, _) v8::Global<v8::Function> name##_callback_; 175 QUIC_JS_CALLBACKS(V) 176 #undef V 177 178 #define V(name, _) mutable v8::Eternal<v8::String> name##_string_; 179 QUIC_STRINGS(V) 180 #undef V 181 182 #define V(name, _) mutable v8::Eternal<v8::String> on_##name##_string_; 183 QUIC_JS_CALLBACKS(V) 184 #undef V 185 }; 186 187 void IllegalConstructor(const v8::FunctionCallbackInfo<v8::Value>& args); 188 189 // The ngtcp2 and nghttp3 callbacks have certain restrictions 190 // that forbid re-entry. We provide the following scopes for 191 // use in those to help protect against it. 192 struct NgTcp2CallbackScope { 193 Environment* env; 194 explicit NgTcp2CallbackScope(Environment* env); 195 ~NgTcp2CallbackScope(); 196 static bool in_ngtcp2_callback(Environment* env); 197 }; 198 199 struct NgHttp3CallbackScope { 200 Environment* env; 201 explicit NgHttp3CallbackScope(Environment* env); 202 ~NgHttp3CallbackScope(); 203 static bool in_nghttp3_callback(Environment* env); 204 }; 205 206 } // namespace quic 207 } // namespace node 208 209 #endif // HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC 210 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 211