# Copyright (c) 2017 - 2026 LiteSpeed Technologies Inc.  See LICENSE.
LSQUIC Examples
===============

LSQUIC comes with several examples of how the library is used.

The client and server programs described below are built on a common
framework and share many options.

Echo client and server
----------------------

Echo client and server (see bin/echo_{client,server}.c) are for simple
line-based request and reply communication.  Only one stream per connection
is supported for simplicity.  The client reads input from stdin.

MD5 client and server
---------------------

See bin/md5_{client,server}.c

MD5 server accepts connections, computes MD5 sum of streams' (one or more)
payload, and sends back the checksum.  MD5 client sends one or more file
contents to the server.  Both client and server support various options to
exercise different aspects of LSQUIC.

HTTP client and server
----------------------

See bin/http_{client,server}.c

This pair of programs is to demonstrate how to use HTTP features of QUIC.
HTTP server is interoperable with proto-quic's quic_client.

Duck client and server
----------------------

See bin/duck_{client,server}.c

This pair of programs implement the siduck-00 protocol.  They provide an
illustration of using the datagram API.

Internal-only helpers used by examples
--------------------------------------

Some example tools under bin/ call internal helper functions that are not
part of the public API in include/lsquic.h.  These calls exist only for
internal testing, diagnostics, or convenience in the example framework, which
is why the functions are not available in lsquic.h.

Usage Examples
--------------

Fetch Google's home page:

    ./bin/http_client -s www.google.com -p /

The default port number is 443, but it can be specified after colon
using the -s flag.  The value of the `host' header as well as the SNI
value defaults to the host part of the -s option.  -H option can be
used to override it.  For example:

    ./bin/http_client -H www.youtube.com -s www.google.com:443 -p / -M HEAD

The host part can be an IP address.  Both IPv4 and IPv6 are supported.
See ./bin/http_client -h for a (long) list of different flags.

POST a file to calculate its CRC32 checksum:

    ./bin/http_client -H www.litespeedtech.com -s 443 \
                        -p /cgi-bin/crc32.cgi -P file-256M -M POST

    HTTP/1.1 200 OK
    content-type: text/plain
    date: Fri, 09 Jun 2017 08:40:45 GMT
    server: LiteSpeed
    alt-svc: quic=":443"; v="35,37"

    CRC32: 2A0E7DBB

This is a good way to check that the payload gets to the other side
correctly.  The CGI script is:

    #!/usr/bin/perl
    use String::CRC32;
    printf "Content-type: text/plain\r\n\r\nCRC32: %X\n", crc32(*STDIN)

On the command line, I do

    alias crc32="perl -MString::CRC32 -e'printf qq(%X\n), crc32(<>)'"

To submit several requests concurrently, one can use -n and -r options:

    ./bin/http_client -H www.litespeedtech.com -s 443 \
                -p /cgi-bin/crc32.cgi -P file-256M -M POST -n 3 -r 10

This will open three parallel connections which will make ten POST
requests together.

To perform load testing, it is good to mix sending and receiving data:

    for i in {1..100}; do
        ./bin/http_client $COMMON_OPTS -p /cgi-bin/crc32.cgi -P file-256M \
                                                    -M POST >out-post.$i &
        ./bin/http_client $COMMON_OPTS -p /docs/file-256M >out-get.$i        &
        sleep 1
    done

If you don't want to create a hundred 256-megabyte out-get.* files, use -K
flag to discard output.

Testing Large Packet Sizes
---------------------------------

IETF QUIC supports all valid UDP packet sizes. This section outlines the
environment setup and testing parameters necessary to test this feature.

Compilation
    - Make sure to compile the library in DEBUG mode so that the NDEBUG
      define is off.
    - Build both the http_client and http_server test programs.

Running Instructions
    - Specify maximum packet size using -o base_plpmtu=$number.
      Valid sizes are up to 65535.
    - Use the -W flag for http_client and http_server for the ability
      to send packets of large size.
    - On the client side, use the -z flag to specify the maximum size
      of packet that the client will accept.

Example Usage
    ./bin/http_client -p /file-1M -H www.litespeedtech.com -s 192.168.0.85:5443
        -o version=FF000014
    ./bin/http_server -c www.litespeedtech.com,certschain,privkey
        -s 0.0.0.0:5443 -W -o base_plpmtu=65535

Additional Notes
    Since this feature does not have MTU discovery enabled at the time of
    writing, make sure to use client and server machines that share a path
    with the intended MTU.

Control QUIC Settings via -o Flag
---------------------------------

Most of the settings in struct lsquic_engine_settings can be controlled
via -o flag.  With exception of es_versions, which is a bit mask, other
es_* options can be mapped to corresponding -o value via s/^es_//:

    es_cfcw             =>  -o cwcf=12345
    es_max_streams_in   =>  -o max_streams_in=123

And so on.

For example, to test version negotiation:

    ./bin/http_server -c www.litespeedtech.com,certschain,privkey \
        -o version=Q035 -L debug 2>server.out &
    ./bin/http_client -H www.litespeedtech.com -p Makefile -L debug 2>client.out

Above, the client will start with the default, which is the highest supported
QUIC version, which the server should negotiate down.  You should see it from
the log files.

The code to set options via -o flag lives in set_engine_option().  It is good
to update this function at the same time as member fields are added to struct
lsquic_engine_settings.

Control LSQUIC Behavior via Environment Variables
-------------------------------------------------

LSQUIC_PACKET_OUT_LIMIT

    If set, the value of this environment variable is the maximum number
    of packets that can be sent out in one shot.  The limit is in the test
    program framework's ea_packets_out() callback.

    It is not applicable when sendmmsg(2) is used.

    Note 1: sendmmsg can be enabled using -g option, if available for your
            platform.

    Note 2: see -m option for a related packet-out limitation.

LSQUIC_LOSE_PACKETS_RE

    If set, this regular expression specifies the numbers of packets which
    the sender will lose on purpose.  For example:

        export LSQUIC_LOSE_PACKETS_RE='^(3|5|10)$'

    The act of losing a packet is performed by changing its payload to
    zero-filled buffer of the same size, which is almost as good as
    not sending anything.  The latter is difficult to implement without
    negatively affecting the regular code flow.

    Only available in debug builds.

LSQUIC_PACER_INTERTICK

    Number of microsecods to use as constant intertick time in lieu of the
    pacer's dynamic intertick time approximation.

    Only available in debug builds.

LSQUIC_CUBIC_SAMPLING_RATE

    Number of microseconds between times CWND is logged at info level.

    Only available in debug builds.

LSQUIC_RANDOM_SEND_FAILURE

    Frequency with which sending of packets fails: one out of this many
    times on average.

    Only available when compiled with -DLSQUIC_RANDOM_SEND_FAILURE=1

LSQUIC_LOG_SECRETS

    If set to true value, crypto secrets will be logged.  Applies to
    IETF QUIC only.

LSQUIC_COALESCE

    If set to false, packets are not coalesced.  Defaults to true.

LSQUIC_USE_POOLS

    If set to false, all memory pooling code is replaced with calls to
    malloc() and free().  This facilitates debugging memory issues.
    The default is true.

LSQUIC_ACK_ATTACK

    If set to true, generate optimistic ACKs.

Control Network-Related Stuff
-----------------------------

   -D          Set `do not fragment' flag on outgoing UDP packets.

   -z BYTES    Maximum size of outgoing UDP packets.  The default is 1370
               bytes for IPv4 socket and 1350 bytes for IPv6 socket.

   -S opt=val  Socket options.  Supported options:
                   sndbuf=12345    # Sets SO_SNDBUF
                   rcvbuf=12345    # Sets SO_RCVBUF

   -g          Use sendmmsg() to send packets.  This is only compiled in
               if available.

