Line data Source code
1 : // QUIC encoders
2 :
3 : /* TODO replace FD_QUIC_PARSE_FAIL with FD_QUIC_ENCODE_FAIL */
4 :
5 : /* TODO add platform optimized versions of these
6 : e.g. 32 bit unaligned fetch w/ byte swap on intel */
7 28469495 : #define FD_TEMPL_ENCODE_IMPL_uchar(p,val) ( \
8 28469495 : ( (p)[0] = (uchar)( (val) ) ) )
9 12 : #define FD_TEMPL_ENCODE_IMPL_ushort(p,val) ( \
10 12 : ( (p)[0] = (uchar)( (ushort)(val) >> (ushort)0x08 ) ), \
11 12 : ( (p)[1] = (uchar)( (ushort)(val) >> (ushort)0x00 ) ) )
12 3025134 : #define FD_TEMPL_ENCODE_IMPL_uint(p,val) ( \
13 3025134 : ( (p)[0] = (uchar)( (uint)(val) >> (uint)0x18 ) ), \
14 3025134 : ( (p)[1] = (uchar)( (uint)(val) >> (uint)0x10 ) ), \
15 3025134 : ( (p)[2] = (uchar)( (uint)(val) >> (uint)0x08 ) ), \
16 3025134 : ( (p)[3] = (uchar)( (uint)(val) >> (uint)0x00 ) ) )
17 : #define FD_TEMPL_ENCODE_IMPL_ulong(p,val) ( \
18 : ( (p)[0] = (uchar)( (ulong)(val) >> (ulong)0x38 ) ), \
19 : ( (p)[1] = (uchar)( (ulong)(val) >> (ulong)0x30 ) ), \
20 : ( (p)[2] = (uchar)( (ulong)(val) >> (ulong)0x28 ) ), \
21 : ( (p)[3] = (uchar)( (ulong)(val) >> (ulong)0x20 ) ), \
22 : ( (p)[4] = (uchar)( (ulong)(val) >> (ulong)0x18 ) ), \
23 : ( (p)[5] = (uchar)( (ulong)(val) >> (ulong)0x10 ) ), \
24 : ( (p)[6] = (uchar)( (ulong)(val) >> (ulong)0x08 ) ), \
25 : ( (p)[7] = (uchar)( (ulong)(val) >> (ulong)0x00 ) ) )
26 :
27 : /* encodes the given type, "returns" the number of bytes encoded */
28 31494641 : #define FD_TEMPL_ENCODE(TYPE,VAR,p) ( ( FD_TEMPL_ENCODE_IMPL_##TYPE((p),(VAR)) ), sizeof(fd_quic_##TYPE) )
29 :
30 : /* returns bytes encoded
31 :
32 : frame is not const, as it may be mutated, for example to store offsets
33 : to particular bytes in the encoded data */
34 : #define FD_TEMPL_DEF_STRUCT_BEGIN(NAME) \
35 : static inline \
36 : ulong \
37 : fd_quic_encode_##NAME( uchar * buf, \
38 : ulong sz, \
39 70290437 : fd_quic_##NAME##_t * frame ) { \
40 70290437 : (void)frame; \
41 70290437 : uchar * orig_buf = buf; \
42 70290437 : uchar * buf_end = buf + sz; \
43 70290437 : ulong tmp_len = 0; (void)tmp_len; \
44 70290437 : uchar * type_ptr = NULL; (void)type_ptr;
45 :
46 : /* encodes TYPE into output */
47 : #define FD_TEMPL_MBR_FRAME_TYPE(NAME,ID_LO,ID_HI) \
48 47871357 : if( buf >= buf_end ) return FD_QUIC_PARSE_FAIL; \
49 47871357 : buf[0] = ID_LO; \
50 47871354 : type_ptr = buf++;
51 :
52 : /* encodes frame->NAME into the type field */
53 : #define FD_TEMPL_MBR_FRAME_TYPE_FLAG(NAME,MASK) \
54 0 : if( type_ptr ) { \
55 0 : type_ptr[0] = (uchar)( ( type_ptr[0] & ~(uint)(MASK) ) \
56 0 : | ( frame->NAME & (uint)(MASK) ) ); \
57 0 : }
58 :
59 :
60 : /* encodes aligned bytes into output */
61 : #define FD_TEMPL_MBR_ELEM(NAME,TYPE) \
62 31494425 : if( FD_UNLIKELY( buf+sizeof(fd_quic_##TYPE) > buf_end ) ) \
63 31494425 : return FD_QUIC_PARSE_FAIL; \
64 31494425 : buf += FD_TEMPL_ENCODE(TYPE,frame->NAME,buf);
65 :
66 :
67 : /* encodes a packet number. Assumes pkt_number_len == 3 (4 bytes)
68 : keeps the pointer to the start of the packet number field */
69 : #define FD_TEMPL_MBR_ELEM_PKTNUM(NAME,TYPE) \
70 19418909 : if( FD_UNLIKELY( buf+4 > buf_end ) ) return FD_QUIC_ENCODE_FAIL; \
71 19418909 : frame->NAME##_pnoff = (unsigned)( buf - orig_buf ); \
72 19418909 : FD_STORE( uint, buf, fd_uint_bswap( (uint)frame->NAME ) ); \
73 19418909 : buf += 4;
74 :
75 :
76 : /* encodes a VARINT
77 : always aligned
78 : most significant two bits represent the width of the int
79 : remaining bits are all data bits
80 : checks for capacity before writing */
81 : #define FD_TEMPL_MBR_ELEM_VARINT(NAME,TYPE) \
82 57928098 : if( FD_UNLIKELY( buf+8 > buf_end ) ) return FD_QUIC_ENCODE_FAIL; \
83 57928098 : buf += fd_quic_varint_encode( buf, frame->NAME );
84 :
85 :
86 : // VAR currently assumed to be aligned bytes
87 : #define FD_TEMPL_MBR_ELEM_VAR(NAME,BITS_MIN,BITS_MAX,LEN_NAME) \
88 25456997 : tmp_len = frame->LEN_NAME; \
89 25456997 : if( FD_UNLIKELY( tmp_len*8 < BITS_MIN || tmp_len*8 > BITS_MAX ) ) {\
90 0 : FD_LOG_DEBUG(( "buffer overflow encoding variable length field." \
91 0 : " field: " #NAME \
92 0 : " BITS_MIN: %lu" \
93 0 : " BITS_MAX: %lu" \
94 0 : " " #LEN_NAME ": %lu" \
95 0 : " tmp_len*8: %lu\n", \
96 0 : (ulong)BITS_MIN, \
97 0 : (ulong)BITS_MAX, \
98 0 : (ulong)frame->LEN_NAME, \
99 0 : (ulong)( tmp_len * 8 ) )); \
100 0 : return FD_QUIC_PARSE_FAIL; \
101 0 : } \
102 25456997 : if( FD_UNLIKELY( (ulong)buf + tmp_len > (ulong)buf_end ) ) { \
103 0 : return FD_QUIC_PARSE_FAIL; \
104 0 : } \
105 25456997 : fd_memcpy( buf, frame->NAME, tmp_len ); \
106 25456997 : buf += tmp_len;
107 :
108 :
109 : // VAR currently assumed to be aligned bytes
110 : #define FD_TEMPL_MBR_ELEM_VAR_RAW(NAME,BITS_MIN,BITS_MAX,LEN_NAME) \
111 : tmp_len = frame->LEN_NAME; \
112 : if( FD_UNLIKELY( tmp_len*8 < BITS_MIN || tmp_len*8 > BITS_MAX ) ) {\
113 : FD_LOG_DEBUG(( "buffer overflow encoding variable length field." \
114 : " field: " #NAME \
115 : " BITS_MIN: %lu" \
116 : " BITS_MAX: %lu" \
117 : " " #LEN_NAME ": %lu" \
118 : " tmp_len*8: %lu\n", \
119 : (ulong)BITS_MIN, \
120 : (ulong)BITS_MAX, \
121 : (ulong)frame->LEN_NAME, \
122 : (ulong)( tmp_len * 8 ) )); \
123 : return FD_QUIC_PARSE_FAIL; \
124 : } \
125 : if( FD_UNLIKELY( (ulong)buf + tmp_len > (ulong)buf_end ) ) { \
126 : return FD_QUIC_PARSE_FAIL; \
127 : } \
128 : fd_memcpy( buf, frame->NAME, tmp_len ); \
129 : buf += tmp_len;
130 :
131 : /* ARRAY is an array of elements, each of the same size,
132 : with length implied by the packet size
133 : caller has responsibility of ensuring the size of the array is not
134 : too large for the space in a packet */
135 : #define FD_TEMPL_MBR_ELEM_ARRAY(NAME,TYPE,BYTES_MIN,BYTES_MAX) \
136 : tmp_len = frame->NAME##_len; \
137 : if( tmp_len * sizeof( fd_quic_##TYPE ) > BYTES_MAX ) { \
138 : return FD_QUIC_ENCODE_FAIL; \
139 : } \
140 : for( ulong j=0; j<tmp_len; ++j ) { \
141 : buf += FD_TEMPL_ENCODE(TYPE,frame->NAME[j],buf); \
142 : }
143 :
144 : /* FIXED is an array of elements, each of the same size,
145 : with length constant */
146 : #define FD_TEMPL_MBR_ELEM_FIXED(NAME,TYPE,BYTES) \
147 18 : if( FD_UNLIKELY( BYTES > buf_end-buf || \
148 18 : BYTES % sizeof(fd_quic_##TYPE) ) ) \
149 18 : return FD_QUIC_PARSE_FAIL; \
150 18 : tmp_len = BYTES / sizeof(fd_quic_##TYPE); \
151 234 : for( ulong j=0; j<tmp_len; ++j ) { \
152 216 : buf += FD_TEMPL_ENCODE(TYPE,frame->NAME[j],buf); \
153 216 : }
154 :
155 : /* TODO remove abort() once tested */
156 : #define FD_TEMPL_MBR_OPT(TYPE,NAME,MASK,...) \
157 126757248 : if( !type_ptr ) { \
158 0 : abort(); \
159 0 : } \
160 126757248 : if( frame->NAME##_opt ) { \
161 59343097 : type_ptr[0] |= (uchar)(MASK); \
162 59343097 : __VA_ARGS__ \
163 25634946 : }
164 :
165 : /* TODO probably easier to split up relevant frames rather than
166 : code a generic optional in macros */
167 :
168 :
169 : /* at end, return the number of bytes consumed */
170 : #define FD_TEMPL_DEF_STRUCT_END(NAME) \
171 70290395 : return (ulong)( buf-orig_buf ); \
172 70290422 : }
173 :
174 : #include "fd_quic_dft.h"
175 :
|