lsquic_hcsi_reader.c revision fbc6cc04
17d09751dSDmitri Tikhonov/* Copyright (c) 2017 - 2020 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 uint64_t len; 475392f7a3SLiteSpeed Tech int s; 485392f7a3SLiteSpeed Tech 49fbc6cc04SDmitri Tikhonov continue_reading: 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_GOAWAY: 795392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_VARINT; 805392f7a3SLiteSpeed Tech break; 815392f7a3SLiteSpeed Tech case HQFT_CANCEL_PUSH: 825392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_VARINT; 835392f7a3SLiteSpeed Tech break; 845392f7a3SLiteSpeed Tech case HQFT_MAX_PUSH_ID: 855392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_VARINT; 865392f7a3SLiteSpeed Tech break; 87fbc6cc04SDmitri Tikhonov case HQFT_PRIORITY_UPDATE_PUSH: 88fbc6cc04SDmitri Tikhonov case HQFT_PRIORITY_UPDATE_STREAM: 89fbc6cc04SDmitri Tikhonov reader->hr_state = HR_READ_VARINT; 90fbc6cc04SDmitri Tikhonov break; 915392f7a3SLiteSpeed Tech case HQFT_DATA: 925392f7a3SLiteSpeed Tech case HQFT_HEADERS: 935392f7a3SLiteSpeed Tech case HQFT_PUSH_PROMISE: 945392f7a3SLiteSpeed Tech reader->hr_cb->on_unexpected_frame(reader->hr_ctx, 955392f7a3SLiteSpeed Tech reader->hr_frame_type); 965392f7a3SLiteSpeed Tech return -1; 975392f7a3SLiteSpeed Tech default: 985392f7a3SLiteSpeed Tech if (!(reader->hr_frame_type >= 0xB && 995392f7a3SLiteSpeed Tech (reader->hr_frame_type - 0xB) % 0x1F == 0)) 1005392f7a3SLiteSpeed Tech LSQ_INFO("unknown frame type 0x%"PRIX64" -- skipping", 1015392f7a3SLiteSpeed Tech reader->hr_frame_type); 1025392f7a3SLiteSpeed Tech reader->hr_state = HR_SKIPPING; 1035392f7a3SLiteSpeed Tech LSQ_DEBUG("unknown frame 0x%"PRIX64": will skip %"PRIu64" bytes", 1045392f7a3SLiteSpeed Tech reader->hr_frame_type, reader->hr_frame_length); 1055392f7a3SLiteSpeed Tech break; 1065392f7a3SLiteSpeed Tech } 1075392f7a3SLiteSpeed Tech break; 1085392f7a3SLiteSpeed Tech case HR_READ_VARINT: 1095392f7a3SLiteSpeed Tech reader->hr_u.vint_state.pos = 0; 1105392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_VARINT_CONTINUE; 1115392f7a3SLiteSpeed Tech reader->hr_nread = 0; 1125392f7a3SLiteSpeed Tech /* fall-through */ 1135392f7a3SLiteSpeed Tech case HR_READ_VARINT_CONTINUE: 1145392f7a3SLiteSpeed Tech orig_p = p; 1155392f7a3SLiteSpeed Tech s = lsquic_varint_read_nb(&p, end, &reader->hr_u.vint_state); 1165392f7a3SLiteSpeed Tech reader->hr_nread += p - orig_p; 1175392f7a3SLiteSpeed Tech if (0 == s) 1185392f7a3SLiteSpeed Tech { 119fbc6cc04SDmitri Tikhonov switch (reader->hr_frame_type) 1205392f7a3SLiteSpeed Tech { 121fbc6cc04SDmitri Tikhonov case HQFT_GOAWAY: 122fbc6cc04SDmitri Tikhonov case HQFT_CANCEL_PUSH: 123fbc6cc04SDmitri Tikhonov case HQFT_MAX_PUSH_ID: 124fbc6cc04SDmitri Tikhonov if (reader->hr_nread != reader->hr_frame_length) 125fbc6cc04SDmitri Tikhonov { 126fbc6cc04SDmitri Tikhonov reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1, 127fbc6cc04SDmitri Tikhonov HEC_FRAME_ERROR, 128fbc6cc04SDmitri Tikhonov "Frame length does not match actual payload length"); 129fbc6cc04SDmitri Tikhonov reader->hr_state = HR_ERROR; 130fbc6cc04SDmitri Tikhonov return -1; 131fbc6cc04SDmitri Tikhonov } 132fbc6cc04SDmitri Tikhonov break; 1335392f7a3SLiteSpeed Tech } 1345392f7a3SLiteSpeed Tech switch (reader->hr_frame_type) 1355392f7a3SLiteSpeed Tech { 1365392f7a3SLiteSpeed Tech case HQFT_GOAWAY: 1375392f7a3SLiteSpeed Tech reader->hr_cb->on_goaway(reader->hr_ctx, 1385392f7a3SLiteSpeed Tech reader->hr_u.vint_state.val); 1395392f7a3SLiteSpeed Tech break; 1405392f7a3SLiteSpeed Tech case HQFT_CANCEL_PUSH: 1415392f7a3SLiteSpeed Tech reader->hr_cb->on_cancel_push(reader->hr_ctx, 1425392f7a3SLiteSpeed Tech reader->hr_u.vint_state.val); 1435392f7a3SLiteSpeed Tech break; 1445392f7a3SLiteSpeed Tech case HQFT_MAX_PUSH_ID: 1455392f7a3SLiteSpeed Tech reader->hr_cb->on_max_push_id(reader->hr_ctx, 1465392f7a3SLiteSpeed Tech reader->hr_u.vint_state.val); 1475392f7a3SLiteSpeed Tech break; 148fbc6cc04SDmitri Tikhonov case HQFT_PRIORITY_UPDATE_PUSH: 149fbc6cc04SDmitri Tikhonov case HQFT_PRIORITY_UPDATE_STREAM: 150fbc6cc04SDmitri Tikhonov len = reader->hr_frame_length - reader->hr_nread; 151fbc6cc04SDmitri Tikhonov if (len <= (uintptr_t) (end - p)) 152fbc6cc04SDmitri Tikhonov { 153fbc6cc04SDmitri Tikhonov reader->hr_cb->on_priority_update(reader->hr_ctx, 154fbc6cc04SDmitri Tikhonov reader->hr_frame_type, reader->hr_u.vint_state.val, 155fbc6cc04SDmitri Tikhonov (char *) p, len); 156fbc6cc04SDmitri Tikhonov p += len; 157fbc6cc04SDmitri Tikhonov } 158fbc6cc04SDmitri Tikhonov else if (len <= sizeof(reader->hr_u.prio_state.buf)) 159fbc6cc04SDmitri Tikhonov { 160fbc6cc04SDmitri Tikhonov reader->hr_frame_length = len; 161fbc6cc04SDmitri Tikhonov reader->hr_nread = 0; 162fbc6cc04SDmitri Tikhonov reader->hr_state = HR_READ_PRIORITY_UPDATE; 163fbc6cc04SDmitri Tikhonov goto continue_reading; 164fbc6cc04SDmitri Tikhonov } 165fbc6cc04SDmitri Tikhonov else 166fbc6cc04SDmitri Tikhonov { 167fbc6cc04SDmitri Tikhonov p += len; 168fbc6cc04SDmitri Tikhonov /* 16 bytes is more than enough for a PRIORITY_UPDATE 169fbc6cc04SDmitri Tikhonov * frame, anything larger than that is unreasonable. 170fbc6cc04SDmitri Tikhonov */ 171fbc6cc04SDmitri Tikhonov if (reader->hr_frame_length 172fbc6cc04SDmitri Tikhonov > sizeof(reader->hr_u.prio_state.buf)) 173fbc6cc04SDmitri Tikhonov LSQ_INFO("skip PRIORITY_UPDATE frame that's too " 174fbc6cc04SDmitri Tikhonov "long (%"PRIu64" bytes)", len); 175fbc6cc04SDmitri Tikhonov } 176fbc6cc04SDmitri Tikhonov break; 1775392f7a3SLiteSpeed Tech default: 1785392f7a3SLiteSpeed Tech assert(0); 1795392f7a3SLiteSpeed Tech } 1805392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_FRAME_BEGIN; 1815392f7a3SLiteSpeed Tech break; 1825392f7a3SLiteSpeed Tech } 1835392f7a3SLiteSpeed Tech else 1845392f7a3SLiteSpeed Tech { 1855392f7a3SLiteSpeed Tech assert(p == end); 1865392f7a3SLiteSpeed Tech return 0; 1875392f7a3SLiteSpeed Tech } 1885392f7a3SLiteSpeed Tech case HR_SKIPPING: 1895392f7a3SLiteSpeed Tech len = MIN((uintptr_t) (end - p), reader->hr_frame_length); 1905392f7a3SLiteSpeed Tech p += len; 1915392f7a3SLiteSpeed Tech reader->hr_frame_length -= len; 1925392f7a3SLiteSpeed Tech if (0 == reader->hr_frame_length) 1935392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_FRAME_BEGIN; 1945392f7a3SLiteSpeed Tech break; 1955392f7a3SLiteSpeed Tech case HR_READ_SETTING_BEGIN: 1965392f7a3SLiteSpeed Tech reader->hr_u.vint2_state.vr2s_state = 0; 1975392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_SETTING_CONTINUE; 1985392f7a3SLiteSpeed Tech /* fall-through */ 1995392f7a3SLiteSpeed Tech case HR_READ_SETTING_CONTINUE: 2005392f7a3SLiteSpeed Tech orig_p = p; 2015392f7a3SLiteSpeed Tech s = lsquic_varint_read_two(&p, end, &reader->hr_u.vint2_state); 2025392f7a3SLiteSpeed Tech reader->hr_nread += p - orig_p; 2035392f7a3SLiteSpeed Tech if (reader->hr_nread > reader->hr_frame_length) 2045392f7a3SLiteSpeed Tech { 2055392f7a3SLiteSpeed Tech reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1, 20692f6e17bSDmitri Tikhonov HEC_FRAME_ERROR, "SETTING frame contents too long"); 2075392f7a3SLiteSpeed Tech reader->hr_state = HR_ERROR; 2085392f7a3SLiteSpeed Tech return -1; 2095392f7a3SLiteSpeed Tech } 2105392f7a3SLiteSpeed Tech if (s < 0) 2115392f7a3SLiteSpeed Tech break; 2125392f7a3SLiteSpeed Tech reader->hr_cb->on_setting(reader->hr_ctx, 2135392f7a3SLiteSpeed Tech reader->hr_u.vint2_state.vr2s_one, 2145392f7a3SLiteSpeed Tech reader->hr_u.vint2_state.vr2s_two); 2155392f7a3SLiteSpeed Tech if (reader->hr_nread >= reader->hr_frame_length) 2165392f7a3SLiteSpeed Tech { 2175392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_FRAME_BEGIN; 2185392f7a3SLiteSpeed Tech reader->hr_cb->on_settings_frame(reader->hr_ctx); 2195392f7a3SLiteSpeed Tech } 2205392f7a3SLiteSpeed Tech else 2215392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_SETTING_BEGIN; 2225392f7a3SLiteSpeed Tech break; 223fbc6cc04SDmitri Tikhonov case HR_READ_PRIORITY_UPDATE: 224fbc6cc04SDmitri Tikhonov len = MIN((uintptr_t) (end - p), 225fbc6cc04SDmitri Tikhonov reader->hr_frame_length - reader->hr_nread); 226fbc6cc04SDmitri Tikhonov memcpy(reader->hr_u.prio_state.buf + reader->hr_nread, p, len); 227fbc6cc04SDmitri Tikhonov reader->hr_nread += len; 228fbc6cc04SDmitri Tikhonov p += len; 229fbc6cc04SDmitri Tikhonov if (reader->hr_frame_length == reader->hr_nread) 230fbc6cc04SDmitri Tikhonov { 231fbc6cc04SDmitri Tikhonov reader->hr_cb->on_priority_update(reader->hr_ctx, 232fbc6cc04SDmitri Tikhonov reader->hr_frame_type, reader->hr_u.vint_state.val, 233fbc6cc04SDmitri Tikhonov reader->hr_u.prio_state.buf, reader->hr_frame_length); 234fbc6cc04SDmitri Tikhonov reader->hr_state = HR_READ_FRAME_BEGIN; 235fbc6cc04SDmitri Tikhonov } 236fbc6cc04SDmitri Tikhonov break; 2375392f7a3SLiteSpeed Tech default: 2385392f7a3SLiteSpeed Tech assert(0); 2395392f7a3SLiteSpeed Tech /* fall-through */ 2405392f7a3SLiteSpeed Tech case HR_ERROR: 2415392f7a3SLiteSpeed Tech return -1; 2425392f7a3SLiteSpeed Tech } 2435392f7a3SLiteSpeed Tech } 2445392f7a3SLiteSpeed Tech 2455392f7a3SLiteSpeed Tech return 0; 2465392f7a3SLiteSpeed Tech} 247