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