duck_server.c revision a74702c6
1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
2b1a7c3f9SDmitri Tikhonov/*
3b1a7c3f9SDmitri Tikhonov * A duck quacks!  The server for the siduck protocol:
4b1a7c3f9SDmitri Tikhonov *      https://tools.ietf.org/html/draft-pardue-quic-siduck-00
5b1a7c3f9SDmitri Tikhonov */
6b1a7c3f9SDmitri Tikhonov
7b1a7c3f9SDmitri Tikhonov#include <assert.h>
8b1a7c3f9SDmitri Tikhonov#include <signal.h>
9b1a7c3f9SDmitri Tikhonov#include <stdio.h>
10b1a7c3f9SDmitri Tikhonov#include <stdlib.h>
11b1a7c3f9SDmitri Tikhonov#include <string.h>
12b1a7c3f9SDmitri Tikhonov#include <sys/queue.h>
13b1a7c3f9SDmitri Tikhonov#include <time.h>
14b1a7c3f9SDmitri Tikhonov#ifndef WIN32
15b1a7c3f9SDmitri Tikhonov#include <unistd.h>
16b1a7c3f9SDmitri Tikhonov#include <netinet/in.h>
17b1a7c3f9SDmitri Tikhonov#else
18b1a7c3f9SDmitri Tikhonov#include "vc_compat.h"
19b1a7c3f9SDmitri Tikhonov#include "getopt.h"
20b1a7c3f9SDmitri Tikhonov#endif
21b1a7c3f9SDmitri Tikhonov
22b1a7c3f9SDmitri Tikhonov#include "lsquic.h"
23b1a7c3f9SDmitri Tikhonov#include "../src/liblsquic/lsquic_hash.h"
24b1a7c3f9SDmitri Tikhonov#include "test_common.h"
25b1a7c3f9SDmitri Tikhonov#include "test_cert.h"
26b1a7c3f9SDmitri Tikhonov#include "prog.h"
27b1a7c3f9SDmitri Tikhonov
28b1a7c3f9SDmitri Tikhonov#include "../src/liblsquic/lsquic_logger.h"
29b1a7c3f9SDmitri Tikhonov
30b1a7c3f9SDmitri Tikhonov
31b1a7c3f9SDmitri Tikhonovstatic lsquic_conn_ctx_t *
32b1a7c3f9SDmitri Tikhonovduck_server_on_new_conn (void *stream_if_ctx, lsquic_conn_t *conn)
33b1a7c3f9SDmitri Tikhonov{
34b1a7c3f9SDmitri Tikhonov    LSQ_NOTICE("New siduck connection established!");
35b1a7c3f9SDmitri Tikhonov    return NULL;
36b1a7c3f9SDmitri Tikhonov}
37b1a7c3f9SDmitri Tikhonov
38b1a7c3f9SDmitri Tikhonov
39b1a7c3f9SDmitri Tikhonovstatic void
40b1a7c3f9SDmitri Tikhonovduck_server_on_conn_closed (lsquic_conn_t *conn)
41b1a7c3f9SDmitri Tikhonov{
42b1a7c3f9SDmitri Tikhonov    LSQ_NOTICE("siduck connection closed");
43b1a7c3f9SDmitri Tikhonov}
44b1a7c3f9SDmitri Tikhonov
45b1a7c3f9SDmitri Tikhonov
46b1a7c3f9SDmitri Tikhonov/* Expected request and response of the siduck protocol */
47b1a7c3f9SDmitri Tikhonov#define REQUEST "quack"
48b1a7c3f9SDmitri Tikhonov#define RESPONSE "quack-ack"
49b1a7c3f9SDmitri Tikhonov
50b1a7c3f9SDmitri Tikhonov
51b1a7c3f9SDmitri Tikhonovstatic ssize_t
52b1a7c3f9SDmitri Tikhonovduck_on_dg_write (lsquic_conn_t *conn, void *buf, size_t sz)
53b1a7c3f9SDmitri Tikhonov{
54b1a7c3f9SDmitri Tikhonov    int s;
55b1a7c3f9SDmitri Tikhonov
56b1a7c3f9SDmitri Tikhonov    /* We only write one response */
57b1a7c3f9SDmitri Tikhonov    s = lsquic_conn_want_datagram_write(conn, 0);
58b1a7c3f9SDmitri Tikhonov    assert(s == 1);     /* Old value was "yes" */
59b1a7c3f9SDmitri Tikhonov
60b1a7c3f9SDmitri Tikhonov    if (sz >= sizeof(RESPONSE) - 1)
61b1a7c3f9SDmitri Tikhonov    {
62b1a7c3f9SDmitri Tikhonov        LSQ_INFO("wrote `%s' in response", RESPONSE);
63b1a7c3f9SDmitri Tikhonov        memcpy(buf, RESPONSE, sizeof(RESPONSE) - 1);
64b1a7c3f9SDmitri Tikhonov        lsquic_conn_close(conn);    /* Close connection right away */
65b1a7c3f9SDmitri Tikhonov        return sizeof(RESPONSE) - 1;
66b1a7c3f9SDmitri Tikhonov    }
67b1a7c3f9SDmitri Tikhonov    else
68b1a7c3f9SDmitri Tikhonov        return -1;
69b1a7c3f9SDmitri Tikhonov}
70b1a7c3f9SDmitri Tikhonov
71b1a7c3f9SDmitri Tikhonov
72b1a7c3f9SDmitri Tikhonovstatic void
73b1a7c3f9SDmitri Tikhonovduck_on_datagram (lsquic_conn_t *conn, const void *buf, size_t bufsz)
74b1a7c3f9SDmitri Tikhonov{
75b1a7c3f9SDmitri Tikhonov    int s;
76b1a7c3f9SDmitri Tikhonov
77b1a7c3f9SDmitri Tikhonov    if (bufsz == sizeof(REQUEST) - 1
78b1a7c3f9SDmitri Tikhonov            && 0 == memcmp(buf, REQUEST, sizeof(REQUEST) - 1))
79b1a7c3f9SDmitri Tikhonov    {
80b1a7c3f9SDmitri Tikhonov        LSQ_DEBUG("received the expected `%s' request", REQUEST);
81b1a7c3f9SDmitri Tikhonov        s = lsquic_conn_want_datagram_write(conn, 1);
82b1a7c3f9SDmitri Tikhonov        assert(s == 0);
83b1a7c3f9SDmitri Tikhonov    }
84b1a7c3f9SDmitri Tikhonov    else
85b1a7c3f9SDmitri Tikhonov    {
86b1a7c3f9SDmitri Tikhonov        LSQ_NOTICE("unexpected request received, abort connection");
87b1a7c3f9SDmitri Tikhonov        lsquic_conn_abort(conn);
88b1a7c3f9SDmitri Tikhonov    }
89b1a7c3f9SDmitri Tikhonov}
90b1a7c3f9SDmitri Tikhonov
91b1a7c3f9SDmitri Tikhonov
92b1a7c3f9SDmitri Tikhonovconst struct lsquic_stream_if duck_server_stream_if = {
93b1a7c3f9SDmitri Tikhonov    .on_new_conn            = duck_server_on_new_conn,
94b1a7c3f9SDmitri Tikhonov    .on_conn_closed         = duck_server_on_conn_closed,
95b1a7c3f9SDmitri Tikhonov    .on_dg_write            = duck_on_dg_write,
96b1a7c3f9SDmitri Tikhonov    .on_datagram            = duck_on_datagram,
97b1a7c3f9SDmitri Tikhonov};
98b1a7c3f9SDmitri Tikhonov
99b1a7c3f9SDmitri Tikhonov
100b1a7c3f9SDmitri Tikhonovstatic void
101b1a7c3f9SDmitri Tikhonovusage (const char *prog)
102b1a7c3f9SDmitri Tikhonov{
103b1a7c3f9SDmitri Tikhonov    const char *const slash = strrchr(prog, '/');
104b1a7c3f9SDmitri Tikhonov    if (slash)
105b1a7c3f9SDmitri Tikhonov        prog = slash + 1;
106b1a7c3f9SDmitri Tikhonov    printf(
107b1a7c3f9SDmitri Tikhonov"Usage: %s [opts]\n"
108b1a7c3f9SDmitri Tikhonov"\n"
109b1a7c3f9SDmitri Tikhonov"Options:\n"
110b1a7c3f9SDmitri Tikhonov                , prog);
111b1a7c3f9SDmitri Tikhonov}
112b1a7c3f9SDmitri Tikhonov
113b1a7c3f9SDmitri Tikhonov
114b1a7c3f9SDmitri Tikhonovint
115b1a7c3f9SDmitri Tikhonovmain (int argc, char **argv)
116b1a7c3f9SDmitri Tikhonov{
117b1a7c3f9SDmitri Tikhonov    int opt, s;
118b1a7c3f9SDmitri Tikhonov    struct prog prog;
119b1a7c3f9SDmitri Tikhonov    struct sport_head sports;
120b1a7c3f9SDmitri Tikhonov
121b1a7c3f9SDmitri Tikhonov    TAILQ_INIT(&sports);
122b1a7c3f9SDmitri Tikhonov    prog_init(&prog, LSENG_SERVER, &sports, &duck_server_stream_if, NULL);
123b1a7c3f9SDmitri Tikhonov    prog.prog_settings.es_datagrams = 1;
124b1a7c3f9SDmitri Tikhonov    prog.prog_settings.es_init_max_data = 0;
125b1a7c3f9SDmitri Tikhonov    prog.prog_settings.es_init_max_streams_bidi = 0;
126b1a7c3f9SDmitri Tikhonov    prog.prog_settings.es_init_max_streams_uni = 0;
127b1a7c3f9SDmitri Tikhonov    prog.prog_settings.es_max_streams_in = 0;
128b1a7c3f9SDmitri Tikhonov
129b1a7c3f9SDmitri Tikhonov    while (-1 != (opt = getopt(argc, argv, PROG_OPTS "h")))
130b1a7c3f9SDmitri Tikhonov    {
131b1a7c3f9SDmitri Tikhonov        switch (opt) {
132b1a7c3f9SDmitri Tikhonov        case 'h':
133b1a7c3f9SDmitri Tikhonov            usage(argv[0]);
134b1a7c3f9SDmitri Tikhonov            prog_print_common_options(&prog, stdout);
135b1a7c3f9SDmitri Tikhonov            exit(0);
136b1a7c3f9SDmitri Tikhonov        default:
137b1a7c3f9SDmitri Tikhonov            if (0 != prog_set_opt(&prog, opt, optarg))
138b1a7c3f9SDmitri Tikhonov                exit(1);
139b1a7c3f9SDmitri Tikhonov        }
140b1a7c3f9SDmitri Tikhonov    }
141b1a7c3f9SDmitri Tikhonov
142b1a7c3f9SDmitri Tikhonov    if (0 != add_alpn("siduck-00"))
143b1a7c3f9SDmitri Tikhonov    {
144b1a7c3f9SDmitri Tikhonov        LSQ_ERROR("could not add ALPN");
145b1a7c3f9SDmitri Tikhonov        exit(EXIT_FAILURE);
146b1a7c3f9SDmitri Tikhonov    }
147b1a7c3f9SDmitri Tikhonov
148b1a7c3f9SDmitri Tikhonov    if (0 != prog_prep(&prog))
149b1a7c3f9SDmitri Tikhonov    {
150b1a7c3f9SDmitri Tikhonov        LSQ_ERROR("could not prep");
151b1a7c3f9SDmitri Tikhonov        exit(EXIT_FAILURE);
152b1a7c3f9SDmitri Tikhonov    }
153b1a7c3f9SDmitri Tikhonov
154b1a7c3f9SDmitri Tikhonov    LSQ_DEBUG("entering event loop");
155b1a7c3f9SDmitri Tikhonov
156b1a7c3f9SDmitri Tikhonov    s = prog_run(&prog);
157b1a7c3f9SDmitri Tikhonov    prog_cleanup(&prog);
158b1a7c3f9SDmitri Tikhonov
159b1a7c3f9SDmitri Tikhonov    exit(0 == s ? EXIT_SUCCESS : EXIT_FAILURE);
160b1a7c3f9SDmitri Tikhonov}
161