lsquic_hcsi_reader.c revision 06b2a236
1/* Copyright (c) 2017 - 2021 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            switch (reader->hr_frame_type)
65            {
66            case HQFT_SETTINGS:
67                if (reader->hr_frame_length)
68                {
69                    reader->hr_state = HR_READ_SETTING_BEGIN;
70                    reader->hr_nread = 0;
71                }
72                else
73                {
74                    reader->hr_cb->on_settings_frame(reader->hr_ctx);
75                    reader->hr_state = HR_READ_FRAME_BEGIN;
76                }
77                break;
78            case HQFT_GOAWAY:
79                reader->hr_state = HR_READ_VARINT;
80                break;
81            case HQFT_CANCEL_PUSH:
82                reader->hr_state = HR_READ_VARINT;
83                break;
84            case HQFT_MAX_PUSH_ID:
85                reader->hr_state = HR_READ_VARINT;
86                break;
87            case HQFT_PRIORITY_UPDATE_PUSH:
88            case HQFT_PRIORITY_UPDATE_STREAM:
89                reader->hr_state = HR_READ_VARINT;
90                break;
91            case HQFT_DATA:
92            case HQFT_HEADERS:
93            case HQFT_PUSH_PROMISE:
94                reader->hr_cb->on_unexpected_frame(reader->hr_ctx,
95                                                        reader->hr_frame_type);
96                return -1;
97            default:
98            {
99            /* From [draft-ietf-quic-http-31] Section 7.2.8:
100             " Frame types of the format "0x1f * N + 0x21" for non-negative
101             " integer values of N are reserved to exercise the requirement
102             " that unknown types be ignored
103             */
104                enum lsq_log_level L;
105                if (!(reader->hr_frame_type >= 0x21 &&
106                        (reader->hr_frame_type - 0x21) % 0x1F == 0))
107                    /* Non-grease: log with higher level: */
108                    L = LSQ_LOG_INFO;
109                else
110                    L = LSQ_LOG_DEBUG;
111                LSQ_LOG(L, "unknown frame type 0x%"PRIX64": will skip "
112                    "%"PRIu64" bytes", reader->hr_frame_type,
113                    reader->hr_frame_length);
114                reader->hr_state = HR_SKIPPING;
115                break;
116            }
117            }
118            break;
119        case HR_READ_VARINT:
120            reader->hr_u.vint_state.pos = 0;
121            reader->hr_state = HR_READ_VARINT_CONTINUE;
122            reader->hr_nread = 0;
123            /* fall-through */
124        case HR_READ_VARINT_CONTINUE:
125            orig_p = p;
126            s = lsquic_varint_read_nb(&p, end, &reader->hr_u.vint_state);
127            reader->hr_nread += p - orig_p;
128            if (0 == s)
129            {
130                switch (reader->hr_frame_type)
131                {
132                case HQFT_GOAWAY:
133                case HQFT_CANCEL_PUSH:
134                case HQFT_MAX_PUSH_ID:
135                    if (reader->hr_nread != reader->hr_frame_length)
136                    {
137                        reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1,
138                            HEC_FRAME_ERROR,
139                            "Frame length does not match actual payload length");
140                        reader->hr_state = HR_ERROR;
141                        return -1;
142                    }
143                    break;
144                }
145                switch (reader->hr_frame_type)
146                {
147                case HQFT_GOAWAY:
148                    reader->hr_cb->on_goaway(reader->hr_ctx,
149                                                reader->hr_u.vint_state.val);
150                    break;
151                case HQFT_CANCEL_PUSH:
152                    reader->hr_cb->on_cancel_push(reader->hr_ctx,
153                                                reader->hr_u.vint_state.val);
154                    break;
155                case HQFT_MAX_PUSH_ID:
156                    reader->hr_cb->on_max_push_id(reader->hr_ctx,
157                                                reader->hr_u.vint_state.val);
158                    break;
159                case HQFT_PRIORITY_UPDATE_PUSH:
160                case HQFT_PRIORITY_UPDATE_STREAM:
161                    len = reader->hr_frame_length - reader->hr_nread;
162                    if (len <= (uintptr_t) (end - p))
163                    {
164                        reader->hr_cb->on_priority_update(reader->hr_ctx,
165                            reader->hr_frame_type, reader->hr_u.vint_state.val,
166                            (char *) p, len);
167                        p += len;
168                    }
169                    else if (len <= sizeof(reader->hr_u.prio_state.buf))
170                    {
171                        reader->hr_frame_length = len;
172                        reader->hr_nread = 0;
173                        reader->hr_state = HR_READ_PRIORITY_UPDATE;
174                        goto continue_reading;
175                    }
176                    else
177                    {
178                        p += len;
179                        /* 16 bytes is more than enough for a PRIORITY_UPDATE
180                         * frame, anything larger than that is unreasonable.
181                         */
182                        if (reader->hr_frame_length
183                                        > sizeof(reader->hr_u.prio_state.buf))
184                            LSQ_INFO("skip PRIORITY_UPDATE frame that's too "
185                                    "long (%"PRIu64" bytes)", len);
186                    }
187                    break;
188                default:
189                    assert(0);
190                }
191                reader->hr_state = HR_READ_FRAME_BEGIN;
192                break;
193            }
194            else
195            {
196                assert(p == end);
197                return 0;
198            }
199        case HR_SKIPPING:
200            len = MIN((uintptr_t) (end - p), reader->hr_frame_length);
201            p += len;
202            reader->hr_frame_length -= len;
203            if (0 == reader->hr_frame_length)
204                reader->hr_state = HR_READ_FRAME_BEGIN;
205            break;
206        case HR_READ_SETTING_BEGIN:
207            reader->hr_u.vint2_state.vr2s_state = 0;
208            reader->hr_state = HR_READ_SETTING_CONTINUE;
209            /* fall-through */
210        case HR_READ_SETTING_CONTINUE:
211            orig_p = p;
212            s = lsquic_varint_read_two(&p, end, &reader->hr_u.vint2_state);
213            reader->hr_nread += p - orig_p;
214            if (reader->hr_nread > reader->hr_frame_length)
215            {
216                reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1,
217                    HEC_FRAME_ERROR, "SETTING frame contents too long");
218                reader->hr_state = HR_ERROR;
219                return -1;
220            }
221            if (s < 0)
222                break;
223            reader->hr_cb->on_setting(reader->hr_ctx,
224                    reader->hr_u.vint2_state.vr2s_one,
225                    reader->hr_u.vint2_state.vr2s_two);
226            if (reader->hr_nread >= reader->hr_frame_length)
227            {
228                reader->hr_state = HR_READ_FRAME_BEGIN;
229                reader->hr_cb->on_settings_frame(reader->hr_ctx);
230            }
231            else
232                reader->hr_state = HR_READ_SETTING_BEGIN;
233            break;
234        case HR_READ_PRIORITY_UPDATE:
235            len = MIN((uintptr_t) (end - p),
236                            reader->hr_frame_length - reader->hr_nread);
237            memcpy(reader->hr_u.prio_state.buf + reader->hr_nread, p, len);
238            reader->hr_nread += len;
239            p += len;
240            if (reader->hr_frame_length == reader->hr_nread)
241            {
242                reader->hr_cb->on_priority_update(reader->hr_ctx,
243                        reader->hr_frame_type, reader->hr_u.vint_state.val,
244                        reader->hr_u.prio_state.buf, reader->hr_frame_length);
245                reader->hr_state = HR_READ_FRAME_BEGIN;
246            }
247            break;
248        default:
249            assert(0);
250            /* fall-through */
251        case HR_ERROR:
252            return -1;
253        }
254    }
255
256    return 0;
257}
258