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