comparison src/event/quic/ngx_event_quic_transport.c @ 8781:81d491f0dc8c quic

QUIC: unroll and inline ngx_quic_varint_len()/ngx_quic_build_int(). According to profiling, those two are among most frequently called, so inlining is generally useful, and unrolling should help with it. Further, this fixes undefined behaviour seen with invalid values. Inspired by Yu Liu.
author Sergey Kandaurov <pluknet@nginx.com>
date Sat, 22 May 2021 18:40:45 +0300
parents 515ac3c8435c
children 4715f3e669f1
comparison
equal deleted inserted replaced
8780:557dc6a06ba6 8781:81d491f0dc8c
63 #define ngx_quic_write_uint16_aligned(p, s) \ 63 #define ngx_quic_write_uint16_aligned(p, s) \
64 (*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t)) 64 (*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t))
65 65
66 #define ngx_quic_write_uint32_aligned(p, s) \ 66 #define ngx_quic_write_uint32_aligned(p, s) \
67 (*(uint32_t *) (p) = htonl((uint32_t) (s)), (p) + sizeof(uint32_t)) 67 (*(uint32_t *) (p) = htonl((uint32_t) (s)), (p) + sizeof(uint32_t))
68
69 #define ngx_quic_build_int_set(p, value, len, bits) \
70 (*(p)++ = ((value >> ((len) * 8)) & 0xff) | ((bits) << 6))
68 71
69 #define NGX_QUIC_VERSION(c) (0xff000000 + (c)) 72 #define NGX_QUIC_VERSION(c) (0xff000000 + (c))
70 73
71 74
72 static u_char *ngx_quic_parse_int(u_char *pos, u_char *end, uint64_t *out); 75 static u_char *ngx_quic_parse_int(u_char *pos, u_char *end, uint64_t *out);
242 245
243 return pos + len; 246 return pos + len;
244 } 247 }
245 248
246 249
247 static ngx_uint_t 250 static ngx_inline ngx_uint_t
248 ngx_quic_varint_len(uint64_t value) 251 ngx_quic_varint_len(uint64_t value)
249 { 252 {
250 ngx_uint_t bits; 253 if (value < (1 << 6)) {
251 254 return 1;
252 bits = 0; 255 }
253 while (value >> ((8 << bits) - 2)) { 256
254 bits++; 257 if (value < (1 << 14)) {
255 } 258 return 2;
256 259 }
257 return 1 << bits; 260
258 } 261 if (value < (1 << 30)) {
259 262 return 4;
260 263 }
261 static void 264
265 return 8;
266 }
267
268
269 static ngx_inline void
262 ngx_quic_build_int(u_char **pos, uint64_t value) 270 ngx_quic_build_int(u_char **pos, uint64_t value)
263 { 271 {
264 u_char *p; 272 u_char *p;
265 ngx_uint_t bits, len;
266 273
267 p = *pos; 274 p = *pos;
268 bits = 0; 275
269 276 if (value < (1 << 6)) {
270 while (value >> ((8 << bits) - 2)) { 277 ngx_quic_build_int_set(p, value, 0, 0);
271 bits++; 278
272 } 279 } else if (value < (1 << 14)) {
273 280 ngx_quic_build_int_set(p, value, 1, 1);
274 len = (1 << bits); 281 ngx_quic_build_int_set(p, value, 0, 0);
275 282
276 while (len--) { 283 } else if (value < (1 << 30)) {
277 *p++ = value >> (len * 8); 284 ngx_quic_build_int_set(p, value, 3, 2);
278 } 285 ngx_quic_build_int_set(p, value, 2, 0);
279 286 ngx_quic_build_int_set(p, value, 1, 0);
280 **pos |= bits << 6; 287 ngx_quic_build_int_set(p, value, 0, 0);
288
289 } else {
290 ngx_quic_build_int_set(p, value, 7, 3);
291 ngx_quic_build_int_set(p, value, 6, 0);
292 ngx_quic_build_int_set(p, value, 5, 0);
293 ngx_quic_build_int_set(p, value, 4, 0);
294 ngx_quic_build_int_set(p, value, 3, 0);
295 ngx_quic_build_int_set(p, value, 2, 0);
296 ngx_quic_build_int_set(p, value, 1, 0);
297 ngx_quic_build_int_set(p, value, 0, 0);
298 }
299
281 *pos = p; 300 *pos = p;
282 } 301 }
283 302
284 303
285 u_char * 304 u_char *