lsquic_varint.c revision 5392f7a3
15392f7a3SLiteSpeed Tech/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */ 25392f7a3SLiteSpeed Tech/* 35392f7a3SLiteSpeed Tech * lsquic_varint.c -- routines dealing with IETF QUIC varint. 45392f7a3SLiteSpeed Tech */ 55392f7a3SLiteSpeed Tech 65392f7a3SLiteSpeed Tech#include <assert.h> 75392f7a3SLiteSpeed Tech#include <stdint.h> 85392f7a3SLiteSpeed Tech#include <string.h> 95392f7a3SLiteSpeed Tech 105392f7a3SLiteSpeed Tech#include "lsquic_byteswap.h" 115392f7a3SLiteSpeed Tech#include "lsquic_varint.h" 125392f7a3SLiteSpeed Tech 135392f7a3SLiteSpeed Tech/* Returns number of bytes read from p (1, 2, 4, or 8), or a negative 145392f7a3SLiteSpeed Tech * value on error. 155392f7a3SLiteSpeed Tech */ 165392f7a3SLiteSpeed Techint 175392f7a3SLiteSpeed Techlsquic_varint_read (const unsigned char *p, const unsigned char *end, 185392f7a3SLiteSpeed Tech uint64_t *valp) 195392f7a3SLiteSpeed Tech{ 205392f7a3SLiteSpeed Tech uint64_t val; 215392f7a3SLiteSpeed Tech 225392f7a3SLiteSpeed Tech if (p >= end) 235392f7a3SLiteSpeed Tech return -1; 245392f7a3SLiteSpeed Tech 255392f7a3SLiteSpeed Tech switch (*p >> 6) 265392f7a3SLiteSpeed Tech { 275392f7a3SLiteSpeed Tech case 0: 285392f7a3SLiteSpeed Tech *valp = *p; 295392f7a3SLiteSpeed Tech return 1; 305392f7a3SLiteSpeed Tech case 1: 315392f7a3SLiteSpeed Tech if (p + 1 >= end) 325392f7a3SLiteSpeed Tech return -1; 335392f7a3SLiteSpeed Tech *valp = (p[0] & VINT_MASK) << 8 345392f7a3SLiteSpeed Tech | p[1] 355392f7a3SLiteSpeed Tech ; 365392f7a3SLiteSpeed Tech return 2; 375392f7a3SLiteSpeed Tech case 2: 385392f7a3SLiteSpeed Tech if (p + 3 >= end) 395392f7a3SLiteSpeed Tech return -1; 405392f7a3SLiteSpeed Tech *valp = (p[0] & VINT_MASK) << 24 415392f7a3SLiteSpeed Tech | p[1] << 16 425392f7a3SLiteSpeed Tech | p[2] << 8 435392f7a3SLiteSpeed Tech | p[3] << 0 445392f7a3SLiteSpeed Tech ; 455392f7a3SLiteSpeed Tech return 4; 465392f7a3SLiteSpeed Tech default: 475392f7a3SLiteSpeed Tech if (p + 7 >= end) 485392f7a3SLiteSpeed Tech return -1; 495392f7a3SLiteSpeed Tech memcpy(&val, p, 8); 505392f7a3SLiteSpeed Tech#if __BYTE_ORDER == __LITTLE_ENDIAN 515392f7a3SLiteSpeed Tech val = bswap_64(val); 525392f7a3SLiteSpeed Tech#endif 535392f7a3SLiteSpeed Tech val &= (1ULL << 62) - 1; 545392f7a3SLiteSpeed Tech *valp = val; 555392f7a3SLiteSpeed Tech return 8; 565392f7a3SLiteSpeed Tech } 575392f7a3SLiteSpeed Tech assert(0); 585392f7a3SLiteSpeed Tech} 595392f7a3SLiteSpeed Tech 605392f7a3SLiteSpeed Tech 615392f7a3SLiteSpeed Techint 625392f7a3SLiteSpeed Techlsquic_varint_read_nb (const unsigned char **pp, const unsigned char *end, 635392f7a3SLiteSpeed Tech struct varint_read_state *state) 645392f7a3SLiteSpeed Tech{ 655392f7a3SLiteSpeed Tech const unsigned char *p = *pp; 665392f7a3SLiteSpeed Tech 675392f7a3SLiteSpeed Tech if (p >= end) 685392f7a3SLiteSpeed Tech return -1; 695392f7a3SLiteSpeed Tech 705392f7a3SLiteSpeed Tech switch (state->pos ? state->pos : *p >> 6) 715392f7a3SLiteSpeed Tech { 725392f7a3SLiteSpeed Tech case 0: 735392f7a3SLiteSpeed Tech state->val = *p++; 745392f7a3SLiteSpeed Tech *pp = p; 755392f7a3SLiteSpeed Tech return 0; 765392f7a3SLiteSpeed Tech case 1: 775392f7a3SLiteSpeed Tech state->val = (*p++ & VINT_MASK) << 8; 785392f7a3SLiteSpeed Tech if (p >= end) { state->pos = __LINE__ + 1; break; } 795392f7a3SLiteSpeed Tech case __LINE__: 805392f7a3SLiteSpeed Tech state->val |= *p++; 815392f7a3SLiteSpeed Tech *pp = p; 825392f7a3SLiteSpeed Tech return 0; 835392f7a3SLiteSpeed Tech case 2: 845392f7a3SLiteSpeed Tech if (p + 3 < end) 855392f7a3SLiteSpeed Tech { 865392f7a3SLiteSpeed Tech state->val = (p[0] & VINT_MASK) << 24 875392f7a3SLiteSpeed Tech | p[1] << 16 885392f7a3SLiteSpeed Tech | p[2] << 8 895392f7a3SLiteSpeed Tech | p[3] << 0 905392f7a3SLiteSpeed Tech ; 915392f7a3SLiteSpeed Tech *pp += 4; 925392f7a3SLiteSpeed Tech return 0; 935392f7a3SLiteSpeed Tech } 945392f7a3SLiteSpeed Tech state->val = (*p++ & VINT_MASK) << 24; 955392f7a3SLiteSpeed Tech if (p >= end) { state->pos = __LINE__ + 1; break; } 965392f7a3SLiteSpeed Tech case __LINE__: 975392f7a3SLiteSpeed Tech state->val |= *p++ << 16; 985392f7a3SLiteSpeed Tech if (p >= end) { state->pos = __LINE__ + 1; break; } 995392f7a3SLiteSpeed Tech case __LINE__: 1005392f7a3SLiteSpeed Tech state->val |= *p++ << 8; 1015392f7a3SLiteSpeed Tech if (p >= end) { state->pos = __LINE__ + 1; break; } 1025392f7a3SLiteSpeed Tech case __LINE__: 1035392f7a3SLiteSpeed Tech state->val |= *p++; 1045392f7a3SLiteSpeed Tech *pp = p; 1055392f7a3SLiteSpeed Tech return 0; 1065392f7a3SLiteSpeed Tech case 3: 1075392f7a3SLiteSpeed Tech if (p + 7 < end) 1085392f7a3SLiteSpeed Tech { 1095392f7a3SLiteSpeed Tech memcpy(&state->val, p, 8); 1105392f7a3SLiteSpeed Tech#if __BYTE_ORDER == __LITTLE_ENDIAN 1115392f7a3SLiteSpeed Tech state->val = bswap_64(state->val); 1125392f7a3SLiteSpeed Tech#endif 1135392f7a3SLiteSpeed Tech state->val &= (1ULL << 62) - 1; 1145392f7a3SLiteSpeed Tech *pp += 8; 1155392f7a3SLiteSpeed Tech return 0; 1165392f7a3SLiteSpeed Tech } 1175392f7a3SLiteSpeed Tech state->val = (uint64_t) (*p++ & VINT_MASK) << 56; 1185392f7a3SLiteSpeed Tech if (p >= end) { state->pos = __LINE__ + 1; break; } 1195392f7a3SLiteSpeed Tech case __LINE__: 1205392f7a3SLiteSpeed Tech state->val |= (uint64_t) *p++ << 48; 1215392f7a3SLiteSpeed Tech if (p >= end) { state->pos = __LINE__ + 1; break; } 1225392f7a3SLiteSpeed Tech case __LINE__: 1235392f7a3SLiteSpeed Tech state->val |= (uint64_t) *p++ << 40; 1245392f7a3SLiteSpeed Tech if (p >= end) { state->pos = __LINE__ + 1; break; } 1255392f7a3SLiteSpeed Tech case __LINE__: 1265392f7a3SLiteSpeed Tech state->val |= (uint64_t) *p++ << 32; 1275392f7a3SLiteSpeed Tech if (p >= end) { state->pos = __LINE__ + 1; break; } 1285392f7a3SLiteSpeed Tech case __LINE__: 1295392f7a3SLiteSpeed Tech state->val |= (uint64_t) *p++ << 24; 1305392f7a3SLiteSpeed Tech if (p >= end) { state->pos = __LINE__ + 1; break; } 1315392f7a3SLiteSpeed Tech case __LINE__: 1325392f7a3SLiteSpeed Tech state->val |= (uint64_t) *p++ << 16; 1335392f7a3SLiteSpeed Tech if (p >= end) { state->pos = __LINE__ + 1; break; } 1345392f7a3SLiteSpeed Tech case __LINE__: 1355392f7a3SLiteSpeed Tech state->val |= (uint64_t) *p++ << 8; 1365392f7a3SLiteSpeed Tech if (p >= end) { state->pos = __LINE__ + 1; break; } 1375392f7a3SLiteSpeed Tech case __LINE__: 1385392f7a3SLiteSpeed Tech state->val |= *p++; 1395392f7a3SLiteSpeed Tech *pp = p; 1405392f7a3SLiteSpeed Tech return 0; 1415392f7a3SLiteSpeed Tech default: 1425392f7a3SLiteSpeed Tech assert(0); 1435392f7a3SLiteSpeed Tech } 1445392f7a3SLiteSpeed Tech 1455392f7a3SLiteSpeed Tech *pp = p; 1465392f7a3SLiteSpeed Tech return -1; 1475392f7a3SLiteSpeed Tech} 1485392f7a3SLiteSpeed Tech 1495392f7a3SLiteSpeed Tech 1505392f7a3SLiteSpeed Techint 1515392f7a3SLiteSpeed Techlsquic_varint_read_two (const unsigned char **begin, const unsigned char *end, 1525392f7a3SLiteSpeed Tech struct varint_read2_state *state) 1535392f7a3SLiteSpeed Tech{ 1545392f7a3SLiteSpeed Tech const unsigned char *p = *begin; 1555392f7a3SLiteSpeed Tech int s; 1565392f7a3SLiteSpeed Tech 1575392f7a3SLiteSpeed Tech while (p < end) 1585392f7a3SLiteSpeed Tech { 1595392f7a3SLiteSpeed Tech switch (state->vr2s_state) 1605392f7a3SLiteSpeed Tech { 1615392f7a3SLiteSpeed Tech case VR2S_READ_ONE_BEGIN: 1625392f7a3SLiteSpeed Tech state->vr2s_varint_state.pos = 0; 1635392f7a3SLiteSpeed Tech state->vr2s_state = VR2S_READ_ONE_CONTINUE; 1645392f7a3SLiteSpeed Tech goto cont; 1655392f7a3SLiteSpeed Tech case VR2S_READ_TWO_BEGIN: 1665392f7a3SLiteSpeed Tech state->vr2s_varint_state.pos = 0; 1675392f7a3SLiteSpeed Tech state->vr2s_state = VR2S_READ_TWO_CONTINUE; 1685392f7a3SLiteSpeed Tech goto cont; 1695392f7a3SLiteSpeed Tech cont: case VR2S_READ_ONE_CONTINUE: 1705392f7a3SLiteSpeed Tech case VR2S_READ_TWO_CONTINUE: 1715392f7a3SLiteSpeed Tech s = lsquic_varint_read_nb(&p, end, &state->vr2s_varint_state); 1725392f7a3SLiteSpeed Tech if (s == 0) 1735392f7a3SLiteSpeed Tech { 1745392f7a3SLiteSpeed Tech if (state->vr2s_state == VR2S_READ_TWO_CONTINUE) 1755392f7a3SLiteSpeed Tech goto done; 1765392f7a3SLiteSpeed Tech state->vr2s_one = state->vr2s_varint_state.val; 1775392f7a3SLiteSpeed Tech state->vr2s_state = VR2S_READ_TWO_BEGIN; 1785392f7a3SLiteSpeed Tech break; 1795392f7a3SLiteSpeed Tech } 1805392f7a3SLiteSpeed Tech else 1815392f7a3SLiteSpeed Tech goto more; 1825392f7a3SLiteSpeed Tech } 1835392f7a3SLiteSpeed Tech } 1845392f7a3SLiteSpeed Tech 1855392f7a3SLiteSpeed Tech more: 1865392f7a3SLiteSpeed Tech *begin = p; 1875392f7a3SLiteSpeed Tech return -1; 1885392f7a3SLiteSpeed Tech 1895392f7a3SLiteSpeed Tech done: 1905392f7a3SLiteSpeed Tech *begin = p; 1915392f7a3SLiteSpeed Tech return 0; 1925392f7a3SLiteSpeed Tech} 193