lsquic_varint.c revision 5392f7a3
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * lsquic_varint.c -- routines dealing with IETF QUIC varint.
4 */
5
6#include <assert.h>
7#include <stdint.h>
8#include <string.h>
9
10#include "lsquic_byteswap.h"
11#include "lsquic_varint.h"
12
13/* Returns number of bytes read from p (1, 2, 4, or 8), or a negative
14 * value on error.
15 */
16int
17lsquic_varint_read (const unsigned char *p, const unsigned char *end,
18                                                            uint64_t *valp)
19{
20    uint64_t val;
21
22    if (p >= end)
23        return -1;
24
25    switch (*p >> 6)
26    {
27    case 0:
28        *valp = *p;
29        return 1;
30    case 1:
31        if (p + 1 >= end)
32            return -1;
33        *valp = (p[0] & VINT_MASK) << 8
34              |  p[1]
35              ;
36        return 2;
37    case 2:
38        if (p + 3 >= end)
39            return -1;
40        *valp = (p[0] & VINT_MASK) << 24
41              |  p[1] << 16
42              |  p[2] << 8
43              |  p[3] << 0
44              ;
45        return 4;
46    default:
47        if (p + 7 >= end)
48            return -1;
49        memcpy(&val, p, 8);
50#if __BYTE_ORDER == __LITTLE_ENDIAN
51        val = bswap_64(val);
52#endif
53        val &= (1ULL << 62) - 1;
54        *valp = val;
55        return 8;
56    }
57    assert(0);
58}
59
60
61int
62lsquic_varint_read_nb (const unsigned char **pp, const unsigned char *end,
63                                            struct varint_read_state *state)
64{
65    const unsigned char *p = *pp;
66
67    if (p >= end)
68        return -1;
69
70    switch (state->pos ? state->pos : *p >> 6)
71    {
72    case 0:
73        state->val = *p++;
74        *pp = p;
75        return 0;
76    case 1:
77        state->val = (*p++ & VINT_MASK) << 8;
78        if (p >= end) { state->pos = __LINE__ + 1; break; }
79    case __LINE__:
80        state->val |= *p++;
81        *pp = p;
82        return 0;
83    case 2:
84        if (p + 3 < end)
85        {
86            state->val = (p[0] & VINT_MASK) << 24
87                       |  p[1] << 16
88                       |  p[2] << 8
89                       |  p[3] << 0
90                       ;
91            *pp += 4;
92            return 0;
93        }
94        state->val = (*p++ & VINT_MASK) << 24;
95        if (p >= end) { state->pos = __LINE__ + 1; break; }
96    case __LINE__:
97        state->val |= *p++ << 16;
98        if (p >= end) { state->pos = __LINE__ + 1; break; }
99    case __LINE__:
100        state->val |= *p++ << 8;
101        if (p >= end) { state->pos = __LINE__ + 1; break; }
102    case __LINE__:
103        state->val |= *p++;
104        *pp = p;
105        return 0;
106    case 3:
107        if (p + 7 < end)
108        {
109            memcpy(&state->val, p, 8);
110#if __BYTE_ORDER == __LITTLE_ENDIAN
111            state->val = bswap_64(state->val);
112#endif
113            state->val &= (1ULL << 62) - 1;
114            *pp += 8;
115            return 0;
116        }
117        state->val = (uint64_t) (*p++ & VINT_MASK) << 56;
118        if (p >= end) { state->pos = __LINE__ + 1; break; }
119    case __LINE__:
120        state->val |= (uint64_t) *p++ << 48;
121        if (p >= end) { state->pos = __LINE__ + 1; break; }
122    case __LINE__:
123        state->val |= (uint64_t) *p++ << 40;
124        if (p >= end) { state->pos = __LINE__ + 1; break; }
125    case __LINE__:
126        state->val |= (uint64_t) *p++ << 32;
127        if (p >= end) { state->pos = __LINE__ + 1; break; }
128    case __LINE__:
129        state->val |= (uint64_t) *p++ << 24;
130        if (p >= end) { state->pos = __LINE__ + 1; break; }
131    case __LINE__:
132        state->val |= (uint64_t) *p++ << 16;
133        if (p >= end) { state->pos = __LINE__ + 1; break; }
134    case __LINE__:
135        state->val |= (uint64_t) *p++ << 8;
136        if (p >= end) { state->pos = __LINE__ + 1; break; }
137    case __LINE__:
138        state->val |= *p++;
139        *pp = p;
140        return 0;
141    default:
142        assert(0);
143    }
144
145    *pp = p;
146    return -1;
147}
148
149
150int
151lsquic_varint_read_two (const unsigned char **begin, const unsigned char *end,
152                            struct varint_read2_state *state)
153{
154    const unsigned char *p = *begin;
155    int s;
156
157    while (p < end)
158    {
159        switch (state->vr2s_state)
160        {
161        case VR2S_READ_ONE_BEGIN:
162            state->vr2s_varint_state.pos = 0;
163            state->vr2s_state = VR2S_READ_ONE_CONTINUE;
164            goto cont;
165        case VR2S_READ_TWO_BEGIN:
166            state->vr2s_varint_state.pos = 0;
167            state->vr2s_state = VR2S_READ_TWO_CONTINUE;
168            goto cont;
169  cont: case VR2S_READ_ONE_CONTINUE:
170        case VR2S_READ_TWO_CONTINUE:
171            s = lsquic_varint_read_nb(&p, end, &state->vr2s_varint_state);
172            if (s == 0)
173            {
174                if (state->vr2s_state == VR2S_READ_TWO_CONTINUE)
175                    goto done;
176                state->vr2s_one = state->vr2s_varint_state.val;
177                state->vr2s_state = VR2S_READ_TWO_BEGIN;
178                break;
179            }
180            else
181                goto more;
182        }
183    }
184
185  more:
186    *begin = p;
187    return -1;
188
189  done:
190    *begin = p;
191    return 0;
192}
193