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 #ifndef quicly_maxsender_h
23 #define quicly_maxsender_h
24
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28
29 #include <assert.h>
30 #include <stddef.h>
31 #include <stdint.h>
32 #include "quicly/constants.h"
33
34 typedef struct st_quicly_maxsender_t {
35 /**
36 * maximum value being announced (never decreases)
37 */
38 int64_t max_committed;
39 /**
40 * maximum value being acked by remote peer
41 */
42 int64_t max_acked;
43 /**
44 * number of maximums inflight
45 */
46 size_t num_inflight;
47 /**
48 *
49 */
50 unsigned force_send : 1;
51 } quicly_maxsender_t;
52
53 typedef struct st_quicly_maxsender_sent_t {
54 uint64_t inflight : 1;
55 uint64_t value : 63;
56 } quicly_maxsender_sent_t;
57
58 static void quicly_maxsender_init(quicly_maxsender_t *m, int64_t initial_value);
59 static void quicly_maxsender_dispose(quicly_maxsender_t *m);
60 static void quicly_maxsender_request_transmit(quicly_maxsender_t *m);
61 static int quicly_maxsender_should_send_max(quicly_maxsender_t *m, int64_t buffered_from, uint32_t window_size,
62 uint32_t update_ratio);
63 static int quicly_maxsender_should_send_blocked(quicly_maxsender_t *m, int64_t local_max);
64 static void quicly_maxsender_record(quicly_maxsender_t *m, int64_t value, quicly_maxsender_sent_t *sent);
65 static void quicly_maxsender_acked(quicly_maxsender_t *m, quicly_maxsender_sent_t *sent);
66 static void quicly_maxsender_lost(quicly_maxsender_t *m, quicly_maxsender_sent_t *sent);
67
68 /* inline definitions */
69
quicly_maxsender_init(quicly_maxsender_t * m,int64_t initial_value)70 inline void quicly_maxsender_init(quicly_maxsender_t *m, int64_t initial_value)
71 {
72 m->max_committed = initial_value;
73 m->max_acked = initial_value;
74 m->num_inflight = 0;
75 m->force_send = 0;
76 }
77
quicly_maxsender_dispose(quicly_maxsender_t * m)78 inline void quicly_maxsender_dispose(quicly_maxsender_t *m)
79 {
80 }
81
quicly_maxsender_request_transmit(quicly_maxsender_t * m)82 inline void quicly_maxsender_request_transmit(quicly_maxsender_t *m)
83 {
84 m->force_send = 1;
85 }
86
quicly_maxsender_should_send_max(quicly_maxsender_t * m,int64_t buffered_from,uint32_t window_size,uint32_t update_ratio)87 inline int quicly_maxsender_should_send_max(quicly_maxsender_t *m, int64_t buffered_from, uint32_t window_size,
88 uint32_t update_ratio)
89 {
90 if (m->force_send)
91 return 1;
92
93 /* ratio is permil (1/1024) */
94 int64_t threshold = buffered_from + ((int64_t)window_size * update_ratio) / 1024;
95 return (m->num_inflight != 0 ? m->max_committed : m->max_acked) <= threshold;
96 }
97
quicly_maxsender_should_send_blocked(quicly_maxsender_t * m,int64_t local_max)98 inline int quicly_maxsender_should_send_blocked(quicly_maxsender_t *m, int64_t local_max)
99 {
100 return m->max_committed < local_max;
101 }
102
quicly_maxsender_record(quicly_maxsender_t * m,int64_t value,quicly_maxsender_sent_t * sent)103 inline void quicly_maxsender_record(quicly_maxsender_t *m, int64_t value, quicly_maxsender_sent_t *sent)
104 {
105 assert(value >= m->max_committed);
106 m->max_committed = value;
107 ++m->num_inflight;
108 m->force_send = 0;
109 sent->inflight = 1;
110 sent->value = value;
111 }
112
quicly_maxsender_acked(quicly_maxsender_t * m,quicly_maxsender_sent_t * sent)113 inline void quicly_maxsender_acked(quicly_maxsender_t *m, quicly_maxsender_sent_t *sent)
114 {
115 if (m->max_acked < (int64_t)sent->value)
116 m->max_acked = sent->value;
117 /* num_inflight should not be adjusted in case of a late ACK */
118 if (sent->inflight) {
119 assert(m->num_inflight != 0);
120 --m->num_inflight;
121 sent->inflight = 0;
122 }
123 }
124
quicly_maxsender_lost(quicly_maxsender_t * m,quicly_maxsender_sent_t * sent)125 inline void quicly_maxsender_lost(quicly_maxsender_t *m, quicly_maxsender_sent_t *sent)
126 {
127 /* the function must be called at most once (when LOST event occurs, but not EXPIRED), hence assert and always decrement */
128 assert(m->num_inflight != 0);
129 --m->num_inflight;
130 sent->inflight = 0;
131 }
132
133 #ifdef __cplusplus
134 }
135 #endif
136
137 #endif
138