Quic deser
a fake deserializer for quic
object quic_deser = {}
<<< member
class `quic_deser`;
>>>
<<< impl
typedef struct transport_error_struct {
const char *name;
int value;
} *transport_error_struct_ptr;
struct transport_error_map : hash_space::hash_map<std::string,int> {};
struct transport_error_struct transport_error_codes[17] = {
{"no_error",0x0},
{"internal_error",0x1},
{"server_busy",0x2},
{"flow_control_error",0x3},
{"stream_limit_error",0x4},
{"stream_state_error",0x5},
{"final_size_error",0x6},
{"frame_encoding_error",0x7},
{"transport_parameter_error",0x8},
{"connection_id_limit_error",0x9},
{"protocol_violation",0xa},
{"invalid_token",0xb},
{"application_error",0xc},
{"crypto_buffer_exceeded",0xd},
{"crypto_error",-1},
{0,0}
};
transport_error_map transport_error_codes_map;
void transport_error_name_map(transport_error_struct *vals, transport_error_map &map) {
while (vals->name) {
map[vals->name] = vals->value;
vals++;
}
}
//TODO
int scid_h = 8;
int dcid_h = 8;
class `quic_deser` : public ivy_binary_deser_128 {
//class `quic_deser` : public ivy_binary_deser {
enum {quic_s_init,
quic_s_type,
quic_s_version,
quic_s_dcil,
quic_s_scil,
quic_s_dcid,
quic_s_scid,
quic_s_retry_token_length,
quic_s_retry_token,
quic_s_payload_length,
quic_s_pkt_num,
quic_s_payload,
quic_stream_id,
quic_stream_off,
quic_stream_len,
quic_stream_fin,
quic_stream_offset,
quic_stream_length,
quic_stream_data,
quic_crypto_offset,
quic_crypto_length,
quic_crypto_data,
quic_ack_largest,
quic_ack_delay,
quic_ack_block_count,
quic_ack_gap,
quic_ack_block,
quic_reset_stream_id,
quic_reset_err_code,
quic_reset_final_offset,
quic_stop_sending_id,
quic_stop_sending_err_code,
quic_connection_close_err_code,
quic_connection_close_frame_type,
quic_connection_close_reason_length,
quic_connection_close_reason,
quic_application_close_err_code,
quic_max_stream_data_id,
quic_new_connection_id_length,
quic_new_connection_id_seq_num,
quic_new_connection_id_retire_prior_to,
quic_new_connection_id_scid,
quic_new_connection_id_token,
quic_path_challenge_data,
quic_retire_connection_id_seq_num,
quic_handshake_done,
quic_immediate_ack,
quic_ack_frequency, //seq_num
quic_ack_frequency_ack_eliciting_threshold,
quic_ack_frequency_request_max_ack_delay,
quic_ack_frequency_reordering_threshold,
quic_padding,
quic_unknow,
quic_ping,
quic_s_done} state;
bool long_format;
char hdr_type;
int dcil_long;
int dcil;
int scil;
long frame_type;
int data_remaining;
int128_t ack_blocks_expected;
int128_t ack_block_count;
//long long ack_blocks_expected;
//long long ack_block_count;
int payload_length;
int fence;
bool have_scid = false;
bool ecn = false;
int token_length;
int token_count = 0;
int token_len = 0;
public:
quic_deser(const std::vector<char> &inp) : ivy_binary_deser_128(inp),state(quic_s_init) {
//quic_deser(const std::vector<char> &inp) : ivy_binary_deser(inp),state(quic_s_init) {
// pos = 42; // skip 42 bytes of IP and UDP header
fence = 0;
}
virtual void get(int128_t &res) {
//virtual void get(long long &res) {
switch (state) {
case quic_s_init:
{
getn(res,1);
long_format = (res & 0x80) ? true : false;
//0x7f is 0111 1111 in binary. This means the lower 7 bits of res are significant.
//0x30 0011 0000
hdr_type = res & 0x7f; //0x7f;
//This is then shifted by 4 so that only the original 0xxx 0000 (3) bits are significant.
res = long_format ? ((hdr_type & 0x30) >> 4) : 3;
state = quic_s_version;
}
break;
case quic_s_version:
{
if (long_format) {
ivy_binary_deser_128::getn(res,4);
//ivy_binary_deser::getn(res,4);
}
else
res = 0;
state = quic_s_dcid;
}
break;
case quic_s_dcid:
{
if (long_format) {
int128_t cil;
//long long cil;
getn(cil,1);
std::cerr << "dstID size " << cil << "\n";
dcil = cil;
dcid_h = cil;
} else {
dcil = dcid_h; //dcil_long
}
getn(res,(dcil));
std::cerr << "dstID res " << res << "\n";
state = quic_s_scid;
}
break;
case quic_s_scid:
{
if (long_format) {
int128_t cil;
//long long cil;
getn(cil,1);
std::cerr << "sourceID size " << cil << "\n";
if(cil > 0)
have_scid = true;
else
have_scid = false;
scil = cil;
scid_h = cil;
} else {
scil = 0;
}
getn(res,scil);
/*if(scil != 8) { //tricks
tls_field_bytes_map["scid"] = scil;
}*/
std::cerr << "sourceID res " << res << "\n";
int128_t len;
//long long len;
if (long_format & ((hdr_type & 0x30) == 0x00)){
get_var_int(len);
}
else len = 0;
data_remaining = len;
std::cerr << "sourceID data_remaining " << data_remaining << "\n";
state = quic_s_retry_token;
}
break;
case quic_s_pkt_num:
{
fence = 0;
if (payload_length > 0) {
fence = pos + payload_length - QUIC_DESER_FAKE_CHECKSUM_LENGTH;
} else {
fence = inp.size() - QUIC_DESER_FAKE_CHECKSUM_LENGTH;
}
get_pkt_num(res);
state = quic_s_payload;
}
break;
case quic_stream_off:
{
res = (0x04 & frame_type) ? 1 : 0;
state = quic_stream_len;
}
break;
case quic_stream_len:
{
res = (0x02 & frame_type) ? 1 : 0;
state = quic_stream_fin;
}
break;
case quic_stream_fin:
{
res = (0x01 & frame_type) ? 1 : 0;
state = quic_stream_id;
}
break;
case quic_stream_id:
{
get_var_int(res);
state = quic_stream_offset;
}
break;
case quic_stream_offset:
{
if (0x04 & frame_type)
get_var_int(res);
else res = 0;
state = quic_stream_length;
}
break;
case quic_stream_length:
{
if (0x02 & frame_type)
get_var_int(res);
else {
res = fence - pos;
}
data_remaining = res;
state = quic_stream_data;
}
break;
case quic_crypto_offset:
{
get_var_int(res);
state = quic_crypto_length;
}
break;
case quic_crypto_length:
{
get_var_int(res);
data_remaining = res;
state = quic_crypto_data;
std::cerr << "quic_crypto_length \n";
}
break;
case quic_stream_data:
case quic_crypto_data:
case quic_path_challenge_data:
case quic_connection_close_reason:
case quic_padding:
case quic_ping:
case quic_unknow:
case quic_handshake_done: // TODO ?
case quic_immediate_ack:
case quic_s_retry_token:
{
//std::cerr << "sourceID quic_s_retry_token 1 " << std::hex << res << "\n";
ivy_binary_deser_128::getn(res,1);
//ivy_binary_deser::getn(res,1);
/*if(const char* env_p3 = std::getenv("RETRY_TOKEN_LENGTH")) {
std::cerr << "RETRY_TOKEN_LENGTH " << env_p3 << "\n";
token_len = atoi(env_p3);
}
if(token_count == 0)
token_len = token_length;
std::cerr << "token_count " << token_count << "\n";
if(token_count < token_len){
getn(res,1);
token_count += 1;
if(token_count == token_len)
state = quic_s_pkt_num;
else
state = quic_s_retry_token; //useless ?
}
else
state = quic_s_pkt_num;*/
// std::cerr << "sourceID quic_s_retry_token 2" << std::hex << res << "\n";
}
break;
case quic_ack_largest:
{
get_var_int(res);
state = quic_ack_delay;
}
break;
case quic_ack_delay:
{
get_var_int(res);
state = quic_ack_block_count;
}
break;
case quic_ack_gap:
{
if (ack_block_count == 0)
res = 0; // first ack block has no gap
else
get_var_int(res);
state = quic_ack_block;
}
break;
case quic_ack_block:
{
get_var_int(res);
state = quic_ack_gap;
ack_block_count++;
}
break;
case quic_reset_stream_id:
{
get_var_int(res);
state = quic_reset_err_code;
}
break;
case quic_reset_err_code:
{
get_var_int(res);
state = quic_reset_final_offset;
}
break;
case quic_reset_final_offset:
{
get_var_int(res);
}
break;
case quic_stop_sending_id:
{
get_var_int(res);
state = quic_stop_sending_err_code;
}
break;
case quic_stop_sending_err_code:
{
get_var_int(res);
}
break;
case quic_connection_close_err_code:
{
get_var_int(res);
state = quic_connection_close_frame_type;
}
break;
case quic_connection_close_frame_type:
{
get_var_int(res);
state = quic_connection_close_reason_length;
}
break;
case quic_connection_close_reason_length:
{
get_var_int(res);
data_remaining = res;
state = quic_connection_close_reason;
}
break;
case quic_application_close_err_code:
{
get_var_int(res);
state = quic_connection_close_reason_length;
}
break;
case quic_max_stream_data_id:
{
get_var_int(res);
state = quic_reset_final_offset;
}
break;
case quic_new_connection_id_length:
{
getn(res,1);
scil = res;
state = quic_new_connection_id_scid;
}
break;
case quic_new_connection_id_seq_num:
{
get_var_int(res);
state = quic_new_connection_id_retire_prior_to;
}
break;
case quic_new_connection_id_retire_prior_to:
{
get_var_int(res);
state = quic_new_connection_id_length;
}
break;
case quic_new_connection_id_scid:
{
getn(res,scil);
state = quic_new_connection_id_token;
}
break;
case quic_new_connection_id_token:
{
getn(res,16);
}
break;
case quic_retire_connection_id_seq_num:
{
get_var_int(res);
}
break;
case quic_ack_frequency: //TODO
{
get_var_int(res);
std::cerr << "deser: quic_ack_frequency = quic_ack_frequency\n";
state = quic_ack_frequency_ack_eliciting_threshold;
}
break;
case quic_ack_frequency_ack_eliciting_threshold:
{
get_var_int(res);
std::cerr << "deser: quic_ack_frequency = quic_ack_frequency_ack_eliciting_threshold\n";
state = quic_ack_frequency_request_max_ack_delay;
}
break;
case quic_ack_frequency_request_max_ack_delay:
{
get_var_int(res);
std::cerr << "deser: quic_ack_frequency = quic_ack_frequency_request_max_ack_delay\n";
state = quic_ack_frequency_reordering_threshold;
}
break;
case quic_ack_frequency_reordering_threshold:
{
std::cerr << "deser: quic_ack_frequency = quic_ack_frequency_reordering_threshold\n";
//getn(res,1);
get_var_int(res);
}
break;
default:
std::cerr << "quic_deser 3\n";
throw deser_err();
}
}
void get_var_int(int128_t &res) {
//void get_var_int(long long &res) {
static int lens[4] = {0,1,3,7};
int128_t lobyte;
ivy_binary_deser_128::getn(lobyte,1);
//long long lobyte;
//ivy_binary_deser::getn(lobyte,1);
int bytes = lens[(lobyte & 0xc0) >> 6];
ivy_binary_deser_128::getn(res,bytes);
//ivy_binary_deser::getn(res,bytes);
res |= (lobyte & 0x3f) << (bytes << 3);
}
void get_pkt_num(int128_t &res) {
ivy_binary_deser_128::getn(res,(hdr_type & 3)+1);
// void get_pkt_num(long long &res) {
// ivy_binary_deser::getn(res,(hdr_type & 3)+1);
return;
static int lens[4] = {0,0,1,3};
int128_t lobyte;
ivy_binary_deser_128::getn(lobyte,1);
//long long lobyte;
//ivy_binary_deser::getn(lobyte,1);
int bytes = lens[(lobyte & 0xc0) >> 6];
if (bytes == 0) {
res = lobyte;
return;
}
ivy_binary_deser_128::getn(res,bytes);
//ivy_binary_deser::getn(res,bytes);
res |= (lobyte & 0x3f) << (bytes << 3);
}
virtual int open_tag(const std::vector<std::string> &tags) {
if (state == quic_s_payload) {
int128_t ft;
ivy_binary_deser_128::getn(ft,1); // could be bigger
//long long ft;
//ivy_binary_deser::getn(ft,1); // could be bigger
/*
TODO we should get varint and then parse in consequence like in tls_deser_ser
*/
frame_type = ft;
std::cerr << "recv frame_type = " << frame_type << "\n";
if (frame_type == 0x01) {
state = quic_ping;
return 0;
}
if (frame_type == 0x02) { //JF
ecn = false;
state = quic_ack_largest;
return 1;
}
if (frame_type == 0x03) {
ecn = true;
state = quic_ack_largest;
return 2;
}
if (frame_type == 0x04) {
state = quic_reset_stream_id;
return 3;
}
if (frame_type == 0x05) {
state = quic_stop_sending_id; // stream_blocked equivalent to this
return 4;
}
if (frame_type == 0x06) {
state = quic_crypto_offset;
return 5;
}
if (frame_type == 0x07) { // new token frame
state = quic_crypto_length; // new token equivalent to this
return 6;
}
if (frame_type >= 0x08 && frame_type <= 0x0f) {
state = quic_stream_off;
return 7;
}
if (frame_type == 0x10) { // new token frame
state = quic_reset_final_offset; // max_data equivalent to this
return 8;
}
if (frame_type == 0x11) {
state = quic_max_stream_data_id;
return 9;
}
if (frame_type == 0x12) { //JF
state = quic_reset_stream_id; // max_stream_id state equivalent to this
return 10;
}
if (frame_type == 0x13) {
state = quic_reset_stream_id; // max_stream_id state equivalent to this
return 11;
}
if (frame_type == 0x14) {
state = quic_reset_final_offset; // blocked equivalent to this
return 12;
}
if (frame_type == 0x15) {
state = quic_max_stream_data_id; // stream_blocked equivalent to this
return 13;
}
if (frame_type == 0x16) {
state = quic_reset_final_offset;
return 14;
}
if (frame_type == 0x17) {
state = quic_reset_final_offset;
return 15;
}
if (frame_type == 0x18) {
state = quic_new_connection_id_seq_num;
return 16;
}
if (frame_type == 0x19) {
state = quic_retire_connection_id_seq_num;
return 17;
}
if (frame_type == 0x1a) {
data_remaining = 8;
state = quic_path_challenge_data;
return 18;
}
if (frame_type == 0x1b) {
data_remaining = 8;
state = quic_path_challenge_data;
return 19;
}
if (frame_type == 0x1c) {
state = quic_connection_close_err_code;
return 20;
}
if (frame_type == 0x1d) {
state = quic_application_close_err_code;
return 21;
}
if (frame_type == 0x1e) {
state = quic_handshake_done;
return 22;
}
if (frame_type == 0x40) {
ft = 0;
//ivy_binary_deser::getn(ft,1); // could be bigger
ivy_binary_deser_128::getn(ft,1); // could be bigger
frame_type = ft;
if (frame_type == 0xAF) { //0x40af
state = quic_ack_frequency;
return 23;
}
if (frame_type == 0xAC) { //0x40af
state = quic_immediate_ack;
return 24;
}
if (frame_type == 0x42) {
state = quic_unknow;
return 25;
}
}
/*if (frame_type == 0x00) {
state = quic_padding;
return 25;
}*/
std::cerr << "saw tag " << ft << "\n";
}
std::cerr << "state = " << state << "\n";
std::cerr << "quic_s_payload = " << quic_s_payload << "\n";
std::cerr << "quic_s_payload == " << (quic_s_payload == state) << "\n";
std::cerr << "quic_deser 2\n";
throw deser_err();
}
virtual bool open_list_elem() {
if (state == quic_s_payload) {
// We must use/take in count the padding frame since Picoquic client sometimes send packet
// only with 1 padding frame which make fails the requirement saying that a
// packet cannot be empty
while ((fence == 0 || pos < fence) && more(1) && inp[pos] == 0)
pos++; // skip padding frames
return (fence == 0 || pos < fence) && more(1);
}
if (state == quic_ack_gap) {
return ack_block_count < ack_blocks_expected;
}
if (state == quic_stream_data)
return data_remaining--> 0;
if (state == quic_connection_close_reason)
return data_remaining--> 0;
if (state == quic_s_retry_token)
return data_remaining--> 0;
//if (state == quic_s_retry_token) {
// We must use/take in count the padding frame since Picoquic client sometimes send packet
// only with 1 padding frame which make fails the requirement saying that a
// packet cannot be empty
/*while ((fence == 0 || pos < fence) && more(1) && inp[pos] == 0)
pos++; // skip padding frames
*/
//return token_count < token_len; //(fence == 0 || pos < fence) && more(1);
//}
if (state == quic_crypto_data)
return data_remaining--> 0;
if (state == quic_path_challenge_data)
return data_remaining--> 0;
if (state == quic_s_init)
return more(1);
//TODO
if (state == quic_ack_frequency_reordering_threshold)
return data_remaining--> 0;
if (state == quic_ack_frequency)
return data_remaining--> 0;
if (state == quic_ack_frequency_request_max_ack_delay)
return data_remaining--> 0;
if (state == quic_ack_frequency_ack_eliciting_threshold)
return data_remaining--> 0;
std::cerr << "quic_deser 1\n";
throw deser_err();
}
void open_list() {
if (state == quic_ack_block_count) {
get_var_int(ack_blocks_expected);
ack_blocks_expected++; // block count doesn't include first
ack_block_count = 0;
state = quic_ack_gap;
}
}
void close_list() {
if (state == quic_s_payload) {
state = quic_s_init;
pos += QUIC_DESER_FAKE_CHECKSUM_LENGTH; // skip the fake checksum
}
if (state == quic_s_retry_token) {
int128_t len;
//long long len;
if (long_format) {
get_var_int(len);
} else {
len = 0;
}
payload_length = len;
state = quic_s_pkt_num;
}
}
void close_list_elem() {}
virtual void close_tag() {
state = quic_s_payload;
}
~quic_deser(){}
};
>>>
<<< init
transport_error_name_map(transport_error_codes,transport_error_codes_map);
>>>