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