1e1657cf2SDmitri Tikhonov/* 2e1657cf2SDmitri Tikhonov * Read QIF and encode it using HPACK. Use for benchmarking. 3e1657cf2SDmitri Tikhonov * 4e1657cf2SDmitri Tikhonov * Based on ls-qpack's interop-encode. 5e1657cf2SDmitri Tikhonov * 6e1657cf2SDmitri Tikhonov * How it works: read in QIF into a list of header set objects and encode 7e1657cf2SDmitri Tikhonov * the list a number of times. 8e1657cf2SDmitri Tikhonov * 9e1657cf2SDmitri Tikhonov * QIF Format: 10e1657cf2SDmitri Tikhonov * https://github.com/quicwg/base-drafts/wiki/QPACK-Offline-Interop 11e1657cf2SDmitri Tikhonov */ 12e1657cf2SDmitri Tikhonov 13e1657cf2SDmitri Tikhonov#define _GNU_SOURCE /* for memmem */ 14e1657cf2SDmitri Tikhonov#include <assert.h> 15e1657cf2SDmitri Tikhonov 16e1657cf2SDmitri Tikhonov#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) 17e1657cf2SDmitri Tikhonov#include <sys/endian.h> 18e1657cf2SDmitri Tikhonov#define bswap_16 bswap16 19e1657cf2SDmitri Tikhonov#define bswap_32 bswap32 20e1657cf2SDmitri Tikhonov#define bswap_64 bswap64 21e1657cf2SDmitri Tikhonov#elif defined(__APPLE__) 22e1657cf2SDmitri Tikhonov#include <libkern/OSByteOrder.h> 23e1657cf2SDmitri Tikhonov#define bswap_16 OSSwapInt16 24e1657cf2SDmitri Tikhonov#define bswap_32 OSSwapInt32 25e1657cf2SDmitri Tikhonov#define bswap_64 OSSwapInt64 26e1657cf2SDmitri Tikhonov#elif defined(WIN32) 27e1657cf2SDmitri Tikhonov#error Not supported on Windows 28e1657cf2SDmitri Tikhonov#else 29e1657cf2SDmitri Tikhonov#include <byteswap.h> 30e1657cf2SDmitri Tikhonov#endif 31e1657cf2SDmitri Tikhonov 32e1657cf2SDmitri Tikhonov#include <errno.h> 33e1657cf2SDmitri Tikhonov#include <stdio.h> 34e1657cf2SDmitri Tikhonov#include <stdlib.h> 35e1657cf2SDmitri Tikhonov#include <string.h> 36e1657cf2SDmitri Tikhonov#include <unistd.h> 37e1657cf2SDmitri Tikhonov#include <sys/types.h> 38e1657cf2SDmitri Tikhonov#include <sys/stat.h> 39e1657cf2SDmitri Tikhonov#include <fcntl.h> 40e1657cf2SDmitri Tikhonov#include <inttypes.h> 41e1657cf2SDmitri Tikhonov#include <sys/mman.h> 42e1657cf2SDmitri Tikhonov 43e1657cf2SDmitri Tikhonov#include "lshpack.h" 44e1657cf2SDmitri Tikhonov 45e1657cf2SDmitri Tikhonovstatic int s_verbose; 46e1657cf2SDmitri Tikhonov 47e1657cf2SDmitri Tikhonov#define TABLE_SIZE 4096 48e1657cf2SDmitri Tikhonov 49e1657cf2SDmitri Tikhonovstatic void 50e1657cf2SDmitri Tikhonovusage (const char *name) 51e1657cf2SDmitri Tikhonov{ 52e1657cf2SDmitri Tikhonov fprintf(stderr, 53e1657cf2SDmitri Tikhonov"Usage: %s [options] [-i input] [-o output]\n" 54e1657cf2SDmitri Tikhonov"\n" 55e1657cf2SDmitri Tikhonov"Options:\n" 56e1657cf2SDmitri Tikhonov" -i FILE Input file.\n" 57e1657cf2SDmitri Tikhonov" -o FILE Output file. If not spepcified or set to `-', the output\n" 58e1657cf2SDmitri Tikhonov" is written to stdout.\n" 59e1657cf2SDmitri Tikhonov" -K Discard output: encoded output is discarded.\n" 6072061d40SDmitri Tikhonov" -H Do not use the history heuristic.\n" 61e1657cf2SDmitri Tikhonov" -n NUMBER Number of times to iterate over the header set list.\n" 62e1657cf2SDmitri Tikhonov" -t NUMBER Dynamic table size. Defaults to %u.\n" 63e1657cf2SDmitri Tikhonov" -v Verbose: print various messages to stderr.\n" 64e1657cf2SDmitri Tikhonov"\n" 65e1657cf2SDmitri Tikhonov" -h Print this help screen and exit\n" 66e1657cf2SDmitri Tikhonov , name, TABLE_SIZE); 67e1657cf2SDmitri Tikhonov} 68e1657cf2SDmitri Tikhonov 69e1657cf2SDmitri Tikhonov 70e1657cf2SDmitri Tikhonovstruct header 71e1657cf2SDmitri Tikhonov{ 72e1657cf2SDmitri Tikhonov const char *name; 73e1657cf2SDmitri Tikhonov const char *val; 74e1657cf2SDmitri Tikhonov size_t name_len; 75e1657cf2SDmitri Tikhonov size_t val_len; 76e1657cf2SDmitri Tikhonov}; 77e1657cf2SDmitri Tikhonov 78e1657cf2SDmitri Tikhonov 79e1657cf2SDmitri Tikhonov#define MAX_HEADERS 32 80e1657cf2SDmitri Tikhonov 81e1657cf2SDmitri Tikhonovstruct header_set 82e1657cf2SDmitri Tikhonov{ 83e1657cf2SDmitri Tikhonov STAILQ_ENTRY(header_set) next; 84e1657cf2SDmitri Tikhonov unsigned n_headers; 85e1657cf2SDmitri Tikhonov struct header headers[MAX_HEADERS]; 86e1657cf2SDmitri Tikhonov}; 87e1657cf2SDmitri Tikhonov 88e1657cf2SDmitri Tikhonov 89600751b9SDmitri Tikhonovstatic inline void 90600751b9SDmitri Tikhonovlsxpack_header_set_ptr(lsxpack_header_t *hdr, 91600751b9SDmitri Tikhonov const char *name, size_t name_len, 92600751b9SDmitri Tikhonov const char *val, size_t val_len) 93600751b9SDmitri Tikhonov{ 94600751b9SDmitri Tikhonov static char buf[65536]; 95600751b9SDmitri Tikhonov memcpy(buf, name, name_len); 96600751b9SDmitri Tikhonov memcpy(&buf[name_len], val, val_len); 97600751b9SDmitri Tikhonov lsxpack_header_set_offset2(hdr, buf, 0, name_len, name_len, val_len); 98600751b9SDmitri Tikhonov} 99600751b9SDmitri Tikhonov 100600751b9SDmitri Tikhonov 101e1657cf2SDmitri Tikhonovint 102e1657cf2SDmitri Tikhonovmain (int argc, char **argv) 103e1657cf2SDmitri Tikhonov{ 104e1657cf2SDmitri Tikhonov FILE *out = stdout; 1052a690864SDmitri Tikhonov int opt, qif_fd = -1; 10672061d40SDmitri Tikhonov int discard = 0, use_history = 1; 107e1657cf2SDmitri Tikhonov unsigned n_iters = 1, n, i; 108e1657cf2SDmitri Tikhonov unsigned dyn_table_size = TABLE_SIZE; 109e1657cf2SDmitri Tikhonov STAILQ_HEAD(, header_set) header_sets = STAILQ_HEAD_INITIALIZER(header_sets); 110e1657cf2SDmitri Tikhonov struct stat st; 111e1657cf2SDmitri Tikhonov const unsigned char *qif = NULL, *p, *tab, *nl, *nlnl; 112e1657cf2SDmitri Tikhonov unsigned char *s; 113e1657cf2SDmitri Tikhonov struct header *header; 114e1657cf2SDmitri Tikhonov struct header_set *hset; 115e1657cf2SDmitri Tikhonov struct lshpack_enc encoder; 116e1657cf2SDmitri Tikhonov unsigned char buf[0x2000]; 117e1657cf2SDmitri Tikhonov 11872061d40SDmitri Tikhonov while (-1 != (opt = getopt(argc, argv, "Hi:o:Kn:t:vh"))) 119e1657cf2SDmitri Tikhonov { 120e1657cf2SDmitri Tikhonov switch (opt) 121e1657cf2SDmitri Tikhonov { 122e1657cf2SDmitri Tikhonov case 'n': 123e1657cf2SDmitri Tikhonov n_iters = atoi(optarg); 124e1657cf2SDmitri Tikhonov break; 125e1657cf2SDmitri Tikhonov case 'i': 126e1657cf2SDmitri Tikhonov qif_fd = open(optarg, O_RDONLY); 127e1657cf2SDmitri Tikhonov if (qif_fd < 0) 128e1657cf2SDmitri Tikhonov { 129e1657cf2SDmitri Tikhonov perror("open"); 130e1657cf2SDmitri Tikhonov exit(EXIT_FAILURE); 131e1657cf2SDmitri Tikhonov } 132e1657cf2SDmitri Tikhonov if (0 != fstat(qif_fd, &st)) 133e1657cf2SDmitri Tikhonov { 134e1657cf2SDmitri Tikhonov perror("fstat"); 135e1657cf2SDmitri Tikhonov exit(EXIT_FAILURE); 136e1657cf2SDmitri Tikhonov } 137e1657cf2SDmitri Tikhonov qif = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, qif_fd, 0); 138e1657cf2SDmitri Tikhonov if (!qif) 139e1657cf2SDmitri Tikhonov { 140e1657cf2SDmitri Tikhonov perror("mmap"); 141e1657cf2SDmitri Tikhonov exit(EXIT_FAILURE); 142e1657cf2SDmitri Tikhonov } 143e1657cf2SDmitri Tikhonov break; 144e1657cf2SDmitri Tikhonov case 'o': 145e1657cf2SDmitri Tikhonov if (0 != strcmp(optarg, "-")) 146e1657cf2SDmitri Tikhonov { 147e1657cf2SDmitri Tikhonov out = fopen(optarg, "wb"); 148e1657cf2SDmitri Tikhonov if (!out) 149e1657cf2SDmitri Tikhonov { 150e1657cf2SDmitri Tikhonov fprintf(stderr, "cannot open `%s' for writing: %s\n", 151e1657cf2SDmitri Tikhonov optarg, strerror(errno)); 152e1657cf2SDmitri Tikhonov exit(EXIT_FAILURE); 153e1657cf2SDmitri Tikhonov } 154e1657cf2SDmitri Tikhonov } 155e1657cf2SDmitri Tikhonov break; 156e1657cf2SDmitri Tikhonov case 'K': 157e1657cf2SDmitri Tikhonov discard = 1; 158e1657cf2SDmitri Tikhonov break; 15972061d40SDmitri Tikhonov case 'H': 16072061d40SDmitri Tikhonov use_history = 0; 16172061d40SDmitri Tikhonov break; 162e1657cf2SDmitri Tikhonov case 't': 163e1657cf2SDmitri Tikhonov dyn_table_size = atoi(optarg); 164e1657cf2SDmitri Tikhonov break; 165e1657cf2SDmitri Tikhonov case 'h': 166e1657cf2SDmitri Tikhonov usage(argv[0]); 167e1657cf2SDmitri Tikhonov exit(EXIT_SUCCESS); 168e1657cf2SDmitri Tikhonov case 'v': 169e1657cf2SDmitri Tikhonov ++s_verbose; 170e1657cf2SDmitri Tikhonov break; 171e1657cf2SDmitri Tikhonov default: 172e1657cf2SDmitri Tikhonov exit(EXIT_FAILURE); 173e1657cf2SDmitri Tikhonov } 174e1657cf2SDmitri Tikhonov } 175e1657cf2SDmitri Tikhonov 176e1657cf2SDmitri Tikhonov if (!qif) 177e1657cf2SDmitri Tikhonov { 178e1657cf2SDmitri Tikhonov fprintf(stderr, "Please specify input QIF file using -i flag\n"); 179e1657cf2SDmitri Tikhonov exit(EXIT_FAILURE); 180e1657cf2SDmitri Tikhonov } 181e1657cf2SDmitri Tikhonov 182e1657cf2SDmitri Tikhonov const unsigned char *const begin = qif; 183e1657cf2SDmitri Tikhonov const unsigned char *const end = begin + st.st_size; 184e1657cf2SDmitri Tikhonov while (qif + 2 < end) 185e1657cf2SDmitri Tikhonov { 186e1657cf2SDmitri Tikhonov nlnl = memmem(qif, end - qif, "\n\n", 2); 187e1657cf2SDmitri Tikhonov if (!nlnl) 188e1657cf2SDmitri Tikhonov nlnl = end; 189e1657cf2SDmitri Tikhonov hset = calloc(1, sizeof(*hset)); 190e1657cf2SDmitri Tikhonov if (!hset) 191e1657cf2SDmitri Tikhonov { 192e1657cf2SDmitri Tikhonov perror("malloc"); 193e1657cf2SDmitri Tikhonov exit(EXIT_FAILURE); 194e1657cf2SDmitri Tikhonov } 195e1657cf2SDmitri Tikhonov STAILQ_INSERT_TAIL(&header_sets, hset, next); 196e1657cf2SDmitri Tikhonov p = qif; 197e1657cf2SDmitri Tikhonov while (p < nlnl) 198e1657cf2SDmitri Tikhonov { 199e1657cf2SDmitri Tikhonov if (hset->n_headers >= MAX_HEADERS) 200e1657cf2SDmitri Tikhonov { 201e1657cf2SDmitri Tikhonov fprintf(stderr, "max headers > 32, off: %u", 202e1657cf2SDmitri Tikhonov (unsigned) (p - begin)); 203e1657cf2SDmitri Tikhonov exit(EXIT_FAILURE); 204e1657cf2SDmitri Tikhonov } 205e1657cf2SDmitri Tikhonov tab = memmem(p, nlnl - p, "\t", 1); 206e1657cf2SDmitri Tikhonov if (!tab) 207e1657cf2SDmitri Tikhonov { 208e1657cf2SDmitri Tikhonov fprintf(stderr, "tab not found, off: %u", 209e1657cf2SDmitri Tikhonov (unsigned) (p - begin)); 210e1657cf2SDmitri Tikhonov exit(EXIT_FAILURE); 211e1657cf2SDmitri Tikhonov } 212e1657cf2SDmitri Tikhonov nl = memmem(tab + 1, nlnl - tab - 1, "\n", 1); 213e1657cf2SDmitri Tikhonov if (!nl) 214e1657cf2SDmitri Tikhonov nl = nlnl; 215e1657cf2SDmitri Tikhonov hset->headers[ hset->n_headers ] = (struct header) { 216e1657cf2SDmitri Tikhonov .name = (const char *) p, 217e1657cf2SDmitri Tikhonov .val = (const char *) tab + 1, 218e1657cf2SDmitri Tikhonov .name_len = tab - p, 219e1657cf2SDmitri Tikhonov .val_len = nl - tab - 1, 220e1657cf2SDmitri Tikhonov }; 221e1657cf2SDmitri Tikhonov ++hset->n_headers; 222e1657cf2SDmitri Tikhonov p = nl + 1; 223e1657cf2SDmitri Tikhonov } 224e1657cf2SDmitri Tikhonov qif = nlnl + 2; 225e1657cf2SDmitri Tikhonov } 226e1657cf2SDmitri Tikhonov 227226eedebSDmitri Tikhonov lsxpack_header_t hdr; 228e1657cf2SDmitri Tikhonov for (n = 0; n < n_iters; ++n) 229e1657cf2SDmitri Tikhonov { 230e1657cf2SDmitri Tikhonov if (0 != lshpack_enc_init(&encoder)) 231e1657cf2SDmitri Tikhonov { 232e1657cf2SDmitri Tikhonov perror("lshpack_enc_init"); 233e1657cf2SDmitri Tikhonov exit(EXIT_FAILURE); 234e1657cf2SDmitri Tikhonov } 23572061d40SDmitri Tikhonov (void) lshpack_enc_use_hist(&encoder, use_history); 236e1657cf2SDmitri Tikhonov 237e1657cf2SDmitri Tikhonov STAILQ_FOREACH(hset, &header_sets, next) 238e1657cf2SDmitri Tikhonov { 239e1657cf2SDmitri Tikhonov for (i = 0; i < hset->n_headers; ++i) 240e1657cf2SDmitri Tikhonov { 241e1657cf2SDmitri Tikhonov header = &hset->headers[i]; 242226eedebSDmitri Tikhonov lsxpack_header_set_ptr(&hdr, header->name, header->name_len, 243226eedebSDmitri Tikhonov header->val, header->val_len); 244226eedebSDmitri Tikhonov s = lshpack_enc_encode(&encoder, buf, buf + sizeof(buf), &hdr); 245e1657cf2SDmitri Tikhonov if (s <= buf) 246e1657cf2SDmitri Tikhonov { 247e1657cf2SDmitri Tikhonov fprintf(stderr, "cannot encode\n"); 248e1657cf2SDmitri Tikhonov exit(EXIT_FAILURE); 249e1657cf2SDmitri Tikhonov } 250e1657cf2SDmitri Tikhonov if (!discard) 251e1657cf2SDmitri Tikhonov (void) fwrite(buf, 1, s - buf, out); 252e1657cf2SDmitri Tikhonov } 253e1657cf2SDmitri Tikhonov } 254e1657cf2SDmitri Tikhonov 255e1657cf2SDmitri Tikhonov lshpack_enc_set_max_capacity(&encoder, dyn_table_size); 256e1657cf2SDmitri Tikhonov lshpack_enc_cleanup(&encoder); 257e1657cf2SDmitri Tikhonov } 258e1657cf2SDmitri Tikhonov 259e1657cf2SDmitri Tikhonov munmap((void *) begin, st.st_size); 2602a690864SDmitri Tikhonov if (qif_fd >= 0) 2612a690864SDmitri Tikhonov close(qif_fd); 262e1657cf2SDmitri Tikhonov exit(EXIT_SUCCESS); 263e1657cf2SDmitri Tikhonov} 264