More Compilation Options
------------------------

-DLSQUIC_CONN_STATS=1

    Track some statistics about connections -- packets in, sent, delayed,
    stream payload per packet size ratio, and some others -- and print them
    at NOTICE level when connection is destroyed.

    Cumulative connections statistics are printed by the engine when it is
    destroyed if lsquic_engine_api.ea_stats_fh is set.  The HTTP client
    programs sets it when -t or -T command-line option is used.

-DLSQUIC_PACKINTS_SANITY_CHECK=1

    Turn on sanity checking for packet interval code.  The packet interval
    code, shared by both send and receive history modules, contained a bug
    which prompted me to add a checking function.

-DLSQUIC_SEND_STATS=0

    Turn off statistics collection performed by the send controller: number
    of packets sent, resent, and delayed.

-DLOG_PACKET_CHECKSUM=1

    When turned on, CRC32 checksum of each sent and received packet is
    logged as an event.

-DLSQUIC_LOWEST_LOG_LEVEL=LSQ_LOG_WARN

    If you want to go even faster: compile out some log levels entirely.

-DLSQUIC_EXTRA_CHECKS=1

    Add relatively expensive run-time sanity checks

-DLSQUIC_RANDOM_SEND_FAILURE=1

    Simulate failure to send packets to test send resumption logic.  When
    this flag is specified, sending of packets will randomly fail, about
    one out of every 10 attempts.  Set environment variable
    LSQUIC_RANDOM_SEND_FAILURE to change this frequency.

-DLSQUIC_ECN_BLACK_HOLE=1

    When compiled with this flag, setting environment variable
    LSQUIC_ECN_BLACK_HOLE to 1 will emulate ECN black hole: all received
    packets with ECN markings are dropped on the floor.

-DLSQUIC_ACK_ATTACK=1

    Enable ACK attack mode.  See LSQUIC_ACK_ATTACK environment variable
    entry above.
