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