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