mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
alpn: assemble defaults from roles and allow override
Since new roles may be incompatible with http, add support for alpn names at the role struct, automatic generation of the default list of alpn names that servers advertise, and the ability to override the used alpn names per-vhost and per- client connection. This not only lets you modulate visibility or use of h2, but also enables vhosts that only offer non-http roles, as well as restricting http role vhosts to only alpn identifiers related to http roles.
This commit is contained in:
parent
f978ea8658
commit
aa816e98a9
25 changed files with 497 additions and 334 deletions
|
@ -864,7 +864,6 @@ if (LWS_WITH_HTTP2 AND NOT LWS_WITHOUT_SERVER)
|
|||
list(APPEND SOURCES
|
||||
lib/roles/h2/http2.c
|
||||
lib/roles/h2/hpack.c
|
||||
lib/roles/h2/ssl-http2.c
|
||||
lib/roles/h2/ops-h2.c)
|
||||
endif()
|
||||
# select the active platform files
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
|
||||
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -25,6 +25,22 @@
|
|||
#define LWS_BUILD_HASH "unknown-build-hash"
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
static const struct lws_role_ops * available_roles[] = {
|
||||
#if defined(LWS_ROLE_H2)
|
||||
&role_ops_h2,
|
||||
#endif
|
||||
#if defined(LWS_ROLE_H1)
|
||||
&role_ops_h1,
|
||||
#endif
|
||||
#if defined(LWS_ROLE_WS)
|
||||
&role_ops_ws,
|
||||
#endif
|
||||
};
|
||||
|
||||
static char alpn_discovered[32];
|
||||
#endif
|
||||
|
||||
static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
|
||||
|
||||
/**
|
||||
|
@ -40,6 +56,25 @@ lws_get_library_version(void)
|
|||
return library_version;
|
||||
}
|
||||
|
||||
int
|
||||
lws_role_call_alpn_negotiated(struct lws *wsi, const char *alpn)
|
||||
{
|
||||
#if defined(LWS_WITH_TLS)
|
||||
int n;
|
||||
|
||||
if (!alpn)
|
||||
return 0;
|
||||
|
||||
lwsl_info("%s: '%s'\n", __func__, alpn);
|
||||
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(available_roles); n++)
|
||||
if (!strcmp(available_roles[n]->alpn, alpn) &&
|
||||
available_roles[n]->alpn_negotiated)
|
||||
return available_roles[n]->alpn_negotiated(wsi, alpn);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const mount_protocols[] = {
|
||||
"http://",
|
||||
"https://",
|
||||
|
@ -553,6 +588,7 @@ lws_create_vhost(struct lws_context *context,
|
|||
vh->pvo = info->pvo;
|
||||
vh->headers = info->headers;
|
||||
vh->user = info->user;
|
||||
vh->alpn = info->alpn;
|
||||
|
||||
#if defined(LWS_ROLE_H2)
|
||||
role_ops_h2.init_vhost(vh, info);
|
||||
|
@ -1081,6 +1117,28 @@ lws_create_context(struct lws_context_creation_info *info)
|
|||
|
||||
context->options = info->options;
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
if (info->alpn)
|
||||
context->alpn_default = info->alpn;
|
||||
else {
|
||||
char *p = alpn_discovered, first = 1;
|
||||
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(available_roles); n++) {
|
||||
if (available_roles[n]->alpn) {
|
||||
if (!first)
|
||||
*p++ = ',';
|
||||
p += lws_snprintf(p, alpn_discovered +
|
||||
sizeof(alpn_discovered) - 2 - p,
|
||||
"%s", available_roles[n]->alpn);
|
||||
first = 0;
|
||||
}
|
||||
}
|
||||
context->alpn_default = alpn_discovered;
|
||||
}
|
||||
|
||||
lwsl_info("Default ALPN advertisment: %s\n", context->alpn_default);
|
||||
#endif
|
||||
|
||||
if (info->timeout_secs)
|
||||
context->timeout_secs = info->timeout_secs;
|
||||
else
|
||||
|
|
|
@ -2294,7 +2294,10 @@ lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
|
|||
#ifndef LWS_PLAT_OPTEE
|
||||
socklen_t len = sizeof(struct sockaddr_storage);
|
||||
#endif
|
||||
int n, m;
|
||||
int n;
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
int m;
|
||||
#endif
|
||||
struct sockaddr_storage sin;
|
||||
struct sockaddr *v;
|
||||
|
||||
|
@ -2822,6 +2825,22 @@ lws_sum_stats(const struct lws_context *ctx, struct lws_conn_stats *cs)
|
|||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
lws_cmdline_option(int argc, const char **argv, const char *val)
|
||||
{
|
||||
int n = strlen(val), c = argc;
|
||||
|
||||
while (--c > 0)
|
||||
if (!strncmp(argv[c], val, n) && !*(argv[c] + n)) {
|
||||
if (c != argc - 1)
|
||||
return argv[c + 1];
|
||||
|
||||
return argv[c] + n;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_SERVER_STATUS
|
||||
|
||||
LWS_EXTERN int
|
||||
|
|
|
@ -2998,6 +2998,13 @@ struct lws_context_creation_info {
|
|||
/**< VHOST: If non-NULL, when asked to serve a non-existent file,
|
||||
* lws attempts to server this url path instead. Eg,
|
||||
* "/404.html" */
|
||||
const char *alpn;
|
||||
/**< CONTEXT: If non-NULL, default list of advertised alpn, comma-
|
||||
* separated
|
||||
*
|
||||
* VHOST: If non-NULL, per-vhost list of advertised alpn, comma-
|
||||
* separated
|
||||
*/
|
||||
unsigned int h2_rx_scratch_size;
|
||||
/**< VHOST: size of the rx scratch buffer for each stream. 0 =
|
||||
* default (512 bytes). This affects the RX chunk size
|
||||
|
@ -3404,7 +3411,6 @@ enum lws_client_connect_ssl_connection_flags {
|
|||
LCCSCF_ALLOW_SELFSIGNED = (1 << 1),
|
||||
LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK = (1 << 2),
|
||||
LCCSCF_ALLOW_EXPIRED = (1 << 3),
|
||||
LCCSCF_NOT_H2 = (1 << 4),
|
||||
|
||||
LCCSCF_PIPELINE = (1 << 16),
|
||||
/**< Serialize / pipeline multiple client connections
|
||||
|
@ -3487,6 +3493,12 @@ struct lws_client_connect_info {
|
|||
* members added above will see 0 (default) even if the app
|
||||
* was not built against the newer headers.
|
||||
*/
|
||||
const char *alpn;
|
||||
/* NULL: allow lws default ALPN list, from vhost if present or from
|
||||
* list of roles built into lws
|
||||
* non-NULL: require one from provided comma-separated list of alpn
|
||||
* tokens
|
||||
*/
|
||||
|
||||
void *_unused[4]; /**< dummy */
|
||||
};
|
||||
|
@ -4088,6 +4100,7 @@ enum lws_token_indexes {
|
|||
_WSI_TOKEN_CLIENT_ORIGIN,
|
||||
_WSI_TOKEN_CLIENT_METHOD,
|
||||
_WSI_TOKEN_CLIENT_IFACE,
|
||||
_WSI_TOKEN_CLIENT_ALPN,
|
||||
|
||||
/* always last real token index*/
|
||||
WSI_TOKEN_COUNT,
|
||||
|
@ -4670,6 +4683,11 @@ LWS_VISIBLE LWS_EXTERN void
|
|||
lws_libuv_static_refcount_del(uv_handle_t *);
|
||||
|
||||
#endif /* LWS_WITH_LIBUV */
|
||||
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
#define lws_libuv_static_refcount_add(_a, _b)
|
||||
#define lws_libuv_static_refcount_del NULL
|
||||
#endif
|
||||
///@}
|
||||
|
||||
/*! \defgroup event libevent helpers
|
||||
|
@ -5365,6 +5383,7 @@ typedef union {
|
|||
lws_filefd_type filefd;
|
||||
} lws_sock_file_fd_type;
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
struct lws_udp {
|
||||
struct sockaddr sa;
|
||||
socklen_t salen;
|
||||
|
@ -5372,6 +5391,7 @@ struct lws_udp {
|
|||
struct sockaddr sa_pending;
|
||||
socklen_t salen_pending;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* lws_adopt_descriptor_vhost() - adopt foreign socket or file descriptor
|
||||
|
@ -5518,12 +5538,12 @@ lws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name,
|
|||
*/
|
||||
LWS_VISIBLE LWS_EXTERN const char *
|
||||
lws_get_peer_simple(struct lws *wsi, char *name, int namelen);
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
|
||||
|
||||
#define LWS_ITOSA_NOT_EXIST -1
|
||||
#define LWS_ITOSA_NOT_USABLE -2
|
||||
#define LWS_ITOSA_USABLE 0
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
/**
|
||||
* lws_interface_to_sa() - Convert interface name or IP to sockaddr struct
|
||||
*
|
||||
|
@ -5809,6 +5829,25 @@ lws_set_wsi_user(struct lws *wsi, void *user);
|
|||
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_parse_uri(char *p, const char **prot, const char **ads, int *port,
|
||||
const char **path);
|
||||
/**
|
||||
* lws_cmdline_option(): simple commandline parser
|
||||
*
|
||||
* \param argc: count of argument strings
|
||||
* \param argv: argument strings
|
||||
* \param val: string to find
|
||||
*
|
||||
* Returns NULL if the string \p val is not found in the arguments.
|
||||
*
|
||||
* If it is found, then it returns a pointer to the next character after \p val.
|
||||
* So if \p val is "-d", then for the commandlines "myapp -d15" and
|
||||
* "myapp -d 15", in both cases the return will point to the "15".
|
||||
*
|
||||
* In the case there is no argument, like "myapp -d", the return will
|
||||
* either point to the '\\0' at the end of -d, or to the start of the
|
||||
* next argument, ie, will be non-NULL.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN const char *
|
||||
lws_cmdline_option(int argc, const char **argv, const char *val);
|
||||
|
||||
/**
|
||||
* lws_now_secs(): return seconds since 1970-1-1
|
||||
|
|
|
@ -181,11 +181,13 @@ handle_truncated_send:
|
|||
wsi->trunc_len = (unsigned int)(real_len - n);
|
||||
memcpy(wsi->trunc_alloc, buf + n, real_len - n);
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
if (lws_wsi_is_udp(wsi)) {
|
||||
/* stash original destination for fulfilling UDP partials */
|
||||
wsi->udp->sa_pending = wsi->udp->sa;
|
||||
wsi->udp->salen_pending = wsi->udp->salen;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* since something buffered, force it to get another chance to send */
|
||||
lws_callback_on_writable(wsi);
|
||||
|
@ -488,14 +490,16 @@ lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)
|
|||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int n;
|
||||
int n = 0;
|
||||
|
||||
lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1);
|
||||
|
||||
if (lws_wsi_is_udp(wsi)) {
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
wsi->udp->salen = sizeof(wsi->udp->sa);
|
||||
n = recvfrom(wsi->desc.sockfd, (char *)buf, len, 0,
|
||||
&wsi->udp->sa, &wsi->udp->salen);
|
||||
#endif
|
||||
} else
|
||||
n = recv(wsi->desc.sockfd, (char *)buf, len, 0);
|
||||
|
||||
|
@ -523,10 +527,12 @@ lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)
|
|||
int n = 0;
|
||||
|
||||
if (lws_wsi_is_udp(wsi)) {
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
if (wsi->trunc_len)
|
||||
n = sendto(wsi->desc.sockfd, buf, len, 0, &wsi->udp->sa_pending, wsi->udp->salen_pending);
|
||||
else
|
||||
n = sendto(wsi->desc.sockfd, buf, len, 0, &wsi->udp->sa, wsi->udp->salen);
|
||||
#endif
|
||||
} else
|
||||
n = send(wsi->desc.sockfd, (char *)buf, len, MSG_NOSIGNAL);
|
||||
// lwsl_info("%s: sent len %d result %d", __func__, len, n);
|
||||
|
|
|
@ -614,6 +614,7 @@ void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs);
|
|||
struct lws_context_per_thread;
|
||||
struct lws_role_ops {
|
||||
const char *name;
|
||||
const char *alpn;
|
||||
/*
|
||||
* After http headers have parsed, this is the last chance for a role
|
||||
* to upgrade the connection to something else using the headers.
|
||||
|
@ -652,6 +653,9 @@ struct lws_role_ops {
|
|||
/* get encapsulation parent */
|
||||
struct lws * (*encapsulation_parent)(struct lws *wsi);
|
||||
|
||||
/* role-specific destructor */
|
||||
int (*alpn_negotiated)(struct lws *wsi, const char *alpn);
|
||||
|
||||
/* chance for the role to handle close in the protocol */
|
||||
int (*close_via_role_protocol)(struct lws *wsi,
|
||||
enum lws_close_status reason);
|
||||
|
@ -693,9 +697,9 @@ enum {
|
|||
LWS_HP_RET_BAIL_DIE,
|
||||
LWS_HP_RET_USER_SERVICE,
|
||||
|
||||
LWS_HPI_RET_DIE,
|
||||
LWS_HPI_RET_HANDLED,
|
||||
LWS_HPI_RET_CLOSE_HANDLED,
|
||||
LWS_HPI_RET_DIE, /* we closed it */
|
||||
LWS_HPI_RET_HANDLED, /* no probs */
|
||||
LWS_HPI_RET_CLOSE_HANDLED, /* close it for us */
|
||||
|
||||
LWS_UPG_RET_DONE,
|
||||
LWS_UPG_RET_CONTINUE,
|
||||
|
@ -1071,6 +1075,11 @@ struct lws_timed_vh_protocol {
|
|||
|
||||
struct lws_tls_ss_pieces;
|
||||
|
||||
struct alpn_ctx {
|
||||
uint8_t data[23];
|
||||
uint8_t len;
|
||||
};
|
||||
|
||||
struct lws_vhost {
|
||||
char http_proxy_address[128];
|
||||
char proxy_basic_auth_token[128];
|
||||
|
@ -1110,11 +1119,13 @@ struct lws_vhost {
|
|||
struct lws_dll_lws dll_active_client_conns;
|
||||
#endif
|
||||
const char *error_document_404;
|
||||
const char *alpn;
|
||||
#if defined(LWS_WITH_TLS)
|
||||
lws_tls_ctx *ssl_ctx;
|
||||
lws_tls_ctx *ssl_client_ctx;
|
||||
struct lws_tls_ss_pieces *ss; /* for acme tls certs */
|
||||
char ecdh_curve[16];
|
||||
struct alpn_ctx alpn_ctx;
|
||||
#endif
|
||||
#if defined(LWS_WITH_MBEDTLS)
|
||||
lws_tls_x509 *x509_client_CA;
|
||||
|
@ -1262,6 +1273,7 @@ struct lws_context {
|
|||
void *user_space;
|
||||
const char *server_string;
|
||||
const struct lws_protocol_vhost_options *reject_service_keywords;
|
||||
const char *alpn_default;
|
||||
lws_reload_func deprecation_cb;
|
||||
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
|
@ -1527,6 +1539,7 @@ struct client_info_stash {
|
|||
char *protocol;
|
||||
char *method;
|
||||
char *iface;
|
||||
char *alpn;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -2406,8 +2419,6 @@ LWS_EXTERN int
|
|||
lws_add_http2_header_status(struct lws *wsi,
|
||||
unsigned int code, unsigned char **p,
|
||||
unsigned char *end);
|
||||
LWS_EXTERN int
|
||||
lws_h2_configure_if_upgraded(struct lws *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_hpack_destroy_dynamic_header(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
|
@ -2435,8 +2446,6 @@ int
|
|||
lws_handle_POLLOUT_event_h2(struct lws *wsi);
|
||||
int
|
||||
lws_read_h2(struct lws *wsi, unsigned char *buf, lws_filepos_t len);
|
||||
#else
|
||||
#define lws_h2_configure_if_upgraded(x)
|
||||
#endif
|
||||
|
||||
LWS_EXTERN int
|
||||
|
@ -2511,7 +2520,7 @@ LWS_EXTERN void lwsl_emit_stderr(int level, const char *line);
|
|||
#define LWS_SSL_ENABLED(context) (0)
|
||||
#define lws_context_init_server_ssl(_a, _b) (0)
|
||||
#define lws_ssl_destroy(_a)
|
||||
#define lws_context_init_http2_ssl(_a)
|
||||
#define lws_context_init_alpn(_a)
|
||||
#define lws_ssl_capable_read lws_ssl_capable_read_no_ssl
|
||||
#define lws_ssl_capable_write lws_ssl_capable_write_no_ssl
|
||||
#define lws_ssl_pending lws_ssl_pending_no_ssl
|
||||
|
@ -2533,6 +2542,8 @@ enum lws_tls_extant {
|
|||
LWS_TLS_EXTANT_YES,
|
||||
LWS_TLS_EXTANT_ALTERNATIVE
|
||||
};
|
||||
LWS_EXTERN void
|
||||
lws_context_init_alpn(struct lws_vhost *vhost);
|
||||
LWS_EXTERN enum lws_tls_extant
|
||||
lws_tls_use_any_upgrade_check_extant(const char *name);
|
||||
LWS_EXTERN int openssl_websocket_private_data_index;
|
||||
|
@ -2641,17 +2652,9 @@ LWS_EXTERN lws_tls_ctx *
|
|||
lws_tls_ctx_from_wsi(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_get_error(struct lws *wsi, int n);
|
||||
|
||||
#endif
|
||||
/* HTTP2-related */
|
||||
|
||||
#ifdef LWS_WITH_HTTP2
|
||||
LWS_EXTERN void
|
||||
lws_context_init_http2_ssl(struct lws_vhost *vhost);
|
||||
#else
|
||||
#define lws_context_init_http2_ssl(_a)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if LWS_MAX_SMP > 1
|
||||
|
||||
static LWS_INLINE void
|
||||
|
@ -3002,6 +3005,13 @@ int
|
|||
lws_client_ws_upgrade(struct lws *wsi, const char **cce);
|
||||
int
|
||||
lws_create_client_ws_object(struct lws_client_connect_info *i, struct lws *wsi);
|
||||
int
|
||||
lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len);
|
||||
int
|
||||
lws_role_call_alpn_negotiated(struct lws *wsi, const char *alpn);
|
||||
int
|
||||
lws_tls_server_conn_alpn(struct lws *wsi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -76,7 +76,8 @@ rops_periodic_checks_cgi(struct lws_context *context, int tsi, time_t now)
|
|||
}
|
||||
|
||||
struct lws_role_ops role_ops_cgi = {
|
||||
"cgi",
|
||||
/* role name */ "cgi",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
|
@ -90,6 +91,7 @@ struct lws_role_ops role_ops_cgi = {
|
|||
/* write_role_protocol */ NULL,
|
||||
/* rxflow_cache */ NULL,
|
||||
/* encapsulation_parent */ NULL,
|
||||
/* alpn_negotiated */ NULL,
|
||||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ NULL,
|
||||
|
|
|
@ -572,7 +572,7 @@ rops_handle_POLLIN_h1(struct lws_context_per_thread *pt, struct lws *wsi,
|
|||
return n;
|
||||
if (lwsi_state(wsi) != LRS_SSL_INIT)
|
||||
if (lws_server_socket_service_ssl(wsi, LWS_SOCK_INVALID))
|
||||
return LWS_HPI_RET_DIE;
|
||||
return LWS_HPI_RET_CLOSE_HANDLED;
|
||||
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
}
|
||||
|
@ -694,8 +694,29 @@ rops_write_role_protocol_h1(struct lws *wsi, unsigned char *buf, size_t len,
|
|||
return lws_issue_raw(wsi, (unsigned char *)buf, len);
|
||||
}
|
||||
|
||||
static int
|
||||
rops_alpn_negotiated_h1(struct lws *wsi, const char *alpn)
|
||||
{
|
||||
lwsl_debug("%s: client %d\n", __func__, lwsi_role_client(wsi));
|
||||
#if !defined(LWS_NO_CLIENT)
|
||||
if (lwsi_role_client(wsi)) {
|
||||
/*
|
||||
* If alpn asserts it is http/1.1, server support for KA is
|
||||
* mandatory.
|
||||
*
|
||||
* Knowing this lets us proceed with sending pipelined headers
|
||||
* before we received the first response headers.
|
||||
*/
|
||||
wsi->keepalive_active = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lws_role_ops role_ops_h1 = {
|
||||
"h1",
|
||||
/* role name */ "h1",
|
||||
/* alpn id */ "http/1.1",
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
|
@ -709,6 +730,7 @@ struct lws_role_ops role_ops_h1 = {
|
|||
/* write_role_protocol */ rops_write_role_protocol_h1,
|
||||
/* rxflow_cache */ NULL,
|
||||
/* encapsulation_parent */ NULL,
|
||||
/* alpn_negotiated */ rops_alpn_negotiated_h1,
|
||||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ NULL,
|
||||
|
|
|
@ -1056,8 +1056,54 @@ rops_encapsulation_parent_h2(struct lws *wsi)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
rops_alpn_negotiated_h2(struct lws *wsi, const char *alpn)
|
||||
{
|
||||
struct allocated_headers *ah;
|
||||
|
||||
lwsl_debug("%s: client %d\n", __func__, lwsi_role_client(wsi));
|
||||
#if !defined(LWS_NO_CLIENT)
|
||||
if (lwsi_role_client(wsi)) {
|
||||
lwsl_info("%s: upgraded to H2\n", __func__);
|
||||
wsi->client_h2_alpn = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
wsi->upgraded_to_http2 = 1;
|
||||
wsi->vhost->conn_stats.h2_alpn++;
|
||||
|
||||
/* adopt the header info */
|
||||
|
||||
ah = wsi->ah;
|
||||
|
||||
lws_role_transition(wsi, LWSIFR_SERVER, LRS_H2_AWAIT_PREFACE,
|
||||
&role_ops_h2);
|
||||
|
||||
/* http2 union member has http union struct at start */
|
||||
wsi->ah = ah;
|
||||
|
||||
if (!wsi->h2.h2n)
|
||||
wsi->h2.h2n = lws_zalloc(sizeof(*wsi->h2.h2n), "h2n");
|
||||
if (!wsi->h2.h2n)
|
||||
return 1;
|
||||
|
||||
lws_h2_init(wsi);
|
||||
|
||||
/* HTTP2 union */
|
||||
|
||||
lws_hpack_dynamic_size(wsi,
|
||||
wsi->h2.h2n->set.s[H2SET_HEADER_TABLE_SIZE]);
|
||||
wsi->h2.tx_cr = 65535;
|
||||
|
||||
lwsl_info("%s: wsi %p: configured for h2\n", __func__, wsi);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lws_role_ops role_ops_h2 = {
|
||||
"h2",
|
||||
/* role name */ "h2",
|
||||
/* alpn id */ "h2",
|
||||
/* check_upgrades */ rops_check_upgrades_h2,
|
||||
/* init_context */ rops_init_context_h2,
|
||||
/* init_vhost */ rops_init_vhost_h2,
|
||||
|
@ -1071,6 +1117,7 @@ struct lws_role_ops role_ops_h2 = {
|
|||
/* write_role_protocol */ rops_write_role_protocol_h2,
|
||||
/* rxflow_cache */ rops_rxflow_cache_h2,
|
||||
/* encapsulation_parent */ rops_encapsulation_parent_h2,
|
||||
/* alpn_negotiated */ rops_alpn_negotiated_h2,
|
||||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ rops_close_kill_connection_h2,
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Some or all of this file is based on code from nghttp2, which has the
|
||||
* following license. Since it's more liberal than lws license, you're also
|
||||
* at liberty to get the original code from
|
||||
* https://github.com/tatsuhiro-t/nghttp2 under his liberal terms alone.
|
||||
*
|
||||
* nghttp2 - HTTP/2.0 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
#if !defined(LWS_NO_SERVER)
|
||||
#if defined(LWS_WITH_TLS)
|
||||
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
|
||||
struct alpn_ctx {
|
||||
unsigned char *data;
|
||||
unsigned short len;
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen, void *arg)
|
||||
{
|
||||
#if !defined(LWS_WITH_MBEDTLS)
|
||||
struct alpn_ctx *alpn_ctx = arg;
|
||||
|
||||
if (SSL_select_next_proto((unsigned char **)out, outlen, alpn_ctx->data,
|
||||
alpn_ctx->len, in, inlen) !=
|
||||
OPENSSL_NPN_NEGOTIATED)
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
#endif
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_context_init_http2_ssl(struct lws_vhost *vhost)
|
||||
{
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
static struct alpn_ctx protos = { (unsigned char *)"\x02h2"
|
||||
"\x08http/1.1", 6 + 9 };
|
||||
|
||||
SSL_CTX_set_alpn_select_cb(vhost->ssl_ctx, alpn_cb, &protos);
|
||||
lwsl_notice(" HTTP2 / ALPN enabled\n");
|
||||
#else
|
||||
lwsl_notice(
|
||||
" HTTP2 / ALPN configured but not supported by OpenSSL 0x%lx\n",
|
||||
OPENSSL_VERSION_NUMBER);
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
}
|
||||
|
||||
int lws_h2_configure_if_upgraded(struct lws *wsi)
|
||||
{
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
struct allocated_headers *ah;
|
||||
const unsigned char *name = NULL;
|
||||
char cstr[10];
|
||||
unsigned len;
|
||||
|
||||
if (!wsi->ssl)
|
||||
return 0;
|
||||
|
||||
SSL_get0_alpn_selected(wsi->ssl, &name, &len);
|
||||
if (!len) {
|
||||
lwsl_info("no ALPN upgrade\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len > sizeof(cstr) - 1)
|
||||
len = sizeof(cstr) - 1;
|
||||
|
||||
memcpy(cstr, name, len);
|
||||
cstr[len] = '\0';
|
||||
|
||||
lwsl_info("negotiated '%s' using ALPN\n", cstr);
|
||||
wsi->use_ssl |= LCCSCF_USE_SSL;
|
||||
if (strncmp((char *)name, "http/1.1", 8) == 0)
|
||||
return 0;
|
||||
|
||||
/* http2 */
|
||||
|
||||
wsi->upgraded_to_http2 = 1;
|
||||
wsi->vhost->conn_stats.h2_alpn++;
|
||||
|
||||
/* adopt the header info */
|
||||
|
||||
ah = wsi->ah;
|
||||
|
||||
lws_role_transition(wsi, LWSIFR_SERVER, LRS_H2_AWAIT_PREFACE,
|
||||
&role_ops_h2);
|
||||
|
||||
/* http2 union member has http union struct at start */
|
||||
wsi->ah = ah;
|
||||
|
||||
wsi->h2.h2n = lws_zalloc(sizeof(*wsi->h2.h2n), "h2n");
|
||||
if (!wsi->h2.h2n)
|
||||
return 1;
|
||||
|
||||
lws_h2_init(wsi);
|
||||
|
||||
/* HTTP2 union */
|
||||
|
||||
lws_hpack_dynamic_size(wsi,
|
||||
wsi->h2.h2n->set.s[H2SET_HEADER_TABLE_SIZE]);
|
||||
wsi->h2.tx_cr = 65535;
|
||||
|
||||
lwsl_info("%s: wsi %p: configured for h2\n", __func__, wsi);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -84,8 +84,8 @@ lws_client_connect_2(struct lws *wsi)
|
|||
if (w != wsi && w->client_hostname_copy &&
|
||||
!strcmp(adsin, w->client_hostname_copy) &&
|
||||
#if defined(LWS_WITH_TLS)
|
||||
(wsi->use_ssl & (LCCSCF_NOT_H2 | LCCSCF_USE_SSL)) ==
|
||||
(w->use_ssl & (LCCSCF_NOT_H2 | LCCSCF_USE_SSL)) &&
|
||||
(wsi->use_ssl & LCCSCF_USE_SSL) ==
|
||||
(w->use_ssl & LCCSCF_USE_SSL) &&
|
||||
#endif
|
||||
wsi->c_port == w->c_port) {
|
||||
|
||||
|
@ -403,7 +403,7 @@ create_new_conn:
|
|||
sa46.sa4.sin_port = htons(port);
|
||||
n = sizeof(struct sockaddr);
|
||||
}
|
||||
lwsl_notice("%s: CONNECT\n", __func__);
|
||||
|
||||
if (connect(wsi->desc.sockfd, (const struct sockaddr *)&sa46, n) == -1 ||
|
||||
LWS_ERRNO == LWS_EISCONN) {
|
||||
if (LWS_ERRNO == LWS_EALREADY ||
|
||||
|
@ -595,7 +595,7 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
|
|||
const char *path, const char *host)
|
||||
{
|
||||
char origin[300] = "", protocol[300] = "", method[32] = "",
|
||||
iface[16] = "", *p;
|
||||
iface[16] = "", alpn[32], *p;
|
||||
struct lws *wsi = *pwsi;
|
||||
|
||||
if (wsi->redirects == 3) {
|
||||
|
@ -618,7 +618,11 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
|
|||
|
||||
p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);
|
||||
if (p)
|
||||
lws_strncpy(method, p, sizeof(iface));
|
||||
lws_strncpy(iface, p, sizeof(iface));
|
||||
|
||||
p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ALPN);
|
||||
if (p)
|
||||
lws_strncpy(alpn, p, sizeof(alpn));
|
||||
|
||||
lwsl_info("redirect ads='%s', port=%d, path='%s', ssl = %d\n",
|
||||
address, port, path, ssl);
|
||||
|
@ -687,6 +691,10 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
|
|||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,
|
||||
iface))
|
||||
return NULL;
|
||||
if (alpn[0])
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ALPN,
|
||||
alpn))
|
||||
return NULL;
|
||||
|
||||
origin[0] = '/';
|
||||
strncpy(&origin[1], path, sizeof(origin) - 2);
|
||||
|
@ -850,6 +858,7 @@ lws_client_stash_destroy(struct lws *wsi)
|
|||
lws_free_set_NULL(wsi->stash->protocol);
|
||||
lws_free_set_NULL(wsi->stash->method);
|
||||
lws_free_set_NULL(wsi->stash->iface);
|
||||
lws_free_set_NULL(wsi->stash->alpn);
|
||||
|
||||
lws_free_set_NULL(wsi->stash);
|
||||
}
|
||||
|
@ -946,9 +955,6 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
|
|||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
wsi->use_ssl = i->ssl_connection;
|
||||
|
||||
if (!i->method) /* !!! disallow ws for h2 right now */
|
||||
wsi->use_ssl |= LCCSCF_NOT_H2;
|
||||
#else
|
||||
if (i->ssl_connection & LCCSCF_USE_SSL) {
|
||||
lwsl_err("libwebsockets not configured for ssl\n");
|
||||
|
@ -995,6 +1001,26 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
|
|||
if (!wsi->stash->iface)
|
||||
goto bail1;
|
||||
}
|
||||
/*
|
||||
* For ws, default to http/1.1 only. If i->alpn is set, defer to
|
||||
* whatever he has set in there (eg, "h2").
|
||||
*
|
||||
* The problem is he has to commit to h2 before he can find out if the
|
||||
* server has the SETTINGS for ws-over-h2 enabled; if not then ws is
|
||||
* not possible on that connection. So we only try it if he
|
||||
* assertively said to use h2 alpn.
|
||||
*/
|
||||
if (!i->method && !i->alpn) {
|
||||
wsi->stash->alpn = lws_strdup("http/1.1");
|
||||
if (!wsi->stash->alpn)
|
||||
goto bail1;
|
||||
} else
|
||||
if (i->alpn) {
|
||||
wsi->stash->alpn = lws_strdup(i->alpn);
|
||||
if (!wsi->stash->alpn)
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
if (i->pwsi)
|
||||
*i->pwsi = wsi;
|
||||
|
||||
|
@ -1049,14 +1075,13 @@ lws_client_connect_via_info2(struct lws *wsi)
|
|||
|
||||
/*
|
||||
* we're not necessarily in a position to action these right away,
|
||||
* stash them... we only need during connect phase so u.hdr is fine
|
||||
* stash them... we only need during connect phase so into a temp
|
||||
* allocated stash
|
||||
*/
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
|
||||
stash->address))
|
||||
goto bail1;
|
||||
|
||||
/* these only need u.hdr lifetime as well */
|
||||
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash->path))
|
||||
goto bail1;
|
||||
|
||||
|
@ -1083,6 +1108,10 @@ lws_client_connect_via_info2(struct lws *wsi)
|
|||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,
|
||||
stash->iface))
|
||||
goto bail1;
|
||||
if (stash->alpn)
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ALPN,
|
||||
stash->alpn))
|
||||
goto bail1;
|
||||
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
if (!wsi->vhost->socks_proxy_port)
|
||||
|
|
|
@ -342,12 +342,7 @@ start_ws_handshake:
|
|||
* So this is it, we are an h2 master client connection
|
||||
* now, not an h1 client connection.
|
||||
*/
|
||||
lwsl_info("client connection upgraded to h2\n");
|
||||
lws_h2_configure_if_upgraded(wsi);
|
||||
|
||||
lws_role_transition(wsi, LWSIFR_CLIENT,
|
||||
LRS_H2_CLIENT_SEND_SETTINGS,
|
||||
&role_ops_h2);
|
||||
lws_tls_server_conn_alpn(wsi);
|
||||
|
||||
/* send the H2 preface to legitimize the connection */
|
||||
if (lws_h2_issue_preface(wsi)) {
|
||||
|
|
|
@ -39,6 +39,7 @@ static const char * const paths_global[] = {
|
|||
"global.timeout-secs",
|
||||
"global.reject-service-keywords[].*",
|
||||
"global.reject-service-keywords[]",
|
||||
"global.default-alpn",
|
||||
};
|
||||
|
||||
enum lejp_global_paths {
|
||||
|
@ -51,7 +52,8 @@ enum lejp_global_paths {
|
|||
LWJPGP_PINGPONG_SECS,
|
||||
LWJPGP_TIMEOUT_SECS,
|
||||
LWJPGP_REJECT_SERVICE_KEYWORDS_NAME,
|
||||
LWJPGP_REJECT_SERVICE_KEYWORDS
|
||||
LWJPGP_REJECT_SERVICE_KEYWORDS,
|
||||
LWJPGP_DEFAULT_ALPN,
|
||||
};
|
||||
|
||||
static const char * const paths_vhosts[] = {
|
||||
|
@ -102,6 +104,7 @@ static const char * const paths_vhosts[] = {
|
|||
"vhosts[].client-cert-required",
|
||||
"vhosts[].ignore-missing-cert",
|
||||
"vhosts[].error-document-404",
|
||||
"vhosts[].alpn",
|
||||
};
|
||||
|
||||
enum lejp_vhost_paths {
|
||||
|
@ -152,6 +155,7 @@ enum lejp_vhost_paths {
|
|||
LEJPVP_FLAG_CLIENT_CERT_REQUIRED,
|
||||
LEJPVP_IGNORE_MISSING_CERT,
|
||||
LEJPVP_ERROR_DOCUMENT_404,
|
||||
LEJPVP_ALPN,
|
||||
};
|
||||
|
||||
static const char * const parser_errs[] = {
|
||||
|
@ -290,6 +294,10 @@ lejp_globals_cb(struct lejp_ctx *ctx, char reason)
|
|||
a->info->timeout_secs = atoi(ctx->buf);
|
||||
return 0;
|
||||
|
||||
case LWJPGP_DEFAULT_ALPN:
|
||||
a->info->alpn = a->p;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -732,6 +740,10 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
|
|||
a->info->ssl_options_clear |= atol(ctx->buf);
|
||||
return 0;
|
||||
|
||||
case LEJPVP_ALPN:
|
||||
a->info->alpn = a->p;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -729,6 +729,7 @@ lws_find_string_in_file(const char *filename, const char *string, int stringlen)
|
|||
|
||||
return hit;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
lws_unauthorised_basic_auth(struct lws *wsi)
|
||||
|
@ -762,8 +763,6 @@ lws_unauthorised_basic_auth(struct lws *wsi)
|
|||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int lws_clean_url(char *p)
|
||||
{
|
||||
if (p[0] == 'h' && p[1] == 't' && p[2] == 't' && p[3] == 'p') {
|
||||
|
@ -1887,13 +1886,14 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
|
|||
if (type & LWS_ADOPT_SOCKET) { /* socket desc */
|
||||
lwsl_debug("%s: new wsi %p, sockfd %d\n", __func__, new_wsi,
|
||||
(int)(lws_intptr_t)fd.sockfd);
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
if (type & LWS_ADOPT_FLAG_UDP)
|
||||
/*
|
||||
* these can be >128 bytes, so just alloc for UDP
|
||||
*/
|
||||
new_wsi->udp = lws_malloc(sizeof(*new_wsi->udp),
|
||||
"udp struct");
|
||||
#endif
|
||||
|
||||
if (type & LWS_ADOPT_HTTP)
|
||||
/* the transport is accepted...
|
||||
|
|
|
@ -129,9 +129,11 @@ rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi,
|
|||
/* already closed cleanly as necessary */
|
||||
return LWS_HPI_RET_DIE;
|
||||
|
||||
if (lws_server_socket_service_ssl(cwsi, accept_fd))
|
||||
if (lws_server_socket_service_ssl(cwsi, accept_fd)) {
|
||||
lws_close_free_wsi(cwsi, LWS_CLOSE_STATUS_NOSTATUS,
|
||||
"listen svc fail");
|
||||
return LWS_HPI_RET_DIE;
|
||||
}
|
||||
|
||||
lwsl_info("%s: new wsi %p: wsistate 0x%x, role_ops %s\n",
|
||||
__func__, cwsi, cwsi->wsistate, cwsi->role_ops->name);
|
||||
|
@ -148,7 +150,8 @@ int rops_handle_POLLOUT_listen(struct lws *wsi)
|
|||
}
|
||||
|
||||
struct lws_role_ops role_ops_listen = {
|
||||
"listen",
|
||||
/* role name */ "listen",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
|
@ -162,6 +165,7 @@ struct lws_role_ops role_ops_listen = {
|
|||
/* write_role_protocol */ NULL,
|
||||
/* rxflow_cache */ NULL,
|
||||
/* encapsulation_parent */ NULL,
|
||||
/* alpn_negotiated */ NULL,
|
||||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ NULL,
|
||||
|
|
|
@ -55,7 +55,8 @@ rops_handle_POLLIN_pipe(struct lws_context_per_thread *pt, struct lws *wsi,
|
|||
}
|
||||
|
||||
struct lws_role_ops role_ops_pipe = {
|
||||
"pipe",
|
||||
/* role name */ "pipe",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
|
@ -69,6 +70,7 @@ struct lws_role_ops role_ops_pipe = {
|
|||
/* write_role_protocol */ NULL,
|
||||
/* rxflow_cache */ NULL,
|
||||
/* encapsulation_parent */ NULL,
|
||||
/* alpn_negotiated */ NULL,
|
||||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ NULL,
|
||||
|
|
|
@ -151,7 +151,8 @@ rops_handle_POLLIN_raw_file(struct lws_context_per_thread *pt, struct lws *wsi,
|
|||
|
||||
|
||||
struct lws_role_ops role_ops_raw_skt = {
|
||||
"raw-skt",
|
||||
/* role name */ "raw-skt",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
|
@ -165,6 +166,7 @@ struct lws_role_ops role_ops_raw_skt = {
|
|||
/* write_role_protocol */ NULL,
|
||||
/* rxflow_cache */ NULL,
|
||||
/* encapsulation_parent */ NULL,
|
||||
/* alpn_negotiated */ NULL,
|
||||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ NULL,
|
||||
|
@ -176,7 +178,8 @@ struct lws_role_ops role_ops_raw_skt = {
|
|||
|
||||
|
||||
struct lws_role_ops role_ops_raw_file = {
|
||||
"raw-file",
|
||||
/* role name */ "raw-file",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
|
@ -190,6 +193,7 @@ struct lws_role_ops role_ops_raw_file = {
|
|||
/* write_role_protocol */ NULL,
|
||||
/* rxflow_cache */ NULL,
|
||||
/* encapsulation_parent */ NULL,
|
||||
/* alpn_negotiated */ NULL,
|
||||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ NULL,
|
||||
|
|
|
@ -1847,7 +1847,8 @@ rops_callback_on_writable_ws(struct lws *wsi)
|
|||
}
|
||||
|
||||
struct lws_role_ops role_ops_ws = {
|
||||
"ws",
|
||||
/* role name */ "ws",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
|
@ -1861,6 +1862,7 @@ struct lws_role_ops role_ops_ws = {
|
|||
/* write_role_protocol */ rops_write_role_protocol_ws,
|
||||
/* rxflow_cache */ NULL,
|
||||
/* encapsulation_parent */ NULL,
|
||||
/* alpn_negotiated */ NULL,
|
||||
/* close_via_role_protocol */ rops_close_via_role_protocol_ws,
|
||||
/* close_role */ rops_close_role_ws,
|
||||
/* close_kill_connection */ rops_close_kill_connection_ws,
|
||||
|
|
|
@ -27,29 +27,13 @@ OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct alpn_ctx {
|
||||
unsigned char *data;
|
||||
unsigned short len;
|
||||
};
|
||||
|
||||
static struct alpn_ctx protos = { (unsigned char *)
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
"\x02h2"
|
||||
#endif
|
||||
"\x08http/1.1", 3 +
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
3 +
|
||||
#endif
|
||||
9 };
|
||||
|
||||
static struct alpn_ctx protos_h1 = { (unsigned char *)"\x08http/1.1", 3 + 9 };
|
||||
|
||||
int
|
||||
lws_ssl_client_bio_create(struct lws *wsi)
|
||||
{
|
||||
struct alpn_ctx *apro = &protos;
|
||||
X509_VERIFY_PARAM *param;
|
||||
char hostname[128], *p;
|
||||
const char *alpn_comma = wsi->context->alpn_default;
|
||||
struct alpn_ctx protos;
|
||||
|
||||
if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
|
||||
_WSI_TOKEN_CLIENT_HOST) <= 0) {
|
||||
|
@ -75,11 +59,6 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
if (!wsi->ssl)
|
||||
return -1;
|
||||
|
||||
if (wsi->use_ssl & LCCSCF_NOT_H2)
|
||||
apro = &protos_h1;
|
||||
|
||||
SSL_set_alpn_select_cb(wsi->ssl, apro);
|
||||
|
||||
if (wsi->vhost->ssl_info_event_mask)
|
||||
SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
|
||||
|
||||
|
@ -91,6 +70,22 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
X509_VERIFY_PARAM_set1_host(param, hostname, 0);
|
||||
}
|
||||
|
||||
if (wsi->vhost->alpn)
|
||||
alpn_comma = wsi->vhost->alpn;
|
||||
|
||||
if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
|
||||
_WSI_TOKEN_CLIENT_ALPN) > 0)
|
||||
alpn_comma = hostname;
|
||||
|
||||
lwsl_info("%s: %p: client conn sending ALPN list '%s'\n",
|
||||
__func__, wsi, alpn_comma);
|
||||
|
||||
protos.len = lws_alpn_comma_to_openssl(alpn_comma, protos.data,
|
||||
sizeof(protos.data) - 1);
|
||||
|
||||
/* with mbedtls, protos is not pointed to after exit from this call */
|
||||
SSL_set_alpn_select_cb(wsi->ssl, &protos);
|
||||
|
||||
/*
|
||||
* use server name indication (SNI), if supported,
|
||||
* when establishing connection
|
||||
|
@ -117,20 +112,8 @@ lws_tls_client_connect(struct lws *wsi)
|
|||
|
||||
if (n == 1) {
|
||||
SSL_get0_alpn_selected(wsi->ssl, &prot, &len);
|
||||
#if !defined(LWS_NO_CLIENT)
|
||||
if (prot && !strcmp((char *)prot, "h2"))
|
||||
wsi->client_h2_alpn = 1;
|
||||
#endif
|
||||
if (prot && !strcmp((char *)prot, "http/1.1"))
|
||||
/*
|
||||
* If alpn asserts it is http/1.1, KA is mandatory.
|
||||
*
|
||||
* Knowing this lets us proceed with sending
|
||||
* pipelined headers before we received the first
|
||||
* response headers.
|
||||
*/
|
||||
wsi->keepalive_active = 1;
|
||||
|
||||
lws_role_call_alpn_negotiated(wsi, (const char *)prot);
|
||||
lwsl_info("client connect OK\n");
|
||||
return LWS_SSL_CAPABLE_DONE;
|
||||
}
|
||||
|
||||
|
|
|
@ -1648,8 +1648,8 @@ void *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx)
|
|||
*/
|
||||
|
||||
struct alpn_ctx {
|
||||
unsigned char *data;
|
||||
unsigned short len;
|
||||
unsigned char data[23];
|
||||
unsigned char len;
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -1674,6 +1674,9 @@ _openssl_alpn_to_mbedtls(struct alpn_ctx *ac, char ***palpn_protos)
|
|||
break;
|
||||
}
|
||||
|
||||
if (!len)
|
||||
count++;
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
|
@ -1705,6 +1708,12 @@ _openssl_alpn_to_mbedtls(struct alpn_ctx *ac, char ***palpn_protos)
|
|||
if (!len)
|
||||
break;
|
||||
}
|
||||
if (!len) {
|
||||
*q++ = '\0';
|
||||
count++;
|
||||
len = *p++;
|
||||
alpn_protos[count] = (char *)q;
|
||||
}
|
||||
alpn_protos[count] = NULL; /* last pointer ends list with NULL */
|
||||
}
|
||||
|
||||
|
|
|
@ -86,14 +86,6 @@ OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(LWS_HAVE_SSL_set_alpn_protos) && defined(LWS_HAVE_SSL_get0_alpn_selected)
|
||||
static const unsigned char client_alpn_protocols[] = {
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
2, 'h', '2',
|
||||
#endif
|
||||
8, 'h', 't', 't', 'p', '/', '1', '.', '1'
|
||||
};
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_ssl_client_bio_create(struct lws *wsi)
|
||||
|
@ -102,9 +94,11 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
X509_VERIFY_PARAM *param;
|
||||
#endif
|
||||
char hostname[128], *p;
|
||||
#if defined(LWS_HAVE_SSL_set_alpn_protos) && defined(LWS_HAVE_SSL_get0_alpn_selected)
|
||||
const unsigned char *plist = client_alpn_protocols;
|
||||
int n = sizeof(client_alpn_protocols);
|
||||
#if defined(LWS_HAVE_SSL_set_alpn_protos) && \
|
||||
defined(LWS_HAVE_SSL_get0_alpn_selected)
|
||||
uint8_t openssl_alpn[40];
|
||||
const char *alpn_comma = wsi->context->alpn_default;
|
||||
int n;
|
||||
#endif
|
||||
|
||||
if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
|
||||
|
@ -135,17 +129,6 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
return -1;
|
||||
}
|
||||
|
||||
#if defined(LWS_HAVE_SSL_set_alpn_protos) && \
|
||||
defined(LWS_HAVE_SSL_get0_alpn_selected)
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (wsi->use_ssl & LCCSCF_NOT_H2) {
|
||||
plist += 3;
|
||||
n -= 3;
|
||||
}
|
||||
#endif
|
||||
SSL_set_alpn_protos(wsi->ssl, plist, n);
|
||||
#endif
|
||||
|
||||
#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
|
||||
if (wsi->vhost->ssl_info_event_mask)
|
||||
SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
|
||||
|
@ -221,6 +204,23 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
BIO_set_nbio(wsi->client_bio, 1); /* nonblocking */
|
||||
#endif
|
||||
|
||||
#if defined(LWS_HAVE_SSL_set_alpn_protos) && \
|
||||
defined(LWS_HAVE_SSL_get0_alpn_selected)
|
||||
if (wsi->vhost->alpn)
|
||||
alpn_comma = wsi->vhost->alpn;
|
||||
|
||||
if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
|
||||
_WSI_TOKEN_CLIENT_ALPN) > 0)
|
||||
alpn_comma = hostname;
|
||||
|
||||
lwsl_info("client conn using alpn list '%s'\n", alpn_comma);
|
||||
|
||||
n = lws_alpn_comma_to_openssl(alpn_comma, openssl_alpn,
|
||||
sizeof(openssl_alpn) - 1);
|
||||
|
||||
SSL_set_alpn_protos(wsi->ssl, openssl_alpn, n);
|
||||
#endif
|
||||
|
||||
SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index, wsi);
|
||||
|
||||
return 0;
|
||||
|
@ -244,24 +244,10 @@ lws_tls_client_connect(struct lws *wsi)
|
|||
len = sizeof(a) - 1;
|
||||
memcpy(a, (const char *)prot, len);
|
||||
a[len] = '\0';
|
||||
#if !defined(LWS_NO_CLIENT)
|
||||
if (prot && !strcmp(a, "h2")) {
|
||||
lwsl_info("%s: upgraded to H2\n", __func__);
|
||||
wsi->client_h2_alpn = 1;
|
||||
}
|
||||
#endif
|
||||
if (prot && !strcmp(a, "http/1.1"))
|
||||
/*
|
||||
* If alpn asserts it is http/1.1, KA is mandatory.
|
||||
*
|
||||
* Knowing this lets us proceed with sending
|
||||
* pipelined headers before we received the first
|
||||
* response headers.
|
||||
*/
|
||||
wsi->keepalive_active = 1;
|
||||
|
||||
lwsl_info("client connect OK\n");
|
||||
lws_role_call_alpn_negotiated(wsi, (const char *)a);
|
||||
#endif
|
||||
lwsl_info("client connect OK\n");
|
||||
return LWS_SSL_CAPABLE_DONE;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,79 @@
|
|||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
static int
|
||||
alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen, void *arg)
|
||||
{
|
||||
#if !defined(LWS_WITH_MBEDTLS)
|
||||
struct alpn_ctx *alpn_ctx = (struct alpn_ctx *)arg;
|
||||
|
||||
if (SSL_select_next_proto((unsigned char **)out, outlen, alpn_ctx->data,
|
||||
alpn_ctx->len, in, inlen) !=
|
||||
OPENSSL_NPN_NEGOTIATED)
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
#endif
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
lws_context_init_alpn(struct lws_vhost *vhost)
|
||||
{
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
const char *alpn_comma = vhost->context->alpn_default;
|
||||
|
||||
if (vhost->alpn)
|
||||
alpn_comma = vhost->alpn;
|
||||
|
||||
lwsl_info(" Server '%s' advertising ALPN: %s\n",
|
||||
vhost->name, alpn_comma);
|
||||
vhost->alpn_ctx.len = lws_alpn_comma_to_openssl(alpn_comma,
|
||||
vhost->alpn_ctx.data,
|
||||
sizeof(vhost->alpn_ctx.data) - 1);
|
||||
|
||||
SSL_CTX_set_alpn_select_cb(vhost->ssl_ctx, alpn_cb, &vhost->alpn_ctx);
|
||||
#else
|
||||
lwsl_err(
|
||||
" HTTP2 / ALPN configured but not supported by OpenSSL 0x%lx\n",
|
||||
OPENSSL_VERSION_NUMBER);
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_server_conn_alpn(struct lws *wsi)
|
||||
{
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
const unsigned char *name = NULL;
|
||||
char cstr[10];
|
||||
unsigned len;
|
||||
|
||||
SSL_get0_alpn_selected(wsi->ssl, &name, &len);
|
||||
if (!len) {
|
||||
lwsl_info("no ALPN upgrade\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len > sizeof(cstr) - 1)
|
||||
len = sizeof(cstr) - 1;
|
||||
|
||||
memcpy(cstr, name, len);
|
||||
cstr[len] = '\0';
|
||||
|
||||
lwsl_info("negotiated '%s' using ALPN\n", cstr);
|
||||
wsi->use_ssl |= LCCSCF_USE_SSL;
|
||||
|
||||
return lws_role_call_alpn_negotiated(wsi, (const char *)cstr);
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost)
|
||||
|
@ -95,11 +168,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
|||
}
|
||||
|
||||
if (vhost->use_ssl)
|
||||
/*
|
||||
* SSL is happy and has a cert it's content with
|
||||
* If we're supporting HTTP2, initialize that
|
||||
*/
|
||||
lws_context_init_http2_ssl(vhost);
|
||||
lws_context_init_alpn(vhost);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -296,11 +365,8 @@ accepted:
|
|||
context->timeout_secs);
|
||||
|
||||
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (lws_h2_configure_if_upgraded(wsi))
|
||||
if (lws_tls_server_conn_alpn(wsi))
|
||||
goto fail;
|
||||
#endif
|
||||
lwsl_debug("accepted new SSL conn\n");
|
||||
break;
|
||||
|
||||
|
|
|
@ -478,3 +478,37 @@ lws_gate_accepts(struct lws_context *context, int on)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* comma-separated alpn list, like "h2,http/1.1" to openssl alpn format */
|
||||
|
||||
int
|
||||
lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len)
|
||||
{
|
||||
uint8_t *oos = os, *plen = NULL;
|
||||
|
||||
while (*comma && len > 1) {
|
||||
if (!plen && *comma == ' ') {
|
||||
comma++;
|
||||
continue;
|
||||
}
|
||||
if (!plen) {
|
||||
plen = os++;
|
||||
len--;
|
||||
}
|
||||
|
||||
if (*comma == ',') {
|
||||
*plen = lws_ptr_diff(os, plen + 1);
|
||||
plen = NULL;
|
||||
comma++;
|
||||
} else {
|
||||
*os++ = *comma++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
if (plen)
|
||||
*plen = lws_ptr_diff(os, plen + 1);
|
||||
|
||||
return lws_ptr_diff(os, oos);
|
||||
}
|
||||
|
||||
|
|
|
@ -153,24 +153,13 @@ lws_try_client_connection(struct lws_client_connect_info *i, int m)
|
|||
lwsl_user("started connection %d\n", m);
|
||||
}
|
||||
|
||||
static int commandline_option(int argc, char **argv, const char *val)
|
||||
{
|
||||
int n = strlen(val);
|
||||
|
||||
while (--argc > 0) {
|
||||
if (!strncmp(argv[argc], val, n))
|
||||
return argc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_client_connect_info i;
|
||||
struct lws_context *context;
|
||||
unsigned long long start, next;
|
||||
const char *p;
|
||||
int n = 0, m, staggered = 0, logs =
|
||||
LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
|
||||
/* for LLL_ verbosity above NOTICE to be built into lws,
|
||||
|
@ -184,14 +173,13 @@ int main(int argc, char **argv)
|
|||
|
||||
memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
|
||||
|
||||
staggered = !!commandline_option(argc, argv, "-s");
|
||||
m = commandline_option(argc, argv, "-d");
|
||||
if (m && m + 1 < argc)
|
||||
logs = atoi(argv[m + 1]);
|
||||
staggered = !!lws_cmdline_option(argc, argv, "-s");
|
||||
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
||||
logs = atoi(p);
|
||||
|
||||
lws_set_log_level(logs, NULL);
|
||||
lwsl_user("LWS minimal http client [-s (staggered)] [-p (pipeline)]\n");
|
||||
lwsl_user(" [--h1 (http/1 only)] [-l (localhost)]\n");
|
||||
lwsl_user(" [--h1 (http/1 only)] [-l (localhost)] [-d <logs>]\n");
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
|
@ -218,14 +206,14 @@ int main(int argc, char **argv)
|
|||
i.ssl_connection = LCCSCF_USE_SSL;
|
||||
|
||||
/* enables h1 or h2 connection sharing */
|
||||
if (commandline_option(argc, argv, "-p"))
|
||||
if (lws_cmdline_option(argc, argv, "-p"))
|
||||
i.ssl_connection |= LCCSCF_PIPELINE;
|
||||
|
||||
/* force h1 even if h2 available */
|
||||
if (commandline_option(argc, argv, "--h1"))
|
||||
i.ssl_connection |= LCCSCF_NOT_H2;
|
||||
if (lws_cmdline_option(argc, argv, "--h1"))
|
||||
i.alpn = "http/1.1";
|
||||
|
||||
if (commandline_option(argc, argv, "-l")) {
|
||||
if (lws_cmdline_option(argc, argv, "-l")) {
|
||||
i.port = 7681;
|
||||
i.address = "localhost";
|
||||
i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
|
||||
|
|
|
@ -69,24 +69,26 @@ sigint_handler(int sig)
|
|||
interrupted = 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_client_connect_info i;
|
||||
struct lws_context *context;
|
||||
int n = 0;
|
||||
const char *p;
|
||||
int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
|
||||
/* for LLL_ verbosity above NOTICE to be built into lws, lws
|
||||
* must have been configured with -DCMAKE_BUILD_TYPE=DEBUG
|
||||
* instead of =RELEASE */
|
||||
/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
|
||||
/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
|
||||
/* | LLL_DEBUG */;
|
||||
|
||||
signal(SIGINT, sigint_handler);
|
||||
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
||||
logs = atoi(p);
|
||||
|
||||
lws_set_log_level(LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
|
||||
/* for LLL_ verbosity above NOTICE to be built into lws,
|
||||
* lws must have been configured and built with
|
||||
* -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
|
||||
/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
|
||||
/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
|
||||
/* | LLL_DEBUG */, NULL);
|
||||
|
||||
lwsl_user("LWS minimal ws client rx\n");
|
||||
lws_set_log_level(logs, NULL);
|
||||
lwsl_user("LWS minimal ws client rx [-d <logs>] [--h2]\n");
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
|
@ -108,22 +110,25 @@ int main(int argc, char **argv)
|
|||
|
||||
memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
|
||||
i.context = context;
|
||||
|
||||
i.port = 443;
|
||||
i.address = "libwebsockets.org";
|
||||
i.path = "/";
|
||||
i.host = i.address;
|
||||
i.origin = i.address;
|
||||
i.ssl_connection = LCCSCF_USE_SSL;
|
||||
|
||||
i.protocol = protocols[0].name; /* "dumb-increment-protocol" */
|
||||
i.pwsi = &client_wsi;
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "--h2"))
|
||||
i.alpn = "h2";
|
||||
|
||||
lws_client_connect_via_info(&i);
|
||||
|
||||
while (n >= 0 && client_wsi && !interrupted)
|
||||
n = lws_service(context, 1000);
|
||||
|
||||
lws_context_destroy(context);
|
||||
|
||||
lwsl_user("Completed\n");
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue