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++;
        }
    }
define QUIC_DESER_FAKE_CHECKSUM_LENGTH 0
    //TODO
define QUOTEME(x) QUOTEME_1(x) define QUOTEME_1(x) #x define QUIC_SER_DESER_HEADER_PATH PANTHER_IVY_BASE_DIR/quic_utils/quic_ser_deser.h include QUOTEME(QUIC_SER_DESER_HEADER_PATH)
    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);

>>>