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 #ifndef P2P_BASE_PSEUDO_TCP_H_
12 #define P2P_BASE_PSEUDO_TCP_H_
13 
14 #include <stddef.h>
15 #include <stdint.h>
16 
17 #include <list>
18 
19 #include "rtc_base/memory/fifo_buffer.h"
20 #include "rtc_base/system/rtc_export.h"
21 
22 namespace cricket {
23 
24 //////////////////////////////////////////////////////////////////////
25 // IPseudoTcpNotify
26 //////////////////////////////////////////////////////////////////////
27 
28 class PseudoTcp;
29 
30 class IPseudoTcpNotify {
31  public:
32   // Notification of tcp events
33   virtual void OnTcpOpen(PseudoTcp* tcp) = 0;
34   virtual void OnTcpReadable(PseudoTcp* tcp) = 0;
35   virtual void OnTcpWriteable(PseudoTcp* tcp) = 0;
36   virtual void OnTcpClosed(PseudoTcp* tcp, uint32_t error) = 0;
37 
38   // Write the packet onto the network
39   enum WriteResult { WR_SUCCESS, WR_TOO_LARGE, WR_FAIL };
40   virtual WriteResult TcpWritePacket(PseudoTcp* tcp,
41                                      const char* buffer,
42                                      size_t len) = 0;
43 
44  protected:
~IPseudoTcpNotify()45   virtual ~IPseudoTcpNotify() {}
46 };
47 
48 //////////////////////////////////////////////////////////////////////
49 // PseudoTcp
50 //////////////////////////////////////////////////////////////////////
51 
52 class RTC_EXPORT PseudoTcp {
53  public:
54   static uint32_t Now();
55 
56   PseudoTcp(IPseudoTcpNotify* notify, uint32_t conv);
57   virtual ~PseudoTcp();
58 
59   int Connect();
60   int Recv(char* buffer, size_t len);
61   int Send(const char* buffer, size_t len);
62   void Close(bool force);
63   int GetError();
64 
65   enum TcpState {
66     TCP_LISTEN,
67     TCP_SYN_SENT,
68     TCP_SYN_RECEIVED,
69     TCP_ESTABLISHED,
70     TCP_CLOSED
71   };
State()72   TcpState State() const { return m_state; }
73 
74   // Call this when the PMTU changes.
75   void NotifyMTU(uint16_t mtu);
76 
77   // Call this based on timeout value returned from GetNextClock.
78   // It's ok to call this too frequently.
79   void NotifyClock(uint32_t now);
80 
81   // Call this whenever a packet arrives.
82   // Returns true if the packet was processed successfully.
83   bool NotifyPacket(const char* buffer, size_t len);
84 
85   // Call this to determine the next time NotifyClock should be called.
86   // Returns false if the socket is ready to be destroyed.
87   bool GetNextClock(uint32_t now, long& timeout);
88 
89   // Call these to get/set option values to tailor this PseudoTcp
90   // instance's behaviour for the kind of data it will carry.
91   // If an unrecognized option is set or got, an assertion will fire.
92   //
93   // Setting options for OPT_RCVBUF or OPT_SNDBUF after Connect() is called
94   // will result in an assertion.
95   enum Option {
96     OPT_NODELAY,   // Whether to enable Nagle's algorithm (0 == off)
97     OPT_ACKDELAY,  // The Delayed ACK timeout (0 == off).
98     OPT_RCVBUF,    // Set the receive buffer size, in bytes.
99     OPT_SNDBUF,    // Set the send buffer size, in bytes.
100   };
101   void GetOption(Option opt, int* value);
102   void SetOption(Option opt, int value);
103 
104   // Returns current congestion window in bytes.
105   uint32_t GetCongestionWindow() const;
106 
107   // Returns amount of data in bytes that has been sent, but haven't
108   // been acknowledged.
109   uint32_t GetBytesInFlight() const;
110 
111   // Returns number of bytes that were written in buffer and haven't
112   // been sent.
113   uint32_t GetBytesBufferedNotSent() const;
114 
115   // Returns current round-trip time estimate in milliseconds.
116   uint32_t GetRoundTripTimeEstimateMs() const;
117 
118  protected:
119   enum SendFlags { sfNone, sfDelayedAck, sfImmediateAck };
120 
121   struct Segment {
122     uint32_t conv, seq, ack;
123     uint8_t flags;
124     uint16_t wnd;
125     const char* data;
126     uint32_t len;
127     uint32_t tsval, tsecr;
128   };
129 
130   struct SSegment {
SSegmentSSegment131     SSegment(uint32_t s, uint32_t l, bool c)
132         : seq(s), len(l), /*tstamp(0),*/ xmit(0), bCtrl(c) {}
133     uint32_t seq, len;
134     // uint32_t tstamp;
135     uint8_t xmit;
136     bool bCtrl;
137   };
138   typedef std::list<SSegment> SList;
139 
140   struct RSegment {
141     uint32_t seq, len;
142   };
143 
144   uint32_t queue(const char* data, uint32_t len, bool bCtrl);
145 
146   // Creates a packet and submits it to the network. This method can either
147   // send payload or just an ACK packet.
148   //
149   // |seq| is the sequence number of this packet.
150   // |flags| is the flags for sending this packet.
151   // |offset| is the offset to read from |m_sbuf|.
152   // |len| is the number of bytes to read from |m_sbuf| as payload. If this
153   // value is 0 then this is an ACK packet, otherwise this packet has payload.
154   IPseudoTcpNotify::WriteResult packet(uint32_t seq,
155                                        uint8_t flags,
156                                        uint32_t offset,
157                                        uint32_t len);
158   bool parse(const uint8_t* buffer, uint32_t size);
159 
160   void attemptSend(SendFlags sflags = sfNone);
161 
162   void closedown(uint32_t err = 0);
163 
164   bool clock_check(uint32_t now, long& nTimeout);
165 
166   bool process(Segment& seg);
167   bool transmit(const SList::iterator& seg, uint32_t now);
168 
169   void adjustMTU();
170 
171  protected:
172   // This method is used in test only to query receive buffer state.
173   bool isReceiveBufferFull() const;
174 
175   // This method is only used in tests, to disable window scaling
176   // support for testing backward compatibility.
177   void disableWindowScale();
178 
179  private:
180   // Queue the connect message with TCP options.
181   void queueConnectMessage();
182 
183   // Parse TCP options in the header.
184   void parseOptions(const char* data, uint32_t len);
185 
186   // Apply a TCP option that has been read from the header.
187   void applyOption(char kind, const char* data, uint32_t len);
188 
189   // Apply window scale option.
190   void applyWindowScaleOption(uint8_t scale_factor);
191 
192   // Resize the send buffer with |new_size| in bytes.
193   void resizeSendBuffer(uint32_t new_size);
194 
195   // Resize the receive buffer with |new_size| in bytes. This call adjusts
196   // window scale factor |m_swnd_scale| accordingly.
197   void resizeReceiveBuffer(uint32_t new_size);
198 
199   IPseudoTcpNotify* m_notify;
200   enum Shutdown { SD_NONE, SD_GRACEFUL, SD_FORCEFUL } m_shutdown;
201   int m_error;
202 
203   // TCB data
204   TcpState m_state;
205   uint32_t m_conv;
206   bool m_bReadEnable, m_bWriteEnable, m_bOutgoing;
207   uint32_t m_lasttraffic;
208 
209   // Incoming data
210   typedef std::list<RSegment> RList;
211   RList m_rlist;
212   uint32_t m_rbuf_len, m_rcv_nxt, m_rcv_wnd, m_lastrecv;
213   uint8_t m_rwnd_scale;  // Window scale factor.
214   rtc::FifoBuffer m_rbuf;
215 
216   // Outgoing data
217   SList m_slist;
218   uint32_t m_sbuf_len, m_snd_nxt, m_snd_wnd, m_lastsend, m_snd_una;
219   uint8_t m_swnd_scale;  // Window scale factor.
220   rtc::FifoBuffer m_sbuf;
221 
222   // Maximum segment size, estimated protocol level, largest segment sent
223   uint32_t m_mss, m_msslevel, m_largest, m_mtu_advise;
224   // Retransmit timer
225   uint32_t m_rto_base;
226 
227   // Timestamp tracking
228   uint32_t m_ts_recent, m_ts_lastack;
229 
230   // Round-trip calculation
231   uint32_t m_rx_rttvar, m_rx_srtt, m_rx_rto;
232 
233   // Congestion avoidance, Fast retransmit/recovery, Delayed ACKs
234   uint32_t m_ssthresh, m_cwnd;
235   uint8_t m_dup_acks;
236   uint32_t m_recover;
237   uint32_t m_t_ack;
238 
239   // Configuration options
240   bool m_use_nagling;
241   uint32_t m_ack_delay;
242 
243   // This is used by unit tests to test backward compatibility of
244   // PseudoTcp implementations that don't support window scaling.
245   bool m_support_wnd_scale;
246 };
247 
248 }  // namespace cricket
249 
250 #endif  // P2P_BASE_PSEUDO_TCP_H_
251