blob: b8cb7f0bcd68b604ab052bd9811aaef150eb541a [file] [log] [blame]
deadbeef6038e972017-02-16 23:31:33 -08001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Steve Anton10542f22019-01-11 09:11:00 -080011#ifndef API_RTC_ERROR_H_
12#define API_RTC_ERROR_H_
deadbeef6038e972017-02-16 23:31:33 -080013
Jonas Olsson3e18c822018-04-18 10:11:07 +020014#ifdef UNIT_TEST
deadbeef6038e972017-02-16 23:31:33 -080015#include <ostream>
Jonas Olsson3e18c822018-04-18 10:11:07 +020016#endif // UNIT_TEST
deadbeef6038e972017-02-16 23:31:33 -080017#include <string>
18#include <utility> // For std::move.
19
Harald Alvestranddfbfb462019-12-08 05:55:43 +010020#include "absl/types/optional.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "rtc_base/checks.h"
22#include "rtc_base/logging.h"
Mirko Bonadei66e76792019-04-02 11:33:59 +020023#include "rtc_base/system/rtc_export.h"
deadbeef6038e972017-02-16 23:31:33 -080024
25namespace webrtc {
26
27// Enumeration to represent distinct classes of errors that an application
28// may wish to act upon differently. These roughly map to DOMExceptions or
29// RTCError "errorDetailEnum" values in the web API, as described in the
30// comments below.
31enum class RTCErrorType {
32 // No error.
33 NONE,
34
35 // An operation is valid, but currently unsupported.
36 // Maps to OperationError DOMException.
37 UNSUPPORTED_OPERATION,
38
39 // A supplied parameter is valid, but currently unsupported.
40 // Maps to OperationError DOMException.
41 UNSUPPORTED_PARAMETER,
42
43 // General error indicating that a supplied parameter is invalid.
44 // Maps to InvalidAccessError or TypeError DOMException depending on context.
45 INVALID_PARAMETER,
46
47 // Slightly more specific than INVALID_PARAMETER; a parameter's value was
48 // outside the allowed range.
49 // Maps to RangeError DOMException.
50 INVALID_RANGE,
51
52 // Slightly more specific than INVALID_PARAMETER; an error occurred while
53 // parsing string input.
54 // Maps to SyntaxError DOMException.
55 SYNTAX_ERROR,
56
57 // The object does not support this operation in its current state.
58 // Maps to InvalidStateError DOMException.
59 INVALID_STATE,
60
61 // An attempt was made to modify the object in an invalid way.
62 // Maps to InvalidModificationError DOMException.
63 INVALID_MODIFICATION,
64
65 // An error occurred within an underlying network protocol.
66 // Maps to NetworkError DOMException.
67 NETWORK_ERROR,
68
69 // Some resource has been exhausted; file handles, hardware resources, ports,
70 // etc.
71 // Maps to OperationError DOMException.
72 RESOURCE_EXHAUSTED,
73
74 // The operation failed due to an internal error.
75 // Maps to OperationError DOMException.
76 INTERNAL_ERROR,
Harald Alvestranddfbfb462019-12-08 05:55:43 +010077
78 // An error occured that has additional data.
79 // The additional data is specified in
80 // https://w3c.github.io/webrtc-pc/#rtcerror-interface
81 // Maps to RTCError DOMException.
82 OPERATION_ERROR_WITH_DATA,
83};
84
85// Detail information, showing what further information should be present.
86// https://w3c.github.io/webrtc-pc/#rtcerrordetailtype-enum
87enum class RTCErrorDetailType {
88 NONE,
89 DATA_CHANNEL_FAILURE,
90 DTLS_FAILURE,
91 FINGERPRINT_FAILURE,
92 SCTP_FAILURE,
93 SDP_SYNTAX_ERROR,
94 HARDWARE_ENCODER_NOT_AVAILABLE,
95 HARDWARE_ENCODER_ERROR,
deadbeef6038e972017-02-16 23:31:33 -080096};
97
98// Roughly corresponds to RTCError in the web api. Holds an error type, a
99// message, and possibly additional information specific to that error.
100//
101// Doesn't contain anything beyond a type and message now, but will in the
102// future as more errors are implemented.
Mirko Bonadei66e76792019-04-02 11:33:59 +0200103class RTC_EXPORT RTCError {
deadbeef6038e972017-02-16 23:31:33 -0800104 public:
105 // Constructors.
106
107 // Creates a "no error" error.
108 RTCError() {}
109 explicit RTCError(RTCErrorType type) : type_(type) {}
Jonas Olsson941a07c2018-09-13 10:07:07 +0200110
111 RTCError(RTCErrorType type, std::string message)
112 : type_(type), message_(std::move(message)) {}
deadbeef6038e972017-02-16 23:31:33 -0800113
Harald Alvestranddfbfb462019-12-08 05:55:43 +0100114 // In many use cases, it is better to use move than copy,
115 // but copy and assignment are provided for those cases that need it.
116 // Note that this has extra overhead because it copies strings.
117 RTCError(const RTCError& other) = default;
Steve Anton2a3190f2020-01-08 11:20:04 -0800118 RTCError(RTCError&&) = default;
Harald Alvestranddfbfb462019-12-08 05:55:43 +0100119 RTCError& operator=(const RTCError& other) = default;
Steve Anton2a3190f2020-01-08 11:20:04 -0800120 RTCError& operator=(RTCError&&) = default;
deadbeef6038e972017-02-16 23:31:33 -0800121
deadbeef6038e972017-02-16 23:31:33 -0800122 // Identical to default constructed error.
123 //
124 // Preferred over the default constructor for code readability.
125 static RTCError OK();
126
127 // Error type.
128 RTCErrorType type() const { return type_; }
129 void set_type(RTCErrorType type) { type_ = type; }
130
131 // Human-readable message describing the error. Shouldn't be used for
132 // anything but logging/diagnostics, since messages are not guaranteed to be
133 // stable.
134 const char* message() const;
Jonas Olsson941a07c2018-09-13 10:07:07 +0200135
136 void set_message(std::string message);
deadbeef6038e972017-02-16 23:31:33 -0800137
Harald Alvestranddfbfb462019-12-08 05:55:43 +0100138 RTCErrorDetailType error_detail() const { return error_detail_; }
139 void set_error_detail(RTCErrorDetailType detail) { error_detail_ = detail; }
140 absl::optional<uint16_t> sctp_cause_code() { return sctp_cause_code_; }
141 void set_sctp_cause_code(uint16_t cause_code) {
142 sctp_cause_code_ = cause_code;
143 }
144
deadbeef6038e972017-02-16 23:31:33 -0800145 // Convenience method for situations where you only care whether or not an
146 // error occurred.
147 bool ok() const { return type_ == RTCErrorType::NONE; }
148
149 private:
150 RTCErrorType type_ = RTCErrorType::NONE;
Jonas Olsson941a07c2018-09-13 10:07:07 +0200151 std::string message_;
Harald Alvestranddfbfb462019-12-08 05:55:43 +0100152 RTCErrorDetailType error_detail_ = RTCErrorDetailType::NONE;
153 absl::optional<uint16_t> sctp_cause_code_;
deadbeef6038e972017-02-16 23:31:33 -0800154};
155
156// Outputs the error as a friendly string. Update this method when adding a new
157// error type.
158//
Mirko Bonadeifb59a6a2019-09-20 09:33:02 +0200159// Only intended to be used for logging/diagnostics. The returned char* points
Mirko Bonadei254ecff2019-01-16 12:14:29 +0100160// to literal string that lives for the whole duration of the program.
Mirko Bonadei35214fc2019-09-23 14:54:28 +0200161RTC_EXPORT const char* ToString(RTCErrorType error);
Harald Alvestranddfbfb462019-12-08 05:55:43 +0100162RTC_EXPORT const char* ToString(RTCErrorDetailType error);
Jonas Olssond7ee7202018-04-18 10:11:07 +0200163
Jonas Olsson3e18c822018-04-18 10:11:07 +0200164#ifdef UNIT_TEST
165inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
166 std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
167 RTCErrorType error) {
168 return stream << ToString(error);
169}
Harald Alvestranddfbfb462019-12-08 05:55:43 +0100170
171inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
172 std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
173 RTCErrorDetailType error) {
174 return stream << ToString(error);
175}
Jonas Olsson3e18c822018-04-18 10:11:07 +0200176#endif // UNIT_TEST
177
deadbeef6038e972017-02-16 23:31:33 -0800178// Helper macro that can be used by implementations to create an error with a
179// message and log it. |message| should be a string literal or movable
180// std::string.
Jonas Olssonabbe8412018-04-03 13:40:05 +0200181#define LOG_AND_RETURN_ERROR_EX(type, message, severity) \
182 { \
183 RTC_DCHECK(type != RTCErrorType::NONE); \
184 RTC_LOG(severity) << message << " (" << ToString(type) << ")"; \
185 return webrtc::RTCError(type, message); \
deadbeef6038e972017-02-16 23:31:33 -0800186 }
187
188#define LOG_AND_RETURN_ERROR(type, message) \
189 LOG_AND_RETURN_ERROR_EX(type, message, LS_ERROR)
190
191// RTCErrorOr<T> is the union of an RTCError object and a T object. RTCErrorOr
192// models the concept of an object that is either a usable value, or an error
193// Status explaining why such a value is not present. To this end RTCErrorOr<T>
194// does not allow its RTCErrorType value to be RTCErrorType::NONE. This is
195// enforced by a debug check in most cases.
196//
197// The primary use-case for RTCErrorOr<T> is as the return value of a function
198// which may fail. For example, CreateRtpSender will fail if the parameters
199// could not be successfully applied at the media engine level, but if
200// successful will return a unique_ptr to an RtpSender.
201//
202// Example client usage for a RTCErrorOr<std::unique_ptr<T>>:
203//
204// RTCErrorOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
205// if (result.ok()) {
206// std::unique_ptr<Foo> foo = result.ConsumeValue();
207// foo->DoSomethingCool();
208// } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100209// RTC_LOG(LS_ERROR) << result.error();
deadbeef6038e972017-02-16 23:31:33 -0800210// }
211//
212// Example factory implementation returning RTCErrorOr<std::unique_ptr<T>>:
213//
214// RTCErrorOr<std::unique_ptr<Foo>> FooFactory::MakeNewFoo(int arg) {
215// if (arg <= 0) {
216// return RTCError(RTCErrorType::INVALID_RANGE, "Arg must be positive");
217// } else {
218// return std::unique_ptr<Foo>(new Foo(arg));
219// }
220// }
221//
222template <typename T>
223class RTCErrorOr {
224 // Used to convert between RTCErrorOr<Foo>/RtcErrorOr<Bar>, when an implicit
225 // conversion from Foo to Bar exists.
226 template <typename U>
227 friend class RTCErrorOr;
228
229 public:
230 typedef T element_type;
231
232 // Constructs a new RTCErrorOr with RTCErrorType::INTERNAL_ERROR error. This
233 // is marked 'explicit' to try to catch cases like 'return {};', where people
234 // think RTCErrorOr<std::vector<int>> will be initialized with an empty
235 // vector, instead of a RTCErrorType::INTERNAL_ERROR error.
oprypin8e58d652017-03-21 07:52:41 -0700236 RTCErrorOr() : error_(RTCErrorType::INTERNAL_ERROR) {}
deadbeef6038e972017-02-16 23:31:33 -0800237
238 // Constructs a new RTCErrorOr with the given non-ok error. After calling
239 // this constructor, calls to value() will DCHECK-fail.
240 //
241 // NOTE: Not explicit - we want to use RTCErrorOr<T> as a return
242 // value, so it is convenient and sensible to be able to do 'return
243 // RTCError(...)' when the return type is RTCErrorOr<T>.
244 //
245 // REQUIRES: !error.ok(). This requirement is DCHECKed.
oprypin8e58d652017-03-21 07:52:41 -0700246 RTCErrorOr(RTCError&& error) : error_(std::move(error)) { // NOLINT
deadbeef6038e972017-02-16 23:31:33 -0800247 RTC_DCHECK(!error.ok());
248 }
249
250 // Constructs a new RTCErrorOr with the given value. After calling this
251 // constructor, calls to value() will succeed, and calls to error() will
252 // return a default-constructed RTCError.
253 //
254 // NOTE: Not explicit - we want to use RTCErrorOr<T> as a return type
255 // so it is convenient and sensible to be able to do 'return T()'
256 // when the return type is RTCErrorOr<T>.
Mirko Bonadei9f3a44f2019-01-30 13:47:42 +0100257 RTCErrorOr(const T& value) : value_(value) {} // NOLINT
oprypin8e58d652017-03-21 07:52:41 -0700258 RTCErrorOr(T&& value) : value_(std::move(value)) {} // NOLINT
deadbeef6038e972017-02-16 23:31:33 -0800259
260 // Delete the copy constructor and assignment operator; there aren't any use
261 // cases where you should need to copy an RTCErrorOr, as opposed to moving
262 // it. Can revisit this decision if use cases arise in the future.
263 RTCErrorOr(const RTCErrorOr& other) = delete;
264 RTCErrorOr& operator=(const RTCErrorOr& other) = delete;
265
266 // Move constructor and move-assignment operator.
deadbeefb5388d72017-02-24 01:17:43 -0800267 //
268 // Visual Studio doesn't support "= default" with move constructors or
269 // assignment operators (even though they compile, they segfault), so define
270 // them explicitly.
271 RTCErrorOr(RTCErrorOr&& other)
272 : error_(std::move(other.error_)), value_(std::move(other.value_)) {}
273 RTCErrorOr& operator=(RTCErrorOr&& other) {
274 error_ = std::move(other.error_);
275 value_ = std::move(other.value_);
276 return *this;
277 }
deadbeef6038e972017-02-16 23:31:33 -0800278
279 // Conversion constructor and assignment operator; T must be copy or move
280 // constructible from U.
281 template <typename U>
oprypin8e58d652017-03-21 07:52:41 -0700282 RTCErrorOr(RTCErrorOr<U> other) // NOLINT
deadbeef6038e972017-02-16 23:31:33 -0800283 : error_(std::move(other.error_)), value_(std::move(other.value_)) {}
284 template <typename U>
285 RTCErrorOr& operator=(RTCErrorOr<U> other) {
286 error_ = std::move(other.error_);
287 value_ = std::move(other.value_);
288 return *this;
289 }
290
291 // Returns a reference to our error. If this contains a T, then returns
292 // default-constructed RTCError.
293 const RTCError& error() const { return error_; }
294
295 // Moves the error. Can be useful if, say "CreateFoo" returns an
296 // RTCErrorOr<Foo>, and internally calls "CreateBar" which returns an
297 // RTCErrorOr<Bar>, and wants to forward the error up the stack.
298 RTCError MoveError() { return std::move(error_); }
299
300 // Returns this->error().ok()
301 bool ok() const { return error_.ok(); }
302
303 // Returns a reference to our current value, or DCHECK-fails if !this->ok().
304 //
305 // Can be convenient for the implementation; for example, a method may want
306 // to access the value in some way before returning it to the next method on
307 // the stack.
308 const T& value() const {
309 RTC_DCHECK(ok());
310 return value_;
311 }
312 T& value() {
313 RTC_DCHECK(ok());
314 return value_;
315 }
316
317 // Moves our current value out of this object and returns it, or DCHECK-fails
318 // if !this->ok().
319 T MoveValue() {
320 RTC_DCHECK(ok());
321 return std::move(value_);
322 }
323
324 private:
325 RTCError error_;
326 T value_;
327};
328
329} // namespace webrtc
330
Steve Anton10542f22019-01-11 09:11:00 -0800331#endif // API_RTC_ERROR_H_