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 kInvalidCodecParameter, 190 kSocketFailure, 191 kUnencryptedOffer, 192 kRemotingNotSupported, 193 194 // A negotiation failure means that the current negotiation must be 195 // restarted by the sender. 196 kNegotiationFailure, 197 }; 198 199 Error(); 200 Error(const Error& error); 201 Error(Error&& error) noexcept; 202 203 Error(Code code); // NOLINT 204 Error(Code code, const std::string& message); 205 Error(Code code, std::string&& message); 206 ~Error(); 207 208 Error& operator=(const Error& other); 209 Error& operator=(Error&& other); 210 bool operator==(const Error& other) const; 211 bool operator!=(const Error& other) const; 212 213 // Special case comparison with codes. Without this case, comparisons will 214 // not work as expected, e.g. 215 // const Error foo(Error::Code::kItemNotFound, "Didn't find an item"); 216 // foo == Error::Code::kItemNotFound is actually false. 217 bool operator==(Code code) const; 218 bool operator!=(Code code) const; ok()219 bool ok() const { return code_ == Code::kNone; } 220 code()221 Code code() const { return code_; } message()222 const std::string& message() const { return message_; } message()223 std::string& message() { return message_; } 224 225 static const Error& None(); 226 227 std::string ToString() const; 228 229 private: 230 Code code_ = Code::kNone; 231 std::string message_; 232 }; 233 234 std::ostream& operator<<(std::ostream& os, const Error::Code& code); 235 236 std::ostream& operator<<(std::ostream& out, const Error& error); 237 238 // A convenience function to return a single value from a function that can 239 // return a value or an error. For normal results, construct with a ValueType* 240 // (ErrorOr takes ownership) and the Error will be kNone with an empty message. 241 // For Error results, construct with an error code and value. 242 // 243 // Example: 244 // 245 // ErrorOr<Bar> Foo::DoSomething() { 246 // if (success) { 247 // return Bar(); 248 // } else { 249 // return Error(kBadThingHappened, "No can do"); 250 // } 251 // } 252 // 253 // TODO(mfoltz): Add support for type conversions. 254 template <typename ValueType> 255 class ErrorOr { 256 public: None()257 static ErrorOr<ValueType> None() { 258 static ErrorOr<ValueType> error(Error::Code::kNone); 259 return error; 260 } 261 ErrorOr(const ValueType & value)262 ErrorOr(const ValueType& value) : value_(value), is_value_(true) {} // NOLINT ErrorOr(ValueType && value)263 ErrorOr(ValueType&& value) noexcept // NOLINT 264 : value_(std::move(value)), is_value_(true) {} 265 ErrorOr(const Error & error)266 ErrorOr(const Error& error) : error_(error), is_value_(false) { // NOLINT 267 assert(error_.code() != Error::Code::kNone); 268 } ErrorOr(Error && error)269 ErrorOr(Error&& error) noexcept // NOLINT 270 : error_(std::move(error)), is_value_(false) { 271 assert(error_.code() != Error::Code::kNone); 272 } ErrorOr(Error::Code code)273 ErrorOr(Error::Code code) : error_(code), is_value_(false) { // NOLINT 274 assert(error_.code() != Error::Code::kNone); 275 } ErrorOr(Error::Code code,std::string message)276 ErrorOr(Error::Code code, std::string message) 277 : error_(code, std::move(message)), is_value_(false) { 278 assert(error_.code() != Error::Code::kNone); 279 } 280 281 ErrorOr(const ErrorOr& other) = delete; ErrorOr(ErrorOr && other)282 ErrorOr(ErrorOr&& other) noexcept : is_value_(other.is_value_) { 283 // NB: Both |value_| and |error_| are uninitialized memory at this point! 284 // Unlike the other constructors, the compiler will not auto-generate 285 // constructor calls for either union member because neither appeared in 286 // this constructor's initializer list. 287 if (other.is_value_) { 288 new (&value_) ValueType(std::move(other.value_)); 289 } else { 290 new (&error_) Error(std::move(other.error_)); 291 } 292 } 293 294 ErrorOr& operator=(const ErrorOr& other) = delete; 295 ErrorOr& operator=(ErrorOr&& other) noexcept { 296 this->~ErrorOr<ValueType>(); 297 new (this) ErrorOr<ValueType>(std::move(other)); 298 return *this; 299 } 300 ~ErrorOr()301 ~ErrorOr() { 302 // NB: |value_| or |error_| must be explicitly destroyed since the compiler 303 // will not auto-generate the destructor calls for union members. 304 if (is_value_) { 305 value_.~ValueType(); 306 } else { 307 error_.~Error(); 308 } 309 } 310 is_error()311 bool is_error() const { return !is_value_; } is_value()312 bool is_value() const { return is_value_; } 313 314 // Unlike Error, we CAN provide an operator bool here, since it is 315 // more obvious to callers that ErrorOr<Foo> will be true if it's Foo. 316 operator bool() const { return is_value_; } 317 error()318 const Error& error() const { 319 assert(!is_value_); 320 return error_; 321 } error()322 Error& error() { 323 assert(!is_value_); 324 return error_; 325 } 326 value()327 const ValueType& value() const { 328 assert(is_value_); 329 return value_; 330 } value()331 ValueType& value() { 332 assert(is_value_); 333 return value_; 334 } 335 336 // Move only value or fallback value(ValueType && fallback)337 ValueType&& value(ValueType&& fallback) { 338 if (is_value()) { 339 return std::move(value()); 340 } 341 return std::forward<ValueType>(fallback); 342 } 343 344 // Copy only value or fallback value(ValueType fallback)345 ValueType value(ValueType fallback) const { 346 if (is_value()) { 347 return value(); 348 } 349 return std::move(fallback); 350 } 351 352 private: 353 // Only one of these is an active member, determined by |is_value_|. Since 354 // they are union'ed, they must be explicitly constructed and destroyed. 355 union { 356 ValueType value_; 357 Error error_; 358 }; 359 360 // If true, |value_| is initialized and active. Otherwise, |error_| is 361 // initialized and active. 362 const bool is_value_; 363 }; 364 365 // Define comparison operators using SFINAE. 366 template <typename ValueType> 367 bool operator<(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) { 368 // Handle the cases where one side is an error. 369 if (lhs.is_error() != rhs.is_error()) { 370 return lhs.is_error(); 371 } 372 373 // Handle the case where both sides are errors. 374 if (lhs.is_error()) { 375 return static_cast<int8_t>(lhs.error().code()) < 376 static_cast<int8_t>(rhs.error().code()); 377 } 378 379 // Handle the case where both are values. 380 return lhs.value() < rhs.value(); 381 } 382 383 template <typename ValueType> 384 bool operator>(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) { 385 return rhs < lhs; 386 } 387 388 template <typename ValueType> 389 bool operator<=(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) { 390 return !(lhs > rhs); 391 } 392 393 template <typename ValueType> 394 bool operator>=(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) { 395 return !(rhs < lhs); 396 } 397 398 template <typename ValueType> 399 bool operator==(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) { 400 // Handle the cases where one side is an error. 401 if (lhs.is_error() != rhs.is_error()) { 402 return false; 403 } 404 405 // Handle the case where both sides are errors. 406 if (lhs.is_error()) { 407 return lhs.error() == rhs.error(); 408 } 409 410 // Handle the case where both are values. 411 return lhs.value() == rhs.value(); 412 } 413 414 template <typename ValueType> 415 bool operator!=(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) { 416 return !(lhs == rhs); 417 } 418 419 } // namespace openscreen 420 421 #endif // PLATFORM_BASE_ERROR_H_ 422