Line data Source code
1 : #include "../fd_quic_common.h"
2 :
3 : #include "fd_quic_transport_params.h"
4 : #include "fd_quic_parse_util.h"
5 :
6 : #include <stdio.h>
7 :
8 : void
9 0 : fd_quic_dump_transport_param_desc( FILE * out ) {
10 0 : fprintf( out, "Transport parameter descriptions:\n" );
11 :
12 0 : #define __( NAME, ID, TYPE, DFT, DESC, ... ) \
13 0 : fprintf( out, #ID " " #TYPE " " #NAME "\n" DESC "\n\n" );
14 :
15 0 : FD_QUIC_TRANSPORT_PARAMS( __, _ )
16 0 : #undef __
17 0 : }
18 :
19 : /* Helper for bounds checking that avoids -Wtype-limits warnings, sigh */
20 : static inline int
21 0 : fd_quic_varint_bounds_check( ulong value, ulong min, ulong max ) {
22 : // compiler should optimize out checks against min/max == VARINT_MIN/MAX
23 0 : if( min != FD_QUIC_VARINT_MIN && value < min ) return -1; /* out of bounds */
24 0 : if( max != FD_QUIC_VARINT_MAX && value > max ) return -1; /* out of bounds */
25 0 : return 0; /* in bounds */
26 0 : }
27 :
28 : #define FD_QUIC_PARSE_TP_VARINT( NAME, MIN, MAX ) \
29 0 : do { \
30 0 : if( FD_UNLIKELY( sz==0 ) ) return -2; \
31 0 : uint width = 1u << ( (unsigned)buf[0] >> 6u ); \
32 0 : if( FD_UNLIKELY( sz<width ) ) return -3; \
33 0 : ulong value = (ulong)( buf[0] & 0x3f ); \
34 0 : for( ulong j=1; j<width; ++j ) { \
35 0 : value= ( value<<8u ) + (ulong)buf[j]; \
36 0 : } \
37 0 : if( FD_UNLIKELY( fd_quic_varint_bounds_check( value, MIN, MAX ) ) ) return -4; \
38 0 : params->NAME = value; \
39 0 : params->NAME##_present = 1; \
40 0 : } while(0)
41 :
42 : #define FD_QUIC_PARSE_TP_CONN_ID( NAME, ... ) \
43 0 : do { \
44 0 : if( FD_UNLIKELY( sz>sizeof(params->NAME) ) ) return -1; \
45 0 : fd_memcpy( params->NAME, buf, sz ); \
46 0 : params->NAME##_len = (uchar)sz; \
47 0 : params->NAME##_present = 1; \
48 0 : } while(0)
49 :
50 : #define FD_QUIC_PARSE_TP_ZERO_LENGTH( NAME, ... ) \
51 0 : params->NAME##_present = 1;
52 :
53 : #define FD_QUIC_PARSE_TP_TOKEN( NAME, ... ) \
54 0 : do { \
55 0 : if( FD_UNLIKELY( sz>sizeof(params->NAME) ) ) return -1; \
56 0 : fd_memcpy( params->NAME, buf, sz ); \
57 0 : params->NAME##_len = (uchar)sz; \
58 0 : params->NAME##_present = 1; \
59 0 : } while(0)
60 :
61 : #define FD_QUIC_PARSE_TP_PREFERRED_ADDRESS( NAME, ... ) \
62 0 : do { \
63 0 : if( FD_UNLIKELY( sz>sizeof(params->NAME) ) ) return -1; \
64 0 : fd_memcpy( params->NAME, buf, sz ); \
65 0 : params->NAME##_len = (uchar)sz; \
66 0 : params->NAME##_present = 1; \
67 0 : } while(0)
68 :
69 :
70 : static int
71 : fd_quic_decode_transport_param( fd_quic_transport_params_t * params,
72 : ulong id,
73 : uchar const * buf,
74 0 : ulong sz ) {
75 : // This compiles into a jump table, which is reasonably fast
76 0 : switch( id ) {
77 0 : #define __( NAME, ID, TYPE, DFT, DESC, MIN, MAX, ... ) \
78 0 : case ID: { \
79 0 : FD_QUIC_PARSE_TP_##TYPE( NAME, MIN, MAX ); \
80 0 : return 0; \
81 0 : } \
82 0 :
83 0 : FD_QUIC_TRANSPORT_PARAMS( __, _ )
84 0 : #undef __
85 :
86 0 : }
87 :
88 0 : return 0; /* ignore unknown IDs */
89 0 : }
90 :
91 : int
92 : fd_quic_decode_transport_params( fd_quic_transport_params_t * params,
93 : uchar const * buf,
94 0 : ulong buf_sz ) {
95 0 : while( buf_sz > 0 ) {
96 : /* upon success, this function adjusts buf and sz by bytes consumed */
97 0 : ulong param_id = fd_quic_tp_parse_varint( &buf, &buf_sz );
98 0 : ulong param_sz = fd_quic_tp_parse_varint( &buf, &buf_sz );
99 0 : if( FD_UNLIKELY( param_sz > buf_sz ) ) return -1; /* length OOB */
100 :
101 0 : int param_err = fd_quic_decode_transport_param( params, param_id, buf, param_sz );
102 0 : if( FD_UNLIKELY( param_err ) ) return -1; /* parse failure */
103 :
104 : /* update buf and buf_sz */
105 0 : buf += param_sz;
106 0 : buf_sz -= param_sz;
107 0 : }
108 :
109 0 : return 0; /* success */
110 0 : }
111 :
112 : #define FD_QUIC_DUMP_TP_VARINT(NAME) \
113 0 : fprintf( out, "%lu", (ulong)params->NAME )
114 : #define FD_QUIC_DUMP_TP_CONN_ID(NAME) \
115 0 : do { \
116 0 : ulong sz = params->NAME##_len; \
117 0 : fprintf( out, "len(%d) ", (int)sz ); \
118 0 : for( ulong j = 0; j < sz; ++j ) { \
119 0 : fprintf( out, "%2.2x ", (unsigned)params->NAME[j] ); \
120 0 : } \
121 0 : } while(0)
122 : #define FD_QUIC_DUMP_TP_ZERO_LENGTH(NAME) \
123 0 : fprintf( out, "%u", (unsigned)params->NAME##_present )
124 0 : #define FD_QUIC_DUMP_TP_TOKEN(NAME) FD_QUIC_DUMP_TP_CONN_ID(NAME)
125 0 : #define FD_QUIC_DUMP_TP_PREFERRED_ADDRESS(NAME) FD_QUIC_DUMP_TP_CONN_ID(NAME)
126 :
127 : void
128 0 : fd_quic_dump_transport_params( fd_quic_transport_params_t const * params, FILE * out ) {
129 0 : fprintf( out, "Transport params:\n" );
130 0 : #define __( NAME, ID, TYPE, DFT, DESC, ... ) \
131 0 : fprintf( out, " %-50s: %s ", #NAME " (" #ID ")", params->NAME##_present ? "*" : " " ); \
132 0 : FD_QUIC_DUMP_TP_##TYPE(NAME); \
133 0 : fprintf( out, "\n" );
134 0 : FD_QUIC_TRANSPORT_PARAMS( __, _ )
135 0 : #undef __
136 0 : }
137 :
138 :
139 : #define FD_QUIC_ENCODE_TP_VARINT(NAME,ID) \
140 0 : do { \
141 0 : ulong val_len = fd_quic_varint_min_sz( params->NAME ); \
142 0 : if( val_len == FD_QUIC_ENCODE_FAIL ) return FD_QUIC_ENCODE_FAIL; \
143 0 : FD_QUIC_ENCODE_VARINT( buf, buf_sz, ID ); \
144 0 : FD_QUIC_ENCODE_VARINT( buf, buf_sz, val_len ); \
145 0 : FD_QUIC_ENCODE_VARINT(buf,buf_sz,params->NAME); \
146 0 : } while(0)
147 :
148 : #define FD_QUIC_ENCODE_TP_CONN_ID(NAME,ID) \
149 0 : do { \
150 0 : ulong val_len = params->NAME##_len; \
151 0 : FD_QUIC_ENCODE_VARINT( buf, buf_sz, ID ); \
152 0 : FD_QUIC_ENCODE_VARINT( buf, buf_sz, val_len ); \
153 0 : if( val_len + 1 > buf_sz ) return FD_QUIC_ENCODE_FAIL; \
154 0 : for( ulong j = 0; j < val_len; ++j ) { \
155 0 : buf[j] = params->NAME[j]; \
156 0 : } \
157 0 : buf += val_len; buf_sz -= val_len; \
158 0 : } while(0);
159 :
160 : #define FD_QUIC_ENCODE_TP_ZERO_LENGTH(NAME,ID) \
161 0 : do { \
162 0 : if( params->NAME##_present ) { \
163 0 : FD_QUIC_ENCODE_VARINT( buf, buf_sz, ID ); \
164 0 : FD_QUIC_ENCODE_VARINT( buf, buf_sz, 0 ); \
165 0 : } \
166 0 : } while(0)
167 :
168 : #define FD_QUIC_ENCODE_TP_TOKEN(NAME,ID) \
169 0 : FD_QUIC_ENCODE_TP_CONN_ID(NAME,ID)
170 :
171 : #define FD_QUIC_ENCODE_TP_PREFERRED_ADDRESS(NAME,ID) \
172 0 : FD_QUIC_ENCODE_TP_CONN_ID(NAME,ID)
173 :
174 :
175 : /* determine footprint of each type */
176 :
177 : #define FD_QUIC_FOOTPRINT_FAIL ((ulong)1 << (ulong)62)
178 :
179 : /* we need the length of the ID + the length of the length of the parameter value
180 : plus the length of the parameter value */
181 : #define FD_QUIC_FOOTPRINT_TP_VARINT(NAME,ID) \
182 : ( \
183 : fd_quic_varint_min_sz( ID ) + \
184 : fd_quic_varint_min_sz( fd_quic_varint_min_sz( params->NAME ) ) + \
185 : fd_quic_varint_min_sz( params->NAME ) \
186 : )
187 :
188 : /* the length of a connection id is specified by *_len */
189 : #define FD_QUIC_FOOTPRINT_TP_CONN_ID(NAME,ID) \
190 : ( \
191 : fd_quic_varint_min_sz( ID ) + \
192 : fd_quic_varint_min_sz( params->NAME##_len ) + \
193 : params->NAME##_len \
194 : )
195 :
196 : #define FD_QUIC_FOOTPRINT_TP_ZERO_LENGTH(NAME,ID) \
197 : ( \
198 : fd_quic_varint_min_sz( ID ) + \
199 : fd_quic_varint_min_sz( 0 ) \
200 : )
201 :
202 : #define FD_QUIC_FOOTPRINT_TP_TOKEN(NAME,ID) \
203 : FD_QUIC_FOOTPRINT_TP_CONN_ID(NAME,ID)
204 :
205 : #define FD_QUIC_FOOTPRINT_TP_PREFERRED_ADDRESS(NAME,ID) \
206 : FD_QUIC_FOOTPRINT_TP_CONN_ID(NAME,ID)
207 :
208 :
209 : #define FD_QUIC_VALIDATE_TP_TOKEN(NAME,ID) \
210 : FD_QUIC_VALIDATE_TP_CONN_ID(NAME,ID)
211 :
212 : #define FD_QUIC_VALIDATE_TP_PREFERRED_ADDRESS(NAME,ID) \
213 : FD_QUIC_VALIDATE_TP_CONN_ID(NAME,ID)
214 :
215 :
216 : // encode transport parameters into a buffer
217 : // returns the number of bytes written
218 : ulong
219 : fd_quic_encode_transport_params( uchar * buf,
220 : ulong buf_sz,
221 0 : fd_quic_transport_params_t const * params ) {
222 0 : ulong orig_buf_sz = buf_sz;
223 0 : #define __( NAME, ID, TYPE, DFT, DESC, ... ) \
224 0 : if( params->NAME##_present ) { \
225 0 : FD_QUIC_ENCODE_TP_##TYPE(NAME,ID); \
226 0 : }
227 0 : FD_QUIC_TRANSPORT_PARAMS( __, _ )
228 0 : #undef __
229 :
230 0 : return orig_buf_sz - buf_sz;
231 0 : }
|