Line data Source code
1 : // QUIC parsers 2 : 3 : // TODO add platform optimized versions of these 4 : // e.g. 32 bit unaligned fetch w/ byte swap on intel 5 27328105 : #define FD_TEMPL_PARSE_IMPL_uchar(p) ( \ 6 27328105 : ( (uchar)((p)[0]) ) ) 7 12 : #define FD_TEMPL_PARSE_IMPL_ushort(p) ( \ 8 12 : ( (ushort)((p)[0]) << (ushort)0x08 ) + \ 9 12 : ( (ushort)((p)[1]) << (ushort)0x00 ) ) 10 3060741 : #define FD_TEMPL_PARSE_IMPL_uint(p) ( \ 11 3060741 : ( (uint)((p)[0]) << (uint)0x18 ) + \ 12 3060741 : ( (uint)((p)[1]) << (uint)0x10 ) + \ 13 3060741 : ( (uint)((p)[2]) << (uint)0x08 ) + \ 14 3060741 : ( (uint)((p)[3]) << (uint)0x00 ) ) 15 : #define FD_TEMPL_PARSE_IMPL_ulong(p) ( \ 16 : ( (ulong)((p)[0]) << (ulong)0x38 ) + \ 17 : ( (ulong)((p)[1]) << (ulong)0x30 ) + \ 18 : ( (ulong)((p)[2]) << (ulong)0x28 ) + \ 19 : ( (ulong)((p)[3]) << (ulong)0x20 ) + \ 20 : ( (ulong)((p)[4]) << (ulong)0x18 ) + \ 21 : ( (ulong)((p)[5]) << (ulong)0x10 ) + \ 22 : ( (ulong)((p)[6]) << (ulong)0x08 ) + \ 23 : ( (ulong)((p)[7]) << (ulong)0x00 ) ) 24 : 25 : /* assigns parsed value 26 : result is the size of the type */ 27 : #define FD_TEMPL_PARSE(TYPE,VAR,p) \ 28 30388894 : ( ( (VAR) = (__typeof__((VAR)))FD_TEMPL_PARSE_IMPL_##TYPE((p)) ), sizeof(fd_quic_##TYPE) ) 29 : 30 : 31 : // returns bytes consumed 32 : #define FD_TEMPL_DEF_STRUCT_BEGIN(NAME) \ 33 : ulong fd_quic_decode_##NAME( fd_quic_##NAME##_t * FD_RESTRICT out, \ 34 : uchar const * FD_RESTRICT buf, \ 35 66785409 : ulong sz ) { \ 36 66785409 : (void)out; (void)buf; (void)sz; \ 37 66785409 : ulong cur_byte = 0; \ 38 66785409 : ulong tmp_len = 0; (void)tmp_len; \ 39 : // TODO check min size here 40 : 41 : // consumes single aligned byte in input 42 : #define FD_TEMPL_MBR_FRAME_TYPE(NAME,ID_LO,ID_HI) \ 43 45548885 : out->NAME = buf[cur_byte]; \ 44 45548885 : cur_byte++; 45 : 46 : 47 : // consumes aligned bytes in input 48 : #define FD_TEMPL_MBR_ELEM(NAME,TYPE) \ 49 30388678 : if( FD_UNLIKELY( cur_byte + sizeof(fd_quic_##TYPE) > sz ) ) \ 50 30388678 : return FD_QUIC_PARSE_FAIL; \ 51 30388678 : cur_byte += FD_TEMPL_PARSE(TYPE,out->NAME,buf+cur_byte); 52 : 53 : 54 : // always aligned 55 : // packet numbers have special parsing, due to being protected by 56 : // header protection 57 : // stores the offset for packet processing 58 : #define FD_TEMPL_MBR_ELEM_PKTNUM(NAME,TYPE) \ 59 18202432 : if( FD_UNLIKELY( cur_byte >= sz ) ) return FD_QUIC_PARSE_FAIL; \ 60 18202432 : out->NAME##_pnoff = (unsigned)cur_byte; 61 : 62 : 63 : // consumes varint 64 : // always aligned 65 : // most significant two bits represent the width of the int 66 : // remaining bits are all data bits 67 : #define FD_TEMPL_MBR_ELEM_VARINT(NAME,TYPE) \ 68 52064363 : do { \ 69 52064363 : out->NAME = 0; \ 70 52064363 : if( FD_UNLIKELY( cur_byte >= sz ) ) return FD_QUIC_PARSE_FAIL; \ 71 52064363 : uint msb2 = buf[cur_byte] >> 6u; \ 72 52064018 : uint vsz = 1U<<msb2; \ 73 52064018 : if( FD_UNLIKELY( cur_byte+vsz > sz ) ) return FD_QUIC_PARSE_FAIL; \ 74 52064018 : out->NAME = (fd_quic_##TYPE)fd_quic_varint_decode( buf+cur_byte, msb2 ); \ 75 52063706 : cur_byte += vsz; \ 76 52063706 : } while(0); 77 : 78 : 79 : // VAR currently assumed to be aligned bytes 80 : // BITS_MIN and BITS_MAX are always divisible by 8 81 : #define FD_TEMPL_MBR_ELEM_VAR(NAME,BITS_MIN,BITS_MAX,LEN_NAME) \ 82 24312838 : tmp_len = out->LEN_NAME; \ 83 24312838 : if( FD_UNLIKELY( ( tmp_len < (ulong)(BITS_MIN / 8) ) || \ 84 24312838 : ( tmp_len > (ulong)(BITS_MAX / 8) ) ) ) { \ 85 996 : return FD_QUIC_PARSE_FAIL; \ 86 996 : } \ 87 24312838 : if( FD_UNLIKELY( cur_byte + tmp_len > sz )) { \ 88 207 : return FD_QUIC_PARSE_FAIL; \ 89 207 : } \ 90 242676471 : for( ulong j=0; j<tmp_len; ++j ) { \ 91 218364836 : out->NAME[j] = buf[cur_byte+j]; \ 92 218364836 : } \ 93 24311635 : cur_byte += tmp_len; 94 : 95 : 96 : // VAR currently assumed to be aligned bytes 97 : // BITS_MIN and BITS_MAX are always divisible by 8 98 : #define FD_TEMPL_MBR_ELEM_VAR_RAW(NAME,BITS_MIN,BITS_MAX,LEN_NAME) \ 99 0 : tmp_len = out->LEN_NAME; \ 100 0 : if( FD_UNLIKELY( ( tmp_len < (ulong)(BITS_MIN / 8) ) || \ 101 0 : ( tmp_len > (ulong)(BITS_MAX / 8) ) ) ) { \ 102 0 : return FD_QUIC_PARSE_FAIL; \ 103 0 : } \ 104 0 : if( FD_UNLIKELY( cur_byte + tmp_len > sz )) { \ 105 0 : return FD_QUIC_PARSE_FAIL; \ 106 0 : } \ 107 0 : out->NAME = &buf[cur_byte]; \ 108 0 : cur_byte += tmp_len; 109 : 110 : 111 : /* ARRAY is an array of elements, each of the same size, 112 : with length implied by the packet size */ 113 : #define FD_TEMPL_MBR_ELEM_ARRAY(NAME,TYPE,BYTES_MIN,BYTES_MAX) \ 114 : tmp_len = sz - cur_byte; \ 115 : if( FD_UNLIKELY( tmp_len > BYTES_MAX ) ) \ 116 : tmp_len = BYTES_MAX; \ 117 : if( FD_UNLIKELY( tmp_len % sizeof(fd_quic_##TYPE) ) ) \ 118 : return FD_QUIC_PARSE_FAIL; \ 119 : tmp_len /= sizeof(fd_quic_##TYPE); \ 120 : out->NAME##_len = (__typeof__(out->NAME##_len))tmp_len; \ 121 : for( ulong j=0; j<tmp_len; ++j ) { \ 122 : cur_byte += FD_TEMPL_PARSE(TYPE,out->NAME[j],buf+cur_byte); \ 123 : } 124 : 125 : /* FIXED is an array of elements, each of the same size, 126 : with length constant */ 127 : #define FD_TEMPL_MBR_ELEM_FIXED(NAME,TYPE,BYTES) \ 128 18 : if( FD_UNLIKELY( cur_byte+BYTES>sz ) ) return FD_QUIC_PARSE_FAIL; \ 129 18 : tmp_len = BYTES / sizeof(fd_quic_##TYPE); \ 130 18 : if( FD_UNLIKELY( tmp_len * sizeof( fd_quic_##TYPE ) > \ 131 18 : sizeof( out->NAME ) ) ) return FD_QUIC_PARSE_FAIL; \ 132 234 : for( ulong j=0; j<tmp_len; ++j ) { \ 133 216 : cur_byte += FD_TEMPL_PARSE(TYPE,out->NAME[j],buf+cur_byte); \ 134 216 : } 135 : 136 : #define FD_TEMPL_MBR_OPT(TYPE_NAME,NAME,MASK,...) \ 137 126757251 : do { \ 138 126757251 : _Bool cond = out->TYPE_NAME & (MASK); \ 139 126757251 : out->NAME##_opt = cond; \ 140 126757251 : if( cond ) { \ 141 157279994 : __VA_ARGS__ \ 142 59343100 : } \ 143 126757251 : } while(0); 144 : 145 : 146 : // at end, return the number of bytes consumed 147 : #define FD_TEMPL_DEF_STRUCT_END(NAME) \ 148 66752535 : return cur_byte; \ 149 66783642 : } 150 : 151 : #include "fd_quic_dft.h" 152 :