1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 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; 6455d69529SGeorge Wang 6555d69529SGeorge Wang if (!(reader->hr_flag & HR_FLAG_RCVD_SETTING) 6655d69529SGeorge Wang && reader->hr_frame_type != HQFT_SETTINGS) 6755d69529SGeorge Wang { 6855d69529SGeorge Wang reader->hr_cb->on_frame_error(reader->hr_ctx, 6955d69529SGeorge Wang HEC_MISSING_SETTINGS, reader->hr_frame_type); 7055d69529SGeorge Wang return -1; 7155d69529SGeorge Wang } 7255d69529SGeorge Wang 735392f7a3SLiteSpeed Tech switch (reader->hr_frame_type) 745392f7a3SLiteSpeed Tech { 755392f7a3SLiteSpeed Tech case HQFT_SETTINGS: 7655d69529SGeorge Wang reader->hr_flag |= HR_FLAG_RCVD_SETTING; 775392f7a3SLiteSpeed Tech if (reader->hr_frame_length) 785392f7a3SLiteSpeed Tech { 795392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_SETTING_BEGIN; 805392f7a3SLiteSpeed Tech reader->hr_nread = 0; 815392f7a3SLiteSpeed Tech } 825392f7a3SLiteSpeed Tech else 835392f7a3SLiteSpeed Tech { 845392f7a3SLiteSpeed Tech reader->hr_cb->on_settings_frame(reader->hr_ctx); 855392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_FRAME_BEGIN; 865392f7a3SLiteSpeed Tech } 875392f7a3SLiteSpeed Tech break; 885392f7a3SLiteSpeed Tech case HQFT_GOAWAY: 895392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_VARINT; 905392f7a3SLiteSpeed Tech break; 915392f7a3SLiteSpeed Tech case HQFT_CANCEL_PUSH: 925392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_VARINT; 935392f7a3SLiteSpeed Tech break; 945392f7a3SLiteSpeed Tech case HQFT_MAX_PUSH_ID: 955392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_VARINT; 965392f7a3SLiteSpeed Tech break; 97fbc6cc04SDmitri Tikhonov case HQFT_PRIORITY_UPDATE_PUSH: 98fbc6cc04SDmitri Tikhonov case HQFT_PRIORITY_UPDATE_STREAM: 99fbc6cc04SDmitri Tikhonov reader->hr_state = HR_READ_VARINT; 100fbc6cc04SDmitri Tikhonov break; 1015392f7a3SLiteSpeed Tech case HQFT_DATA: 1025392f7a3SLiteSpeed Tech case HQFT_HEADERS: 1035392f7a3SLiteSpeed Tech case HQFT_PUSH_PROMISE: 10455d69529SGeorge Wang reader->hr_cb->on_frame_error(reader->hr_ctx, 10555d69529SGeorge Wang HEC_FRAME_UNEXPECTED, reader->hr_frame_type); 1065392f7a3SLiteSpeed Tech return -1; 1075392f7a3SLiteSpeed Tech default: 108758aff32SDmitri Tikhonov { 109758aff32SDmitri Tikhonov /* From [draft-ietf-quic-http-31] Section 7.2.8: 110758aff32SDmitri Tikhonov " Frame types of the format "0x1f * N + 0x21" for non-negative 111758aff32SDmitri Tikhonov " integer values of N are reserved to exercise the requirement 112758aff32SDmitri Tikhonov " that unknown types be ignored 113758aff32SDmitri Tikhonov */ 114758aff32SDmitri Tikhonov enum lsq_log_level L; 115758aff32SDmitri Tikhonov if (!(reader->hr_frame_type >= 0x21 && 116758aff32SDmitri Tikhonov (reader->hr_frame_type - 0x21) % 0x1F == 0)) 117758aff32SDmitri Tikhonov /* Non-grease: log with higher level: */ 118758aff32SDmitri Tikhonov L = LSQ_LOG_INFO; 119758aff32SDmitri Tikhonov else 120758aff32SDmitri Tikhonov L = LSQ_LOG_DEBUG; 121758aff32SDmitri Tikhonov LSQ_LOG(L, "unknown frame type 0x%"PRIX64": will skip " 122758aff32SDmitri Tikhonov "%"PRIu64" bytes", reader->hr_frame_type, 123758aff32SDmitri Tikhonov reader->hr_frame_length); 1245392f7a3SLiteSpeed Tech reader->hr_state = HR_SKIPPING; 1255392f7a3SLiteSpeed Tech break; 1265392f7a3SLiteSpeed Tech } 127758aff32SDmitri Tikhonov } 1285392f7a3SLiteSpeed Tech break; 1295392f7a3SLiteSpeed Tech case HR_READ_VARINT: 1305392f7a3SLiteSpeed Tech reader->hr_u.vint_state.pos = 0; 1315392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_VARINT_CONTINUE; 1325392f7a3SLiteSpeed Tech reader->hr_nread = 0; 1335392f7a3SLiteSpeed Tech /* fall-through */ 1345392f7a3SLiteSpeed Tech case HR_READ_VARINT_CONTINUE: 1355392f7a3SLiteSpeed Tech orig_p = p; 1365392f7a3SLiteSpeed Tech s = lsquic_varint_read_nb(&p, end, &reader->hr_u.vint_state); 1375392f7a3SLiteSpeed Tech reader->hr_nread += p - orig_p; 1385392f7a3SLiteSpeed Tech if (0 == s) 1395392f7a3SLiteSpeed Tech { 140fbc6cc04SDmitri Tikhonov switch (reader->hr_frame_type) 1415392f7a3SLiteSpeed Tech { 142fbc6cc04SDmitri Tikhonov case HQFT_GOAWAY: 143fbc6cc04SDmitri Tikhonov case HQFT_CANCEL_PUSH: 144fbc6cc04SDmitri Tikhonov case HQFT_MAX_PUSH_ID: 145fbc6cc04SDmitri Tikhonov if (reader->hr_nread != reader->hr_frame_length) 146fbc6cc04SDmitri Tikhonov { 147fbc6cc04SDmitri Tikhonov reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1, 148fbc6cc04SDmitri Tikhonov HEC_FRAME_ERROR, 149fbc6cc04SDmitri Tikhonov "Frame length does not match actual payload length"); 150fbc6cc04SDmitri Tikhonov reader->hr_state = HR_ERROR; 151fbc6cc04SDmitri Tikhonov return -1; 152fbc6cc04SDmitri Tikhonov } 153fbc6cc04SDmitri Tikhonov break; 1545392f7a3SLiteSpeed Tech } 1555392f7a3SLiteSpeed Tech switch (reader->hr_frame_type) 1565392f7a3SLiteSpeed Tech { 1575392f7a3SLiteSpeed Tech case HQFT_GOAWAY: 1585392f7a3SLiteSpeed Tech reader->hr_cb->on_goaway(reader->hr_ctx, 1595392f7a3SLiteSpeed Tech reader->hr_u.vint_state.val); 1605392f7a3SLiteSpeed Tech break; 1615392f7a3SLiteSpeed Tech case HQFT_CANCEL_PUSH: 1625392f7a3SLiteSpeed Tech reader->hr_cb->on_cancel_push(reader->hr_ctx, 1635392f7a3SLiteSpeed Tech reader->hr_u.vint_state.val); 1645392f7a3SLiteSpeed Tech break; 1655392f7a3SLiteSpeed Tech case HQFT_MAX_PUSH_ID: 1665392f7a3SLiteSpeed Tech reader->hr_cb->on_max_push_id(reader->hr_ctx, 1675392f7a3SLiteSpeed Tech reader->hr_u.vint_state.val); 1685392f7a3SLiteSpeed Tech break; 169fbc6cc04SDmitri Tikhonov case HQFT_PRIORITY_UPDATE_PUSH: 170fbc6cc04SDmitri Tikhonov case HQFT_PRIORITY_UPDATE_STREAM: 171fbc6cc04SDmitri Tikhonov len = reader->hr_frame_length - reader->hr_nread; 172fbc6cc04SDmitri Tikhonov if (len <= (uintptr_t) (end - p)) 173fbc6cc04SDmitri Tikhonov { 174fbc6cc04SDmitri Tikhonov reader->hr_cb->on_priority_update(reader->hr_ctx, 175fbc6cc04SDmitri Tikhonov reader->hr_frame_type, reader->hr_u.vint_state.val, 176fbc6cc04SDmitri Tikhonov (char *) p, len); 177fbc6cc04SDmitri Tikhonov p += len; 178fbc6cc04SDmitri Tikhonov } 179fbc6cc04SDmitri Tikhonov else if (len <= sizeof(reader->hr_u.prio_state.buf)) 180fbc6cc04SDmitri Tikhonov { 181fbc6cc04SDmitri Tikhonov reader->hr_frame_length = len; 182fbc6cc04SDmitri Tikhonov reader->hr_nread = 0; 183fbc6cc04SDmitri Tikhonov reader->hr_state = HR_READ_PRIORITY_UPDATE; 184fbc6cc04SDmitri Tikhonov goto continue_reading; 185fbc6cc04SDmitri Tikhonov } 186fbc6cc04SDmitri Tikhonov else 187fbc6cc04SDmitri Tikhonov { 188fbc6cc04SDmitri Tikhonov p += len; 189fbc6cc04SDmitri Tikhonov /* 16 bytes is more than enough for a PRIORITY_UPDATE 190fbc6cc04SDmitri Tikhonov * frame, anything larger than that is unreasonable. 191fbc6cc04SDmitri Tikhonov */ 192fbc6cc04SDmitri Tikhonov if (reader->hr_frame_length 193fbc6cc04SDmitri Tikhonov > sizeof(reader->hr_u.prio_state.buf)) 194fbc6cc04SDmitri Tikhonov LSQ_INFO("skip PRIORITY_UPDATE frame that's too " 195fbc6cc04SDmitri Tikhonov "long (%"PRIu64" bytes)", len); 196fbc6cc04SDmitri Tikhonov } 197fbc6cc04SDmitri Tikhonov break; 1985392f7a3SLiteSpeed Tech default: 1995392f7a3SLiteSpeed Tech assert(0); 2005392f7a3SLiteSpeed Tech } 2015392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_FRAME_BEGIN; 2025392f7a3SLiteSpeed Tech break; 2035392f7a3SLiteSpeed Tech } 2045392f7a3SLiteSpeed Tech else 2055392f7a3SLiteSpeed Tech { 2065392f7a3SLiteSpeed Tech assert(p == end); 2075392f7a3SLiteSpeed Tech return 0; 2085392f7a3SLiteSpeed Tech } 2095392f7a3SLiteSpeed Tech case HR_SKIPPING: 2105392f7a3SLiteSpeed Tech len = MIN((uintptr_t) (end - p), reader->hr_frame_length); 2115392f7a3SLiteSpeed Tech p += len; 2125392f7a3SLiteSpeed Tech reader->hr_frame_length -= len; 2135392f7a3SLiteSpeed Tech if (0 == reader->hr_frame_length) 2145392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_FRAME_BEGIN; 2155392f7a3SLiteSpeed Tech break; 2165392f7a3SLiteSpeed Tech case HR_READ_SETTING_BEGIN: 2175392f7a3SLiteSpeed Tech reader->hr_u.vint2_state.vr2s_state = 0; 2185392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_SETTING_CONTINUE; 2195392f7a3SLiteSpeed Tech /* fall-through */ 2205392f7a3SLiteSpeed Tech case HR_READ_SETTING_CONTINUE: 2215392f7a3SLiteSpeed Tech orig_p = p; 2225392f7a3SLiteSpeed Tech s = lsquic_varint_read_two(&p, end, &reader->hr_u.vint2_state); 2235392f7a3SLiteSpeed Tech reader->hr_nread += p - orig_p; 2245392f7a3SLiteSpeed Tech if (reader->hr_nread > reader->hr_frame_length) 2255392f7a3SLiteSpeed Tech { 2265392f7a3SLiteSpeed Tech reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1, 22792f6e17bSDmitri Tikhonov HEC_FRAME_ERROR, "SETTING frame contents too long"); 2285392f7a3SLiteSpeed Tech reader->hr_state = HR_ERROR; 2295392f7a3SLiteSpeed Tech return -1; 2305392f7a3SLiteSpeed Tech } 2315392f7a3SLiteSpeed Tech if (s < 0) 2325392f7a3SLiteSpeed Tech break; 2335392f7a3SLiteSpeed Tech reader->hr_cb->on_setting(reader->hr_ctx, 2345392f7a3SLiteSpeed Tech reader->hr_u.vint2_state.vr2s_one, 2355392f7a3SLiteSpeed Tech reader->hr_u.vint2_state.vr2s_two); 2365392f7a3SLiteSpeed Tech if (reader->hr_nread >= reader->hr_frame_length) 2375392f7a3SLiteSpeed Tech { 2385392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_FRAME_BEGIN; 2395392f7a3SLiteSpeed Tech reader->hr_cb->on_settings_frame(reader->hr_ctx); 2405392f7a3SLiteSpeed Tech } 2415392f7a3SLiteSpeed Tech else 2425392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_SETTING_BEGIN; 2435392f7a3SLiteSpeed Tech break; 244fbc6cc04SDmitri Tikhonov case HR_READ_PRIORITY_UPDATE: 245fbc6cc04SDmitri Tikhonov len = MIN((uintptr_t) (end - p), 246fbc6cc04SDmitri Tikhonov reader->hr_frame_length - reader->hr_nread); 247fbc6cc04SDmitri Tikhonov memcpy(reader->hr_u.prio_state.buf + reader->hr_nread, p, len); 248fbc6cc04SDmitri Tikhonov reader->hr_nread += len; 249fbc6cc04SDmitri Tikhonov p += len; 250fbc6cc04SDmitri Tikhonov if (reader->hr_frame_length == reader->hr_nread) 251fbc6cc04SDmitri Tikhonov { 252fbc6cc04SDmitri Tikhonov reader->hr_cb->on_priority_update(reader->hr_ctx, 253fbc6cc04SDmitri Tikhonov reader->hr_frame_type, reader->hr_u.vint_state.val, 254fbc6cc04SDmitri Tikhonov reader->hr_u.prio_state.buf, reader->hr_frame_length); 255fbc6cc04SDmitri Tikhonov reader->hr_state = HR_READ_FRAME_BEGIN; 256fbc6cc04SDmitri Tikhonov } 257fbc6cc04SDmitri Tikhonov break; 2585392f7a3SLiteSpeed Tech default: 2595392f7a3SLiteSpeed Tech assert(0); 2605392f7a3SLiteSpeed Tech /* fall-through */ 2615392f7a3SLiteSpeed Tech case HR_ERROR: 2625392f7a3SLiteSpeed Tech return -1; 2635392f7a3SLiteSpeed Tech } 2645392f7a3SLiteSpeed Tech } 2655392f7a3SLiteSpeed Tech 2665392f7a3SLiteSpeed Tech return 0; 2675392f7a3SLiteSpeed Tech} 268