lsquic_hcsi_reader.c revision 758aff32
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: 98758aff32SDmitri Tikhonov { 99758aff32SDmitri Tikhonov /* From [draft-ietf-quic-http-31] Section 7.2.8: 100758aff32SDmitri Tikhonov " Frame types of the format "0x1f * N + 0x21" for non-negative 101758aff32SDmitri Tikhonov " integer values of N are reserved to exercise the requirement 102758aff32SDmitri Tikhonov " that unknown types be ignored 103758aff32SDmitri Tikhonov */ 104758aff32SDmitri Tikhonov enum lsq_log_level L; 105758aff32SDmitri Tikhonov if (!(reader->hr_frame_type >= 0x21 && 106758aff32SDmitri Tikhonov (reader->hr_frame_type - 0x21) % 0x1F == 0)) 107758aff32SDmitri Tikhonov /* Non-grease: log with higher level: */ 108758aff32SDmitri Tikhonov L = LSQ_LOG_INFO; 109758aff32SDmitri Tikhonov else 110758aff32SDmitri Tikhonov L = LSQ_LOG_DEBUG; 111758aff32SDmitri Tikhonov LSQ_LOG(L, "unknown frame type 0x%"PRIX64": will skip " 112758aff32SDmitri Tikhonov "%"PRIu64" bytes", reader->hr_frame_type, 113758aff32SDmitri Tikhonov reader->hr_frame_length); 1145392f7a3SLiteSpeed Tech reader->hr_state = HR_SKIPPING; 1155392f7a3SLiteSpeed Tech break; 1165392f7a3SLiteSpeed Tech } 117758aff32SDmitri Tikhonov } 1185392f7a3SLiteSpeed Tech break; 1195392f7a3SLiteSpeed Tech case HR_READ_VARINT: 1205392f7a3SLiteSpeed Tech reader->hr_u.vint_state.pos = 0; 1215392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_VARINT_CONTINUE; 1225392f7a3SLiteSpeed Tech reader->hr_nread = 0; 1235392f7a3SLiteSpeed Tech /* fall-through */ 1245392f7a3SLiteSpeed Tech case HR_READ_VARINT_CONTINUE: 1255392f7a3SLiteSpeed Tech orig_p = p; 1265392f7a3SLiteSpeed Tech s = lsquic_varint_read_nb(&p, end, &reader->hr_u.vint_state); 1275392f7a3SLiteSpeed Tech reader->hr_nread += p - orig_p; 1285392f7a3SLiteSpeed Tech if (0 == s) 1295392f7a3SLiteSpeed Tech { 130fbc6cc04SDmitri Tikhonov switch (reader->hr_frame_type) 1315392f7a3SLiteSpeed Tech { 132fbc6cc04SDmitri Tikhonov case HQFT_GOAWAY: 133fbc6cc04SDmitri Tikhonov case HQFT_CANCEL_PUSH: 134fbc6cc04SDmitri Tikhonov case HQFT_MAX_PUSH_ID: 135fbc6cc04SDmitri Tikhonov if (reader->hr_nread != reader->hr_frame_length) 136fbc6cc04SDmitri Tikhonov { 137fbc6cc04SDmitri Tikhonov reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1, 138fbc6cc04SDmitri Tikhonov HEC_FRAME_ERROR, 139fbc6cc04SDmitri Tikhonov "Frame length does not match actual payload length"); 140fbc6cc04SDmitri Tikhonov reader->hr_state = HR_ERROR; 141fbc6cc04SDmitri Tikhonov return -1; 142fbc6cc04SDmitri Tikhonov } 143fbc6cc04SDmitri Tikhonov break; 1445392f7a3SLiteSpeed Tech } 1455392f7a3SLiteSpeed Tech switch (reader->hr_frame_type) 1465392f7a3SLiteSpeed Tech { 1475392f7a3SLiteSpeed Tech case HQFT_GOAWAY: 1485392f7a3SLiteSpeed Tech reader->hr_cb->on_goaway(reader->hr_ctx, 1495392f7a3SLiteSpeed Tech reader->hr_u.vint_state.val); 1505392f7a3SLiteSpeed Tech break; 1515392f7a3SLiteSpeed Tech case HQFT_CANCEL_PUSH: 1525392f7a3SLiteSpeed Tech reader->hr_cb->on_cancel_push(reader->hr_ctx, 1535392f7a3SLiteSpeed Tech reader->hr_u.vint_state.val); 1545392f7a3SLiteSpeed Tech break; 1555392f7a3SLiteSpeed Tech case HQFT_MAX_PUSH_ID: 1565392f7a3SLiteSpeed Tech reader->hr_cb->on_max_push_id(reader->hr_ctx, 1575392f7a3SLiteSpeed Tech reader->hr_u.vint_state.val); 1585392f7a3SLiteSpeed Tech break; 159fbc6cc04SDmitri Tikhonov case HQFT_PRIORITY_UPDATE_PUSH: 160fbc6cc04SDmitri Tikhonov case HQFT_PRIORITY_UPDATE_STREAM: 161fbc6cc04SDmitri Tikhonov len = reader->hr_frame_length - reader->hr_nread; 162fbc6cc04SDmitri Tikhonov if (len <= (uintptr_t) (end - p)) 163fbc6cc04SDmitri Tikhonov { 164fbc6cc04SDmitri Tikhonov reader->hr_cb->on_priority_update(reader->hr_ctx, 165fbc6cc04SDmitri Tikhonov reader->hr_frame_type, reader->hr_u.vint_state.val, 166fbc6cc04SDmitri Tikhonov (char *) p, len); 167fbc6cc04SDmitri Tikhonov p += len; 168fbc6cc04SDmitri Tikhonov } 169fbc6cc04SDmitri Tikhonov else if (len <= sizeof(reader->hr_u.prio_state.buf)) 170fbc6cc04SDmitri Tikhonov { 171fbc6cc04SDmitri Tikhonov reader->hr_frame_length = len; 172fbc6cc04SDmitri Tikhonov reader->hr_nread = 0; 173fbc6cc04SDmitri Tikhonov reader->hr_state = HR_READ_PRIORITY_UPDATE; 174fbc6cc04SDmitri Tikhonov goto continue_reading; 175fbc6cc04SDmitri Tikhonov } 176fbc6cc04SDmitri Tikhonov else 177fbc6cc04SDmitri Tikhonov { 178fbc6cc04SDmitri Tikhonov p += len; 179fbc6cc04SDmitri Tikhonov /* 16 bytes is more than enough for a PRIORITY_UPDATE 180fbc6cc04SDmitri Tikhonov * frame, anything larger than that is unreasonable. 181fbc6cc04SDmitri Tikhonov */ 182fbc6cc04SDmitri Tikhonov if (reader->hr_frame_length 183fbc6cc04SDmitri Tikhonov > sizeof(reader->hr_u.prio_state.buf)) 184fbc6cc04SDmitri Tikhonov LSQ_INFO("skip PRIORITY_UPDATE frame that's too " 185fbc6cc04SDmitri Tikhonov "long (%"PRIu64" bytes)", len); 186fbc6cc04SDmitri Tikhonov } 187fbc6cc04SDmitri Tikhonov break; 1885392f7a3SLiteSpeed Tech default: 1895392f7a3SLiteSpeed Tech assert(0); 1905392f7a3SLiteSpeed Tech } 1915392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_FRAME_BEGIN; 1925392f7a3SLiteSpeed Tech break; 1935392f7a3SLiteSpeed Tech } 1945392f7a3SLiteSpeed Tech else 1955392f7a3SLiteSpeed Tech { 1965392f7a3SLiteSpeed Tech assert(p == end); 1975392f7a3SLiteSpeed Tech return 0; 1985392f7a3SLiteSpeed Tech } 1995392f7a3SLiteSpeed Tech case HR_SKIPPING: 2005392f7a3SLiteSpeed Tech len = MIN((uintptr_t) (end - p), reader->hr_frame_length); 2015392f7a3SLiteSpeed Tech p += len; 2025392f7a3SLiteSpeed Tech reader->hr_frame_length -= len; 2035392f7a3SLiteSpeed Tech if (0 == reader->hr_frame_length) 2045392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_FRAME_BEGIN; 2055392f7a3SLiteSpeed Tech break; 2065392f7a3SLiteSpeed Tech case HR_READ_SETTING_BEGIN: 2075392f7a3SLiteSpeed Tech reader->hr_u.vint2_state.vr2s_state = 0; 2085392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_SETTING_CONTINUE; 2095392f7a3SLiteSpeed Tech /* fall-through */ 2105392f7a3SLiteSpeed Tech case HR_READ_SETTING_CONTINUE: 2115392f7a3SLiteSpeed Tech orig_p = p; 2125392f7a3SLiteSpeed Tech s = lsquic_varint_read_two(&p, end, &reader->hr_u.vint2_state); 2135392f7a3SLiteSpeed Tech reader->hr_nread += p - orig_p; 2145392f7a3SLiteSpeed Tech if (reader->hr_nread > reader->hr_frame_length) 2155392f7a3SLiteSpeed Tech { 2165392f7a3SLiteSpeed Tech reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1, 21792f6e17bSDmitri Tikhonov HEC_FRAME_ERROR, "SETTING frame contents too long"); 2185392f7a3SLiteSpeed Tech reader->hr_state = HR_ERROR; 2195392f7a3SLiteSpeed Tech return -1; 2205392f7a3SLiteSpeed Tech } 2215392f7a3SLiteSpeed Tech if (s < 0) 2225392f7a3SLiteSpeed Tech break; 2235392f7a3SLiteSpeed Tech reader->hr_cb->on_setting(reader->hr_ctx, 2245392f7a3SLiteSpeed Tech reader->hr_u.vint2_state.vr2s_one, 2255392f7a3SLiteSpeed Tech reader->hr_u.vint2_state.vr2s_two); 2265392f7a3SLiteSpeed Tech if (reader->hr_nread >= reader->hr_frame_length) 2275392f7a3SLiteSpeed Tech { 2285392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_FRAME_BEGIN; 2295392f7a3SLiteSpeed Tech reader->hr_cb->on_settings_frame(reader->hr_ctx); 2305392f7a3SLiteSpeed Tech } 2315392f7a3SLiteSpeed Tech else 2325392f7a3SLiteSpeed Tech reader->hr_state = HR_READ_SETTING_BEGIN; 2335392f7a3SLiteSpeed Tech break; 234fbc6cc04SDmitri Tikhonov case HR_READ_PRIORITY_UPDATE: 235fbc6cc04SDmitri Tikhonov len = MIN((uintptr_t) (end - p), 236fbc6cc04SDmitri Tikhonov reader->hr_frame_length - reader->hr_nread); 237fbc6cc04SDmitri Tikhonov memcpy(reader->hr_u.prio_state.buf + reader->hr_nread, p, len); 238fbc6cc04SDmitri Tikhonov reader->hr_nread += len; 239fbc6cc04SDmitri Tikhonov p += len; 240fbc6cc04SDmitri Tikhonov if (reader->hr_frame_length == reader->hr_nread) 241fbc6cc04SDmitri Tikhonov { 242fbc6cc04SDmitri Tikhonov reader->hr_cb->on_priority_update(reader->hr_ctx, 243fbc6cc04SDmitri Tikhonov reader->hr_frame_type, reader->hr_u.vint_state.val, 244fbc6cc04SDmitri Tikhonov reader->hr_u.prio_state.buf, reader->hr_frame_length); 245fbc6cc04SDmitri Tikhonov reader->hr_state = HR_READ_FRAME_BEGIN; 246fbc6cc04SDmitri Tikhonov } 247fbc6cc04SDmitri Tikhonov break; 2485392f7a3SLiteSpeed Tech default: 2495392f7a3SLiteSpeed Tech assert(0); 2505392f7a3SLiteSpeed Tech /* fall-through */ 2515392f7a3SLiteSpeed Tech case HR_ERROR: 2525392f7a3SLiteSpeed Tech return -1; 2535392f7a3SLiteSpeed Tech } 2545392f7a3SLiteSpeed Tech } 2555392f7a3SLiteSpeed Tech 2565392f7a3SLiteSpeed Tech return 0; 2575392f7a3SLiteSpeed Tech} 258