Signal detailed packet info for each packet sent.

Per-packet info is now signaled in SentPacket to provide useful stats
for bandwidth consumption and overhead analysis in the network stack.

Bug: webrtc:9103
Change-Id: I2b8f6491567d0fa54cc559fc5a96d7aac7d9565e
Reviewed-on: https://webrtc-review.googlesource.com/66281
Commit-Queue: Qingsi Wang <qingsi@google.com>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22834}
diff --git a/media/base/rtpdataengine.cc b/media/base/rtpdataengine.cc
index 3aebe84..6e2155b 100644
--- a/media/base/rtpdataengine.cc
+++ b/media/base/rtpdataengine.cc
@@ -327,7 +327,9 @@
                       << ", timestamp=" << header.timestamp
                       << ", len=" << payload.size();
 
-  MediaChannel::SendPacket(&packet, rtc::PacketOptions());
+  rtc::PacketOptions options;
+  options.info_signaled_after_sent.packet_type = rtc::PacketType::kData;
+  MediaChannel::SendPacket(&packet, options);
   send_limiter_->Use(packet_len, now);
   if (result) {
     *result = SDR_SUCCESS;
diff --git a/media/engine/webrtcvoiceengine.h b/media/engine/webrtcvoiceengine.h
index 56cccbc..21b352b 100644
--- a/media/engine/webrtcvoiceengine.h
+++ b/media/engine/webrtcvoiceengine.h
@@ -206,7 +206,8 @@
 
   bool SendRtcp(const uint8_t* data, size_t len) override {
     rtc::CopyOnWriteBuffer packet(data, len, kMaxRtpPacketLen);
-    return VoiceMediaChannel::SendRtcp(&packet, rtc::PacketOptions());
+    rtc::PacketOptions rtc_options;
+    return VoiceMediaChannel::SendRtcp(&packet, rtc_options);
   }
 
  private:
diff --git a/p2p/base/p2ptransportchannel.cc b/p2p/base/p2ptransportchannel.cc
index 804cab1..00f7388 100644
--- a/p2p/base/p2ptransportchannel.cc
+++ b/p2p/base/p2ptransportchannel.cc
@@ -1206,7 +1206,10 @@
   }
 
   last_sent_packet_id_ = options.packet_id;
-  int sent = selected_connection_->Send(data, len, options);
+  rtc::PacketOptions modified_options(options);
+  modified_options.info_signaled_after_sent.packet_type =
+      rtc::PacketType::kData;
+  int sent = selected_connection_->Send(data, len, modified_options);
   if (sent <= 0) {
     RTC_DCHECK(sent < 0);
     error_ = selected_connection_->GetError();
diff --git a/p2p/base/p2ptransportchannel_unittest.cc b/p2p/base/p2ptransportchannel_unittest.cc
index 2b0efac..192cbaa 100644
--- a/p2p/base/p2ptransportchannel_unittest.cc
+++ b/p2p/base/p2ptransportchannel_unittest.cc
@@ -382,6 +382,8 @@
         this, &P2PTransportChannelTestBase::OnRoleConflict);
     channel->SignalNetworkRouteChanged.connect(
         this, &P2PTransportChannelTestBase::OnNetworkRouteChanged);
+    channel->SignalSentPacket.connect(
+        this, &P2PTransportChannelTestBase::OnSentPacket);
     channel->SetIceParameters(local_ice);
     if (remote_ice_parameter_source_ == FROM_SETICEPARAMETERS) {
       channel->SetRemoteIceParameters(remote_ice);
@@ -681,6 +683,13 @@
     TestSendRecv(&clock);
   }
 
+  void TestPacketInfoIsSet(rtc::PacketInfo info) {
+    EXPECT_NE(info.packet_type, rtc::PacketType::kUnknown);
+    EXPECT_NE(info.protocol, rtc::PacketInfoProtocolType::kUnknown);
+    EXPECT_TRUE(info.network_id.has_value());
+    EXPECT_FALSE(info.local_socket_address.IsNil());
+  }
+
   void OnReadyToSend(rtc::PacketTransportInternal* transport) {
     GetEndpoint(transport)->ready_to_send_ = true;
   }
@@ -804,6 +813,11 @@
     channel->SetIceRole(new_role);
   }
 
+  void OnSentPacket(rtc::PacketTransportInternal* transport,
+                    const rtc::SentPacket& packet) {
+    TestPacketInfoIsSet(packet.info);
+  }
+
   int SendData(IceTransportInternal* channel, const char* data, size_t len) {
     rtc::PacketOptions options;
     return channel->SendPacket(data, len, options, 0);
diff --git a/p2p/base/port.cc b/p2p/base/port.cc
index 7d3c719..c2fcdd6 100644
--- a/p2p/base/port.cc
+++ b/p2p/base/port.cc
@@ -115,6 +115,22 @@
   return webrtc::IceCandidateNetworkType::kUnknown;
 }
 
+rtc::PacketInfoProtocolType ConvertProtocolTypeToPacketInfoProtocolType(
+    cricket::ProtocolType type) {
+  switch (type) {
+    case cricket::ProtocolType::PROTO_UDP:
+      return rtc::PacketInfoProtocolType::kUdp;
+    case cricket::ProtocolType::PROTO_TCP:
+      return rtc::PacketInfoProtocolType::kTcp;
+    case cricket::ProtocolType::PROTO_SSLTCP:
+      return rtc::PacketInfoProtocolType::kSsltcp;
+    case cricket::ProtocolType::PROTO_TLS:
+      return rtc::PacketInfoProtocolType::kTls;
+    default:
+      return rtc::PacketInfoProtocolType::kUnknown;
+  }
+}
+
 // We will restrict RTT estimates (when used for determining state) to be
 // within a reasonable range.
 const int MINIMUM_RTT = 100;   // 0.1 seconds
@@ -774,6 +790,8 @@
   rtc::ByteBufferWriter buf;
   response.Write(&buf);
   rtc::PacketOptions options(DefaultDscpValue());
+  options.info_signaled_after_sent.packet_type =
+      rtc::PacketType::kIceConnectivityCheckResponse;
   auto err = SendTo(buf.Data(), buf.Length(), addr, options, false);
   if (err < 0) {
     RTC_LOG(LS_ERROR) << ToString()
@@ -825,6 +843,8 @@
   rtc::ByteBufferWriter buf;
   response.Write(&buf);
   rtc::PacketOptions options(DefaultDscpValue());
+  options.info_signaled_after_sent.packet_type =
+      rtc::PacketType::kIceConnectivityCheckResponse;
   SendTo(buf.Data(), buf.Length(), addr, options, false);
   RTC_LOG(LS_INFO) << ToString()
                    << ": Sending STUN binding error: reason=" << reason
@@ -926,6 +946,11 @@
   return ice_username_fragment_;
 }
 
+void Port::CopyPortInformationToPacketInfo(rtc::PacketInfo* info) const {
+  info->protocol = ConvertProtocolTypeToPacketInfoProtocolType(GetProtocol());
+  info->network_id = Network()->id();
+}
+
 // A ConnectionRequest is a simple STUN ping used to determine writability.
 class ConnectionRequest : public StunRequest {
  public:
@@ -1159,6 +1184,8 @@
 void Connection::OnSendStunPacket(const void* data, size_t size,
                                   StunRequest* req) {
   rtc::PacketOptions options(port_->DefaultDscpValue());
+  options.info_signaled_after_sent.packet_type =
+      rtc::PacketType::kIceConnectivityCheck;
   auto err = port_->SendTo(
       data, size, remote_candidate_.address(), options, false);
   if (err < 0) {
diff --git a/p2p/base/port.h b/p2p/base/port.h
index 434aaef..10463ed 100644
--- a/p2p/base/port.h
+++ b/p2p/base/port.h
@@ -448,6 +448,8 @@
   // Extra work to be done in subclasses when a connection is destroyed.
   virtual void HandleConnectionDestroyed(Connection* conn) {}
 
+  void CopyPortInformationToPacketInfo(rtc::PacketInfo* info) const;
+
  private:
   void Construct();
   // Called when one of our connections deletes itself.
diff --git a/p2p/base/relayport.cc b/p2p/base/relayport.cc
index d1c5ac6..373882f 100644
--- a/p2p/base/relayport.cc
+++ b/p2p/base/relayport.cc
@@ -349,7 +349,9 @@
   }
 
   // Send the actual contents to the server using the usual mechanism.
-  int sent = entry->SendTo(data, size, addr, options);
+  rtc::PacketOptions modified_options(options);
+  CopyPortInformationToPacketInfo(&modified_options.info_signaled_after_sent);
+  int sent = entry->SendTo(data, size, addr, modified_options);
   if (sent <= 0) {
     RTC_DCHECK(sent < 0);
     error_ = entry->GetError();
diff --git a/p2p/base/stunport.cc b/p2p/base/stunport.cc
index 1a6db16..2f6bf61 100644
--- a/p2p/base/stunport.cc
+++ b/p2p/base/stunport.cc
@@ -268,7 +268,9 @@
                     const rtc::SocketAddress& addr,
                     const rtc::PacketOptions& options,
                     bool payload) {
-  int sent = socket_->SendTo(data, size, addr, options);
+  rtc::PacketOptions modified_options(options);
+  CopyPortInformationToPacketInfo(&modified_options.info_signaled_after_sent);
+  int sent = socket_->SendTo(data, size, addr, modified_options);
   if (sent < 0) {
     error_ = socket_->GetError();
     RTC_LOG(LS_ERROR) << ToString() << ": UDP send of "
@@ -526,6 +528,8 @@
 void UDPPort::OnSendPacket(const void* data, size_t size, StunRequest* req) {
   StunBindingRequest* sreq = static_cast<StunBindingRequest*>(req);
   rtc::PacketOptions options(DefaultDscpValue());
+  options.info_signaled_after_sent.packet_type = rtc::PacketType::kStunMessage;
+  CopyPortInformationToPacketInfo(&options.info_signaled_after_sent);
   if (socket_->SendTo(data, size, sreq->server_addr(), options) < 0) {
     RTC_LOG_ERR_EX(LERROR, socket_->GetError()) << "sendto";
   }
diff --git a/p2p/base/tcpport.cc b/p2p/base/tcpport.cc
index 45acfc7..7017952 100644
--- a/p2p/base/tcpport.cc
+++ b/p2p/base/tcpport.cc
@@ -216,8 +216,9 @@
                       << addr.ToSensitiveString();
     return SOCKET_ERROR;  // TODO(tbd): Set error_
   }
-
-  int sent = socket->Send(data, size, options);
+  rtc::PacketOptions modified_options(options);
+  CopyPortInformationToPacketInfo(&modified_options.info_signaled_after_sent);
+  int sent = socket->Send(data, size, modified_options);
   if (sent < 0) {
     error_ = socket->GetError();
     // Error from this code path for a Connection (instead of from a bare
@@ -386,7 +387,10 @@
     return SOCKET_ERROR;
   }
   stats_.sent_total_packets++;
-  int sent = socket_->Send(data, size, options);
+  rtc::PacketOptions modified_options(options);
+  static_cast<TCPPort*>(port_)->CopyPortInformationToPacketInfo(
+      &modified_options.info_signaled_after_sent);
+  int sent = socket_->Send(data, size, modified_options);
   if (sent < 0) {
     stats_.sent_discarded_packets++;
     error_ = socket_->GetError();
diff --git a/p2p/base/turnport.cc b/p2p/base/turnport.cc
index bf858be..57ce32b 100644
--- a/p2p/base/turnport.cc
+++ b/p2p/base/turnport.cc
@@ -595,7 +595,9 @@
   }
 
   // Send the actual contents to the server using the usual mechanism.
-  int sent = entry->Send(data, size, payload, options);
+  rtc::PacketOptions modified_options(options);
+  CopyPortInformationToPacketInfo(&modified_options.info_signaled_after_sent);
+  int sent = entry->Send(data, size, payload, modified_options);
   if (sent <= 0) {
     return SOCKET_ERROR;
   }
@@ -795,6 +797,8 @@
                                 StunRequest* request) {
   RTC_DCHECK(connected());
   rtc::PacketOptions options(DefaultDscpValue());
+  options.info_signaled_after_sent.packet_type = rtc::PacketType::kTurnMessage;
+  CopyPortInformationToPacketInfo(&options.info_signaled_after_sent);
   if (Send(data, size, options) < 0) {
     RTC_LOG(LS_ERROR) << ToString()
                       << ": Failed to send TURN message, error: "
@@ -1717,7 +1721,10 @@
     buf.WriteUInt16(static_cast<uint16_t>(size));
     buf.WriteBytes(reinterpret_cast<const char*>(data), size);
   }
-  return port_->Send(buf.Data(), buf.Length(), options);
+  rtc::PacketOptions modified_options(options);
+  modified_options.info_signaled_after_sent.turn_overhead_bytes =
+      buf.Length() - size;
+  return port_->Send(buf.Data(), buf.Length(), modified_options);
 }
 
 void TurnEntry::OnCreatePermissionSuccess() {
diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn
index 1f8e5cc..35c9da8 100644
--- a/rtc_base/BUILD.gn
+++ b/rtc_base/BUILD.gn
@@ -805,6 +805,7 @@
     "sigslot.cc",
     "sigslot.h",
     "sigslotrepeater.h",
+    "socket.cc",
     "socket.h",
     "socketadapters.cc",
     "socketadapters.h",
diff --git a/rtc_base/asyncpacketsocket.cc b/rtc_base/asyncpacketsocket.cc
index d945039..104e511 100644
--- a/rtc_base/asyncpacketsocket.cc
+++ b/rtc_base/asyncpacketsocket.cc
@@ -12,18 +12,28 @@
 
 namespace rtc {
 
-PacketTimeUpdateParams::PacketTimeUpdateParams()
-    : rtp_sendtime_extension_id(-1),
-      srtp_auth_tag_len(-1),
-      srtp_packet_index(-1) {
-}
+PacketTimeUpdateParams::PacketTimeUpdateParams() = default;
+
+PacketTimeUpdateParams::PacketTimeUpdateParams(
+    const PacketTimeUpdateParams& other) = default;
 
 PacketTimeUpdateParams::~PacketTimeUpdateParams() = default;
 
-AsyncPacketSocket::AsyncPacketSocket() {
-}
+PacketOptions::PacketOptions() = default;
+PacketOptions::PacketOptions(DiffServCodePoint dscp) : dscp(dscp) {}
+PacketOptions::PacketOptions(const PacketOptions& other) = default;
+PacketOptions::~PacketOptions() = default;
 
-AsyncPacketSocket::~AsyncPacketSocket() {
+AsyncPacketSocket::AsyncPacketSocket() = default;
+
+AsyncPacketSocket::~AsyncPacketSocket() = default;
+
+void CopySocketInformationToPacketInfo(size_t packet_size_bytes,
+                                       const AsyncPacketSocket& socket_from,
+                                       rtc::PacketInfo* info) {
+  info->packet_size_bytes = packet_size_bytes;
+  info->local_socket_address = socket_from.GetLocalAddress();
+  info->remote_socket_address = socket_from.GetRemoteAddress();
 }
 
 };  // namespace rtc
diff --git a/rtc_base/asyncpacketsocket.h b/rtc_base/asyncpacketsocket.h
index 16f4de0..6ae0525 100644
--- a/rtc_base/asyncpacketsocket.h
+++ b/rtc_base/asyncpacketsocket.h
@@ -24,23 +24,28 @@
 // after changing the value.
 struct PacketTimeUpdateParams {
   PacketTimeUpdateParams();
+  PacketTimeUpdateParams(const PacketTimeUpdateParams& other);
   ~PacketTimeUpdateParams();
 
-  int rtp_sendtime_extension_id;    // extension header id present in packet.
+  int rtp_sendtime_extension_id = -1;  // extension header id present in packet.
   std::vector<char> srtp_auth_key;  // Authentication key.
-  int srtp_auth_tag_len;            // Authentication tag length.
-  int64_t srtp_packet_index;        // Required for Rtp Packet authentication.
+  int srtp_auth_tag_len = -1;       // Authentication tag length.
+  int64_t srtp_packet_index = -1;   // Required for Rtp Packet authentication.
 };
 
 // This structure holds meta information for the packet which is about to send
 // over network.
 struct PacketOptions {
-  PacketOptions() : dscp(DSCP_NO_CHANGE), packet_id(-1) {}
-  explicit PacketOptions(DiffServCodePoint dscp) : dscp(dscp), packet_id(-1) {}
+  PacketOptions();
+  explicit PacketOptions(DiffServCodePoint dscp);
+  PacketOptions(const PacketOptions& other);
+  ~PacketOptions();
 
-  DiffServCodePoint dscp;
-  int packet_id;  // 16 bits, -1 represents "not set".
+  DiffServCodePoint dscp = DSCP_NO_CHANGE;
+  int packet_id = -1;  // 16 bits, -1 represents "not set".
   PacketTimeUpdateParams packet_time_params;
+  // PacketInfo is passed to SentPacket when signaling this packet is sent.
+  PacketInfo info_signaled_after_sent;
 };
 
 // This structure will have the information about when packet is actually
@@ -138,6 +143,10 @@
   RTC_DISALLOW_COPY_AND_ASSIGN(AsyncPacketSocket);
 };
 
+void CopySocketInformationToPacketInfo(size_t packet_size_bytes,
+                                       const AsyncPacketSocket& socket_from,
+                                       rtc::PacketInfo* info);
+
 }  // namespace rtc
 
 #endif  // RTC_BASE_ASYNCPACKETSOCKET_H_
diff --git a/rtc_base/asynctcpsocket.cc b/rtc_base/asynctcpsocket.cc
index 9e0589c..0e35841 100644
--- a/rtc_base/asynctcpsocket.cc
+++ b/rtc_base/asynctcpsocket.cc
@@ -297,7 +297,9 @@
     return res;
   }
 
-  rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis());
+  rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
+                              options.info_signaled_after_sent);
+  CopySocketInformationToPacketInfo(cb, *this, &sent_packet.info);
   SignalSentPacket(this, sent_packet);
 
   // We claim to have sent the whole thing, even if we only sent partial
diff --git a/rtc_base/asyncudpsocket.cc b/rtc_base/asyncudpsocket.cc
index 5a50ae3..c874ee6 100644
--- a/rtc_base/asyncudpsocket.cc
+++ b/rtc_base/asyncudpsocket.cc
@@ -60,7 +60,9 @@
 
 int AsyncUDPSocket::Send(const void *pv, size_t cb,
                          const rtc::PacketOptions& options) {
-  rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis());
+  rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
+                              options.info_signaled_after_sent);
+  CopySocketInformationToPacketInfo(cb, *this, &sent_packet.info);
   int ret = socket_->Send(pv, cb);
   SignalSentPacket(this, sent_packet);
   return ret;
@@ -69,7 +71,10 @@
 int AsyncUDPSocket::SendTo(const void *pv, size_t cb,
                            const SocketAddress& addr,
                            const rtc::PacketOptions& options) {
-  rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis());
+  rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
+                              options.info_signaled_after_sent);
+  CopySocketInformationToPacketInfo(cb, *this, &sent_packet.info);
+  sent_packet.info.remote_socket_address = addr;
   int ret = socket_->SendTo(pv, cb, addr);
   SignalSentPacket(this, sent_packet);
   return ret;
diff --git a/rtc_base/socket.cc b/rtc_base/socket.cc
new file mode 100644
index 0000000..13d5bc5
--- /dev/null
+++ b/rtc_base/socket.cc
@@ -0,0 +1,27 @@
+/*
+ *  Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/socket.h"
+
+namespace rtc {
+
+PacketInfo::PacketInfo() = default;
+PacketInfo::PacketInfo(const PacketInfo& info) = default;
+PacketInfo::~PacketInfo() = default;
+
+SentPacket::SentPacket() = default;
+SentPacket::SentPacket(int packet_id, int64_t send_time_ms)
+    : packet_id(packet_id), send_time_ms(send_time_ms) {}
+SentPacket::SentPacket(int packet_id,
+                       int64_t send_time_ms,
+                       const rtc::PacketInfo& info)
+    : packet_id(packet_id), send_time_ms(send_time_ms), info(info) {}
+
+}  // namespace rtc
diff --git a/rtc_base/socket.h b/rtc_base/socket.h
index ca1a302..d735d3f 100644
--- a/rtc_base/socket.h
+++ b/rtc_base/socket.h
@@ -25,6 +25,7 @@
 #include "rtc_base/win32.h"
 #endif
 
+#include "api/optional.h"
 #include "rtc_base/basictypes.h"
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/socketaddress.h"
@@ -123,13 +124,46 @@
   return (e == EWOULDBLOCK) || (e == EAGAIN) || (e == EINPROGRESS);
 }
 
-struct SentPacket {
-  SentPacket() : packet_id(-1), send_time_ms(-1) {}
-  SentPacket(int packet_id, int64_t send_time_ms)
-      : packet_id(packet_id), send_time_ms(send_time_ms) {}
+enum class PacketType {
+  kUnknown,
+  kData,
+  kIceConnectivityCheck,
+  kIceConnectivityCheckResponse,
+  kStunMessage,
+  kTurnMessage,
+};
 
-  int packet_id;
-  int64_t send_time_ms;
+enum class PacketInfoProtocolType {
+  kUnknown,
+  kUdp,
+  kTcp,
+  kSsltcp,
+  kTls,
+};
+
+struct PacketInfo {
+  PacketInfo();
+  PacketInfo(const PacketInfo& info);
+  ~PacketInfo();
+
+  PacketType packet_type = PacketType::kUnknown;
+  PacketInfoProtocolType protocol = PacketInfoProtocolType::kUnknown;
+  // A unique id assigned by the network manager, and rtc::nullopt if not set.
+  rtc::Optional<uint16_t> network_id;
+  size_t packet_size_bytes = 0;
+  size_t turn_overhead_bytes = 0;
+  SocketAddress local_socket_address;
+  SocketAddress remote_socket_address;
+};
+
+struct SentPacket {
+  SentPacket();
+  SentPacket(int packet_id, int64_t send_time_ms);
+  SentPacket(int packet_id, int64_t send_time_ms, const rtc::PacketInfo& info);
+
+  int packet_id = -1;
+  int64_t send_time_ms = -1;
+  rtc::PacketInfo info;
 };
 
 // General interface for the socket implementations of various networks.  The