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