duck_server.c revision b1a7c3f9
1b1a7c3f9SDmitri Tikhonov/* Copyright (c) 2017 - 2020 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