commit d0126d1340b8bb5cca506e999540c81d24aa4336
parent 50c999e25d8ee1b77bed801bc49339e6143f8b37
Author: Michael Froman <mfroman@mozilla.com>
Date: Wed, 15 Oct 2025 11:16:22 -0500
Bug 1993083 - Vendor libwebrtc from 58733c5bd2
Upstream commit: https://webrtc.googlesource.com/src/+/58733c5bd2b86bfac68cdc31bb7527945518d251
Remove PseudoTcp implementation from WebRTC
The webrtc::PseudoTcp class was only used by Chromium's remoting/protocol/
and has been moved there as of crrev.com/c/6760418.
Bug: chromium:431990415
Change-Id: I3a25bbf1d968017d7a65c41a3feae5ef6a91533b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/402480
Commit-Queue: Helmut Januschka <helmut@januschka.com>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#45242}
Diffstat:
10 files changed, 9 insertions(+), 2729 deletions(-)
diff --git a/third_party/libwebrtc/README.mozilla.last-vendor b/third_party/libwebrtc/README.mozilla.last-vendor
@@ -1,4 +1,4 @@
# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /home/mfroman/mozilla/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc
-libwebrtc updated from /home/mfroman/mozilla/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2025-10-15T16:15:08.237570+00:00.
+libwebrtc updated from /home/mfroman/mozilla/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2025-10-15T16:16:10.069554+00:00.
# base of lastest vendoring
-244e9693bb
+58733c5bd2
diff --git a/third_party/libwebrtc/moz-patch-stack/s0103.patch b/third_party/libwebrtc/moz-patch-stack/s0103.patch
@@ -782,7 +782,7 @@ index 33f4ee8624..edd3e02d77 100644
deps = [ ":google_test_runner_delegate" ]
}
diff --git a/test/fuzzers/BUILD.gn b/test/fuzzers/BUILD.gn
-index d8f0eba11f..eb25867dc9 100644
+index 6bdaf144fb..184f608d1b 100644
--- a/test/fuzzers/BUILD.gn
+++ b/test/fuzzers/BUILD.gn
@@ -6,7 +6,7 @@
diff --git a/third_party/libwebrtc/p2p/BUILD.gn b/third_party/libwebrtc/p2p/BUILD.gn
@@ -638,7 +638,7 @@ rtc_library("port_interface") {
"../api:candidate",
"../api:field_trials_view",
"../api:packet_socket_factory",
- "../api/task_queue:task_queue",
+ "../api/task_queue",
"../rtc_base:async_packet_socket",
"../rtc_base:callback_list",
"../rtc_base:dscp",
@@ -652,26 +652,6 @@ rtc_library("port_interface") {
]
}
-rtc_library("pseudo_tcp") {
- sources = [
- "base/pseudo_tcp.cc",
- "base/pseudo_tcp.h",
- ]
- deps = [
- "../api:array_view",
- "../rtc_base:byte_buffer",
- "../rtc_base:byte_order",
- "../rtc_base:checks",
- "../rtc_base:logging",
- "../rtc_base:macromagic",
- "../rtc_base:safe_minmax",
- "../rtc_base:socket",
- "../rtc_base:timeutils",
- "../rtc_base/synchronization:mutex",
- "../rtc_base/system:rtc_export",
- ]
-}
-
rtc_library("regathering_controller") {
sources = [
"base/regathering_controller.cc",
@@ -1172,7 +1152,6 @@ if (rtc_include_tests) {
"base/packet_transport_internal_unittest.cc",
"base/port_allocator_unittest.cc",
"base/port_unittest.cc",
- "base/pseudo_tcp_unittest.cc",
"base/regathering_controller_unittest.cc",
"base/stun_dictionary_unittest.cc",
"base/stun_port_unittest.cc",
@@ -1219,7 +1198,6 @@ if (rtc_include_tests) {
":port",
":port_allocator",
":port_interface",
- ":pseudo_tcp",
":regathering_controller",
":relay_port_factory_interface",
":stun_dictionary",
diff --git a/third_party/libwebrtc/p2p/base/pseudo_tcp.cc b/third_party/libwebrtc/p2p/base/pseudo_tcp.cc
@@ -1,1434 +0,0 @@
-/*
- * Copyright 2004 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 "p2p/base/pseudo_tcp.h"
-
-#include <algorithm>
-#include <cerrno>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <memory>
-#include <set>
-
-#include "api/array_view.h"
-#include "rtc_base/byte_buffer.h"
-#include "rtc_base/byte_order.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/logging.h"
-#include "rtc_base/numerics/safe_minmax.h"
-#include "rtc_base/socket.h"
-#include "rtc_base/synchronization/mutex.h"
-#include "rtc_base/time_utils.h"
-
-// The following logging is for detailed (packet-level) analysis only.
-#define _DBG_NONE 0
-#define _DBG_NORMAL 1
-#define _DBG_VERBOSE 2
-#define _DEBUGMSG _DBG_NONE
-
-namespace webrtc {
-
-//////////////////////////////////////////////////////////////////////
-// Network Constants
-//////////////////////////////////////////////////////////////////////
-
-// Standard MTUs
-const uint16_t PACKET_MAXIMUMS[] = {
- 65535, // Theoretical maximum, Hyperchannel
- 32000, // Nothing
- 17914, // 16Mb IBM Token Ring
- 8166, // IEEE 802.4
- // 4464, // IEEE 802.5 (4Mb max)
- 4352, // FDDI
- // 2048, // Wideband Network
- 2002, // IEEE 802.5 (4Mb recommended)
- // 1536, // Expermental Ethernet Networks
- // 1500, // Ethernet, Point-to-Point (default)
- 1492, // IEEE 802.3
- 1006, // SLIP, ARPANET
- // 576, // X.25 Networks
- // 544, // DEC IP Portal
- // 512, // NETBIOS
- 508, // IEEE 802/Source-Rt Bridge, ARCNET
- 296, // Point-to-Point (low delay)
- // 68, // Official minimum
- 0, // End of list marker
-};
-
-const uint32_t MAX_PACKET = 65535;
-// Note: we removed lowest level because packet overhead was larger!
-const uint32_t MIN_PACKET = 296;
-
-const uint32_t IP_HEADER_SIZE = 20; // (+ up to 40 bytes of options?)
-const uint32_t UDP_HEADER_SIZE = 8;
-// TODO(?): Make JINGLE_HEADER_SIZE transparent to this code?
-const uint32_t JINGLE_HEADER_SIZE = 64; // when relay framing is in use
-
-// Default size for receive and send buffer.
-const uint32_t DEFAULT_RCV_BUF_SIZE = 60 * 1024;
-const uint32_t DEFAULT_SND_BUF_SIZE = 90 * 1024;
-
-//////////////////////////////////////////////////////////////////////
-// Global Constants and Functions
-//////////////////////////////////////////////////////////////////////
-//
-// 0 1 2 3
-// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// 0 | Conversation Number |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// 4 | Sequence Number |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// 8 | Acknowledgment Number |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | | |U|A|P|R|S|F| |
-// 12 | Control | |R|C|S|S|Y|I| Window |
-// | | |G|K|H|T|N|N| |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// 16 | Timestamp sending |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// 20 | Timestamp receiving |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// 24 | data |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//
-//////////////////////////////////////////////////////////////////////
-
-#define PSEUDO_KEEPALIVE 0
-
-const uint32_t HEADER_SIZE = 24;
-const uint32_t PACKET_OVERHEAD =
- HEADER_SIZE + UDP_HEADER_SIZE + IP_HEADER_SIZE + JINGLE_HEADER_SIZE;
-
-const uint32_t MIN_RTO =
- 250; // 250 ms (RFC1122, Sec 4.2.3.1 "fractions of a second")
-const uint32_t DEF_RTO = 3000; // 3 seconds (RFC1122, Sec 4.2.3.1)
-const uint32_t MAX_RTO = 60000; // 60 seconds
-const uint32_t DEF_ACK_DELAY = 100; // 100 milliseconds
-
-const uint8_t FLAG_CTL = 0x02;
-const uint8_t FLAG_RST = 0x04;
-
-const uint8_t CTL_CONNECT = 0;
-
-// TCP options.
-const uint8_t TCP_OPT_EOL = 0; // End of list.
-const uint8_t TCP_OPT_NOOP = 1; // No-op.
-const uint8_t TCP_OPT_MSS = 2; // Maximum segment size.
-const uint8_t TCP_OPT_WND_SCALE = 3; // Window scale factor.
-
-const long DEFAULT_TIMEOUT =
- 4000; // If there are no pending clocks, wake up every 4 seconds
-const long CLOSED_TIMEOUT =
- 60 * 1000; // If the connection is closed, once per minute
-
-#if PSEUDO_KEEPALIVE
-// !?! Rethink these times
-const uint32_t IDLE_PING =
- 20 *
- 1000; // 20 seconds (note: WinXP SP2 firewall udp timeout is 90 seconds)
-const uint32_t IDLE_TIMEOUT = 90 * 1000; // 90 seconds;
-#endif // PSEUDO_KEEPALIVE
-
-//////////////////////////////////////////////////////////////////////
-// Helper Functions
-//////////////////////////////////////////////////////////////////////
-
-inline void long_to_bytes(uint32_t val, void* buf) {
- *static_cast<uint32_t*>(buf) = HostToNetwork32(val);
-}
-
-inline void short_to_bytes(uint16_t val, void* buf) {
- *static_cast<uint16_t*>(buf) = HostToNetwork16(val);
-}
-
-inline uint32_t bytes_to_long(const void* buf) {
- return NetworkToHost32(*static_cast<const uint32_t*>(buf));
-}
-
-inline uint16_t bytes_to_short(const void* buf) {
- return NetworkToHost16(*static_cast<const uint16_t*>(buf));
-}
-
-//////////////////////////////////////////////////////////////////////
-// Debugging Statistics
-//////////////////////////////////////////////////////////////////////
-
-#if 0 // Not used yet
-
-enum Stat {
- S_SENT_PACKET, // All packet sends
- S_RESENT_PACKET, // All packet sends that are retransmits
- S_RECV_PACKET, // All packet receives
- S_RECV_NEW, // All packet receives that are too new
- S_RECV_OLD, // All packet receives that are too old
- S_NUM_STATS
-};
-
-const char* const STAT_NAMES[S_NUM_STATS] = {
- "snt",
- "snt-r",
- "rcv"
- "rcv-n",
- "rcv-o"
-};
-
-int g_stats[S_NUM_STATS];
-inline void Incr(Stat s) { ++g_stats[s]; }
-void ReportStats() {
- char buffer[256];
- size_t len = 0;
- for (int i = 0; i < S_NUM_STATS; ++i) {
- len += snprintf(buffer, std::size(buffer), "%s%s:%d",
- (i == 0) ? "" : ",", STAT_NAMES[i], g_stats[i]);
- g_stats[i] = 0;
- }
- RTC_LOG(LS_INFO) << "Stats[" << buffer << "]";
-}
-
-#endif
-
-//////////////////////////////////////////////////////////////////////
-// PseudoTcp
-//////////////////////////////////////////////////////////////////////
-
-uint32_t PseudoTcp::Now() {
-#if 0 // Use this to synchronize timers with logging timestamps (easier debug)
- return static_cast<uint32_t>(TimeSince(StartTime()));
-#else
- return Time32();
-#endif
-}
-
-PseudoTcp::PseudoTcp(IPseudoTcpNotify* notify, uint32_t conv)
- : m_notify(notify),
- m_shutdown(SD_NONE),
- m_error(0),
- m_rbuf_len(DEFAULT_RCV_BUF_SIZE),
- m_rbuf(m_rbuf_len),
- m_sbuf_len(DEFAULT_SND_BUF_SIZE),
- m_sbuf(m_sbuf_len) {
- // Sanity check on buffer sizes (needed for OnTcpWriteable notification logic)
- RTC_DCHECK(m_rbuf_len + MIN_PACKET < m_sbuf_len);
-
- uint32_t now = Now();
-
- m_state = TCP_LISTEN;
- m_conv = conv;
- m_rcv_wnd = m_rbuf_len;
- m_rwnd_scale = m_swnd_scale = 0;
- m_snd_nxt = 0;
- m_snd_wnd = 1;
- m_snd_una = m_rcv_nxt = 0;
- m_bReadEnable = true;
- m_bWriteEnable = false;
- m_t_ack = 0;
-
- m_msslevel = 0;
- m_largest = 0;
- RTC_DCHECK(MIN_PACKET > PACKET_OVERHEAD);
- m_mss = MIN_PACKET - PACKET_OVERHEAD;
- m_mtu_advise = MAX_PACKET;
-
- m_rto_base = 0;
-
- m_cwnd = 2 * m_mss;
- m_ssthresh = m_rbuf_len;
- m_lastrecv = m_lastsend = m_lasttraffic = now;
- m_bOutgoing = false;
-
- m_dup_acks = 0;
- m_recover = 0;
-
- m_ts_recent = m_ts_lastack = 0;
-
- m_rx_rto = DEF_RTO;
- m_rx_srtt = m_rx_rttvar = 0;
-
- m_use_nagling = true;
- m_ack_delay = DEF_ACK_DELAY;
- m_support_wnd_scale = true;
-}
-
-PseudoTcp::~PseudoTcp() {}
-
-int PseudoTcp::Connect() {
- if (m_state != TCP_LISTEN) {
- m_error = EINVAL;
- return -1;
- }
-
- m_state = TCP_SYN_SENT;
- RTC_LOG(LS_INFO) << "State: TCP_SYN_SENT";
-
- queueConnectMessage();
- attemptSend();
-
- return 0;
-}
-
-void PseudoTcp::NotifyMTU(uint16_t mtu) {
- m_mtu_advise = mtu;
- if (m_state == TCP_ESTABLISHED) {
- adjustMTU();
- }
-}
-
-void PseudoTcp::NotifyClock(uint32_t now) {
- if (m_state == TCP_CLOSED)
- return;
-
- // Check if it's time to retransmit a segment
- if (m_rto_base && (TimeDiff32(m_rto_base + m_rx_rto, now) <= 0)) {
- if (m_slist.empty()) {
- RTC_DCHECK_NOTREACHED();
- } else {
-// Note: (m_slist.front().xmit == 0)) {
-// retransmit segments
-#if _DEBUGMSG >= _DBG_NORMAL
- RTC_LOG(LS_INFO) << "timeout retransmit (rto: " << m_rx_rto
- << ") (rto_base: " << m_rto_base << ") (now: " << now
- << ") (dup_acks: " << static_cast<unsigned>(m_dup_acks)
- << ")";
-#endif // _DEBUGMSG
- if (!transmit(m_slist.begin(), now)) {
- closedown(ECONNABORTED);
- return;
- }
-
- uint32_t nInFlight = m_snd_nxt - m_snd_una;
- m_ssthresh = std::max(nInFlight / 2, 2 * m_mss);
- // RTC_LOG(LS_INFO) << "m_ssthresh: " << m_ssthresh << " nInFlight: " <<
- // nInFlight << " m_mss: " << m_mss;
- m_cwnd = m_mss;
-
- // Back off retransmit timer. Note: the limit is lower when connecting.
- uint32_t rto_limit = (m_state < TCP_ESTABLISHED) ? DEF_RTO : MAX_RTO;
- m_rx_rto = std::min(rto_limit, m_rx_rto * 2);
- m_rto_base = now;
- }
- }
-
- // Check if it's time to probe closed windows
- if ((m_snd_wnd == 0) && (TimeDiff32(m_lastsend + m_rx_rto, now) <= 0)) {
- if (TimeDiff32(now, m_lastrecv) >= 15000) {
- closedown(ECONNABORTED);
- return;
- }
-
- // probe the window
- packet(m_snd_nxt - 1, 0, 0, 0);
- m_lastsend = now;
-
- // back off retransmit timer
- m_rx_rto = std::min(MAX_RTO, m_rx_rto * 2);
- }
-
- // Check if it's time to send delayed acks
- if (m_t_ack && (TimeDiff32(m_t_ack + m_ack_delay, now) <= 0)) {
- packet(m_snd_nxt, 0, 0, 0);
- }
-
-#if PSEUDO_KEEPALIVE
- // Check for idle timeout
- if ((m_state == TCP_ESTABLISHED) &&
- (TimeDiff32(m_lastrecv + IDLE_TIMEOUT, now) <= 0)) {
- closedown(ECONNABORTED);
- return;
- }
-
- // Check for ping timeout (to keep udp mapping open)
- if ((m_state == TCP_ESTABLISHED) &&
- (TimeDiff32(m_lasttraffic + (m_bOutgoing ? IDLE_PING * 3 / 2 : IDLE_PING),
- now) <= 0)) {
- packet(m_snd_nxt, 0, 0, 0);
- }
-#endif // PSEUDO_KEEPALIVE
-}
-
-bool PseudoTcp::NotifyPacket(const char* buffer, size_t len) {
- if (len > MAX_PACKET) {
- RTC_LOG_F(LS_WARNING) << "packet too large";
- return false;
- }
- return parse(reinterpret_cast<const uint8_t*>(buffer), uint32_t(len));
-}
-
-bool PseudoTcp::GetNextClock(uint32_t now, long& timeout) {
- return clock_check(now, timeout);
-}
-
-void PseudoTcp::GetOption(Option opt, int* value) {
- if (opt == OPT_NODELAY) {
- *value = m_use_nagling ? 0 : 1;
- } else if (opt == OPT_ACKDELAY) {
- *value = m_ack_delay;
- } else if (opt == OPT_SNDBUF) {
- *value = m_sbuf_len;
- } else if (opt == OPT_RCVBUF) {
- *value = m_rbuf_len;
- } else {
- RTC_DCHECK_NOTREACHED();
- }
-}
-void PseudoTcp::SetOption(Option opt, int value) {
- if (opt == OPT_NODELAY) {
- m_use_nagling = value == 0;
- } else if (opt == OPT_ACKDELAY) {
- m_ack_delay = value;
- } else if (opt == OPT_SNDBUF) {
- RTC_DCHECK(m_state == TCP_LISTEN);
- resizeSendBuffer(value);
- } else if (opt == OPT_RCVBUF) {
- RTC_DCHECK(m_state == TCP_LISTEN);
- resizeReceiveBuffer(value);
- } else {
- RTC_DCHECK_NOTREACHED();
- }
-}
-
-uint32_t PseudoTcp::GetCongestionWindow() const {
- return m_cwnd;
-}
-
-uint32_t PseudoTcp::GetBytesInFlight() const {
- return m_snd_nxt - m_snd_una;
-}
-
-uint32_t PseudoTcp::GetBytesBufferedNotSent() const {
- return static_cast<uint32_t>(m_snd_una + m_sbuf.GetBuffered() - m_snd_nxt);
-}
-
-uint32_t PseudoTcp::GetRoundTripTimeEstimateMs() const {
- return m_rx_srtt;
-}
-
-//
-// IPStream Implementation
-//
-
-int PseudoTcp::Recv(char* buffer, size_t len) {
- if (m_state != TCP_ESTABLISHED) {
- m_error = ENOTCONN;
- return SOCKET_ERROR;
- }
-
- size_t read = 0;
- if (!m_rbuf.Read(buffer, len, &read)) {
- m_bReadEnable = true;
- m_error = EWOULDBLOCK;
- return SOCKET_ERROR;
- }
-
- size_t available_space = 0;
- m_rbuf.GetWriteRemaining(&available_space);
-
- if (uint32_t(available_space) - m_rcv_wnd >=
- std::min<uint32_t>(m_rbuf_len / 2, m_mss)) {
- // TODO(jbeda): !?! Not sure about this was closed business
- bool bWasClosed = (m_rcv_wnd == 0);
- m_rcv_wnd = static_cast<uint32_t>(available_space);
-
- if (bWasClosed) {
- attemptSend(sfImmediateAck);
- }
- }
-
- return static_cast<int>(read);
-}
-
-int PseudoTcp::Send(const char* buffer, size_t len) {
- if (m_state != TCP_ESTABLISHED) {
- m_error = ENOTCONN;
- return SOCKET_ERROR;
- }
-
- size_t available_space = 0;
- m_sbuf.GetWriteRemaining(&available_space);
-
- if (!available_space) {
- m_bWriteEnable = true;
- m_error = EWOULDBLOCK;
- return SOCKET_ERROR;
- }
-
- int written = queue(buffer, uint32_t(len), false);
- attemptSend();
- return written;
-}
-
-void PseudoTcp::Close(bool force) {
- RTC_LOG_F(LS_VERBOSE) << "(" << (force ? "true" : "false") << ")";
- m_shutdown = force ? SD_FORCEFUL : SD_GRACEFUL;
-}
-
-int PseudoTcp::GetError() {
- return m_error;
-}
-
-//
-// Internal Implementation
-//
-
-uint32_t PseudoTcp::queue(const char* data, uint32_t len, bool bCtrl) {
- size_t available_space = 0;
- m_sbuf.GetWriteRemaining(&available_space);
-
- if (len > static_cast<uint32_t>(available_space)) {
- RTC_DCHECK(!bCtrl);
- len = static_cast<uint32_t>(available_space);
- }
-
- // We can concatenate data if the last segment is the same type
- // (control v. regular data), and has not been transmitted yet
- if (!m_slist.empty() && (m_slist.back().bCtrl == bCtrl) &&
- (m_slist.back().xmit == 0)) {
- m_slist.back().len += len;
- } else {
- SSegment sseg(static_cast<uint32_t>(m_snd_una + m_sbuf.GetBuffered()), len,
- bCtrl);
- m_slist.push_back(sseg);
- }
-
- size_t written = 0;
- m_sbuf.Write(data, len, &written);
- return static_cast<uint32_t>(written);
-}
-
-IPseudoTcpNotify::WriteResult PseudoTcp::packet(uint32_t seq,
- uint8_t flags,
- uint32_t offset,
- uint32_t len) {
- RTC_DCHECK(HEADER_SIZE + len <= MAX_PACKET);
-
- uint32_t now = Now();
-
- std::unique_ptr<uint8_t[]> buffer(new uint8_t[MAX_PACKET]);
- long_to_bytes(m_conv, buffer.get());
- long_to_bytes(seq, buffer.get() + 4);
- long_to_bytes(m_rcv_nxt, buffer.get() + 8);
- buffer[12] = 0;
- buffer[13] = flags;
- short_to_bytes(static_cast<uint16_t>(m_rcv_wnd >> m_rwnd_scale),
- buffer.get() + 14);
-
- // Timestamp computations
- long_to_bytes(now, buffer.get() + 16);
- long_to_bytes(m_ts_recent, buffer.get() + 20);
- m_ts_lastack = m_rcv_nxt;
-
- if (len) {
- size_t bytes_read = 0;
- bool result =
- m_sbuf.ReadOffset(buffer.get() + HEADER_SIZE, len, offset, &bytes_read);
- RTC_DCHECK(result);
- RTC_DCHECK(static_cast<uint32_t>(bytes_read) == len);
- }
-
-#if _DEBUGMSG >= _DBG_VERBOSE
- RTC_LOG(LS_INFO) << "<-- <CONV=" << m_conv
- << "><FLG=" << static_cast<unsigned>(flags)
- << "><SEQ=" << seq << ":" << seq + len
- << "><ACK=" << m_rcv_nxt << "><WND=" << m_rcv_wnd
- << "><TS=" << (now % 10000)
- << "><TSR=" << (m_ts_recent % 10000) << "><LEN=" << len
- << ">";
-#endif // _DEBUGMSG
-
- IPseudoTcpNotify::WriteResult wres = m_notify->TcpWritePacket(
- this, reinterpret_cast<char*>(buffer.get()), len + HEADER_SIZE);
- // Note: When len is 0, this is an ACK packet. We don't read the return value
- // for those, and thus we won't retry. So go ahead and treat the packet as a
- // success (basically simulate as if it were dropped), which will prevent our
- // timers from being messed up.
- if ((wres != IPseudoTcpNotify::WR_SUCCESS) && (0 != len))
- return wres;
-
- m_t_ack = 0;
- if (len > 0) {
- m_lastsend = now;
- }
- m_lasttraffic = now;
- m_bOutgoing = true;
-
- return IPseudoTcpNotify::WR_SUCCESS;
-}
-
-bool PseudoTcp::parse(const uint8_t* buffer, uint32_t size) {
- if (size < HEADER_SIZE)
- return false;
-
- Segment seg;
- seg.conv = bytes_to_long(buffer);
- seg.seq = bytes_to_long(buffer + 4);
- seg.ack = bytes_to_long(buffer + 8);
- seg.flags = buffer[13];
- seg.wnd = bytes_to_short(buffer + 14);
-
- seg.tsval = bytes_to_long(buffer + 16);
- seg.tsecr = bytes_to_long(buffer + 20);
-
- seg.data = reinterpret_cast<const char*>(buffer) + HEADER_SIZE;
- seg.len = size - HEADER_SIZE;
-
-#if _DEBUGMSG >= _DBG_VERBOSE
- RTC_LOG(LS_INFO) << "--> <CONV=" << seg.conv
- << "><FLG=" << static_cast<unsigned>(seg.flags)
- << "><SEQ=" << seg.seq << ":" << seg.seq + seg.len
- << "><ACK=" << seg.ack << "><WND=" << seg.wnd
- << "><TS=" << (seg.tsval % 10000)
- << "><TSR=" << (seg.tsecr % 10000) << "><LEN=" << seg.len
- << ">";
-#endif // _DEBUGMSG
-
- return process(seg);
-}
-
-bool PseudoTcp::clock_check(uint32_t now, long& nTimeout) {
- if (m_shutdown == SD_FORCEFUL)
- return false;
-
- if ((m_shutdown == SD_GRACEFUL) &&
- ((m_state != TCP_ESTABLISHED) ||
- ((m_sbuf.GetBuffered() == 0) && (m_t_ack == 0)))) {
- return false;
- }
-
- if (m_state == TCP_CLOSED) {
- nTimeout = CLOSED_TIMEOUT;
- return true;
- }
-
- nTimeout = DEFAULT_TIMEOUT;
-
- if (m_t_ack) {
- nTimeout =
- std::min<int32_t>(nTimeout, TimeDiff32(m_t_ack + m_ack_delay, now));
- }
- if (m_rto_base) {
- nTimeout =
- std::min<int32_t>(nTimeout, TimeDiff32(m_rto_base + m_rx_rto, now));
- }
- if (m_snd_wnd == 0) {
- nTimeout =
- std::min<int32_t>(nTimeout, TimeDiff32(m_lastsend + m_rx_rto, now));
- }
-#if PSEUDO_KEEPALIVE
- if (m_state == TCP_ESTABLISHED) {
- nTimeout = std::min<int32_t>(
- nTimeout, TimeDiff32(m_lasttraffic +
- (m_bOutgoing ? IDLE_PING * 3 / 2 : IDLE_PING),
- now));
- }
-#endif // PSEUDO_KEEPALIVE
- return true;
-}
-
-bool PseudoTcp::process(Segment& seg) {
- // If this is the wrong conversation, send a reset!?! (with the correct
- // conversation?)
- if (seg.conv != m_conv) {
- // if ((seg.flags & FLAG_RST) == 0) {
- // packet(tcb, seg.ack, 0, FLAG_RST, 0, 0);
- //}
- RTC_LOG_F(LS_ERROR) << "wrong conversation";
- return false;
- }
-
- uint32_t now = Now();
- m_lasttraffic = m_lastrecv = now;
- m_bOutgoing = false;
-
- if (m_state == TCP_CLOSED) {
- // !?! send reset?
- RTC_LOG_F(LS_ERROR) << "closed";
- return false;
- }
-
- // Check if this is a reset segment
- if (seg.flags & FLAG_RST) {
- closedown(ECONNRESET);
- return false;
- }
-
- // Check for control data
- bool bConnect = false;
- if (seg.flags & FLAG_CTL) {
- if (seg.len == 0) {
- RTC_LOG_F(LS_ERROR) << "Missing control code";
- return false;
- } else if (seg.data[0] == CTL_CONNECT) {
- bConnect = true;
-
- // TCP options are in the remainder of the payload after CTL_CONNECT.
- parseOptions(&seg.data[1], seg.len - 1);
-
- if (m_state == TCP_LISTEN) {
- m_state = TCP_SYN_RECEIVED;
- RTC_LOG(LS_INFO) << "State: TCP_SYN_RECEIVED";
- // m_notify->associate(addr);
- queueConnectMessage();
- } else if (m_state == TCP_SYN_SENT) {
- m_state = TCP_ESTABLISHED;
- RTC_LOG(LS_INFO) << "State: TCP_ESTABLISHED";
- adjustMTU();
- if (m_notify) {
- m_notify->OnTcpOpen(this);
- }
- // notify(evOpen);
- }
- } else {
- RTC_LOG_F(LS_WARNING) << "Unknown control code: " << seg.data[0];
- return false;
- }
- }
-
- // Update timestamp
- if ((seg.seq <= m_ts_lastack) && (m_ts_lastack < seg.seq + seg.len)) {
- m_ts_recent = seg.tsval;
- }
-
- // Check if this is a valuable ack
- if ((seg.ack > m_snd_una) && (seg.ack <= m_snd_nxt)) {
- // Calculate round-trip time
- if (seg.tsecr) {
- int32_t rtt = TimeDiff32(now, seg.tsecr);
- if (rtt >= 0) {
- if (m_rx_srtt == 0) {
- m_rx_srtt = rtt;
- m_rx_rttvar = rtt / 2;
- } else {
- uint32_t unsigned_rtt = static_cast<uint32_t>(rtt);
- uint32_t abs_err = unsigned_rtt > m_rx_srtt
- ? unsigned_rtt - m_rx_srtt
- : m_rx_srtt - unsigned_rtt;
- m_rx_rttvar = (3 * m_rx_rttvar + abs_err) / 4;
- m_rx_srtt = (7 * m_rx_srtt + rtt) / 8;
- }
- m_rx_rto = SafeClamp(m_rx_srtt + SafeMax(1, 4 * m_rx_rttvar), MIN_RTO,
- MAX_RTO);
-#if _DEBUGMSG >= _DBG_VERBOSE
- RTC_LOG(LS_INFO) << "rtt: " << rtt << " srtt: " << m_rx_srtt
- << " rto: " << m_rx_rto;
-#endif // _DEBUGMSG
- } else {
- RTC_LOG(LS_WARNING) << "rtt < 0";
- }
- }
-
- m_snd_wnd = static_cast<uint32_t>(seg.wnd) << m_swnd_scale;
-
- uint32_t nAcked = seg.ack - m_snd_una;
- m_snd_una = seg.ack;
-
- m_rto_base = (m_snd_una == m_snd_nxt) ? 0 : now;
-
- m_sbuf.ConsumeReadData(nAcked);
-
- for (uint32_t nFree = nAcked; nFree > 0;) {
- RTC_DCHECK(!m_slist.empty());
- if (nFree < m_slist.front().len) {
- m_slist.front().len -= nFree;
- nFree = 0;
- } else {
- if (m_slist.front().len > m_largest) {
- m_largest = m_slist.front().len;
- }
- nFree -= m_slist.front().len;
- m_slist.pop_front();
- }
- }
-
- if (m_dup_acks >= 3) {
- if (m_snd_una >= m_recover) { // NewReno
- uint32_t nInFlight = m_snd_nxt - m_snd_una;
- m_cwnd = std::min(m_ssthresh, nInFlight + m_mss); // (Fast Retransmit)
-#if _DEBUGMSG >= _DBG_NORMAL
- RTC_LOG(LS_INFO) << "exit recovery";
-#endif // _DEBUGMSG
- m_dup_acks = 0;
- } else {
-#if _DEBUGMSG >= _DBG_NORMAL
- RTC_LOG(LS_INFO) << "recovery retransmit";
-#endif // _DEBUGMSG
- if (!transmit(m_slist.begin(), now)) {
- closedown(ECONNABORTED);
- return false;
- }
- m_cwnd += m_mss - std::min(nAcked, m_cwnd);
- }
- } else {
- m_dup_acks = 0;
- // Slow start, congestion avoidance
- if (m_cwnd < m_ssthresh) {
- m_cwnd += m_mss;
- } else {
- m_cwnd += std::max<uint32_t>(1, m_mss * m_mss / m_cwnd);
- }
- }
- } else if (seg.ack == m_snd_una) {
- // !?! Note, tcp says don't do this... but otherwise how does a closed
- // window become open?
- m_snd_wnd = static_cast<uint32_t>(seg.wnd) << m_swnd_scale;
-
- // Check duplicate acks
- if (seg.len > 0) {
- // it's a dup ack, but with a data payload, so don't modify m_dup_acks
- } else if (m_snd_una != m_snd_nxt) {
- m_dup_acks += 1;
- if (m_dup_acks == 3) { // (Fast Retransmit)
-#if _DEBUGMSG >= _DBG_NORMAL
- RTC_LOG(LS_INFO) << "enter recovery";
- RTC_LOG(LS_INFO) << "recovery retransmit";
-#endif // _DEBUGMSG
- if (!transmit(m_slist.begin(), now)) {
- closedown(ECONNABORTED);
- return false;
- }
- m_recover = m_snd_nxt;
- uint32_t nInFlight = m_snd_nxt - m_snd_una;
- m_ssthresh = std::max(nInFlight / 2, 2 * m_mss);
- // RTC_LOG(LS_INFO) << "m_ssthresh: " << m_ssthresh << " nInFlight: "
- // << nInFlight << " m_mss: " << m_mss;
- m_cwnd = m_ssthresh + 3 * m_mss;
- } else if (m_dup_acks > 3) {
- m_cwnd += m_mss;
- }
- } else {
- m_dup_acks = 0;
- }
- }
-
- // !?! A bit hacky
- if ((m_state == TCP_SYN_RECEIVED) && !bConnect) {
- m_state = TCP_ESTABLISHED;
- RTC_LOG(LS_INFO) << "State: TCP_ESTABLISHED";
- adjustMTU();
- if (m_notify) {
- m_notify->OnTcpOpen(this);
- }
- // notify(evOpen);
- }
-
- // If we make room in the send queue, notify the user
- // The goal it to make sure we always have at least enough data to fill the
- // window. We'd like to notify the app when we are halfway to that point.
- const uint32_t kIdealRefillSize = (m_sbuf_len + m_rbuf_len) / 2;
- if (m_bWriteEnable &&
- static_cast<uint32_t>(m_sbuf.GetBuffered()) < kIdealRefillSize) {
- m_bWriteEnable = false;
- if (m_notify) {
- m_notify->OnTcpWriteable(this);
- }
- // notify(evWrite);
- }
-
- // Conditions were acks must be sent:
- // 1) Segment is too old (they missed an ACK) (immediately)
- // 2) Segment is too new (we missed a segment) (immediately)
- // 3) Segment has data (so we need to ACK!) (delayed)
- // ... so the only time we don't need to ACK, is an empty segment that points
- // to rcv_nxt!
-
- SendFlags sflags = sfNone;
- if (seg.seq != m_rcv_nxt) {
- sflags = sfImmediateAck; // (Fast Recovery)
- } else if (seg.len != 0) {
- if (m_ack_delay == 0) {
- sflags = sfImmediateAck;
- } else {
- sflags = sfDelayedAck;
- }
- }
-#if _DEBUGMSG >= _DBG_NORMAL
- if (sflags == sfImmediateAck) {
- if (seg.seq > m_rcv_nxt) {
- RTC_LOG_F(LS_INFO) << "too new";
- } else if (seg.seq + seg.len <= m_rcv_nxt) {
- RTC_LOG_F(LS_INFO) << "too old";
- }
- }
-#endif // _DEBUGMSG
-
- // Adjust the incoming segment to fit our receive buffer
- if (seg.seq < m_rcv_nxt) {
- uint32_t nAdjust = m_rcv_nxt - seg.seq;
- if (nAdjust < seg.len) {
- seg.seq += nAdjust;
- seg.data += nAdjust;
- seg.len -= nAdjust;
- } else {
- seg.len = 0;
- }
- }
-
- size_t available_space = 0;
- m_rbuf.GetWriteRemaining(&available_space);
-
- if ((seg.seq + seg.len - m_rcv_nxt) >
- static_cast<uint32_t>(available_space)) {
- uint32_t nAdjust =
- seg.seq + seg.len - m_rcv_nxt - static_cast<uint32_t>(available_space);
- if (nAdjust < seg.len) {
- seg.len -= nAdjust;
- } else {
- seg.len = 0;
- }
- }
-
- bool bIgnoreData = (seg.flags & FLAG_CTL) || (m_shutdown != SD_NONE);
- bool bNewData = false;
-
- if (seg.len > 0) {
- bool bRecover = false;
- if (bIgnoreData) {
- if (seg.seq == m_rcv_nxt) {
- m_rcv_nxt += seg.len;
- // If we received a data segment out of order relative to a control
- // segment, then we wrote it into the receive buffer at an offset (see
- // "WriteOffset") below. So we need to advance the position in the
- // buffer to avoid corrupting data. See bugs.webrtc.org/9208
- //
- // We advance the position in the buffer by N bytes by acting like we
- // wrote N bytes and then immediately read them. We can only do this if
- // there's not already data ready to read, but this should always be
- // true in the problematic scenario, since control frames are always
- // sent first in the stream.
- if (m_rbuf.GetBuffered() == 0) {
- m_rbuf.ConsumeWriteBuffer(seg.len);
- m_rbuf.ConsumeReadData(seg.len);
- // After shifting the position in the buffer, we may have
- // out-of-order packets ready to be recovered.
- bRecover = true;
- }
- }
- } else {
- uint32_t nOffset = seg.seq - m_rcv_nxt;
-
- if (!m_rbuf.WriteOffset(seg.data, seg.len, nOffset, nullptr)) {
- // Ignore incoming packets outside of the receive window.
- return false;
- }
-
- if (seg.seq == m_rcv_nxt) {
- m_rbuf.ConsumeWriteBuffer(seg.len);
- m_rcv_nxt += seg.len;
- m_rcv_wnd -= seg.len;
- bNewData = true;
- // May be able to recover packets previously received out-of-order
- // now.
- bRecover = true;
- } else {
-#if _DEBUGMSG >= _DBG_NORMAL
- RTC_LOG(LS_INFO) << "Saving " << seg.len << " bytes (" << seg.seq
- << " -> " << seg.seq + seg.len << ")";
-#endif // _DEBUGMSG
- RSegment rseg;
- rseg.seq = seg.seq;
- rseg.len = seg.len;
- RList::iterator it = m_rlist.begin();
- while ((it != m_rlist.end()) && (it->seq < rseg.seq)) {
- ++it;
- }
- m_rlist.insert(it, rseg);
- }
- }
- if (bRecover) {
- RList::iterator it = m_rlist.begin();
- while ((it != m_rlist.end()) && (it->seq <= m_rcv_nxt)) {
- if (it->seq + it->len > m_rcv_nxt) {
- sflags = sfImmediateAck; // (Fast Recovery)
- uint32_t nAdjust = (it->seq + it->len) - m_rcv_nxt;
-#if _DEBUGMSG >= _DBG_NORMAL
- RTC_LOG(LS_INFO) << "Recovered " << nAdjust << " bytes (" << m_rcv_nxt
- << " -> " << m_rcv_nxt + nAdjust << ")";
-#endif // _DEBUGMSG
- m_rbuf.ConsumeWriteBuffer(nAdjust);
- m_rcv_nxt += nAdjust;
- m_rcv_wnd -= nAdjust;
- bNewData = true;
- }
- it = m_rlist.erase(it);
- }
- }
- }
-
- attemptSend(sflags);
-
- // If we have new data, notify the user
- if (bNewData && m_bReadEnable) {
- m_bReadEnable = false;
- if (m_notify) {
- m_notify->OnTcpReadable(this);
- }
- // notify(evRead);
- }
-
- return true;
-}
-
-bool PseudoTcp::transmit(const SList::iterator& seg, uint32_t now) {
- if (seg->xmit >= ((m_state == TCP_ESTABLISHED) ? 15 : 30)) {
- RTC_LOG_F(LS_VERBOSE) << "too many retransmits";
- return false;
- }
-
- uint32_t nTransmit = std::min(seg->len, m_mss);
-
- while (true) {
- uint32_t seq = seg->seq;
- uint8_t flags = (seg->bCtrl ? FLAG_CTL : 0);
- IPseudoTcpNotify::WriteResult wres =
- packet(seq, flags, seg->seq - m_snd_una, nTransmit);
-
- if (wres == IPseudoTcpNotify::WR_SUCCESS)
- break;
-
- if (wres == IPseudoTcpNotify::WR_FAIL) {
- RTC_LOG_F(LS_VERBOSE) << "packet failed";
- return false;
- }
-
- RTC_DCHECK(wres == IPseudoTcpNotify::WR_TOO_LARGE);
-
- while (true) {
- if (PACKET_MAXIMUMS[m_msslevel + 1] == 0) {
- RTC_LOG_F(LS_VERBOSE) << "MTU too small";
- return false;
- }
- // !?! We need to break up all outstanding and pending packets and then
- // retransmit!?!
-
- m_mss = PACKET_MAXIMUMS[++m_msslevel] - PACKET_OVERHEAD;
- m_cwnd = 2 * m_mss; // I added this... haven't researched actual formula
- if (m_mss < nTransmit) {
- nTransmit = m_mss;
- break;
- }
- }
-#if _DEBUGMSG >= _DBG_NORMAL
- RTC_LOG(LS_INFO) << "Adjusting mss to " << m_mss << " bytes";
-#endif // _DEBUGMSG
- }
-
- if (nTransmit < seg->len) {
- RTC_LOG_F(LS_VERBOSE) << "mss reduced to " << m_mss;
-
- SSegment subseg(seg->seq + nTransmit, seg->len - nTransmit, seg->bCtrl);
- // subseg.tstamp = seg->tstamp;
- subseg.xmit = seg->xmit;
- seg->len = nTransmit;
-
- SList::iterator next = seg;
- m_slist.insert(++next, subseg);
- }
-
- if (seg->xmit == 0) {
- m_snd_nxt += seg->len;
- }
- seg->xmit += 1;
- // seg->tstamp = now;
- if (m_rto_base == 0) {
- m_rto_base = now;
- }
-
- return true;
-}
-
-void PseudoTcp::attemptSend(SendFlags sflags) {
- uint32_t now = Now();
-
- if (TimeDiff32(now, m_lastsend) > static_cast<long>(m_rx_rto)) {
- m_cwnd = m_mss;
- }
-
-#if _DEBUGMSG
- bool bFirst = true;
-#endif // _DEBUGMSG
-
- while (true) {
- uint32_t cwnd = m_cwnd;
- if ((m_dup_acks == 1) || (m_dup_acks == 2)) { // Limited Transmit
- cwnd += m_dup_acks * m_mss;
- }
- uint32_t nWindow = std::min(m_snd_wnd, cwnd);
- uint32_t nInFlight = m_snd_nxt - m_snd_una;
- uint32_t nUseable = (nInFlight < nWindow) ? (nWindow - nInFlight) : 0;
-
- size_t snd_buffered = m_sbuf.GetBuffered();
- uint32_t nAvailable =
- std::min(static_cast<uint32_t>(snd_buffered) - nInFlight, m_mss);
-
- if (nAvailable > nUseable) {
- if (nUseable * 4 < nWindow) {
- // RFC 813 - avoid SWS
- nAvailable = 0;
- } else {
- nAvailable = nUseable;
- }
- }
-
-#if _DEBUGMSG >= _DBG_VERBOSE
- if (bFirst) {
- size_t available_space = 0;
- m_sbuf.GetWriteRemaining(&available_space);
-
- bFirst = false;
- RTC_LOG(LS_INFO) << "[cwnd: " << m_cwnd << " nWindow: " << nWindow
- << " nInFlight: " << nInFlight
- << " nAvailable: " << nAvailable
- << " nQueued: " << snd_buffered
- << " nEmpty: " << available_space
- << " ssthresh: " << m_ssthresh << "]";
- }
-#endif // _DEBUGMSG
-
- if (nAvailable == 0) {
- if (sflags == sfNone)
- return;
-
- // If this is an immediate ack, or the second delayed ack
- if ((sflags == sfImmediateAck) || m_t_ack) {
- packet(m_snd_nxt, 0, 0, 0);
- } else {
- m_t_ack = Now();
- }
- return;
- }
-
- // Nagle's algorithm.
- // If there is data already in-flight, and we haven't a full segment of
- // data ready to send then hold off until we get more to send, or the
- // in-flight data is acknowledged.
- if (m_use_nagling && (m_snd_nxt > m_snd_una) && (nAvailable < m_mss)) {
- return;
- }
-
- // Find the next segment to transmit
- SList::iterator it = m_slist.begin();
- while (it->xmit > 0) {
- ++it;
- RTC_DCHECK(it != m_slist.end());
- }
- SList::iterator seg = it;
-
- // If the segment is too large, break it into two
- if (seg->len > nAvailable) {
- SSegment subseg(seg->seq + nAvailable, seg->len - nAvailable, seg->bCtrl);
- seg->len = nAvailable;
- m_slist.insert(++it, subseg);
- }
-
- if (!transmit(seg, now)) {
- RTC_LOG_F(LS_VERBOSE) << "transmit failed";
- // TODO(?): consider closing socket
- return;
- }
-
- sflags = sfNone;
- }
-}
-
-void PseudoTcp::closedown(uint32_t err) {
- RTC_LOG(LS_INFO) << "State: TCP_CLOSED";
- m_state = TCP_CLOSED;
- if (m_notify) {
- m_notify->OnTcpClosed(this, err);
- }
- // notify(evClose, err);
-}
-
-void PseudoTcp::adjustMTU() {
- // Determine our current mss level, so that we can adjust appropriately later
- for (m_msslevel = 0; PACKET_MAXIMUMS[m_msslevel + 1] > 0; ++m_msslevel) {
- if (static_cast<uint16_t>(PACKET_MAXIMUMS[m_msslevel]) <= m_mtu_advise) {
- break;
- }
- }
- m_mss = m_mtu_advise - PACKET_OVERHEAD;
-// !?! Should we reset m_largest here?
-#if _DEBUGMSG >= _DBG_NORMAL
- RTC_LOG(LS_INFO) << "Adjusting mss to " << m_mss << " bytes";
-#endif // _DEBUGMSG
- // Enforce minimums on ssthresh and cwnd
- m_ssthresh = std::max(m_ssthresh, 2 * m_mss);
- m_cwnd = std::max(m_cwnd, m_mss);
-}
-
-bool PseudoTcp::isReceiveBufferFull() const {
- size_t available_space = 0;
- m_rbuf.GetWriteRemaining(&available_space);
- return !available_space;
-}
-
-void PseudoTcp::disableWindowScale() {
- m_support_wnd_scale = false;
-}
-
-void PseudoTcp::queueConnectMessage() {
- ByteBufferWriter buf;
-
- buf.WriteUInt8(CTL_CONNECT);
- if (m_support_wnd_scale) {
- buf.WriteUInt8(TCP_OPT_WND_SCALE);
- buf.WriteUInt8(1);
- buf.WriteUInt8(m_rwnd_scale);
- }
- m_snd_wnd = static_cast<uint32_t>(buf.Length());
- queue(reinterpret_cast<const char*>(buf.Data()),
- static_cast<uint32_t>(buf.Length()), true);
-}
-
-void PseudoTcp::parseOptions(const char* data, uint32_t len) {
- std::set<uint8_t> options_specified;
-
- // See http://www.freesoft.org/CIE/Course/Section4/8.htm for
- // parsing the options list.
- ByteBufferReader buf(
- MakeArrayView(reinterpret_cast<const uint8_t*>(data), len));
- while (buf.Length()) {
- uint8_t kind = TCP_OPT_EOL;
- buf.ReadUInt8(&kind);
-
- if (kind == TCP_OPT_EOL) {
- // End of option list.
- break;
- } else if (kind == TCP_OPT_NOOP) {
- // No op.
- continue;
- }
-
- // Length of this option.
- RTC_DCHECK(len != 0);
- uint8_t opt_len = 0;
- buf.ReadUInt8(&opt_len);
-
- // Content of this option.
- if (opt_len <= buf.Length()) {
- applyOption(kind, reinterpret_cast<const char*>(buf.Data()), opt_len);
- buf.Consume(opt_len);
- } else {
- RTC_LOG(LS_ERROR) << "Invalid option length received.";
- return;
- }
- options_specified.insert(kind);
- }
-
- if (options_specified.find(TCP_OPT_WND_SCALE) == options_specified.end()) {
- RTC_LOG(LS_WARNING) << "Peer doesn't support window scaling";
-
- if (m_rwnd_scale > 0) {
- // Peer doesn't support TCP options and window scaling.
- // Revert receive buffer size to default value.
- resizeReceiveBuffer(DEFAULT_RCV_BUF_SIZE);
- m_swnd_scale = 0;
- }
- }
-}
-
-void PseudoTcp::applyOption(char kind, const char* data, uint32_t len) {
- if (kind == TCP_OPT_MSS) {
- RTC_LOG(LS_WARNING) << "Peer specified MSS option which is not supported.";
- // TODO(?): Implement.
- } else if (kind == TCP_OPT_WND_SCALE) {
- // Window scale factor.
- // http://www.ietf.org/rfc/rfc1323.txt
- if (len != 1) {
- RTC_LOG_F(LS_WARNING) << "Invalid window scale option received.";
- return;
- }
- applyWindowScaleOption(data[0]);
- }
-}
-
-void PseudoTcp::applyWindowScaleOption(uint8_t scale_factor) {
- m_swnd_scale = scale_factor;
-}
-
-void PseudoTcp::resizeSendBuffer(uint32_t new_size) {
- m_sbuf_len = new_size;
- m_sbuf.SetCapacity(new_size);
-}
-
-void PseudoTcp::resizeReceiveBuffer(uint32_t new_size) {
- uint8_t scale_factor = 0;
-
- // Determine the scale factor such that the scaled window size can fit
- // in a 16-bit unsigned integer.
- while (new_size > 0xFFFF) {
- ++scale_factor;
- new_size >>= 1;
- }
-
- // Determine the proper size of the buffer.
- new_size <<= scale_factor;
- bool result = m_rbuf.SetCapacity(new_size);
-
- // Make sure the new buffer is large enough to contain data in the old
- // buffer. This should always be true because this method is called either
- // before connection is established or when peers are exchanging connect
- // messages.
- RTC_DCHECK(result);
- m_rbuf_len = new_size;
- m_rwnd_scale = scale_factor;
- m_ssthresh = new_size;
-
- size_t available_space = 0;
- m_rbuf.GetWriteRemaining(&available_space);
- m_rcv_wnd = static_cast<uint32_t>(available_space);
-}
-
-PseudoTcp::LockedFifoBuffer::LockedFifoBuffer(size_t size)
- : buffer_(new char[size]),
- buffer_length_(size),
- data_length_(0),
- read_position_(0) {}
-
-PseudoTcp::LockedFifoBuffer::~LockedFifoBuffer() {}
-
-size_t PseudoTcp::LockedFifoBuffer::GetBuffered() const {
- MutexLock lock(&mutex_);
- return data_length_;
-}
-
-bool PseudoTcp::LockedFifoBuffer::SetCapacity(size_t size) {
- MutexLock lock(&mutex_);
- if (data_length_ > size)
- return false;
-
- if (size != buffer_length_) {
- char* buffer = new char[size];
- const size_t copy = data_length_;
- const size_t tail_copy = std::min(copy, buffer_length_ - read_position_);
- memcpy(buffer, &buffer_[read_position_], tail_copy);
- memcpy(buffer + tail_copy, &buffer_[0], copy - tail_copy);
- buffer_.reset(buffer);
- read_position_ = 0;
- buffer_length_ = size;
- }
-
- return true;
-}
-
-bool PseudoTcp::LockedFifoBuffer::ReadOffset(void* buffer,
- size_t bytes,
- size_t offset,
- size_t* bytes_read) {
- MutexLock lock(&mutex_);
- return ReadOffsetLocked(buffer, bytes, offset, bytes_read);
-}
-
-bool PseudoTcp::LockedFifoBuffer::WriteOffset(const void* buffer,
- size_t bytes,
- size_t offset,
- size_t* bytes_written) {
- MutexLock lock(&mutex_);
- return WriteOffsetLocked(buffer, bytes, offset, bytes_written);
-}
-
-bool PseudoTcp::LockedFifoBuffer::Read(void* buffer,
- size_t bytes,
- size_t* bytes_read) {
- MutexLock lock(&mutex_);
- size_t copy = 0;
- if (!ReadOffsetLocked(buffer, bytes, 0, ©))
- return false;
-
- // If read was successful then adjust the read position and number of
- // bytes buffered.
- read_position_ = (read_position_ + copy) % buffer_length_;
- data_length_ -= copy;
- if (bytes_read)
- *bytes_read = copy;
-
- return true;
-}
-
-bool PseudoTcp::LockedFifoBuffer::Write(const void* buffer,
- size_t bytes,
- size_t* bytes_written) {
- MutexLock lock(&mutex_);
- size_t copy = 0;
- if (!WriteOffsetLocked(buffer, bytes, 0, ©))
- return false;
-
- // If write was successful then adjust the number of readable bytes.
- data_length_ += copy;
- if (bytes_written) {
- *bytes_written = copy;
- }
-
- return true;
-}
-
-void PseudoTcp::LockedFifoBuffer::ConsumeReadData(size_t size) {
- MutexLock lock(&mutex_);
- RTC_DCHECK(size <= data_length_);
- read_position_ = (read_position_ + size) % buffer_length_;
- data_length_ -= size;
-}
-
-void PseudoTcp::LockedFifoBuffer::ConsumeWriteBuffer(size_t size) {
- MutexLock lock(&mutex_);
- RTC_DCHECK(size <= buffer_length_ - data_length_);
- data_length_ += size;
-}
-
-bool PseudoTcp::LockedFifoBuffer::GetWriteRemaining(size_t* size) const {
- MutexLock lock(&mutex_);
- *size = buffer_length_ - data_length_;
- return true;
-}
-
-bool PseudoTcp::LockedFifoBuffer::ReadOffsetLocked(void* buffer,
- size_t bytes,
- size_t offset,
- size_t* bytes_read) {
- if (offset >= data_length_)
- return false;
-
- const size_t available = data_length_ - offset;
- const size_t read_position = (read_position_ + offset) % buffer_length_;
- const size_t copy = std::min(bytes, available);
- const size_t tail_copy = std::min(copy, buffer_length_ - read_position);
- char* const p = static_cast<char*>(buffer);
- memcpy(p, &buffer_[read_position], tail_copy);
- memcpy(p + tail_copy, &buffer_[0], copy - tail_copy);
-
- if (bytes_read)
- *bytes_read = copy;
-
- return true;
-}
-
-bool PseudoTcp::LockedFifoBuffer::WriteOffsetLocked(const void* buffer,
- size_t bytes,
- size_t offset,
- size_t* bytes_written) {
- if (data_length_ + offset >= buffer_length_)
- return false;
-
- const size_t available = buffer_length_ - data_length_ - offset;
- const size_t write_position =
- (read_position_ + data_length_ + offset) % buffer_length_;
- const size_t copy = std::min(bytes, available);
- const size_t tail_copy = std::min(copy, buffer_length_ - write_position);
- const char* const p = static_cast<const char*>(buffer);
- memcpy(&buffer_[write_position], p, tail_copy);
- memcpy(&buffer_[0], p + tail_copy, copy - tail_copy);
-
- if (bytes_written)
- *bytes_written = copy;
-
- return true;
-}
-
-} // namespace webrtc
diff --git a/third_party/libwebrtc/p2p/base/pseudo_tcp.h b/third_party/libwebrtc/p2p/base/pseudo_tcp.h
@@ -1,296 +0,0 @@
-/*
- * Copyright 2004 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.
- */
-
-#ifndef P2P_BASE_PSEUDO_TCP_H_
-#define P2P_BASE_PSEUDO_TCP_H_
-
-#include <cstddef>
-#include <cstdint>
-#include <list>
-#include <memory>
-
-#include "rtc_base/synchronization/mutex.h"
-#include "rtc_base/system/rtc_export.h"
-#include "rtc_base/thread_annotations.h"
-
-namespace webrtc {
-
-//////////////////////////////////////////////////////////////////////
-// IPseudoTcpNotify
-//////////////////////////////////////////////////////////////////////
-
-class PseudoTcp;
-
-class IPseudoTcpNotify {
- public:
- // Notification of tcp events
- virtual void OnTcpOpen(PseudoTcp* tcp) = 0;
- virtual void OnTcpReadable(PseudoTcp* tcp) = 0;
- virtual void OnTcpWriteable(PseudoTcp* tcp) = 0;
- virtual void OnTcpClosed(PseudoTcp* tcp, uint32_t error) = 0;
-
- // Write the packet onto the network
- enum WriteResult { WR_SUCCESS, WR_TOO_LARGE, WR_FAIL };
- virtual WriteResult TcpWritePacket(PseudoTcp* tcp,
- const char* buffer,
- size_t len) = 0;
-
- protected:
- virtual ~IPseudoTcpNotify() {}
-};
-
-//////////////////////////////////////////////////////////////////////
-// PseudoTcp
-//////////////////////////////////////////////////////////////////////
-
-class RTC_EXPORT PseudoTcp {
- public:
- static uint32_t Now();
-
- PseudoTcp(IPseudoTcpNotify* notify, uint32_t conv);
- virtual ~PseudoTcp();
-
- int Connect();
- int Recv(char* buffer, size_t len);
- int Send(const char* buffer, size_t len);
- void Close(bool force);
- int GetError();
-
- enum TcpState {
- TCP_LISTEN,
- TCP_SYN_SENT,
- TCP_SYN_RECEIVED,
- TCP_ESTABLISHED,
- TCP_CLOSED
- };
- TcpState State() const { return m_state; }
-
- // Call this when the PMTU changes.
- void NotifyMTU(uint16_t mtu);
-
- // Call this based on timeout value returned from GetNextClock.
- // It's ok to call this too frequently.
- void NotifyClock(uint32_t now);
-
- // Call this whenever a packet arrives.
- // Returns true if the packet was processed successfully.
- bool NotifyPacket(const char* buffer, size_t len);
-
- // Call this to determine the next time NotifyClock should be called.
- // Returns false if the socket is ready to be destroyed.
- bool GetNextClock(uint32_t now, long& timeout);
-
- // Call these to get/set option values to tailor this PseudoTcp
- // instance's behaviour for the kind of data it will carry.
- // If an unrecognized option is set or got, an assertion will fire.
- //
- // Setting options for OPT_RCVBUF or OPT_SNDBUF after Connect() is called
- // will result in an assertion.
- enum Option {
- OPT_NODELAY, // Whether to enable Nagle's algorithm (0 == off)
- OPT_ACKDELAY, // The Delayed ACK timeout (0 == off).
- OPT_RCVBUF, // Set the receive buffer size, in bytes.
- OPT_SNDBUF, // Set the send buffer size, in bytes.
- };
- void GetOption(Option opt, int* value);
- void SetOption(Option opt, int value);
-
- // Returns current congestion window in bytes.
- uint32_t GetCongestionWindow() const;
-
- // Returns amount of data in bytes that has been sent, but haven't
- // been acknowledged.
- uint32_t GetBytesInFlight() const;
-
- // Returns number of bytes that were written in buffer and haven't
- // been sent.
- uint32_t GetBytesBufferedNotSent() const;
-
- // Returns current round-trip time estimate in milliseconds.
- uint32_t GetRoundTripTimeEstimateMs() const;
-
- protected:
- enum SendFlags { sfNone, sfDelayedAck, sfImmediateAck };
-
- struct Segment {
- uint32_t conv, seq, ack;
- uint8_t flags;
- uint16_t wnd;
- const char* data;
- uint32_t len;
- uint32_t tsval, tsecr;
- };
-
- struct SSegment {
- SSegment(uint32_t s, uint32_t l, bool c)
- : seq(s), len(l), /*tstamp(0),*/ xmit(0), bCtrl(c) {}
- uint32_t seq, len;
- // uint32_t tstamp;
- uint8_t xmit;
- bool bCtrl;
- };
- typedef std::list<SSegment> SList;
-
- struct RSegment {
- uint32_t seq, len;
- };
-
- uint32_t queue(const char* data, uint32_t len, bool bCtrl);
-
- // Creates a packet and submits it to the network. This method can either
- // send payload or just an ACK packet.
- //
- // `seq` is the sequence number of this packet.
- // `flags` is the flags for sending this packet.
- // `offset` is the offset to read from `m_sbuf`.
- // `len` is the number of bytes to read from `m_sbuf` as payload. If this
- // value is 0 then this is an ACK packet, otherwise this packet has payload.
- IPseudoTcpNotify::WriteResult packet(uint32_t seq,
- uint8_t flags,
- uint32_t offset,
- uint32_t len);
- bool parse(const uint8_t* buffer, uint32_t size);
-
- void attemptSend(SendFlags sflags = sfNone);
-
- void closedown(uint32_t err = 0);
-
- bool clock_check(uint32_t now, long& nTimeout);
-
- bool process(Segment& seg);
- bool transmit(const SList::iterator& seg, uint32_t now);
-
- void adjustMTU();
-
- protected:
- // This method is used in test only to query receive buffer state.
- bool isReceiveBufferFull() const;
-
- // This method is only used in tests, to disable window scaling
- // support for testing backward compatibility.
- void disableWindowScale();
-
- private:
- // Queue the connect message with TCP options.
- void queueConnectMessage();
-
- // Parse TCP options in the header.
- void parseOptions(const char* data, uint32_t len);
-
- // Apply a TCP option that has been read from the header.
- void applyOption(char kind, const char* data, uint32_t len);
-
- // Apply window scale option.
- void applyWindowScaleOption(uint8_t scale_factor);
-
- // Resize the send buffer with `new_size` in bytes.
- void resizeSendBuffer(uint32_t new_size);
-
- // Resize the receive buffer with `new_size` in bytes. This call adjusts
- // window scale factor `m_swnd_scale` accordingly.
- void resizeReceiveBuffer(uint32_t new_size);
-
- class LockedFifoBuffer final {
- public:
- explicit LockedFifoBuffer(size_t size);
- ~LockedFifoBuffer();
-
- size_t GetBuffered() const;
- bool SetCapacity(size_t size);
- bool ReadOffset(void* buffer,
- size_t bytes,
- size_t offset,
- size_t* bytes_read);
- bool WriteOffset(const void* buffer,
- size_t bytes,
- size_t offset,
- size_t* bytes_written);
- bool Read(void* buffer, size_t bytes, size_t* bytes_read);
- bool Write(const void* buffer, size_t bytes, size_t* bytes_written);
- void ConsumeReadData(size_t size);
- void ConsumeWriteBuffer(size_t size);
- bool GetWriteRemaining(size_t* size) const;
-
- private:
- bool ReadOffsetLocked(void* buffer,
- size_t bytes,
- size_t offset,
- size_t* bytes_read)
- RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
- bool WriteOffsetLocked(const void* buffer,
- size_t bytes,
- size_t offset,
- size_t* bytes_written)
- RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
-
- // the allocated buffer
- std::unique_ptr<char[]> buffer_ RTC_GUARDED_BY(mutex_);
- // size of the allocated buffer
- size_t buffer_length_ RTC_GUARDED_BY(mutex_);
- // amount of readable data in the buffer
- size_t data_length_ RTC_GUARDED_BY(mutex_);
- // offset to the readable data
- size_t read_position_ RTC_GUARDED_BY(mutex_);
- mutable Mutex mutex_;
- };
-
- IPseudoTcpNotify* m_notify;
- enum Shutdown { SD_NONE, SD_GRACEFUL, SD_FORCEFUL } m_shutdown;
- int m_error;
-
- // TCB data
- TcpState m_state;
- uint32_t m_conv;
- bool m_bReadEnable, m_bWriteEnable, m_bOutgoing;
- uint32_t m_lasttraffic;
-
- // Incoming data
- typedef std::list<RSegment> RList;
- RList m_rlist;
- uint32_t m_rbuf_len, m_rcv_nxt, m_rcv_wnd, m_lastrecv;
- uint8_t m_rwnd_scale; // Window scale factor.
- LockedFifoBuffer m_rbuf;
-
- // Outgoing data
- SList m_slist;
- uint32_t m_sbuf_len, m_snd_nxt, m_snd_wnd, m_lastsend, m_snd_una;
- uint8_t m_swnd_scale; // Window scale factor.
- LockedFifoBuffer m_sbuf;
-
- // Maximum segment size, estimated protocol level, largest segment sent
- uint32_t m_mss, m_msslevel, m_largest, m_mtu_advise;
- // Retransmit timer
- uint32_t m_rto_base;
-
- // Timestamp tracking
- uint32_t m_ts_recent, m_ts_lastack;
-
- // Round-trip calculation
- uint32_t m_rx_rttvar, m_rx_srtt, m_rx_rto;
-
- // Congestion avoidance, Fast retransmit/recovery, Delayed ACKs
- uint32_t m_ssthresh, m_cwnd;
- uint8_t m_dup_acks;
- uint32_t m_recover;
- uint32_t m_t_ack;
-
- // Configuration options
- bool m_use_nagling;
- uint32_t m_ack_delay;
-
- // This is used by unit tests to test backward compatibility of
- // PseudoTcp implementations that don't support window scaling.
- bool m_support_wnd_scale;
-};
-
-} // namespace webrtc
-
-
-#endif // P2P_BASE_PSEUDO_TCP_H_
diff --git a/third_party/libwebrtc/p2p/base/pseudo_tcp_unittest.cc b/third_party/libwebrtc/p2p/base/pseudo_tcp_unittest.cc
@@ -1,907 +0,0 @@
-/*
- * Copyright 2011 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 "p2p/base/pseudo_tcp.h"
-
-#include <algorithm>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "api/array_view.h"
-#include "api/task_queue/pending_task_safety_flag.h"
-#include "api/task_queue/task_queue_base.h"
-#include "api/test/rtc_error_matchers.h"
-#include "api/units/time_delta.h"
-#include "rtc_base/crypto_random.h"
-#include "rtc_base/logging.h"
-#include "rtc_base/memory_stream.h"
-#include "rtc_base/stream.h"
-#include "rtc_base/thread.h"
-#include "rtc_base/time_utils.h"
-#include "test/gmock.h"
-#include "test/gtest.h"
-#include "test/wait_until.h"
-
-using ::testing::IsTrue;
-using ::webrtc::PseudoTcp;
-using ::webrtc::ScopedTaskSafety;
-using ::webrtc::TaskQueueBase;
-using ::webrtc::TimeDelta;
-
-static const int kConnectTimeoutMs = 10000; // ~3 * default RTO of 3000ms
-static const int kTransferTimeoutMs = 15000;
-static const int kBlockSize = 4096;
-
-class PseudoTcpForTest : public webrtc::PseudoTcp {
- public:
- PseudoTcpForTest(webrtc::IPseudoTcpNotify* notify, uint32_t conv)
- : webrtc::PseudoTcp(notify, conv) {}
-
- bool isReceiveBufferFull() const {
- return webrtc::PseudoTcp::isReceiveBufferFull();
- }
-
- void disableWindowScale() { webrtc::PseudoTcp::disableWindowScale(); }
-};
-
-class PseudoTcpTestBase : public ::testing::Test,
- public webrtc::IPseudoTcpNotify {
- public:
- PseudoTcpTestBase()
- : local_(this, 1),
- remote_(this, 1),
- have_connected_(false),
- have_disconnected_(false),
- local_mtu_(65535),
- remote_mtu_(65535),
- delay_(0),
- loss_(0) {
- // Set use of the test RNG to get predictable loss patterns. Otherwise,
- // this test would occasionally get really unlucky loss and time out.
- webrtc::SetRandomTestMode(true);
- }
- ~PseudoTcpTestBase() override {
- // Put it back for the next test.
- webrtc::SetRandomTestMode(false);
- }
- // If true, both endpoints will send the "connect" segment simultaneously,
- // rather than `local_` sending it followed by a response from `remote_`.
- // Note that this is what chromoting ends up doing.
- void SetSimultaneousOpen(bool enabled) { simultaneous_open_ = enabled; }
- void SetLocalMtu(int mtu) {
- local_.NotifyMTU(mtu);
- local_mtu_ = mtu;
- }
- void SetRemoteMtu(int mtu) {
- remote_.NotifyMTU(mtu);
- remote_mtu_ = mtu;
- }
- void SetDelay(int delay) { delay_ = delay; }
- void SetLoss(int percent) { loss_ = percent; }
- // Used to cause the initial "connect" segment to be lost, needed for a
- // regression test.
- void DropNextPacket() { drop_next_packet_ = true; }
- void SetOptNagling(bool enable_nagles) {
- local_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
- remote_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles);
- }
- void SetOptAckDelay(int ack_delay) {
- local_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
- remote_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay);
- }
- void SetOptSndBuf(int size) {
- local_.SetOption(PseudoTcp::OPT_SNDBUF, size);
- remote_.SetOption(PseudoTcp::OPT_SNDBUF, size);
- }
- void SetRemoteOptRcvBuf(int size) {
- remote_.SetOption(PseudoTcp::OPT_RCVBUF, size);
- }
- void SetLocalOptRcvBuf(int size) {
- local_.SetOption(PseudoTcp::OPT_RCVBUF, size);
- }
- void DisableRemoteWindowScale() { remote_.disableWindowScale(); }
- void DisableLocalWindowScale() { local_.disableWindowScale(); }
-
- protected:
- int Connect() {
- int ret = local_.Connect();
- if (ret == 0) {
- UpdateLocalClock();
- }
- if (simultaneous_open_) {
- ret = remote_.Connect();
- if (ret == 0) {
- UpdateRemoteClock();
- }
- }
- return ret;
- }
- void Close() {
- local_.Close(false);
- UpdateLocalClock();
- }
-
- void OnTcpOpen(PseudoTcp* tcp) override {
- // Consider ourselves connected when the local side gets OnTcpOpen.
- // OnTcpWriteable isn't fired at open, so we trigger it now.
- RTC_LOG(LS_VERBOSE) << "Opened";
- if (tcp == &local_) {
- have_connected_ = true;
- OnTcpWriteable(tcp);
- }
- }
- // Test derived from the base should override
- // virtual void OnTcpReadable(PseudoTcp* tcp)
- // and
- // virtual void OnTcpWritable(PseudoTcp* tcp)
- void OnTcpClosed(PseudoTcp* tcp, uint32_t error) override {
- // Consider ourselves closed when the remote side gets OnTcpClosed.
- // TODO(?): OnTcpClosed is only ever notified in case of error in
- // the current implementation. Solicited close is not (yet) supported.
- RTC_LOG(LS_VERBOSE) << "Closed";
- EXPECT_EQ(0U, error);
- if (tcp == &remote_) {
- have_disconnected_ = true;
- }
- }
- WriteResult TcpWritePacket(PseudoTcp* tcp,
- const char* buffer,
- size_t len) override {
- // Drop a packet if the test called DropNextPacket.
- if (drop_next_packet_) {
- drop_next_packet_ = false;
- RTC_LOG(LS_VERBOSE) << "Dropping packet due to DropNextPacket, size="
- << len;
- return WR_SUCCESS;
- }
- // Randomly drop the desired percentage of packets.
- if (webrtc::CreateRandomId() % 100 < static_cast<uint32_t>(loss_)) {
- RTC_LOG(LS_VERBOSE) << "Randomly dropping packet, size=" << len;
- return WR_SUCCESS;
- }
- // Also drop packets that are larger than the configured MTU.
- if (len > static_cast<size_t>(std::min(local_mtu_, remote_mtu_))) {
- RTC_LOG(LS_VERBOSE) << "Dropping packet that exceeds path MTU, size="
- << len;
- return WR_SUCCESS;
- }
- PseudoTcp* other;
- ScopedTaskSafety* timer;
- if (tcp == &local_) {
- other = &remote_;
- timer = &remote_timer_;
- } else {
- other = &local_;
- timer = &local_timer_;
- }
- std::string packet(buffer, len);
- ++packets_in_flight_;
- TaskQueueBase::Current()->PostDelayedTask(
- [other, timer, packet = std::move(packet), this] {
- --packets_in_flight_;
- other->NotifyPacket(packet.c_str(), packet.size());
- UpdateClock(*other, *timer);
- },
- TimeDelta::Millis(delay_));
- return WR_SUCCESS;
- }
-
- void UpdateLocalClock() { UpdateClock(local_, local_timer_); }
- void UpdateRemoteClock() { UpdateClock(remote_, remote_timer_); }
- static void UpdateClock(PseudoTcp& tcp, ScopedTaskSafety& timer) {
- long interval = 0; // NOLINT
- tcp.GetNextClock(PseudoTcp::Now(), interval);
- interval = std::max<int>(interval, 0L); // sometimes interval is < 0
- timer.reset();
- TaskQueueBase::Current()->PostDelayedTask(
- SafeTask(timer.flag(),
- [&tcp, &timer] {
- tcp.NotifyClock(PseudoTcp::Now());
- UpdateClock(tcp, timer);
- }),
- TimeDelta::Millis(interval));
- }
-
- webrtc::AutoThread main_thread_;
- PseudoTcpForTest local_;
- PseudoTcpForTest remote_;
- ScopedTaskSafety local_timer_;
- ScopedTaskSafety remote_timer_;
- webrtc::MemoryStream send_stream_;
- webrtc::MemoryStream recv_stream_;
- bool have_connected_;
- bool have_disconnected_;
- int local_mtu_;
- int remote_mtu_;
- int delay_;
- int loss_;
- bool drop_next_packet_ = false;
- bool simultaneous_open_ = false;
- int packets_in_flight_ = 0;
-};
-
-class PseudoTcpTest : public PseudoTcpTestBase {
- public:
- void TestTransfer(int size) {
- uint32_t start;
- int32_t elapsed;
- size_t received;
- // Create some dummy data to send.
- send_stream_.ReserveSize(size);
- for (int i = 0; i < size; ++i) {
- uint8_t ch = static_cast<uint8_t>(i);
- size_t written;
- int error;
- send_stream_.Write(webrtc::MakeArrayView(&ch, 1), written, error);
- }
- send_stream_.Rewind();
- // Prepare the receive stream.
- recv_stream_.ReserveSize(size);
- // Connect and wait until connected.
- start = webrtc::Time32();
- EXPECT_EQ(0, Connect());
- EXPECT_THAT(webrtc::WaitUntil(
- [&] { return have_connected_; }, IsTrue(),
- {.timeout = webrtc::TimeDelta::Millis(kConnectTimeoutMs)}),
- webrtc::IsRtcOk());
- // Sending will start from OnTcpWriteable and complete when all data has
- // been received.
- EXPECT_THAT(webrtc::WaitUntil(
- [&] { return have_disconnected_; }, IsTrue(),
- {.timeout = webrtc::TimeDelta::Millis(kTransferTimeoutMs)}),
- webrtc::IsRtcOk());
- elapsed = webrtc::Time32() - start;
- recv_stream_.GetSize(&received);
- // Ensure we closed down OK and we got the right data.
- // TODO(?): Ensure the errors are cleared properly.
- // EXPECT_EQ(0, local_.GetError());
- // EXPECT_EQ(0, remote_.GetError());
- EXPECT_EQ(static_cast<size_t>(size), received);
- EXPECT_EQ(0,
- memcmp(send_stream_.GetBuffer(), recv_stream_.GetBuffer(), size));
- RTC_LOG(LS_INFO) << "Transferred " << received << " bytes in " << elapsed
- << " ms (" << size * 8 / elapsed << " Kbps)";
- }
-
- private:
- // IPseudoTcpNotify interface
-
- void OnTcpReadable(PseudoTcp* tcp) override {
- // Stream bytes to the recv stream as they arrive.
- if (tcp == &remote_) {
- ReadData();
-
- // TODO(?): OnTcpClosed() is currently only notified on error -
- // there is no on-the-wire equivalent of TCP FIN.
- // So we fake the notification when all the data has been read.
- size_t received, required;
- recv_stream_.GetPosition(&received);
- send_stream_.GetSize(&required);
- if (received == required)
- OnTcpClosed(&remote_, 0);
- }
- }
- void OnTcpWriteable(PseudoTcp* tcp) override {
- // Write bytes from the send stream when we can.
- // Shut down when we've sent everything.
- if (tcp == &local_) {
- RTC_LOG(LS_VERBOSE) << "Flow Control Lifted";
- bool done;
- WriteData(&done);
- if (done) {
- Close();
- }
- }
- }
-
- void ReadData() {
- char block[kBlockSize];
- size_t position;
- int received;
- do {
- received = remote_.Recv(block, sizeof(block));
- if (received != -1) {
- size_t written;
- int error;
- recv_stream_.Write(
- webrtc::MakeArrayView(reinterpret_cast<uint8_t*>(block), received),
- written, error);
- recv_stream_.GetPosition(&position);
- RTC_LOG(LS_VERBOSE) << "Received: " << position;
- }
- } while (received > 0);
- }
- void WriteData(bool* done) {
- size_t position, tosend;
- int sent;
- char block[kBlockSize];
- do {
- send_stream_.GetPosition(&position);
- int error;
- if (send_stream_.Read(webrtc::MakeArrayView(
- reinterpret_cast<uint8_t*>(block), kBlockSize),
- tosend, error) != webrtc::SR_EOS) {
- sent = local_.Send(block, tosend);
- UpdateLocalClock();
- if (sent != -1) {
- send_stream_.SetPosition(position + sent);
- RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
- } else {
- send_stream_.SetPosition(position);
- RTC_LOG(LS_VERBOSE) << "Flow Controlled";
- }
- } else {
- sent = static_cast<int>(tosend = 0);
- }
- } while (sent > 0);
- *done = (tosend == 0);
- }
-
- private:
- webrtc::MemoryStream send_stream_;
- webrtc::MemoryStream recv_stream_;
-};
-
-class PseudoTcpTestPingPong : public PseudoTcpTestBase {
- public:
- PseudoTcpTestPingPong()
- : iterations_remaining_(0),
- sender_(nullptr),
- receiver_(nullptr),
- bytes_per_send_(0) {}
- void SetBytesPerSend(int bytes) { bytes_per_send_ = bytes; }
- void TestPingPong(int size, int iterations) {
- uint32_t start, elapsed;
- iterations_remaining_ = iterations;
- receiver_ = &remote_;
- sender_ = &local_;
- // Create some dummy data to send.
- send_stream_.ReserveSize(size);
- for (int i = 0; i < size; ++i) {
- uint8_t ch = static_cast<uint8_t>(i);
- size_t written;
- int error;
- send_stream_.Write(webrtc::MakeArrayView(&ch, 1), written, error);
- }
- send_stream_.Rewind();
- // Prepare the receive stream.
- recv_stream_.ReserveSize(size);
- // Connect and wait until connected.
- start = webrtc::Time32();
- EXPECT_EQ(0, Connect());
- EXPECT_THAT(webrtc::WaitUntil(
- [&] { return have_connected_; }, IsTrue(),
- {.timeout = webrtc::TimeDelta::Millis(kConnectTimeoutMs)}),
- webrtc::IsRtcOk());
- // Sending will start from OnTcpWriteable and stop when the required
- // number of iterations have completed.
- EXPECT_THAT(webrtc::WaitUntil(
- [&] { return have_disconnected_; }, IsTrue(),
- {.timeout = webrtc::TimeDelta::Millis(kTransferTimeoutMs)}),
- webrtc::IsRtcOk());
- elapsed = webrtc::TimeSince(start);
- RTC_LOG(LS_INFO) << "Performed " << iterations << " pings in " << elapsed
- << " ms";
- }
-
- private:
- // IPseudoTcpNotify interface
-
- void OnTcpReadable(PseudoTcp* tcp) override {
- if (tcp != receiver_) {
- RTC_LOG_F(LS_ERROR) << "unexpected OnTcpReadable";
- return;
- }
- // Stream bytes to the recv stream as they arrive.
- ReadData();
- // If we've received the desired amount of data, rewind things
- // and send it back the other way!
- size_t position, desired;
- recv_stream_.GetPosition(&position);
- send_stream_.GetSize(&desired);
- if (position == desired) {
- if (receiver_ == &local_ && --iterations_remaining_ == 0) {
- Close();
- // TODO(?): Fake OnTcpClosed() on the receiver for now.
- OnTcpClosed(&remote_, 0);
- return;
- }
- PseudoTcp* tmp = receiver_;
- receiver_ = sender_;
- sender_ = tmp;
- recv_stream_.Rewind();
- send_stream_.Rewind();
- OnTcpWriteable(sender_);
- }
- }
- void OnTcpWriteable(PseudoTcp* tcp) override {
- if (tcp != sender_)
- return;
- // Write bytes from the send stream when we can.
- // Shut down when we've sent everything.
- RTC_LOG(LS_VERBOSE) << "Flow Control Lifted";
- WriteData();
- }
-
- void ReadData() {
- char block[kBlockSize];
- size_t position;
- int received;
- do {
- received = receiver_->Recv(block, sizeof(block));
- if (received != -1) {
- size_t written;
- int error;
- recv_stream_.Write(
- webrtc::MakeArrayView(reinterpret_cast<const uint8_t*>(block),
- received),
- written, error);
- recv_stream_.GetPosition(&position);
- RTC_LOG(LS_VERBOSE) << "Received: " << position;
- }
- } while (received > 0);
- }
- void WriteData() {
- size_t position, tosend;
- int sent;
- char block[kBlockSize];
- do {
- send_stream_.GetPosition(&position);
- tosend = bytes_per_send_ ? bytes_per_send_ : sizeof(block);
- int error;
- if (send_stream_.Read(
- webrtc::MakeArrayView(reinterpret_cast<uint8_t*>(block), tosend),
- tosend, error) != webrtc::SR_EOS) {
- sent = sender_->Send(block, tosend);
- UpdateLocalClock();
- if (sent != -1) {
- send_stream_.SetPosition(position + sent);
- RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
- } else {
- send_stream_.SetPosition(position);
- RTC_LOG(LS_VERBOSE) << "Flow Controlled";
- }
- } else {
- sent = static_cast<int>(tosend = 0);
- }
- } while (sent > 0);
- }
-
- private:
- int iterations_remaining_;
- PseudoTcp* sender_;
- PseudoTcp* receiver_;
- int bytes_per_send_;
-};
-
-// Fill the receiver window until it is full, drain it and then
-// fill it with the same amount. This is to test that receiver window
-// contracts and enlarges correctly.
-class PseudoTcpTestReceiveWindow : public PseudoTcpTestBase {
- public:
- // Not all the data are transfered, `size` just need to be big enough
- // to fill up the receiver window twice.
- void TestTransfer(int size) {
- // Create some dummy data to send.
- send_stream_.ReserveSize(size);
- for (int i = 0; i < size; ++i) {
- uint8_t ch = static_cast<uint8_t>(i);
- size_t written;
- int error;
- send_stream_.Write(webrtc::MakeArrayView(&ch, 1), written, error);
- }
- send_stream_.Rewind();
-
- // Prepare the receive stream.
- recv_stream_.ReserveSize(size);
-
- // Connect and wait until connected.
- EXPECT_EQ(0, Connect());
- EXPECT_THAT(webrtc::WaitUntil(
- [&] { return have_connected_; }, IsTrue(),
- {.timeout = webrtc::TimeDelta::Millis(kConnectTimeoutMs)}),
- webrtc::IsRtcOk());
-
- TaskQueueBase::Current()->PostTask([this] { WriteData(); });
- EXPECT_THAT(webrtc::WaitUntil(
- [&] { return have_disconnected_; }, IsTrue(),
- {.timeout = webrtc::TimeDelta::Millis(kTransferTimeoutMs)}),
- webrtc::IsRtcOk());
-
- ASSERT_EQ(2u, send_position_.size());
- ASSERT_EQ(2u, recv_position_.size());
-
- const size_t estimated_recv_window = EstimateReceiveWindowSize();
-
- // The difference in consecutive send positions should equal the
- // receive window size or match very closely. This verifies that receive
- // window is open after receiver drained all the data.
- const size_t send_position_diff = send_position_[1] - send_position_[0];
- EXPECT_GE(1024u, estimated_recv_window - send_position_diff);
-
- // Receiver drained the receive window twice.
- EXPECT_EQ(2 * estimated_recv_window, recv_position_[1]);
- }
-
- uint32_t EstimateReceiveWindowSize() const {
- return static_cast<uint32_t>(recv_position_[0]);
- }
-
- uint32_t EstimateSendWindowSize() const {
- return static_cast<uint32_t>(send_position_[0] - recv_position_[0]);
- }
-
- private:
- // IPseudoTcpNotify interface
- void OnTcpReadable(PseudoTcp* /* tcp */) override {}
-
- void OnTcpWriteable(PseudoTcp* /* tcp */) override {}
-
- void ReadUntilIOPending() {
- char block[kBlockSize];
- size_t position;
- int received;
-
- do {
- received = remote_.Recv(block, sizeof(block));
- if (received != -1) {
- size_t written;
- int error;
- recv_stream_.Write(
- webrtc::MakeArrayView(reinterpret_cast<uint8_t*>(block), received),
- written, error);
- recv_stream_.GetPosition(&position);
- RTC_LOG(LS_VERBOSE) << "Received: " << position;
- }
- } while (received > 0);
-
- recv_stream_.GetPosition(&position);
- recv_position_.push_back(position);
-
- // Disconnect if we have done two transfers.
- if (recv_position_.size() == 2u) {
- Close();
- OnTcpClosed(&remote_, 0);
- } else {
- WriteData();
- }
- }
-
- void WriteData() {
- size_t position, tosend;
- int sent;
- char block[kBlockSize];
- do {
- send_stream_.GetPosition(&position);
- int error;
- if (send_stream_.Read(
- webrtc::MakeArrayView(reinterpret_cast<uint8_t*>(block),
- sizeof(block)),
- tosend, error) != webrtc::SR_EOS) {
- sent = local_.Send(block, tosend);
- UpdateLocalClock();
- if (sent != -1) {
- send_stream_.SetPosition(position + sent);
- RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent;
- } else {
- send_stream_.SetPosition(position);
- RTC_LOG(LS_VERBOSE) << "Flow Controlled";
- }
- } else {
- sent = static_cast<int>(tosend = 0);
- }
- } while (sent > 0);
- // At this point, we've filled up the available space in the send queue.
-
- if (packets_in_flight_ > 0) {
- // If there are packet tasks, attempt to continue sending after giving
- // those packets time to process, which should free up the send buffer.
- webrtc::Thread::Current()->PostDelayedTask([this] { WriteData(); },
- TimeDelta::Millis(10));
- } else {
- if (!remote_.isReceiveBufferFull()) {
- RTC_LOG(LS_ERROR) << "This shouldn't happen - the send buffer is full, "
- "the receive buffer is not, and there are no "
- "remaining messages to process.";
- }
- send_stream_.GetPosition(&position);
- send_position_.push_back(position);
-
- // Drain the receiver buffer.
- ReadUntilIOPending();
- }
- }
-
- private:
- webrtc::MemoryStream send_stream_;
- webrtc::MemoryStream recv_stream_;
-
- std::vector<size_t> send_position_;
- std::vector<size_t> recv_position_;
-};
-
-// Basic end-to-end data transfer tests
-
-// Test the normal case of sending data from one side to the other.
-TEST_F(PseudoTcpTest, TestSend) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- TestTransfer(1000000);
-}
-
-// Test sending data with a 50 ms RTT. Transmission should take longer due
-// to a slower ramp-up in send rate.
-TEST_F(PseudoTcpTest, TestSendWithDelay) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetDelay(50);
- TestTransfer(1000000);
-}
-
-// Test sending data with packet loss. Transmission should take much longer due
-// to send back-off when loss occurs.
-TEST_F(PseudoTcpTest, TestSendWithLoss) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetLoss(10);
- TestTransfer(100000); // less data so test runs faster
-}
-
-// Test sending data with a 50 ms RTT and 10% packet loss. Transmission should
-// take much longer due to send back-off and slower detection of loss.
-TEST_F(PseudoTcpTest, TestSendWithDelayAndLoss) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetDelay(50);
- SetLoss(10);
- TestTransfer(100000); // less data so test runs faster
-}
-
-// Test sending data with 10% packet loss and Nagling disabled. Transmission
-// should take about the same time as with Nagling enabled.
-TEST_F(PseudoTcpTest, TestSendWithLossAndOptNaglingOff) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetLoss(10);
- SetOptNagling(false);
- TestTransfer(100000); // less data so test runs faster
-}
-
-// Regression test for bugs.webrtc.org/9208.
-//
-// This bug resulted in corrupted data if a "connect" segment was received after
-// a data segment. This is only possible if:
-//
-// * The initial "connect" segment is lost, and retransmitted later.
-// * Both sides send "connect"s simultaneously, such that the local side thinks
-// a connection is established even before its "connect" has been
-// acknowledged.
-// * Nagle algorithm disabled, allowing a data segment to be sent before the
-// "connect" has been acknowledged.
-TEST_F(PseudoTcpTest,
- TestSendWhenFirstPacketLostWithOptNaglingOffAndSimultaneousOpen) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- DropNextPacket();
- SetOptNagling(false);
- SetSimultaneousOpen(true);
- TestTransfer(10000);
-}
-
-// Test sending data with 10% packet loss and Delayed ACK disabled.
-// Transmission should be slightly faster than with it enabled.
-TEST_F(PseudoTcpTest, TestSendWithLossAndOptAckDelayOff) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetLoss(10);
- SetOptAckDelay(0);
- TestTransfer(100000);
-}
-
-// Test sending data with 50ms delay and Nagling disabled.
-TEST_F(PseudoTcpTest, TestSendWithDelayAndOptNaglingOff) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetDelay(50);
- SetOptNagling(false);
- TestTransfer(100000); // less data so test runs faster
-}
-
-// Test sending data with 50ms delay and Delayed ACK disabled.
-TEST_F(PseudoTcpTest, TestSendWithDelayAndOptAckDelayOff) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetDelay(50);
- SetOptAckDelay(0);
- TestTransfer(100000); // less data so test runs faster
-}
-
-// Test a large receive buffer with a sender that doesn't support scaling.
-TEST_F(PseudoTcpTest, TestSendRemoteNoWindowScale) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetLocalOptRcvBuf(100000);
- DisableRemoteWindowScale();
- TestTransfer(1000000);
-}
-
-// Test a large sender-side receive buffer with a receiver that doesn't support
-// scaling.
-TEST_F(PseudoTcpTest, TestSendLocalNoWindowScale) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetRemoteOptRcvBuf(100000);
- DisableLocalWindowScale();
- TestTransfer(1000000);
-}
-
-// Test when both sides use window scaling.
-TEST_F(PseudoTcpTest, TestSendBothUseWindowScale) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetRemoteOptRcvBuf(100000);
- SetLocalOptRcvBuf(100000);
- TestTransfer(1000000);
-}
-
-// Test using a large window scale value.
-TEST_F(PseudoTcpTest, TestSendLargeInFlight) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetRemoteOptRcvBuf(100000);
- SetLocalOptRcvBuf(100000);
- SetOptSndBuf(150000);
- TestTransfer(1000000);
-}
-
-TEST_F(PseudoTcpTest, TestSendBothUseLargeWindowScale) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetRemoteOptRcvBuf(1000000);
- SetLocalOptRcvBuf(1000000);
- TestTransfer(10000000);
-}
-
-// Test using a small receive buffer.
-TEST_F(PseudoTcpTest, TestSendSmallReceiveBuffer) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetRemoteOptRcvBuf(10000);
- SetLocalOptRcvBuf(10000);
- TestTransfer(1000000);
-}
-
-// Test using a very small receive buffer.
-TEST_F(PseudoTcpTest, TestSendVerySmallReceiveBuffer) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetRemoteOptRcvBuf(100);
- SetLocalOptRcvBuf(100);
- TestTransfer(100000);
-}
-
-// Ping-pong (request/response) tests
-
-// Test sending <= 1x MTU of data in each ping/pong. Should take <10ms.
-TEST_F(PseudoTcpTestPingPong, TestPingPong1xMtu) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- TestPingPong(100, 100);
-}
-
-// Test sending 2x-3x MTU of data in each ping/pong. Should take <10ms.
-TEST_F(PseudoTcpTestPingPong, TestPingPong3xMtu) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- TestPingPong(400, 100);
-}
-
-// Test sending 1x-2x MTU of data in each ping/pong.
-// Should take ~1s, due to interaction between Nagling and Delayed ACK.
-TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtu) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- TestPingPong(2000, 5);
-}
-
-// Test sending 1x-2x MTU of data in each ping/pong with Delayed ACK off.
-// Should take <10ms.
-TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithAckDelayOff) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetOptAckDelay(0);
- TestPingPong(2000, 100);
-}
-
-// Test sending 1x-2x MTU of data in each ping/pong with Nagling off.
-// Should take <10ms.
-TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithNaglingOff) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetOptNagling(false);
- TestPingPong(2000, 5);
-}
-
-// Test sending a ping as pair of short (non-full) segments.
-// Should take ~1s, due to Delayed ACK interaction with Nagling.
-TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegments) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetOptAckDelay(5000);
- SetBytesPerSend(50); // i.e. two Send calls per payload
- TestPingPong(100, 5);
-}
-
-// Test sending ping as a pair of short (non-full) segments, with Nagling off.
-// Should take <10ms.
-TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithNaglingOff) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetOptNagling(false);
- SetBytesPerSend(50); // i.e. two Send calls per payload
- TestPingPong(100, 5);
-}
-
-// Test sending <= 1x MTU of data ping/pong, in two segments, no Delayed ACK.
-// Should take ~1s.
-TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithAckDelayOff) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetBytesPerSend(50); // i.e. two Send calls per payload
- SetOptAckDelay(0);
- TestPingPong(100, 5);
-}
-
-// Test that receive window expands and contract correctly.
-TEST_F(PseudoTcpTestReceiveWindow, TestReceiveWindow) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetOptNagling(false);
- SetOptAckDelay(0);
- TestTransfer(1024 * 1000);
-}
-
-// Test setting send window size to a very small value.
-TEST_F(PseudoTcpTestReceiveWindow, TestSetVerySmallSendWindowSize) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetOptNagling(false);
- SetOptAckDelay(0);
- SetOptSndBuf(900);
- TestTransfer(1024 * 1000);
- EXPECT_EQ(900u, EstimateSendWindowSize());
-}
-
-// Test setting receive window size to a value other than default.
-TEST_F(PseudoTcpTestReceiveWindow, TestSetReceiveWindowSize) {
- SetLocalMtu(1500);
- SetRemoteMtu(1500);
- SetOptNagling(false);
- SetOptAckDelay(0);
- SetRemoteOptRcvBuf(100000);
- SetLocalOptRcvBuf(100000);
- TestTransfer(1024 * 1000);
- EXPECT_EQ(100000u, EstimateReceiveWindowSize());
-}
-
-/* Test sending data with mismatched MTUs. We should detect this and reduce
-// our packet size accordingly.
-// TODO(?): This doesn't actually work right now. The current code
-// doesn't detect if the MTU is set too high on either side.
-TEST_F(PseudoTcpTest, TestSendWithMismatchedMtus) {
- SetLocalMtu(1500);
- SetRemoteMtu(1280);
- TestTransfer(1000000);
-}
-*/
diff --git a/third_party/libwebrtc/test/DEPS b/third_party/libwebrtc/test/DEPS
@@ -42,9 +42,6 @@ specific_include_rules = {
".*mdns_parser_fuzzer\.cc": [
"+p2p/base/mdns_message.h",
],
- ".*pseudotcp_parser_fuzzer\.cc": [
- "+p2p/base/pseudo_tcp.h",
- ],
".*stun_parser_fuzzer\.cc": [
"+p2p/base/stun.h",
],
diff --git a/third_party/libwebrtc/test/fuzzers/BUILD.gn b/third_party/libwebrtc/test/fuzzers/BUILD.gn
@@ -270,7 +270,7 @@ webrtc_fuzzer_test("rtp_packetizer_av1_fuzzer") {
deps = [
"../../api:array_view",
"../../api/video:video_frame_type",
- "../../modules/rtp_rtcp:rtp_rtcp",
+ "../../modules/rtp_rtcp",
"../../modules/rtp_rtcp:rtp_rtcp_format",
"../../rtc_base:checks",
]
@@ -281,7 +281,7 @@ webrtc_fuzzer_test("rtp_format_h264_fuzzer") {
deps = [
"../../api:array_view",
"../../api/video:video_frame_type",
- "../../modules/rtp_rtcp:rtp_rtcp",
+ "../../modules/rtp_rtcp",
"../../modules/rtp_rtcp:rtp_rtcp_format",
"../../modules/video_coding:codec_globals_headers",
"../../rtc_base:checks",
@@ -293,7 +293,7 @@ webrtc_fuzzer_test("rtp_format_vp8_fuzzer") {
deps = [
"../../api:array_view",
"../../api/video:video_frame_type",
- "../../modules/rtp_rtcp:rtp_rtcp",
+ "../../modules/rtp_rtcp",
"../../modules/rtp_rtcp:rtp_rtcp_format",
"../../modules/video_coding:codec_globals_headers",
"../../rtc_base:checks",
@@ -305,7 +305,7 @@ webrtc_fuzzer_test("rtp_format_vp9_fuzzer") {
deps = [
"../../api:array_view",
"../../api/video:video_frame_type",
- "../../modules/rtp_rtcp:rtp_rtcp",
+ "../../modules/rtp_rtcp",
"../../modules/rtp_rtcp:rtp_rtcp_format",
"../../modules/video_coding:codec_globals_headers",
"../../rtc_base:checks",
@@ -523,14 +523,6 @@ webrtc_fuzzer_test("stun_validator_fuzzer") {
dict = "corpora/stun.tokens"
}
-webrtc_fuzzer_test("pseudotcp_parser_fuzzer") {
- sources = [ "pseudotcp_parser_fuzzer.cc" ]
- deps = [
- "../../p2p:pseudo_tcp",
- "../../rtc_base:threading",
- ]
-}
-
rtc_library("audio_processing_fuzzer_helper") {
testonly = true
sources = [
@@ -691,8 +683,8 @@ webrtc_fuzzer_test("rtp_frame_reference_finder_fuzzer") {
"../../api/video:video_rtp_headers",
"../../modules/rtp_rtcp",
"../../modules/rtp_rtcp:rtp_video_header",
+ "../../modules/video_coding",
"../../modules/video_coding:codec_globals_headers",
- "../../modules/video_coding:video_coding",
"../../system_wrappers",
]
}
@@ -854,7 +846,6 @@ group("fuzzers") {
":h264_depacketizer_fuzzer",
":neteq_rtp_fuzzer",
":neteq_signal_fuzzer",
- ":pseudotcp_parser_fuzzer",
":receive_side_congestion_controller_fuzzer",
":residual_echo_detector_fuzzer",
":rtcp_receiver_fuzzer",
diff --git a/third_party/libwebrtc/test/fuzzers/corpora/README b/third_party/libwebrtc/test/fuzzers/corpora/README
@@ -30,8 +30,6 @@ prefixed by the byte 0xff. Some of the rtp fuzzers need to decide
which header extensions to enable, and the first byte of the fuzz data
is used for this.
-### PseudoTCP ###
-Very small corpus minimised from the unit tests.
### SCTP ###
This corpus was extracted from a few manually recorder wireshark dumps.
diff --git a/third_party/libwebrtc/test/fuzzers/pseudotcp_parser_fuzzer.cc b/third_party/libwebrtc/test/fuzzers/pseudotcp_parser_fuzzer.cc
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2016 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 <stddef.h>
-#include <stdint.h>
-
-#include "p2p/base/pseudo_tcp.h"
-#include "rtc_base/thread.h"
-
-namespace webrtc {
-class FakeIPseudoTcpNotify : public webrtc::IPseudoTcpNotify {
- public:
- void OnTcpOpen(webrtc::PseudoTcp* tcp) {}
- void OnTcpReadable(webrtc::PseudoTcp* tcp) {}
- void OnTcpWriteable(webrtc::PseudoTcp* tcp) {}
- void OnTcpClosed(webrtc::PseudoTcp* tcp, uint32_t error) {}
-
- webrtc::IPseudoTcpNotify::WriteResult TcpWritePacket(webrtc::PseudoTcp* tcp,
- const char* buffer,
- size_t len) {
- return webrtc::IPseudoTcpNotify::WriteResult::WR_SUCCESS;
- }
-};
-
-struct Environment {
- explicit Environment(webrtc::IPseudoTcpNotify* notifier)
- : ptcp(notifier, 0) {}
-
- // We need the thread to avoid some uninteresting crashes, since the
- // production code expects there to be a thread object available.
- webrtc::AutoThread thread;
- webrtc::PseudoTcp ptcp;
-};
-
-Environment* env = new Environment(new FakeIPseudoTcpNotify());
-
-void FuzzOneInput(const uint8_t* data, size_t size) {
- env->ptcp.NotifyPacket(reinterpret_cast<const char*>(data), size);
-}
-} // namespace webrtc