lsquic_varint.c revision 06b2a236
1/* Copyright (c) 2017 - 2021 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}
58
59
60int
61lsquic_varint_read_nb (const unsigned char **pp, const unsigned char *end,
62                                            struct varint_read_state *state)
63{
64    const unsigned char *p = *pp;
65
66    if (p >= end)
67        return -1;
68
69    switch (state->pos ? state->pos : *p >> 6)
70    {
71    case 0:
72        state->val = *p++;
73        *pp = p;
74        return 0;
75    case 1:
76        state->val = (*p++ & VINT_MASK) << 8;
77        if (p >= end) { state->pos = 1000; break; }
78        /* fall through */
79    case 1000:
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 = 1001; break; }
96        /* fall through */
97    case 1001:
98        state->val |= *p++ << 16;
99        if (p >= end) { state->pos = 1002; break; }
100        /* fall through */
101    case 1002:
102        state->val |= *p++ << 8;
103        if (p >= end) { state->pos = 1003; break; }
104        /* fall through */
105    case 1003:
106        state->val |= *p++;
107        *pp = p;
108        return 0;
109    case 3:
110        if (p + 7 < end)
111        {
112            memcpy(&state->val, p, 8);
113#if __BYTE_ORDER == __LITTLE_ENDIAN
114            state->val = bswap_64(state->val);
115#endif
116            state->val &= (1ULL << 62) - 1;
117            *pp += 8;
118            return 0;
119        }
120        state->val = (uint64_t) (*p++ & VINT_MASK) << 56;
121        if (p >= end) { state->pos = 1004; break; }
122        /* fall through */
123    case 1004:
124        state->val |= (uint64_t) *p++ << 48;
125        if (p >= end) { state->pos = 1005; break; }
126        /* fall through */
127    case 1005:
128        state->val |= (uint64_t) *p++ << 40;
129        if (p >= end) { state->pos = 1006; break; }
130        /* fall through */
131    case 1006:
132        state->val |= (uint64_t) *p++ << 32;
133        if (p >= end) { state->pos = 1007; break; }
134        /* fall through */
135    case 1007:
136        state->val |= (uint64_t) *p++ << 24;
137        if (p >= end) { state->pos = 1008; break; }
138        /* fall through */
139    case 1008:
140        state->val |= (uint64_t) *p++ << 16;
141        if (p >= end) { state->pos = 1009; break; }
142        /* fall through */
143    case 1009:
144        state->val |= (uint64_t) *p++ << 8;
145        if (p >= end) { state->pos = 1010; break; }
146        /* fall through */
147    case 1010:
148        state->val |= *p++;
149        *pp = p;
150        return 0;
151    default:
152        assert(0);
153    }
154
155    *pp = p;
156    return -1;
157}
158
159
160int
161lsquic_varint_read_two (const unsigned char **begin, const unsigned char *end,
162                            struct varint_read2_state *state)
163{
164    const unsigned char *p = *begin;
165    int s;
166
167    while (p < end)
168    {
169        switch (state->vr2s_state)
170        {
171        case VR2S_READ_ONE_BEGIN:
172            state->vr2s_varint_state.pos = 0;
173            state->vr2s_state = VR2S_READ_ONE_CONTINUE;
174            goto cont;
175        case VR2S_READ_TWO_BEGIN:
176            state->vr2s_varint_state.pos = 0;
177            state->vr2s_state = VR2S_READ_TWO_CONTINUE;
178            goto cont;
179  cont: case VR2S_READ_ONE_CONTINUE:
180        case VR2S_READ_TWO_CONTINUE:
181            s = lsquic_varint_read_nb(&p, end, &state->vr2s_varint_state);
182            if (s == 0)
183            {
184                if (state->vr2s_state == VR2S_READ_TWO_CONTINUE)
185                    goto done;
186                state->vr2s_one = state->vr2s_varint_state.val;
187                state->vr2s_state = VR2S_READ_TWO_BEGIN;
188                break;
189            }
190            else
191                goto more;
192        }
193    }
194
195  more:
196    *begin = p;
197    return -1;
198
199  done:
200    *begin = p;
201    return 0;
202}
203