lsqpack 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }