From 6e641e64b2d9aac6ff1a2c57e70f01a2b99f6d2b Mon Sep 17 00:00:00 2001 From: Qingsi Wang Date: Wed, 11 Apr 2018 20:14:17 -0700 Subject: [PATCH] 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 Reviewed-by: Taylor Brandstetter Reviewed-by: Bjorn Mellem Cr-Commit-Position: refs/heads/master@{#22834} --- media/base/rtpdataengine.cc | 4 ++- media/engine/webrtcvoiceengine.h | 3 +- p2p/base/p2ptransportchannel.cc | 5 ++- p2p/base/p2ptransportchannel_unittest.cc | 14 ++++++++ p2p/base/port.cc | 27 ++++++++++++++ p2p/base/port.h | 2 ++ p2p/base/relayport.cc | 4 ++- p2p/base/stunport.cc | 6 +++- p2p/base/tcpport.cc | 10 ++++-- p2p/base/turnport.cc | 11 ++++-- rtc_base/BUILD.gn | 1 + rtc_base/asyncpacketsocket.cc | 26 +++++++++----- rtc_base/asyncpacketsocket.h | 23 ++++++++---- rtc_base/asynctcpsocket.cc | 4 ++- rtc_base/asyncudpsocket.cc | 9 +++-- rtc_base/socket.cc | 27 ++++++++++++++ rtc_base/socket.h | 46 ++++++++++++++++++++---- 17 files changed, 188 insertions(+), 34 deletions(-) create mode 100644 rtc_base/socket.cc diff --git a/media/base/rtpdataengine.cc b/media/base/rtpdataengine.cc index 3aebe84584..6e2155b3b2 100644 --- a/media/base/rtpdataengine.cc +++ b/media/base/rtpdataengine.cc @@ -327,7 +327,9 @@ bool RtpDataMediaChannel::SendData( << ", 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 56cccbc3fd..21b352bf87 100644 --- a/media/engine/webrtcvoiceengine.h +++ b/media/engine/webrtcvoiceengine.h @@ -206,7 +206,8 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, 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 804cab153c..00f7388217 100644 --- a/p2p/base/p2ptransportchannel.cc +++ b/p2p/base/p2ptransportchannel.cc @@ -1206,7 +1206,10 @@ int P2PTransportChannel::SendPacket(const char *data, size_t len, } 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 2b0efacc2d..192cbaa6c1 100644 --- a/p2p/base/p2ptransportchannel_unittest.cc +++ b/p2p/base/p2ptransportchannel_unittest.cc @@ -382,6 +382,8 @@ class P2PTransportChannelTestBase : public testing::Test, 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 @@ class P2PTransportChannelTestBase : public testing::Test, 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 @@ class P2PTransportChannelTestBase : public testing::Test, 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 7d3c719e47..c2fcdd63e7 100644 --- a/p2p/base/port.cc +++ b/p2p/base/port.cc @@ -115,6 +115,22 @@ webrtc::IceCandidateNetworkType ConvertNetworkType(rtc::AdapterType type) { 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 @@ void Port::SendBindingResponse(StunMessage* request, 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 @@ void Port::SendBindingErrorResponse(StunMessage* request, 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 @@ const std::string Port::username_fragment() const { 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 @@ int Connection::receiving_timeout() const { 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 434aaef204..10463ede51 100644 --- a/p2p/base/port.h +++ b/p2p/base/port.h @@ -448,6 +448,8 @@ class Port : public PortInterface, public rtc::MessageHandler, // 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 d1c5ac6943..373882fd68 100644 --- a/p2p/base/relayport.cc +++ b/p2p/base/relayport.cc @@ -349,7 +349,9 @@ int RelayPort::SendTo(const void* data, size_t size, } // 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 1a6db168ff..2f6bf614c6 100644 --- a/p2p/base/stunport.cc +++ b/p2p/base/stunport.cc @@ -268,7 +268,9 @@ int UDPPort::SendTo(const void* data, size_t size, 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::MaybeSetPortCompleteOrError() { void UDPPort::OnSendPacket(const void* data, size_t size, StunRequest* req) { StunBindingRequest* sreq = static_cast(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 45acfc7ecc..7017952806 100644 --- a/p2p/base/tcpport.cc +++ b/p2p/base/tcpport.cc @@ -216,8 +216,9 @@ int TCPPort::SendTo(const void* data, size_t size, << 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 @@ int TCPConnection::Send(const void* data, size_t size, return SOCKET_ERROR; } stats_.sent_total_packets++; - int sent = socket_->Send(data, size, options); + rtc::PacketOptions modified_options(options); + static_cast(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 bf858be17e..57ce32b82c 100644 --- a/p2p/base/turnport.cc +++ b/p2p/base/turnport.cc @@ -595,7 +595,9 @@ int TurnPort::SendTo(const void* data, size_t size, } // 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 @@ void TurnPort::OnSendStunPacket(const void* data, size_t size, 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 @@ int TurnEntry::Send(const void* data, size_t size, bool payload, buf.WriteUInt16(static_cast(size)); buf.WriteBytes(reinterpret_cast(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 1f8e5ccb27..35c9da895a 100644 --- a/rtc_base/BUILD.gn +++ b/rtc_base/BUILD.gn @@ -805,6 +805,7 @@ rtc_static_library("rtc_base_generic") { "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 d9450398a5..104e511d04 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 16f4de0822..6ae0525e5c 100644 --- a/rtc_base/asyncpacketsocket.h +++ b/rtc_base/asyncpacketsocket.h @@ -24,23 +24,28 @@ namespace rtc { // 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 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 @@ class AsyncPacketSocket : public sigslot::has_slots<> { 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 9e0589c194..0e35841412 100644 --- a/rtc_base/asynctcpsocket.cc +++ b/rtc_base/asynctcpsocket.cc @@ -297,7 +297,9 @@ int AsyncTCPSocket::Send(const void *pv, size_t cb, 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 5a50ae3855..c874ee6ce0 100644 --- a/rtc_base/asyncudpsocket.cc +++ b/rtc_base/asyncudpsocket.cc @@ -60,7 +60,9 @@ SocketAddress AsyncUDPSocket::GetRemoteAddress() const { 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::Send(const void *pv, size_t cb, 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 0000000000..13d5bc546f --- /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 ca1a30267a..d735d3f107 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 @@ inline bool IsBlockingError(int e) { 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 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