1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 250aadb33SDmitri Tikhonov/* 350aadb33SDmitri Tikhonov * Write several things to HEADERS stream and check the results. What 450aadb33SDmitri Tikhonov * varies is the amount of bytes that are written to stream every time. 550aadb33SDmitri Tikhonov * This will exercise buffering in frame writer and verify that contents 650aadb33SDmitri Tikhonov * are written out correctly no matter where frab writing leaves off 750aadb33SDmitri Tikhonov * and picks up. 850aadb33SDmitri Tikhonov */ 950aadb33SDmitri Tikhonov 1050aadb33SDmitri Tikhonov#include <assert.h> 1150aadb33SDmitri Tikhonov#include <errno.h> 1250aadb33SDmitri Tikhonov#include <limits.h> 1350aadb33SDmitri Tikhonov#include <stdio.h> 1450aadb33SDmitri Tikhonov#include <stdlib.h> 1550aadb33SDmitri Tikhonov#include <string.h> 16461e84d8SAmol Deshpande#ifndef WIN32 1750aadb33SDmitri Tikhonov#include <unistd.h> 18461e84d8SAmol Deshpande#else 19461e84d8SAmol Deshpande#include <getopt.h> 20461e84d8SAmol Deshpande#endif 2150aadb33SDmitri Tikhonov#include <sys/queue.h> 2250aadb33SDmitri Tikhonov 2350aadb33SDmitri Tikhonov#include "lsquic.h" 24bea64822SDmitri Tikhonov#include "lshpack.h" 2550aadb33SDmitri Tikhonov#include "lsquic_logger.h" 2650aadb33SDmitri Tikhonov#include "lsquic_mm.h" 2750aadb33SDmitri Tikhonov#include "lsquic_frame_common.h" 2850aadb33SDmitri Tikhonov#include "lsquic_frame_writer.h" 2950aadb33SDmitri Tikhonov#include "lsquic_frame_reader.h" 3019f667fbSDmitri Tikhonov#if LSQUIC_CONN_STATS 3119f667fbSDmitri Tikhonov#include "lsquic_int_types.h" 32758aff32SDmitri Tikhonov#include "lsquic_hash.h" 3319f667fbSDmitri Tikhonov#include "lsquic_conn.h" 3419f667fbSDmitri Tikhonov#endif 3550aadb33SDmitri Tikhonov 3650aadb33SDmitri Tikhonov 3750aadb33SDmitri Tikhonovstruct lsquic_stream 3850aadb33SDmitri Tikhonov{ 3950aadb33SDmitri Tikhonov size_t sm_write_off, 4050aadb33SDmitri Tikhonov sm_buf_sz; /* Number of bytes allocated */ 4150aadb33SDmitri Tikhonov size_t sm_max_write; 4250aadb33SDmitri Tikhonov size_t sm_read_off; 4350aadb33SDmitri Tikhonov unsigned char *sm_buf; 4450aadb33SDmitri Tikhonov}; 4550aadb33SDmitri Tikhonov 4650aadb33SDmitri Tikhonov 4750aadb33SDmitri Tikhonovstatic struct lsquic_stream * 4850aadb33SDmitri Tikhonovstream_new (size_t max_write) 4950aadb33SDmitri Tikhonov{ 5050aadb33SDmitri Tikhonov struct lsquic_stream *stream = calloc(1, sizeof(*stream)); 5150aadb33SDmitri Tikhonov stream->sm_max_write = max_write; 5250aadb33SDmitri Tikhonov return stream; 5350aadb33SDmitri Tikhonov} 5450aadb33SDmitri Tikhonov 5550aadb33SDmitri Tikhonov 5650aadb33SDmitri Tikhonovstatic void 5750aadb33SDmitri Tikhonovstream_destroy (struct lsquic_stream *stream) 5850aadb33SDmitri Tikhonov{ 5950aadb33SDmitri Tikhonov free(stream->sm_buf); 6050aadb33SDmitri Tikhonov free(stream); 6150aadb33SDmitri Tikhonov} 6250aadb33SDmitri Tikhonov 6350aadb33SDmitri Tikhonov 6450aadb33SDmitri Tikhonov#define reset_output(max_) do { \ 6550aadb33SDmitri Tikhonov output.sz = 0; \ 6650aadb33SDmitri Tikhonov if (max_) \ 6750aadb33SDmitri Tikhonov output.max = max_; \ 6850aadb33SDmitri Tikhonov else \ 6950aadb33SDmitri Tikhonov output.max = sizeof(output.buf);\ 7050aadb33SDmitri Tikhonov} while (0) 7150aadb33SDmitri Tikhonov 7250aadb33SDmitri Tikhonov 7350aadb33SDmitri Tikhonovstatic ssize_t 745392f7a3SLiteSpeed Techstream_write (struct lsquic_stream *stream, struct lsquic_reader *reader) 7550aadb33SDmitri Tikhonov{ 765392f7a3SLiteSpeed Tech size_t sz; 775392f7a3SLiteSpeed Tech 785392f7a3SLiteSpeed Tech sz = reader->lsqr_size(reader->lsqr_ctx); 7950aadb33SDmitri Tikhonov if (sz > stream->sm_max_write) 8050aadb33SDmitri Tikhonov sz = stream->sm_max_write; 8150aadb33SDmitri Tikhonov if (stream->sm_write_off + sz > stream->sm_buf_sz) 8250aadb33SDmitri Tikhonov { 8350aadb33SDmitri Tikhonov if (stream->sm_write_off + sz < stream->sm_buf_sz * 2) 8450aadb33SDmitri Tikhonov stream->sm_buf_sz *= 2; 8550aadb33SDmitri Tikhonov else 8650aadb33SDmitri Tikhonov stream->sm_buf_sz = stream->sm_write_off + sz; 8750aadb33SDmitri Tikhonov stream->sm_buf = realloc(stream->sm_buf, stream->sm_buf_sz); 8850aadb33SDmitri Tikhonov } 8950aadb33SDmitri Tikhonov 905392f7a3SLiteSpeed Tech sz = reader->lsqr_read(reader->lsqr_ctx, 915392f7a3SLiteSpeed Tech stream->sm_buf + stream->sm_write_off, sz); 9250aadb33SDmitri Tikhonov stream->sm_write_off += sz; 9350aadb33SDmitri Tikhonov 9450aadb33SDmitri Tikhonov return sz; 9550aadb33SDmitri Tikhonov} 9650aadb33SDmitri Tikhonov 9750aadb33SDmitri Tikhonov 98fb3e20e0SDmitri Tikhonov#define XHDR(name_, value_) .buf = name_ value_, .name_offset = 0, .name_len = sizeof(name_) - 1, .val_offset = sizeof(name_) - 1, .val_len = sizeof(value_) - 1, 9950aadb33SDmitri Tikhonov 10050aadb33SDmitri Tikhonov 10150aadb33SDmitri Tikhonovstatic void 10250aadb33SDmitri Tikhonovtest_chop (unsigned max_write_sz) 10350aadb33SDmitri Tikhonov{ 10450aadb33SDmitri Tikhonov struct lsquic_frame_writer *fw; 10550aadb33SDmitri Tikhonov struct lsquic_stream *stream; 10650aadb33SDmitri Tikhonov struct lsquic_mm mm; 107bea64822SDmitri Tikhonov struct lshpack_enc henc; 10850aadb33SDmitri Tikhonov int s; 10950aadb33SDmitri Tikhonov 11019f667fbSDmitri Tikhonov#if LSQUIC_CONN_STATS 11119f667fbSDmitri Tikhonov struct conn_stats conn_stats; 11219f667fbSDmitri Tikhonov memset(&conn_stats, 0, sizeof(conn_stats)); 11319f667fbSDmitri Tikhonov#endif 11419f667fbSDmitri Tikhonov 11550aadb33SDmitri Tikhonov lsquic_mm_init(&mm); 116bea64822SDmitri Tikhonov lshpack_enc_init(&henc); 11750aadb33SDmitri Tikhonov stream = stream_new(max_write_sz); 11850aadb33SDmitri Tikhonov 11919f667fbSDmitri Tikhonov fw = lsquic_frame_writer_new(&mm, stream, 0, &henc, stream_write, 12019f667fbSDmitri Tikhonov#if LSQUIC_CONN_STATS 12119f667fbSDmitri Tikhonov &conn_stats, 12219f667fbSDmitri Tikhonov#endif 12319f667fbSDmitri Tikhonov 0); 12450aadb33SDmitri Tikhonov 12555613f44SDmitri Tikhonov struct lsxpack_header header_arr[] = 12650aadb33SDmitri Tikhonov { 12755613f44SDmitri Tikhonov { XHDR(":status", "302") }, 12850aadb33SDmitri Tikhonov }; 12950aadb33SDmitri Tikhonov 13050aadb33SDmitri Tikhonov struct lsquic_http_headers headers = { 13150aadb33SDmitri Tikhonov .count = 1, 13250aadb33SDmitri Tikhonov .headers = header_arr, 13350aadb33SDmitri Tikhonov }; 13450aadb33SDmitri Tikhonov 13550aadb33SDmitri Tikhonov s = lsquic_frame_writer_write_headers(fw, 12345, &headers, 0, 100); 13650aadb33SDmitri Tikhonov assert(0 == s); 13750aadb33SDmitri Tikhonov 13850aadb33SDmitri Tikhonov struct lsquic_http2_setting settings[] = { { 1, 2, }, { 3, 4, } }; 13950aadb33SDmitri Tikhonov s = lsquic_frame_writer_write_settings(fw, settings, 2); 14050aadb33SDmitri Tikhonov assert(0 == s); 14150aadb33SDmitri Tikhonov 14250aadb33SDmitri Tikhonov /* TODO: server must not send priority frames, add a check for that 14350aadb33SDmitri Tikhonov * error condition. 14450aadb33SDmitri Tikhonov */ 14550aadb33SDmitri Tikhonov s = lsquic_frame_writer_write_priority(fw, 3, 0, 1, 256); 14650aadb33SDmitri Tikhonov assert(0 == s); 14750aadb33SDmitri Tikhonov 14850aadb33SDmitri Tikhonov while (lsquic_frame_writer_have_leftovers(fw)) 14950aadb33SDmitri Tikhonov { 15050aadb33SDmitri Tikhonov s = lsquic_frame_writer_flush(fw); 15150aadb33SDmitri Tikhonov assert(0 == s); 15250aadb33SDmitri Tikhonov } 15350aadb33SDmitri Tikhonov 15450aadb33SDmitri Tikhonov const unsigned char expected_buf[] = { 15550aadb33SDmitri Tikhonov /* Length: */ 0x00, 0x00, 0x09, 15650aadb33SDmitri Tikhonov /* Type: */ HTTP_FRAME_HEADERS, 15750aadb33SDmitri Tikhonov /* Flags: */ HFHF_END_HEADERS|HFHF_PRIORITY, 15850aadb33SDmitri Tikhonov /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 15950aadb33SDmitri Tikhonov /* Dep stream id: */0x00, 0x00, 0x00, 0x00, 16050aadb33SDmitri Tikhonov /* Weight: */ 100 - 1, 16150aadb33SDmitri Tikhonov /* Block fragment: */ 16250aadb33SDmitri Tikhonov 0x48, 0x82, 0x64, 0x02, 16350aadb33SDmitri Tikhonov /* Length: */ 0x00, 0x00, 0x0C, 16450aadb33SDmitri Tikhonov /* Type: */ HTTP_FRAME_SETTINGS, 16550aadb33SDmitri Tikhonov /* Flags: */ 0x00, 16650aadb33SDmitri Tikhonov /* Stream Id: */ 0x00, 0x00, 0x00, 0x00, 16750aadb33SDmitri Tikhonov /* Payload: */ 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 16850aadb33SDmitri Tikhonov 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 16950aadb33SDmitri Tikhonov /* Length: */ 0x00, 0x00, 5, 17050aadb33SDmitri Tikhonov /* Type: */ HTTP_FRAME_PRIORITY, 17150aadb33SDmitri Tikhonov /* Flags: */ 0x00, 17250aadb33SDmitri Tikhonov /* Stream Id: */ 0x00, 0x00, 0x00, 0x03, 17350aadb33SDmitri Tikhonov /* Dep stream Id: */0x00, 0x00, 0x00, 0x01, 17450aadb33SDmitri Tikhonov /* Weight: */ 0xFF, 17550aadb33SDmitri Tikhonov }; 17650aadb33SDmitri Tikhonov 17750aadb33SDmitri Tikhonov assert(stream->sm_write_off == sizeof(expected_buf)); 17850aadb33SDmitri Tikhonov assert(0 == memcmp(stream->sm_buf, expected_buf, sizeof(expected_buf))); 17950aadb33SDmitri Tikhonov 18050aadb33SDmitri Tikhonov lsquic_frame_writer_destroy(fw); 18150aadb33SDmitri Tikhonov stream_destroy(stream); 182bea64822SDmitri Tikhonov lshpack_enc_cleanup(&henc); 18350aadb33SDmitri Tikhonov lsquic_mm_cleanup(&mm); 18450aadb33SDmitri Tikhonov} 18550aadb33SDmitri Tikhonov 18650aadb33SDmitri Tikhonov 18750aadb33SDmitri Tikhonovint 18850aadb33SDmitri Tikhonovmain (int argc, char **argv) 18950aadb33SDmitri Tikhonov{ 19050aadb33SDmitri Tikhonov const unsigned write_sizes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 20, 19150aadb33SDmitri Tikhonov 30, 100, 200, 255, 0xFFF, 0x1000, 0x100D, 19250aadb33SDmitri Tikhonov UINT_MAX, }; 19350aadb33SDmitri Tikhonov unsigned i; 19450aadb33SDmitri Tikhonov int opt, max_write_sz = -1; 19550aadb33SDmitri Tikhonov 19650aadb33SDmitri Tikhonov while (-1 != (opt = getopt(argc, argv, "l:s:"))) 19750aadb33SDmitri Tikhonov { 19850aadb33SDmitri Tikhonov switch (opt) 19950aadb33SDmitri Tikhonov { 20050aadb33SDmitri Tikhonov case 'l': 20150aadb33SDmitri Tikhonov lsquic_log_to_fstream(stderr, LLTS_NONE); 20250aadb33SDmitri Tikhonov lsquic_logger_lopt(optarg); 20350aadb33SDmitri Tikhonov break; 20450aadb33SDmitri Tikhonov case 's': 20550aadb33SDmitri Tikhonov max_write_sz = atoi(optarg); 20650aadb33SDmitri Tikhonov break; 20750aadb33SDmitri Tikhonov default: 20850aadb33SDmitri Tikhonov exit(1); 20950aadb33SDmitri Tikhonov } 21050aadb33SDmitri Tikhonov } 21150aadb33SDmitri Tikhonov 21250aadb33SDmitri Tikhonov if (-1 == max_write_sz) 21350aadb33SDmitri Tikhonov for (i = 0; i < sizeof(write_sizes) / sizeof(write_sizes[0]); ++i) 21450aadb33SDmitri Tikhonov test_chop(write_sizes[i]); 21550aadb33SDmitri Tikhonov else 21650aadb33SDmitri Tikhonov test_chop(max_write_sz); 21750aadb33SDmitri Tikhonov 21850aadb33SDmitri Tikhonov return 0; 21950aadb33SDmitri Tikhonov} 220