1 /*
2  * ngtcp2
3  *
4  * Copyright (c) 2017 ngtcp2 contributors
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include "ngtcp2_acktr.h"
26 
27 #include <assert.h>
28 
ngtcp2_acktr_entry_new(ngtcp2_acktr_entry ** ent,int64_t pkt_num,ngtcp2_tstamp tstamp,const ngtcp2_mem * mem)29 int ngtcp2_acktr_entry_new(ngtcp2_acktr_entry **ent, int64_t pkt_num,
30                            ngtcp2_tstamp tstamp, const ngtcp2_mem *mem) {
31   *ent = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_acktr_entry));
32   if (*ent == NULL) {
33     return NGTCP2_ERR_NOMEM;
34   }
35 
36   (*ent)->pkt_num = pkt_num;
37   (*ent)->len = 1;
38   (*ent)->tstamp = tstamp;
39 
40   return 0;
41 }
42 
ngtcp2_acktr_entry_del(ngtcp2_acktr_entry * ent,const ngtcp2_mem * mem)43 void ngtcp2_acktr_entry_del(ngtcp2_acktr_entry *ent, const ngtcp2_mem *mem) {
44   ngtcp2_mem_free(mem, ent);
45 }
46 
greater(const ngtcp2_ksl_key * lhs,const ngtcp2_ksl_key * rhs)47 static int greater(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) {
48   return *(int64_t *)lhs > *(int64_t *)rhs;
49 }
50 
ngtcp2_acktr_init(ngtcp2_acktr * acktr,ngtcp2_log * log,const ngtcp2_mem * mem)51 int ngtcp2_acktr_init(ngtcp2_acktr *acktr, ngtcp2_log *log,
52                       const ngtcp2_mem *mem) {
53   int rv;
54 
55   rv = ngtcp2_ringbuf_init(&acktr->acks, 128, sizeof(ngtcp2_acktr_ack_entry),
56                            mem);
57   if (rv != 0) {
58     return rv;
59   }
60 
61   rv = ngtcp2_ksl_init(&acktr->ents, greater, sizeof(int64_t), mem);
62   if (rv != 0) {
63     ngtcp2_ringbuf_free(&acktr->acks);
64     return rv;
65   }
66 
67   acktr->log = log;
68   acktr->mem = mem;
69   acktr->flags = NGTCP2_ACKTR_FLAG_NONE;
70   acktr->first_unacked_ts = UINT64_MAX;
71   acktr->rx_npkt = 0;
72 
73   return 0;
74 }
75 
ngtcp2_acktr_free(ngtcp2_acktr * acktr)76 void ngtcp2_acktr_free(ngtcp2_acktr *acktr) {
77   ngtcp2_ksl_it it;
78 
79   if (acktr == NULL) {
80     return;
81   }
82 
83   for (it = ngtcp2_ksl_begin(&acktr->ents); !ngtcp2_ksl_it_end(&it);
84        ngtcp2_ksl_it_next(&it)) {
85     ngtcp2_acktr_entry_del(ngtcp2_ksl_it_get(&it), acktr->mem);
86   }
87   ngtcp2_ksl_free(&acktr->ents);
88 
89   ngtcp2_ringbuf_free(&acktr->acks);
90 }
91 
ngtcp2_acktr_add(ngtcp2_acktr * acktr,int64_t pkt_num,int active_ack,ngtcp2_tstamp ts)92 int ngtcp2_acktr_add(ngtcp2_acktr *acktr, int64_t pkt_num, int active_ack,
93                      ngtcp2_tstamp ts) {
94   ngtcp2_ksl_it it, prev_it;
95   ngtcp2_acktr_entry *ent, *prev_ent, *delent;
96   int rv;
97   int added = 0;
98 
99   if (ngtcp2_ksl_len(&acktr->ents)) {
100     it = ngtcp2_ksl_lower_bound(&acktr->ents, &pkt_num);
101     if (ngtcp2_ksl_it_end(&it)) {
102       ngtcp2_ksl_it_prev(&it);
103       ent = ngtcp2_ksl_it_get(&it);
104 
105       assert(ent->pkt_num >= pkt_num + (int64_t)ent->len);
106 
107       if (ent->pkt_num == pkt_num + (int64_t)ent->len) {
108         ++ent->len;
109         added = 1;
110       }
111     } else {
112       ent = ngtcp2_ksl_it_get(&it);
113 
114       assert(ent->pkt_num != pkt_num);
115 
116       if (ngtcp2_ksl_it_begin(&it)) {
117         if (ent->pkt_num + 1 == pkt_num) {
118           ngtcp2_ksl_update_key(&acktr->ents, &ent->pkt_num, &pkt_num);
119           ent->pkt_num = pkt_num;
120           ent->tstamp = ts;
121           ++ent->len;
122           added = 1;
123         }
124       } else {
125         prev_it = it;
126         ngtcp2_ksl_it_prev(&prev_it);
127         prev_ent = ngtcp2_ksl_it_get(&prev_it);
128 
129         assert(prev_ent->pkt_num >= pkt_num + (int64_t)prev_ent->len);
130 
131         if (ent->pkt_num + 1 == pkt_num) {
132           if (prev_ent->pkt_num == pkt_num + (int64_t)prev_ent->len) {
133             prev_ent->len += ent->len + 1;
134             ngtcp2_ksl_remove_hint(&acktr->ents, NULL, &it, &ent->pkt_num);
135             ngtcp2_acktr_entry_del(ent, acktr->mem);
136             added = 1;
137           } else {
138             ngtcp2_ksl_update_key(&acktr->ents, &ent->pkt_num, &pkt_num);
139             ent->pkt_num = pkt_num;
140             ent->tstamp = ts;
141             ++ent->len;
142             added = 1;
143           }
144         } else if (prev_ent->pkt_num == pkt_num + (int64_t)prev_ent->len) {
145           ++prev_ent->len;
146           added = 1;
147         }
148       }
149     }
150   }
151 
152   if (!added) {
153     rv = ngtcp2_acktr_entry_new(&ent, pkt_num, ts, acktr->mem);
154     if (rv != 0) {
155       return rv;
156     }
157     rv = ngtcp2_ksl_insert(&acktr->ents, NULL, &ent->pkt_num, ent);
158     if (rv != 0) {
159       ngtcp2_acktr_entry_del(ent, acktr->mem);
160       return rv;
161     }
162   }
163 
164   if (active_ack) {
165     acktr->flags |= NGTCP2_ACKTR_FLAG_ACTIVE_ACK;
166     if (acktr->first_unacked_ts == UINT64_MAX) {
167       acktr->first_unacked_ts = ts;
168     }
169   }
170 
171   if (ngtcp2_ksl_len(&acktr->ents) > NGTCP2_ACKTR_MAX_ENT) {
172     it = ngtcp2_ksl_end(&acktr->ents);
173     ngtcp2_ksl_it_prev(&it);
174     delent = ngtcp2_ksl_it_get(&it);
175     ngtcp2_ksl_remove_hint(&acktr->ents, NULL, &it, &delent->pkt_num);
176     ngtcp2_acktr_entry_del(delent, acktr->mem);
177   }
178 
179   return 0;
180 }
181 
ngtcp2_acktr_forget(ngtcp2_acktr * acktr,ngtcp2_acktr_entry * ent)182 void ngtcp2_acktr_forget(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent) {
183   ngtcp2_ksl_it it;
184 
185   it = ngtcp2_ksl_lower_bound(&acktr->ents, &ent->pkt_num);
186   assert(*(int64_t *)ngtcp2_ksl_it_key(&it) == (int64_t)ent->pkt_num);
187 
188   for (; !ngtcp2_ksl_it_end(&it);) {
189     ent = ngtcp2_ksl_it_get(&it);
190     ngtcp2_ksl_remove_hint(&acktr->ents, &it, &it, &ent->pkt_num);
191     ngtcp2_acktr_entry_del(ent, acktr->mem);
192   }
193 }
194 
ngtcp2_acktr_get(ngtcp2_acktr * acktr)195 ngtcp2_ksl_it ngtcp2_acktr_get(ngtcp2_acktr *acktr) {
196   return ngtcp2_ksl_begin(&acktr->ents);
197 }
198 
ngtcp2_acktr_empty(ngtcp2_acktr * acktr)199 int ngtcp2_acktr_empty(ngtcp2_acktr *acktr) {
200   ngtcp2_ksl_it it = ngtcp2_ksl_begin(&acktr->ents);
201   return ngtcp2_ksl_it_end(&it);
202 }
203 
ngtcp2_acktr_add_ack(ngtcp2_acktr * acktr,int64_t pkt_num,int64_t largest_ack)204 ngtcp2_acktr_ack_entry *ngtcp2_acktr_add_ack(ngtcp2_acktr *acktr,
205                                              int64_t pkt_num,
206                                              int64_t largest_ack) {
207   ngtcp2_acktr_ack_entry *ent = ngtcp2_ringbuf_push_front(&acktr->acks);
208 
209   ent->largest_ack = largest_ack;
210   ent->pkt_num = pkt_num;
211 
212   return ent;
213 }
214 
215 /*
216  * acktr_remove removes |ent| from |acktr|.  |it| must point to the
217  * node whose key identifies |ent|.  The iterator which points to the
218  * entry next to |ent| is assigned to |it|.
219  */
acktr_remove(ngtcp2_acktr * acktr,ngtcp2_ksl_it * it,ngtcp2_acktr_entry * ent)220 static void acktr_remove(ngtcp2_acktr *acktr, ngtcp2_ksl_it *it,
221                          ngtcp2_acktr_entry *ent) {
222   ngtcp2_ksl_remove_hint(&acktr->ents, it, it, &ent->pkt_num);
223   ngtcp2_acktr_entry_del(ent, acktr->mem);
224 }
225 
acktr_on_ack(ngtcp2_acktr * acktr,ngtcp2_ringbuf * rb,size_t ack_ent_offset)226 static void acktr_on_ack(ngtcp2_acktr *acktr, ngtcp2_ringbuf *rb,
227                          size_t ack_ent_offset) {
228   ngtcp2_acktr_ack_entry *ack_ent;
229   ngtcp2_acktr_entry *ent;
230   ngtcp2_ksl_it it;
231 
232   assert(ngtcp2_ringbuf_len(rb));
233 
234   ack_ent = ngtcp2_ringbuf_get(rb, ack_ent_offset);
235 
236   /* Assume that ngtcp2_pkt_validate_ack(fr) returns 0 */
237   it = ngtcp2_ksl_lower_bound(&acktr->ents, &ack_ent->largest_ack);
238   for (; !ngtcp2_ksl_it_end(&it);) {
239     ent = ngtcp2_ksl_it_get(&it);
240     acktr_remove(acktr, &it, ent);
241   }
242 
243   if (ngtcp2_ksl_len(&acktr->ents)) {
244     assert(ngtcp2_ksl_it_end(&it));
245 
246     ngtcp2_ksl_it_prev(&it);
247     ent = ngtcp2_ksl_it_get(&it);
248     if (ent->pkt_num > ack_ent->largest_ack &&
249         ack_ent->largest_ack >= ent->pkt_num - (int64_t)(ent->len - 1)) {
250       ent->len = (size_t)(ent->pkt_num - ack_ent->largest_ack);
251     }
252   }
253 
254   ngtcp2_ringbuf_resize(rb, ack_ent_offset);
255 }
256 
ngtcp2_acktr_recv_ack(ngtcp2_acktr * acktr,const ngtcp2_ack * fr)257 void ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr) {
258   ngtcp2_acktr_ack_entry *ent;
259   int64_t largest_ack = fr->largest_ack, min_ack;
260   size_t i, j;
261   ngtcp2_ringbuf *rb = &acktr->acks;
262   size_t nacks = ngtcp2_ringbuf_len(rb);
263 
264   /* Assume that ngtcp2_pkt_validate_ack(fr) returns 0 */
265   for (j = 0; j < nacks; ++j) {
266     ent = ngtcp2_ringbuf_get(rb, j);
267     if (largest_ack >= ent->pkt_num) {
268       break;
269     }
270   }
271   if (j == nacks) {
272     return;
273   }
274 
275   min_ack = largest_ack - (int64_t)fr->first_ack_blklen;
276 
277   if (min_ack <= ent->pkt_num && ent->pkt_num <= largest_ack) {
278     acktr_on_ack(acktr, rb, j);
279     return;
280   }
281 
282   for (i = 0; i < fr->num_blks && j < nacks; ++i) {
283     largest_ack = min_ack - (int64_t)fr->blks[i].gap - 2;
284     min_ack = largest_ack - (int64_t)fr->blks[i].blklen;
285 
286     for (;;) {
287       if (ent->pkt_num > largest_ack) {
288         ++j;
289         if (j == nacks) {
290           return;
291         }
292         ent = ngtcp2_ringbuf_get(rb, j);
293         continue;
294       }
295       if (ent->pkt_num < min_ack) {
296         break;
297       }
298       acktr_on_ack(acktr, rb, j);
299       return;
300     }
301   }
302 }
303 
ngtcp2_acktr_commit_ack(ngtcp2_acktr * acktr)304 void ngtcp2_acktr_commit_ack(ngtcp2_acktr *acktr) {
305   acktr->flags &= (uint16_t) ~(NGTCP2_ACKTR_FLAG_ACTIVE_ACK |
306                                NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK |
307                                NGTCP2_ACKTR_FLAG_CANCEL_TIMER);
308   acktr->first_unacked_ts = UINT64_MAX;
309   acktr->rx_npkt = 0;
310 }
311 
ngtcp2_acktr_require_active_ack(ngtcp2_acktr * acktr,ngtcp2_duration max_ack_delay,ngtcp2_tstamp ts)312 int ngtcp2_acktr_require_active_ack(ngtcp2_acktr *acktr,
313                                     ngtcp2_duration max_ack_delay,
314                                     ngtcp2_tstamp ts) {
315   return acktr->first_unacked_ts != UINT64_MAX &&
316          acktr->first_unacked_ts + max_ack_delay <= ts;
317 }
318 
ngtcp2_acktr_immediate_ack(ngtcp2_acktr * acktr)319 void ngtcp2_acktr_immediate_ack(ngtcp2_acktr *acktr) {
320   acktr->flags |= NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK;
321 }
322