lsqpack 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +19 -0
  3. data/Gemfile.lock +82 -0
  4. data/LICENSE +21 -0
  5. data/README.md +36 -0
  6. data/Rakefile +19 -0
  7. data/Steepfile +6 -0
  8. data/ext/lsqpack/extconf.rb +18 -0
  9. data/ext/lsqpack/lsqpack.c +426 -0
  10. data/ext/lsqpack/lsqpack.h +6 -0
  11. data/lib/lsqpack/version.rb +5 -0
  12. data/lib/lsqpack.rb +30 -0
  13. data/ls-qpack/.appveyor.yml +14 -0
  14. data/ls-qpack/.cirrus.yml +6 -0
  15. data/ls-qpack/.travis.yml +32 -0
  16. data/ls-qpack/CMakeLists.txt +66 -0
  17. data/ls-qpack/LICENSE +21 -0
  18. data/ls-qpack/README.md +65 -0
  19. data/ls-qpack/bin/CMakeLists.txt +21 -0
  20. data/ls-qpack/bin/encode-int.c +87 -0
  21. data/ls-qpack/bin/fuzz-decode.c +247 -0
  22. data/ls-qpack/bin/interop-decode.c +433 -0
  23. data/ls-qpack/bin/interop-encode.c +554 -0
  24. data/ls-qpack/deps/xxhash/xxhash.c +941 -0
  25. data/ls-qpack/deps/xxhash/xxhash.h +160 -0
  26. data/ls-qpack/fuzz/decode/a/README +3 -0
  27. data/ls-qpack/fuzz/decode/a/preamble +0 -0
  28. data/ls-qpack/fuzz/decode/a/test-cases/id_000000,sig_06,src_000390,op_havoc,rep_4 +0 -0
  29. data/ls-qpack/fuzz/decode/a/test-cases/id_000000,sig_06,src_000579,op_flip1,pos_14 +0 -0
  30. data/ls-qpack/fuzz/decode/a/test-cases/id_000000,src_000000,op_flip2,pos_12 +0 -0
  31. data/ls-qpack/fuzz/decode/a/test-cases/id_000001,sig_11,src_000579,op_havoc,rep_4 +0 -0
  32. data/ls-qpack/fuzz/decode/a/test-cases/id_000002,sig_11,src_000481,op_int16,pos_15,val_-1 +0 -0
  33. data/ls-qpack/fuzz/decode/a/test-cases/id_000002,src_000000,op_havoc,rep_8 +0 -0
  34. data/ls-qpack/fuzz/decode/a/test-cases/id_000006,src_000285,op_flip2,pos_14 +0 -0
  35. data/ls-qpack/fuzz/decode/a/test-cases/id_000008,src_000285,op_flip2,pos_20 +0 -0
  36. data/ls-qpack/fuzz/decode/a/test-cases/id_000010,src_000306,op_flip2,pos_75 +0 -0
  37. data/ls-qpack/fuzz/decode/a/test-cases/id_000011,src_000344,op_havoc,rep_2 +0 -0
  38. data/ls-qpack/fuzz/decode/a/test-cases/id_000014,src_000366,op_flip2,pos_28 +0 -0
  39. data/ls-qpack/fuzz/decode/b/README +1 -0
  40. data/ls-qpack/fuzz/decode/b/preamble +0 -0
  41. data/ls-qpack/fuzz/decode/b/test-cases/seed +0 -0
  42. data/ls-qpack/fuzz/decode/c/setup.sh +3 -0
  43. data/ls-qpack/fuzz/decode/c/test-cases/fb-req.qif.proxygen.out.256.100.0-chopped +0 -0
  44. data/ls-qpack/fuzz/decode/d/preamble +0 -0
  45. data/ls-qpack/fuzz/decode/d/setup.sh +3 -0
  46. data/ls-qpack/fuzz/decode/d/test-cases/fb-resp.minhq.256.128.0.ack +0 -0
  47. data/ls-qpack/fuzz/input/256.100.1/fb-req.out.256.100.1 +0 -0
  48. data/ls-qpack/fuzz/input/256.100.1/fb-resp.out.256.100.1 +0 -0
  49. data/ls-qpack/fuzz/input/256.100.1/netbsd.out.256.100.1 +0 -0
  50. data/ls-qpack/huff-tables.h +136247 -0
  51. data/ls-qpack/lsqpack.c +5547 -0
  52. data/ls-qpack/lsqpack.h +768 -0
  53. data/ls-qpack/test/CMakeLists.txt +76 -0
  54. data/ls-qpack/test/lsqpack-test.h +43 -0
  55. data/ls-qpack/test/qifs/fb-req.qif +4917 -0
  56. data/ls-qpack/test/qifs/fb-resp.qif +5982 -0
  57. data/ls-qpack/test/qifs/long-codes.qif +5984 -0
  58. data/ls-qpack/test/qifs/netbsd.qif +235 -0
  59. data/ls-qpack/test/run-qif.pl +97 -0
  60. data/ls-qpack/test/run-scenario.sh +68 -0
  61. data/ls-qpack/test/scenarios/0.95-reset.sce +10 -0
  62. data/ls-qpack/test/scenarios/cancel-stream.sce +22 -0
  63. data/ls-qpack/test/scenarios/drain-2.sce +37 -0
  64. data/ls-qpack/test/scenarios/drain.sce +37 -0
  65. data/ls-qpack/test/scenarios/end-dst-2.sce +14 -0
  66. data/ls-qpack/test/scenarios/end-dst.sce +14 -0
  67. data/ls-qpack/test/scenarios/incl-name.sce +13 -0
  68. data/ls-qpack/test/scenarios/multi-byte-int-dyn-ref-1.sce +110 -0
  69. data/ls-qpack/test/scenarios/multi-byte-int-dyn-ref-2.sce +161 -0
  70. data/ls-qpack/test/scenarios/post-base-1.sce +10 -0
  71. data/ls-qpack/test/scenarios/post-base-2.sce +13 -0
  72. data/ls-qpack/test/scenarios/post-base-nr.sce +10 -0
  73. data/ls-qpack/test/scenarios/set-max-cap.sce +15 -0
  74. data/ls-qpack/test/test_enc_str.c +139 -0
  75. data/ls-qpack/test/test_get_stx_id.c +144 -0
  76. data/ls-qpack/test/test_huff_dec.c +399 -0
  77. data/ls-qpack/test/test_int.c +220 -0
  78. data/ls-qpack/test/test_qpack.c +856 -0
  79. data/ls-qpack/test/test_read_enc_stream.c +256 -0
  80. data/ls-qpack/tools/har2qif.pl +139 -0
  81. data/ls-qpack/tools/randomize-cookies.pl +41 -0
  82. data/ls-qpack/tools/sort-qif.pl +31 -0
  83. data/ls-qpack/wincompat/getopt.c +758 -0
  84. data/ls-qpack/wincompat/getopt.h +131 -0
  85. data/ls-qpack/wincompat/getopt1.c +188 -0
  86. data/ls-qpack/wincompat/sys/queue.h +859 -0
  87. data/lsqpack.gemspec +39 -0
  88. data/sig/lsqpack.rbs +29 -0
  89. metadata +135 -0
