blob: cb2b89ae25374d10607a1126fda62eaa8aeabfd1 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller605ad622016-03-25 20:07:21 -07003 * Copyright 2015-2016, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34/* generates constant tables for hpack.c */
35
Craig Tillerffae43c2016-03-25 19:34:29 -070036#include <assert.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080037#include <stddef.h>
38#include <stdio.h>
39#include <string.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080040
41#include <grpc/support/log.h>
Craig Tillerc7762a82016-03-28 10:13:08 -070042#include "src/core/ext/transport/chttp2/transport/huffsyms.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080043
44/*
45 * first byte LUT generation
46 */
47
48typedef struct {
49 const char *call;
50 /* bit prefix for the field type */
51 unsigned char prefix;
52 /* length of the bit prefix for the field type */
53 unsigned char prefix_length;
54 /* index value: 0 = all zeros, 2 = all ones, 1 otherwise */
55 unsigned char index;
56} spec;
57
Craig Tiller4aa71a12015-06-15 13:00:55 -070058static const spec fields[] = {
59 {"INDEXED_FIELD", 0X80, 1, 1}, {"INDEXED_FIELD_X", 0X80, 1, 2},
60 {"LITHDR_INCIDX", 0X40, 2, 1}, {"LITHDR_INCIDX_X", 0X40, 2, 2},
61 {"LITHDR_INCIDX_V", 0X40, 2, 0}, {"LITHDR_NOTIDX", 0X00, 4, 1},
62 {"LITHDR_NOTIDX_X", 0X00, 4, 2}, {"LITHDR_NOTIDX_V", 0X00, 4, 0},
63 {"LITHDR_NVRIDX", 0X10, 4, 1}, {"LITHDR_NVRIDX_X", 0X10, 4, 2},
64 {"LITHDR_NVRIDX_V", 0X10, 4, 0}, {"MAX_TBL_SIZE", 0X20, 3, 1},
65 {"MAX_TBL_SIZE_X", 0X20, 3, 2},
66};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080067
68static const int num_fields = sizeof(fields) / sizeof(*fields);
69
70static unsigned char prefix_mask(unsigned char prefix_len) {
71 unsigned char i;
72 unsigned char out = 0;
73 for (i = 0; i < prefix_len; i++) {
David Garcia Quintas809831e2015-10-05 13:40:07 -070074 /* NB: the following integer arithmetic operation needs to be in its
75 * expanded form due to the "integral promotion" performed (see section
David Garcia Quintas35284f02015-10-06 11:05:05 -070076 * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type
77 * is then required to avoid the compiler warning */
David Garcia Quintasd76cdac2015-10-03 15:57:09 -070078 out = (unsigned char)(out | (unsigned char)(1 << (7 - i)));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080079 }
80 return out;
81}
82
83static unsigned char suffix_mask(unsigned char prefix_len) {
Craig Tiller6a6b36c2015-09-10 16:00:22 -070084 return (unsigned char)~prefix_mask(prefix_len);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080085}
86
Craig Tiller32946d32015-01-15 11:37:30 -080087static void generate_first_byte_lut(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080088 int i, j, n;
89 const spec *chrspec;
90 unsigned char suffix;
91
92 n = printf("static CALLTYPE first_byte[256] = {");
93 /* for each potential first byte of a header */
94 for (i = 0; i < 256; i++) {
95 /* find the field type that matches it */
96 chrspec = NULL;
97 for (j = 0; j < num_fields; j++) {
98 if ((prefix_mask(fields[j].prefix_length) & i) == fields[j].prefix) {
David Garcia Quintas809831e2015-10-05 13:40:07 -070099 /* NB: the following integer arithmetic operation needs to be in its
100 * expanded form due to the "integral promotion" performed (see section
David Garcia Quintas35284f02015-10-06 11:05:05 -0700101 * 3.2.1.1 of the C89 draft standard). A cast to the smaller container
102 * type is then required to avoid the compiler warning */
David Garcia Quintasd76cdac2015-10-03 15:57:09 -0700103 suffix = (unsigned char)(suffix_mask(fields[j].prefix_length) &
104 (unsigned char)i);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800105 if (suffix == suffix_mask(fields[j].prefix_length)) {
106 if (fields[j].index != 2) continue;
107 } else if (suffix == 0) {
108 if (fields[j].index != 0) continue;
109 } else {
110 if (fields[j].index != 1) continue;
111 }
112 GPR_ASSERT(chrspec == NULL);
113 chrspec = &fields[j];
114 }
115 }
116 if (chrspec) {
117 n += printf("%s, ", chrspec->call);
118 } else {
119 n += printf("ILLEGAL, ");
120 }
121 /* make some small effort towards readable output */
122 if (n > 70) {
123 printf("\n ");
124 n = 2;
125 }
126 }
127 printf("};\n");
128}
129
130/*
131 * Huffman decoder table generation
132 */
133
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800134#define MAXHUFFSTATES 1024
135
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800136/* represents a set of symbols as an array of booleans indicating inclusion */
Craig Tiller4aa71a12015-06-15 13:00:55 -0700137typedef struct { char included[GRPC_CHTTP2_NUM_HUFFSYMS]; } symset;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800138/* represents a lookup table indexed by a nibble */
Craig Tillerf96dfc32015-09-10 14:43:18 -0700139typedef struct { unsigned values[16]; } nibblelut;
140
141#define NOT_SET (~(unsigned)0)
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800142
143/* returns a symset that includes all possible symbols */
Craig Tiller32946d32015-01-15 11:37:30 -0800144static symset symset_all(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800145 symset x;
146 memset(x.included, 1, sizeof(x.included));
147 return x;
148}
149
150/* returns a symset that includes no symbols */
Craig Tiller32946d32015-01-15 11:37:30 -0800151static symset symset_none(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800152 symset x;
153 memset(x.included, 0, sizeof(x.included));
154 return x;
155}
156
157/* returns an empty nibblelut */
Craig Tiller32946d32015-01-15 11:37:30 -0800158static nibblelut nibblelut_empty(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800159 nibblelut x;
160 int i;
161 for (i = 0; i < 16; i++) {
Craig Tillerf96dfc32015-09-10 14:43:18 -0700162 x.values[i] = NOT_SET;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800163 }
164 return x;
165}
166
167/* counts symbols in a symset - only used for debug builds */
168#ifndef NDEBUG
169static int nsyms(symset s) {
170 int i;
171 int c = 0;
nnoble0c475f02014-12-05 15:37:39 -0800172 for (i = 0; i < GRPC_CHTTP2_NUM_HUFFSYMS; i++) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800173 c += s.included[i] != 0;
174 }
175 return c;
176}
177#endif
178
179/* global table of discovered huffman decoding states */
180static struct {
181 /* the bit offset that this state starts at */
Craig Tillerf96dfc32015-09-10 14:43:18 -0700182 unsigned bitofs;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800183 /* the set of symbols that this state started with */
184 symset syms;
185
186 /* lookup table for the next state */
187 nibblelut next;
188 /* lookup table for what to emit */
189 nibblelut emit;
190} huffstates[MAXHUFFSTATES];
Craig Tillerf96dfc32015-09-10 14:43:18 -0700191static unsigned nhuffstates = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800192
193/* given a number of decoded bits and a set of symbols that are live,
194 return the index into the decoder table for this state.
195 set isnew to 1 if this state was previously undiscovered */
Craig Tillerf96dfc32015-09-10 14:43:18 -0700196static unsigned state_index(unsigned bitofs, symset syms, unsigned *isnew) {
197 unsigned i;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800198 for (i = 0; i < nhuffstates; i++) {
199 if (huffstates[i].bitofs != bitofs) continue;
nnoble0c475f02014-12-05 15:37:39 -0800200 if (0 != memcmp(huffstates[i].syms.included, syms.included,
201 GRPC_CHTTP2_NUM_HUFFSYMS))
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800202 continue;
203 *isnew = 0;
204 return i;
205 }
206 GPR_ASSERT(nhuffstates != MAXHUFFSTATES);
207 i = nhuffstates++;
208 huffstates[i].bitofs = bitofs;
209 huffstates[i].syms = syms;
210 huffstates[i].next = nibblelut_empty();
211 huffstates[i].emit = nibblelut_empty();
212 *isnew = 1;
213 return i;
214}
215
216/* recursively build a decoding table
217
218 state - the huffman state that we are trying to fill in
219 nibble - the current nibble
220 nibbits - the number of bits in the nibble that have been filled in
221 bitofs - the number of bits of symbol that have been decoded
222 emit - the symbol to emit on this nibble (or -1 if no symbol has been
223 found)
224 syms - the set of symbols that could be matched */
Craig Tillerf96dfc32015-09-10 14:43:18 -0700225static void build_dec_tbl(unsigned state, unsigned nibble, int nibbits,
226 unsigned bitofs, unsigned emit, symset syms) {
227 unsigned i;
Nicolas "Pixel" Noble85352632015-06-02 02:01:51 +0200228 unsigned bit;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800229
230 /* If we have four bits in the nibble we're looking at, then we can fill in
231 a slot in the lookup tables. */
232 if (nibbits == 4) {
Craig Tillerf96dfc32015-09-10 14:43:18 -0700233 unsigned isnew;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800234 /* Find the state that we are in: this may be a new state, in which case
235 we recurse to fill it in, or we may have already seen this state, in
236 which case the recursion terminates */
Craig Tillerf96dfc32015-09-10 14:43:18 -0700237 unsigned st = state_index(bitofs, syms, &isnew);
238 GPR_ASSERT(huffstates[state].next.values[nibble] == NOT_SET);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800239 huffstates[state].next.values[nibble] = st;
240 huffstates[state].emit.values[nibble] = emit;
241 if (isnew) {
Craig Tillerf96dfc32015-09-10 14:43:18 -0700242 build_dec_tbl(st, 0, 0, bitofs, NOT_SET, syms);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800243 }
244 return;
245 }
246
247 assert(nsyms(syms));
248
249 /* A bit can be 0 or 1 */
250 for (bit = 0; bit < 2; bit++) {
251 /* walk over active symbols and see if they have this bit set */
252 symset nextsyms = symset_none();
nnoble0c475f02014-12-05 15:37:39 -0800253 for (i = 0; i < GRPC_CHTTP2_NUM_HUFFSYMS; i++) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800254 if (!syms.included[i]) continue; /* disregard inactive symbols */
nnoble0c475f02014-12-05 15:37:39 -0800255 if (((grpc_chttp2_huffsyms[i].bits >>
256 (grpc_chttp2_huffsyms[i].length - bitofs - 1)) &
257 1) == bit) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800258 /* the bit is set, include it in the next recursive set */
nnoble0c475f02014-12-05 15:37:39 -0800259 if (grpc_chttp2_huffsyms[i].length == bitofs + 1) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800260 /* additionally, we've gotten to the end of a symbol - this is a
261 special recursion step: re-activate all the symbols, reset
262 bitofs to zero, and recurse */
263 build_dec_tbl(state, (nibble << 1) | bit, nibbits + 1, 0, i,
264 symset_all());
265 /* skip the remainder of this loop */
266 goto next;
267 }
268 nextsyms.included[i] = 1;
269 }
270 }
271 /* recurse down for this bit */
272 build_dec_tbl(state, (nibble << 1) | bit, nibbits + 1, bitofs + 1, emit,
273 nextsyms);
Craig Tiller4aa71a12015-06-15 13:00:55 -0700274 next:;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800275 }
276}
277
278static nibblelut ctbl[MAXHUFFSTATES];
279static int nctbl;
280
281static int ctbl_idx(nibblelut x) {
282 int i;
283 for (i = 0; i < nctbl; i++) {
284 if (0 == memcmp(&x, ctbl + i, sizeof(nibblelut))) return i;
285 }
286 ctbl[i] = x;
287 nctbl++;
288 return i;
289}
290
291static void dump_ctbl(const char *name) {
292 int i, j;
293 printf("static const gpr_int16 %s[%d*16] = {\n", name, nctbl);
294 for (i = 0; i < nctbl; i++) {
295 for (j = 0; j < 16; j++) {
296 printf("%d,", ctbl[i].values[j]);
297 }
298 printf("\n");
299 }
300 printf("};\n");
301}
302
Craig Tiller32946d32015-01-15 11:37:30 -0800303static void generate_huff_tables(void) {
Craig Tillerf96dfc32015-09-10 14:43:18 -0700304 unsigned i;
305 build_dec_tbl(state_index(0, symset_all(), &i), 0, 0, 0, NOT_SET,
306 symset_all());
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800307
308 nctbl = 0;
309 printf("static const gpr_uint8 next_tbl[%d] = {", nhuffstates);
310 for (i = 0; i < nhuffstates; i++) {
311 printf("%d,", ctbl_idx(huffstates[i].next));
312 }
313 printf("};\n");
314 dump_ctbl("next_sub_tbl");
315
316 nctbl = 0;
317 printf("static const gpr_uint16 emit_tbl[%d] = {", nhuffstates);
318 for (i = 0; i < nhuffstates; i++) {
319 printf("%d,", ctbl_idx(huffstates[i].emit));
320 }
321 printf("};\n");
322 dump_ctbl("emit_sub_tbl");
323}
324
Craig Tiller32946d32015-01-15 11:37:30 -0800325static void generate_base64_huff_encoder_table(void) {
nnoble0c475f02014-12-05 15:37:39 -0800326 static const char alphabet[] =
327 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
328 int i;
329
330 printf(
331 "static const struct { gpr_uint16 bits, gpr_uint8 length } "
332 "base64_syms[64] = {\n");
333 for (i = 0; i < 64; i++) {
334 printf("{0x%x, %d},", grpc_chttp2_huffsyms[(unsigned char)alphabet[i]].bits,
335 grpc_chttp2_huffsyms[(unsigned char)alphabet[i]].length);
336 }
337 printf("};\n");
338}
339
Craig Tiller32946d32015-01-15 11:37:30 -0800340static void generate_base64_inverse_table(void) {
ctiller33023c42014-12-12 16:28:33 -0800341 static const char alphabet[] =
342 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
343 unsigned char inverse[256];
Nicolas "Pixel" Noble85352632015-06-02 02:01:51 +0200344 unsigned i;
ctiller33023c42014-12-12 16:28:33 -0800345
346 memset(inverse, 255, sizeof(inverse));
347 for (i = 0; i < strlen(alphabet); i++) {
Craig Tiller6a6b36c2015-09-10 16:00:22 -0700348 inverse[(unsigned char)alphabet[i]] = (unsigned char)i;
ctiller33023c42014-12-12 16:28:33 -0800349 }
350
351 printf("static const gpr_uint8 inverse_base64[256] = {");
352 for (i = 0; i < 256; i++) {
353 printf("%d,", inverse[i]);
354 }
355 printf("};\n");
356}
357
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800358int main(void) {
359 generate_huff_tables();
360 generate_first_byte_lut();
nnoble0c475f02014-12-05 15:37:39 -0800361 generate_base64_huff_encoder_table();
ctiller33023c42014-12-12 16:28:33 -0800362 generate_base64_inverse_table();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800363
364 return 0;
Craig Tiller190d3602015-02-18 09:23:38 -0800365}