1 // Copyright 2018 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef PLATFORM_BASE_ERROR_H_ 6 #define PLATFORM_BASE_ERROR_H_ 7 8 #include <cassert> 9 #include <ostream> 10 #include <string> 11 #include <utility> 12 13 #include "platform/base/macros.h" 14 15 namespace openscreen { 16 17 // Represents an error returned by an OSP library operation. An error has a 18 // code and an optional message. 19 class Error { 20 public: 21 // TODO(crbug.com/openscreen/65): Group/rename OSP-specific errors 22 enum class Code : int8_t { 23 // No error occurred. 24 kNone = 0, 25 26 // A transient condition prevented the operation from proceeding (e.g., 27 // cannot send on a non-blocking socket without blocking). This indicates 28 // the caller should try again later. 29 kAgain = -1, 30 31 // CBOR errors. 32 kCborParsing = 1, 33 kCborEncoding, 34 kCborIncompleteMessage, 35 kCborInvalidResponseId, 36 kCborInvalidMessage, 37 38 // Presentation start errors. 39 kNoAvailableReceivers, 40 kRequestCancelled, 41 kNoPresentationFound, 42 kPreviousStartInProgress, 43 kUnknownStartError, 44 kUnknownRequestId, 45 46 kAddressInUse, 47 kDomainNameTooLong, 48 kDomainNameLabelTooLong, 49 50 kIOFailure, 51 kInitializationFailure, 52 kInvalidIPV4Address, 53 kInvalidIPV6Address, 54 kConnectionFailed, 55 56 kSocketOptionSettingFailure, 57 kSocketAcceptFailure, 58 kSocketBindFailure, 59 kSocketClosedFailure, 60 kSocketConnectFailure, 61 kSocketInvalidState, 62 kSocketListenFailure, 63 kSocketReadFailure, 64 kSocketSendFailure, 65 66 // MDNS errors. 67 kMdnsRegisterFailure, 68 kMdnsReadFailure, 69 kMdnsNonConformingFailure, 70 71 kParseError, 72 kUnknownMessageType, 73 74 kNoActiveConnection, 75 kAlreadyClosed, 76 kInvalidConnectionState, 77 kNoStartedPresentation, 78 kPresentationAlreadyStarted, 79 80 kJsonParseError, 81 kJsonWriteError, 82 83 // OpenSSL errors. 84 85 // Was unable to generate an RSA key. 86 kRSAKeyGenerationFailure, 87 kRSAKeyParseError, 88 89 // Was unable to initialize an EVP_PKEY type. 90 kEVPInitializationError, 91 92 // Was unable to generate a certificate. 93 kCertificateCreationError, 94 95 // Certificate failed validation. 96 kCertificateValidationError, 97 98 // Failed to produce a hashing digest. 99 kSha256HashFailure, 100 101 // A non-recoverable SSL library error has occurred. 102 kFatalSSLError, 103 kFileLoadFailure, 104 105 // Cast certificate errors. 106 107 // Certificates were not provided for verification. 108 kErrCertsMissing, 109 110 // The certificates provided could not be parsed. 111 kErrCertsParse, 112 113 // Key usage is missing or is not set to Digital Signature. 114 // This error could also be thrown if the CN is missing. 115 kErrCertsRestrictions, 116 117 // The current date is before the notBefore date or after the notAfter date. 118 kErrCertsDateInvalid, 119 120 // The certificate failed to chain to a trusted root. 121 kErrCertsVerifyGeneric, 122 123 // The certificate was not found in the trust store. 124 kErrCertsVerifyUntrustedCert, 125 126 // The CRL is missing or failed to verify. 127 kErrCrlInvalid, 128 129 // One of the certificates in the chain is revoked. 130 kErrCertsRevoked, 131 132 // The pathlen constraint of the root certificate was exceeded. 133 kErrCertsPathlen, 134 135 // Cast authentication errors. 136 kCastV2PeerCertEmpty, 137 kCastV2WrongPayloadType, 138 kCastV2NoPayload, 139 kCastV2PayloadParsingFailed, 140 kCastV2MessageError, 141 kCastV2NoResponse, 142 kCastV2FingerprintNotFound, 143 kCastV2CertNotSignedByTrustedCa, 144 kCastV2CannotExtractPublicKey, 145 kCastV2SignedBlobsMismatch, 146 kCastV2TlsCertValidityPeriodTooLong, 147 kCastV2TlsCertValidStartDateInFuture, 148 kCastV2TlsCertExpired, 149 kCastV2SenderNonceMismatch, 150 kCastV2DigestUnsupported, 151 kCastV2SignatureEmpty, 152 153 // Cast channel errors. 154 kCastV2ChannelNotOpen, 155 kCastV2AuthenticationError, 156 kCastV2ConnectError, 157 kCastV2CastSocketError, 158 kCastV2TransportError, 159 kCastV2InvalidMessage, 160 kCastV2InvalidChannelId, 161 kCastV2ConnectTimeout, 162 kCastV2PingTimeout, 163 kCastV2ChannelPolicyMismatch, 164 165 kCreateSignatureFailed, 166 167 // Discovery errors. 168 kUpdateReceivedRecordFailure, 169 kRecordPublicationError, 170 kProcessReceivedRecordFailure, 171 172 // Generic errors. 173 kUnknownError, 174 kNotImplemented, 175 kInsufficientBuffer, 176 kParameterInvalid, 177 kParameterOutOfRange, 178 kParameterNullPointer, 179 kIndexOutOfBounds, 180 kItemAlreadyExists, 181 kItemNotFound, 182 kOperationInvalid, 183 kOperationInProgress, 184 kOperationCancelled, 185 186 // Cast streaming errors 187 kTypeError, 188 kUnknownCodec, 189 kSocketFailure, 190 kUnencryptedOffer 191 }; 192 193 Error(); 194 Error(const Error& error); 195 Error(Error&& error) noexcept; 196 197 Error(Code code); // NOLINT 198 Error(Code code, const std::string& message); 199 Error(Code code, std::string&& message); 200 ~Error(); 201 202 Error& operator=(const Error& other); 203 Error& operator=(Error&& other); 204 bool operator==(const Error& other) const; 205 bool operator!=(const Error& other) const; 206 207 // Special case comparison with codes. Without this case, comparisons will 208 // not work as expected, e.g. 209 // const Error foo(Error::Code::kItemNotFound, "Didn't find an item"); 210 // foo == Error::Code::kItemNotFound is actually false. 211 bool operator==(Code code) const; 212 bool operator!=(Code code) const; ok()213 bool ok() const { return code_ == Code::kNone; } 214 code()215 Code code() const { return code_; } message()216 const std::string& message() const { return message_; } message()217 std::string& message() { return message_; } 218 219 static const Error& None(); 220 221 std::string ToString() const; 222 223 private: 224 Code code_ = Code::kNone; 225 std::string message_; 226 }; 227 228 std::ostream& operator<<(std::ostream& os, const Error::Code& code); 229 230 std::ostream& operator<<(std::ostream& out, const Error& error); 231 232 // A convenience function to return a single value from a function that can 233 // return a value or an error. For normal results, construct with a ValueType* 234 // (ErrorOr takes ownership) and the Error will be kNone with an empty message. 235 // For Error results, construct with an error code and value. 236 // 237 // Example: 238 // 239 // ErrorOr<Bar> Foo::DoSomething() { 240 // if (success) { 241 // return Bar(); 242 // } else { 243 // return Error(kBadThingHappened, "No can do"); 244 // } 245 // } 246 // 247 // TODO(mfoltz): Add support for type conversions. 248 template <typename ValueType> 249 class ErrorOr { 250 public: None()251 static ErrorOr<ValueType> None() { 252 static ErrorOr<ValueType> error(Error::Code::kNone); 253 return error; 254 } 255 ErrorOr(const ValueType & value)256 ErrorOr(const ValueType& value) : value_(value), is_value_(true) {} // NOLINT ErrorOr(ValueType && value)257 ErrorOr(ValueType&& value) noexcept // NOLINT 258 : value_(std::move(value)), is_value_(true) {} 259 ErrorOr(const Error & error)260 ErrorOr(const Error& error) : error_(error), is_value_(false) { // NOLINT 261 assert(error_.code() != Error::Code::kNone); 262 } ErrorOr(Error && error)263 ErrorOr(Error&& error) noexcept // NOLINT 264 : error_(std::move(error)), is_value_(false) { 265 assert(error_.code() != Error::Code::kNone); 266 } ErrorOr(Error::Code code)267 ErrorOr(Error::Code code) : error_(code), is_value_(false) { // NOLINT 268 assert(error_.code() != Error::Code::kNone); 269 } ErrorOr(Error::Code code,std::string message)270 ErrorOr(Error::Code code, std::string message) 271 : error_(code, std::move(message)), is_value_(false) { 272 assert(error_.code() != Error::Code::kNone); 273 } 274 275 ErrorOr(const ErrorOr& other) = delete; ErrorOr(ErrorOr && other)276 ErrorOr(ErrorOr&& other) noexcept : is_value_(other.is_value_) { 277 // NB: Both |value_| and |error_| are uninitialized memory at this point! 278 // Unlike the other constructors, the compiler will not auto-generate 279 // constructor calls for either union member because neither appeared in 280 // this constructor's initializer list. 281 if (other.is_value_) { 282 new (&value_) ValueType(std::move(other.value_)); 283 } else { 284 new (&error_) Error(std::move(other.error_)); 285 } 286 } 287 288 ErrorOr& operator=(const ErrorOr& other) = delete; 289 ErrorOr& operator=(ErrorOr&& other) noexcept { 290 this->~ErrorOr<ValueType>(); 291 new (this) ErrorOr<ValueType>(std::move(other)); 292 return *this; 293 } 294 ~ErrorOr()295 ~ErrorOr() { 296 // NB: |value_| or |error_| must be explicitly destroyed since the compiler 297 // will not auto-generate the destructor calls for union members. 298 if (is_value_) { 299 value_.~ValueType(); 300 } else { 301 error_.~Error(); 302 } 303 } 304 is_error()305 bool is_error() const { return !is_value_; } is_value()306 bool is_value() const { return is_value_; } 307 308 // Unlike Error, we CAN provide an operator bool here, since it is 309 // more obvious to callers that ErrorOr<Foo> will be true if it's Foo. 310 operator bool() const { return is_value_; } 311 error()312 const Error& error() const { 313 assert(!is_value_); 314 return error_; 315 } error()316 Error& error() { 317 assert(!is_value_); 318 return error_; 319 } 320 value()321 const ValueType& value() const { 322 assert(is_value_); 323 return value_; 324 } value()325 ValueType& value() { 326 assert(is_value_); 327 return value_; 328 } 329 330 // Move only value or fallback value(ValueType && fallback)331 ValueType&& value(ValueType&& fallback) { 332 if (is_value()) { 333 return std::move(value()); 334 } 335 return std::forward<ValueType>(fallback); 336 } 337 338 // Copy only value or fallback value(ValueType fallback)339 ValueType value(ValueType fallback) const { 340 if (is_value()) { 341 return value(); 342 } 343 return std::move(fallback); 344 } 345 346 private: 347 // Only one of these is an active member, determined by |is_value_|. Since 348 // they are union'ed, they must be explicitly constructed and destroyed. 349 union { 350 ValueType value_; 351 Error error_; 352 }; 353 354 // If true, |value_| is initialized and active. Otherwise, |error_| is 355 // initialized and active. 356 const bool is_value_; 357 }; 358 359 // Define comparison operators using SFINAE. 360 template <typename ValueType> 361 bool operator<(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) { 362 // Handle the cases where one side is an error. 363 if (lhs.is_error() != rhs.is_error()) { 364 return lhs.is_error(); 365 } 366 367 // Handle the case where both sides are errors. 368 if (lhs.is_error()) { 369 return static_cast<int8_t>(lhs.error().code()) < 370 static_cast<int8_t>(rhs.error().code()); 371 } 372 373 // Handle the case where both are values. 374 return lhs.value() < rhs.value(); 375 } 376 377 template <typename ValueType> 378 bool operator>(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) { 379 return rhs < lhs; 380 } 381 382 template <typename ValueType> 383 bool operator<=(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) { 384 return !(lhs > rhs); 385 } 386 387 template <typename ValueType> 388 bool operator>=(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) { 389 return !(rhs < lhs); 390 } 391 392 template <typename ValueType> 393 bool operator==(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) { 394 // Handle the cases where one side is an error. 395 if (lhs.is_error() != rhs.is_error()) { 396 return false; 397 } 398 399 // Handle the case where both sides are errors. 400 if (lhs.is_error()) { 401 return lhs.error() == rhs.error(); 402 } 403 404 // Handle the case where both are values. 405 return lhs.value() == rhs.value(); 406 } 407 408 template <typename ValueType> 409 bool operator!=(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) { 410 return !(lhs == rhs); 411 } 412 413 } // namespace openscreen 414 415 #endif // PLATFORM_BASE_ERROR_H_ 416