/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include #include #include #include #include namespace quic { QuicTransportException::QuicTransportException( const std::string& msg, TransportErrorCode errCode) : std::runtime_error(msg), errCode_(errCode) {} QuicTransportException::QuicTransportException( const char* msg, TransportErrorCode errCode) : std::runtime_error(msg), errCode_(errCode) {} QuicInternalException::QuicInternalException( const std::string& msg, LocalErrorCode errCode) : std::runtime_error(msg), errorCode_(errCode) {} QuicInternalException::QuicInternalException( const char* msg, LocalErrorCode errCode) : std::runtime_error(msg), errorCode_(errCode) {} QuicInternalException::QuicInternalException( folly::StringPiece msg, LocalErrorCode errCode) : std::runtime_error(folly::to(msg)), errorCode_(errCode) {} QuicApplicationException::QuicApplicationException( const std::string& msg, ApplicationErrorCode errorCode) : std::runtime_error(msg), errorCode_(errorCode) {} QuicApplicationException::QuicApplicationException( const char* msg, ApplicationErrorCode errorCode) : std::runtime_error(msg), errorCode_(errorCode) {} folly::StringPiece toString(LocalErrorCode code) { switch (code) { case LocalErrorCode::NO_ERROR: return "No Error"; case LocalErrorCode::CONNECT_FAILED: return "Connect failed"; case LocalErrorCode::CODEC_ERROR: return "Codec Error"; case LocalErrorCode::STREAM_CLOSED: return "Stream is closed"; case LocalErrorCode::STREAM_NOT_EXISTS: return "Stream does not exist"; case LocalErrorCode::CREATING_EXISTING_STREAM: return "Creating an existing stream"; case LocalErrorCode::SHUTTING_DOWN: return "Shutting down"; case LocalErrorCode::RESET_CRYPTO_STREAM: return "Reset the crypto stream"; case LocalErrorCode::CWND_OVERFLOW: return "CWND overflow"; case LocalErrorCode::INFLIGHT_BYTES_OVERFLOW: return "Inflight bytes overflow"; case LocalErrorCode::LOST_BYTES_OVERFLOW: return "Lost bytes overflow"; case LocalErrorCode::NEW_VERSION_NEGOTIATED: return "New version negotiatied"; case LocalErrorCode::INVALID_WRITE_CALLBACK: return "Invalid write callback"; case LocalErrorCode::CALLBACK_ALREADY_INSTALLED: return "Callback already installed"; case LocalErrorCode::TLS_HANDSHAKE_FAILED: return "TLS handshake failed"; case LocalErrorCode::APP_ERROR: return "App error"; case LocalErrorCode::INTERNAL_ERROR: return "Internal error"; case LocalErrorCode::TRANSPORT_ERROR: return "Transport error"; case LocalErrorCode::INVALID_WRITE_DATA: return "Invalid write data"; case LocalErrorCode::INVALID_STATE_TRANSITION: return "Invalid state transition"; case LocalErrorCode::CONNECTION_CLOSED: return "Connection closed"; case LocalErrorCode::EARLY_DATA_REJECTED: return "Early data rejected"; case LocalErrorCode::CONNECTION_RESET: return "Connection reset"; case LocalErrorCode::IDLE_TIMEOUT: return "Idle timeout"; case LocalErrorCode::PACKET_NUMBER_ENCODING: return "Packet number encoding"; case LocalErrorCode::INVALID_OPERATION: return "Invalid operation"; case LocalErrorCode::STREAM_LIMIT_EXCEEDED: return "Stream limit exceeded"; case LocalErrorCode::CONNECTION_ABANDONED: return "Connection abandoned"; case LocalErrorCode::KNOB_FRAME_UNSUPPORTED: return "Knob Frame Not Supported"; case LocalErrorCode::PACER_NOT_AVAILABLE: return "Pacer not available"; case LocalErrorCode::RTX_POLICIES_LIMIT_EXCEEDED: return "Retransmission policies limit exceeded"; default: break; } LOG(WARNING) << "toString has unhandled ErrorCode"; return "Unknown error"; } std::string toString(TransportErrorCode code) { switch (code) { case TransportErrorCode::NO_ERROR: return "No Error"; case TransportErrorCode::INTERNAL_ERROR: return "Internal Error"; case TransportErrorCode::FLOW_CONTROL_ERROR: return "Flow control error"; case TransportErrorCode::STREAM_LIMIT_ERROR: return "Stream limit error"; case TransportErrorCode::STREAM_STATE_ERROR: return "Stream State error"; case TransportErrorCode::FINAL_SIZE_ERROR: return "Final offset error"; case TransportErrorCode::FRAME_ENCODING_ERROR: return "Frame format error"; case TransportErrorCode::TRANSPORT_PARAMETER_ERROR: return "Transport parameter error"; case TransportErrorCode::PROTOCOL_VIOLATION: return "Protocol violation"; case TransportErrorCode::INVALID_MIGRATION: return "Invalid migration"; case TransportErrorCode::SERVER_BUSY: return "Server busy"; case TransportErrorCode::INVALID_TOKEN: return "Invalid token"; case TransportErrorCode::CRYPTO_ERROR: return cryptoErrorToString(code); case TransportErrorCode::CRYPTO_ERROR_MAX: return cryptoErrorToString(code); } auto codeVal = static_cast::type>(code); if ((codeVal & static_cast::type>( TransportErrorCode::CRYPTO_ERROR_MAX)) == codeVal) { return cryptoErrorToString(code); } LOG(WARNING) << "toString has unhandled ErrorCode"; return "Unknown error"; } std::vector getAllTransportErrorCodes() { std::vector all = { TransportErrorCode::NO_ERROR, TransportErrorCode::INTERNAL_ERROR, TransportErrorCode::SERVER_BUSY, TransportErrorCode::FLOW_CONTROL_ERROR, TransportErrorCode::STREAM_LIMIT_ERROR, TransportErrorCode::STREAM_STATE_ERROR, TransportErrorCode::FINAL_SIZE_ERROR, TransportErrorCode::FRAME_ENCODING_ERROR, TransportErrorCode::TRANSPORT_PARAMETER_ERROR, TransportErrorCode::PROTOCOL_VIOLATION, TransportErrorCode::INVALID_MIGRATION, TransportErrorCode::CRYPTO_ERROR, TransportErrorCode::CRYPTO_ERROR_MAX, TransportErrorCode::INVALID_TOKEN}; return all; } std::vector getAllLocalErrorCodes() { std::vector all = { LocalErrorCode::NO_ERROR, LocalErrorCode::CONNECT_FAILED, LocalErrorCode::CODEC_ERROR, LocalErrorCode::STREAM_CLOSED, LocalErrorCode::STREAM_NOT_EXISTS, LocalErrorCode::CREATING_EXISTING_STREAM, LocalErrorCode::SHUTTING_DOWN, LocalErrorCode::RESET_CRYPTO_STREAM, LocalErrorCode::CWND_OVERFLOW, LocalErrorCode::INFLIGHT_BYTES_OVERFLOW, LocalErrorCode::LOST_BYTES_OVERFLOW, LocalErrorCode::NEW_VERSION_NEGOTIATED, LocalErrorCode::INVALID_WRITE_CALLBACK, LocalErrorCode::TLS_HANDSHAKE_FAILED, LocalErrorCode::APP_ERROR, LocalErrorCode::INTERNAL_ERROR, LocalErrorCode::TRANSPORT_ERROR, LocalErrorCode::INVALID_WRITE_DATA, LocalErrorCode::INVALID_STATE_TRANSITION, LocalErrorCode::CONNECTION_CLOSED, LocalErrorCode::EARLY_DATA_REJECTED, LocalErrorCode::CONNECTION_RESET, LocalErrorCode::IDLE_TIMEOUT, LocalErrorCode::PACKET_NUMBER_ENCODING, LocalErrorCode::INVALID_OPERATION, LocalErrorCode::STREAM_LIMIT_EXCEEDED, LocalErrorCode::CONNECTION_ABANDONED, LocalErrorCode::CALLBACK_ALREADY_INSTALLED, LocalErrorCode::KNOB_FRAME_UNSUPPORTED, LocalErrorCode::PACER_NOT_AVAILABLE, }; return all; } std::string cryptoErrorToString(TransportErrorCode code) { auto codeVal = static_cast::type>(code); auto alertDescNum = codeVal - static_cast::type>( TransportErrorCode::CRYPTO_ERROR); return "Crypto error: " + toString(static_cast(alertDescNum)); } std::string toString(QuicErrorCode code) { switch (code.type()) { case QuicErrorCode::Type::ApplicationErrorCode: if (*code.asApplicationErrorCode() == GenericApplicationErrorCode::NO_ERROR) { return "No Error"; } return folly::to(*code.asApplicationErrorCode()); case QuicErrorCode::Type::LocalErrorCode: return toString(*code.asLocalErrorCode()).str(); case QuicErrorCode::Type::TransportErrorCode: return toString(*code.asTransportErrorCode()); } folly::assume_unreachable(); } std::string toString(const QuicError& error) { std::string err; switch (error.code.type()) { case QuicErrorCode::Type::ApplicationErrorCode: err = "ApplicationError: " + toString(*error.code.asApplicationErrorCode()) + ", "; break; case QuicErrorCode::Type::LocalErrorCode: err = "LocalError: " + folly::to(toString(*error.code.asLocalErrorCode())) + ", "; break; case QuicErrorCode::Type::TransportErrorCode: err = "TransportError: " + toString(*error.code.asTransportErrorCode()) + ", "; } if (!error.message.empty()) { err = folly::to(err, error.message); } return err; } } // namespace quic