2016-03-29 08:51:42 +08:00
|
|
|
/*
|
|
|
|
* libwebsockets - small server side websockets and web server implementation
|
|
|
|
*
|
2018-04-02 11:55:17 +08:00
|
|
|
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
|
2016-03-29 08:51:42 +08:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2018-05-03 10:49:36 +08:00
|
|
|
#include "core/private.h"
|
2016-03-29 08:51:42 +08:00
|
|
|
|
2018-04-12 15:56:38 +08:00
|
|
|
#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)
|
2018-05-01 12:41:42 +08:00
|
|
|
const char *alpn_comma = vhost->context->tls.alpn_default;
|
2018-04-12 15:56:38 +08:00
|
|
|
|
2018-05-01 12:41:42 +08:00
|
|
|
if (vhost->tls.alpn)
|
|
|
|
alpn_comma = vhost->tls.alpn;
|
2018-04-12 15:56:38 +08:00
|
|
|
|
|
|
|
lwsl_info(" Server '%s' advertising ALPN: %s\n",
|
|
|
|
vhost->name, alpn_comma);
|
2018-05-01 12:41:42 +08:00
|
|
|
vhost->tls.alpn_ctx.len = lws_alpn_comma_to_openssl(alpn_comma,
|
|
|
|
vhost->tls.alpn_ctx.data,
|
|
|
|
sizeof(vhost->tls.alpn_ctx.data) - 1);
|
2018-04-12 15:56:38 +08:00
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
SSL_CTX_set_alpn_select_cb(vhost->tls.ssl_ctx, alpn_cb,
|
|
|
|
&vhost->tls.alpn_ctx);
|
2018-04-12 15:56:38 +08:00
|
|
|
#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;
|
|
|
|
|
2019-03-22 05:30:22 +08:00
|
|
|
if (!wsi->tls.ssl)
|
|
|
|
return 0;
|
|
|
|
|
2018-05-01 12:41:42 +08:00
|
|
|
SSL_get0_alpn_selected(wsi->tls.ssl, &name, &len);
|
2018-04-12 15:56:38 +08:00
|
|
|
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);
|
2018-05-01 12:41:42 +08:00
|
|
|
wsi->tls.use_ssl |= LCCSCF_USE_SSL;
|
2018-04-12 15:56:38 +08:00
|
|
|
|
|
|
|
return lws_role_call_alpn_negotiated(wsi, (const char *)cstr);
|
|
|
|
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-05 05:04:17 +01:00
|
|
|
#if !defined(LWS_NO_SERVER)
|
2019-08-09 10:12:09 +01:00
|
|
|
|
|
|
|
static void
|
|
|
|
lws_sul_tls_cb(lws_sorted_usec_list_t *sul)
|
|
|
|
{
|
|
|
|
struct lws_context_per_thread *pt = lws_container_of(sul,
|
|
|
|
struct lws_context_per_thread, sul_tls);
|
|
|
|
|
|
|
|
lws_tls_check_all_cert_lifetimes(pt->context);
|
|
|
|
|
|
|
|
__lws_sul_insert(&pt->pt_sul_owner, &pt->sul_tls,
|
|
|
|
(lws_usec_t)24 * 3600 * LWS_US_PER_SEC);
|
|
|
|
}
|
|
|
|
|
2016-03-29 08:51:42 +08:00
|
|
|
LWS_VISIBLE int
|
2018-04-27 08:27:16 +08:00
|
|
|
lws_context_init_server_ssl(const struct lws_context_creation_info *info,
|
2016-03-29 08:51:42 +08:00
|
|
|
struct lws_vhost *vhost)
|
|
|
|
{
|
|
|
|
struct lws_context *context = vhost->context;
|
|
|
|
struct lws wsi;
|
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
if (!lws_check_opt(info->options,
|
|
|
|
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
|
2018-05-01 12:41:42 +08:00
|
|
|
vhost->tls.use_ssl = 0;
|
2017-10-18 09:41:44 +08:00
|
|
|
|
2016-03-29 08:51:42 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2017-09-06 10:15:10 +08:00
|
|
|
|
|
|
|
/*
|
2019-02-14 14:35:24 +08:00
|
|
|
* If he is giving a server cert, take it as a sign he wants to use
|
2017-09-06 10:15:10 +08:00
|
|
|
* it on this vhost. User code can leave the cert filepath NULL and
|
|
|
|
* set the LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX option itself, in
|
|
|
|
* which case he's expected to set up the cert himself at
|
|
|
|
* LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which
|
|
|
|
* provides the vhost SSL_CTX * in the user parameter.
|
|
|
|
*/
|
2019-02-14 14:35:24 +08:00
|
|
|
if (info->ssl_cert_filepath || info->server_ssl_cert_mem)
|
2018-04-27 08:27:16 +08:00
|
|
|
vhost->options |= LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX;
|
2017-09-06 10:15:10 +08:00
|
|
|
|
2016-03-29 08:51:42 +08:00
|
|
|
if (info->port != CONTEXT_PORT_NO_LISTEN) {
|
|
|
|
|
2018-05-01 12:41:42 +08:00
|
|
|
vhost->tls.use_ssl = lws_check_opt(vhost->options,
|
2017-09-06 10:15:10 +08:00
|
|
|
LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX);
|
2016-03-29 08:51:42 +08:00
|
|
|
|
2018-05-01 12:41:42 +08:00
|
|
|
if (vhost->tls.use_ssl && info->ssl_cipher_list)
|
2017-10-18 09:41:44 +08:00
|
|
|
lwsl_notice(" SSL ciphers: '%s'\n",
|
|
|
|
info->ssl_cipher_list);
|
2016-03-29 08:51:42 +08:00
|
|
|
|
2018-05-01 12:41:42 +08:00
|
|
|
if (vhost->tls.use_ssl)
|
2016-03-29 08:51:42 +08:00
|
|
|
lwsl_notice(" Using SSL mode\n");
|
|
|
|
else
|
|
|
|
lwsl_notice(" Using non-SSL mode\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* give him a fake wsi with context + vhost set, so he can use
|
|
|
|
* lws_get_context() in the callback
|
|
|
|
*/
|
|
|
|
memset(&wsi, 0, sizeof(wsi));
|
vhost_destroy: use vhost wsi reference counting to trigger destroy
This changes the vhost destroy flow to only hand off the listen
socket if another vhost sharing it, and mark the vhost as
being_destroyed.
Each tsi calls lws_check_deferred_free() once a second, if it sees
any vhost being_destroyed there, it closes all wsi on its tsi on
the same vhost, one time.
As the wsi on the vhost complete close (ie, after libuv async close
if on libuv event loop), they decrement a reference count for all
wsi open on the vhost. The tsi who closes the last one then
completes the destroy flow for the vhost itself... it's random
which tsi completes the vhost destroy but since there are no
wsi left on the vhost, and it holds the context lock, nothing
can conflict.
The advantage of this is that owning tsi do the close for wsi
that are bound to the vhost under destruction, at a time when
they are guaranteed to be idle for service, and they do it with
both vhost and context locks owned, so no other service thread
can conflict for stuff protected by those either.
For the situation the user code may have allocations attached to
the vhost, this adds args to lws_vhost_destroy() to allow destroying
the user allocations just before the vhost is freed.
2018-06-16 09:31:07 +08:00
|
|
|
wsi.vhost = vhost; /* not a real bound wsi */
|
2016-04-17 11:28:43 +08:00
|
|
|
wsi.context = context;
|
|
|
|
|
2016-03-29 08:51:42 +08:00
|
|
|
/*
|
2017-10-18 09:41:44 +08:00
|
|
|
* as a server, if we are requiring clients to identify themselves
|
|
|
|
* then set the backend up for it
|
2016-03-29 08:51:42 +08:00
|
|
|
*/
|
2016-04-17 11:28:43 +08:00
|
|
|
if (lws_check_opt(info->options,
|
2017-10-18 09:41:44 +08:00
|
|
|
LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT))
|
|
|
|
/* Normally SSL listener rejects non-ssl, optionally allow */
|
2018-05-01 12:41:42 +08:00
|
|
|
vhost->tls.allow_non_ssl_on_ssl_port = 1;
|
2016-03-29 08:51:42 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* give user code a chance to load certs into the server
|
|
|
|
* allowing it to verify incoming client certs
|
|
|
|
*/
|
2018-05-01 12:41:42 +08:00
|
|
|
if (vhost->tls.use_ssl) {
|
2017-10-18 09:41:44 +08:00
|
|
|
if (lws_tls_server_vhost_backend_init(info, vhost, &wsi))
|
2016-03-29 08:51:42 +08:00
|
|
|
return -1;
|
|
|
|
|
2017-11-06 06:28:55 +08:00
|
|
|
lws_tls_server_client_cert_verify_config(vhost);
|
2017-10-25 15:27:06 +02:00
|
|
|
|
2017-11-26 09:22:42 +08:00
|
|
|
if (vhost->protocols[0].callback(&wsi,
|
|
|
|
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
|
2018-05-01 12:41:42 +08:00
|
|
|
vhost->tls.ssl_ctx, vhost, 0))
|
2017-11-26 09:22:42 +08:00
|
|
|
return -1;
|
2016-03-29 08:51:42 +08:00
|
|
|
}
|
|
|
|
|
2018-05-01 12:41:42 +08:00
|
|
|
if (vhost->tls.use_ssl)
|
2018-04-12 15:56:38 +08:00
|
|
|
lws_context_init_alpn(vhost);
|
2016-03-29 08:51:42 +08:00
|
|
|
|
2019-08-09 10:12:09 +01:00
|
|
|
/* check certs once a day */
|
|
|
|
|
|
|
|
context->pt[0].sul_tls.cb = lws_sul_tls_cb;
|
|
|
|
__lws_sul_insert(&context->pt[0].pt_sul_owner, &context->pt[0].sul_tls,
|
|
|
|
(lws_usec_t)24 * 3600 * LWS_US_PER_SEC);
|
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2019-06-05 05:04:17 +01:00
|
|
|
#endif
|
2017-01-10 09:10:49 +08:00
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
LWS_VISIBLE int
|
|
|
|
lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
|
|
|
|
{
|
|
|
|
struct lws_context *context = wsi->context;
|
|
|
|
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
2018-11-23 08:47:56 +08:00
|
|
|
struct lws_vhost *vh;
|
2017-10-18 09:41:44 +08:00
|
|
|
char buf[256];
|
2018-11-23 08:47:56 +08:00
|
|
|
int n;
|
2016-06-10 08:37:26 +08:00
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
(void)buf;
|
2016-06-10 08:37:26 +08:00
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
if (!LWS_SSL_ENABLED(wsi->vhost))
|
|
|
|
return 0;
|
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
switch (lwsi_state(wsi)) {
|
|
|
|
case LRS_SSL_INIT:
|
|
|
|
|
2018-05-01 12:41:42 +08:00
|
|
|
if (wsi->tls.ssl)
|
2017-10-18 09:41:44 +08:00
|
|
|
lwsl_err("%s: leaking ssl\n", __func__);
|
|
|
|
if (accept_fd == LWS_SOCK_INVALID)
|
|
|
|
assert(0);
|
|
|
|
if (context->simultaneous_ssl_restriction &&
|
2017-10-28 07:42:44 +08:00
|
|
|
context->simultaneous_ssl >=
|
|
|
|
context->simultaneous_ssl_restriction) {
|
2017-10-18 09:41:44 +08:00
|
|
|
lwsl_notice("unable to deal with SSL connection\n");
|
2016-03-29 08:51:42 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2017-03-11 11:51:06 +08:00
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
if (lws_tls_server_new_nonblocking(wsi, accept_fd)) {
|
|
|
|
if (accept_fd != LWS_SOCK_INVALID)
|
|
|
|
compatible_close(accept_fd);
|
|
|
|
goto fail;
|
|
|
|
}
|
2017-03-11 11:51:06 +08:00
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
if (context->simultaneous_ssl_restriction &&
|
2017-10-28 07:42:44 +08:00
|
|
|
++context->simultaneous_ssl ==
|
|
|
|
context->simultaneous_ssl_restriction)
|
2017-10-18 09:41:44 +08:00
|
|
|
/* that was the last allowed SSL connection */
|
|
|
|
lws_gate_accepts(context, 0);
|
2017-11-26 09:22:42 +08:00
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
#if defined(LWS_WITH_STATS)
|
2018-05-02 18:35:58 +08:00
|
|
|
context->updated = 1;
|
2017-10-18 09:41:44 +08:00
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* we are not accepted yet, but we need to enter ourselves
|
|
|
|
* as a live connection. That way we can retry when more
|
|
|
|
* pieces come if we're not sorted yet
|
|
|
|
*/
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_SSL_ACK_PENDING);
|
2017-10-18 09:41:44 +08:00
|
|
|
|
2018-03-05 16:49:28 +08:00
|
|
|
lws_pt_lock(pt, __func__);
|
|
|
|
if (__insert_wsi_socket_into_fds(context, wsi)) {
|
2017-10-18 09:41:44 +08:00
|
|
|
lwsl_err("%s: failed to insert into fds\n", __func__);
|
|
|
|
goto fail;
|
2017-03-11 11:51:06 +08:00
|
|
|
}
|
2018-03-05 16:49:28 +08:00
|
|
|
lws_pt_unlock(pt);
|
2017-10-18 09:41:44 +08:00
|
|
|
|
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
|
|
|
|
context->timeout_secs);
|
|
|
|
|
|
|
|
lwsl_debug("inserted SSL accept into fds, trying SSL_accept\n");
|
|
|
|
|
|
|
|
/* fallthru */
|
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
case LRS_SSL_ACK_PENDING:
|
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
|
|
|
lwsl_err("%s: lws_change_pollfd failed\n", __func__);
|
|
|
|
goto fail;
|
2017-03-11 11:51:06 +08:00
|
|
|
}
|
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
lws_latency_pre(context, wsi);
|
2016-03-29 08:51:42 +08:00
|
|
|
|
2018-05-01 12:41:42 +08:00
|
|
|
if (wsi->vhost->tls.allow_non_ssl_on_ssl_port) {
|
2017-10-18 09:41:44 +08:00
|
|
|
|
|
|
|
n = recv(wsi->desc.sockfd, (char *)pt->serv_buf,
|
|
|
|
context->pt_serv_buf_size, MSG_PEEK);
|
2017-03-11 11:51:06 +08:00
|
|
|
|
2018-11-29 08:47:49 +08:00
|
|
|
/*
|
|
|
|
* We have LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT..
|
|
|
|
* this just means don't hang up on him because of no
|
|
|
|
* tls hello... what happens next is driven by
|
|
|
|
* additional option flags:
|
|
|
|
*
|
|
|
|
* none: fail the connection
|
|
|
|
*
|
|
|
|
* LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS:
|
|
|
|
* Destroy the TLS, issue a redirect using plaintext
|
|
|
|
* http (this may not be accepted by a client that
|
|
|
|
* has visited the site before and received an STS
|
|
|
|
* header).
|
|
|
|
*
|
|
|
|
* LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER:
|
|
|
|
* Destroy the TLS, continue and serve normally
|
|
|
|
* using http
|
|
|
|
*
|
|
|
|
* LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG:
|
|
|
|
* Destroy the TLS, apply whatever role and protocol
|
|
|
|
* were told in the vhost info struct
|
|
|
|
* .listen_accept_role / .listen_accept_protocol and
|
|
|
|
* continue with that
|
|
|
|
*/
|
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
if (n >= 1 && pt->serv_buf[0] >= ' ') {
|
|
|
|
/*
|
|
|
|
* TLS content-type for Handshake is 0x16, and
|
|
|
|
* for ChangeCipherSpec Record, it's 0x14
|
|
|
|
*
|
|
|
|
* A non-ssl session will start with the HTTP
|
|
|
|
* method in ASCII. If we see it's not a legit
|
|
|
|
* SSL handshake kill the SSL for this
|
|
|
|
* connection and try to handle as a HTTP
|
|
|
|
* connection upgrade directly.
|
|
|
|
*/
|
2018-05-01 12:41:42 +08:00
|
|
|
wsi->tls.use_ssl = 0;
|
2017-10-18 09:41:44 +08:00
|
|
|
|
|
|
|
lws_tls_server_abort_connection(wsi);
|
2018-02-27 07:48:25 +08:00
|
|
|
/*
|
2018-11-29 08:47:49 +08:00
|
|
|
* care... this creates wsi with no ssl when ssl
|
|
|
|
* is enabled and normally mandatory
|
2018-02-27 07:48:25 +08:00
|
|
|
*/
|
2018-05-01 12:41:42 +08:00
|
|
|
wsi->tls.ssl = NULL;
|
2018-11-29 08:47:49 +08:00
|
|
|
|
2018-11-29 08:29:48 +08:00
|
|
|
if (lws_check_opt(wsi->vhost->options,
|
2018-11-29 08:47:49 +08:00
|
|
|
LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS)) {
|
|
|
|
lwsl_info("%s: redirecting from http "
|
|
|
|
"to https\n", __func__);
|
2018-05-01 12:41:42 +08:00
|
|
|
wsi->tls.redirect_to_https = 1;
|
2018-11-29 08:47:49 +08:00
|
|
|
goto notls_accepted;
|
|
|
|
}
|
|
|
|
|
2018-11-29 08:29:48 +08:00
|
|
|
if (lws_check_opt(wsi->vhost->options,
|
2018-11-29 08:47:49 +08:00
|
|
|
LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER)) {
|
|
|
|
lwsl_info("%s: allowing unencrypted "
|
|
|
|
"http service on tls port\n",
|
|
|
|
__func__);
|
|
|
|
goto notls_accepted;
|
|
|
|
}
|
|
|
|
|
2018-11-29 08:29:48 +08:00
|
|
|
if (lws_check_opt(wsi->vhost->options,
|
2018-11-29 08:47:49 +08:00
|
|
|
LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG)) {
|
|
|
|
if (lws_http_to_fallback(wsi, NULL, 0))
|
|
|
|
goto fail;
|
|
|
|
lwsl_info("%s: allowing non-tls "
|
|
|
|
"fallback\n", __func__);
|
|
|
|
goto notls_accepted;
|
|
|
|
}
|
|
|
|
|
|
|
|
lwsl_notice("%s: client did not send a valid "
|
2018-11-29 08:29:48 +08:00
|
|
|
"tls hello (default vhost %s)\n",
|
|
|
|
__func__, wsi->vhost->name);
|
2018-11-29 08:47:49 +08:00
|
|
|
goto fail;
|
2017-10-18 09:41:44 +08:00
|
|
|
}
|
2018-03-13 21:25:54 +08:00
|
|
|
if (!n) {
|
|
|
|
/*
|
|
|
|
* connection is gone, fail out
|
2017-10-18 09:41:44 +08:00
|
|
|
*/
|
2018-03-13 21:25:54 +08:00
|
|
|
lwsl_debug("PEEKed 0\n");
|
|
|
|
goto fail;
|
|
|
|
}
|
2017-10-18 09:41:44 +08:00
|
|
|
if (n < 0 && (LWS_ERRNO == LWS_EAGAIN ||
|
|
|
|
LWS_ERRNO == LWS_EWOULDBLOCK)) {
|
|
|
|
/*
|
|
|
|
* well, we get no way to know ssl or not
|
|
|
|
* so go around again waiting for something
|
|
|
|
* to come and give us a hint, or timeout the
|
|
|
|
* connection.
|
|
|
|
*/
|
|
|
|
if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
|
2017-10-28 07:42:44 +08:00
|
|
|
lwsl_info("%s: change_pollfd failed\n",
|
2017-10-18 09:41:44 +08:00
|
|
|
__func__);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
lwsl_info("SSL_ERROR_WANT_READ\n");
|
|
|
|
return 0;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
2017-03-11 11:51:06 +08:00
|
|
|
}
|
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
/* normal SSL connection processing path */
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_STATS)
|
2018-08-25 06:38:28 +08:00
|
|
|
/* only set this the first time around */
|
2017-10-18 09:41:44 +08:00
|
|
|
if (!wsi->accept_start_us)
|
2019-08-10 07:32:32 +01:00
|
|
|
wsi->accept_start_us = lws_now_usecs();
|
2017-03-11 11:51:06 +08:00
|
|
|
#endif
|
2017-10-18 09:41:44 +08:00
|
|
|
errno = 0;
|
2019-08-10 07:32:32 +01:00
|
|
|
lws_stats_bump(pt, LWSSTATS_C_SSL_ACCEPT_SPIN, 1);
|
2017-10-18 09:41:44 +08:00
|
|
|
n = lws_tls_server_accept(wsi);
|
|
|
|
lws_latency(context, wsi,
|
2018-04-02 11:55:17 +08:00
|
|
|
"SSL_accept LRS_SSL_ACK_PENDING\n", n, n == 1);
|
2017-10-18 09:41:44 +08:00
|
|
|
lwsl_info("SSL_accept says %d\n", n);
|
|
|
|
switch (n) {
|
|
|
|
case LWS_SSL_CAPABLE_DONE:
|
|
|
|
break;
|
|
|
|
case LWS_SSL_CAPABLE_ERROR:
|
2019-08-10 07:32:32 +01:00
|
|
|
lws_stats_bump(pt, LWSSTATS_C_SSL_CONNECTIONS_FAILED, 1);
|
2017-10-18 09:41:44 +08:00
|
|
|
lwsl_info("SSL_accept failed socket %u: %d\n",
|
|
|
|
wsi->desc.sockfd, n);
|
2018-02-06 07:58:13 +08:00
|
|
|
wsi->socket_is_permanently_unusable = 1;
|
2017-10-18 09:41:44 +08:00
|
|
|
goto fail;
|
|
|
|
|
|
|
|
default: /* MORE_SERVICE */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-08-10 07:32:32 +01:00
|
|
|
lws_stats_bump(pt, LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED, 1);
|
2017-10-18 09:41:44 +08:00
|
|
|
#if defined(LWS_WITH_STATS)
|
2018-08-25 06:38:28 +08:00
|
|
|
if (wsi->accept_start_us)
|
2019-08-10 07:32:32 +01:00
|
|
|
lws_stats_bump(pt,
|
|
|
|
LWSSTATS_US_SSL_ACCEPT_LATENCY_AVG,
|
|
|
|
lws_now_usecs() -
|
2018-11-23 08:47:56 +08:00
|
|
|
wsi->accept_start_us);
|
2019-08-10 07:32:32 +01:00
|
|
|
wsi->accept_start_us = lws_now_usecs();
|
2017-03-11 11:51:06 +08:00
|
|
|
#endif
|
2016-03-29 08:51:42 +08:00
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
/* adapt our vhost to match the SNI SSL_CTX that was chosen */
|
|
|
|
vh = context->vhost_list;
|
|
|
|
while (vh) {
|
2018-05-01 12:41:42 +08:00
|
|
|
if (!vh->being_destroyed && wsi->tls.ssl &&
|
|
|
|
vh->tls.ssl_ctx == lws_tls_ctx_from_wsi(wsi)) {
|
2017-10-18 09:41:44 +08:00
|
|
|
lwsl_info("setting wsi to vh %s\n", vh->name);
|
vhost_destroy: use vhost wsi reference counting to trigger destroy
This changes the vhost destroy flow to only hand off the listen
socket if another vhost sharing it, and mark the vhost as
being_destroyed.
Each tsi calls lws_check_deferred_free() once a second, if it sees
any vhost being_destroyed there, it closes all wsi on its tsi on
the same vhost, one time.
As the wsi on the vhost complete close (ie, after libuv async close
if on libuv event loop), they decrement a reference count for all
wsi open on the vhost. The tsi who closes the last one then
completes the destroy flow for the vhost itself... it's random
which tsi completes the vhost destroy but since there are no
wsi left on the vhost, and it holds the context lock, nothing
can conflict.
The advantage of this is that owning tsi do the close for wsi
that are bound to the vhost under destruction, at a time when
they are guaranteed to be idle for service, and they do it with
both vhost and context locks owned, so no other service thread
can conflict for stuff protected by those either.
For the situation the user code may have allocations attached to
the vhost, this adds args to lws_vhost_destroy() to allow destroying
the user allocations just before the vhost is freed.
2018-06-16 09:31:07 +08:00
|
|
|
lws_vhost_bind_wsi(vh, wsi);
|
2017-10-18 09:41:44 +08:00
|
|
|
break;
|
2016-03-29 08:51:42 +08:00
|
|
|
}
|
2017-10-18 09:41:44 +08:00
|
|
|
vh = vh->vhost_next;
|
2016-03-29 08:51:42 +08:00
|
|
|
}
|
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
/* OK, we are accepted... give him some time to negotiate */
|
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
|
|
|
|
context->timeout_secs);
|
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
2018-04-12 15:56:38 +08:00
|
|
|
if (lws_tls_server_conn_alpn(wsi))
|
2017-10-18 09:41:44 +08:00
|
|
|
goto fail;
|
|
|
|
lwsl_debug("accepted new SSL conn\n");
|
|
|
|
break;
|
2018-04-02 11:55:17 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2016-03-29 08:51:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2017-10-18 09:41:44 +08:00
|
|
|
|
2018-11-29 08:47:49 +08:00
|
|
|
notls_accepted:
|
|
|
|
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
2018-11-29 08:29:48 +08:00
|
|
|
|
2018-11-29 08:47:49 +08:00
|
|
|
return 0;
|
|
|
|
|
2017-10-18 09:41:44 +08:00
|
|
|
fail:
|
|
|
|
return 1;
|
2016-03-29 08:51:42 +08:00
|
|
|
}
|
|
|
|
|