Skip to content
This repository has been archived by the owner on Aug 11, 2020. It is now read-only.

Commit

Permalink
quic: refactoring error code handling
Browse files Browse the repository at this point in the history
PR-URL: #31
  • Loading branch information
jasnell committed Aug 19, 2019
1 parent a6133ea commit 18a67b2
Show file tree
Hide file tree
Showing 8 changed files with 301 additions and 127 deletions.
22 changes: 22 additions & 0 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,28 @@ E('ERR_OUT_OF_RANGE',
msg += ` It must be ${range}. Received ${received}`;
return msg;
}, RangeError);
E('ERR_QUIC_ERROR', function(code, family) {
const {
constants: {
QUIC_ERROR_APPLICATION,
QUIC_ERROR_CRYPTO,
QUIC_ERROR_SESSION,
}
} = internalBinding('quic');
let familyType = 'unknown';
switch (family) {
case QUIC_ERROR_APPLICATION:
familyType = 'application';
break;
case QUIC_ERROR_CRYPTO:
familyType = 'crypto';
break;
case QUIC_ERROR_SESSION:
familyType = 'session';
break;
}
return `QUIC session closed with ${familyType} error code ${code}`;
}, Error);
E('ERR_QUICCLIENTSESSION_FAILED',
'Failed to create a new QuicClientSession: %s', Error);
E('ERR_QUICCLIENTSESSION_FAILED_SETSOCKET',
Expand Down
49 changes: 43 additions & 6 deletions lib/internal/quic/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ const {

assertCrypto();

const { Error } = primordials;
const {
getAllowUnauthorized,
getSocketType,
lookup4,
lookup6,
validateCloseCode,
validateTransportParams,
validateQuicClientSessionOptions,
validateQuicSocketOptions,
Expand Down Expand Up @@ -106,6 +108,8 @@ const {
ERR_INVALID_REMOTE_TRANSPORT_PARAMS,
ERR_INVALID_TLS_SESSION_TICKET,
NGTCP2_PATH_VALIDATION_RESULT_FAILURE,
NGTCP2_NO_ERROR,
QUIC_ERROR_APPLICATION,
}
} = internalBinding('quic');

Expand All @@ -132,6 +136,7 @@ const kReceiveStop = Symbol('kReceiveStop');
const kRemoveSession = Symbol('kRemove');
const kRemoveStream = Symbol('kRemoveStream');
const kReset = Symbol('kReset');
const kSetCloseCode = Symbol('kSetCloseCode');
const kSetSocket = Symbol('kSetSocket');
const kTrackWriteState = Symbol('kTrackWriteState');
const kWriteGeneric = Symbol('kWriteGeneric');
Expand Down Expand Up @@ -208,7 +213,8 @@ function onSessionReady(sessionHandle) {
}

// Called when a QuicSession is closed
function onSessionClose(code) {
function onSessionClose(code, family) {
this[owner_symbol][kSetCloseCode](code, family);
this[owner_symbol].destroy();
}

Expand Down Expand Up @@ -872,7 +878,8 @@ class QuicSession extends EventEmitter {
#alpn = undefined;
#cipher = undefined;
#cipherVersion = undefined;
#closeCode = 0;
#closeCode = NGTCP2_NO_ERROR;
#closeFamily = QUIC_ERROR_APPLICATION;
#closing = false;
#destroyed = false;
#handshakeComplete = false;
Expand All @@ -892,11 +899,17 @@ class QuicSession extends EventEmitter {
this.#servername = servername;
}

[kSetCloseCode](code, family) {
this.#closeCode = code;
this.#closeFamily = family;
}

[kInspect]() {
const obj = {
alpn: this.#alpn,
cipher: this.cipher,
closing: this.closing,
closeCode: this.closeCode,
destroyed: this.destroyed,
servername: this.servername,
streams: this.#streams.size,
Expand Down Expand Up @@ -977,11 +990,15 @@ class QuicSession extends EventEmitter {

if (typeof code === 'function') {
callback = code;
code = 0;
code = NGTCP2_NO_ERROR;
}

if (code !== undefined && typeof code !== 'number')
throw new ERR_INVALID_ARG_TYPE('code', 'number', code);
const {
closeCode,
closeFamily
} = validateCloseCode(code);
this.#closeCode = closeCode;
this.#closeFamily = closeFamily;

if (callback) {
if (typeof callback !== 'function')
Expand Down Expand Up @@ -1027,6 +1044,19 @@ class QuicSession extends EventEmitter {
this.#destroyed = true;
this.#closing = false;

if (typeof error === 'number' ||
(error != null &&
typeof error === 'Object' &&
!(error instanceof Error))) {
const {
closeCode,
closeFamily
} = validateCloseCode(error);
this.#closeCode = closeCode;
this.#closeFamily = closeFamily;
error = new ERR_QUIC_ERROR(closeCode, closeFamily);
}

// Destroy any remaining streams immediately
for (const stream of this.#streams.values())
stream.destroy(error);
Expand All @@ -1041,7 +1071,7 @@ class QuicSession extends EventEmitter {
// Calling destroy will cause a CONNECTION_CLOSE to be
// sent to the peer and will destroy the QuicSession
// handler immediately.
handle.destroy();
handle.destroy(this.#closeCode, this.#closeFamily);
}

// Remove the QuicSession JavaScript object from the
Expand Down Expand Up @@ -1090,6 +1120,13 @@ class QuicSession extends EventEmitter {
return this.#closing;
}

get closeCode() {
return {
code: this.#closeCode,
family: this.#closeFamily
};
}

get socket() {
return this.#socket;
}
Expand Down
20 changes: 20 additions & 0 deletions lib/internal/quic/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const {
NGTCP2_MIN_CIDLEN,
QUIC_PREFERRED_ADDRESS_IGNORE,
QUIC_PREFERRED_ADDRESS_ACCEPT,
QUIC_ERROR_APPLICATION,
}
} = internalBinding('quic');

Expand Down Expand Up @@ -81,6 +82,24 @@ function lookup6(address, callback) {
lookup(address || '::1', 6, callback);
}

function validateCloseCode(code) {
let closeCode;
let closeFamily;
if (code != null && typeof code === 'object') {
closeCode = code.code || NGTCP2_NO_ERROR;
closeFamily = code.family || QUIC_ERROR_APPLICATION;
} else if (typeof code === 'number') {
closeCode = code;
closeFamily = QUIC_ERROR_APPLICATION;
} else {
throw new ERR_INVALID_ARG_TYPE('code', ['number', 'Object'], code)
}
return {
closeCode,
closeFamily
};
}

function validateBindOptions(port, address) {
if (!isLegalPort(port)) {
throw new ERR_INVALID_ARG_VALUE(
Expand Down Expand Up @@ -357,6 +376,7 @@ module.exports = {
lookup4,
lookup6,
validateBindOptions,
validateCloseCode,
validateNumberInRange,
validateTransportParams,
validateQuicClientSessionOptions,
Expand Down
4 changes: 4 additions & 0 deletions src/node_quic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,10 @@ void Initialize(Local<Object> target,
NODE_DEFINE_CONSTANT(constants, MIN_RETRYTOKEN_EXPIRATION);
NODE_DEFINE_CONSTANT(constants, NGTCP2_MAX_CIDLEN);
NODE_DEFINE_CONSTANT(constants, NGTCP2_MIN_CIDLEN);
NODE_DEFINE_CONSTANT(constants, NGTCP2_NO_ERROR);
NODE_DEFINE_CONSTANT(constants, QUIC_ERROR_APPLICATION);
NODE_DEFINE_CONSTANT(constants, QUIC_ERROR_CRYPTO);
NODE_DEFINE_CONSTANT(constants, QUIC_ERROR_SESSION);
NODE_DEFINE_CONSTANT(constants, QUIC_PREFERRED_ADDRESS_ACCEPT);
NODE_DEFINE_CONSTANT(constants, QUIC_PREFERRED_ADDRESS_IGNORE);
NODE_DEFINE_CONSTANT(constants, NGTCP2_DEFAULT_MAX_ACK_DELAY);
Expand Down
Loading

0 comments on commit 18a67b2

Please sign in to comment.