lsquic_hcsi_reader.c revision a74702c6
1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
2#include <assert.h>
3#include <inttypes.h>
4#include <stddef.h>
5#include <stdint.h>
6#include <string.h>
7#include <sys/queue.h>
8
9#include "lsquic.h"
10#include "lsquic_int_types.h"
11#include "lsquic_varint.h"
12#include "lsquic_hq.h"
13#include "lsquic_hash.h"
14#include "lsquic_conn.h"
15#include "lsquic_hcsi_reader.h"
16
17#define LSQUIC_LOGGER_MODULE LSQLM_HCSI_READER
18#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(reader->hr_conn)
19#include "lsquic_logger.h"
20
21#define MIN(a, b) ((a) < (b) ? (a) : (b))
22
23
24void
25lsquic_hcsi_reader_init (struct hcsi_reader *reader,
26        struct lsquic_conn *conn, const struct hcsi_callbacks *callbacks,
27        void *ctx)
28{
29    memset(reader, 0, sizeof(*reader));
30    reader->hr_state = HR_READ_FRAME_BEGIN;
31    reader->hr_conn = conn;
32    reader->hr_cb = callbacks;
33    reader->hr_ctx = ctx;
34    LSQ_DEBUG("initialized");
35}
36
37
38int
39lsquic_hcsi_reader_feed (struct hcsi_reader *reader, const void *buf,
40                                                                size_t bufsz)
41{
42    const unsigned char *p = buf;
43    const unsigned char *const end = p + bufsz;
44
45    const unsigned char *orig_p;
46    uint64_t len;
47    int s;
48
49  continue_reading:
50    while (p < end)
51    {
52        switch (reader->hr_state)
53        {
54        case HR_READ_FRAME_BEGIN:
55            reader->hr_u.vint2_state.vr2s_state = 0;
56            reader->hr_state = HR_READ_FRAME_CONTINUE;
57            /* fall-through */
58        case HR_READ_FRAME_CONTINUE:
59            s = lsquic_varint_read_two(&p, end, &reader->hr_u.vint2_state);
60            if (s < 0)
61                break;
62            reader->hr_frame_type = reader->hr_u.vint2_state.vr2s_one;
63            reader->hr_frame_length = reader->hr_u.vint2_state.vr2s_two;
64
65            if (!(reader->hr_flag & HR_FLAG_RCVD_SETTING)
66                && reader->hr_frame_type != HQFT_SETTINGS)
67            {
68                reader->hr_cb->on_frame_error(reader->hr_ctx,
69                            HEC_MISSING_SETTINGS, reader->hr_frame_type);
70                return -1;
71            }
72
73            switch (reader->hr_frame_type)
74            {
75            case HQFT_SETTINGS:
76                reader->hr_flag |= HR_FLAG_RCVD_SETTING;
77                if (reader->hr_frame_length)
78                {
79                    reader->hr_state = HR_READ_SETTING_BEGIN;
80                    reader->hr_nread = 0;
81                }
82                else
83                {
84                    reader->hr_cb->on_settings_frame(reader->hr_ctx);
85                    reader->hr_state = HR_READ_FRAME_BEGIN;
86                }
87                break;
88            case HQFT_GOAWAY:
89                reader->hr_state = HR_READ_VARINT;
90                break;
91            case HQFT_CANCEL_PUSH:
92                reader->hr_state = HR_READ_VARINT;
93                break;
94            case HQFT_MAX_PUSH_ID:
95                reader->hr_state = HR_READ_VARINT;
96                break;
97            case HQFT_PRIORITY_UPDATE_PUSH:
98            case HQFT_PRIORITY_UPDATE_STREAM:
99                reader->hr_state = HR_READ_VARINT;
100                break;
101            case HQFT_DATA:
102            case HQFT_HEADERS:
103            case HQFT_PUSH_PROMISE:
104                reader->hr_cb->on_frame_error(reader->hr_ctx,
105                    HEC_FRAME_UNEXPECTED, reader->hr_frame_type);
106                return -1;
107            default:
108            {
109            /* From [draft-ietf-quic-http-31] Section 7.2.8:
110             " Frame types of the format "0x1f * N + 0x21" for non-negative
111             " integer values of N are reserved to exercise the requirement
112             " that unknown types be ignored
113             */
114                enum lsq_log_level L;
115                if (!(reader->hr_frame_type >= 0x21 &&
116                        (reader->hr_frame_type - 0x21) % 0x1F == 0))
117                    /* Non-grease: log with higher level: */
118                    L = LSQ_LOG_INFO;
119                else
120                    L = LSQ_LOG_DEBUG;
121                LSQ_LOG(L, "unknown frame type 0x%"PRIX64": will skip "
122                    "%"PRIu64" bytes", reader->hr_frame_type,
123                    reader->hr_frame_length);
124                reader->hr_state = HR_SKIPPING;
125                break;
126            }
127            }
128            break;
129        case HR_READ_VARINT:
130            reader->hr_u.vint_state.pos = 0;
131            reader->hr_state = HR_READ_VARINT_CONTINUE;
132            reader->hr_nread = 0;
133            /* fall-through */
134        case HR_READ_VARINT_CONTINUE:
135            orig_p = p;
136            s = lsquic_varint_read_nb(&p, end, &reader->hr_u.vint_state);
137            reader->hr_nread += p - orig_p;
138            if (0 == s)
139            {
140                switch (reader->hr_frame_type)
141                {
142                case HQFT_GOAWAY:
143                case HQFT_CANCEL_PUSH:
144                case HQFT_MAX_PUSH_ID:
145                    if (reader->hr_nread != reader->hr_frame_length)
146                    {
147                        reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1,
148                            HEC_FRAME_ERROR,
149                            "Frame length does not match actual payload length");
150                        reader->hr_state = HR_ERROR;
151                        return -1;
152                    }
153                    break;
154                }
155                switch (reader->hr_frame_type)
156                {
157                case HQFT_GOAWAY:
158                    reader->hr_cb->on_goaway(reader->hr_ctx,
159                                                reader->hr_u.vint_state.val);
160                    break;
161                case HQFT_CANCEL_PUSH:
162                    reader->hr_cb->on_cancel_push(reader->hr_ctx,
163                                                reader->hr_u.vint_state.val);
164                    break;
165                case HQFT_MAX_PUSH_ID:
166                    reader->hr_cb->on_max_push_id(reader->hr_ctx,
167                                                reader->hr_u.vint_state.val);
168                    break;
169                case HQFT_PRIORITY_UPDATE_PUSH:
170                case HQFT_PRIORITY_UPDATE_STREAM:
171                    len = reader->hr_frame_length - reader->hr_nread;
172                    if (len <= (uintptr_t) (end - p))
173                    {
174                        reader->hr_cb->on_priority_update(reader->hr_ctx,
175                            reader->hr_frame_type, reader->hr_u.vint_state.val,
176                            (char *) p, len);
177                        p += len;
178                    }
179                    else if (len <= sizeof(reader->hr_u.prio_state.buf))
180                    {
181                        reader->hr_frame_length = len;
182                        reader->hr_nread = 0;
183                        reader->hr_state = HR_READ_PRIORITY_UPDATE;
184                        goto continue_reading;
185                    }
186                    else
187                    {
188                        p += len;
189                        /* 16 bytes is more than enough for a PRIORITY_UPDATE
190                         * frame, anything larger than that is unreasonable.
191                         */
192                        if (reader->hr_frame_length
193                                        > sizeof(reader->hr_u.prio_state.buf))
194                            LSQ_INFO("skip PRIORITY_UPDATE frame that's too "
195                                    "long (%"PRIu64" bytes)", len);
196                    }
197                    break;
198                default:
199                    assert(0);
200                }
201                reader->hr_state = HR_READ_FRAME_BEGIN;
202                break;
203            }
204            else
205            {
206                assert(p == end);
207                return 0;
208            }
209        case HR_SKIPPING:
210            len = MIN((uintptr_t) (end - p), reader->hr_frame_length);
211            p += len;
212            reader->hr_frame_length -= len;
213            if (0 == reader->hr_frame_length)
214                reader->hr_state = HR_READ_FRAME_BEGIN;
215            break;
216        case HR_READ_SETTING_BEGIN:
217            reader->hr_u.vint2_state.vr2s_state = 0;
218            reader->hr_state = HR_READ_SETTING_CONTINUE;
219            /* fall-through */
220        case HR_READ_SETTING_CONTINUE:
221            orig_p = p;
222            s = lsquic_varint_read_two(&p, end, &reader->hr_u.vint2_state);
223            reader->hr_nread += p - orig_p;
224            if (reader->hr_nread > reader->hr_frame_length)
225            {
226                reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1,
227                    HEC_FRAME_ERROR, "SETTING frame contents too long");
228                reader->hr_state = HR_ERROR;
229                return -1;
230            }
231            if (s < 0)
232                break;
233            reader->hr_cb->on_setting(reader->hr_ctx,
234                    reader->hr_u.vint2_state.vr2s_one,
235                    reader->hr_u.vint2_state.vr2s_two);
236            if (reader->hr_nread >= reader->hr_frame_length)
237            {
238                reader->hr_state = HR_READ_FRAME_BEGIN;
239                reader->hr_cb->on_settings_frame(reader->hr_ctx);
240            }
241            else
242                reader->hr_state = HR_READ_SETTING_BEGIN;
243            break;
244        case HR_READ_PRIORITY_UPDATE:
245            len = MIN((uintptr_t) (end - p),
246                            reader->hr_frame_length - reader->hr_nread);
247            memcpy(reader->hr_u.prio_state.buf + reader->hr_nread, p, len);
248            reader->hr_nread += len;
249            p += len;
250            if (reader->hr_frame_length == reader->hr_nread)
251            {
252                reader->hr_cb->on_priority_update(reader->hr_ctx,
253                        reader->hr_frame_type, reader->hr_u.vint_state.val,
254                        reader->hr_u.prio_state.buf, reader->hr_frame_length);
255                reader->hr_state = HR_READ_FRAME_BEGIN;
256            }
257            break;
258        default:
259            assert(0);
260            /* fall-through */
261        case HR_ERROR:
262            return -1;
263        }
264    }
265
266    return 0;
267}
268