@@ -0,0 +1,554 @@
1
+ /*
2
+ * QPACK Interop -- encode to intermediate format
3
+ *
4
+ * https://github.com/quicwg/base-drafts/wiki/QPACK-Offline-Interop
5
+ */
6
+
7
+ #include <assert.h>
8
+
9
+ #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
10
+ #include <sys/endian.h>
11
+ #define bswap_16 bswap16
12
+ #define bswap_32 bswap32
13
+ #define bswap_64 bswap64
14
+ #elif defined(__APPLE__)
15
+ #include <libkern/OSByteOrder.h>
16
+ #define bswap_16 OSSwapInt16
17
+ #define bswap_32 OSSwapInt32
18
+ #define bswap_64 OSSwapInt64
19
+ #elif defined(WIN32)
20
+ #define bswap_16 _byteswap_ushort
21
+ #define bswap_32 _byteswap_ulong
22
+ #define bswap_64 _byteswap_uint64
23
+ #else
24
+ #include <byteswap.h>
25
+ #endif
26
+
27
+ #include <errno.h>
28
+ #include <stdio.h>
29
+ #include <stdlib.h>
30
+ #include <string.h>
31
+ #ifdef WIN32
32
+ #include "getopt.h"
33
+ #else
34
+ #include <unistd.h>
35
+ #endif
36
+ #include <sys/types.h>
37
+ #include <sys/stat.h>
38
+ #include <fcntl.h>
39
+ #include <inttypes.h>
40
+
41
+ #include "lsqpack.h"
42
+
43
+ static int s_verbose;
44
+
45
+ unsigned char *
46
+ lsqpack_enc_int (unsigned char *dst, unsigned char *const end, uint64_t value,
47
+ unsigned prefix_bits);
48
+
49
+ static void
50
+ usage (const char *name)
51
+ {
52
+ fprintf(stderr,
53
+ "Usage: %s [options] [-i input] [-o output]\n"
54
+ "\n"
55
+ "Options:\n"
56
+ " -i FILE Input file. If not specified or set to `-', the input is\n"
57
+ " read from stdin.\n"
58
+ " -o FILE Output file. If not spepcified or set to `-', the output\n"
59
+ " is written to stdout.\n"
60
+ " -s NUMBER Maximum number of risked streams. Defaults to %u.\n"
61
+ " -t NUMBER Dynamic table size. Defaults to %u.\n"
62
+ " -a MODE Header acknowledgement mode. 0 means headers are never\n"
63
+ " acknowledged, non-zero means header blocks are acknowledged\n"
64
+ " immediately. Default value is 0.\n"
65
+ " -n Process annotations.\n"
66
+ " -S Server mode.\n"
67
+ " -D Do not emit \"Duplicate\" instructions.\n"
68
+ " -A Aggressive indexing.\n"
69
+ " -M Turn off memory guard.\n"
70
+ " -f Fast: use maximum output buffers.\n"
71
+ " -v Verbose: print various messages to stderr.\n"
72
+ "\n"
73
+ " -h Print this help screen and exit\n"
74
+ , name, LSQPACK_DEF_MAX_RISKED_STREAMS, LSQPACK_DEF_DYN_TABLE_SIZE);
75
+ }
76
+
77
+
78
+ static void
79
+ write_enc_stream (FILE *out, const unsigned char *enc_buf, size_t enc_sz)
80
+ {
81
+ uint64_t stream_id_enc;
82
+ uint32_t length_enc;
83
+ size_t written;
84
+
85
+ if (enc_sz <= 0)
86
+ return;
87
+ stream_id_enc = 0;
88
+ length_enc = enc_sz;
89
+ #if __BYTE_ORDER == __LITTLE_ENDIAN
90
+ stream_id_enc = bswap_64(stream_id_enc);
91
+ length_enc = bswap_32(length_enc);
92
+ #endif
93
+ written = fwrite(&stream_id_enc, 1, sizeof(stream_id_enc), out);
94
+ if (written != sizeof(stream_id_enc))
95
+ {
96
+ perror("fwrite");
97
+ exit(EXIT_FAILURE);
98
+ }
99
+ written = fwrite(&length_enc, 1, sizeof(length_enc), out);
100
+ if (written != sizeof(length_enc))
101
+ {
102
+ perror("fwrite");
103
+ exit(EXIT_FAILURE);
104
+ }
105
+ written = fwrite(enc_buf, 1, enc_sz, out);
106
+ if (written != enc_sz)
107
+ {
108
+ perror("fwrite");
109
+ exit(EXIT_FAILURE);
110
+ }
111
+ }
112
+
113
+
114
+ static void
115
+ write_enc_and_header_streams (FILE *out, unsigned stream_id,
116
+ const unsigned char *enc_buf, size_t enc_sz,
117
+ const unsigned char *pref_buf, size_t pref_sz,
118
+ const unsigned char *hea_buf, size_t hea_sz)
119
+ {
120
+ uint64_t stream_id_enc;
121
+ uint32_t length_enc;
122
+ size_t written;
123
+
124
+ if (s_verbose)
125
+ fprintf(stderr, "%s: stream %"PRIu32"\n", __func__, stream_id);
126
+
127
+ if (enc_sz)
128
+ {
129
+ stream_id_enc = 0;
130
+ length_enc = enc_sz;
131
+ #if __BYTE_ORDER == __LITTLE_ENDIAN
132
+ stream_id_enc = bswap_64(stream_id_enc);
133
+ length_enc = bswap_32(length_enc);
134
+ #endif
135
+ written = fwrite(&stream_id_enc, 1, sizeof(stream_id_enc), out);
136
+ if (written != sizeof(stream_id_enc))
137
+ goto write_err;
138
+ written = fwrite(&length_enc, 1, sizeof(length_enc), out);
139
+ if (written != sizeof(length_enc))
140
+ goto write_err;
141
+ written = fwrite(enc_buf, 1, enc_sz, out);
142
+ if (written != enc_sz)
143
+ goto write_err;
144
+ }
145
+
146
+ stream_id_enc = stream_id;
147
+ length_enc = pref_sz + hea_sz;
148
+ #if __BYTE_ORDER == __LITTLE_ENDIAN
149
+ stream_id_enc = bswap_64(stream_id_enc);
150
+ length_enc = bswap_32(length_enc);
151
+ #endif
152
+ written = fwrite(&stream_id_enc, 1, sizeof(stream_id_enc), out);
153
+ if (written != sizeof(stream_id_enc))
154
+ goto write_err;
155
+ written = fwrite(&length_enc, 1, sizeof(length_enc), out);
156
+ if (written != sizeof(length_enc))
157
+ goto write_err;
158
+ written = fwrite(pref_buf, 1, pref_sz, out);
159
+ if (written != pref_sz)
160
+ goto write_err;
161
+ written = fwrite(hea_buf, 1, hea_sz, out);
162
+ if (written != hea_sz)
163
+ goto write_err;
164
+ return;
165
+
166
+ write_err:
167
+ perror("fwrite");
168
+ exit(EXIT_FAILURE);
169
+ }
170
+
171
+
172
+ static unsigned s_saved_ins_count;
173
+ static int
174
+ ack_last_entry_id (struct lsqpack_enc *encoder)
175
+ {
176
+ unsigned char *end_cmd;
177
+ unsigned char cmd[80];
178
+ unsigned val;
179
+
180
+ if (s_verbose)
181
+ fprintf(stderr, "ACK entry ID %u\n", encoder->qpe_ins_count);
182
+
183
+ cmd[0] = 0x00;
184
+ val = encoder->qpe_ins_count - s_saved_ins_count;
185
+ s_saved_ins_count = encoder->qpe_ins_count;
186
+ end_cmd = lsqpack_enc_int(cmd, cmd + sizeof(cmd), val, 6);
187
+ assert(end_cmd > cmd);
188
+ return lsqpack_enc_decoder_in(encoder, cmd, end_cmd - cmd);
189
+ }
190
+
191
+
192
+ static int
193
+ ack_stream (struct lsqpack_enc *encoder, uint64_t stream_id)
194
+ {
195
+ unsigned char *end_cmd;
196
+ unsigned char cmd[80];
197
+
198
+ if (s_verbose)
199
+ fprintf(stderr, "ACK stream ID %"PRIu64"\n", stream_id);
200
+
201
+ cmd[0] = 0x80;
202
+ end_cmd = lsqpack_enc_int(cmd, cmd + sizeof(cmd), stream_id, 7);
203
+ assert(end_cmd > cmd);
204
+ return lsqpack_enc_decoder_in(encoder, cmd, end_cmd - cmd);
205
+ }
206
+
207
+
208
+ static int
209
+ sync_table (struct lsqpack_enc *encoder, uint64_t num_inserts)
210
+ {
211
+ unsigned char *end_cmd;
212
+ unsigned char cmd[80];
213
+
214
+ if (s_verbose)
215
+ fprintf(stderr, "Sync table num inserts %"PRIu64"\n", num_inserts);
216
+
217
+ cmd[0] = 0x00;
218
+ end_cmd = lsqpack_enc_int(cmd, cmd + sizeof(cmd), num_inserts, 6);
219
+ assert(end_cmd > cmd);
220
+ return lsqpack_enc_decoder_in(encoder, cmd, end_cmd - cmd);
221
+ }
222
+
223
+
224
+ static int
225
+ cancel_stream (struct lsqpack_enc *encoder, uint64_t stream_id)
226
+ {
227
+ unsigned char *end_cmd;
228
+ unsigned char cmd[80];
229
+
230
+ if (s_verbose)
231
+ fprintf(stderr, "Cancel stream ID %"PRIu64"\n", stream_id);
232
+
233
+ cmd[0] = 0x40;
234
+ end_cmd = lsqpack_enc_int(cmd, cmd + sizeof(cmd), stream_id, 6);
235
+ assert(end_cmd > cmd);
236
+ return lsqpack_enc_decoder_in(encoder, cmd, end_cmd - cmd);
237
+ }
238
+
239
+
240
+ int
241
+ main (int argc, char **argv)
242
+ {
243
+ FILE *in = stdin;
244
+ FILE *out = stdout;
245
+ int opt;
246
+ unsigned dyn_table_size = LSQPACK_DEF_DYN_TABLE_SIZE,
247
+ max_risked_streams = LSQPACK_DEF_MAX_RISKED_STREAMS;
248
+ unsigned lineno, stream_id;
249
+ struct lsqpack_enc encoder;
250
+ char *line, *end, *tab;
251
+ ssize_t pref_sz;
252
+ enum lsqpack_enc_status st;
253
+ enum lsqpack_enc_opts enc_opts = 0;
254
+ size_t enc_sz, hea_sz, enc_off, hea_off;
255
+ int header_opened, r;
256
+ unsigned arg;
257
+ enum { ACK_NEVER, ACK_IMMEDIATE, } ack_mode = ACK_NEVER;
258
+ int process_annotations = 0;
259
+ char line_buf[0x1000];
260
+ unsigned char tsu_buf[LSQPACK_LONGEST_SDTC];
261
+ size_t tsu_buf_sz;
262
+ enum lsqpack_enc_header_flags hflags;
263
+ int fast = 0;
264
+ unsigned char enc_buf[0x1000], hea_buf[0x1000], pref_buf[0x20];
265
+
266
+ while (-1 != (opt = getopt(argc, argv, "ADMSa:i:no:s:t:hvf")))
267
+ {
268
+ switch (opt)
269
+ {
270
+ case 'S':
271
+ enc_opts |= LSQPACK_ENC_OPT_SERVER;
272
+ break;
273
+ case 'D':
274
+ enc_opts |= LSQPACK_ENC_OPT_NO_DUP;
275
+ break;
276
+ case 'A':
277
+ enc_opts |= LSQPACK_ENC_OPT_IX_AGGR;
278
+ break;
279
+ case 'M':
280
+ enc_opts |= LSQPACK_ENC_OPT_NO_MEM_GUARD;
281
+ break;
282
+ case 'n':
283
+ ++process_annotations;
284
+ break;
285
+ case 'a':
286
+ ack_mode = atoi(optarg) ? ACK_IMMEDIATE : ACK_NEVER;
287
+ break;
288
+ case 'i':
289
+ if (0 != strcmp(optarg, "-"))
290
+ {
291
+ in = fopen(optarg, "r");
292
+ if (!in)
293
+ {
294
+ fprintf(stderr, "cannot open `%s' for reading: %s\n",
295
+ optarg, strerror(errno));
296
+ exit(EXIT_FAILURE);
297
+ }
298
+ }
299
+ break;
300
+ case 'o':
301
+ if (0 != strcmp(optarg, "-"))
302
+ {
303
+ out = fopen(optarg, "wb");
304
+ if (!out)
305
+ {
306
+ fprintf(stderr, "cannot open `%s' for writing: %s\n",
307
+ optarg, strerror(errno));
308
+ exit(EXIT_FAILURE);
309
+ }
310
+ }
311
+ break;
312
+ case 's':
313
+ max_risked_streams = atoi(optarg);
314
+ break;
315
+ case 't':
316
+ dyn_table_size = atoi(optarg);
317
+ break;
318
+ case 'h':
319
+ usage(argv[0]);
320
+ exit(EXIT_SUCCESS);
321
+ case 'f':
322
+ fast = 1;
323
+ break;
324
+ case 'v':
325
+ ++s_verbose;
326
+ break;
327
+ default:
328
+ exit(EXIT_FAILURE);
329
+ }
330
+ }
331
+
332
+ tsu_buf_sz = sizeof(tsu_buf);
333
+ if (0 != lsqpack_enc_init(&encoder, s_verbose ? stderr : NULL, dyn_table_size,
334
+ dyn_table_size, max_risked_streams, enc_opts, tsu_buf,
335
+ &tsu_buf_sz))
336
+ {
337
+ perror("lsqpack_enc_init");
338
+ exit(EXIT_FAILURE);
339
+ }
340
+
341
+ lineno = 0;
342
+ stream_id = 0;
343
+ enc_off = 0;
344
+ hea_off = 0;
345
+ header_opened = 0;
346
+
347
+ while (line = fgets(line_buf, sizeof(line_buf), in), line != NULL)
348
+ {
349
+ ++lineno;
350
+ end = strchr(line, '\n');
351
+ if (!end)
352
+ {
353
+ fprintf(stderr, "no newline on line %u\n", lineno);
354
+ exit(EXIT_FAILURE);
355
+ }
356
+ *end = '\0';
357
+
358
+ if (end == line)
359
+ {
360
+ if (header_opened)
361
+ {
362
+ size_t sz, pref_max = sizeof(pref_buf);
363
+ for (sz = (fast ? pref_max : 0); sz <= pref_max; sz++)
364
+ {
365
+ pref_sz = lsqpack_enc_end_header(&encoder, pref_buf, sz, &hflags);
366
+ if (pref_sz > 0)
367
+ {
368
+ if (max_risked_streams == 0)
369
+ assert(!(hflags & LSQECH_REF_AT_RISK));
370
+ break;
371
+ }
372
+ }
373
+ assert(pref_sz <= lsqpack_enc_header_block_prefix_size(&encoder));
374
+ if (pref_sz < 0)
375
+ {
376
+ fprintf(stderr, "end_header failed: %s", strerror(errno));
377
+ exit(EXIT_FAILURE);
378
+ }
379
+ if (ack_mode == ACK_IMMEDIATE)
380
+ {
381
+ if (!(2 == pref_sz && pref_buf[0] == 0 && pref_buf[1] == 0))
382
+ r = ack_stream(&encoder, stream_id);
383
+ else
384
+ r = 0;
385
+ if (r == 0 && encoder.qpe_ins_count > s_saved_ins_count)
386
+ r = ack_last_entry_id(&encoder);
387
+ else
388
+ r = 0;
389
+ if (r != 0)
390
+ {
391
+ fprintf(stderr, "acking stream %u failed: %s", stream_id,
392
+ strerror(errno));
393
+ exit(EXIT_FAILURE);
394
+ }
395
+ }
396
+ if (s_verbose)
397
+ fprintf(stderr, "compression ratio: %.3f\n",
398
+ lsqpack_enc_ratio(&encoder));
399
+ write_enc_and_header_streams(out, stream_id, enc_buf, enc_off,
400
+ pref_buf, pref_sz, hea_buf, hea_off);
401
+ enc_off = 0;
402
+ hea_off = 0;
403
+ header_opened = 0;
404
+ }
405
+ continue;
406
+ }
407
+
408
+ if (*line == '#')
409
+ {
410
+ if (!process_annotations)
411
+ continue;
412
+
413
+ /* Lines starting with ## are potential annotations */
414
+ if (ack_mode != ACK_IMMEDIATE
415
+ /* Ignore ACK annotations in immediate ACK mode, as we do
416
+ * not tolerate duplicate ACKs.
417
+ */
418
+ && 1 == sscanf(line, "## %*[a] %u ", &arg))
419
+ {
420
+ if (0 != ack_stream(&encoder, arg))
421
+ {
422
+ fprintf(stderr, "ACKing stream ID %u failed\n", arg);
423
+ exit(EXIT_FAILURE);
424
+ }
425
+ }
426
+ else if (1 == sscanf(line, "## %*[s] %u", &arg))
427
+ sync_table(&encoder, arg);
428
+ else if (1 == sscanf(line, "## %*[c] %u", &arg))
429
+ cancel_stream(&encoder, arg);
430
+ else if (1 == sscanf(line, "## %*[t] %u", &arg))
431
+ {
432
+ tsu_buf_sz = sizeof(tsu_buf);
433
+ if (0 != lsqpack_enc_set_max_capacity(&encoder, arg, tsu_buf,
434
+ &tsu_buf_sz))
435
+ {
436
+ fprintf(stderr, "cannot set capacity to %u: %s\n", arg,
437
+ strerror(errno));
438
+ exit(EXIT_FAILURE);
439
+ }
440
+ write_enc_stream(out, tsu_buf, tsu_buf_sz);
441
+ }
442
+ continue;
443
+ }
444
+
445
+ tab = strchr(line, '\t');
446
+ if (!tab)
447
+ {
448
+ fprintf(stderr, "no TAB on line %u\n", lineno);
449
+ exit(EXIT_FAILURE);
450
+ }
451
+
452
+ if (!header_opened)
453
+ {
454
+ ++stream_id;
455
+ if (0 != lsqpack_enc_start_header(&encoder, stream_id, 0))
456
+ {
457
+ fprintf(stderr, "start_header failed: %s\n", strerror(errno));
458
+ exit(EXIT_FAILURE);
459
+ }
460
+ header_opened = 1;
461
+ }
462
+ if (fast)
463
+ {
464
+ enc_sz = sizeof(enc_buf) - enc_off;
465
+ hea_sz = sizeof(hea_buf) - hea_off;
466
+ }
467
+ else
468
+ {
469
+ /* Increase buffers one by one to exercise error conditions */
470
+ enc_sz = 0;
471
+ hea_sz = 0;
472
+ }
473
+ while (1)
474
+ {
475
+ st = lsqpack_enc_encode(&encoder, enc_buf + enc_off, &enc_sz,
476
+ hea_buf + hea_off, &hea_sz, line, tab - line,
477
+ tab + 1, end - tab - 1, 0);
478
+ switch (st)
479
+ {
480
+ case LQES_NOBUF_ENC:
481
+ if (enc_sz < sizeof(enc_buf) - enc_off)
482
+ ++enc_sz;
483
+ else
484
+ assert(0);
485
+ break;
486
+ case LQES_NOBUF_HEAD:
487
+ if (hea_sz < sizeof(hea_buf) - hea_off)
488
+ ++hea_sz;
489
+ else
490
+ assert(0);
491
+ break;
492
+ default:
493
+ assert(st == LQES_OK);
494
+ goto end_encode_one_header;
495
+ }
496
+ }
497
+ if (st != LQES_OK)
498
+ {
499
+ /* It could only run of of output space, so it's not really an
500
+ * error, but we make no provision in the interop encoder to
501
+ * grow the buffers.
502
+ */
503
+ fprintf(stderr, "Could not encode header on line %u: %u\n",
504
+ lineno, st);
505
+ exit(EXIT_FAILURE);
506
+ }
507
+ end_encode_one_header:
508
+ enc_off += enc_sz;
509
+ hea_off += hea_sz;
510
+ }
511
+
512
+ if (s_verbose)
513
+ fprintf(stderr, "exited while loop\n");
514
+
515
+ (void) fclose(in);
516
+
517
+ if (header_opened)
518
+ {
519
+ if (s_verbose)
520
+ fprintf(stderr, "close opened header\n");
521
+ pref_sz = lsqpack_enc_end_header(&encoder, pref_buf, sizeof(pref_buf),
522
+ &hflags);
523
+ if (pref_sz < 0)
524
+ {
525
+ fprintf(stderr, "end_header failed: %s", strerror(errno));
526
+ exit(EXIT_FAILURE);
527
+ }
528
+ if (max_risked_streams == 0)
529
+ assert(!(hflags & LSQECH_REF_AT_RISK));
530
+ if (ack_mode == ACK_IMMEDIATE
531
+ && !(2 == pref_sz && pref_buf[0] == 0 && pref_buf[1] == 0)
532
+ && 0 != ack_stream(&encoder, stream_id))
533
+ {
534
+ fprintf(stderr, "acking stream %u failed: %s", stream_id,
535
+ strerror(errno));
536
+ exit(EXIT_FAILURE);
537
+ }
538
+ if (s_verbose)
539
+ fprintf(stderr, "compression ratio: %.3f\n",
540
+ lsqpack_enc_ratio(&encoder));
541
+ write_enc_and_header_streams(out, stream_id, enc_buf, enc_off, pref_buf,
542
+ pref_sz, hea_buf, hea_off);
543
+ }
544
+
545
+ lsqpack_enc_cleanup(&encoder);
546
+
547
+ if (0 != fclose(out))
548
+ {
549
+ perror("fclose(out)");
550
+ exit(EXIT_FAILURE);
551
+ }
552
+
553
+ exit(EXIT_SUCCESS);
554
+ }