dtls-in-stun: add "implicit ack" for binding responses

Binding responses now implicitly ack the data that was sent in the original request.
This allows a receiver to omit the hash in the response (not implemented yet)

Note:
* duplicates are ignored
* the implicit ack is only passed when there is an ack attribute

Bug: webrtc:367395350
Change-Id: I80bcf1c0031bbe92a9e715f27222a458977726de
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/394141
Reviewed-by: Jonas Oreland <jonaso@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@meta.com>
Cr-Commit-Position: refs/heads/main@{#45086}
diff --git a/p2p/BUILD.gn b/p2p/BUILD.gn
index 4324972..01fe103 100644
--- a/p2p/BUILD.gn
+++ b/p2p/BUILD.gn
@@ -182,6 +182,7 @@
     ":candidate_pair_interface",
     ":connection_info",
     ":dtls_stun_piggyback_controller",
+    ":dtls_utils",
     ":ice_credentials_iterator",
     ":p2p_constants",
     ":p2p_transport_channel_ice_field_trials",
diff --git a/p2p/base/connection.cc b/p2p/base/connection.cc
index a4207d4..11fabca 100644
--- a/p2p/base/connection.cc
+++ b/p2p/base/connection.cc
@@ -40,6 +40,7 @@
 #include "p2p/base/stun_request.h"
 #include "p2p/base/transport_description.h"
 #include "p2p/dtls/dtls_stun_piggyback_callbacks.h"
+#include "p2p/dtls/dtls_utils.h"
 #include "rtc_base/async_packet_socket.h"
 #include "rtc_base/byte_buffer.h"
 #include "rtc_base/checks.h"
@@ -629,7 +630,9 @@
   }
 }
 
-void Connection::MaybeHandleDtlsPiggybackingAttributes(const StunMessage* msg) {
+void Connection::MaybeHandleDtlsPiggybackingAttributes(
+    const StunMessage* msg,
+    const StunRequest* original_request) {
   if (dtls_stun_piggyback_callbacks_.empty()) {
     return;
   }
@@ -645,6 +648,20 @@
   if (dtls_piggyback_ack != nullptr) {
     piggyback_acks = dtls_piggyback_ack->GetUInt32Vector();
   }
+  // A response implicitly acknowledges the original embedded packet
+  // when the ack attribute is included.
+  if (dtls_piggyback_ack != nullptr && original_request != nullptr) {
+    const StunByteStringAttribute* request_dtls_piggyback =
+        original_request->msg()->GetByteString(STUN_ATTR_META_DTLS_IN_STUN);
+    if (request_dtls_piggyback) {
+      uint32_t sent_hash =
+          ComputeDtlsPacketHash(request_dtls_piggyback->array_view());
+      if (!piggyback_acks) {
+        piggyback_acks = {};
+      }
+      piggyback_acks->push_back(sent_hash);
+    }
+  }
   dtls_stun_piggyback_callbacks_.recv_data(piggyback_data, piggyback_acks);
 }
 
@@ -690,7 +707,7 @@
 
   // This is a validated stun request from remote peer.
   if (msg->type() == STUN_BINDING_REQUEST) {
-    MaybeHandleDtlsPiggybackingAttributes(msg);
+    MaybeHandleDtlsPiggybackingAttributes(msg, /*original_request=*/nullptr);
     SendStunBindingResponse(msg);
   } else {
     RTC_DCHECK(msg->type() == GOOG_PING_REQUEST);
@@ -1558,7 +1575,7 @@
   const bool sent_dtls_piggyback_ack =
       request->msg()->GetByteString(STUN_ATTR_META_DTLS_IN_STUN_ACK) != nullptr;
   if (sent_dtls_piggyback || sent_dtls_piggyback_ack) {
-    MaybeHandleDtlsPiggybackingAttributes(response);
+    MaybeHandleDtlsPiggybackingAttributes(response, request);
   }
 }
 
diff --git a/p2p/base/connection.h b/p2p/base/connection.h
index 4c08384..b62ed99 100644
--- a/p2p/base/connection.h
+++ b/p2p/base/connection.h
@@ -519,7 +519,9 @@
       received_packet_callback_;
 
   void MaybeAddDtlsPiggybackingAttributes(StunMessage* msg);
-  void MaybeHandleDtlsPiggybackingAttributes(const StunMessage* msg);
+  void MaybeHandleDtlsPiggybackingAttributes(
+      const StunMessage* msg,
+      const StunRequest* original_request);
   DtlsStunPiggybackCallbacks dtls_stun_piggyback_callbacks_;
 };
 
diff --git a/p2p/dtls/dtls_stun_piggyback_controller_unittest.cc b/p2p/dtls/dtls_stun_piggyback_controller_unittest.cc
index 4060e15..ebbaf0b 100644
--- a/p2p/dtls/dtls_stun_piggyback_controller_unittest.cc
+++ b/p2p/dtls/dtls_stun_piggyback_controller_unittest.cc
@@ -450,4 +450,13 @@
             std::string(dtls_flight2.begin(), dtls_flight2.end()));
 }
 
+TEST_F(DtlsStunPiggybackControllerTest, DuplicateAck) {
+  server_.CapturePacket(dtls_flight1);
+  server_.Flush();
+  server_.ReportDataPiggybacked(
+      std::nullopt,
+      std::vector<uint32_t>({ComputeDtlsPacketHash(dtls_flight1),
+                             ComputeDtlsPacketHash(dtls_flight1)}));
+}
+
 }  // namespace webrtc