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