tcp_timer.c
Go to the documentation of this file.
1 /**
2  * @file tcp_timer.c
3  * @brief TCP timer management
4  *
5  * @section License
6  *
7  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneTCP Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 1.9.0
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL TCP_TRACE_LEVEL
31 
32 //Dependencies
33 #include "core/net.h"
34 #include "core/socket.h"
35 #include "core/tcp.h"
36 #include "core/tcp_misc.h"
37 #include "core/tcp_timer.h"
38 #include "ipv4/ipv4.h"
39 #include "ipv6/ipv6.h"
40 #include "date_time.h"
41 #include "debug.h"
42 
43 //Check TCP/IP stack configuration
44 #if (TCP_SUPPORT == ENABLED)
45 
46 
47 /**
48  * @brief TCP timer handler
49  *
50  * This routine must be periodically called by the TCP/IP stack to
51  * handle retransmissions and TCP related timers (persist timer,
52  * FIN-WAIT-2 timer and TIME-WAIT timer)
53  *
54  **/
55 
56 void tcpTick(void)
57 {
58  error_t error;
59  uint_t i;
60  uint_t n;
61  uint_t u;
62 
63  //Loop through opened sockets
64  for(i = 0; i < SOCKET_MAX_COUNT; i++)
65  {
66  //Shortcut to the current socket
67  Socket *socket = socketTable + i;
68  //Check socket type
69  if(socket->type != SOCKET_TYPE_STREAM)
70  continue;
71  //Check the current state of the TCP state machine
72  if(socket->state == TCP_STATE_CLOSED)
73  continue;
74 
75  //Is there any packet in the retransmission queue?
76  if(socket->retransmitQueue != NULL)
77  {
78  //Retransmission timeout?
79  if(tcpTimerElapsed(&socket->retransmitTimer))
80  {
81 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
82  //When a TCP sender detects segment loss using the retransmission
83  //timer and the given segment has not yet been resent by way of
84  //the retransmission timer, the value of ssthresh must be updated
85  if(!socket->retransmitCount)
86  {
87  //Amount of data that has been sent but not yet acknowledged
88  uint_t flightSize = socket->sndNxt - socket->sndUna;
89  //Adjust ssthresh value
90  socket->ssthresh = MAX(flightSize / 2, 2 * socket->smss);
91  }
92 
93  //Furthermore, upon a timeout cwnd must be set to no more than
94  //the loss window, LW, which equals 1 full-sized segment
95  socket->cwnd = MIN(TCP_LOSS_WINDOW * socket->smss, socket->txBufferSize);
96 
97  //After a retransmit timeout, record the highest sequence number
98  //transmitted in the variable recover
99  socket->recover = socket->sndNxt - 1;
100 
101  //Enter the fast loss recovery procedure
102  socket->congestState = TCP_CONGEST_STATE_LOSS_RECOVERY;
103 #endif
104  //Make sure the maximum number of retransmissions has not been reached
105  if(socket->retransmitCount < TCP_MAX_RETRIES)
106  {
107  //Debug message
108  TRACE_INFO("%s: TCP segment retransmission #%u (%u data bytes)...\r\n",
109  formatSystemTime(osGetSystemTime(), NULL), socket->retransmitCount + 1,
110  socket->retransmitQueue->length);
111 
112  //Retransmit the earliest segment that has not been
113  //acknowledged by the TCP receiver
115 
116  //Use exponential back-off algorithm to calculate the new RTO
117  socket->rto = MIN(socket->rto * 2, TCP_MAX_RTO);
118  //Restart retransmission timer
119  tcpTimerStart(&socket->retransmitTimer, socket->rto);
120  //Increment retransmission counter
121  socket->retransmitCount++;
122  }
123  else
124  {
125  //The maximum number of retransmissions has been exceeded
127  //Turn off the retransmission timer
128  tcpTimerStop(&socket->retransmitTimer);
129  }
130 
131  //TCP must use Karn's algorithm for taking RTT samples. That is, RTT
132  //samples must not be made using segments that were retransmitted
133  socket->rttBusy = FALSE;
134  }
135  }
136 
137  //Check the current state of the TCP state machine
138  if(socket->state == TCP_STATE_CLOSED)
139  continue;
140 
141  //The persist timer is used when the remote host advertises
142  //a window size of zero
143  if(!socket->sndWnd && socket->wndProbeInterval)
144  {
145  //Time to send a new probe?
146  if(tcpTimerElapsed(&socket->persistTimer))
147  {
148  //Make sure the maximum number of retransmissions has not been reached
149  if(socket->wndProbeCount < TCP_MAX_RETRIES)
150  {
151  //Debug message
152  TRACE_INFO("%s: TCP zero window probe #%u...\r\n",
153  formatSystemTime(osGetSystemTime(), NULL), socket->wndProbeCount + 1);
154 
155  //Zero window probes usually have the sequence number one less than expected
156  tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt - 1, socket->rcvNxt, 0, FALSE);
157  //The interval between successive probes should be increased exponentially
158  socket->wndProbeInterval = MIN(socket->wndProbeInterval * 2, TCP_MAX_PROBE_INTERVAL);
159  //Restart the persist timer
160  tcpTimerStart(&socket->persistTimer, socket->wndProbeInterval);
161  //Increment window probe counter
162  socket->wndProbeCount++;
163  }
164  else
165  {
166  //Enter CLOSED state
168  }
169  }
170  }
171 
172  //To avoid a deadlock, it is necessary to have a timeout to force
173  //transmission of data, overriding the SWS avoidance algorithm. In
174  //practice, this timeout should seldom occur (see RFC 1122 4.2.3.4)
175  if(socket->state == TCP_STATE_ESTABLISHED || socket->state == TCP_STATE_CLOSE_WAIT)
176  {
177  //The override timeout occurred?
178  if(socket->sndUser && tcpTimerElapsed(&socket->overrideTimer))
179  {
180  //The amount of data that can be sent at any given time is
181  //limited by the receiver window and the congestion window
182  n = MIN(socket->sndWnd, socket->txBufferSize);
183 
184 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
185  //Check the congestion window
186  n = MIN(n, socket->cwnd);
187 #endif
188  //Retrieve the size of the usable window
189  u = n - (socket->sndNxt - socket->sndUna);
190 
191  //Send as much data as possible
192  while(socket->sndUser > 0)
193  {
194  //The usable window size may become zero or negative,
195  //preventing packet transmission
196  if((int_t) u <= 0)
197  break;
198 
199  //Calculate the number of bytes to send at a time
200  n = MIN(u, socket->sndUser);
201  n = MIN(n, socket->smss);
202 
203  //Send TCP segment
205  socket->sndNxt, socket->rcvNxt, n, TRUE);
206  //Failed to send TCP segment?
207  if(error)
208  break;
209 
210  //Advance SND.NXT pointer
211  socket->sndNxt += n;
212  //Adjust the number of bytes buffered but not yet sent
213  socket->sndUser -= n;
214  //Update the size of the usable window
215  u -= n;
216  }
217 
218  //Check whether the transmitter can accept more data
220 
221  //Restart override timer if necessary
222  if(socket->sndUser > 0)
223  tcpTimerStart(&socket->overrideTimer, TCP_OVERRIDE_TIMEOUT);
224  }
225  }
226 
227  //The FIN-WAIT-2 timer prevents the connection
228  //from staying in the FIN-WAIT-2 state forever
229  if(socket->state == TCP_STATE_FIN_WAIT_2)
230  {
231  //Maximum FIN-WAIT-2 time has elapsed?
232  if(tcpTimerElapsed(&socket->finWait2Timer))
233  {
234  //Debug message
235  TRACE_WARNING("TCP FIN-WAIT-2 timer elapsed...\r\n");
236  //Enter CLOSED state
238  }
239  }
240 
241  //TIME-WAIT timer
242  if(socket->state == TCP_STATE_TIME_WAIT)
243  {
244  //2MSL time has elapsed?
245  if(tcpTimerElapsed(&socket->timeWaitTimer))
246  {
247  //Debug message
248  TRACE_WARNING("TCP 2MSL timer elapsed (socket %u)...\r\n", i);
249  //Enter CLOSED state
251 
252  //Dispose the socket if the user does not have the ownership anymore
253  if(!socket->ownedFlag)
254  {
255  //Delete the TCB
257  //Mark the socket as closed
258  socket->type = SOCKET_TYPE_UNUSED;
259  }
260  }
261  }
262  }
263 }
264 
265 
266 /**
267  * @brief Start TCP timer
268  * @param[in] timer Pointer to the timer structure
269  * @param[in] delay Time interval
270  **/
271 
272 void tcpTimerStart(TcpTimer *timer, systime_t delay)
273 {
274  //Start timer
275  timer->startTime = osGetSystemTime();
276  timer->interval = delay;
277 
278  //The timer is now running...
279  timer->running = TRUE;
280 }
281 
282 
283 /**
284  * @brief Stop TCP timer
285  * @param[in] timer Pointer to the timer structure
286  **/
287 
288 void tcpTimerStop(TcpTimer *timer)
289 {
290  //Stop timer
291  timer->running = FALSE;
292 }
293 
294 
295 /**
296  * @brief Check whether a TCP timer is running
297  * @param[in] timer Pointer to the timer structure
298  * @return Timer state
299  **/
300 
302 {
303  //Check whether the timer is running
304  return timer->running;
305 }
306 
307 
308 /**
309  * @brief Check whether a TCP timer has elapsed
310  * @param[in] timer Pointer to the timer structure
311  * @return Timer state
312  **/
313 
315 {
316  systime_t time;
317 
318  //Check whether the timer is running
319  if(!timer->running)
320  return FALSE;
321 
322  //Get current time
323  time = osGetSystemTime();
324 
325  //Check whether the specified time interval has elapsed
326  if(timeCompare(time, timer->startTime + timer->interval) >= 0)
327  return TRUE;
328  else
329  return FALSE;
330 }
331 
332 
333 /**
334  * @brief Get current time interval
335  * @param[in] timer Pointer to the timer structure
336  * @return Current time interval
337  **/
338 
340 {
341  //Return current time interval
342  return timer->interval;
343 }
344 
345 #endif
uint32_t systime_t
Definition: compiler_port.h:44
#define TCP_MAX_RETRIES
Definition: tcp.h:108
#define timeCompare(t1, t2)
Definition: os_port.h:40
systime_t osGetSystemTime(void)
Retrieve system time.
uint32_t time
TCP/IP stack core.
Debugging facilities.
void tcpTick(void)
TCP timer handler.
Definition: tcp_timer.c:56
bool_t tcpTimerRunning(TcpTimer *timer)
Check whether a TCP timer is running.
Definition: tcp_timer.c:301
#define SOCKET_MAX_COUNT
Definition: socket.h:43
#define TCP_MAX_PROBE_INTERVAL
Definition: tcp.h:171
#define MAX(a, b)
Definition: os_port.h:64
void tcpDeleteControlBlock(Socket *socket)
Delete TCB structure.
Definition: tcp_misc.c:1128
#define TRUE
Definition: os_port.h:48
int_t socket(int_t family, int_t type, int_t protocol)
Create a socket that is bound to a specific transport service provider.
Definition: bsd_socket.c:106
error_t tcpSendSegment(Socket *socket, uint8_t flags, uint32_t seqNum, uint32_t ackNum, size_t length, bool_t addToQueue)
Send a TCP segment.
Definition: tcp_misc.c:63
Socket socketTable[SOCKET_MAX_COUNT]
Definition: socket.c:46
systime_t interval
Definition: tcp.h:348
#define Socket
Definition: socket.h:34
#define TCP_LOSS_WINDOW
Definition: tcp.h:157
const char_t * formatSystemTime(systime_t time, char_t *str)
Format system time.
Definition: date_time.c:75
signed int int_t
Definition: compiler_port.h:42
Date and time management.
systime_t startTime
Definition: tcp.h:347
IPv4 (Internet Protocol Version 4)
#define MIN(a, b)
Definition: os_port.h:60
systime_t tcpTimerGetInterval(TcpTimer *timer)
Get current time interval.
Definition: tcp_timer.c:339
#define TRACE_INFO(...)
Definition: debug.h:86
#define TCP_OVERRIDE_TIMEOUT
Definition: tcp.h:178
IPv6 (Internet Protocol Version 6)
#define TCP_MAX_RTO
Definition: tcp.h:129
error_t
Error codes.
Definition: error.h:40
#define TRACE_WARNING(...)
Definition: debug.h:78
TCP timer.
Definition: tcp.h:344
unsigned int uint_t
Definition: compiler_port.h:43
Helper functions for TCP.
void tcpChangeState(Socket *socket, TcpState newState)
Update TCP FSM current state.
Definition: tcp_misc.c:1723
void tcpUpdateEvents(Socket *socket)
Update TCP related events.
Definition: tcp_misc.c:1754
void tcpTimerStart(TcpTimer *timer, systime_t delay)
Start TCP timer.
Definition: tcp_timer.c:272
void tcpTimerStop(TcpTimer *timer)
Stop TCP timer.
Definition: tcp_timer.c:288
error_t tcpRetransmitSegment(Socket *socket)
TCP segment retransmission.
Definition: tcp_misc.c:1491
Socket API.
uint8_t n
TCP (Transmission Control Protocol)
bool_t tcpTimerElapsed(TcpTimer *timer)
Check whether a TCP timer has elapsed.
Definition: tcp_timer.c:314
#define FALSE
Definition: os_port.h:44
bool_t running
Definition: tcp.h:346
int bool_t
Definition: compiler_port.h:47
TCP timer management.