1 /*
2 SPDX-FileCopyrightText: 2009 Joris Guisson <joris.guisson@gmail.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "remotewindow.h"
8 #include "connection.h"
9 #include "utpprotocol.h"
10 #include <util/functions.h>
11 #include <util/log.h>
12
13 using namespace bt;
14
15 namespace utp
16 {
UnackedPacket(const PacketBuffer & packet,bt::Uint16 seq_nr,bt::TimeStamp send_time)17 UnackedPacket::UnackedPacket(const PacketBuffer &packet, bt::Uint16 seq_nr, bt::TimeStamp send_time)
18 : packet(packet)
19 , seq_nr(seq_nr)
20 , send_time(send_time)
21 , retransmitted(false)
22 {
23 }
24
~UnackedPacket()25 UnackedPacket::~UnackedPacket()
26 {
27 }
28
RemoteWindow()29 RemoteWindow::RemoteWindow()
30 : cur_window(0)
31 , max_window(64 * 1024)
32 , wnd_size(0)
33 , last_ack_nr(0)
34 , last_ack_receive_count(0)
35 {
36 }
37
~RemoteWindow()38 RemoteWindow::~RemoteWindow()
39 {
40 clear();
41 }
42
packetReceived(const utp::Header * hdr,const SelectiveAck * sack,Retransmitter * conn)43 void RemoteWindow::packetReceived(const utp::Header *hdr, const SelectiveAck *sack, Retransmitter *conn)
44 {
45 if (hdr->ack_nr == last_ack_nr) {
46 if (hdr->type == ST_STATE)
47 last_ack_receive_count++;
48 } else {
49 last_ack_nr = hdr->ack_nr;
50 last_ack_receive_count = 1;
51 }
52
53 wnd_size = hdr->wnd_size;
54
55 bt::TimeStamp now = bt::Now();
56 QList<UnackedPacket>::iterator i = unacked_packets.begin();
57 while (i != unacked_packets.end()) {
58 if (SeqNrCmpSE(i->seq_nr, hdr->ack_nr)) {
59 // everything up until the ack_nr in the header is acked
60 conn->updateRTT(hdr, now - i->send_time, i->packet.payloadSize());
61 cur_window -= i->packet.payloadSize();
62 i = unacked_packets.erase(i);
63 } else if (sack) {
64 if (Acked(sack, i->seq_nr - hdr->ack_nr)) {
65 conn->updateRTT(hdr, now - i->send_time, i->packet.payloadSize());
66 cur_window -= i->packet.payloadSize();
67 i = unacked_packets.erase(i);
68 } else
69 ++i;
70 } else
71 break;
72 }
73
74 if (!unacked_packets.isEmpty()) {
75 checkLostPackets(hdr, sack, conn);
76 }
77 }
78
addPacket(const PacketBuffer & packet,bt::Uint16 seq_nr,bt::TimeStamp send_time)79 void RemoteWindow::addPacket(const PacketBuffer &packet, bt::Uint16 seq_nr, bt::TimeStamp send_time)
80 {
81 cur_window += packet.payloadSize();
82 wnd_size -= packet.payloadSize();
83 unacked_packets.append(UnackedPacket(packet, seq_nr, send_time));
84 }
85
checkLostPackets(const utp::Header * hdr,const utp::SelectiveAck * sack,Retransmitter * conn)86 void RemoteWindow::checkLostPackets(const utp::Header *hdr, const utp::SelectiveAck *sack, Retransmitter *conn)
87 {
88 bt::TimeStamp now = bt::Now();
89 bool lost_packets = false;
90
91 QList<UnackedPacket>::iterator itr = unacked_packets.begin();
92 UnackedPacket &first_unacked = *itr;
93 if (last_ack_receive_count >= 3 && first_unacked.seq_nr == hdr->ack_nr + 1) {
94 // packet has been lost
95 if (!first_unacked.retransmitted || now - first_unacked.send_time > conn->currentTimeout()) {
96 try {
97 conn->retransmit(first_unacked.packet, first_unacked.seq_nr);
98 first_unacked.send_time = now;
99 first_unacked.retransmitted = true;
100 } catch (utp::Connection::TransmissionError &) {
101 }
102 lost_packets = true;
103 }
104
105 ++itr;
106 }
107
108 if (sack) {
109 bt::Uint16 lost_index = lost(sack);
110 while (lost_index > 0 && itr != unacked_packets.end()) {
111 bt::Uint16 d = itr->seq_nr - hdr->ack_nr;
112 if (d < lost_index && (!itr->retransmitted || now - itr->send_time > conn->currentTimeout())) {
113 try {
114 conn->retransmit(itr->packet, itr->seq_nr);
115 itr->send_time = now;
116 itr->retransmitted = true;
117 } catch (utp::Connection::TransmissionError &) {
118 }
119 lost_packets = true;
120 }
121 ++itr;
122 }
123 }
124
125 if (lost_packets) {
126 Out(SYS_UTP | LOG_DEBUG) << "UTP: lost packets on connection " << hdr->connection_id << endl;
127 max_window = (bt::Uint32)qRound(0.78 * max_window);
128 }
129 }
130
lost(const SelectiveAck * sack)131 bt::Uint16 RemoteWindow::lost(const SelectiveAck *sack)
132 {
133 // A packet is lost if 3 packets have been acked after it
134 bt::Uint32 acked = 0;
135 bt::Int16 i = sack->length * 8 - 1;
136 while (i >= 0 && acked < 3) {
137 if (Acked(sack, i)) {
138 acked++;
139 if (acked == 3)
140 return i;
141 }
142
143 i--;
144 }
145
146 return 0;
147 }
148
timeout(Retransmitter * conn)149 void RemoteWindow::timeout(Retransmitter *conn)
150 {
151 try {
152 max_window = MIN_PACKET_SIZE;
153 bt::TimeStamp now = bt::Now();
154 // When a timeout occurs retransmit packets which are lost longer then the current timeout
155 for (UnackedPacket &pkt : unacked_packets) {
156 if (!pkt.retransmitted || now - pkt.send_time > conn->currentTimeout()) {
157 conn->retransmit(pkt.packet, pkt.seq_nr);
158 pkt.send_time = bt::Now();
159 pkt.retransmitted = true;
160 }
161 }
162 } catch (utp::Connection::TransmissionError &) {
163 }
164 }
165
updateWindowSize(double scaled_gain)166 void RemoteWindow::updateWindowSize(double scaled_gain)
167 {
168 int d = (int)qRound(scaled_gain);
169 if (max_window + d < MIN_PACKET_SIZE)
170 max_window = MIN_PACKET_SIZE;
171 else
172 max_window += d;
173
174 // if (scaled_gain > 1000)
175 // Out(SYS_UTP|LOG_DEBUG) << "RemoteWindow::updateWindowSize " << scaled_gain << " " << max_window << endl;
176 }
177
clear()178 void RemoteWindow::clear()
179 {
180 unacked_packets.clear();
181 }
182 }
183