lsquic_hcsi_reader.c revision 5392f7a3
15392f7a3SLiteSpeed Tech/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
25392f7a3SLiteSpeed Tech#include <assert.h>
35392f7a3SLiteSpeed Tech#include <inttypes.h>
45392f7a3SLiteSpeed Tech#include <stddef.h>
55392f7a3SLiteSpeed Tech#include <stdint.h>
65392f7a3SLiteSpeed Tech#include <string.h>
75392f7a3SLiteSpeed Tech#include <sys/queue.h>
85392f7a3SLiteSpeed Tech
95392f7a3SLiteSpeed Tech#include "lsquic.h"
105392f7a3SLiteSpeed Tech#include "lsquic_int_types.h"
115392f7a3SLiteSpeed Tech#include "lsquic_varint.h"
125392f7a3SLiteSpeed Tech#include "lsquic_hq.h"
135392f7a3SLiteSpeed Tech#include "lsquic_hash.h"
145392f7a3SLiteSpeed Tech#include "lsquic_conn.h"
155392f7a3SLiteSpeed Tech#include "lsquic_hcsi_reader.h"
165392f7a3SLiteSpeed Tech
175392f7a3SLiteSpeed Tech#define LSQUIC_LOGGER_MODULE LSQLM_HCSI_READER
185392f7a3SLiteSpeed Tech#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(reader->hr_conn)
195392f7a3SLiteSpeed Tech#include "lsquic_logger.h"
205392f7a3SLiteSpeed Tech
215392f7a3SLiteSpeed Tech#define MIN(a, b) ((a) < (b) ? (a) : (b))
225392f7a3SLiteSpeed Tech
235392f7a3SLiteSpeed Tech
245392f7a3SLiteSpeed Techvoid
255392f7a3SLiteSpeed Techlsquic_hcsi_reader_init (struct hcsi_reader *reader,
265392f7a3SLiteSpeed Tech        struct lsquic_conn *conn, const struct hcsi_callbacks *callbacks,
275392f7a3SLiteSpeed Tech        void *ctx)
285392f7a3SLiteSpeed Tech{
295392f7a3SLiteSpeed Tech    memset(reader, 0, sizeof(*reader));
305392f7a3SLiteSpeed Tech    reader->hr_state = HR_READ_FRAME_BEGIN;
315392f7a3SLiteSpeed Tech    reader->hr_conn = conn;
325392f7a3SLiteSpeed Tech    reader->hr_cb = callbacks;
335392f7a3SLiteSpeed Tech    reader->hr_ctx = ctx;
345392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized");
355392f7a3SLiteSpeed Tech}
365392f7a3SLiteSpeed Tech
375392f7a3SLiteSpeed Tech
385392f7a3SLiteSpeed Techint
395392f7a3SLiteSpeed Techlsquic_hcsi_reader_feed (struct hcsi_reader *reader, const void *buf,
405392f7a3SLiteSpeed Tech                                                                size_t bufsz)
415392f7a3SLiteSpeed Tech{
425392f7a3SLiteSpeed Tech    const unsigned char *p = buf;
435392f7a3SLiteSpeed Tech    const unsigned char *const end = p + bufsz;
445392f7a3SLiteSpeed Tech
455392f7a3SLiteSpeed Tech    const unsigned char *orig_p;
465392f7a3SLiteSpeed Tech    enum h3_prio_frame_read_status prio_status;
475392f7a3SLiteSpeed Tech    uint64_t len;
485392f7a3SLiteSpeed Tech    int s;
495392f7a3SLiteSpeed Tech
505392f7a3SLiteSpeed Tech    while (p < end)
515392f7a3SLiteSpeed Tech    {
525392f7a3SLiteSpeed Tech        switch (reader->hr_state)
535392f7a3SLiteSpeed Tech        {
545392f7a3SLiteSpeed Tech        case HR_READ_FRAME_BEGIN:
555392f7a3SLiteSpeed Tech            reader->hr_u.vint2_state.vr2s_state = 0;
565392f7a3SLiteSpeed Tech            reader->hr_state = HR_READ_FRAME_CONTINUE;
575392f7a3SLiteSpeed Tech            /* fall-through */
585392f7a3SLiteSpeed Tech        case HR_READ_FRAME_CONTINUE:
595392f7a3SLiteSpeed Tech            s = lsquic_varint_read_two(&p, end, &reader->hr_u.vint2_state);
605392f7a3SLiteSpeed Tech            if (s < 0)
615392f7a3SLiteSpeed Tech                break;
625392f7a3SLiteSpeed Tech            reader->hr_frame_type = reader->hr_u.vint2_state.vr2s_one;
635392f7a3SLiteSpeed Tech            reader->hr_frame_length = reader->hr_u.vint2_state.vr2s_two;
645392f7a3SLiteSpeed Tech            switch (reader->hr_frame_type)
655392f7a3SLiteSpeed Tech            {
665392f7a3SLiteSpeed Tech            case HQFT_SETTINGS:
675392f7a3SLiteSpeed Tech                if (reader->hr_frame_length)
685392f7a3SLiteSpeed Tech                {
695392f7a3SLiteSpeed Tech                    reader->hr_state = HR_READ_SETTING_BEGIN;
705392f7a3SLiteSpeed Tech                    reader->hr_nread = 0;
715392f7a3SLiteSpeed Tech                }
725392f7a3SLiteSpeed Tech                else
735392f7a3SLiteSpeed Tech                {
745392f7a3SLiteSpeed Tech                    reader->hr_cb->on_settings_frame(reader->hr_ctx);
755392f7a3SLiteSpeed Tech                    reader->hr_state = HR_READ_FRAME_BEGIN;
765392f7a3SLiteSpeed Tech                }
775392f7a3SLiteSpeed Tech                break;
785392f7a3SLiteSpeed Tech            case HQFT_PRIORITY:
795392f7a3SLiteSpeed Tech                reader->hr_state = HR_READ_PRIORITY_BEGIN;
805392f7a3SLiteSpeed Tech                break;
815392f7a3SLiteSpeed Tech            case HQFT_GOAWAY:
825392f7a3SLiteSpeed Tech                reader->hr_state = HR_READ_VARINT;
835392f7a3SLiteSpeed Tech                break;
845392f7a3SLiteSpeed Tech            case HQFT_CANCEL_PUSH:
855392f7a3SLiteSpeed Tech                reader->hr_state = HR_READ_VARINT;
865392f7a3SLiteSpeed Tech                break;
875392f7a3SLiteSpeed Tech            case HQFT_MAX_PUSH_ID:
885392f7a3SLiteSpeed Tech                reader->hr_state = HR_READ_VARINT;
895392f7a3SLiteSpeed Tech                break;
905392f7a3SLiteSpeed Tech            case HQFT_DATA:
915392f7a3SLiteSpeed Tech            case HQFT_HEADERS:
925392f7a3SLiteSpeed Tech            case HQFT_PUSH_PROMISE:
935392f7a3SLiteSpeed Tech                reader->hr_cb->on_unexpected_frame(reader->hr_ctx,
945392f7a3SLiteSpeed Tech                                                        reader->hr_frame_type);
955392f7a3SLiteSpeed Tech                return -1;
965392f7a3SLiteSpeed Tech            default:
975392f7a3SLiteSpeed Tech                if (!(reader->hr_frame_type >= 0xB &&
985392f7a3SLiteSpeed Tech                        (reader->hr_frame_type - 0xB) % 0x1F == 0))
995392f7a3SLiteSpeed Tech                    LSQ_INFO("unknown frame type 0x%"PRIX64" -- skipping",
1005392f7a3SLiteSpeed Tech                                                        reader->hr_frame_type);
1015392f7a3SLiteSpeed Tech                reader->hr_state = HR_SKIPPING;
1025392f7a3SLiteSpeed Tech                LSQ_DEBUG("unknown frame 0x%"PRIX64": will skip %"PRIu64" bytes",
1035392f7a3SLiteSpeed Tech                            reader->hr_frame_type, reader->hr_frame_length);
1045392f7a3SLiteSpeed Tech                break;
1055392f7a3SLiteSpeed Tech            }
1065392f7a3SLiteSpeed Tech            break;
1075392f7a3SLiteSpeed Tech        case HR_READ_VARINT:
1085392f7a3SLiteSpeed Tech            reader->hr_u.vint_state.pos = 0;
1095392f7a3SLiteSpeed Tech            reader->hr_state = HR_READ_VARINT_CONTINUE;
1105392f7a3SLiteSpeed Tech            reader->hr_nread = 0;
1115392f7a3SLiteSpeed Tech            /* fall-through */
1125392f7a3SLiteSpeed Tech        case HR_READ_VARINT_CONTINUE:
1135392f7a3SLiteSpeed Tech            orig_p = p;
1145392f7a3SLiteSpeed Tech            s = lsquic_varint_read_nb(&p, end, &reader->hr_u.vint_state);
1155392f7a3SLiteSpeed Tech            reader->hr_nread += p - orig_p;
1165392f7a3SLiteSpeed Tech            if (0 == s)
1175392f7a3SLiteSpeed Tech            {
1185392f7a3SLiteSpeed Tech                if (reader->hr_nread != reader->hr_frame_length)
1195392f7a3SLiteSpeed Tech                {
1205392f7a3SLiteSpeed Tech                    reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1,
1215392f7a3SLiteSpeed Tech                        HEC_MALFORMED_FRAME + reader->hr_frame_type,
1225392f7a3SLiteSpeed Tech                        "Frame length does not match actual payload length");
1235392f7a3SLiteSpeed Tech                    reader->hr_state = HR_ERROR;
1245392f7a3SLiteSpeed Tech                    return -1;
1255392f7a3SLiteSpeed Tech                }
1265392f7a3SLiteSpeed Tech                switch (reader->hr_frame_type)
1275392f7a3SLiteSpeed Tech                {
1285392f7a3SLiteSpeed Tech                case HQFT_GOAWAY:
1295392f7a3SLiteSpeed Tech                    reader->hr_cb->on_goaway(reader->hr_ctx,
1305392f7a3SLiteSpeed Tech                                                reader->hr_u.vint_state.val);
1315392f7a3SLiteSpeed Tech                    break;
1325392f7a3SLiteSpeed Tech                case HQFT_CANCEL_PUSH:
1335392f7a3SLiteSpeed Tech                    reader->hr_cb->on_cancel_push(reader->hr_ctx,
1345392f7a3SLiteSpeed Tech                                                reader->hr_u.vint_state.val);
1355392f7a3SLiteSpeed Tech                    break;
1365392f7a3SLiteSpeed Tech                case HQFT_MAX_PUSH_ID:
1375392f7a3SLiteSpeed Tech                    reader->hr_cb->on_max_push_id(reader->hr_ctx,
1385392f7a3SLiteSpeed Tech                                                reader->hr_u.vint_state.val);
1395392f7a3SLiteSpeed Tech                    break;
1405392f7a3SLiteSpeed Tech                default:
1415392f7a3SLiteSpeed Tech                    assert(0);
1425392f7a3SLiteSpeed Tech                }
1435392f7a3SLiteSpeed Tech                reader->hr_state = HR_READ_FRAME_BEGIN;
1445392f7a3SLiteSpeed Tech                break;
1455392f7a3SLiteSpeed Tech            }
1465392f7a3SLiteSpeed Tech            else
1475392f7a3SLiteSpeed Tech            {
1485392f7a3SLiteSpeed Tech                assert(p == end);
1495392f7a3SLiteSpeed Tech                return 0;
1505392f7a3SLiteSpeed Tech            }
1515392f7a3SLiteSpeed Tech        case HR_SKIPPING:
1525392f7a3SLiteSpeed Tech            len = MIN((uintptr_t) (end - p), reader->hr_frame_length);
1535392f7a3SLiteSpeed Tech            p += len;
1545392f7a3SLiteSpeed Tech            reader->hr_frame_length -= len;
1555392f7a3SLiteSpeed Tech            if (0 == reader->hr_frame_length)
1565392f7a3SLiteSpeed Tech                reader->hr_state = HR_READ_FRAME_BEGIN;
1575392f7a3SLiteSpeed Tech            break;
1585392f7a3SLiteSpeed Tech        case HR_READ_SETTING_BEGIN:
1595392f7a3SLiteSpeed Tech            reader->hr_u.vint2_state.vr2s_state = 0;
1605392f7a3SLiteSpeed Tech            reader->hr_state = HR_READ_SETTING_CONTINUE;
1615392f7a3SLiteSpeed Tech            /* fall-through */
1625392f7a3SLiteSpeed Tech        case HR_READ_SETTING_CONTINUE:
1635392f7a3SLiteSpeed Tech            orig_p = p;
1645392f7a3SLiteSpeed Tech            s = lsquic_varint_read_two(&p, end, &reader->hr_u.vint2_state);
1655392f7a3SLiteSpeed Tech            reader->hr_nread += p - orig_p;
1665392f7a3SLiteSpeed Tech            if (reader->hr_nread > reader->hr_frame_length)
1675392f7a3SLiteSpeed Tech            {
1685392f7a3SLiteSpeed Tech                reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1,
1695392f7a3SLiteSpeed Tech                    HEC_MALFORMED_FRAME + HQFT_SETTINGS,
1705392f7a3SLiteSpeed Tech                    "SETTING frame contents too long");
1715392f7a3SLiteSpeed Tech                reader->hr_state = HR_ERROR;
1725392f7a3SLiteSpeed Tech                return -1;
1735392f7a3SLiteSpeed Tech            }
1745392f7a3SLiteSpeed Tech            if (s < 0)
1755392f7a3SLiteSpeed Tech                break;
1765392f7a3SLiteSpeed Tech            reader->hr_cb->on_setting(reader->hr_ctx,
1775392f7a3SLiteSpeed Tech                    reader->hr_u.vint2_state.vr2s_one,
1785392f7a3SLiteSpeed Tech                    reader->hr_u.vint2_state.vr2s_two);
1795392f7a3SLiteSpeed Tech            if (reader->hr_nread >= reader->hr_frame_length)
1805392f7a3SLiteSpeed Tech            {
1815392f7a3SLiteSpeed Tech                reader->hr_state = HR_READ_FRAME_BEGIN;
1825392f7a3SLiteSpeed Tech                reader->hr_cb->on_settings_frame(reader->hr_ctx);
1835392f7a3SLiteSpeed Tech            }
1845392f7a3SLiteSpeed Tech            else
1855392f7a3SLiteSpeed Tech                reader->hr_state = HR_READ_SETTING_BEGIN;
1865392f7a3SLiteSpeed Tech            break;
1875392f7a3SLiteSpeed Tech        case HR_READ_PRIORITY_BEGIN:
1885392f7a3SLiteSpeed Tech            reader->hr_u.prio.h3pfrs_state = 0;
1895392f7a3SLiteSpeed Tech            reader->hr_nread = 0;
1905392f7a3SLiteSpeed Tech            reader->hr_state = HR_READ_PRIORITY_CONTINUE;
1915392f7a3SLiteSpeed Tech            /* fall-through */
1925392f7a3SLiteSpeed Tech        case HR_READ_PRIORITY_CONTINUE:
1935392f7a3SLiteSpeed Tech            orig_p = p;
1945392f7a3SLiteSpeed Tech            prio_status = lsquic_h3_prio_frame_read(&p, end - p,
1955392f7a3SLiteSpeed Tech                                                        &reader->hr_u.prio);
1965392f7a3SLiteSpeed Tech            reader->hr_nread += p - orig_p;
1975392f7a3SLiteSpeed Tech            if (prio_status == H3PFR_STATUS_DONE)
1985392f7a3SLiteSpeed Tech            {
1995392f7a3SLiteSpeed Tech                if (reader->hr_nread != reader->hr_frame_length)
2005392f7a3SLiteSpeed Tech                {
2015392f7a3SLiteSpeed Tech                    reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1,
2025392f7a3SLiteSpeed Tech                        HEC_MALFORMED_FRAME + HQFT_PRIORITY, "PRIORITY frame "
2035392f7a3SLiteSpeed Tech                        "contents size does not match frame length");
2045392f7a3SLiteSpeed Tech                    reader->hr_state = HR_ERROR;
2055392f7a3SLiteSpeed Tech                    return -1;
2065392f7a3SLiteSpeed Tech                }
2075392f7a3SLiteSpeed Tech                reader->hr_state = HR_READ_FRAME_BEGIN;
2085392f7a3SLiteSpeed Tech                reader->hr_cb->on_priority(reader->hr_ctx,
2095392f7a3SLiteSpeed Tech                                                    &reader->hr_u.prio.h3pfrs_prio);
2105392f7a3SLiteSpeed Tech            }
2115392f7a3SLiteSpeed Tech            break;
2125392f7a3SLiteSpeed Tech        default:
2135392f7a3SLiteSpeed Tech            assert(0);
2145392f7a3SLiteSpeed Tech            /* fall-through */
2155392f7a3SLiteSpeed Tech        case HR_ERROR:
2165392f7a3SLiteSpeed Tech            return -1;
2175392f7a3SLiteSpeed Tech        }
2185392f7a3SLiteSpeed Tech    }
2195392f7a3SLiteSpeed Tech
2205392f7a3SLiteSpeed Tech    return 0;
2215392f7a3SLiteSpeed Tech}
222