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