/src/h2o/deps/quicly/lib/sentmap.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2017 Fastly, Kazuho Oku |
3 | | * |
4 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | | * of this software and associated documentation files (the "Software"), to |
6 | | * deal in the Software without restriction, including without limitation the |
7 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
8 | | * sell copies of the Software, and to permit persons to whom the Software is |
9 | | * furnished to do so, subject to the following conditions: |
10 | | * |
11 | | * The above copyright notice and this permission notice shall be included in |
12 | | * all copies or substantial portions of the Software. |
13 | | * |
14 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
19 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
20 | | * IN THE SOFTWARE. |
21 | | */ |
22 | | #include <assert.h> |
23 | | #include <stdlib.h> |
24 | | #include "picotls.h" |
25 | | #include "quicly/sentmap.h" |
26 | | |
27 | | const quicly_sent_t quicly_sentmap__end_iter = {quicly_sentmap__type_packet, {{UINT64_MAX, INT64_MAX}}}; |
28 | | |
29 | | static void next_entry(quicly_sentmap_iter_t *iter) |
30 | 0 | { |
31 | 0 | if (--iter->count != 0) { |
32 | 0 | ++iter->p; |
33 | 0 | } else if (*(iter->ref = &(*iter->ref)->next) == NULL) { |
34 | 0 | iter->p = (quicly_sent_t *)&quicly_sentmap__end_iter; |
35 | 0 | iter->count = 0; |
36 | 0 | return; |
37 | 0 | } else { |
38 | 0 | assert((*iter->ref)->num_entries != 0); |
39 | 0 | iter->count = (*iter->ref)->num_entries; |
40 | 0 | iter->p = (*iter->ref)->entries; |
41 | 0 | } |
42 | 0 | while (iter->p->acked == NULL) |
43 | 0 | ++iter->p; |
44 | 0 | } |
45 | | |
46 | | static struct st_quicly_sent_block_t **free_block(quicly_sentmap_t *map, struct st_quicly_sent_block_t **ref) |
47 | 0 | { |
48 | 0 | static const struct st_quicly_sent_block_t dummy = {NULL}; |
49 | 0 | static const struct st_quicly_sent_block_t *const dummy_ref = &dummy; |
50 | 0 | struct st_quicly_sent_block_t *block = *ref; |
51 | |
|
52 | 0 | if (block->next != NULL) { |
53 | 0 | *ref = block->next; |
54 | 0 | assert((*ref)->num_entries != 0); |
55 | 0 | } else { |
56 | 0 | assert(block == map->tail); |
57 | 0 | if (ref == &map->head) { |
58 | 0 | map->head = NULL; |
59 | 0 | map->tail = NULL; |
60 | 0 | } else { |
61 | 0 | map->tail = (void *)((char *)ref - offsetof(struct st_quicly_sent_block_t, next)); |
62 | 0 | map->tail->next = NULL; |
63 | 0 | } |
64 | 0 | ref = (struct st_quicly_sent_block_t **)&dummy_ref; |
65 | 0 | } |
66 | | |
67 | 0 | free(block); |
68 | 0 | return ref; |
69 | 0 | } |
70 | | |
71 | | static void discard_entry(quicly_sentmap_t *map, quicly_sentmap_iter_t *iter) |
72 | 0 | { |
73 | 0 | assert(iter->p->acked != NULL); |
74 | 0 | iter->p->acked = NULL; |
75 | |
|
76 | 0 | struct st_quicly_sent_block_t *block = *iter->ref; |
77 | 0 | if (--block->num_entries == 0) { |
78 | 0 | iter->ref = free_block(map, iter->ref); |
79 | 0 | block = *iter->ref; |
80 | 0 | iter->p = block->entries - 1; |
81 | 0 | iter->count = block->num_entries + 1; |
82 | 0 | } |
83 | 0 | } |
84 | | |
85 | | void quicly_sentmap_dispose(quicly_sentmap_t *map) |
86 | 0 | { |
87 | 0 | struct st_quicly_sent_block_t *block; |
88 | |
|
89 | 0 | while ((block = map->head) != NULL) { |
90 | 0 | map->head = block->next; |
91 | 0 | free(block); |
92 | 0 | } |
93 | 0 | } |
94 | | |
95 | | quicly_error_t quicly_sentmap_prepare(quicly_sentmap_t *map, uint64_t packet_number, int64_t now, uint8_t ack_epoch) |
96 | 0 | { |
97 | 0 | assert(map->_pending_packet == NULL); |
98 | | |
99 | 0 | if ((map->_pending_packet = quicly_sentmap_allocate(map, quicly_sentmap__type_packet)) == NULL) |
100 | 0 | return PTLS_ERROR_NO_MEMORY; |
101 | 0 | map->_pending_packet->data.packet = (quicly_sent_packet_t){packet_number, now, ack_epoch}; |
102 | 0 | return 0; |
103 | 0 | } |
104 | | |
105 | | struct st_quicly_sent_block_t *quicly_sentmap__new_block(quicly_sentmap_t *map) |
106 | 0 | { |
107 | 0 | struct st_quicly_sent_block_t *block; |
108 | |
|
109 | 0 | if ((block = malloc(sizeof(*block))) == NULL) |
110 | 0 | return NULL; |
111 | | |
112 | 0 | block->next = NULL; |
113 | 0 | block->num_entries = 0; |
114 | 0 | block->next_insert_at = 0; |
115 | 0 | if (map->tail != NULL) { |
116 | 0 | map->tail->next = block; |
117 | 0 | map->tail = block; |
118 | 0 | } else { |
119 | 0 | map->head = map->tail = block; |
120 | 0 | } |
121 | |
|
122 | 0 | return block; |
123 | 0 | } |
124 | | |
125 | | void quicly_sentmap_skip(quicly_sentmap_iter_t *iter) |
126 | 0 | { |
127 | 0 | do { |
128 | 0 | next_entry(iter); |
129 | 0 | } while (iter->p->acked != quicly_sentmap__type_packet); |
130 | 0 | } |
131 | | |
132 | | quicly_error_t quicly_sentmap_update(quicly_sentmap_t *map, quicly_sentmap_iter_t *iter, quicly_sentmap_event_t event) |
133 | 0 | { |
134 | 0 | quicly_sent_packet_t packet; |
135 | 0 | quicly_error_t ret = 0; |
136 | |
|
137 | 0 | assert(iter->p != &quicly_sentmap__end_iter); |
138 | 0 | assert(iter->p->acked == quicly_sentmap__type_packet); |
139 | | |
140 | | /* copy packet info */ |
141 | 0 | packet = iter->p->data.packet; |
142 | | |
143 | | /* update CC state unless the event is PTO */ |
144 | 0 | if (packet.cc_bytes_in_flight != 0 && event != QUICLY_SENTMAP_EVENT_PTO) { |
145 | 0 | assert(map->bytes_in_flight >= packet.cc_bytes_in_flight); |
146 | 0 | map->bytes_in_flight -= packet.cc_bytes_in_flight; |
147 | 0 | iter->p->data.packet.cc_bytes_in_flight = 0; |
148 | 0 | } |
149 | 0 | iter->p->data.packet.frames_in_flight = 0; |
150 | |
|
151 | 0 | int should_notify = event == QUICLY_SENTMAP_EVENT_ACKED || packet.frames_in_flight, |
152 | 0 | should_discard = event == QUICLY_SENTMAP_EVENT_ACKED || event == QUICLY_SENTMAP_EVENT_EXPIRED; |
153 | | |
154 | | /* Advance to next packet, while if necessary, doing either or both of the following: |
155 | | * * discard entries (if should_discard is set) |
156 | | * * invoke the frame-level callbacks (if should_notify is set) */ |
157 | 0 | if (should_discard) { |
158 | 0 | discard_entry(map, iter); |
159 | 0 | --map->num_packets; |
160 | 0 | } |
161 | 0 | for (next_entry(iter); iter->p->acked != quicly_sentmap__type_packet; next_entry(iter)) { |
162 | 0 | if (should_notify && (ret = iter->p->acked(map, &packet, event == QUICLY_SENTMAP_EVENT_ACKED, iter->p)) != 0) |
163 | 0 | goto Exit; |
164 | 0 | if (should_discard) |
165 | 0 | discard_entry(map, iter); |
166 | 0 | } |
167 | | |
168 | 0 | Exit: |
169 | 0 | return ret; |
170 | 0 | } |
171 | | |
172 | | quicly_error_t quicly_sentmap__type_packet(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, |
173 | | quicly_sent_t *sent) |
174 | 0 | { |
175 | 0 | assert(!"quicly_sentmap__type_packet cannot be called"); |
176 | 0 | return QUICLY_TRANSPORT_ERROR_INTERNAL; |
177 | 0 | } |