From b17ab979ca5668fc0083e57d3ac60024eb482968 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Thu, 9 Jul 2020 12:22:55 -0700 Subject: [PATCH 01/18] quic: replace ipv6Only option with `'udp6-only'` type Since the `ipv6Only` option was mutually exclusive with using `'udp6'`, making it it's own type simplifies things a bit. --- doc/api/quic.md | 22 +++------ lib/internal/quic/core.js | 49 +++++++++---------- lib/internal/quic/util.js | 27 ++++------ .../test-quic-errors-quicsocket-connect.js | 7 --- .../test-quic-errors-quicsocket-create.js | 7 --- test/parallel/test-quic-ipv6only.js | 34 ++----------- 6 files changed, 42 insertions(+), 104 deletions(-) diff --git a/doc/api/quic.md b/doc/api/quic.md index f6628bf9803fb1..0c8f73a0e5c8d1 100644 --- a/doc/api/quic.md +++ b/doc/api/quic.md @@ -260,12 +260,9 @@ added: REPLACEME IPv6 address or a host name. If a host name is given, it will be resolved to an IP address. * `port` {number} The local port to bind to. - * `type` {string} Either `'udp4'` or `'upd6'` to use either IPv4 or IPv6, - respectively. **Default**: `'udp4'`. - * `ipv6Only` {boolean} If `type` is `'udp6'`, then setting `ipv6Only` to - `true` will disable dual-stack support on the UDP binding -- that is, - binding to address `'::'` will not make `'0.0.0.0'` be bound. The option - is ignored if `type` is `'udp4'`. **Default**: `false`. + * `type` {string} Can be one of `'udp4'`, `'upd6'`, or `'udp6-only'` to + use IPv4, IPv6, or IPv6 with dual-stack mode disabled. + **Default**: `'udp4'`. * `lookup` {Function} A custom DNS lookup function. Default `dns.lookup()`. * `maxConnections` {number} The maximum number of total active inbound connections. @@ -1450,12 +1447,9 @@ added: REPLACEME IPv6 address or a host name. If a host name is given, it will be resolved to an IP address. * `port` {number} The local port to bind to. - * `type` {string} Either `'udp4'` or `'upd6'` to use either IPv4 or IPv6, - respectively. **Default**: `'udp4'`. - * `ipv6Only` {boolean} If `type` is `'udp6'`, then setting `ipv6Only` to - `true` will disable dual-stack support on the UDP binding -- that is, - binding to address `'::'` will not make `'0.0.0.0'` be bound. The option - is ignored if `type` is `'udp4'`. **Default**: `false`. + * `type` {string} Can be one of `'udp4'`, `'upd6'`, or `'udp6-only'` to + use IPv4, IPv6, or IPv6 with dual-stack mode disabled. + **Default**: `'udp4'`. * Returns: {QuicEndpoint} Creates and adds a new `QuicEndpoint` to the `QuicSocket` instance. @@ -1600,10 +1594,6 @@ added: REPLACEME `SSL_OP_CIPHER_SERVER_PREFERENCE` to be set in `secureOptions`, see [OpenSSL Options][] for more information. * `idleTimeout` {number} - * `ipv6Only` {boolean} If `type` is `'udp6'`, then setting `ipv6Only` to - `true` will disable dual-stack support on the UDP binding -- that is, - binding to address `'::'` will not make `'0.0.0.0'` be bound. The option - is ignored if `type` is `'udp4'`. **Default**: `false`. * `key` {string|string[]|Buffer|Buffer[]|Object[]} Private keys in PEM format. PEM allows the option of private keys being encrypted. Encrypted keys will be decrypted with `options.passphrase`. Multiple keys using different diff --git a/lib/internal/quic/core.js b/lib/internal/quic/core.js index e46e2763241914..908e01b625b665 100644 --- a/lib/internal/quic/core.js +++ b/lib/internal/quic/core.js @@ -611,10 +611,10 @@ class QuicEndpoint { const state = this[kInternalState]; state.socket = socket; state.address = address || (type === AF_INET6 ? '::' : '0.0.0.0'); - state.ipv6Only = !!ipv6Only; + state.ipv6Only = ipv6Only; state.lookup = lookup || (type === AF_INET6 ? lookup6 : lookup4); state.port = port; - state.reuseAddr = !!reuseAddr; + state.reuseAddr = reuseAddr; state.type = type; state.udpSocket = dgram.createSocket(type === AF_INET6 ? 'udp6' : 'udp4'); @@ -696,20 +696,26 @@ class QuicEndpoint { state.socket[kEndpointBound](this); } - [kDestroy](error) { + destroy(error) { + if (this.destroyed) + return; + + const state = this[kInternalState]; + state.state = kSocketDestroyed; + const handle = this[kHandle]; - if (handle !== undefined) { - this[kHandle] = undefined; - handle[owner_symbol] = undefined; - handle.ondone = () => { - const state = this[kInternalState]; - state.udpSocket.close((err) => { - if (err) error = err; - state.socket[kEndpointClose](this, error); - }); - }; - handle.waitForPendingCallbacks(); - } + if (handle === undefined) + return; + + this[kHandle] = undefined; + handle[owner_symbol] = undefined; + handle.ondone = () => { + state.udpSocket.close((err) => { + if (err) error = err; + state.socket[kEndpointClose](this, error); + }); + }; + handle.waitForPendingCallbacks(); } // If the QuicEndpoint is bound, returns an object detailing @@ -825,14 +831,6 @@ class QuicEndpoint { state.udpSocket.unref(); return this; } - - destroy(error) { - const state = this[kInternalState]; - if (this.destroyed) - return; - state.state = kSocketDestroyed; - this[kDestroy](error); - } } // QuicSocket wraps a UDP socket plus the associated TLS context and QUIC @@ -1195,7 +1193,7 @@ class QuicSocket extends EventEmitter { port, type = 'udp4', } = { ...preferredAddress }; - const typeVal = getSocketType(type); + const [ typeVal ] = getSocketType(type); // If preferred address is set, we need to perform a lookup on it // to get the IP address. Only after that lookup completes can we // continue with the listen operation, passing in the resolved @@ -2331,7 +2329,6 @@ class QuicClientSession extends QuicSession { autoStart: true, dcid: undefined, handshakeStarted: false, - ipv6Only: undefined, minDHSize: undefined, port: undefined, ready: 0, @@ -2355,7 +2352,6 @@ class QuicClientSession extends QuicSession { autoStart, alpn, dcid, - ipv6Only, minDHSize, port, preferredAddressPolicy, @@ -2383,7 +2379,6 @@ class QuicClientSession extends QuicSession { state.autoStart = autoStart; state.handshakeStarted = autoStart; state.dcid = dcid; - state.ipv6Only = ipv6Only; state.minDHSize = minDHSize; state.port = port || 0; state.preferredAddressPolicy = preferredAddressPolicy; diff --git a/lib/internal/quic/util.js b/lib/internal/quic/util.js index 31087ef96e5000..6e3087ea2938e1 100644 --- a/lib/internal/quic/util.js +++ b/lib/internal/quic/util.js @@ -140,8 +140,9 @@ function validateNumber(value, name, function getSocketType(type = 'udp4') { switch (type) { - case 'udp4': return AF_INET; - case 'udp6': return AF_INET6; + case 'udp4': return [AF_INET, false]; + case 'udp6': return [AF_INET6, false]; + case 'udp6-only': return [AF_INET6, true]; } throw new ERR_INVALID_ARG_VALUE('options.type', type); } @@ -366,7 +367,6 @@ function validateQuicClientSessionOptions(options = {}) { address = 'localhost', alpn = '', dcid: dcid_value, - ipv6Only = false, minDHSize = 1024, port = 0, preferredAddressPolicy = 'ignore', @@ -434,7 +434,6 @@ function validateQuicClientSessionOptions(options = {}) { if (preferredAddressPolicy !== undefined) validateString(preferredAddressPolicy, 'options.preferredAddressPolicy'); - validateBoolean(ipv6Only, 'options.ipv6Only'); validateBoolean(requestOCSP, 'options.requestOCSP'); validateBoolean(verifyHostnameIdentity, 'options.verifyHostnameIdentity'); validateBoolean(qlog, 'options.qlog'); @@ -444,7 +443,6 @@ function validateQuicClientSessionOptions(options = {}) { address, alpn, dcid, - ipv6Only, minDHSize, port, preferredAddressPolicy: @@ -495,7 +493,6 @@ function validateQuicEndpointOptions(options = {}, name = 'options') { throw new ERR_INVALID_ARG_TYPE('options', 'Object', options); const { address, - ipv6Only = false, lookup, port = 0, reuseAddr = false, @@ -507,17 +504,17 @@ function validateQuicEndpointOptions(options = {}, name = 'options') { validatePort(port, 'options.port'); validateString(type, 'options.type'); validateLookup(lookup); - validateBoolean(ipv6Only, 'options.ipv6Only'); validateBoolean(reuseAddr, 'options.reuseAddr'); validateBoolean(preferred, 'options.preferred'); + const [typeVal, ipv6Only] = getSocketType(type); return { - address, + type: typeVal, ipv6Only, + address, lookup, port, preferred, reuseAddr, - type: getSocketType(type), }; } @@ -536,15 +533,13 @@ function validateQuicSocketOptions(options = {}) { retryTokenTimeout = DEFAULT_RETRYTOKEN_EXPIRATION, server = {}, statelessResetSecret, - type = endpoint.type || 'udp4', validateAddressLRU = false, validateAddress = false, } = options; - validateQuicEndpointOptions(endpoint, 'options.endpoint'); + const { type } = validateQuicEndpointOptions(endpoint, 'options.endpoint'); validateObject(client, 'options.client'); validateObject(server, 'options.server'); - validateString(type, 'options.type'); validateLookup(lookup); validateBoolean(validateAddress, 'options.validateAddress'); validateBoolean(validateAddressLRU, 'options.validateAddressLRU'); @@ -595,7 +590,7 @@ function validateQuicSocketOptions(options = {}) { maxStatelessResetsPerHost, retryTokenTimeout, server, - type: getSocketType(type), + type, validateAddress: validateAddress || validateAddressLRU, validateAddressLRU, qlog, @@ -642,10 +637,8 @@ function validateQuicSocketConnectOptions(options = {}) { } = options; if (address !== undefined) validateString(address, 'options.address'); - return { - type: getSocketType(type), - address, - }; + const [typeVal] = getSocketType(type); + return { type: typeVal, address }; } function validateCreateSecureContextOptions(options = {}) { diff --git a/test/parallel/test-quic-errors-quicsocket-connect.js b/test/parallel/test-quic-errors-quicsocket-connect.js index 7b545a4ad40a41..2713c0ec4af5f8 100644 --- a/test/parallel/test-quic-errors-quicsocket-connect.js +++ b/test/parallel/test-quic-errors-quicsocket-connect.js @@ -131,12 +131,6 @@ const client = createQuicSocket(); }); }); -['a', 1n, 1, [], {}].forEach((ipv6Only) => { - assert.throws(() => client.connect({ ipv6Only }), { - code: 'ERR_INVALID_ARG_TYPE' - }); -}); - [1, 1n, false, [], {}].forEach((preferredAddressPolicy) => { assert.throws(() => client.connect({ preferredAddressPolicy }), { code: 'ERR_INVALID_ARG_TYPE' @@ -202,7 +196,6 @@ assert.throws(() => client.connect(), { // Client QuicSession Related: // // [x] idleTimeout - must be a number greater than zero -// [x] ipv6Only - must be a boolean // [x] activeConnectionIdLimit - must be a number between 2 and 8 // [x] maxAckDelay - must be a number greater than zero // [x] maxData - must be a number greater than zero diff --git a/test/parallel/test-quic-errors-quicsocket-create.js b/test/parallel/test-quic-errors-quicsocket-create.js index 64c27a50f2701a..570f02b1a95661 100644 --- a/test/parallel/test-quic-errors-quicsocket-create.js +++ b/test/parallel/test-quic-errors-quicsocket-create.js @@ -47,13 +47,6 @@ const { createQuicSocket } = require('net'); }); }); -// Test invalid QuicSocket ipv6Only argument option -[1, NaN, 1n, null, {}, []].forEach((ipv6Only) => { - assert.throws(() => createQuicSocket({ endpoint: { ipv6Only } }), { - code: 'ERR_INVALID_ARG_TYPE' - }); -}); - // Test invalid QuicSocket reuseAddr argument option [1, NaN, 1n, null, {}, []].forEach((reuseAddr) => { assert.throws(() => createQuicSocket({ endpoint: { reuseAddr } }), { diff --git a/test/parallel/test-quic-ipv6only.js b/test/parallel/test-quic-ipv6only.js index 4c6695804e3231..5b4a23dd66efbe 100644 --- a/test/parallel/test-quic-ipv6only.js +++ b/test/parallel/test-quic-ipv6only.js @@ -19,29 +19,10 @@ const { once } = require('events'); const kALPN = 'zzz'; -// Setting `type` to `udp4` while setting `ipv6Only` to `true` is possible. -// The ipv6Only setting will be ignored. -async function ipv4() { - const server = createQuicSocket({ - endpoint: { - type: 'udp4', - ipv6Only: true - } - }); - server.on('error', common.mustNotCall()); - server.listen({ key, cert, ca, alpn: kALPN }); - await once(server, 'ready'); - server.close(); -} - // Connecting to ipv6 server using "127.0.0.1" should work when // `ipv6Only` is set to `false`. async function ipv6() { - const server = createQuicSocket({ - endpoint: { - type: 'udp6', - ipv6Only: false - } }); + const server = createQuicSocket({ endpoint: { type: 'udp6' } }); const client = createQuicSocket({ client: { key, cert, ca, alpn: kALPN } }); server.listen({ key, cert, ca, alpn: kALPN }); @@ -54,8 +35,7 @@ async function ipv6() { const session = client.connect({ address: common.localhostIPv4, - port: server.endpoints[0].address.port, - ipv6Only: true, + port: server.endpoints[0].address.port }); await once(session, 'secure'); @@ -77,11 +57,7 @@ async function ipv6() { // When the `ipv6Only` set to `true`, a client cann't connect to it // through "127.0.0.1". async function ipv6Only() { - const server = createQuicSocket({ - endpoint: { - type: 'udp6', - ipv6Only: true - } }); + const server = createQuicSocket({ endpoint: { type: 'udp6-only' } }); const client = createQuicSocket({ client: { key, cert, ca, alpn: kALPN } }); server.listen({ key, cert, ca, alpn: kALPN }); @@ -95,7 +71,6 @@ async function ipv6Only() { address: common.localhostIPv4, port: server.endpoints[0].address.port, idleTimeout: common.platformTimeout(1), - ipv6Only: true, }); session.on('secure', common.mustNotCall()); @@ -144,8 +119,7 @@ async function mismatch() { ]); } -ipv4() - .then(ipv6) +ipv6() .then(ipv6Only) .then(mismatch) .then(common.mustCall()); From 63b79fd6c7f269e71cae5da350a337e704da34f5 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Thu, 9 Jul 2020 12:34:28 -0700 Subject: [PATCH 02/18] quic: minor reduction in code duplication --- doc/api/quic.md | 6 ++++++ lib/internal/quic/core.js | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/doc/api/quic.md b/doc/api/quic.md index 0c8f73a0e5c8d1..b21d432642580b 100644 --- a/doc/api/quic.md +++ b/doc/api/quic.md @@ -255,6 +255,8 @@ added: REPLACEME * `options` {Object} * `client` {Object} A default configuration for QUIC client sessions created using `quicsocket.connect()`. + * `disableStatelessReset` {boolean} When `true` the `QuicSocket` will not + send stateless resets. **Default**: `false`. * `endpoint` {Object} An object describing the local address to bind to. * `address` {string} The local address to bind to. This may be an IPv4 or IPv6 address or a host name. If a host name is given, it will be resolved @@ -276,6 +278,10 @@ added: REPLACEME * `retryTokenTimeout` {number} The maximum number of *seconds* for retry token validation. Default: `10` seconds. * `server` {Object} A default configuration for QUIC server sessions. + * `statelessResetSecret` {Buffer|Uint8Array} A 16-byte `Buffer` or + `Uint8Array` providing the secret to use when generating stateless reset + tokens. If not specified, a random secret will be generated for the + `QuicSocket`. **Default**: `undefined`. * `validateAddress` {boolean} When `true`, the `QuicSocket` will use explicit address validation using a QUIC `RETRY` frame when listening for new server sessions. Default: `false`. diff --git a/lib/internal/quic/core.js b/lib/internal/quic/core.js index 908e01b625b665..9995b935b1c17c 100644 --- a/lib/internal/quic/core.js +++ b/lib/internal/quic/core.js @@ -581,6 +581,14 @@ function getStats(obj, idx) { return stats[idx]; } +function addressOrLocalhost(address, type) { + return address || (type === AF_INET6 ? '::' : '0.0.0.0'); +} + +function lookupOrDefault(lookup, type) { + return lookup || (type === AF_INET6 ? lookup6 : lookup4); +} + // QuicEndpoint wraps a UDP socket and is owned // by a QuicSocket. It does not exist independently // of the QuicSocket. @@ -610,9 +618,9 @@ class QuicEndpoint { } = validateQuicEndpointOptions(options); const state = this[kInternalState]; state.socket = socket; - state.address = address || (type === AF_INET6 ? '::' : '0.0.0.0'); + state.address = addressOrLocalhost(address, type); + state.lookup = lookupOrDefault(lookup, type); state.ipv6Only = ipv6Only; - state.lookup = lookup || (type === AF_INET6 ? lookup6 : lookup4); state.port = port; state.reuseAddr = reuseAddr; state.type = type; @@ -901,8 +909,8 @@ class QuicSocket extends EventEmitter { const state = this[kInternalState]; state.client = client; - state.lookup = lookup || (type === AF_INET6 ? lookup6 : lookup4); state.server = server; + state.lookup = lookupOrDefault(lookup, type); let socketOptions = 0; if (validateAddress) @@ -1286,7 +1294,7 @@ class QuicSocket extends EventEmitter { // Notice here that connectAfterLookup is bound to the QuicSession // that was created... lookup( - address || (type === AF_INET6 ? '::' : '0.0.0.0'), + addressOrLocalhost(address, type), connectAfterLookup.bind(session, type)); } From cc4674d34100efd9c90d1a2f29f8afc9f6a34f5c Mon Sep 17 00:00:00 2001 From: James M Snell Date: Thu, 9 Jul 2020 12:43:51 -0700 Subject: [PATCH 03/18] quic: clarifying code comments --- lib/internal/quic/core.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/internal/quic/core.js b/lib/internal/quic/core.js index 9995b935b1c17c..04ff53e6a4483e 100644 --- a/lib/internal/quic/core.js +++ b/lib/internal/quic/core.js @@ -717,6 +717,13 @@ class QuicEndpoint { this[kHandle] = undefined; handle[owner_symbol] = undefined; + // Calling waitForPendingCallbacks starts the process of + // closing down the QuicEndpoint. Once all pending writes + // to the underlying libuv udp handle have completed, the + // ondone callback will be invoked, triggering the UDP + // socket to be closed. Once it is closed, we notify + // the QuicSocket that this QuicEndpoint has been closed, + // allowing it to be freed. handle.ondone = () => { state.udpSocket.close((err) => { if (err) error = err; @@ -747,6 +754,7 @@ class QuicEndpoint { return {}; } + // On Windows, this always returns undefined. get fd() { return this[kInternalState].fd >= 0 ? this[kInternalState].fd : undefined; From 99b37e021468a606ccd92f0f5b89bf789937493e Mon Sep 17 00:00:00 2001 From: James M Snell Date: Thu, 9 Jul 2020 13:22:06 -0700 Subject: [PATCH 04/18] quic: use a getter for stream options Doesn't need to be a function --- lib/internal/quic/core.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/internal/quic/core.js b/lib/internal/quic/core.js index 04ff53e6a4483e..bbddf0851d0c48 100644 --- a/lib/internal/quic/core.js +++ b/lib/internal/quic/core.js @@ -214,7 +214,6 @@ const kContinueBind = Symbol('kContinueBind'); const kDestroy = Symbol('kDestroy'); const kEndpointBound = Symbol('kEndpointBound'); const kEndpointClose = Symbol('kEndpointClose'); -const kGetStreamOptions = Symbol('kGetStreamOptions'); const kHandshake = Symbol('kHandshake'); const kHandshakePost = Symbol('kHandshakePost'); const kHeaders = Symbol('kHeaders'); @@ -237,6 +236,7 @@ const kSetSocket = Symbol('kSetSocket'); const kSetSocketAfterBind = Symbol('kSetSocketAfterBind'); const kStartFilePipe = Symbol('kStartFilePipe'); const kStreamClose = Symbol('kStreamClose'); +const kStreamOptions = Symbol('kStreamOptions'); const kStreamReset = Symbol('kStreamReset'); const kTrackWriteState = Symbol('kTrackWriteState'); const kUDPHandleForTesting = Symbol('kUDPHandleForTesting'); @@ -277,7 +277,7 @@ function onSessionReady(handle) { new QuicServerSession( socket, handle, - socket[kGetStreamOptions]()); + socket[kStreamOptions]); try { socket.emit('session', session); } catch (error) { @@ -475,7 +475,7 @@ function onStreamReady(streamHandle, id, push_id) { const { highWaterMark, defaultEncoding, - } = session[kGetStreamOptions](); + } = session[kStreamOptions]; const stream = new QuicStream({ writable: !uni, highWaterMark, @@ -965,7 +965,7 @@ class QuicSocket extends EventEmitter { // Returns the default QuicStream options for peer-initiated // streams. These are passed on to new client and server // QuicSession instances when they are created. - [kGetStreamOptions]() { + get [kStreamOptions]() { const state = this[kInternalState]; return { highWaterMark: state.highWaterMark, @@ -1685,9 +1685,9 @@ class QuicSession extends EventEmitter { socket[kAddSession](this); } - // kGetStreamOptions is called to get the configured options - // for peer initiated QuicStream instances. - [kGetStreamOptions]() { + // Used to get the configured options for peer initiated QuicStream + // instances. + get [kStreamOptions]() { const state = this[kInternalState]; return { highWaterMark: state.highWaterMark, From 7297f7025c5438f23eb92ce5beef01a82ccaee7a Mon Sep 17 00:00:00 2001 From: James M Snell Date: Thu, 9 Jul 2020 13:40:23 -0700 Subject: [PATCH 05/18] quic: restrict addEndpoint to before QuicSocket bind Restricting this to pre-bind keeps things simple --- doc/api/quic.md | 5 ++++- lib/internal/quic/core.js | 15 ++++++--------- test/parallel/test-quic-quicendpoint-address.js | 5 +++++ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/doc/api/quic.md b/doc/api/quic.md index b21d432642580b..d16b0a853e19fa 100644 --- a/doc/api/quic.md +++ b/doc/api/quic.md @@ -1458,7 +1458,10 @@ added: REPLACEME **Default**: `'udp4'`. * Returns: {QuicEndpoint} -Creates and adds a new `QuicEndpoint` to the `QuicSocket` instance. +Creates and adds a new `QuicEndpoint` to the `QuicSocket` instance. An +error will be thrown if `quicsock.addEndpoint()` is called either after +the `QuicSocket` has already started binding to the local ports or after +the `QuicSocket` has been destroyed. #### quicsocket.bound + +Emitted after a `QuicEndpoint` associated witht the `QuicSocket` closes and +has been destroyed. The handler will be invoked with two arguments: + +* `endpoint` {QuicEndpoint} The `QuicEndpoint` that has been destroyed. +* `error` {Error} An `Error` object if the `QuicEndpoint` was destroyed because + of an error. + +When all of the `QuicEndpoint` instances associated with a `QuicSocket` have +closed, the `QuicEndpoint` will also automatically close. + #### Event: `'error'` + +Binds the `QuicEndpoint` if it has not already been bound. User code will +not typically be responsible for binding a `QuicEndpoint` as the owning +`QuicSocket` will do that automatically. + +* `options` {object} + * `signal` {AbortSignal} Optionally allows the `bind()` to be canceled + using an `AbortController`. +* Returns: {Promise} + +The `quicendpoint.bind()` function returns `Promise` that will be resolved +with the address once the bind operation is successful. + +If the `QuicEndpoint` has been destroyed, or is destroyed while the `Promise` +is pending, the `Promise` will be rejected with an `ERR_INVALID_STATE` error. + +If an `AbortSignal` is specified in the `options` and it is triggered while +the `Promise` is pending, the `Promise` will be rejected with an `AbortError`. + +If `quicendpoint.bind()` is called again while a previously returned `Promise` +is still pending or has already successfully resolved, the previously returned +pending `Promise` will be returned. If the additional call to +`quicendpoint.bind()` contains an `AbortSignal`, the `signal` will be ignored. + #### quicendpoint.bound + +Closes and destroys the `QuicEndpoint`. Returns a `Promise` that is resolved +once the `QuicEndpoint` has been destroyed, or rejects if the `QuicEndpoint` +is destroyed with an error. + +* Returns: {Promise} + +The `Promise` cannot be canceled. Once `quicendpoint.close()` is called, the +`QuicEndpoint` will be destroyed. + #### quicendpoint.closing * `socket` {QuicSocket} A `QuicSocket` instance to move this session to. -* `callback` {Function} A callback function that will be invoked once the - migration to the new `QuicSocket` is complete. +* Returns: {Promise} Migrates the `QuicClientSession` to the given `QuicSocket` instance. If the new `QuicSocket` has not yet been bound to a local UDP port, it will be bound prior -to attempting the migration. If the `QuicClientSession` is not yet ready to -migrate, the callback will be invoked with an `Error` using the code -`ERR_OPERATION_FAILED`. +to attempting the migration. ### Class: QuicServerSession extends QuicSession @@ -1877,13 +1882,10 @@ added: REPLACEME [OpenSSL Options][]. * `sessionIdContext` {string} Opaque identifier used by servers to ensure session state is not shared between applications. Unused by clients. +* Returns: {Promise} -* `callback` {Function} - -Listen for new peer-initiated sessions. - -If a `callback` is given, it is registered as a handler for the -`'session'` event. +Listen for new peer-initiated sessions. Returns a `Promise` that is resolved +once the `QuicSocket` is actively listening. #### quicsocket.listenDuration -* Type: {number} - -The number of stateless resets that have been sent. +* Type: {boolean} `true` if stateless reset processing is enabled; `false` + if disabled. -Read-only. +By default, a listening `QuicSocket` will generate stateless reset tokens when +appropriate. The `disableStatelessReset` option may be set when the +`QuicSocket` is created to disable generation of stateless resets. The +`quicsocket.statelessReset` property allows stateless reset to be turned on and +off dynamically through the lifetime of the `QuicSocket`. -#### quicsocket.toggleStatelessReset() +#### quicsocket.statelessResetCount -* Returns {boolean} `true` if stateless reset processing is enabled; `false` - if disabled. +* Type: {number} -By default, a listening `QuicSocket` will generate stateless reset tokens when -appropriate. The `disableStatelessReset` option may be set when the -`QuicSocket` is created to disable generation of stateless resets. The -`toggleStatelessReset()` function allows stateless reset to be turned on and -off dynamically through the lifetime of the `QuicSocket`. +The number of stateless resets that have been sent. + +Read-only. #### quicsocket.unref(); -* `callback` {Function} +* Returns: {Promise} Gracefully closes the `QuicSocket`. Existing `QuicSession` instances will be permitted to close naturally. New `QuicClientSession` and `QuicServerSession` -instances will not be allowed. +instances will not be allowed. The returns `Promise` will be resolved once +the `QuicSocket` is destroyed. #### quicsocket.connect(\[options\]) - -* Type: {boolean} - -Set to `true` if the `QuicClientSession` is ready for use. False if the -`QuicSocket` has not yet been bound. - #### quicclientsession.setSocket(socket]) -* `callback` {Function} Callback invoked when the close operation is completed - Begins a graceful close of the `QuicSession`. Existing `QuicStream` instances will be permitted to close naturally. New `QuicStream` instances will not be permitted. Once all `QuicStream` instances have closed, the `QuicSession` -instance will be destroyed. +instance will be destroyed. Returns a `Promise` that is resolved once the +`QuicSession` instance is destroyed. #### quicsession.closeCode @@ -299,7 +299,7 @@ added: REPLACEME The `net.createQuicSocket()` function is used to create new `QuicSocket` instances associated with a local UDP address. -### Class: QuicEndpoint +### Class: `QuicEndpoint` @@ -310,7 +310,7 @@ and receive data. A single `QuicSocket` may be bound to multiple Users will not create instances of `QuicEndpoint` directly. -#### quicendpoint.addMembership(address, iface) +#### `quicendpoint.addMembership(address, iface)` @@ -325,7 +325,7 @@ choose one interface and will add membership to it. To add membership to every available interface, call `addMembership()` multiple times, once per interface. -#### quicendpoint.address +#### `quicendpoint.address` @@ -343,9 +343,9 @@ The object will contain the properties: If the `QuicEndpoint` is not bound, `quicendpoint.address` is an empty object. -#### quicendpoint.bind(\[options\]) +#### `quicendpoint.bind(\[options\])` Binds the `QuicEndpoint` if it has not already been bound. User code will @@ -371,7 +371,7 @@ is still pending or has already successfully resolved, the previously returned pending `Promise` will be returned. If the additional call to `quicendpoint.bind()` contains an `AbortSignal`, the `signal` will be ignored. -#### quicendpoint.bound +#### `quicendpoint.bound` @@ -380,7 +380,7 @@ added: REPLACEME Set to `true` if the `QuicEndpoint` is bound to the local UDP port. -#### quicendpoint.close() +#### `quicendpoint.close()` @@ -394,7 +394,7 @@ is destroyed with an error. The `Promise` cannot be canceled. Once `quicendpoint.close()` is called, the `QuicEndpoint` will be destroyed. -#### quicendpoint.closing +#### `quicendpoint.closing` @@ -403,7 +403,7 @@ added: REPLACEME Set to `true` if the `QuicEndpoint` is in the process of closing. -#### quicendpoint.destroy(\[error\]) +#### `quicendpoint.destroy(\[error\])` @@ -412,7 +412,7 @@ added: REPLACEME Closes and destroys the `QuicEndpoint` instance making it usuable. -#### quicendpoint.destroyed +#### `quicendpoint.destroyed` @@ -421,7 +421,7 @@ added: REPLACEME Set to `true` if the `QuicEndpoint` has been destroyed. -#### quicendpoint.dropMembership(address, iface) +#### `quicendpoint.dropMembership(address, iface)` @@ -437,7 +437,7 @@ never have reason to call this. If `multicastInterface` is not specified, the operating system will attempt to drop membership on all valid interfaces. -#### quicendpoint.fd +#### `quicendpoint.fd` @@ -447,7 +447,7 @@ added: REPLACEME The system file descriptor the `QuicEndpoint` is bound to. This property is not set on Windows. -#### quicendpoint.pending +#### `quicendpoint.pending` @@ -457,12 +457,12 @@ added: REPLACEME Set to `true` if the `QuicEndpoint` is in the process of binding to the local UDP port. -#### quicendpoint.ref() +#### `quicendpoint.ref()` -#### quicendpoint.setBroadcast(\[on\]) +#### `quicendpoint.setBroadcast(\[on\])` @@ -472,7 +472,7 @@ added: REPLACEME Sets or clears the `SO_BROADCAST` socket option. When set to `true`, UDP packets may be sent to a local interface's broadcast address. -#### quicendpoint.setMulticastInterface(iface) +#### `quicendpoint.setMulticastInterface(iface)` @@ -559,7 +559,7 @@ A socket's address family's ANY address (IPv4 `'0.0.0.0'` or IPv6 `'::'`) can be used to return control of the sockets default outgoing interface to the system for future multicast packets. -#### quicendpoint.setMulticastLoopback(\[on\]) +#### `quicendpoint.setMulticastLoopback(\[on\])` @@ -569,7 +569,7 @@ added: REPLACEME Sets or clears the `IP_MULTICAST_LOOP` socket option. When set to `true`, multicast packets will also be received on the local interface. -#### quicendpoint.setMulticastTTL(ttl) +#### `quicendpoint.setMulticastTTL(ttl)` @@ -585,7 +585,7 @@ decremented to `0` by a router, it will not be forwarded. The argument passed to `setMulticastTTL()` is a number of hops between `0` and `255`. The default on most systems is `1` but can vary. -#### quicendpoint.setTTL(ttl) +#### `quicendpoint.setTTL(ttl)` @@ -601,12 +601,12 @@ Changing TTL values is typically done for network probes or when multicasting. The argument to `setTTL()` is a number of hops between `1` and `255`. The default on most systems is `64` but can vary. -#### quicendpoint.unref() +#### `quicendpoint.unref()` -### Class: QuicSession extends EventEmitter +### Class: `QuicSession extends EventEmitter` @@ -712,7 +712,7 @@ Emitted when a new `QuicStream` has been initiated by the connected peer. The `'stream'` event may be emitted multiple times. -#### quicsession.ackDelayRetransmitCount +#### `quicsession.ackDelayRetransmitCount` @@ -721,7 +721,7 @@ added: REPLACEME The number of retransmissions caused by delayed acknowledgements. -#### quicsession.address +#### `quicsession.address` @@ -735,7 +735,7 @@ added: REPLACEME An object containing the local address information for the `QuicSocket` to which the `QuicSession` is currently associated. -#### quicsession.alpnProtocol +#### `quicsession.alpnProtocol` @@ -744,7 +744,7 @@ added: REPLACEME The ALPN protocol identifier negotiated for this session. -#### quicsession.authenticated +#### `quicsession.authenticated` @@ -753,14 +753,14 @@ added: REPLACEME True if the certificate provided by the peer during the TLS 1.3 handshake has been verified. -#### quicsession.authenticationError +#### `quicsession.authenticationError` * Type: {Object} An error object If `quicsession.authenticated` is false, returns an `Error` object representing the reason the peer certificate verification failed. -#### quicsession.bidiStreamCount +#### `quicsession.bidiStreamCount` @@ -769,7 +769,7 @@ added: REPLACEME The total number of bidirectional streams created for this `QuicSession`. -#### quicsession.blockCount +#### `quicsession.blockCount` @@ -782,7 +782,7 @@ stream data due to flow control. Such blocks indicate that transmitted stream data is not being consumed quickly enough by the connected peer. -#### quicsession.bytesInFlight +#### `quicsession.bytesInFlight` @@ -792,7 +792,7 @@ added: REPLACEME The total number of unacknowledged bytes this QUIC endpoint has transmitted to the connected peer. -#### quicsession.bytesReceived +#### `quicsession.bytesReceived` @@ -801,7 +801,7 @@ added: REPLACEME The total number of bytes received from the peer. -#### quicsession.bytesSent +#### `quicsession.bytesSent` @@ -810,7 +810,7 @@ added: REPLACEME The total number of bytes sent to the peer. -#### quicsession.cipher +#### `quicsession.cipher` @@ -821,7 +821,7 @@ added: REPLACEME Information about the cipher algorithm selected for the session. -#### quicsession.close() +#### `quicsession.close()` @@ -832,7 +832,7 @@ permitted. Once all `QuicStream` instances have closed, the `QuicSession` instance will be destroyed. Returns a `Promise` that is resolved once the `QuicSession` instance is destroyed. -#### quicsession.closeCode +#### `quicsession.closeCode` @@ -842,7 +842,7 @@ added: REPLACEME protocol level error, `1` indicates a TLS error, `2` represents an application level error.) -#### quicsession.closing +#### `quicsession.closing` @@ -851,7 +851,7 @@ added: REPLACEME Set to `true` if the `QuicSession` is in the process of a graceful shutdown. -#### quicsession.destroy(\[error\]) +#### `quicsession.destroy(\[error\])` @@ -864,7 +864,7 @@ before the `close` event. Any `QuicStream` instances that are still opened will be abruptly closed. -#### quicsession.destroyed +#### `quicsession.destroyed` @@ -873,7 +873,7 @@ added: REPLACEME Set to `true` if the `QuicSession` has been destroyed. -#### quicsession.duration +#### `quicsession.duration` @@ -882,7 +882,7 @@ added: REPLACEME The length of time the `QuicSession` was active. -#### quicsession.getCertificate() +#### `quicsession.getCertificate()` @@ -895,7 +895,7 @@ some properties corresponding to the fields of the certificate. If there is no local certificate, or if the `QuicSession` has been destroyed, an empty object will be returned. -#### quicsession.getPeerCertificate(\[detailed\]) +#### `quicsession.getPeerCertificate(\[detailed\])` @@ -912,21 +912,21 @@ If the full certificate chain was requested (`details` equals `true`), each certificate will include an `issuerCertificate` property containing an object representing the issuer's certificate. -#### quicsession.handshakeAckHistogram +#### `quicsession.handshakeAckHistogram` TBD -#### quicsession.handshakeContinuationHistogram +#### `quicsession.handshakeContinuationHistogram` TBD -#### quicsession.handshakeComplete +#### `quicsession.handshakeComplete` @@ -935,7 +935,7 @@ added: REPLACEME Set to `true` if the TLS handshake has completed. -#### quicsession.handshakeConfirmed +#### `quicsession.handshakeConfirmed` @@ -944,7 +944,7 @@ added: REPLACEME Set to `true` when the TLS handshake completion has been confirmed. -#### quicsession.handshakeDuration +#### `quicsession.handshakeDuration` @@ -953,7 +953,7 @@ added: REPLACEME The length of time taken to complete the TLS handshake. -#### quicsession.idleTimeout +#### `quicsession.idleTimeout` @@ -962,7 +962,7 @@ added: REPLACEME Set to `true` if the `QuicSession` was closed due to an idle timeout. -#### quicsession.keyUpdateCount +#### `quicsession.keyUpdateCount` @@ -971,7 +971,7 @@ added: REPLACEME The number of key update operations that have occured. -#### quicsession.latestRTT +#### `quicsession.latestRTT` @@ -980,7 +980,7 @@ added: REPLACEME The most recently recorded RTT for this `QuicSession`. -#### quicsession.lossRetransmitCount +#### `quicsession.lossRetransmitCount` @@ -990,7 +990,7 @@ added: REPLACEME The number of lost-packet retransmissions that have been performed on this `QuicSession`. -#### quicsession.maxDataLeft +#### `quicsession.maxDataLeft` @@ -1000,7 +1000,7 @@ added: REPLACEME The total number of bytes the `QuicSession` is *currently* allowed to send to the connected peer. -#### quicsession.maxInFlightBytes +#### `quicsession.maxInFlightBytes` @@ -1009,7 +1009,7 @@ added: REPLACEME The maximum number of in-flight bytes recorded for this `QuicSession`. -#### quicsession.maxStreams +#### `quicsession.maxStreams` @@ -1023,7 +1023,7 @@ that can currently be opened. The values are set initially by configuration parameters when the `QuicSession` is created, then updated over the lifespan of the `QuicSession` as the connected peer allows new streams to be created. -#### quicsession.minRTT +#### `quicsession.minRTT` @@ -1032,7 +1032,7 @@ added: REPLACEME The minimum RTT recorded so far for this `QuicSession`. -#### quicsession.openStream(\[options\]) +#### `quicsession.openStream(\[options\])` @@ -1052,7 +1052,7 @@ Returns a new `QuicStream`. An error will be thrown if the `QuicSession` has been destroyed or is in the process of a graceful shutdown. -#### quicsession.ping() +#### `quicsession.ping()` @@ -1065,7 +1065,7 @@ that ignores any errors that may occur during the serialization and send operations. There is no return value and there is no way to monitor the status of the `ping()` operation. -#### quicsession.peerInitiatedStreamCount +#### `quicsession.peerInitiatedStreamCount` @@ -1074,7 +1074,7 @@ added: REPLACEME The total number of `QuicStreams` initiated by the connected peer. -#### quicsession.qlog +#### `quicsession.qlog` @@ -1087,7 +1087,7 @@ data according to the [qlog standard][]. For client `QuicSessions`, the `quicsession.qlog` property will be `undefined` untilt the `'qlog'` event is emitted. -#### quicsession.remoteAddress +#### `quicsession.remoteAddress` @@ -1100,7 +1100,7 @@ added: REPLACEME An object containing the remote address information for the connected peer. -#### quicsession.selfInitiatedStreamCount +#### `quicsession.selfInitiatedStreamCount` @@ -1109,7 +1109,7 @@ added: REPLACEME The total number of `QuicStream` instances initiated by this `QuicSession`. -#### quicsession.servername +#### `quicsession.servername` @@ -1118,7 +1118,7 @@ added: REPLACEME The SNI servername requested for this session by the client. -#### quicsession.smoothedRTT +#### `quicsession.smoothedRTT` @@ -1127,7 +1127,7 @@ added: REPLACEME The modified RTT calculated for this `QuicSession`. -#### quicsession.socket +#### `quicsession.socket` @@ -1136,7 +1136,7 @@ added: REPLACEME The `QuicSocket` the `QuicSession` is associated with. -#### quicsession.statelessReset +#### `quicsession.statelessReset` @@ -1145,7 +1145,7 @@ added: REPLACEME True if the `QuicSession` was closed due to QUIC stateless reset. -#### quicsession.uniStreamCount +#### `quicsession.uniStreamCount` @@ -1154,7 +1154,7 @@ added: REPLACEME The total number of unidirectional streams created on this `QuicSession`. -#### quicsession.updateKey() +#### `quicsession.updateKey()` @@ -1167,7 +1167,7 @@ Initiates QuicSession key update. An error will be thrown if called before `quicsession.handshakeConfirmed` is equal to `true`. -#### quicsession.usingEarlyData +#### `quicsession.usingEarlyData` @@ -1179,7 +1179,7 @@ handshake if early data is enabled. On client `QuicSession` instances, set to true on handshake completion if early data is enabled *and* was accepted by the server. -### Class: QuicClientSession extends QuicSession +### Class: `QuicClientSession extends QuicSession` @@ -1254,7 +1254,7 @@ This event is purely informational and will be emitted only when The `'usePreferredAddress'` event will not be emitted more than once. -#### quicclientsession.ephemeralKeyInfo +#### `quicclientsession.ephemeralKeyInfo` @@ -1269,7 +1269,7 @@ empty object when the key exchange is not ephemeral. The supported types are For example: `{ type: 'ECDH', name: 'prime256v1', size: 256 }`. -#### quicclientsession.setSocket(socket]) +#### `quicclientsession.setSocket(socket])` @@ -1281,7 +1281,7 @@ Migrates the `QuicClientSession` to the given `QuicSocket` instance. If the new `QuicSocket` has not yet been bound to a local UDP port, it will be bound prior to attempting the migration. -### Class: QuicServerSession extends QuicSession +### Class: `QuicServerSession extends QuicSession` @@ -1332,7 +1332,7 @@ The callback *must* be invoked in order for the TLS handshake to continue. The `'OCSPRequest'` event will not be emitted more than once. -#### quicserversession.addContext(servername\[, context\]) +#### `quicserversession.addContext(servername\[, context\])` @@ -1342,7 +1342,7 @@ added: REPLACEME TBD -### Class: QuicSocket +### Class: `QuicSocket` @@ -1392,7 +1392,7 @@ The `'close'` event will only ever be emitted once. added: REPLACEME --> -Emitted after a `QuicEndpoint` associated witht the `QuicSocket` closes and +Emitted after a `QuicEndpoint` associated with the `QuicSocket` closes and has been destroyed. The handler will be invoked with two arguments: * `endpoint` {QuicEndpoint} The `QuicEndpoint` that has been destroyed. @@ -1492,7 +1492,7 @@ server.on('sessionError', (error, session) => { }); ``` -#### quicsocket.addEndpoint(options) +#### `quicsocket.addEndpoint(options)` @@ -1514,7 +1514,7 @@ error will be thrown if `quicsock.addEndpoint()` is called either after the `QuicSocket` has already started binding to the local ports, or after the `QuicSocket` has been destroyed. -#### quicsocket.bound +#### `quicsocket.bound` @@ -1531,7 +1531,7 @@ event will be emitted once the `QuicSocket` has been bound and the value of Read-only. -#### quicsocket.boundDuration +#### `quicsocket.boundDuration` @@ -1542,7 +1542,7 @@ The length of time this `QuicSocket` has been bound to a local port. Read-only. -#### quicsocket.bytesReceived +#### `quicsocket.bytesReceived` @@ -1553,7 +1553,7 @@ The number of bytes received by this `QuicSocket`. Read-only. -#### quicsocket.bytesSent +#### `quicsocket.bytesSent` @@ -1564,7 +1564,7 @@ The number of bytes sent by this `QuicSocket`. Read-only. -#### quicsocket.clientSessions +#### `quicsocket.clientSessions` @@ -1576,7 +1576,7 @@ with this `QuicSocket`. Read-only. -#### quicsocket.close() +#### `quicsocket.close()` @@ -1588,7 +1588,7 @@ permitted to close naturally. New `QuicClientSession` and `QuicServerSession` instances will not be allowed. The returns `Promise` will be resolved once the `QuicSocket` is destroyed. -#### quicsocket.connect(\[options\]) +#### `quicsocket.connect(\[options\])` @@ -1722,7 +1722,7 @@ added: REPLACEME Returns a `Promise` that resolves a new `QuicClientSession`. -#### quicsocket.destroy(\[error\]) +#### `quicsocket.destroy(\[error\])` @@ -1732,7 +1732,7 @@ added: REPLACEME Destroys the `QuicSocket` then emits the `'close'` event when done. The `'error'` event will be emitted after `'close'` if the `error` is not `undefined`. -#### quicsocket.destroyed +#### `quicsocket.destroyed` @@ -1743,7 +1743,7 @@ Will be `true` if the `QuicSocket` has been destroyed. Read-only. -#### quicsocket.duration +#### `quicsocket.duration` @@ -1754,7 +1754,7 @@ The length of time this `QuicSocket` has been active, Read-only. -#### quicsocket.endpoints +#### `quicsocket.endpoints` @@ -1765,7 +1765,7 @@ An array of `QuicEndpoint` instances associated with the `QuicSocket`. Read-only. -#### quicsocket.listen(\[options\]) +#### `quicsocket.listen(\[options\])` @@ -1884,7 +1884,7 @@ added: REPLACEME Listen for new peer-initiated sessions. Returns a `Promise` that is resolved once the `QuicSocket` is actively listening. -#### quicsocket.listenDuration +#### `quicsocket.listenDuration` @@ -1895,7 +1895,7 @@ The length of time this `QuicSocket` has been listening for connections. Read-only -#### quicsocket.listening +#### `quicsocket.listening` @@ -1906,7 +1906,7 @@ Set to `true` if the `QuicSocket` is listening for new connections. Read-only. -#### quicsocket.packetsIgnored +#### `quicsocket.packetsIgnored` @@ -1917,7 +1917,7 @@ The number of packets received by this `QuicSocket` that have been ignored. Read-only. -#### quicsocket.packetsReceived +#### `quicsocket.packetsReceived` @@ -1928,7 +1928,7 @@ The number of packets successfully received by this `QuicSocket`. Read-only -#### quicsocket.packetsSent +#### `quicsocket.packetsSent` @@ -1939,7 +1939,7 @@ The number of packets sent by this `QuicSocket`. Read-only -#### quicsocket.pending +#### `quicsocket.pending` @@ -1950,12 +1950,12 @@ Set to `true` if the socket is not yet bound to the local UDP port. Read-only. -#### quicsocket.ref() +#### `quicsocket.ref()` -#### quicsocket.serverBusy +#### `quicsocket.serverBusy` @@ -1967,7 +1967,7 @@ to reject all new incoming connection requests using the `SERVER_BUSY` QUIC error code. To begin receiving connections again, disable busy mode by setting `quicsocket.serverBusy = false`. -#### quicsocket.serverBusyCount +#### `quicsocket.serverBusyCount` @@ -1978,7 +1978,7 @@ The number of `QuicSession` instances rejected due to server busy status. Read-only. -#### quicsocket.serverSessions +#### `quicsocket.serverSessions` @@ -1990,7 +1990,7 @@ this `QuicSocket`. Read-only. -#### quicsocket.setDiagnosticPacketLoss(options) +#### `quicsocket.setDiagnosticPacketLoss(options)` @@ -2007,7 +2007,7 @@ by artificially dropping received or transmitted packets. This method is *not* to be used in production applications. -#### quicsocket.statelessReset +#### `quicsocket.statelessReset` @@ -2021,7 +2021,7 @@ appropriate. The `disableStatelessReset` option may be set when the `quicsocket.statelessReset` property allows stateless reset to be turned on and off dynamically through the lifetime of the `QuicSocket`. -#### quicsocket.statelessResetCount +#### `quicsocket.statelessResetCount` @@ -2032,12 +2032,12 @@ The number of stateless resets that have been sent. Read-only. -#### quicsocket.unref(); +#### `quicsocket.unref();` -### Class: QuicStream extends stream.Duplex +### Class: `QuicStream extends stream.Duplex` @@ -2153,7 +2153,7 @@ stream('trailingHeaders', (headers) => { added: REPLACEME --> -#### quicstream.aborted +#### `quicstream.aborted` @@ -2161,7 +2161,7 @@ added: REPLACEME True if dataflow on the `QuicStream` was prematurely terminated. -#### quicstream.bidirectional +#### `quicstream.bidirectional` @@ -2170,7 +2170,7 @@ added: REPLACEME Set to `true` if the `QuicStream` is bidirectional. -#### quicstream.bytesReceived +#### `quicstream.bytesReceived` @@ -2179,7 +2179,7 @@ added: REPLACEME The total number of bytes received for this `QuicStream`. -#### quicstream.bytesSent +#### `quicstream.bytesSent` @@ -2188,7 +2188,7 @@ added: REPLACEME The total number of bytes sent by this `QuicStream`. -#### quicstream.clientInitiated +#### `quicstream.clientInitiated` @@ -2198,7 +2198,7 @@ added: REPLACEME Set to `true` if the `QuicStream` was initiated by a `QuicClientSession` instance. -#### quicstream.close(code) +#### `quicstream.close(code)` @@ -2207,27 +2207,27 @@ added: REPLACEME Closes the `QuicStream`. -#### quicstream.dataAckHistogram +#### `quicstream.dataAckHistogram` TBD -#### quicstream.dataRateHistogram +#### `quicstream.dataRateHistogram` TBD -#### quicstream.dataSizeHistogram +#### `quicstream.dataSizeHistogram` TBD -#### quicstream.duration +#### `quicstream.duration` @@ -2236,7 +2236,7 @@ added: REPLACEME The length of time the `QuicStream` has been active. -#### quicstream.finalSize +#### `quicstream.finalSize` @@ -2245,7 +2245,7 @@ added: REPLACEME The total number of bytes successfully received by the `QuicStream`. -#### quicstream.id +#### `quicstream.id` @@ -2254,7 +2254,7 @@ added: REPLACEME The numeric identifier of the `QuicStream`. -#### quicstream.maxAcknowledgedOffset +#### `quicstream.maxAcknowledgedOffset` @@ -2263,7 +2263,7 @@ added: REPLACEME The highest acknowledged data offset received for this `QuicStream`. -#### quicstream.maxExtendedOffset +#### `quicstream.maxExtendedOffset` @@ -2272,7 +2272,7 @@ added: REPLACEME The maximum extended data offset that has been reported to the connected peer. -#### quicstream.maxReceivedOffset +#### `quicstream.maxReceivedOffset` @@ -2281,7 +2281,7 @@ added: REPLACEME The maximum received offset for this `QuicStream`. -#### quicstream.pending +#### `quicstream.pending` @@ -2291,7 +2291,7 @@ added: REPLACEME This property is `true` if the underlying session is not finished yet, i.e. before the `'ready'` event is emitted. -#### quicstream.pushStream(headers\[, options\]) +#### `quicstream.pushStream(headers\[, options\])` @@ -2317,7 +2317,7 @@ Currently only HTTP/3 supports the use of `pushStream()`. If the selected QUIC application protocol does not support push streams, an error will be thrown. -#### quicstream.serverInitiated +#### `quicstream.serverInitiated` @@ -2327,7 +2327,7 @@ added: REPLACEME Set to `true` if the `QuicStream` was initiated by a `QuicServerSession` instance. -#### quicstream.session +#### `quicstream.session` @@ -2336,7 +2336,7 @@ added: REPLACEME The `QuicServerSession` or `QuicClientSession`. -#### quicstream.sendFD(fd\[, options\]) +#### `quicstream.sendFD(fd\[, options\])` @@ -2362,7 +2362,7 @@ Using the same file descriptor concurrently for multiple streams is not supported and may result in data loss. Re-using a file descriptor after a stream has finished is supported. -#### quicstream.sendFile(path\[, options\]) +#### `quicstream.sendFile(path\[, options\])` @@ -2384,7 +2384,7 @@ If `offset` is set to a non-negative number, reading starts from that position. If `length` is set to a non-negative number, it gives the maximum number of bytes that are read from the file. -#### quicstream.submitInformationalHeaders(headers) +#### `quicstream.submitInformationalHeaders(headers)` @@ -2392,7 +2392,7 @@ added: REPLACEME TBD -#### quicstream.submitInitialHeaders(headers) +#### `quicstream.submitInitialHeaders(headers)` @@ -2400,7 +2400,7 @@ added: REPLACEME TBD -#### quicstream.submitTrailingHeaders(headers) +#### `quicstream.submitTrailingHeaders(headers)` @@ -2408,7 +2408,7 @@ added: REPLACEME TBD -#### quicstream.unidirectional +#### `quicstream.unidirectional` @@ -2432,7 +2432,7 @@ function as an option in several places throughout the QUIC API: * `quicsocket.connect()` * `quicsocket.listen()` -The custom `lookup` function must teturn a `Promise` that is +The custom `lookup` function must return a `Promise` that is resolved once the lookup is complete. It will be invoked with two arguments: @@ -2443,6 +2443,7 @@ two arguments: ```js async function myCustomLookup(address, type) { + // TODO(@jasnell): Make this example more useful return resolveTheAddressSomehow(address, type); } ``` @@ -2454,7 +2455,7 @@ async function myCustomLookup(address, type) { [ALPN]: https://tools.ietf.org/html/rfc7301 [RFC 4007]: https://tools.ietf.org/html/rfc4007 [Certificate Object]: https://nodejs.org/dist/latest-v12.x/docs/api/tls.html#tls_certificate_object -[custom DNS lookup function]: #custom_dns_lookups +[custom DNS lookup function]: #quic_custom_dns_lookup_functions [modifying the default cipher suite]: tls.html#tls_modifying_the_default_tls_cipher_suite [OpenSSL Options]: crypto.html#crypto_openssl_options [Perfect Forward Secrecy]: #tls_perfect_forward_secrecy