lsquic_varint.c revision 7d09751d
1/* Copyright (c) 2017 - 2020 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