Return an error when datachannel closes due to network error

This is the start of generating compliant errors, including diagnostics,
when datachannels close because of errors.

Bug: chromium:1030631
Change-Id: I39aa41728efb25bca6193a782db4cbdaad8e0dc1
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/161304
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30034}
diff --git a/api/BUILD.gn b/api/BUILD.gn
index acc2bd7..45f555c 100644
--- a/api/BUILD.gn
+++ b/api/BUILD.gn
@@ -229,6 +229,7 @@
     "../rtc_base:logging",
     "../rtc_base:macromagic",
     "../rtc_base/system:rtc_export",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
 
diff --git a/api/data_channel_interface.h b/api/data_channel_interface.h
index ccf3ad7..e08830f 100644
--- a/api/data_channel_interface.h
+++ b/api/data_channel_interface.h
@@ -20,6 +20,7 @@
 #include <string>
 
 #include "absl/types/optional.h"
+#include "api/rtc_error.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/copy_on_write_buffer.h"
 #include "rtc_base/ref_count.h"
@@ -154,6 +155,10 @@
   // determined, and until then this will return -1.
   virtual int id() const = 0;
   virtual DataState state() const = 0;
+  // When state is kClosed, and the DataChannel was not closed using
+  // the closing procedure, returns the error information about the closing.
+  // The default implementation returns "no error".
+  virtual RTCError error() const { return RTCError(); }
   virtual uint32_t messages_sent() const = 0;
   virtual uint64_t bytes_sent() const = 0;
   virtual uint32_t messages_received() const = 0;
diff --git a/api/rtc_error.cc b/api/rtc_error.cc
index c9ad7cb..4d3033b 100644
--- a/api/rtc_error.cc
+++ b/api/rtc_error.cc
@@ -26,19 +26,34 @@
     "NETWORK_ERROR",
     "RESOURCE_EXHAUSTED",
     "INTERNAL_ERROR",
+    "OPERATION_ERROR_WITH_DATA",
 };
-static_assert(static_cast<int>(webrtc::RTCErrorType::INTERNAL_ERROR) ==
-                  (arraysize(kRTCErrorTypeNames) - 1),
-              "kRTCErrorTypeNames must have as many strings as RTCErrorType "
-              "has values.");
+static_assert(
+    static_cast<int>(webrtc::RTCErrorType::OPERATION_ERROR_WITH_DATA) ==
+        (arraysize(kRTCErrorTypeNames) - 1),
+    "kRTCErrorTypeNames must have as many strings as RTCErrorType "
+    "has values.");
+
+const char* kRTCErrorDetailTypeNames[] = {
+    "NONE",
+    "DATA_CHANNEL_FAILURE",
+    "DTLS_FAILURE",
+    "FINGERPRINT_FAILURE",
+    "SCTP_FAILURE",
+    "SDP_SYNTAX_ERROR",
+    "HARDWARE_ENCODER_NOT_AVAILABLE",
+    "HARDWARE_ENCODER_ERROR",
+};
+static_assert(
+    static_cast<int>(webrtc::RTCErrorDetailType::HARDWARE_ENCODER_ERROR) ==
+        (arraysize(kRTCErrorDetailTypeNames) - 1),
+    "kRTCErrorDetailTypeNames must have as many strings as "
+    "RTCErrorDetailType has values.");
 
 }  // namespace
 
 namespace webrtc {
 
-RTCError::RTCError(RTCError&& other) = default;
-RTCError& RTCError::operator=(RTCError&& other) = default;
-
 // static
 RTCError RTCError::OK() {
   return RTCError();
@@ -57,4 +72,9 @@
   return kRTCErrorTypeNames[index];
 }
 
+const char* ToString(RTCErrorDetailType error) {
+  int index = static_cast<int>(error);
+  return kRTCErrorDetailTypeNames[index];
+}
+
 }  // namespace webrtc
