• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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