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