1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "p2p/base/pseudo_tcp.h"
12 
13 #include <errno.h>
14 #include <stdio.h>
15 
16 #include <algorithm>
17 #include <cstdint>
18 #include <memory>
19 #include <set>
20 
21 #include "rtc_base/byte_buffer.h"
22 #include "rtc_base/byte_order.h"
23 #include "rtc_base/checks.h"
24 #include "rtc_base/logging.h"
25 #include "rtc_base/numerics/safe_minmax.h"
26 #include "rtc_base/socket.h"
27 #include "rtc_base/time_utils.h"
28 
29 // The following logging is for detailed (packet-level) analysis only.
30 #define _DBG_NONE 0
31 #define _DBG_NORMAL 1
32 #define _DBG_VERBOSE 2
33 #define _DEBUGMSG _DBG_NONE
34 
35 namespace cricket {
36 
37 //////////////////////////////////////////////////////////////////////
38 // Network Constants
39 //////////////////////////////////////////////////////////////////////
40 
41 // Standard MTUs
42 const uint16_t PACKET_MAXIMUMS[] = {
43     65535,  // Theoretical maximum, Hyperchannel
44     32000,  // Nothing
45     17914,  // 16Mb IBM Token Ring
46     8166,   // IEEE 802.4
47     // 4464,   // IEEE 802.5 (4Mb max)
48     4352,  // FDDI
49     // 2048,   // Wideband Network
50     2002,  // IEEE 802.5 (4Mb recommended)
51     // 1536,   // Expermental Ethernet Networks
52     // 1500,   // Ethernet, Point-to-Point (default)
53     1492,  // IEEE 802.3
54     1006,  // SLIP, ARPANET
55     // 576,    // X.25 Networks
56     // 544,    // DEC IP Portal
57     // 512,    // NETBIOS
58     508,  // IEEE 802/Source-Rt Bridge, ARCNET
59     296,  // Point-to-Point (low delay)
60     // 68,     // Official minimum
61     0,  // End of list marker
62 };
63 
64 const uint32_t MAX_PACKET = 65535;
65 // Note: we removed lowest level because packet overhead was larger!
66 const uint32_t MIN_PACKET = 296;
67 
68 const uint32_t IP_HEADER_SIZE = 20;  // (+ up to 40 bytes of options?)
69 const uint32_t UDP_HEADER_SIZE = 8;
70 // TODO(?): Make JINGLE_HEADER_SIZE transparent to this code?
71 const uint32_t JINGLE_HEADER_SIZE = 64;  // when relay framing is in use
72 
73 // Default size for receive and send buffer.
74 const uint32_t DEFAULT_RCV_BUF_SIZE = 60 * 1024;
75 const uint32_t DEFAULT_SND_BUF_SIZE = 90 * 1024;
76 
77 //////////////////////////////////////////////////////////////////////
78 // Global Constants and Functions
79 //////////////////////////////////////////////////////////////////////
80 //
81 //    0                   1                   2                   3
82 //    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
83 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84 //  0 |                      Conversation Number                      |
85 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
86 //  4 |                        Sequence Number                        |
87 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88 //  8 |                     Acknowledgment Number                     |
89 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90 //    |               |   |U|A|P|R|S|F|                               |
91 // 12 |    Control    |   |R|C|S|S|Y|I|            Window             |
92 //    |               |   |G|K|H|T|N|N|                               |
93 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94 // 16 |                       Timestamp sending                       |
95 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96 // 20 |                      Timestamp receiving                      |
97 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
98 // 24 |                             data                              |
99 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
100 //
101 //////////////////////////////////////////////////////////////////////
102 
103 #define PSEUDO_KEEPALIVE 0
104 
105 const uint32_t HEADER_SIZE = 24;
106 const uint32_t PACKET_OVERHEAD =
107     HEADER_SIZE + UDP_HEADER_SIZE + IP_HEADER_SIZE + JINGLE_HEADER_SIZE;
108 
109 const uint32_t MIN_RTO =
110     250;  // 250 ms (RFC1122, Sec 4.2.3.1 "fractions of a second")
111 const uint32_t DEF_RTO = 3000;       // 3 seconds (RFC1122, Sec 4.2.3.1)
112 const uint32_t MAX_RTO = 60000;      // 60 seconds
113 const uint32_t DEF_ACK_DELAY = 100;  // 100 milliseconds
114 
115 const uint8_t FLAG_CTL = 0x02;
116 const uint8_t FLAG_RST = 0x04;
117 
118 const uint8_t CTL_CONNECT = 0;
119 
120 // TCP options.
121 const uint8_t TCP_OPT_EOL = 0;        // End of list.
122 const uint8_t TCP_OPT_NOOP = 1;       // No-op.
123 const uint8_t TCP_OPT_MSS = 2;        // Maximum segment size.
124 const uint8_t TCP_OPT_WND_SCALE = 3;  // Window scale factor.
125 
126 const long DEFAULT_TIMEOUT =
127     4000;  // If there are no pending clocks, wake up every 4 seconds
128 const long CLOSED_TIMEOUT =
129     60 * 1000;  // If the connection is closed, once per minute
130 
131 #if PSEUDO_KEEPALIVE
132 // !?! Rethink these times
133 const uint32_t IDLE_PING =
134     20 *
135     1000;  // 20 seconds (note: WinXP SP2 firewall udp timeout is 90 seconds)
136 const uint32_t IDLE_TIMEOUT = 90 * 1000;  // 90 seconds;
137 #endif                                    // PSEUDO_KEEPALIVE
138 
139 //////////////////////////////////////////////////////////////////////
140 // Helper Functions
141 //////////////////////////////////////////////////////////////////////
142 
long_to_bytes(uint32_t val,void * buf)143 inline void long_to_bytes(uint32_t val, void* buf) {
144   *static_cast<uint32_t*>(buf) = rtc::HostToNetwork32(val);
145 }
146 
short_to_bytes(uint16_t val,void * buf)147 inline void short_to_bytes(uint16_t val, void* buf) {
148   *static_cast<uint16_t*>(buf) = rtc::HostToNetwork16(val);
149 }
150 
bytes_to_long(const void * buf)151 inline uint32_t bytes_to_long(const void* buf) {
152   return rtc::NetworkToHost32(*static_cast<const uint32_t*>(buf));
153 }
154 
bytes_to_short(const void * buf)155 inline uint16_t bytes_to_short(const void* buf) {
156   return rtc::NetworkToHost16(*static_cast<const uint16_t*>(buf));
157 }
158 
159 //////////////////////////////////////////////////////////////////////
160 // Debugging Statistics
161 //////////////////////////////////////////////////////////////////////
162 
163 #if 0  // Not used yet
164 
165 enum Stat {
166   S_SENT_PACKET,    // All packet sends
167   S_RESENT_PACKET,  // All packet sends that are retransmits
168   S_RECV_PACKET,    // All packet receives
169   S_RECV_NEW,       // All packet receives that are too new
170   S_RECV_OLD,       // All packet receives that are too old
171   S_NUM_STATS
172 };
173 
174 const char* const STAT_NAMES[S_NUM_STATS] = {
175   "snt",
176   "snt-r",
177   "rcv"
178   "rcv-n",
179   "rcv-o"
180 };
181 
182 int g_stats[S_NUM_STATS];
183 inline void Incr(Stat s) { ++g_stats[s]; }
184 void ReportStats() {
185   char buffer[256];
186   size_t len = 0;
187   for (int i = 0; i < S_NUM_STATS; ++i) {
188     len += snprintf(buffer, arraysize(buffer), "%s%s:%d",
189                           (i == 0) ? "" : ",", STAT_NAMES[i], g_stats[i]);
190     g_stats[i] = 0;
191   }
192   RTC_LOG(LS_INFO) << "Stats[" << buffer << "]";
193 }
194 
195 #endif
196 
197 //////////////////////////////////////////////////////////////////////
198 // PseudoTcp
199 //////////////////////////////////////////////////////////////////////
200 
Now()201 uint32_t PseudoTcp::Now() {
202 #if 0  // Use this to synchronize timers with logging timestamps (easier debug)
203   return static_cast<uint32_t>(rtc::TimeSince(StartTime()));
204 #else
205   return rtc::Time32();
206 #endif
207 }
208 
PseudoTcp(IPseudoTcpNotify * notify,uint32_t conv)209 PseudoTcp::PseudoTcp(IPseudoTcpNotify* notify, uint32_t conv)
210     : m_notify(notify),
211       m_shutdown(SD_NONE),
212       m_error(0),
213       m_rbuf_len(DEFAULT_RCV_BUF_SIZE),
214       m_rbuf(m_rbuf_len),
215       m_sbuf_len(DEFAULT_SND_BUF_SIZE),
216       m_sbuf(m_sbuf_len) {
217   // Sanity check on buffer sizes (needed for OnTcpWriteable notification logic)
218   RTC_DCHECK(m_rbuf_len + MIN_PACKET < m_sbuf_len);
219 
220   uint32_t now = Now();
221 
222   m_state = TCP_LISTEN;
223   m_conv = conv;
224   m_rcv_wnd = m_rbuf_len;
225   m_rwnd_scale = m_swnd_scale = 0;
226   m_snd_nxt = 0;
227   m_snd_wnd = 1;
228   m_snd_una = m_rcv_nxt = 0;
229   m_bReadEnable = true;
230   m_bWriteEnable = false;
231   m_t_ack = 0;
232 
233   m_msslevel = 0;
234   m_largest = 0;
235   RTC_DCHECK(MIN_PACKET > PACKET_OVERHEAD);
236   m_mss = MIN_PACKET - PACKET_OVERHEAD;
237   m_mtu_advise = MAX_PACKET;
238 
239   m_rto_base = 0;
240 
241   m_cwnd = 2 * m_mss;
242   m_ssthresh = m_rbuf_len;
243   m_lastrecv = m_lastsend = m_lasttraffic = now;
244   m_bOutgoing = false;
245 
246   m_dup_acks = 0;
247   m_recover = 0;
248 
249   m_ts_recent = m_ts_lastack = 0;
250 
251   m_rx_rto = DEF_RTO;
252   m_rx_srtt = m_rx_rttvar = 0;
253 
254   m_use_nagling = true;
255   m_ack_delay = DEF_ACK_DELAY;
256   m_support_wnd_scale = true;
257 }
258 
~PseudoTcp()259 PseudoTcp::~PseudoTcp() {}
260 
Connect()261 int PseudoTcp::Connect() {
262   if (m_state != TCP_LISTEN) {
263     m_error = EINVAL;
264     return -1;
265   }
266 
267   m_state = TCP_SYN_SENT;
268   RTC_LOG(LS_INFO) << "State: TCP_SYN_SENT";
269 
270   queueConnectMessage();
271   attemptSend();
272 
273   return 0;
274 }
275 
NotifyMTU(uint16_t mtu)276 void PseudoTcp::NotifyMTU(uint16_t mtu) {
277   m_mtu_advise = mtu;
278   if (m_state == TCP_ESTABLISHED) {
279     adjustMTU();
280   }
281 }
282 
NotifyClock(uint32_t now)283 void PseudoTcp::NotifyClock(uint32_t now) {
284   if (m_state == TCP_CLOSED)
285     return;
286 
287   // Check if it's time to retransmit a segment
288   if (m_rto_base && (rtc::TimeDiff32(m_rto_base + m_rx_rto, now) <= 0)) {
289     if (m_slist.empty()) {
290       RTC_NOTREACHED();
291     } else {
292 // Note: (m_slist.front().xmit == 0)) {
293 // retransmit segments
294 #if _DEBUGMSG >= _DBG_NORMAL
295       RTC_LOG(LS_INFO) << "timeout retransmit (rto: " << m_rx_rto
296                        << ") (rto_base: " << m_rto_base << ") (now: " << now
297                        << ") (dup_acks: " << static_cast<unsigned>(m_dup_acks)
298                        << ")";
299 #endif  // _DEBUGMSG
300       if (!transmit(m_slist.begin(), now)) {
301         closedown(ECONNABORTED);
302         return;
303       }
304 
305       uint32_t nInFlight = m_snd_nxt - m_snd_una;
306       m_ssthresh = std::max(nInFlight / 2, 2 * m_mss);
307       // RTC_LOG(LS_INFO) << "m_ssthresh: " << m_ssthresh << "  nInFlight: " <<
308       // nInFlight << "  m_mss: " << m_mss;
309       m_cwnd = m_mss;
310 
311       // Back off retransmit timer.  Note: the limit is lower when connecting.
312       uint32_t rto_limit = (m_state < TCP_ESTABLISHED) ? DEF_RTO : MAX_RTO;
313       m_rx_rto = std::min(rto_limit, m_rx_rto * 2);
314       m_rto_base = now;
315     }
316   }
317 
318   // Check if it's time to probe closed windows
319   if ((m_snd_wnd == 0) && (rtc::TimeDiff32(m_lastsend + m_rx_rto, now) <= 0)) {
320     if (rtc::TimeDiff32(now, m_lastrecv) >= 15000) {
321       closedown(ECONNABORTED);
322       return;
323     }
324 
325     // probe the window
326     packet(m_snd_nxt - 1, 0, 0, 0);
327     m_lastsend = now;
328 
329     // back off retransmit timer
330     m_rx_rto = std::min(MAX_RTO, m_rx_rto * 2);
331   }
332 
333   // Check if it's time to send delayed acks
334   if (m_t_ack && (rtc::TimeDiff32(m_t_ack + m_ack_delay, now) <= 0)) {
335     packet(m_snd_nxt, 0, 0, 0);
336   }
337 
338 #if PSEUDO_KEEPALIVE
339   // Check for idle timeout
340   if ((m_state == TCP_ESTABLISHED) &&
341       (TimeDiff32(m_lastrecv + IDLE_TIMEOUT, now) <= 0)) {
342     closedown(ECONNABORTED);
343     return;
344   }
345 
346   // Check for ping timeout (to keep udp mapping open)
347   if ((m_state == TCP_ESTABLISHED) &&
348       (TimeDiff32(m_lasttraffic + (m_bOutgoing ? IDLE_PING * 3 / 2 : IDLE_PING),
349                   now) <= 0)) {
350     packet(m_snd_nxt, 0, 0, 0);
351   }
352 #endif  // PSEUDO_KEEPALIVE
353 }
354 
NotifyPacket(const char * buffer,size_t len)355 bool PseudoTcp::NotifyPacket(const char* buffer, size_t len) {
356   if (len > MAX_PACKET) {
357     RTC_LOG_F(WARNING) << "packet too large";
358     return false;
359   }
360   return parse(reinterpret_cast<const uint8_t*>(buffer), uint32_t(len));
361 }
362 
GetNextClock(uint32_t now,long & timeout)363 bool PseudoTcp::GetNextClock(uint32_t now, long& timeout) {
364   return clock_check(now, timeout);
365 }
366 
GetOption(Option opt,int * value)367 void PseudoTcp::GetOption(Option opt, int* value) {
368   if (opt == OPT_NODELAY) {
369     *value = m_use_nagling ? 0 : 1;
370   } else if (opt == OPT_ACKDELAY) {
371     *value = m_ack_delay;
372   } else if (opt == OPT_SNDBUF) {
373     *value = m_sbuf_len;
374   } else if (opt == OPT_RCVBUF) {
375     *value = m_rbuf_len;
376   } else {
377     RTC_NOTREACHED();
378   }
379 }
SetOption(Option opt,int value)380 void PseudoTcp::SetOption(Option opt, int value) {
381   if (opt == OPT_NODELAY) {
382     m_use_nagling = value == 0;
383   } else if (opt == OPT_ACKDELAY) {
384     m_ack_delay = value;
385   } else if (opt == OPT_SNDBUF) {
386     RTC_DCHECK(m_state == TCP_LISTEN);
387     resizeSendBuffer(value);
388   } else if (opt == OPT_RCVBUF) {
389     RTC_DCHECK(m_state == TCP_LISTEN);
390     resizeReceiveBuffer(value);
391   } else {
392     RTC_NOTREACHED();
393   }
394 }
395 
GetCongestionWindow() const396 uint32_t PseudoTcp::GetCongestionWindow() const {
397   return m_cwnd;
398 }
399 
GetBytesInFlight() const400 uint32_t PseudoTcp::GetBytesInFlight() const {
401   return m_snd_nxt - m_snd_una;
402 }
403 
GetBytesBufferedNotSent() const404 uint32_t PseudoTcp::GetBytesBufferedNotSent() const {
405   size_t buffered_bytes = 0;
406   m_sbuf.GetBuffered(&buffered_bytes);
407   return static_cast<uint32_t>(m_snd_una + buffered_bytes - m_snd_nxt);
408 }
409 
GetRoundTripTimeEstimateMs() const410 uint32_t PseudoTcp::GetRoundTripTimeEstimateMs() const {
411   return m_rx_srtt;
412 }
413 
414 //
415 // IPStream Implementation
416 //
417 
Recv(char * buffer,size_t len)418 int PseudoTcp::Recv(char* buffer, size_t len) {
419   if (m_state != TCP_ESTABLISHED) {
420     m_error = ENOTCONN;
421     return SOCKET_ERROR;
422   }
423 
424   size_t read = 0;
425   rtc::StreamResult result = m_rbuf.Read(buffer, len, &read, NULL);
426 
427   // If there's no data in |m_rbuf|.
428   if (result == rtc::SR_BLOCK) {
429     m_bReadEnable = true;
430     m_error = EWOULDBLOCK;
431     return SOCKET_ERROR;
432   }
433   RTC_DCHECK(result == rtc::SR_SUCCESS);
434 
435   size_t available_space = 0;
436   m_rbuf.GetWriteRemaining(&available_space);
437 
438   if (uint32_t(available_space) - m_rcv_wnd >=
439       std::min<uint32_t>(m_rbuf_len / 2, m_mss)) {
440     // TODO(jbeda): !?! Not sure about this was closed business
441     bool bWasClosed = (m_rcv_wnd == 0);
442     m_rcv_wnd = static_cast<uint32_t>(available_space);
443 
444     if (bWasClosed) {
445       attemptSend(sfImmediateAck);
446     }
447   }
448 
449   return static_cast<int>(read);
450 }
451 
Send(const char * buffer,size_t len)452 int PseudoTcp::Send(const char* buffer, size_t len) {
453   if (m_state != TCP_ESTABLISHED) {
454     m_error = ENOTCONN;
455     return SOCKET_ERROR;
456   }
457 
458   size_t available_space = 0;
459   m_sbuf.GetWriteRemaining(&available_space);
460 
461   if (!available_space) {
462     m_bWriteEnable = true;
463     m_error = EWOULDBLOCK;
464     return SOCKET_ERROR;
465   }
466 
467   int written = queue(buffer, uint32_t(len), false);
468   attemptSend();
469   return written;
470 }
471 
Close(bool force)472 void PseudoTcp::Close(bool force) {
473   RTC_LOG_F(LS_VERBOSE) << "(" << (force ? "true" : "false") << ")";
474   m_shutdown = force ? SD_FORCEFUL : SD_GRACEFUL;
475 }
476 
GetError()477 int PseudoTcp::GetError() {
478   return m_error;
479 }
480 
481 //
482 // Internal Implementation
483 //
484 
queue(const char * data,uint32_t len,bool bCtrl)485 uint32_t PseudoTcp::queue(const char* data, uint32_t len, bool bCtrl) {
486   size_t available_space = 0;
487   m_sbuf.GetWriteRemaining(&available_space);
488 
489   if (len > static_cast<uint32_t>(available_space)) {
490     RTC_DCHECK(!bCtrl);
491     len = static_cast<uint32_t>(available_space);
492   }
493 
494   // We can concatenate data if the last segment is the same type
495   // (control v. regular data), and has not been transmitted yet
496   if (!m_slist.empty() && (m_slist.back().bCtrl == bCtrl) &&
497       (m_slist.back().xmit == 0)) {
498     m_slist.back().len += len;
499   } else {
500     size_t snd_buffered = 0;
501     m_sbuf.GetBuffered(&snd_buffered);
502     SSegment sseg(static_cast<uint32_t>(m_snd_una + snd_buffered), len, bCtrl);
503     m_slist.push_back(sseg);
504   }
505 
506   size_t written = 0;
507   m_sbuf.Write(data, len, &written, NULL);
508   return static_cast<uint32_t>(written);
509 }
510 
packet(uint32_t seq,uint8_t flags,uint32_t offset,uint32_t len)511 IPseudoTcpNotify::WriteResult PseudoTcp::packet(uint32_t seq,
512                                                 uint8_t flags,
513                                                 uint32_t offset,
514                                                 uint32_t len) {
515   RTC_DCHECK(HEADER_SIZE + len <= MAX_PACKET);
516 
517   uint32_t now = Now();
518 
519   std::unique_ptr<uint8_t[]> buffer(new uint8_t[MAX_PACKET]);
520   long_to_bytes(m_conv, buffer.get());
521   long_to_bytes(seq, buffer.get() + 4);
522   long_to_bytes(m_rcv_nxt, buffer.get() + 8);
523   buffer[12] = 0;
524   buffer[13] = flags;
525   short_to_bytes(static_cast<uint16_t>(m_rcv_wnd >> m_rwnd_scale),
526                  buffer.get() + 14);
527 
528   // Timestamp computations
529   long_to_bytes(now, buffer.get() + 16);
530   long_to_bytes(m_ts_recent, buffer.get() + 20);
531   m_ts_lastack = m_rcv_nxt;
532 
533   if (len) {
534     size_t bytes_read = 0;
535     rtc::StreamResult result =
536         m_sbuf.ReadOffset(buffer.get() + HEADER_SIZE, len, offset, &bytes_read);
537     RTC_DCHECK(result == rtc::SR_SUCCESS);
538     RTC_DCHECK(static_cast<uint32_t>(bytes_read) == len);
539   }
540 
541 #if _DEBUGMSG >= _DBG_VERBOSE
542   RTC_LOG(LS_INFO) << "<-- <CONV=" << m_conv
543                    << "><FLG=" << static_cast<unsigned>(flags)
544                    << "><SEQ=" << seq << ":" << seq + len
545                    << "><ACK=" << m_rcv_nxt << "><WND=" << m_rcv_wnd
546                    << "><TS=" << (now % 10000)
547                    << "><TSR=" << (m_ts_recent % 10000) << "><LEN=" << len
548                    << ">";
549 #endif  // _DEBUGMSG
550 
551   IPseudoTcpNotify::WriteResult wres = m_notify->TcpWritePacket(
552       this, reinterpret_cast<char*>(buffer.get()), len + HEADER_SIZE);
553   // Note: When len is 0, this is an ACK packet.  We don't read the return value
554   // for those, and thus we won't retry.  So go ahead and treat the packet as a
555   // success (basically simulate as if it were dropped), which will prevent our
556   // timers from being messed up.
557   if ((wres != IPseudoTcpNotify::WR_SUCCESS) && (0 != len))
558     return wres;
559 
560   m_t_ack = 0;
561   if (len > 0) {
562     m_lastsend = now;
563   }
564   m_lasttraffic = now;
565   m_bOutgoing = true;
566 
567   return IPseudoTcpNotify::WR_SUCCESS;
568 }
569 
parse(const uint8_t * buffer,uint32_t size)570 bool PseudoTcp::parse(const uint8_t* buffer, uint32_t size) {
571   if (size < HEADER_SIZE)
572     return false;
573 
574   Segment seg;
575   seg.conv = bytes_to_long(buffer);
576   seg.seq = bytes_to_long(buffer + 4);
577   seg.ack = bytes_to_long(buffer + 8);
578   seg.flags = buffer[13];
579   seg.wnd = bytes_to_short(buffer + 14);
580 
581   seg.tsval = bytes_to_long(buffer + 16);
582   seg.tsecr = bytes_to_long(buffer + 20);
583 
584   seg.data = reinterpret_cast<const char*>(buffer) + HEADER_SIZE;
585   seg.len = size - HEADER_SIZE;
586 
587 #if _DEBUGMSG >= _DBG_VERBOSE
588   RTC_LOG(LS_INFO) << "--> <CONV=" << seg.conv
589                    << "><FLG=" << static_cast<unsigned>(seg.flags)
590                    << "><SEQ=" << seg.seq << ":" << seg.seq + seg.len
591                    << "><ACK=" << seg.ack << "><WND=" << seg.wnd
592                    << "><TS=" << (seg.tsval % 10000)
593                    << "><TSR=" << (seg.tsecr % 10000) << "><LEN=" << seg.len
594                    << ">";
595 #endif  // _DEBUGMSG
596 
597   return process(seg);
598 }
599 
clock_check(uint32_t now,long & nTimeout)600 bool PseudoTcp::clock_check(uint32_t now, long& nTimeout) {
601   if (m_shutdown == SD_FORCEFUL)
602     return false;
603 
604   size_t snd_buffered = 0;
605   m_sbuf.GetBuffered(&snd_buffered);
606   if ((m_shutdown == SD_GRACEFUL) &&
607       ((m_state != TCP_ESTABLISHED) ||
608        ((snd_buffered == 0) && (m_t_ack == 0)))) {
609     return false;
610   }
611 
612   if (m_state == TCP_CLOSED) {
613     nTimeout = CLOSED_TIMEOUT;
614     return true;
615   }
616 
617   nTimeout = DEFAULT_TIMEOUT;
618 
619   if (m_t_ack) {
620     nTimeout = std::min<int32_t>(nTimeout,
621                                  rtc::TimeDiff32(m_t_ack + m_ack_delay, now));
622   }
623   if (m_rto_base) {
624     nTimeout = std::min<int32_t>(nTimeout,
625                                  rtc::TimeDiff32(m_rto_base + m_rx_rto, now));
626   }
627   if (m_snd_wnd == 0) {
628     nTimeout = std::min<int32_t>(nTimeout,
629                                  rtc::TimeDiff32(m_lastsend + m_rx_rto, now));
630   }
631 #if PSEUDO_KEEPALIVE
632   if (m_state == TCP_ESTABLISHED) {
633     nTimeout = std::min<int32_t>(
634         nTimeout,
635         rtc::TimeDiff32(
636             m_lasttraffic + (m_bOutgoing ? IDLE_PING * 3 / 2 : IDLE_PING),
637             now));
638   }
639 #endif  // PSEUDO_KEEPALIVE
640   return true;
641 }
642 
process(Segment & seg)643 bool PseudoTcp::process(Segment& seg) {
644   // If this is the wrong conversation, send a reset!?! (with the correct
645   // conversation?)
646   if (seg.conv != m_conv) {
647     // if ((seg.flags & FLAG_RST) == 0) {
648     //  packet(tcb, seg.ack, 0, FLAG_RST, 0, 0);
649     //}
650     RTC_LOG_F(LS_ERROR) << "wrong conversation";
651     return false;
652   }
653 
654   uint32_t now = Now();
655   m_lasttraffic = m_lastrecv = now;
656   m_bOutgoing = false;
657 
658   if (m_state == TCP_CLOSED) {
659     // !?! send reset?
660     RTC_LOG_F(LS_ERROR) << "closed";
661     return false;
662   }
663 
664   // Check if this is a reset segment
665   if (seg.flags & FLAG_RST) {
666     closedown(ECONNRESET);
667     return false;
668   }
669 
670   // Check for control data
671   bool bConnect = false;
672   if (seg.flags & FLAG_CTL) {
673     if (seg.len == 0) {
674       RTC_LOG_F(LS_ERROR) << "Missing control code";
675       return false;
676     } else if (seg.data[0] == CTL_CONNECT) {
677       bConnect = true;
678 
679       // TCP options are in the remainder of the payload after CTL_CONNECT.
680       parseOptions(&seg.data[1], seg.len - 1);
681 
682       if (m_state == TCP_LISTEN) {
683         m_state = TCP_SYN_RECEIVED;
684         RTC_LOG(LS_INFO) << "State: TCP_SYN_RECEIVED";
685         // m_notify->associate(addr);
686         queueConnectMessage();
687       } else if (m_state == TCP_SYN_SENT) {
688         m_state = TCP_ESTABLISHED;
689         RTC_LOG(LS_INFO) << "State: TCP_ESTABLISHED";
690         adjustMTU();
691         if (m_notify) {
692           m_notify->OnTcpOpen(this);
693         }
694         // notify(evOpen);
695       }
696     } else {
697       RTC_LOG_F(LS_WARNING) << "Unknown control code: " << seg.data[0];
698       return false;
699     }
700   }
701 
702   // Update timestamp
703   if ((seg.seq <= m_ts_lastack) && (m_ts_lastack < seg.seq + seg.len)) {
704     m_ts_recent = seg.tsval;
705   }
706 
707   // Check if this is a valuable ack
708   if ((seg.ack > m_snd_una) && (seg.ack <= m_snd_nxt)) {
709     // Calculate round-trip time
710     if (seg.tsecr) {
711       int32_t rtt = rtc::TimeDiff32(now, seg.tsecr);
712       if (rtt >= 0) {
713         if (m_rx_srtt == 0) {
714           m_rx_srtt = rtt;
715           m_rx_rttvar = rtt / 2;
716         } else {
717           uint32_t unsigned_rtt = static_cast<uint32_t>(rtt);
718           uint32_t abs_err = unsigned_rtt > m_rx_srtt
719                                  ? unsigned_rtt - m_rx_srtt
720                                  : m_rx_srtt - unsigned_rtt;
721           m_rx_rttvar = (3 * m_rx_rttvar + abs_err) / 4;
722           m_rx_srtt = (7 * m_rx_srtt + rtt) / 8;
723         }
724         m_rx_rto = rtc::SafeClamp(m_rx_srtt + rtc::SafeMax(1, 4 * m_rx_rttvar),
725                                   MIN_RTO, MAX_RTO);
726 #if _DEBUGMSG >= _DBG_VERBOSE
727         RTC_LOG(LS_INFO) << "rtt: " << rtt << "  srtt: " << m_rx_srtt
728                          << "  rto: " << m_rx_rto;
729 #endif  // _DEBUGMSG
730       } else {
731         RTC_LOG(LS_WARNING) << "rtt < 0";
732       }
733     }
734 
735     m_snd_wnd = static_cast<uint32_t>(seg.wnd) << m_swnd_scale;
736 
737     uint32_t nAcked = seg.ack - m_snd_una;
738     m_snd_una = seg.ack;
739 
740     m_rto_base = (m_snd_una == m_snd_nxt) ? 0 : now;
741 
742     m_sbuf.ConsumeReadData(nAcked);
743 
744     for (uint32_t nFree = nAcked; nFree > 0;) {
745       RTC_DCHECK(!m_slist.empty());
746       if (nFree < m_slist.front().len) {
747         m_slist.front().len -= nFree;
748         nFree = 0;
749       } else {
750         if (m_slist.front().len > m_largest) {
751           m_largest = m_slist.front().len;
752         }
753         nFree -= m_slist.front().len;
754         m_slist.pop_front();
755       }
756     }
757 
758     if (m_dup_acks >= 3) {
759       if (m_snd_una >= m_recover) {  // NewReno
760         uint32_t nInFlight = m_snd_nxt - m_snd_una;
761         m_cwnd = std::min(m_ssthresh, nInFlight + m_mss);  // (Fast Retransmit)
762 #if _DEBUGMSG >= _DBG_NORMAL
763         RTC_LOG(LS_INFO) << "exit recovery";
764 #endif  // _DEBUGMSG
765         m_dup_acks = 0;
766       } else {
767 #if _DEBUGMSG >= _DBG_NORMAL
768         RTC_LOG(LS_INFO) << "recovery retransmit";
769 #endif  // _DEBUGMSG
770         if (!transmit(m_slist.begin(), now)) {
771           closedown(ECONNABORTED);
772           return false;
773         }
774         m_cwnd += m_mss - std::min(nAcked, m_cwnd);
775       }
776     } else {
777       m_dup_acks = 0;
778       // Slow start, congestion avoidance
779       if (m_cwnd < m_ssthresh) {
780         m_cwnd += m_mss;
781       } else {
782         m_cwnd += std::max<uint32_t>(1, m_mss * m_mss / m_cwnd);
783       }
784     }
785   } else if (seg.ack == m_snd_una) {
786     // !?! Note, tcp says don't do this... but otherwise how does a closed
787     // window become open?
788     m_snd_wnd = static_cast<uint32_t>(seg.wnd) << m_swnd_scale;
789 
790     // Check duplicate acks
791     if (seg.len > 0) {
792       // it's a dup ack, but with a data payload, so don't modify m_dup_acks
793     } else if (m_snd_una != m_snd_nxt) {
794       m_dup_acks += 1;
795       if (m_dup_acks == 3) {  // (Fast Retransmit)
796 #if _DEBUGMSG >= _DBG_NORMAL
797         RTC_LOG(LS_INFO) << "enter recovery";
798         RTC_LOG(LS_INFO) << "recovery retransmit";
799 #endif  // _DEBUGMSG
800         if (!transmit(m_slist.begin(), now)) {
801           closedown(ECONNABORTED);
802           return false;
803         }
804         m_recover = m_snd_nxt;
805         uint32_t nInFlight = m_snd_nxt - m_snd_una;
806         m_ssthresh = std::max(nInFlight / 2, 2 * m_mss);
807         // RTC_LOG(LS_INFO) << "m_ssthresh: " << m_ssthresh << "  nInFlight: "
808         // << nInFlight << "  m_mss: " << m_mss;
809         m_cwnd = m_ssthresh + 3 * m_mss;
810       } else if (m_dup_acks > 3) {
811         m_cwnd += m_mss;
812       }
813     } else {
814       m_dup_acks = 0;
815     }
816   }
817 
818   // !?! A bit hacky
819   if ((m_state == TCP_SYN_RECEIVED) && !bConnect) {
820     m_state = TCP_ESTABLISHED;
821     RTC_LOG(LS_INFO) << "State: TCP_ESTABLISHED";
822     adjustMTU();
823     if (m_notify) {
824       m_notify->OnTcpOpen(this);
825     }
826     // notify(evOpen);
827   }
828 
829   // If we make room in the send queue, notify the user
830   // The goal it to make sure we always have at least enough data to fill the
831   // window.  We'd like to notify the app when we are halfway to that point.
832   const uint32_t kIdealRefillSize = (m_sbuf_len + m_rbuf_len) / 2;
833   size_t snd_buffered = 0;
834   m_sbuf.GetBuffered(&snd_buffered);
835   if (m_bWriteEnable &&
836       static_cast<uint32_t>(snd_buffered) < kIdealRefillSize) {
837     m_bWriteEnable = false;
838     if (m_notify) {
839       m_notify->OnTcpWriteable(this);
840     }
841     // notify(evWrite);
842   }
843 
844   // Conditions were acks must be sent:
845   // 1) Segment is too old (they missed an ACK) (immediately)
846   // 2) Segment is too new (we missed a segment) (immediately)
847   // 3) Segment has data (so we need to ACK!) (delayed)
848   // ... so the only time we don't need to ACK, is an empty segment that points
849   // to rcv_nxt!
850 
851   SendFlags sflags = sfNone;
852   if (seg.seq != m_rcv_nxt) {
853     sflags = sfImmediateAck;  // (Fast Recovery)
854   } else if (seg.len != 0) {
855     if (m_ack_delay == 0) {
856       sflags = sfImmediateAck;
857     } else {
858       sflags = sfDelayedAck;
859     }
860   }
861 #if _DEBUGMSG >= _DBG_NORMAL
862   if (sflags == sfImmediateAck) {
863     if (seg.seq > m_rcv_nxt) {
864       RTC_LOG_F(LS_INFO) << "too new";
865     } else if (seg.seq + seg.len <= m_rcv_nxt) {
866       RTC_LOG_F(LS_INFO) << "too old";
867     }
868   }
869 #endif  // _DEBUGMSG
870 
871   // Adjust the incoming segment to fit our receive buffer
872   if (seg.seq < m_rcv_nxt) {
873     uint32_t nAdjust = m_rcv_nxt - seg.seq;
874     if (nAdjust < seg.len) {
875       seg.seq += nAdjust;
876       seg.data += nAdjust;
877       seg.len -= nAdjust;
878     } else {
879       seg.len = 0;
880     }
881   }
882 
883   size_t available_space = 0;
884   m_rbuf.GetWriteRemaining(&available_space);
885 
886   if ((seg.seq + seg.len - m_rcv_nxt) >
887       static_cast<uint32_t>(available_space)) {
888     uint32_t nAdjust =
889         seg.seq + seg.len - m_rcv_nxt - static_cast<uint32_t>(available_space);
890     if (nAdjust < seg.len) {
891       seg.len -= nAdjust;
892     } else {
893       seg.len = 0;
894     }
895   }
896 
897   bool bIgnoreData = (seg.flags & FLAG_CTL) || (m_shutdown != SD_NONE);
898   bool bNewData = false;
899 
900   if (seg.len > 0) {
901     bool bRecover = false;
902     if (bIgnoreData) {
903       if (seg.seq == m_rcv_nxt) {
904         m_rcv_nxt += seg.len;
905         // If we received a data segment out of order relative to a control
906         // segment, then we wrote it into the receive buffer at an offset (see
907         // "WriteOffset") below. So we need to advance the position in the
908         // buffer to avoid corrupting data. See bugs.webrtc.org/9208
909         //
910         // We advance the position in the buffer by N bytes by acting like we
911         // wrote N bytes and then immediately read them. We can only do this if
912         // there's not already data ready to read, but this should always be
913         // true in the problematic scenario, since control frames are always
914         // sent first in the stream.
915         size_t rcv_buffered;
916         if (m_rbuf.GetBuffered(&rcv_buffered) && rcv_buffered == 0) {
917           m_rbuf.ConsumeWriteBuffer(seg.len);
918           m_rbuf.ConsumeReadData(seg.len);
919           // After shifting the position in the buffer, we may have
920           // out-of-order packets ready to be recovered.
921           bRecover = true;
922         }
923       }
924     } else {
925       uint32_t nOffset = seg.seq - m_rcv_nxt;
926 
927       rtc::StreamResult result =
928           m_rbuf.WriteOffset(seg.data, seg.len, nOffset, NULL);
929       if (result == rtc::SR_BLOCK) {
930         // Ignore incoming packets outside of the receive window.
931         return false;
932       }
933 
934       RTC_DCHECK(result == rtc::SR_SUCCESS);
935 
936       if (seg.seq == m_rcv_nxt) {
937         m_rbuf.ConsumeWriteBuffer(seg.len);
938         m_rcv_nxt += seg.len;
939         m_rcv_wnd -= seg.len;
940         bNewData = true;
941         // May be able to recover packets previously received out-of-order
942         // now.
943         bRecover = true;
944       } else {
945 #if _DEBUGMSG >= _DBG_NORMAL
946         RTC_LOG(LS_INFO) << "Saving " << seg.len << " bytes (" << seg.seq
947                          << " -> " << seg.seq + seg.len << ")";
948 #endif  // _DEBUGMSG
949         RSegment rseg;
950         rseg.seq = seg.seq;
951         rseg.len = seg.len;
952         RList::iterator it = m_rlist.begin();
953         while ((it != m_rlist.end()) && (it->seq < rseg.seq)) {
954           ++it;
955         }
956         m_rlist.insert(it, rseg);
957       }
958     }
959     if (bRecover) {
960       RList::iterator it = m_rlist.begin();
961       while ((it != m_rlist.end()) && (it->seq <= m_rcv_nxt)) {
962         if (it->seq + it->len > m_rcv_nxt) {
963           sflags = sfImmediateAck;  // (Fast Recovery)
964           uint32_t nAdjust = (it->seq + it->len) - m_rcv_nxt;
965 #if _DEBUGMSG >= _DBG_NORMAL
966           RTC_LOG(LS_INFO) << "Recovered " << nAdjust << " bytes (" << m_rcv_nxt
967                            << " -> " << m_rcv_nxt + nAdjust << ")";
968 #endif  // _DEBUGMSG
969           m_rbuf.ConsumeWriteBuffer(nAdjust);
970           m_rcv_nxt += nAdjust;
971           m_rcv_wnd -= nAdjust;
972           bNewData = true;
973         }
974         it = m_rlist.erase(it);
975       }
976     }
977   }
978 
979   attemptSend(sflags);
980 
981   // If we have new data, notify the user
982   if (bNewData && m_bReadEnable) {
983     m_bReadEnable = false;
984     if (m_notify) {
985       m_notify->OnTcpReadable(this);
986     }
987     // notify(evRead);
988   }
989 
990   return true;
991 }
992 
transmit(const SList::iterator & seg,uint32_t now)993 bool PseudoTcp::transmit(const SList::iterator& seg, uint32_t now) {
994   if (seg->xmit >= ((m_state == TCP_ESTABLISHED) ? 15 : 30)) {
995     RTC_LOG_F(LS_VERBOSE) << "too many retransmits";
996     return false;
997   }
998 
999   uint32_t nTransmit = std::min(seg->len, m_mss);
1000 
1001   while (true) {
1002     uint32_t seq = seg->seq;
1003     uint8_t flags = (seg->bCtrl ? FLAG_CTL : 0);
1004     IPseudoTcpNotify::WriteResult wres =
1005         packet(seq, flags, seg->seq - m_snd_una, nTransmit);
1006 
1007     if (wres == IPseudoTcpNotify::WR_SUCCESS)
1008       break;
1009 
1010     if (wres == IPseudoTcpNotify::WR_FAIL) {
1011       RTC_LOG_F(LS_VERBOSE) << "packet failed";
1012       return false;
1013     }
1014 
1015     RTC_DCHECK(wres == IPseudoTcpNotify::WR_TOO_LARGE);
1016 
1017     while (true) {
1018       if (PACKET_MAXIMUMS[m_msslevel + 1] == 0) {
1019         RTC_LOG_F(LS_VERBOSE) << "MTU too small";
1020         return false;
1021       }
1022       // !?! We need to break up all outstanding and pending packets and then
1023       // retransmit!?!
1024 
1025       m_mss = PACKET_MAXIMUMS[++m_msslevel] - PACKET_OVERHEAD;
1026       m_cwnd = 2 * m_mss;  // I added this... haven't researched actual formula
1027       if (m_mss < nTransmit) {
1028         nTransmit = m_mss;
1029         break;
1030       }
1031     }
1032 #if _DEBUGMSG >= _DBG_NORMAL
1033     RTC_LOG(LS_INFO) << "Adjusting mss to " << m_mss << " bytes";
1034 #endif  // _DEBUGMSG
1035   }
1036 
1037   if (nTransmit < seg->len) {
1038     RTC_LOG_F(LS_VERBOSE) << "mss reduced to " << m_mss;
1039 
1040     SSegment subseg(seg->seq + nTransmit, seg->len - nTransmit, seg->bCtrl);
1041     // subseg.tstamp = seg->tstamp;
1042     subseg.xmit = seg->xmit;
1043     seg->len = nTransmit;
1044 
1045     SList::iterator next = seg;
1046     m_slist.insert(++next, subseg);
1047   }
1048 
1049   if (seg->xmit == 0) {
1050     m_snd_nxt += seg->len;
1051   }
1052   seg->xmit += 1;
1053   // seg->tstamp = now;
1054   if (m_rto_base == 0) {
1055     m_rto_base = now;
1056   }
1057 
1058   return true;
1059 }
1060 
attemptSend(SendFlags sflags)1061 void PseudoTcp::attemptSend(SendFlags sflags) {
1062   uint32_t now = Now();
1063 
1064   if (rtc::TimeDiff32(now, m_lastsend) > static_cast<long>(m_rx_rto)) {
1065     m_cwnd = m_mss;
1066   }
1067 
1068 #if _DEBUGMSG
1069   bool bFirst = true;
1070 #endif  // _DEBUGMSG
1071 
1072   while (true) {
1073     uint32_t cwnd = m_cwnd;
1074     if ((m_dup_acks == 1) || (m_dup_acks == 2)) {  // Limited Transmit
1075       cwnd += m_dup_acks * m_mss;
1076     }
1077     uint32_t nWindow = std::min(m_snd_wnd, cwnd);
1078     uint32_t nInFlight = m_snd_nxt - m_snd_una;
1079     uint32_t nUseable = (nInFlight < nWindow) ? (nWindow - nInFlight) : 0;
1080 
1081     size_t snd_buffered = 0;
1082     m_sbuf.GetBuffered(&snd_buffered);
1083     uint32_t nAvailable =
1084         std::min(static_cast<uint32_t>(snd_buffered) - nInFlight, m_mss);
1085 
1086     if (nAvailable > nUseable) {
1087       if (nUseable * 4 < nWindow) {
1088         // RFC 813 - avoid SWS
1089         nAvailable = 0;
1090       } else {
1091         nAvailable = nUseable;
1092       }
1093     }
1094 
1095 #if _DEBUGMSG >= _DBG_VERBOSE
1096     if (bFirst) {
1097       size_t available_space = 0;
1098       m_sbuf.GetWriteRemaining(&available_space);
1099 
1100       bFirst = false;
1101       RTC_LOG(LS_INFO) << "[cwnd: " << m_cwnd << "  nWindow: " << nWindow
1102                        << "  nInFlight: " << nInFlight
1103                        << "  nAvailable: " << nAvailable
1104                        << "  nQueued: " << snd_buffered
1105                        << "  nEmpty: " << available_space
1106                        << "  ssthresh: " << m_ssthresh << "]";
1107     }
1108 #endif  // _DEBUGMSG
1109 
1110     if (nAvailable == 0) {
1111       if (sflags == sfNone)
1112         return;
1113 
1114       // If this is an immediate ack, or the second delayed ack
1115       if ((sflags == sfImmediateAck) || m_t_ack) {
1116         packet(m_snd_nxt, 0, 0, 0);
1117       } else {
1118         m_t_ack = Now();
1119       }
1120       return;
1121     }
1122 
1123     // Nagle's algorithm.
1124     // If there is data already in-flight, and we haven't a full segment of
1125     // data ready to send then hold off until we get more to send, or the
1126     // in-flight data is acknowledged.
1127     if (m_use_nagling && (m_snd_nxt > m_snd_una) && (nAvailable < m_mss)) {
1128       return;
1129     }
1130 
1131     // Find the next segment to transmit
1132     SList::iterator it = m_slist.begin();
1133     while (it->xmit > 0) {
1134       ++it;
1135       RTC_DCHECK(it != m_slist.end());
1136     }
1137     SList::iterator seg = it;
1138 
1139     // If the segment is too large, break it into two
1140     if (seg->len > nAvailable) {
1141       SSegment subseg(seg->seq + nAvailable, seg->len - nAvailable, seg->bCtrl);
1142       seg->len = nAvailable;
1143       m_slist.insert(++it, subseg);
1144     }
1145 
1146     if (!transmit(seg, now)) {
1147       RTC_LOG_F(LS_VERBOSE) << "transmit failed";
1148       // TODO(?): consider closing socket
1149       return;
1150     }
1151 
1152     sflags = sfNone;
1153   }
1154 }
1155 
closedown(uint32_t err)1156 void PseudoTcp::closedown(uint32_t err) {
1157   RTC_LOG(LS_INFO) << "State: TCP_CLOSED";
1158   m_state = TCP_CLOSED;
1159   if (m_notify) {
1160     m_notify->OnTcpClosed(this, err);
1161   }
1162   // notify(evClose, err);
1163 }
1164 
adjustMTU()1165 void PseudoTcp::adjustMTU() {
1166   // Determine our current mss level, so that we can adjust appropriately later
1167   for (m_msslevel = 0; PACKET_MAXIMUMS[m_msslevel + 1] > 0; ++m_msslevel) {
1168     if (static_cast<uint16_t>(PACKET_MAXIMUMS[m_msslevel]) <= m_mtu_advise) {
1169       break;
1170     }
1171   }
1172   m_mss = m_mtu_advise - PACKET_OVERHEAD;
1173 // !?! Should we reset m_largest here?
1174 #if _DEBUGMSG >= _DBG_NORMAL
1175   RTC_LOG(LS_INFO) << "Adjusting mss to " << m_mss << " bytes";
1176 #endif  // _DEBUGMSG
1177   // Enforce minimums on ssthresh and cwnd
1178   m_ssthresh = std::max(m_ssthresh, 2 * m_mss);
1179   m_cwnd = std::max(m_cwnd, m_mss);
1180 }
1181 
isReceiveBufferFull() const1182 bool PseudoTcp::isReceiveBufferFull() const {
1183   size_t available_space = 0;
1184   m_rbuf.GetWriteRemaining(&available_space);
1185   return !available_space;
1186 }
1187 
disableWindowScale()1188 void PseudoTcp::disableWindowScale() {
1189   m_support_wnd_scale = false;
1190 }
1191 
queueConnectMessage()1192 void PseudoTcp::queueConnectMessage() {
1193   rtc::ByteBufferWriter buf;
1194 
1195   buf.WriteUInt8(CTL_CONNECT);
1196   if (m_support_wnd_scale) {
1197     buf.WriteUInt8(TCP_OPT_WND_SCALE);
1198     buf.WriteUInt8(1);
1199     buf.WriteUInt8(m_rwnd_scale);
1200   }
1201   m_snd_wnd = static_cast<uint32_t>(buf.Length());
1202   queue(buf.Data(), static_cast<uint32_t>(buf.Length()), true);
1203 }
1204 
parseOptions(const char * data,uint32_t len)1205 void PseudoTcp::parseOptions(const char* data, uint32_t len) {
1206   std::set<uint8_t> options_specified;
1207 
1208   // See http://www.freesoft.org/CIE/Course/Section4/8.htm for
1209   // parsing the options list.
1210   rtc::ByteBufferReader buf(data, len);
1211   while (buf.Length()) {
1212     uint8_t kind = TCP_OPT_EOL;
1213     buf.ReadUInt8(&kind);
1214 
1215     if (kind == TCP_OPT_EOL) {
1216       // End of option list.
1217       break;
1218     } else if (kind == TCP_OPT_NOOP) {
1219       // No op.
1220       continue;
1221     }
1222 
1223     // Length of this option.
1224     RTC_DCHECK(len != 0);
1225     uint8_t opt_len = 0;
1226     buf.ReadUInt8(&opt_len);
1227 
1228     // Content of this option.
1229     if (opt_len <= buf.Length()) {
1230       applyOption(kind, buf.Data(), opt_len);
1231       buf.Consume(opt_len);
1232     } else {
1233       RTC_LOG(LS_ERROR) << "Invalid option length received.";
1234       return;
1235     }
1236     options_specified.insert(kind);
1237   }
1238 
1239   if (options_specified.find(TCP_OPT_WND_SCALE) == options_specified.end()) {
1240     RTC_LOG(LS_WARNING) << "Peer doesn't support window scaling";
1241 
1242     if (m_rwnd_scale > 0) {
1243       // Peer doesn't support TCP options and window scaling.
1244       // Revert receive buffer size to default value.
1245       resizeReceiveBuffer(DEFAULT_RCV_BUF_SIZE);
1246       m_swnd_scale = 0;
1247     }
1248   }
1249 }
1250 
applyOption(char kind,const char * data,uint32_t len)1251 void PseudoTcp::applyOption(char kind, const char* data, uint32_t len) {
1252   if (kind == TCP_OPT_MSS) {
1253     RTC_LOG(LS_WARNING) << "Peer specified MSS option which is not supported.";
1254     // TODO(?): Implement.
1255   } else if (kind == TCP_OPT_WND_SCALE) {
1256     // Window scale factor.
1257     // http://www.ietf.org/rfc/rfc1323.txt
1258     if (len != 1) {
1259       RTC_LOG_F(WARNING) << "Invalid window scale option received.";
1260       return;
1261     }
1262     applyWindowScaleOption(data[0]);
1263   }
1264 }
1265 
applyWindowScaleOption(uint8_t scale_factor)1266 void PseudoTcp::applyWindowScaleOption(uint8_t scale_factor) {
1267   m_swnd_scale = scale_factor;
1268 }
1269 
resizeSendBuffer(uint32_t new_size)1270 void PseudoTcp::resizeSendBuffer(uint32_t new_size) {
1271   m_sbuf_len = new_size;
1272   m_sbuf.SetCapacity(new_size);
1273 }
1274 
resizeReceiveBuffer(uint32_t new_size)1275 void PseudoTcp::resizeReceiveBuffer(uint32_t new_size) {
1276   uint8_t scale_factor = 0;
1277 
1278   // Determine the scale factor such that the scaled window size can fit
1279   // in a 16-bit unsigned integer.
1280   while (new_size > 0xFFFF) {
1281     ++scale_factor;
1282     new_size >>= 1;
1283   }
1284 
1285   // Determine the proper size of the buffer.
1286   new_size <<= scale_factor;
1287   bool result = m_rbuf.SetCapacity(new_size);
1288 
1289   // Make sure the new buffer is large enough to contain data in the old
1290   // buffer. This should always be true because this method is called either
1291   // before connection is established or when peers are exchanging connect
1292   // messages.
1293   RTC_DCHECK(result);
1294   m_rbuf_len = new_size;
1295   m_rwnd_scale = scale_factor;
1296   m_ssthresh = new_size;
1297 
1298   size_t available_space = 0;
1299   m_rbuf.GetWriteRemaining(&available_space);
1300   m_rcv_wnd = static_cast<uint32_t>(available_space);
1301 }
1302 
1303 }  // namespace cricket
1304