Modify the visitor to allow it to interact with packets written by the packet exchanger.

PiperOrigin-RevId: 651483615
diff --git a/quiche/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc b/quiche/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc
index e6cb919..988b00e 100644
--- a/quiche/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc
+++ b/quiche/quic/qbone/bonnet/tun_device_packet_exchanger_test.cc
@@ -6,6 +6,8 @@
 
 #include <string>
 
+#include "absl/status/status.h"
+#include "absl/strings/string_view.h"
 #include "quiche/quic/platform/api/quic_test.h"
 #include "quiche/quic/qbone/bonnet/mock_packet_exchanger_stats_interface.h"
 #include "quiche/quic/qbone/mock_qbone_client.h"
@@ -27,6 +29,7 @@
  public:
   MOCK_METHOD(void, OnReadError, (const std::string&), (override));
   MOCK_METHOD(void, OnWriteError, (const std::string&), (override));
+  MOCK_METHOD(absl::Status, OnWrite, (absl::string_view), (override));
 };
 
 class TunDevicePacketExchangerTest : public QuicTest {
@@ -56,6 +59,7 @@
       }));
 
   EXPECT_CALL(mock_visitor_, OnWriteError(_));
+  EXPECT_CALL(mock_visitor_, OnWrite(StrEq(packet))).Times(1);
   exchanger_.WritePacketToNetwork(packet.data(), packet.size());
 }
 
@@ -69,6 +73,7 @@
       }));
 
   EXPECT_CALL(mock_stats_, OnWriteError(_)).Times(1);
+  EXPECT_CALL(mock_visitor_, OnWrite(StrEq(packet))).Times(1);
   exchanger_.WritePacketToNetwork(packet.data(), packet.size());
 }
 
@@ -81,6 +86,7 @@
       }));
 
   EXPECT_CALL(mock_stats_, OnPacketWritten(_)).Times(1);
+  EXPECT_CALL(mock_visitor_, OnWrite(StrEq(packet))).Times(1);
   exchanger_.WritePacketToNetwork(packet.data(), packet.size());
 }
 
diff --git a/quiche/quic/qbone/qbone_packet_exchanger.cc b/quiche/quic/qbone/qbone_packet_exchanger.cc
index aa99a78..f82292c 100644
--- a/quiche/quic/qbone/qbone_packet_exchanger.cc
+++ b/quiche/quic/qbone/qbone_packet_exchanger.cc
@@ -8,6 +8,8 @@
 #include <string>
 #include <utility>
 
+#include "absl/status/status.h"
+
 namespace quic {
 
 bool QbonePacketExchanger::ReadAndDeliverPacket(
@@ -27,6 +29,13 @@
 
 void QbonePacketExchanger::WritePacketToNetwork(const char* packet,
                                                 size_t size) {
+  if (visitor_) {
+    absl::Status status = visitor_->OnWrite(packet);
+    if (!status.ok()) {
+      QUIC_LOG_EVERY_N_SEC(ERROR, 60) << status;
+    }
+  }
+
   bool blocked = false;
   std::string error;
   if (packet_queue_.empty() && !write_blocked_) {
diff --git a/quiche/quic/qbone/qbone_packet_exchanger.h b/quiche/quic/qbone/qbone_packet_exchanger.h
index 4fd617b..c69f9b8 100644
--- a/quiche/quic/qbone/qbone_packet_exchanger.h
+++ b/quiche/quic/qbone/qbone_packet_exchanger.h
@@ -5,6 +5,8 @@
 #ifndef QUICHE_QUIC_QBONE_QBONE_PACKET_EXCHANGER_H_
 #define QUICHE_QUIC_QBONE_QBONE_PACKET_EXCHANGER_H_
 
+#include "absl/status/status.h"
+#include "absl/strings/string_view.h"
 #include "quiche/quic/core/quic_packets.h"
 #include "quiche/quic/qbone/qbone_client_interface.h"
 #include "quiche/quic/qbone/qbone_packet_writer.h"
@@ -21,6 +23,9 @@
     virtual ~Visitor() {}
     virtual void OnReadError(const std::string& error) {}
     virtual void OnWriteError(const std::string& error) {}
+    virtual absl::Status OnWrite(absl::string_view packet) {
+      return absl::OkStatus();
+    }
   };
   // Does not take ownership of visitor.
   QbonePacketExchanger(Visitor* visitor, size_t max_pending_packets)
diff --git a/quiche/quic/qbone/qbone_packet_exchanger_test.cc b/quiche/quic/qbone/qbone_packet_exchanger_test.cc
index 1663907..e9371e4 100644
--- a/quiche/quic/qbone/qbone_packet_exchanger_test.cc
+++ b/quiche/quic/qbone/qbone_packet_exchanger_test.cc
@@ -10,6 +10,8 @@
 #include <utility>
 #include <vector>
 
+#include "absl/status/status.h"
+#include "absl/strings/string_view.h"
 #include "quiche/quic/platform/api/quic_test.h"
 #include "quiche/quic/qbone/mock_qbone_client.h"
 
@@ -25,6 +27,7 @@
  public:
   MOCK_METHOD(void, OnReadError, (const std::string&), (override));
   MOCK_METHOD(void, OnWriteError, (const std::string&), (override));
+  MOCK_METHOD(absl::Status, OnWrite, (absl::string_view), (override));
 };
 
 class FakeQbonePacketExchanger : public QbonePacketExchanger {