mirror of
				https://gitea.invidious.io/iv-org/litespeed-quic.git
				synced 2024-08-15 00:53:43 +00:00 
			
		
		
		
	Release 2.20.0
- [FEATURE] QUIC and HTTP/3 Internet Draft 30 support. - [FEATURE] Unreliable Datagram Extension support. - [FEATURE] Adaptive congestion controller. - [BUGFIX] Do not send MAX_STREAM_DATA frames on crypto streams. - [BUGFIX] Fail with CRYPTO_BUFFER_EXCEEDED when too much CRYPTO data comes in. - [BUFFIX] Spin bit is now strictly per path; value is reset on DCID change. - [BUGFIX] Check that max value of max_streams_uni and max_streams_bidi TPs is 2^60. - [BUGFIX] Close IETF mini conn immediately if crypto session cannot be initialized. - Deprecate ID-28 (no browser uses it): it's no longer in the default versions list. - New programs duck_server and duck_client that implement the experimental siduck-00 protocol. They quack! - IETF crypto streams: don't limit ourselves from sending. - Command-line programs: turn off QL loss bits if -G is used, as Wireshark cannot decrypt QUIC packets when this extension is used. - Turn all h3 framing unit tests back on. - Fix malo initialization when compiled in no-pool mode.
This commit is contained in:
		
							parent
							
								
									c3c69ba3bb
								
							
						
					
					
						commit
						b1a7c3f944
					
				
					 53 changed files with 1745 additions and 161 deletions
				
			
		
							
								
								
									
										189
									
								
								bin/duck_client.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								bin/duck_client.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,189 @@
 | 
			
		|||
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc.  See LICENSE. */
 | 
			
		||||
/*
 | 
			
		||||
 * duck_client.c -- The siduck client.  See
 | 
			
		||||
 *      https://tools.ietf.org/html/draft-pardue-quic-siduck-00
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#define Read read
 | 
			
		||||
#else
 | 
			
		||||
#include "vc_compat.h"
 | 
			
		||||
#include "getopt.h"
 | 
			
		||||
#include <io.h>
 | 
			
		||||
#define Read _read
 | 
			
		||||
#define STDIN_FILENO 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <event2/event.h>
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "test_common.h"
 | 
			
		||||
#include "prog.h"
 | 
			
		||||
 | 
			
		||||
#include "../src/liblsquic/lsquic_logger.h"
 | 
			
		||||
 | 
			
		||||
/* Expected request and response of the siduck protocol */
 | 
			
		||||
#define REQUEST "quack"
 | 
			
		||||
#define RESPONSE "quack-ack"
 | 
			
		||||
 | 
			
		||||
static lsquic_conn_ctx_t *
 | 
			
		||||
duck_client_on_new_conn (void *stream_if_ctx, lsquic_conn_t *conn)
 | 
			
		||||
{
 | 
			
		||||
    LSQ_NOTICE("created a new connection");
 | 
			
		||||
    return stream_if_ctx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
duck_client_on_hsk_done (lsquic_conn_t *conn, enum lsquic_hsk_status s)
 | 
			
		||||
{
 | 
			
		||||
    if (s == LSQ_HSK_OK || s == LSQ_HSK_RESUMED_OK)
 | 
			
		||||
    {
 | 
			
		||||
        if (lsquic_conn_want_datagram_write(conn, 1) < 0)
 | 
			
		||||
            LSQ_ERROR("want_datagram_write failed");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
duck_client_on_conn_closed (lsquic_conn_t *conn)
 | 
			
		||||
{
 | 
			
		||||
    lsquic_conn_ctx_t *ctx = lsquic_conn_get_ctx(conn);
 | 
			
		||||
    LSQ_NOTICE("Connection closed, stop client");
 | 
			
		||||
    prog_stop((struct prog *) ctx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static ssize_t
 | 
			
		||||
duck_client_on_dg_write (lsquic_conn_t *conn, void *buf, size_t sz)
 | 
			
		||||
{
 | 
			
		||||
    int s;
 | 
			
		||||
 | 
			
		||||
    /* We only write one request */
 | 
			
		||||
    s = lsquic_conn_want_datagram_write(conn, 0);
 | 
			
		||||
    assert(s == 1); /* Old value was "yes, we want to write a datagram" */
 | 
			
		||||
 | 
			
		||||
    if (sz >= sizeof(REQUEST) - 1)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_INFO("wrote `%s' in request", REQUEST);
 | 
			
		||||
        memcpy(buf, REQUEST, sizeof(REQUEST) - 1);
 | 
			
		||||
        return sizeof(REQUEST) - 1;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
duck_client_on_datagram (lsquic_conn_t *conn, const void *buf, size_t bufsz)
 | 
			
		||||
{
 | 
			
		||||
    if (bufsz == sizeof(RESPONSE) - 1
 | 
			
		||||
            && 0 == memcmp(buf, RESPONSE, sizeof(RESPONSE) - 1))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_DEBUG("received the expected `%s' response", RESPONSE);
 | 
			
		||||
        lsquic_conn_close(conn);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_NOTICE("unexpected request received, abort connection");
 | 
			
		||||
        lsquic_conn_abort(conn);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const struct lsquic_stream_if duck_client_stream_if = {
 | 
			
		||||
    .on_new_conn            = duck_client_on_new_conn,
 | 
			
		||||
    .on_hsk_done            = duck_client_on_hsk_done,
 | 
			
		||||
    .on_conn_closed         = duck_client_on_conn_closed,
 | 
			
		||||
    .on_dg_write            = duck_client_on_dg_write,
 | 
			
		||||
    .on_datagram            = duck_client_on_datagram,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
usage (const char *prog)
 | 
			
		||||
{
 | 
			
		||||
    const char *const slash = strrchr(prog, '/');
 | 
			
		||||
    if (slash)
 | 
			
		||||
        prog = slash + 1;
 | 
			
		||||
    LSQ_NOTICE(
 | 
			
		||||
"Usage: %s [opts]\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"Options:\n"
 | 
			
		||||
            , prog);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main (int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    int opt, s;
 | 
			
		||||
    struct sport_head sports;
 | 
			
		||||
    struct prog prog;
 | 
			
		||||
 | 
			
		||||
    TAILQ_INIT(&sports);
 | 
			
		||||
    prog_init(&prog, 0, &sports, &duck_client_stream_if, &prog);
 | 
			
		||||
    prog.prog_settings.es_datagrams = 1;
 | 
			
		||||
    prog.prog_settings.es_init_max_data = 0;
 | 
			
		||||
    prog.prog_settings.es_init_max_streams_bidi = 0;
 | 
			
		||||
    prog.prog_settings.es_init_max_streams_uni = 0;
 | 
			
		||||
    prog.prog_settings.es_max_streams_in = 0;
 | 
			
		||||
    prog.prog_api.ea_alpn = "siduck-00";
 | 
			
		||||
 | 
			
		||||
    while (-1 != (opt = getopt(argc, argv, PROG_OPTS "h")))
 | 
			
		||||
    {
 | 
			
		||||
        switch (opt) {
 | 
			
		||||
        case 'h':
 | 
			
		||||
            usage(argv[0]);
 | 
			
		||||
            prog_print_common_options(&prog, stdout);
 | 
			
		||||
            exit(0);
 | 
			
		||||
        default:
 | 
			
		||||
            if (0 != prog_set_opt(&prog, opt, optarg))
 | 
			
		||||
                exit(1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
    int flags = fcntl(STDIN_FILENO, F_GETFL);
 | 
			
		||||
    flags |= O_NONBLOCK;
 | 
			
		||||
    if (0 != fcntl(STDIN_FILENO, F_SETFL, flags))
 | 
			
		||||
    {
 | 
			
		||||
        perror("fcntl");
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    {
 | 
			
		||||
        u_long on = 1;
 | 
			
		||||
        ioctlsocket(STDIN_FILENO, FIONBIO, &on);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    if (0 != prog_prep(&prog))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("could not prep");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
    if (0 != prog_connect(&prog, NULL, 0))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("could not connect");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("entering event loop");
 | 
			
		||||
 | 
			
		||||
    s = prog_run(&prog);
 | 
			
		||||
    prog_cleanup(&prog);
 | 
			
		||||
 | 
			
		||||
    exit(0 == s ? EXIT_SUCCESS : EXIT_FAILURE);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										160
									
								
								bin/duck_server.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								bin/duck_server.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,160 @@
 | 
			
		|||
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc.  See LICENSE. */
 | 
			
		||||
/*
 | 
			
		||||
 * A duck quacks!  The server for the siduck protocol:
 | 
			
		||||
 *      https://tools.ietf.org/html/draft-pardue-quic-siduck-00
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#else
 | 
			
		||||
#include "vc_compat.h"
 | 
			
		||||
#include "getopt.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "../src/liblsquic/lsquic_hash.h"
 | 
			
		||||
#include "test_common.h"
 | 
			
		||||
#include "test_cert.h"
 | 
			
		||||
#include "prog.h"
 | 
			
		||||
 | 
			
		||||
#include "../src/liblsquic/lsquic_logger.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static lsquic_conn_ctx_t *
 | 
			
		||||
duck_server_on_new_conn (void *stream_if_ctx, lsquic_conn_t *conn)
 | 
			
		||||
{
 | 
			
		||||
    LSQ_NOTICE("New siduck connection established!");
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
duck_server_on_conn_closed (lsquic_conn_t *conn)
 | 
			
		||||
{
 | 
			
		||||
    LSQ_NOTICE("siduck connection closed");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Expected request and response of the siduck protocol */
 | 
			
		||||
#define REQUEST "quack"
 | 
			
		||||
#define RESPONSE "quack-ack"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static ssize_t
 | 
			
		||||
duck_on_dg_write (lsquic_conn_t *conn, void *buf, size_t sz)
 | 
			
		||||
{
 | 
			
		||||
    int s;
 | 
			
		||||
 | 
			
		||||
    /* We only write one response */
 | 
			
		||||
    s = lsquic_conn_want_datagram_write(conn, 0);
 | 
			
		||||
    assert(s == 1);     /* Old value was "yes" */
 | 
			
		||||
 | 
			
		||||
    if (sz >= sizeof(RESPONSE) - 1)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_INFO("wrote `%s' in response", RESPONSE);
 | 
			
		||||
        memcpy(buf, RESPONSE, sizeof(RESPONSE) - 1);
 | 
			
		||||
        lsquic_conn_close(conn);    /* Close connection right away */
 | 
			
		||||
        return sizeof(RESPONSE) - 1;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
duck_on_datagram (lsquic_conn_t *conn, const void *buf, size_t bufsz)
 | 
			
		||||
{
 | 
			
		||||
    int s;
 | 
			
		||||
 | 
			
		||||
    if (bufsz == sizeof(REQUEST) - 1
 | 
			
		||||
            && 0 == memcmp(buf, REQUEST, sizeof(REQUEST) - 1))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_DEBUG("received the expected `%s' request", REQUEST);
 | 
			
		||||
        s = lsquic_conn_want_datagram_write(conn, 1);
 | 
			
		||||
        assert(s == 0);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_NOTICE("unexpected request received, abort connection");
 | 
			
		||||
        lsquic_conn_abort(conn);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const struct lsquic_stream_if duck_server_stream_if = {
 | 
			
		||||
    .on_new_conn            = duck_server_on_new_conn,
 | 
			
		||||
    .on_conn_closed         = duck_server_on_conn_closed,
 | 
			
		||||
    .on_dg_write            = duck_on_dg_write,
 | 
			
		||||
    .on_datagram            = duck_on_datagram,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
usage (const char *prog)
 | 
			
		||||
{
 | 
			
		||||
    const char *const slash = strrchr(prog, '/');
 | 
			
		||||
    if (slash)
 | 
			
		||||
        prog = slash + 1;
 | 
			
		||||
    printf(
 | 
			
		||||
"Usage: %s [opts]\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"Options:\n"
 | 
			
		||||
                , prog);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main (int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    int opt, s;
 | 
			
		||||
    struct prog prog;
 | 
			
		||||
    struct sport_head sports;
 | 
			
		||||
 | 
			
		||||
    TAILQ_INIT(&sports);
 | 
			
		||||
    prog_init(&prog, LSENG_SERVER, &sports, &duck_server_stream_if, NULL);
 | 
			
		||||
    prog.prog_settings.es_datagrams = 1;
 | 
			
		||||
    prog.prog_settings.es_init_max_data = 0;
 | 
			
		||||
    prog.prog_settings.es_init_max_streams_bidi = 0;
 | 
			
		||||
    prog.prog_settings.es_init_max_streams_uni = 0;
 | 
			
		||||
    prog.prog_settings.es_max_streams_in = 0;
 | 
			
		||||
 | 
			
		||||
    while (-1 != (opt = getopt(argc, argv, PROG_OPTS "h")))
 | 
			
		||||
    {
 | 
			
		||||
        switch (opt) {
 | 
			
		||||
        case 'h':
 | 
			
		||||
            usage(argv[0]);
 | 
			
		||||
            prog_print_common_options(&prog, stdout);
 | 
			
		||||
            exit(0);
 | 
			
		||||
        default:
 | 
			
		||||
            if (0 != prog_set_opt(&prog, opt, optarg))
 | 
			
		||||
                exit(1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (0 != add_alpn("siduck-00"))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("could not add ALPN");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (0 != prog_prep(&prog))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("could not prep");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("entering event loop");
 | 
			
		||||
 | 
			
		||||
    s = prog_run(&prog);
 | 
			
		||||
    prog_cleanup(&prog);
 | 
			
		||||
 | 
			
		||||
    exit(0 == s ? EXIT_SUCCESS : EXIT_FAILURE);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -29,9 +29,11 @@
 | 
			
		|||
#include <openssl/md5.h>
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "../src/liblsquic/lsquic_hash.h"
 | 
			
		||||
#include "lsxpack_header.h"
 | 
			
		||||
#include "test_config.h"
 | 
			
		||||
#include "test_common.h"
 | 
			
		||||
#include "test_cert.h"
 | 
			
		||||
#include "prog.h"
 | 
			
		||||
 | 
			
		||||
#if HAVE_REGEX
 | 
			
		||||
| 
						 | 
				
			
			@ -1764,6 +1766,7 @@ main (int argc, char **argv)
 | 
			
		|||
    struct stat st;
 | 
			
		||||
    struct server_ctx server_ctx;
 | 
			
		||||
    struct prog prog;
 | 
			
		||||
    const char *const *alpn;
 | 
			
		||||
 | 
			
		||||
#if !(HAVE_OPEN_MEMSTREAM || HAVE_REGEX)
 | 
			
		||||
    fprintf(stderr, "cannot run server without regex or open_memstream\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -1846,6 +1849,18 @@ main (int argc, char **argv)
 | 
			
		|||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    alpn = lsquic_get_h3_alpns(prog.prog_settings.es_versions);
 | 
			
		||||
    while (*alpn)
 | 
			
		||||
    {
 | 
			
		||||
        if (0 == add_alpn(*alpn))
 | 
			
		||||
            ++alpn;
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            LSQ_ERROR("cannot add ALPN %s", *alpn);
 | 
			
		||||
            exit(EXIT_FAILURE);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (0 != prog_prep(&prog))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("could not prep");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -357,6 +357,12 @@ prog_set_opt (struct prog *prog, int opt, const char *arg)
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
        prog->prog_keylog_dir = optarg;
 | 
			
		||||
        if (prog->prog_settings.es_ql_bits)
 | 
			
		||||
        {
 | 
			
		||||
            LSQ_NOTICE("QL loss bits turned off because of -G.  If you want "
 | 
			
		||||
                "to turn it on, just override: -G dir -o ql_bits=2");
 | 
			
		||||
            prog->prog_settings.es_ql_bits = 0;
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
#else
 | 
			
		||||
        LSQ_ERROR("key logging is not supported on Windows");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,15 +17,36 @@
 | 
			
		|||
#include "test_cert.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static char s_alpn[0x100];
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
add_alpn (const char *alpn)
 | 
			
		||||
{
 | 
			
		||||
    size_t alpn_len, all_len;
 | 
			
		||||
 | 
			
		||||
    alpn_len = strlen(alpn);
 | 
			
		||||
    if (alpn_len > 255)
 | 
			
		||||
        return -1;
 | 
			
		||||
 | 
			
		||||
    all_len = strlen(s_alpn);
 | 
			
		||||
    if (all_len + 1 + alpn_len + 1 > sizeof(s_alpn))
 | 
			
		||||
        return -1;
 | 
			
		||||
 | 
			
		||||
    s_alpn[all_len] = alpn_len;
 | 
			
		||||
    memcpy(&s_alpn[all_len + 1], alpn, alpn_len);
 | 
			
		||||
    s_alpn[all_len + 1 + alpn_len] = '\0';
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
select_alpn (SSL *ssl, const unsigned char **out, unsigned char *outlen,
 | 
			
		||||
                    const unsigned char *in, unsigned int inlen, void *arg)
 | 
			
		||||
{
 | 
			
		||||
    const unsigned char alpn[] = "\x5h3-27\x5h3-28\x5h3-29";
 | 
			
		||||
    int r;
 | 
			
		||||
 | 
			
		||||
    r = SSL_select_next_proto((unsigned char **) out, outlen, in, inlen,
 | 
			
		||||
                                                            alpn, sizeof(alpn));
 | 
			
		||||
                                    (unsigned char *) s_alpn, strlen(s_alpn));
 | 
			
		||||
    if (r == OPENSSL_NPN_NEGOTIATED)
 | 
			
		||||
        return SSL_TLSEXT_ERR_OK;
 | 
			
		||||
    else
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,5 +24,7 @@ lookup_cert (void *cert_lu_ctx, const struct sockaddr * /*unused */,
 | 
			
		|||
void
 | 
			
		||||
delete_certs (struct lsquic_hash *);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
add_alpn (const char *alpn);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue