1387f7481SDmitri Tikhonov/* 2387f7481SDmitri Tikhonov * QPACK Interop -- encode to intermediate format 3387f7481SDmitri Tikhonov * 4387f7481SDmitri Tikhonov * https://github.com/quicwg/base-drafts/wiki/QPACK-Offline-Interop 5387f7481SDmitri Tikhonov */ 6387f7481SDmitri Tikhonov 7a4e3cfd9SDmitri Tikhonov#include <assert.h> 8446dba69SDmitri Tikhonov 9446dba69SDmitri Tikhonov#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) 10446dba69SDmitri Tikhonov#include <sys/endian.h> 11446dba69SDmitri Tikhonov#define bswap_16 bswap16 12446dba69SDmitri Tikhonov#define bswap_32 bswap32 13446dba69SDmitri Tikhonov#define bswap_64 bswap64 14446dba69SDmitri Tikhonov#elif defined(__APPLE__) 15446dba69SDmitri Tikhonov#include <libkern/OSByteOrder.h> 16446dba69SDmitri Tikhonov#define bswap_16 OSSwapInt16 17446dba69SDmitri Tikhonov#define bswap_32 OSSwapInt32 18446dba69SDmitri Tikhonov#define bswap_64 OSSwapInt64 19446dba69SDmitri Tikhonov#elif defined(WIN32) 20446dba69SDmitri Tikhonov#define bswap_16 _byteswap_ushort 21446dba69SDmitri Tikhonov#define bswap_32 _byteswap_ulong 22446dba69SDmitri Tikhonov#define bswap_64 _byteswap_uint64 23446dba69SDmitri Tikhonov#else 24387f7481SDmitri Tikhonov#include <byteswap.h> 25446dba69SDmitri Tikhonov#endif 26446dba69SDmitri Tikhonov 27387f7481SDmitri Tikhonov#include <errno.h> 28387f7481SDmitri Tikhonov#include <stdio.h> 29387f7481SDmitri Tikhonov#include <stdlib.h> 30387f7481SDmitri Tikhonov#include <string.h> 31205a2804SDmitri Tikhonov#ifdef WIN32 32948d3c75STyler Young#include <getopt.h> 33205a2804SDmitri Tikhonov#else 34387f7481SDmitri Tikhonov#include <unistd.h> 35205a2804SDmitri Tikhonov#endif 36387f7481SDmitri Tikhonov#include <sys/types.h> 37387f7481SDmitri Tikhonov#include <sys/stat.h> 38387f7481SDmitri Tikhonov#include <fcntl.h> 390e41c471SDmitri Tikhonov#include <inttypes.h> 40387f7481SDmitri Tikhonov 41387f7481SDmitri Tikhonov#include "lsqpack.h" 4260620859SDmitri Tikhonov#include "lsxpack_header.h" 43387f7481SDmitri Tikhonov 441999dccfSDmitri Tikhonovstatic int s_verbose; 451999dccfSDmitri Tikhonov 46a4e3cfd9SDmitri Tikhonovunsigned char * 47a4e3cfd9SDmitri Tikhonovlsqpack_enc_int (unsigned char *dst, unsigned char *const end, uint64_t value, 48a4e3cfd9SDmitri Tikhonov unsigned prefix_bits); 49a4e3cfd9SDmitri Tikhonov 50387f7481SDmitri Tikhonovstatic void 51387f7481SDmitri Tikhonovusage (const char *name) 52387f7481SDmitri Tikhonov{ 53387f7481SDmitri Tikhonov fprintf(stderr, 54387f7481SDmitri Tikhonov"Usage: %s [options] [-i input] [-o output]\n" 55387f7481SDmitri Tikhonov"\n" 56387f7481SDmitri Tikhonov"Options:\n" 57387f7481SDmitri Tikhonov" -i FILE Input file. If not specified or set to `-', the input is\n" 58387f7481SDmitri Tikhonov" read from stdin.\n" 59387f7481SDmitri Tikhonov" -o FILE Output file. If not spepcified or set to `-', the output\n" 60387f7481SDmitri Tikhonov" is written to stdout.\n" 61387f7481SDmitri Tikhonov" -s NUMBER Maximum number of risked streams. Defaults to %u.\n" 62387f7481SDmitri Tikhonov" -t NUMBER Dynamic table size. Defaults to %u.\n" 630e41c471SDmitri Tikhonov" -a MODE Header acknowledgement mode. 0 means headers are never\n" 640e41c471SDmitri Tikhonov" acknowledged, non-zero means header blocks are acknowledged\n" 650e41c471SDmitri Tikhonov" immediately. Default value is 0.\n" 66fdc428d6SDmitri Tikhonov" -n Process annotations.\n" 67f3eec0d9SDmitri Tikhonov" -S Server mode.\n" 6834b3ff7cSDmitri Tikhonov" -D Do not emit \"Duplicate\" instructions.\n" 69d35900e5SDmitri Tikhonov" -A Aggressive indexing.\n" 70ecec593fSDmitri Tikhonov" -M Turn off memory guard.\n" 712499f175SDmitri Tikhonov" -f Fast: use maximum output buffers.\n" 721999dccfSDmitri Tikhonov" -v Verbose: print various messages to stderr.\n" 73387f7481SDmitri Tikhonov"\n" 74387f7481SDmitri Tikhonov" -h Print this help screen and exit\n" 75387f7481SDmitri Tikhonov , name, LSQPACK_DEF_MAX_RISKED_STREAMS, LSQPACK_DEF_DYN_TABLE_SIZE); 76387f7481SDmitri Tikhonov} 77387f7481SDmitri Tikhonov 78387f7481SDmitri Tikhonov 798624e82bSDmitri Tikhonovstatic void 80205a2804SDmitri Tikhonovwrite_enc_stream (FILE *out, const unsigned char *enc_buf, size_t enc_sz) 818624e82bSDmitri Tikhonov{ 828624e82bSDmitri Tikhonov uint64_t stream_id_enc; 838624e82bSDmitri Tikhonov uint32_t length_enc; 84205a2804SDmitri Tikhonov size_t written; 858624e82bSDmitri Tikhonov 8650c5c9faSStephen Petrides if (enc_sz <= 0) 8750c5c9faSStephen Petrides return; 888624e82bSDmitri Tikhonov stream_id_enc = 0; 898624e82bSDmitri Tikhonov length_enc = enc_sz; 908624e82bSDmitri Tikhonov#if __BYTE_ORDER == __LITTLE_ENDIAN 918624e82bSDmitri Tikhonov stream_id_enc = bswap_64(stream_id_enc); 928624e82bSDmitri Tikhonov length_enc = bswap_32(length_enc); 938624e82bSDmitri Tikhonov#endif 94205a2804SDmitri Tikhonov written = fwrite(&stream_id_enc, 1, sizeof(stream_id_enc), out); 95205a2804SDmitri Tikhonov if (written != sizeof(stream_id_enc)) 96205a2804SDmitri Tikhonov { 97205a2804SDmitri Tikhonov perror("fwrite"); 98205a2804SDmitri Tikhonov exit(EXIT_FAILURE); 99205a2804SDmitri Tikhonov } 100205a2804SDmitri Tikhonov written = fwrite(&length_enc, 1, sizeof(length_enc), out); 101205a2804SDmitri Tikhonov if (written != sizeof(length_enc)) 102205a2804SDmitri Tikhonov { 103205a2804SDmitri Tikhonov perror("fwrite"); 104205a2804SDmitri Tikhonov exit(EXIT_FAILURE); 105205a2804SDmitri Tikhonov } 106205a2804SDmitri Tikhonov written = fwrite(enc_buf, 1, enc_sz, out); 107205a2804SDmitri Tikhonov if (written != enc_sz) 108205a2804SDmitri Tikhonov { 109205a2804SDmitri Tikhonov perror("fwrite"); 110205a2804SDmitri Tikhonov exit(EXIT_FAILURE); 111205a2804SDmitri Tikhonov } 1128624e82bSDmitri Tikhonov} 1138624e82bSDmitri Tikhonov 1148624e82bSDmitri Tikhonov 115387f7481SDmitri Tikhonovstatic void 116205a2804SDmitri Tikhonovwrite_enc_and_header_streams (FILE *out, unsigned stream_id, 117387f7481SDmitri Tikhonov const unsigned char *enc_buf, size_t enc_sz, 118387f7481SDmitri Tikhonov const unsigned char *pref_buf, size_t pref_sz, 119387f7481SDmitri Tikhonov const unsigned char *hea_buf, size_t hea_sz) 120387f7481SDmitri Tikhonov{ 121387f7481SDmitri Tikhonov uint64_t stream_id_enc; 122387f7481SDmitri Tikhonov uint32_t length_enc; 123205a2804SDmitri Tikhonov size_t written; 124205a2804SDmitri Tikhonov 125205a2804SDmitri Tikhonov if (s_verbose) 126205a2804SDmitri Tikhonov fprintf(stderr, "%s: stream %"PRIu32"\n", __func__, stream_id); 127387f7481SDmitri Tikhonov 128387f7481SDmitri Tikhonov if (enc_sz) 129387f7481SDmitri Tikhonov { 130387f7481SDmitri Tikhonov stream_id_enc = 0; 131387f7481SDmitri Tikhonov length_enc = enc_sz; 132387f7481SDmitri Tikhonov#if __BYTE_ORDER == __LITTLE_ENDIAN 133387f7481SDmitri Tikhonov stream_id_enc = bswap_64(stream_id_enc); 134387f7481SDmitri Tikhonov length_enc = bswap_32(length_enc); 135387f7481SDmitri Tikhonov#endif 136205a2804SDmitri Tikhonov written = fwrite(&stream_id_enc, 1, sizeof(stream_id_enc), out); 137205a2804SDmitri Tikhonov if (written != sizeof(stream_id_enc)) 138205a2804SDmitri Tikhonov goto write_err; 139205a2804SDmitri Tikhonov written = fwrite(&length_enc, 1, sizeof(length_enc), out); 140205a2804SDmitri Tikhonov if (written != sizeof(length_enc)) 141205a2804SDmitri Tikhonov goto write_err; 142205a2804SDmitri Tikhonov written = fwrite(enc_buf, 1, enc_sz, out); 143205a2804SDmitri Tikhonov if (written != enc_sz) 144205a2804SDmitri Tikhonov goto write_err; 145387f7481SDmitri Tikhonov } 146387f7481SDmitri Tikhonov 147387f7481SDmitri Tikhonov stream_id_enc = stream_id; 148387f7481SDmitri Tikhonov length_enc = pref_sz + hea_sz; 149387f7481SDmitri Tikhonov#if __BYTE_ORDER == __LITTLE_ENDIAN 150387f7481SDmitri Tikhonov stream_id_enc = bswap_64(stream_id_enc); 151387f7481SDmitri Tikhonov length_enc = bswap_32(length_enc); 152387f7481SDmitri Tikhonov#endif 153205a2804SDmitri Tikhonov written = fwrite(&stream_id_enc, 1, sizeof(stream_id_enc), out); 154205a2804SDmitri Tikhonov if (written != sizeof(stream_id_enc)) 155205a2804SDmitri Tikhonov goto write_err; 156205a2804SDmitri Tikhonov written = fwrite(&length_enc, 1, sizeof(length_enc), out); 157205a2804SDmitri Tikhonov if (written != sizeof(length_enc)) 158205a2804SDmitri Tikhonov goto write_err; 159205a2804SDmitri Tikhonov written = fwrite(pref_buf, 1, pref_sz, out); 160205a2804SDmitri Tikhonov if (written != pref_sz) 161205a2804SDmitri Tikhonov goto write_err; 162205a2804SDmitri Tikhonov written = fwrite(hea_buf, 1, hea_sz, out); 163205a2804SDmitri Tikhonov if (written != hea_sz) 164205a2804SDmitri Tikhonov goto write_err; 165205a2804SDmitri Tikhonov return; 166205a2804SDmitri Tikhonov 167205a2804SDmitri Tikhonov write_err: 168205a2804SDmitri Tikhonov perror("fwrite"); 169205a2804SDmitri Tikhonov exit(EXIT_FAILURE); 170387f7481SDmitri Tikhonov} 171387f7481SDmitri Tikhonov 172387f7481SDmitri Tikhonov 173e6970152SDmitri Tikhonovstatic unsigned s_saved_ins_count; 174e6970152SDmitri Tikhonovstatic int 175e6970152SDmitri Tikhonovack_last_entry_id (struct lsqpack_enc *encoder) 176e6970152SDmitri Tikhonov{ 177e6970152SDmitri Tikhonov unsigned char *end_cmd; 178e6970152SDmitri Tikhonov unsigned char cmd[80]; 179e6970152SDmitri Tikhonov unsigned val; 180e6970152SDmitri Tikhonov 181e6970152SDmitri Tikhonov if (s_verbose) 182e6970152SDmitri Tikhonov fprintf(stderr, "ACK entry ID %u\n", encoder->qpe_ins_count); 183e6970152SDmitri Tikhonov 184e6970152SDmitri Tikhonov cmd[0] = 0x00; 185e6970152SDmitri Tikhonov val = encoder->qpe_ins_count - s_saved_ins_count; 186e6970152SDmitri Tikhonov s_saved_ins_count = encoder->qpe_ins_count; 187e6970152SDmitri Tikhonov end_cmd = lsqpack_enc_int(cmd, cmd + sizeof(cmd), val, 6); 188e6970152SDmitri Tikhonov assert(end_cmd > cmd); 189e6970152SDmitri Tikhonov return lsqpack_enc_decoder_in(encoder, cmd, end_cmd - cmd); 190e6970152SDmitri Tikhonov} 191e6970152SDmitri Tikhonov 192e6970152SDmitri Tikhonov 1930e41c471SDmitri Tikhonovstatic int 1940e41c471SDmitri Tikhonovack_stream (struct lsqpack_enc *encoder, uint64_t stream_id) 1950e41c471SDmitri Tikhonov{ 1960e41c471SDmitri Tikhonov unsigned char *end_cmd; 1970e41c471SDmitri Tikhonov unsigned char cmd[80]; 1980e41c471SDmitri Tikhonov 1990e41c471SDmitri Tikhonov if (s_verbose) 2000e41c471SDmitri Tikhonov fprintf(stderr, "ACK stream ID %"PRIu64"\n", stream_id); 2010e41c471SDmitri Tikhonov 2020e41c471SDmitri Tikhonov cmd[0] = 0x80; 2030e41c471SDmitri Tikhonov end_cmd = lsqpack_enc_int(cmd, cmd + sizeof(cmd), stream_id, 7); 2040e41c471SDmitri Tikhonov assert(end_cmd > cmd); 2050e41c471SDmitri Tikhonov return lsqpack_enc_decoder_in(encoder, cmd, end_cmd - cmd); 2060e41c471SDmitri Tikhonov} 2070e41c471SDmitri Tikhonov 2080e41c471SDmitri Tikhonov 20904dd4598SDmitri Tikhonovstatic int 21091dfe80fSStephen Petridessync_table (struct lsqpack_enc *encoder, uint64_t num_inserts) 21191dfe80fSStephen Petrides{ 21291dfe80fSStephen Petrides unsigned char *end_cmd; 21391dfe80fSStephen Petrides unsigned char cmd[80]; 21491dfe80fSStephen Petrides 21591dfe80fSStephen Petrides if (s_verbose) 21691dfe80fSStephen Petrides fprintf(stderr, "Sync table num inserts %"PRIu64"\n", num_inserts); 21791dfe80fSStephen Petrides 21891dfe80fSStephen Petrides cmd[0] = 0x00; 21991dfe80fSStephen Petrides end_cmd = lsqpack_enc_int(cmd, cmd + sizeof(cmd), num_inserts, 6); 22091dfe80fSStephen Petrides assert(end_cmd > cmd); 22191dfe80fSStephen Petrides return lsqpack_enc_decoder_in(encoder, cmd, end_cmd - cmd); 22291dfe80fSStephen Petrides} 22391dfe80fSStephen Petrides 22491dfe80fSStephen Petrides 22591dfe80fSStephen Petridesstatic int 22604dd4598SDmitri Tikhonovcancel_stream (struct lsqpack_enc *encoder, uint64_t stream_id) 22704dd4598SDmitri Tikhonov{ 22804dd4598SDmitri Tikhonov unsigned char *end_cmd; 22904dd4598SDmitri Tikhonov unsigned char cmd[80]; 23004dd4598SDmitri Tikhonov 23104dd4598SDmitri Tikhonov if (s_verbose) 23204dd4598SDmitri Tikhonov fprintf(stderr, "Cancel stream ID %"PRIu64"\n", stream_id); 23304dd4598SDmitri Tikhonov 23404dd4598SDmitri Tikhonov cmd[0] = 0x40; 23504dd4598SDmitri Tikhonov end_cmd = lsqpack_enc_int(cmd, cmd + sizeof(cmd), stream_id, 6); 23604dd4598SDmitri Tikhonov assert(end_cmd > cmd); 23704dd4598SDmitri Tikhonov return lsqpack_enc_decoder_in(encoder, cmd, end_cmd - cmd); 23804dd4598SDmitri Tikhonov} 23904dd4598SDmitri Tikhonov 24004dd4598SDmitri Tikhonov 241387f7481SDmitri Tikhonovint 242387f7481SDmitri Tikhonovmain (int argc, char **argv) 243387f7481SDmitri Tikhonov{ 244387f7481SDmitri Tikhonov FILE *in = stdin; 245205a2804SDmitri Tikhonov FILE *out = stdout; 246387f7481SDmitri Tikhonov int opt; 247387f7481SDmitri Tikhonov unsigned dyn_table_size = LSQPACK_DEF_DYN_TABLE_SIZE, 248387f7481SDmitri Tikhonov max_risked_streams = LSQPACK_DEF_MAX_RISKED_STREAMS; 249387f7481SDmitri Tikhonov unsigned lineno, stream_id; 250387f7481SDmitri Tikhonov struct lsqpack_enc encoder; 251387f7481SDmitri Tikhonov char *line, *end, *tab; 252387f7481SDmitri Tikhonov ssize_t pref_sz; 253387f7481SDmitri Tikhonov enum lsqpack_enc_status st; 25407831cdfSDmitri Tikhonov enum lsqpack_enc_opts enc_opts = 0; 255387f7481SDmitri Tikhonov size_t enc_sz, hea_sz, enc_off, hea_off; 256e6970152SDmitri Tikhonov int header_opened, r; 257a4e3cfd9SDmitri Tikhonov unsigned arg; 2580e41c471SDmitri Tikhonov enum { ACK_NEVER, ACK_IMMEDIATE, } ack_mode = ACK_NEVER; 259fdc428d6SDmitri Tikhonov int process_annotations = 0; 260387f7481SDmitri Tikhonov char line_buf[0x1000]; 261a122a7bdSDmitri Tikhonov unsigned char tsu_buf[LSQPACK_LONGEST_SDTC]; 2628624e82bSDmitri Tikhonov size_t tsu_buf_sz; 2633ce33568SDmitri Tikhonov enum lsqpack_enc_header_flags hflags; 2642499f175SDmitri Tikhonov int fast = 0; 26560620859SDmitri Tikhonov struct lsxpack_header xhdr; 266387f7481SDmitri Tikhonov unsigned char enc_buf[0x1000], hea_buf[0x1000], pref_buf[0x20]; 267387f7481SDmitri Tikhonov 2682499f175SDmitri Tikhonov while (-1 != (opt = getopt(argc, argv, "ADMSa:i:no:s:t:hvf"))) 269387f7481SDmitri Tikhonov { 270387f7481SDmitri Tikhonov switch (opt) 271387f7481SDmitri Tikhonov { 272f3eec0d9SDmitri Tikhonov case 'S': 273f3eec0d9SDmitri Tikhonov enc_opts |= LSQPACK_ENC_OPT_SERVER; 274f3eec0d9SDmitri Tikhonov break; 275f3eec0d9SDmitri Tikhonov case 'D': 27607831cdfSDmitri Tikhonov enc_opts |= LSQPACK_ENC_OPT_NO_DUP; 277f3eec0d9SDmitri Tikhonov break; 278d35900e5SDmitri Tikhonov case 'A': 2798fb62aa5SDmitri Tikhonov enc_opts |= LSQPACK_ENC_OPT_IX_AGGR; 280d35900e5SDmitri Tikhonov break; 281ecec593fSDmitri Tikhonov case 'M': 282ecec593fSDmitri Tikhonov enc_opts |= LSQPACK_ENC_OPT_NO_MEM_GUARD; 283ecec593fSDmitri Tikhonov break; 284fdc428d6SDmitri Tikhonov case 'n': 285fdc428d6SDmitri Tikhonov ++process_annotations; 286fdc428d6SDmitri Tikhonov break; 2870e41c471SDmitri Tikhonov case 'a': 2880e41c471SDmitri Tikhonov ack_mode = atoi(optarg) ? ACK_IMMEDIATE : ACK_NEVER; 2890e41c471SDmitri Tikhonov break; 290387f7481SDmitri Tikhonov case 'i': 291387f7481SDmitri Tikhonov if (0 != strcmp(optarg, "-")) 292387f7481SDmitri Tikhonov { 293387f7481SDmitri Tikhonov in = fopen(optarg, "r"); 294387f7481SDmitri Tikhonov if (!in) 295387f7481SDmitri Tikhonov { 296387f7481SDmitri Tikhonov fprintf(stderr, "cannot open `%s' for reading: %s\n", 297387f7481SDmitri Tikhonov optarg, strerror(errno)); 298387f7481SDmitri Tikhonov exit(EXIT_FAILURE); 299387f7481SDmitri Tikhonov } 300387f7481SDmitri Tikhonov } 301387f7481SDmitri Tikhonov break; 302387f7481SDmitri Tikhonov case 'o': 303387f7481SDmitri Tikhonov if (0 != strcmp(optarg, "-")) 304387f7481SDmitri Tikhonov { 305205a2804SDmitri Tikhonov out = fopen(optarg, "wb"); 306205a2804SDmitri Tikhonov if (!out) 307387f7481SDmitri Tikhonov { 308387f7481SDmitri Tikhonov fprintf(stderr, "cannot open `%s' for writing: %s\n", 309387f7481SDmitri Tikhonov optarg, strerror(errno)); 310387f7481SDmitri Tikhonov exit(EXIT_FAILURE); 311387f7481SDmitri Tikhonov } 312387f7481SDmitri Tikhonov } 313387f7481SDmitri Tikhonov break; 314387f7481SDmitri Tikhonov case 's': 315387f7481SDmitri Tikhonov max_risked_streams = atoi(optarg); 316387f7481SDmitri Tikhonov break; 317387f7481SDmitri Tikhonov case 't': 318387f7481SDmitri Tikhonov dyn_table_size = atoi(optarg); 319387f7481SDmitri Tikhonov break; 320387f7481SDmitri Tikhonov case 'h': 321387f7481SDmitri Tikhonov usage(argv[0]); 322387f7481SDmitri Tikhonov exit(EXIT_SUCCESS); 3232499f175SDmitri Tikhonov case 'f': 3242499f175SDmitri Tikhonov fast = 1; 3252499f175SDmitri Tikhonov break; 3261999dccfSDmitri Tikhonov case 'v': 3271999dccfSDmitri Tikhonov ++s_verbose; 3281999dccfSDmitri Tikhonov break; 329387f7481SDmitri Tikhonov default: 330387f7481SDmitri Tikhonov exit(EXIT_FAILURE); 331387f7481SDmitri Tikhonov } 332387f7481SDmitri Tikhonov } 333387f7481SDmitri Tikhonov 334b43d0c9bSDmitri Tikhonov tsu_buf_sz = sizeof(tsu_buf); 3359dbae519SStephen Petrides if (0 != lsqpack_enc_init(&encoder, s_verbose ? stderr : NULL, dyn_table_size, 336b43d0c9bSDmitri Tikhonov dyn_table_size, max_risked_streams, enc_opts, tsu_buf, 337b43d0c9bSDmitri Tikhonov &tsu_buf_sz)) 338387f7481SDmitri Tikhonov { 339387f7481SDmitri Tikhonov perror("lsqpack_enc_init"); 340387f7481SDmitri Tikhonov exit(EXIT_FAILURE); 341387f7481SDmitri Tikhonov } 342387f7481SDmitri Tikhonov 343387f7481SDmitri Tikhonov lineno = 0; 344387f7481SDmitri Tikhonov stream_id = 0; 345387f7481SDmitri Tikhonov enc_off = 0; 346387f7481SDmitri Tikhonov hea_off = 0; 3474df4823bSDmitri Tikhonov header_opened = 0; 348387f7481SDmitri Tikhonov 349205a2804SDmitri Tikhonov while (line = fgets(line_buf, sizeof(line_buf), in), line != NULL) 350387f7481SDmitri Tikhonov { 351387f7481SDmitri Tikhonov ++lineno; 352387f7481SDmitri Tikhonov end = strchr(line, '\n'); 353387f7481SDmitri Tikhonov if (!end) 354387f7481SDmitri Tikhonov { 355387f7481SDmitri Tikhonov fprintf(stderr, "no newline on line %u\n", lineno); 356387f7481SDmitri Tikhonov exit(EXIT_FAILURE); 357387f7481SDmitri Tikhonov } 358387f7481SDmitri Tikhonov *end = '\0'; 359387f7481SDmitri Tikhonov 3604df4823bSDmitri Tikhonov if (end == line) 361387f7481SDmitri Tikhonov { 3624df4823bSDmitri Tikhonov if (header_opened) 363387f7481SDmitri Tikhonov { 364bcc44931SStephen Petrides size_t sz, pref_max = sizeof(pref_buf); 3659ed0fb1cSDmitri Tikhonov for (sz = (fast ? pref_max : 0); sz <= pref_max; sz++) 366bcc44931SStephen Petrides { 3673ce33568SDmitri Tikhonov pref_sz = lsqpack_enc_end_header(&encoder, pref_buf, sz, &hflags); 368bcc44931SStephen Petrides if (pref_sz > 0) 3693ce33568SDmitri Tikhonov { 3703ce33568SDmitri Tikhonov if (max_risked_streams == 0) 3713ce33568SDmitri Tikhonov assert(!(hflags & LSQECH_REF_AT_RISK)); 372bcc44931SStephen Petrides break; 3733ce33568SDmitri Tikhonov } 374bcc44931SStephen Petrides } 375a122a7bdSDmitri Tikhonov assert(pref_sz <= lsqpack_enc_header_block_prefix_size(&encoder)); 3764df4823bSDmitri Tikhonov if (pref_sz < 0) 3774df4823bSDmitri Tikhonov { 3784df4823bSDmitri Tikhonov fprintf(stderr, "end_header failed: %s", strerror(errno)); 3794df4823bSDmitri Tikhonov exit(EXIT_FAILURE); 3804df4823bSDmitri Tikhonov } 381e6970152SDmitri Tikhonov if (ack_mode == ACK_IMMEDIATE) 3820e41c471SDmitri Tikhonov { 383e6970152SDmitri Tikhonov if (!(2 == pref_sz && pref_buf[0] == 0 && pref_buf[1] == 0)) 384e6970152SDmitri Tikhonov r = ack_stream(&encoder, stream_id); 38548cefec0SDmitri Tikhonov else 38648cefec0SDmitri Tikhonov r = 0; 387f4a5c91dSDmitri Tikhonov if (r == 0 && encoder.qpe_ins_count > s_saved_ins_count) 388e6970152SDmitri Tikhonov r = ack_last_entry_id(&encoder); 389e6970152SDmitri Tikhonov else 390e6970152SDmitri Tikhonov r = 0; 391e6970152SDmitri Tikhonov if (r != 0) 392e6970152SDmitri Tikhonov { 393e6970152SDmitri Tikhonov fprintf(stderr, "acking stream %u failed: %s", stream_id, 394e6970152SDmitri Tikhonov strerror(errno)); 395e6970152SDmitri Tikhonov exit(EXIT_FAILURE); 396e6970152SDmitri Tikhonov } 3970e41c471SDmitri Tikhonov } 3981678c8a4SDmitri Tikhonov if (s_verbose) 3991678c8a4SDmitri Tikhonov fprintf(stderr, "compression ratio: %.3f\n", 4001678c8a4SDmitri Tikhonov lsqpack_enc_ratio(&encoder)); 4014df4823bSDmitri Tikhonov write_enc_and_header_streams(out, stream_id, enc_buf, enc_off, 4024df4823bSDmitri Tikhonov pref_buf, pref_sz, hea_buf, hea_off); 4034df4823bSDmitri Tikhonov enc_off = 0; 4044df4823bSDmitri Tikhonov hea_off = 0; 4054df4823bSDmitri Tikhonov header_opened = 0; 406387f7481SDmitri Tikhonov } 407387f7481SDmitri Tikhonov continue; 408387f7481SDmitri Tikhonov } 409387f7481SDmitri Tikhonov 410387f7481SDmitri Tikhonov if (*line == '#') 411a4e3cfd9SDmitri Tikhonov { 412fdc428d6SDmitri Tikhonov if (!process_annotations) 413fdc428d6SDmitri Tikhonov continue; 414fdc428d6SDmitri Tikhonov 415a4e3cfd9SDmitri Tikhonov /* Lines starting with ## are potential annotations */ 4160e41c471SDmitri Tikhonov if (ack_mode != ACK_IMMEDIATE 4170e41c471SDmitri Tikhonov /* Ignore ACK annotations in immediate ACK mode, as we do 4180e41c471SDmitri Tikhonov * not tolerate duplicate ACKs. 4190e41c471SDmitri Tikhonov */ 4200e41c471SDmitri Tikhonov && 1 == sscanf(line, "## %*[a] %u ", &arg)) 421a4e3cfd9SDmitri Tikhonov { 4220e41c471SDmitri Tikhonov if (0 != ack_stream(&encoder, arg)) 423a4e3cfd9SDmitri Tikhonov { 424a4e3cfd9SDmitri Tikhonov fprintf(stderr, "ACKing stream ID %u failed\n", arg); 425a4e3cfd9SDmitri Tikhonov exit(EXIT_FAILURE); 426a4e3cfd9SDmitri Tikhonov } 427a4e3cfd9SDmitri Tikhonov } 42891dfe80fSStephen Petrides else if (1 == sscanf(line, "## %*[s] %u", &arg)) 42991dfe80fSStephen Petrides sync_table(&encoder, arg); 43004dd4598SDmitri Tikhonov else if (1 == sscanf(line, "## %*[c] %u", &arg)) 43104dd4598SDmitri Tikhonov cancel_stream(&encoder, arg); 4328624e82bSDmitri Tikhonov else if (1 == sscanf(line, "## %*[t] %u", &arg)) 4338624e82bSDmitri Tikhonov { 4348624e82bSDmitri Tikhonov tsu_buf_sz = sizeof(tsu_buf); 4358624e82bSDmitri Tikhonov if (0 != lsqpack_enc_set_max_capacity(&encoder, arg, tsu_buf, 4368624e82bSDmitri Tikhonov &tsu_buf_sz)) 4378624e82bSDmitri Tikhonov { 4388624e82bSDmitri Tikhonov fprintf(stderr, "cannot set capacity to %u: %s\n", arg, 4398624e82bSDmitri Tikhonov strerror(errno)); 4408624e82bSDmitri Tikhonov exit(EXIT_FAILURE); 4418624e82bSDmitri Tikhonov } 4428624e82bSDmitri Tikhonov write_enc_stream(out, tsu_buf, tsu_buf_sz); 4438624e82bSDmitri Tikhonov } 444387f7481SDmitri Tikhonov continue; 445a4e3cfd9SDmitri Tikhonov } 446387f7481SDmitri Tikhonov 447387f7481SDmitri Tikhonov tab = strchr(line, '\t'); 448387f7481SDmitri Tikhonov if (!tab) 449387f7481SDmitri Tikhonov { 450387f7481SDmitri Tikhonov fprintf(stderr, "no TAB on line %u\n", lineno); 451387f7481SDmitri Tikhonov exit(EXIT_FAILURE); 452387f7481SDmitri Tikhonov } 453387f7481SDmitri Tikhonov 4544df4823bSDmitri Tikhonov if (!header_opened) 4554df4823bSDmitri Tikhonov { 4564df4823bSDmitri Tikhonov ++stream_id; 4574df4823bSDmitri Tikhonov if (0 != lsqpack_enc_start_header(&encoder, stream_id, 0)) 4584df4823bSDmitri Tikhonov { 4594df4823bSDmitri Tikhonov fprintf(stderr, "start_header failed: %s\n", strerror(errno)); 4604df4823bSDmitri Tikhonov exit(EXIT_FAILURE); 4614df4823bSDmitri Tikhonov } 4624df4823bSDmitri Tikhonov header_opened = 1; 4634df4823bSDmitri Tikhonov } 4642499f175SDmitri Tikhonov if (fast) 4652499f175SDmitri Tikhonov { 4662499f175SDmitri Tikhonov enc_sz = sizeof(enc_buf) - enc_off; 4672499f175SDmitri Tikhonov hea_sz = sizeof(hea_buf) - hea_off; 4682499f175SDmitri Tikhonov } 4692499f175SDmitri Tikhonov else 4702499f175SDmitri Tikhonov { 4712499f175SDmitri Tikhonov /* Increase buffers one by one to exercise error conditions */ 4722499f175SDmitri Tikhonov enc_sz = 0; 4732499f175SDmitri Tikhonov hea_sz = 0; 4742499f175SDmitri Tikhonov } 4759dbae519SStephen Petrides while (1) 4769dbae519SStephen Petrides { 4779e982dfdSDmitri Tikhonov lsxpack_header_set_offset2(&xhdr, line, 0, tab - line, 4789e982dfdSDmitri Tikhonov tab + 1 - line, end - tab - 1); 4799dbae519SStephen Petrides st = lsqpack_enc_encode(&encoder, enc_buf + enc_off, &enc_sz, 48060620859SDmitri Tikhonov hea_buf + hea_off, &hea_sz, &xhdr, 0); 4819dbae519SStephen Petrides switch (st) 4829dbae519SStephen Petrides { 4839dbae519SStephen Petrides case LQES_NOBUF_ENC: 4849dbae519SStephen Petrides if (enc_sz < sizeof(enc_buf) - enc_off) 4859dbae519SStephen Petrides ++enc_sz; 4869dbae519SStephen Petrides else 4879dbae519SStephen Petrides assert(0); 4889dbae519SStephen Petrides break; 4899dbae519SStephen Petrides case LQES_NOBUF_HEAD: 4909dbae519SStephen Petrides if (hea_sz < sizeof(hea_buf) - hea_off) 4919dbae519SStephen Petrides ++hea_sz; 4929dbae519SStephen Petrides else 4939dbae519SStephen Petrides assert(0); 4949dbae519SStephen Petrides break; 4959dbae519SStephen Petrides default: 4969dbae519SStephen Petrides assert(st == LQES_OK); 4979dbae519SStephen Petrides goto end_encode_one_header; 4989dbae519SStephen Petrides } 4999dbae519SStephen Petrides } 500387f7481SDmitri Tikhonov if (st != LQES_OK) 501387f7481SDmitri Tikhonov { 502387f7481SDmitri Tikhonov /* It could only run of of output space, so it's not really an 503387f7481SDmitri Tikhonov * error, but we make no provision in the interop encoder to 504387f7481SDmitri Tikhonov * grow the buffers. 505387f7481SDmitri Tikhonov */ 506387f7481SDmitri Tikhonov fprintf(stderr, "Could not encode header on line %u: %u\n", 507387f7481SDmitri Tikhonov lineno, st); 508387f7481SDmitri Tikhonov exit(EXIT_FAILURE); 509387f7481SDmitri Tikhonov } 5109dbae519SStephen Petrides end_encode_one_header: 511387f7481SDmitri Tikhonov enc_off += enc_sz; 512387f7481SDmitri Tikhonov hea_off += hea_sz; 513387f7481SDmitri Tikhonov } 514387f7481SDmitri Tikhonov 515205a2804SDmitri Tikhonov if (s_verbose) 516205a2804SDmitri Tikhonov fprintf(stderr, "exited while loop\n"); 517205a2804SDmitri Tikhonov 518387f7481SDmitri Tikhonov (void) fclose(in); 519387f7481SDmitri Tikhonov 5204df4823bSDmitri Tikhonov if (header_opened) 521387f7481SDmitri Tikhonov { 522205a2804SDmitri Tikhonov if (s_verbose) 523205a2804SDmitri Tikhonov fprintf(stderr, "close opened header\n"); 5243ce33568SDmitri Tikhonov pref_sz = lsqpack_enc_end_header(&encoder, pref_buf, sizeof(pref_buf), 5253ce33568SDmitri Tikhonov &hflags); 526387f7481SDmitri Tikhonov if (pref_sz < 0) 527387f7481SDmitri Tikhonov { 528387f7481SDmitri Tikhonov fprintf(stderr, "end_header failed: %s", strerror(errno)); 529387f7481SDmitri Tikhonov exit(EXIT_FAILURE); 530387f7481SDmitri Tikhonov } 5313ce33568SDmitri Tikhonov if (max_risked_streams == 0) 5323ce33568SDmitri Tikhonov assert(!(hflags & LSQECH_REF_AT_RISK)); 5330e41c471SDmitri Tikhonov if (ack_mode == ACK_IMMEDIATE 534dd11e024SDmitri Tikhonov && !(2 == pref_sz && pref_buf[0] == 0 && pref_buf[1] == 0) 5350e41c471SDmitri Tikhonov && 0 != ack_stream(&encoder, stream_id)) 5360e41c471SDmitri Tikhonov { 5370e41c471SDmitri Tikhonov fprintf(stderr, "acking stream %u failed: %s", stream_id, 5380e41c471SDmitri Tikhonov strerror(errno)); 5390e41c471SDmitri Tikhonov exit(EXIT_FAILURE); 5400e41c471SDmitri Tikhonov } 5411678c8a4SDmitri Tikhonov if (s_verbose) 5421678c8a4SDmitri Tikhonov fprintf(stderr, "compression ratio: %.3f\n", 5431678c8a4SDmitri Tikhonov lsqpack_enc_ratio(&encoder)); 544387f7481SDmitri Tikhonov write_enc_and_header_streams(out, stream_id, enc_buf, enc_off, pref_buf, 545387f7481SDmitri Tikhonov pref_sz, hea_buf, hea_off); 546387f7481SDmitri Tikhonov } 547387f7481SDmitri Tikhonov 548387f7481SDmitri Tikhonov lsqpack_enc_cleanup(&encoder); 549387f7481SDmitri Tikhonov 550205a2804SDmitri Tikhonov if (0 != fclose(out)) 551205a2804SDmitri Tikhonov { 552205a2804SDmitri Tikhonov perror("fclose(out)"); 553205a2804SDmitri Tikhonov exit(EXIT_FAILURE); 554205a2804SDmitri Tikhonov } 555205a2804SDmitri Tikhonov 556387f7481SDmitri Tikhonov exit(EXIT_SUCCESS); 557387f7481SDmitri Tikhonov} 558