diff --git a/api/rtc_error.h b/api/rtc_error.h
index 970507f..0e264af 100644
--- a/api/rtc_error.h
+++ b/api/rtc_error.h
@@ -17,6 +17,7 @@
 #include <string>
 #include <utility>  // For std::move.
 
+#include "absl/types/optional.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/system/rtc_export.h"
@@ -73,6 +74,25 @@
   // The operation failed due to an internal error.
   // Maps to OperationError DOMException.
   INTERNAL_ERROR,
+
+  // An error occured that has additional data.
+  // The additional data is specified in
+  // https://w3c.github.io/webrtc-pc/#rtcerror-interface
+  // Maps to RTCError DOMException.
+  OPERATION_ERROR_WITH_DATA,
+};
+
+// Detail information, showing what further information should be present.
+// https://w3c.github.io/webrtc-pc/#rtcerrordetailtype-enum
+enum class RTCErrorDetailType {
+  NONE,
+  DATA_CHANNEL_FAILURE,
+  DTLS_FAILURE,
+  FINGERPRINT_FAILURE,
+  SCTP_FAILURE,
+  SDP_SYNTAX_ERROR,
+  HARDWARE_ENCODER_NOT_AVAILABLE,
+  HARDWARE_ENCODER_ERROR,
 };
 
 // Roughly corresponds to RTCError in the web api. Holds an error type, a
@@ -91,15 +111,11 @@
   RTCError(RTCErrorType type, std::string message)
       : type_(type), message_(std::move(message)) {}
 
-  // Delete the copy constructor and assignment operator; there aren't any use
-  // cases where you should need to copy an RTCError, as opposed to moving it.
-  // Can revisit this decision if use cases arise in the future.
-  RTCError(const RTCError& other) = delete;
-  RTCError& operator=(const RTCError& other) = delete;
-
-  // Move constructor and move-assignment operator.
-  RTCError(RTCError&& other);
-  RTCError& operator=(RTCError&& other);
+  // In many use cases, it is better to use move than copy,
+  // but copy and assignment are provided for those cases that need it.
+  // Note that this has extra overhead because it copies strings.
+  RTCError(const RTCError& other) = default;
+  RTCError& operator=(const RTCError& other) = default;
 
   // Identical to default constructed error.
   //
@@ -117,6 +133,13 @@
 
   void set_message(std::string message);
 
+  RTCErrorDetailType error_detail() const { return error_detail_; }
+  void set_error_detail(RTCErrorDetailType detail) { error_detail_ = detail; }
+  absl::optional<uint16_t> sctp_cause_code() { return sctp_cause_code_; }
+  void set_sctp_cause_code(uint16_t cause_code) {
+    sctp_cause_code_ = cause_code;
+  }
+
   // Convenience method for situations where you only care whether or not an
   // error occurred.
   bool ok() const { return type_ == RTCErrorType::NONE; }
@@ -124,6 +147,8 @@
  private:
   RTCErrorType type_ = RTCErrorType::NONE;
   std::string message_;
+  RTCErrorDetailType error_detail_ = RTCErrorDetailType::NONE;
+  absl::optional<uint16_t> sctp_cause_code_;
 };
 
 // Outputs the error as a friendly string. Update this method when adding a new
@@ -132,6 +157,7 @@
 // Only intended to be used for logging/diagnostics. The returned char* points
 // to literal string that lives for the whole duration of the program.
 RTC_EXPORT const char* ToString(RTCErrorType error);
+RTC_EXPORT const char* ToString(RTCErrorDetailType error);
 
 #ifdef UNIT_TEST
 inline std::ostream& operator<<(  // no-presubmit-check TODO(webrtc:8982)
@@ -139,6 +165,12 @@
     RTCErrorType error) {
   return stream << ToString(error);
 }
+
+inline std::ostream& operator<<(  // no-presubmit-check TODO(webrtc:8982)
+    std::ostream& stream,         // no-presubmit-check TODO(webrtc:8982)
+    RTCErrorDetailType error) {
+  return stream << ToString(error);
+}
 #endif  // UNIT_TEST
 
 // Helper macro that can be used by implementations to create an error with a