NetSim Source Code Help v14.4
All 13 Components
 
Loading...
Searching...
No Matches
RTO.c
1/************************************************************************************
2* Copyright (C) 2023 *
3* TETCOS, Bangalore. India *
4* *
5* Tetcos owns the intellectual property rights in the Product and its content. *
6* The copying, redistribution, reselling or publication of any or all of the *
7* Product or its content without express prior written consent of Tetcos is *
8* prohibited. Ownership and / or any other right relating to the software and all *
9* intellectual property rights therein shall remain at all times with Tetcos. *
10* *
11* This source code is licensed per the NetSim license agreement. *
12* *
13* No portion of this source code may be used as the basis for a derivative work, *
14* or used, for any purpose other than its intended use per the NetSim license *
15* agreement. *
16* *
17* This source code and the algorithms contained within it are confidential trade *
18* secrets of TETCOS and may not be used as the basis for any other software, *
19* hardware, product or service. *
20* *
21* Author: Shashi Kant Suman *
22* *
23* ----------------------------------------------------------------------------------*/
24#include "main.h"
25#include "TCP.h"
26#include "TCP_Enum.h"
27#include "TCP_Header.h"
28
29//RFC 6298
30#define alpha (1/8.0)
31#define beta (1/4.0)
32#define G (0.5*SECOND) /* Min RTO value is set to 0.5 s.
33 * The RFC states this should be 1 s
34 * Linux seems to be currently using 200 ms.
35 */
36#define K (4)
37
38double calculate_RTO(double R,
39 double* srtt,
40 double* rtt_var)
41{
42 double rto;
43 if (!R) //2.1
44 rto = 1 * SECOND;
45 else if (!*srtt) //2.2
46 {
47 *srtt = R;
48 *rtt_var = R / 2.0;
49 rto = *srtt + max(G, K*(*rtt_var));
50 }
51 else //2.3
52 {
53 *rtt_var = (1 - beta) * (*rtt_var) + beta * fabs(*srtt - R);
54 *srtt = (1 - alpha) * (*srtt) + alpha * R;
55 rto = *srtt + max(G, K*(*rtt_var));
56 }
57 return min(max(rto, G), (60 * SECOND)); //2.4 and 2.5
58}
59
60static void Backoff_RTO(double* rto)
61{
62 *rto = min(max((*rto*2), G), (60 * SECOND));
63 print_tcp_log("New RTO = %0.2lf", *rto);
64}
65
66void add_timeout_event(PNETSIM_SOCKET s,
67 NetSim_PACKET* packet)
68{
69 NetSim_PACKET* p = fn_NetSim_Packet_CopyPacket(packet);
70 add_packet_to_queue(&s->tcb->retransmissionQueue, p, pstruEventDetails->dEventTime);
71 if (s->tcb->isRTOTimerRunning) return;
72 s->tcb->isRTOTimerRunning = true;
73 NetSim_EVENTDETAILS pevent;
74 memcpy(&pevent, pstruEventDetails, sizeof pevent);
75 pevent.dEventTime += TCP_RTO(s->tcb);
76 pevent.dPacketSize = packet->pstruTransportData->dPacketSize;
77 pevent.nEventType = TIMER_EVENT;
78 pevent.nPacketId = packet->nPacketId;
79 if (packet->pstruAppData)
80 {
81 pevent.nApplicationId = packet->pstruAppData->nApplicationId;
82 pevent.nSegmentId = packet->pstruAppData->nSegmentId;
83 }
84 else
85 pevent.nSegmentId = 0;
86 pevent.nProtocolId = TX_PROTOCOL_TCP;
87 pevent.pPacket = fn_NetSim_Packet_CopyPacket(p);
88 pevent.szOtherDetails = NULL;
89 pevent.nSubEventType = TCP_RTO_TIMEOUT;
90 s->tcb->RTOEventId = fnpAddEvent(&pevent);
91 s->tcb->eventPacketptr = pevent.pPacket;
92 print_tcp_log("Adding RTO Timer at %0.1lf", pevent.dEventTime);
93}
94
95static void handle_rto_timer_for_ctrl(PNETSIM_SOCKET s)
96{
97 if (isSynbitSet(pstruEventDetails->pPacket))
98 resend_syn(s);
99 else
100 fnNetSimError("Unknown packet %d arrives at %s\n",
101 pstruEventDetails->pPacket->nControlDataType,
102 __FUNCTION__);
103}
104void handle_rto_timer()
105{
106 PNETSIM_SOCKET s = find_socket_at_source(pstruEventDetails->pPacket);
107 if (!s)
108 {
109 //Socket is already close. Ignore this event
110 fn_NetSim_Packet_FreePacket(pstruEventDetails->pPacket);
111 return;
112 }
113 if (!s->tcb || s->tcb->isOtherTimerCancel)
114 {
115 fn_NetSim_Packet_FreePacket(pstruEventDetails->pPacket);
116 return;
117 }
118
119 s->tcb->isRTOTimerRunning = false;
120 bool isPresent = isAnySegmentInQueue(&s->tcb->retransmissionQueue);
121
122 if (isPresent)
123 {
124 NetSim_PACKET* segment = get_earliest_copy_segment_from_queue(&s->tcb->retransmissionQueue);
125
126 print_tcp_log("\nDevice %d, Time %0.2lf: RTO Time expire.",
127 pstruEventDetails->nDeviceId,
128 pstruEventDetails->dEventTime);
129
130 s->tcpMetrics->timesRTOExpired++;
131
132 Backoff_RTO(&TCP_RTO(s->tcb));
133
134 if (isTCPControl(segment))
135 {
136 handle_rto_timer_for_ctrl(s);
137 }
138 else
139 {
140 //Call congestion algorithm
141 s->tcb->rto_expired(s);
142
143 resend_segment(s, segment);
144 }
145
146 fn_NetSim_Packet_FreePacket(segment);
147 }
148 else
149 {
150 //Ignore this event
151 }
152 fn_NetSim_Packet_FreePacket(pstruEventDetails->pPacket);
153}
154
155void restart_rto_timer(PNETSIM_SOCKET s)
156{
157 fnDeleteEvent(s->tcb->RTOEventId);
158 fn_NetSim_Packet_FreePacket(s->tcb->eventPacketptr);
159 s->tcb->eventPacketptr = NULL;
160 s->tcb->isRTOTimerRunning = false;
161
162 bool isPresent = isAnySegmentInQueue(&s->tcb->retransmissionQueue);
163 if (isPresent)
164 {
165 s->tcb->isRTOTimerRunning = true;
166 NetSim_PACKET* segment = get_earliest_copy_segment_from_queue(&s->tcb->retransmissionQueue);
167 NetSim_EVENTDETAILS pevent;
168 memcpy(&pevent, pstruEventDetails, sizeof pevent);
169 pevent.dEventTime += TCP_RTO(s->tcb);
170 pevent.dPacketSize = segment->pstruTransportData->dPacketSize;
171 pevent.nEventType = TIMER_EVENT;
172 pevent.nPacketId = segment->nPacketId;
173 if (segment->pstruAppData)
174 {
175 pevent.nApplicationId = segment->pstruAppData->nApplicationId;
176 pevent.nSegmentId = segment->pstruAppData->nSegmentId;
177 }
178 else
179 pevent.nSegmentId = 0;
180 pevent.nProtocolId = TX_PROTOCOL_TCP;
181 pevent.pPacket = segment;
182 pevent.szOtherDetails = NULL;
183 pevent.nSubEventType = TCP_RTO_TIMEOUT;
184 s->tcb->RTOEventId = fnpAddEvent(&pevent);
185 s->tcb->eventPacketptr = segment;
186 print_tcp_log("Adding RTO Timer at %0.1lf", pevent.dEventTime);
187 }
188}