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 "quicly/constants.h"
23 #include "quicly/recvstate.h"
24 
quicly_recvstate_init(quicly_recvstate_t * state)25 void quicly_recvstate_init(quicly_recvstate_t *state)
26 {
27     quicly_ranges_init_with_range(&state->received, 0, 0);
28     state->data_off = 0;
29     state->eos = UINT64_MAX;
30 }
31 
quicly_recvstate_init_closed(quicly_recvstate_t * state)32 void quicly_recvstate_init_closed(quicly_recvstate_t *state)
33 {
34     quicly_ranges_init(&state->received);
35     state->data_off = 0;
36     state->eos = 0;
37 }
38 
quicly_recvstate_dispose(quicly_recvstate_t * state)39 void quicly_recvstate_dispose(quicly_recvstate_t *state)
40 {
41     quicly_ranges_clear(&state->received);
42 }
43 
quicly_recvstate_update(quicly_recvstate_t * state,uint64_t off,size_t * len,int is_fin,size_t max_ranges)44 int quicly_recvstate_update(quicly_recvstate_t *state, uint64_t off, size_t *len, int is_fin, size_t max_ranges)
45 {
46     int ret;
47 
48     assert(!quicly_recvstate_transfer_complete(state));
49 
50     /* eos handling */
51     if (state->eos == UINT64_MAX) {
52         if (is_fin) {
53             state->eos = off + *len;
54             if (state->eos < state->received.ranges[state->received.num_ranges - 1].end)
55                 return QUICLY_TRANSPORT_ERROR_FINAL_SIZE;
56         }
57     } else {
58         if (off + *len > state->eos)
59             return QUICLY_TRANSPORT_ERROR_FINAL_SIZE;
60     }
61 
62     /* no state change; entire data has already been received */
63     if (off + *len <= state->data_off) {
64         *len = 0;
65         if (state->received.ranges[0].end == state->eos)
66             goto Complete;
67         return 0;
68     }
69 
70     /* adjust if partially received */
71     if (off < state->data_off) {
72         size_t delta = state->data_off - off;
73         off += delta;
74         *len -= delta;
75     }
76 
77     /* update received range */
78     if (*len != 0) {
79         if ((ret = quicly_ranges_add(&state->received, off, off + *len)) != 0)
80             return ret;
81         if (state->received.num_ranges > max_ranges)
82             return QUICLY_ERROR_STATE_EXHAUSTION;
83     }
84     if (state->received.num_ranges == 1 && state->received.ranges[0].start == 0 && state->received.ranges[0].end == state->eos)
85         goto Complete;
86 
87     return 0;
88 
89 Complete:
90     quicly_ranges_clear(&state->received);
91     return 0;
92 }
93 
quicly_recvstate_reset(quicly_recvstate_t * state,uint64_t eos_at,uint64_t * bytes_missing)94 int quicly_recvstate_reset(quicly_recvstate_t *state, uint64_t eos_at, uint64_t *bytes_missing)
95 {
96     assert(!quicly_recvstate_transfer_complete(state));
97 
98     /* validate */
99     if (state->eos != UINT64_MAX && state->eos != eos_at)
100         return QUICLY_TRANSPORT_ERROR_FINAL_SIZE;
101     if (eos_at < state->received.ranges[state->received.num_ranges - 1].end)
102         return QUICLY_TRANSPORT_ERROR_FINAL_SIZE;
103 
104     /* calculate bytes missing */
105     *bytes_missing = eos_at - state->received.ranges[state->received.num_ranges - 1].end;
106 
107     /* clear the received range */
108     quicly_ranges_clear(&state->received);
109 
110     return 0;
111 }
112