lsquic_hcsi_reader.c revision 7d09751d
1/* Copyright (c) 2017 - 2020 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    while (p < end)
50    {
51        switch (reader->hr_state)
52        {
53        case HR_READ_FRAME_BEGIN:
54            reader->hr_u.vint2_state.vr2s_state = 0;
55            reader->hr_state = HR_READ_FRAME_CONTINUE;
56            /* fall-through */
57        case HR_READ_FRAME_CONTINUE:
58            s = lsquic_varint_read_two(&p, end, &reader->hr_u.vint2_state);
59            if (s < 0)
60                break;
61            reader->hr_frame_type = reader->hr_u.vint2_state.vr2s_one;
62            reader->hr_frame_length = reader->hr_u.vint2_state.vr2s_two;
63            switch (reader->hr_frame_type)
64            {
65            case HQFT_SETTINGS:
66                if (reader->hr_frame_length)
67                {
68                    reader->hr_state = HR_READ_SETTING_BEGIN;
69                    reader->hr_nread = 0;
70                }
71                else
72                {
73                    reader->hr_cb->on_settings_frame(reader->hr_ctx);
74                    reader->hr_state = HR_READ_FRAME_BEGIN;
75                }
76                break;
77            case HQFT_GOAWAY:
78                reader->hr_state = HR_READ_VARINT;
79                break;
80            case HQFT_CANCEL_PUSH:
81                reader->hr_state = HR_READ_VARINT;
82                break;
83            case HQFT_MAX_PUSH_ID:
84                reader->hr_state = HR_READ_VARINT;
85                break;
86            case HQFT_DATA:
87            case HQFT_HEADERS:
88            case HQFT_PUSH_PROMISE:
89                reader->hr_cb->on_unexpected_frame(reader->hr_ctx,
90                                                        reader->hr_frame_type);
91                return -1;
92            default:
93                if (!(reader->hr_frame_type >= 0xB &&
94                        (reader->hr_frame_type - 0xB) % 0x1F == 0))
95                    LSQ_INFO("unknown frame type 0x%"PRIX64" -- skipping",
96                                                        reader->hr_frame_type);
97                reader->hr_state = HR_SKIPPING;
98                LSQ_DEBUG("unknown frame 0x%"PRIX64": will skip %"PRIu64" bytes",
99                            reader->hr_frame_type, reader->hr_frame_length);
100                break;
101            }
102            break;
103        case HR_READ_VARINT:
104            reader->hr_u.vint_state.pos = 0;
105            reader->hr_state = HR_READ_VARINT_CONTINUE;
106            reader->hr_nread = 0;
107            /* fall-through */
108        case HR_READ_VARINT_CONTINUE:
109            orig_p = p;
110            s = lsquic_varint_read_nb(&p, end, &reader->hr_u.vint_state);
111            reader->hr_nread += p - orig_p;
112            if (0 == s)
113            {
114                if (reader->hr_nread != reader->hr_frame_length)
115                {
116                    reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1,
117                        HEC_FRAME_ERROR,
118                        "Frame length does not match actual payload length");
119                    reader->hr_state = HR_ERROR;
120                    return -1;
121                }
122                switch (reader->hr_frame_type)
123                {
124                case HQFT_GOAWAY:
125                    reader->hr_cb->on_goaway(reader->hr_ctx,
126                                                reader->hr_u.vint_state.val);
127                    break;
128                case HQFT_CANCEL_PUSH:
129                    reader->hr_cb->on_cancel_push(reader->hr_ctx,
130                                                reader->hr_u.vint_state.val);
131                    break;
132                case HQFT_MAX_PUSH_ID:
133                    reader->hr_cb->on_max_push_id(reader->hr_ctx,
134                                                reader->hr_u.vint_state.val);
135                    break;
136                default:
137                    assert(0);
138                }
139                reader->hr_state = HR_READ_FRAME_BEGIN;
140                break;
141            }
142            else
143            {
144                assert(p == end);
145                return 0;
146            }
147        case HR_SKIPPING:
148            len = MIN((uintptr_t) (end - p), reader->hr_frame_length);
149            p += len;
150            reader->hr_frame_length -= len;
151            if (0 == reader->hr_frame_length)
152                reader->hr_state = HR_READ_FRAME_BEGIN;
153            break;
154        case HR_READ_SETTING_BEGIN:
155            reader->hr_u.vint2_state.vr2s_state = 0;
156            reader->hr_state = HR_READ_SETTING_CONTINUE;
157            /* fall-through */
158        case HR_READ_SETTING_CONTINUE:
159            orig_p = p;
160            s = lsquic_varint_read_two(&p, end, &reader->hr_u.vint2_state);
161            reader->hr_nread += p - orig_p;
162            if (reader->hr_nread > reader->hr_frame_length)
163            {
164                reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1,
165                    HEC_FRAME_ERROR, "SETTING frame contents too long");
166                reader->hr_state = HR_ERROR;
167                return -1;
168            }
169            if (s < 0)
170                break;
171            reader->hr_cb->on_setting(reader->hr_ctx,
172                    reader->hr_u.vint2_state.vr2s_one,
173                    reader->hr_u.vint2_state.vr2s_two);
174            if (reader->hr_nread >= reader->hr_frame_length)
175            {
176                reader->hr_state = HR_READ_FRAME_BEGIN;
177                reader->hr_cb->on_settings_frame(reader->hr_ctx);
178            }
179            else
180                reader->hr_state = HR_READ_SETTING_BEGIN;
181            break;
182        default:
183            assert(0);
184            /* fall-through */
185        case HR_ERROR:
186            return -1;
187        }
188    }
189
190    return 0;
191}
192