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

Commit

Permalink
quic: refine QuicError
Browse files Browse the repository at this point in the history
PR-URL: #207
Reviewed-By: #207
  • Loading branch information
jasnell committed Dec 4, 2019
1 parent c79cfa2 commit 81c7b17
Showing 6 changed files with 91 additions and 75 deletions.
6 changes: 3 additions & 3 deletions src/node_quic_session-inl.h
Original file line number Diff line number Diff line change
@@ -39,12 +39,12 @@ void QuicSession::SetLastError(QuicError error) {
last_error_ = error;
}

void QuicSession::SetLastError(QuicErrorFamily family, uint64_t code) {
void QuicSession::SetLastError(int32_t family, uint64_t code) {
SetLastError({ family, code });
}

void QuicSession::SetLastError(QuicErrorFamily family, int code) {
SetLastError(family, ngtcp2_err_infer_quic_transport_error_code(code));
void QuicSession::SetLastError(int32_t family, int code) {
SetLastError({ family, code });
}

bool QuicSession::IsInClosingPeriod() {
17 changes: 5 additions & 12 deletions src/node_quic_session.cc
Original file line number Diff line number Diff line change
@@ -612,7 +612,7 @@ bool QuicCryptoContext::SetSession(const unsigned char* data, size_t length) {

void QuicCryptoContext::SetTLSAlert(int err) {
Debug(session_, "TLS Alert [%d]: %s", err, SSL_alert_type_string_long(err));
session_->SetLastError(InitQuicError(QUIC_ERROR_CRYPTO, err));
session_->SetLastError(QuicError(QUIC_ERROR_CRYPTO, err));
}

bool QuicCryptoContext::SetupInitialKey(const ngtcp2_cid* dcid) {
@@ -1048,7 +1048,7 @@ void QuicSession::ImmediateClose() {
QuicError last_error = GetLastError();
Debug(this, "Immediate close with code %" PRIu64 " (%s)",
last_error.code,
ErrorFamilyName(last_error.family));
last_error.GetFamilyName());

HandleScope scope(env()->isolate());
Context::Scope context_scope(env()->context());
@@ -2040,7 +2040,7 @@ void QuicSession::SilentClose(bool stateless_reset) {
QuicError last_error = GetLastError();
Debug(this,
"Silent close with %s code %" PRIu64 " (stateless reset? %s)",
ErrorFamilyName(last_error.family),
last_error.GetFamilyName(),
last_error.code,
stateless_reset ? "yes" : "no");

@@ -3021,10 +3021,7 @@ void QuicSessionClose(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
QuicSession* session;
ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
int family = QUIC_ERROR_SESSION;
uint64_t code = ExtractErrorCode(env, args[0]);
if (!args[1]->Int32Value(env->context()).To(&family)) return;
session->SetLastError(static_cast<QuicErrorFamily>(family), code);
session->SetLastError(QuicError(env, args[0], args[1]));
session->SendConnectionClose();
}

@@ -3044,11 +3041,7 @@ void QuicSessionDestroy(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
QuicSession* session;
ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
int code = 0;
int family = QUIC_ERROR_SESSION;
if (!args[0]->Int32Value(env->context()).To(&code)) return;
if (!args[1]->Int32Value(env->context()).To(&family)) return;
session->SetLastError(static_cast<QuicErrorFamily>(family), code);
session->SetLastError(QuicError(env, args[0], args[1]));
session->Destroy();
}

15 changes: 9 additions & 6 deletions src/node_quic_session.h
Original file line number Diff line number Diff line change
@@ -666,11 +666,11 @@ class QuicSession : public AsyncWrap,

inline void SetLastError(
QuicError error = {
QUIC_ERROR_SESSION,
NGTCP2_NO_ERROR
uint32_t{QUIC_ERROR_SESSION},
uint64_t{NGTCP2_NO_ERROR}
});
inline void SetLastError(QuicErrorFamily family, uint64_t error_code);
inline void SetLastError(QuicErrorFamily family, int error_code);
inline void SetLastError(int32_t family, uint64_t error_code);
inline void SetLastError(int32_t family, int error_code);

inline uint64_t GetMaxLocalStreamsUni();

@@ -1108,7 +1108,7 @@ class QuicSession : public AsyncWrap,
uint64_t error_code,
ngtcp2_tstamp ts);

static inline ngtcp2_close_fn SelectCloseFn(QuicErrorFamily family) {
static inline ngtcp2_close_fn SelectCloseFn(uint32_t family) {
if (family == QUIC_ERROR_APPLICATION)
return ngtcp2_conn_write_application_close;
return ngtcp2_conn_write_connection_close;
@@ -1123,7 +1123,10 @@ class QuicSession : public AsyncWrap,
BaseObjectWeakPtr<QuicSocket> socket_;
std::string alpn_;
std::string hostname_;
QuicError last_error_ = { QUIC_ERROR_SESSION, NGTCP2_NO_ERROR };
QuicError last_error_ = {
uint32_t{QUIC_ERROR_SESSION},
uint64_t{NGTCP2_NO_ERROR}
};
ConnectionPointer connection_;
SocketAddress remote_address_;
uint32_t flags_ = 0;
8 changes: 3 additions & 5 deletions src/node_quic_stream.cc
Original file line number Diff line number Diff line change
@@ -491,13 +491,11 @@ void QuicStreamReset(const FunctionCallbackInfo<Value>& args) {
QuicStream* stream;
ASSIGN_OR_RETURN_UNWRAP(&stream, args.Holder());

uint32_t family = QUIC_ERROR_APPLICATION;
uint64_t code = ExtractErrorCode(env, args[0]);
if (!args[1]->Uint32Value(env->context()).To(&family)) return;
QuicError error(env, args[0], args[1], QUIC_ERROR_APPLICATION);

stream->ResetStream(
family == QUIC_ERROR_APPLICATION ?
code : static_cast<uint64_t>(NGTCP2_NO_ERROR));
error.family == QUIC_ERROR_APPLICATION ?
error.code : static_cast<uint64_t>(NGTCP2_NO_ERROR));
}

// Requests transmission of a block of informational headers. Not all
57 changes: 57 additions & 0 deletions src/node_quic_util.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "node_internals.h"
#include "node_quic_util.h"
#include "env-inl.h"
#include "util-inl.h"
@@ -53,5 +54,61 @@ const char* crypto_level_name(ngtcp2_crypto_level level) {
}
}

QuicError::QuicError(
int32_t family_,
uint64_t code_) :
family(family_),
code(code_) {}

QuicError::QuicError(
int32_t family_,
int code_) :
family(family_) {
switch (family) {
case QUIC_ERROR_CRYPTO:
code_ |= NGTCP2_CRYPTO_ERROR;
// Fall-through...
case QUIC_ERROR_SESSION:
code = ngtcp2_err_infer_quic_transport_error_code(code_);
break;
case QUIC_ERROR_APPLICATION:
code = code_;
default:
UNREACHABLE();
}
}

QuicError::QuicError(
Environment* env,
v8::Local<v8::Value> codeArg,
v8::Local<v8::Value> familyArg,
int32_t family_) :
code(NGTCP2_NO_ERROR),
family(family_) {
if (codeArg->IsBigInt()) {
code = codeArg.As<v8::BigInt>()->Int64Value();
} else if (codeArg->IsNumber()) {
double num = 0;
CHECK(codeArg->NumberValue(env->context()).To(&num));
code = static_cast<uint64_t>(num);
}
if (familyArg->IsNumber()) {
CHECK(familyArg->Int32Value(env->context()).To(&family));
}
}

const char* QuicError::GetFamilyName() {
switch (family) {
case QUIC_ERROR_SESSION:
return "Session";
case QUIC_ERROR_APPLICATION:
return "Application";
case QUIC_ERROR_CRYPTO:
return "Crypto";
default:
UNREACHABLE();
}
}

} // namespace quic
} // namespace node
63 changes: 14 additions & 49 deletions src/node_quic_util.h
Original file line number Diff line number Diff line change
@@ -71,64 +71,29 @@ inline void hash_combine(size_t* seed, const T& value, Args... rest) {
// look at the ALPN identifier to determine exactly what it
// means. Connection (Session) and Crypto errors, on the other
// hand, share the same meaning regardless of the ALPN.
enum QuicErrorFamily : int {
enum QuicErrorFamily : int32_t {
QUIC_ERROR_SESSION,
QUIC_ERROR_CRYPTO,
QUIC_ERROR_APPLICATION
};

struct QuicError {
QuicErrorFamily family;
int32_t family;
uint64_t code;
inline QuicError(
QuicErrorFamily family_ = QUIC_ERROR_SESSION,
uint64_t code_ = NGTCP2_NO_ERROR) :
family(family_), code(code_) {}
QuicError(
int32_t family_ = QUIC_ERROR_SESSION,
int code_ = NGTCP2_NO_ERROR);
QuicError(
int32_t family_ = QUIC_ERROR_SESSION,
uint64_t code_ = NGTCP2_NO_ERROR);
QuicError(
Environment* env,
v8::Local<v8::Value> codeArg,
v8::Local<v8::Value> familyArg = v8::Local<v8::Object>(),
int32_t family_ = QUIC_ERROR_SESSION);
const char* GetFamilyName();
};

inline QuicError InitQuicError(
QuicErrorFamily family = QUIC_ERROR_SESSION,
int code_ = NGTCP2_NO_ERROR) {
QuicError error;
error.family = family;
switch (family) {
case QUIC_ERROR_CRYPTO:
code_ |= NGTCP2_CRYPTO_ERROR;
// Fall-through...
case QUIC_ERROR_SESSION:
error.code = ngtcp2_err_infer_quic_transport_error_code(code_);
break;
case QUIC_ERROR_APPLICATION:
error.code = code_;
}
return error;
}

inline uint64_t ExtractErrorCode(Environment* env, v8::Local<v8::Value> arg) {
uint64_t code = NGTCP2_APP_NOERROR;
if (arg->IsBigInt()) {
code = arg.As<v8::BigInt>()->Int64Value();
} else if (arg->IsNumber()) {
double num = 0;
USE(arg->NumberValue(env->context()).To(&num));
code = static_cast<uint64_t>(num);
}
return code;
}

inline const char* ErrorFamilyName(QuicErrorFamily family) {
switch (family) {
case QUIC_ERROR_SESSION:
return "Session";
case QUIC_ERROR_APPLICATION:
return "Application";
case QUIC_ERROR_CRYPTO:
return "Crypto";
default:
return "<unknown>";
}
}

class SocketAddress {
public:
// std::hash specialization for sockaddr instances (ipv4 or ipv6) used

0 comments on commit 81c7b17

Please sign in to comment.