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