2019-01-13 06:58:21 +08:00
|
|
|
/*
|
|
|
|
* libwebsockets - small server side websockets and web server implementation
|
|
|
|
*
|
2021-01-06 15:08:22 +00:00
|
|
|
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
2019-01-13 06:58:21 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* 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:
|
2019-01-13 06:58:21 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
2019-01-13 06:58:21 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* 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.
|
2019-01-13 06:58:21 +08:00
|
|
|
*/
|
|
|
|
|
2019-08-15 10:49:52 +01:00
|
|
|
#include "private-lib-core.h"
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2021-03-25 08:37:36 +00:00
|
|
|
void
|
|
|
|
lws_tls_session_vh_destroy(struct lws_vhost *vh);
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
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
|
|
|
|
#if defined(LWS_ROLE_DBUS)
|
|
|
|
&role_ops_dbus,
|
|
|
|
#endif
|
|
|
|
#if defined(LWS_ROLE_RAW_PROXY)
|
|
|
|
&role_ops_raw_proxy,
|
2020-02-25 13:28:25 +00:00
|
|
|
#endif
|
|
|
|
#if defined(LWS_ROLE_MQTT) && defined(LWS_WITH_CLIENT)
|
|
|
|
&role_ops_mqtt,
|
2020-10-04 07:28:41 +01:00
|
|
|
#endif
|
|
|
|
#if defined(LWS_WITH_NETLINK)
|
|
|
|
&role_ops_netlink,
|
2019-01-13 06:58:21 +08:00
|
|
|
#endif
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2019-06-22 06:59:49 +01:00
|
|
|
#if defined(LWS_WITH_ABSTRACT)
|
2019-04-21 19:57:19 +01:00
|
|
|
const struct lws_protocols *available_abstract_protocols[] = {
|
|
|
|
#if defined(LWS_ROLE_RAW)
|
|
|
|
&protocol_abs_client_raw_skt,
|
|
|
|
#endif
|
|
|
|
NULL
|
|
|
|
};
|
2019-06-22 06:59:49 +01:00
|
|
|
#endif
|
2019-04-21 19:57:19 +01:00
|
|
|
|
2020-02-29 12:37:24 +00:00
|
|
|
#if defined(LWS_WITH_SECURE_STREAMS)
|
|
|
|
const struct lws_protocols *available_secstream_protocols[] = {
|
|
|
|
#if defined(LWS_ROLE_H1)
|
|
|
|
&protocol_secstream_h1,
|
|
|
|
#endif
|
|
|
|
#if defined(LWS_ROLE_H2)
|
|
|
|
&protocol_secstream_h2,
|
|
|
|
#endif
|
|
|
|
#if defined(LWS_ROLE_WS)
|
|
|
|
&protocol_secstream_ws,
|
|
|
|
#endif
|
|
|
|
#if defined(LWS_ROLE_MQTT)
|
|
|
|
&protocol_secstream_mqtt,
|
|
|
|
#endif
|
2020-03-28 16:20:50 +00:00
|
|
|
&protocol_secstream_raw,
|
2020-02-29 12:37:24 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
static const char * const mount_protocols[] = {
|
|
|
|
"http://",
|
|
|
|
"https://",
|
|
|
|
"file://",
|
|
|
|
"cgi://",
|
|
|
|
">http://",
|
|
|
|
">https://",
|
|
|
|
"callback://"
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct lws_role_ops *
|
|
|
|
lws_role_by_name(const char *name)
|
|
|
|
{
|
|
|
|
LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
|
|
|
|
if (!strcmp(ar->name, name))
|
|
|
|
return ar;
|
|
|
|
LWS_FOR_EVERY_AVAILABLE_ROLE_END;
|
|
|
|
|
|
|
|
if (!strcmp(name, role_ops_raw_skt.name))
|
|
|
|
return &role_ops_raw_skt;
|
|
|
|
|
2020-02-28 15:50:15 +00:00
|
|
|
#if defined(LWS_ROLE_RAW_FILE)
|
2019-01-13 06:58:21 +08:00
|
|
|
if (!strcmp(name, role_ops_raw_file.name))
|
|
|
|
return &role_ops_raw_file;
|
2020-02-28 15:50:15 +00:00
|
|
|
#endif
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_role_call_alpn_negotiated(struct lws *wsi, const char *alpn)
|
|
|
|
{
|
|
|
|
#if defined(LWS_WITH_TLS)
|
|
|
|
if (!alpn)
|
|
|
|
return 0;
|
|
|
|
|
2020-06-22 20:05:06 +01:00
|
|
|
#if !defined(LWS_ESP_PLATFORM)
|
2019-01-13 06:58:21 +08:00
|
|
|
lwsl_info("%s: '%s'\n", __func__, alpn);
|
2020-06-22 20:05:06 +01:00
|
|
|
#endif
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
if (ar->alpn && !strcmp(ar->alpn, alpn) &&
|
2021-01-06 15:08:22 +00:00
|
|
|
lws_rops_fidx(ar, LWS_ROPS_alpn_negotiated)) {
|
|
|
|
#if defined(LWS_WITH_SERVER)
|
|
|
|
lws_metrics_tag_wsi_add(wsi, "upg", ar->name);
|
|
|
|
#endif
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
return (lws_rops_func_fidx(ar, LWS_ROPS_alpn_negotiated)).
|
|
|
|
alpn_negotiated(wsi, alpn);
|
2021-01-06 15:08:22 +00:00
|
|
|
}
|
2019-01-13 06:58:21 +08:00
|
|
|
LWS_FOR_EVERY_AVAILABLE_ROLE_END;
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_role_call_adoption_bind(struct lws *wsi, int type, const char *prot)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if the vhost is told to bind accepted sockets to a given role,
|
|
|
|
* then look it up by name and try to bind to the specific role.
|
|
|
|
*/
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (lws_check_opt(wsi->a.vhost->options,
|
2019-01-13 06:58:21 +08:00
|
|
|
LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG) &&
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.vhost->listen_accept_role) {
|
2019-01-13 06:58:21 +08:00
|
|
|
const struct lws_role_ops *role =
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
lws_role_by_name(wsi->a.vhost->listen_accept_role);
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
if (!prot)
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
prot = wsi->a.vhost->listen_accept_protocol;
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
if (!role)
|
|
|
|
lwsl_err("%s: can't find role '%s'\n", __func__,
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.vhost->listen_accept_role);
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2021-07-06 20:22:18 +01:00
|
|
|
if (!strcmp(wsi->a.vhost->listen_accept_role, "raw-proxy"))
|
|
|
|
type |= LWS_ADOPT_FLAG_RAW_PROXY;
|
|
|
|
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
if (role && lws_rops_fidx(role, LWS_ROPS_adoption_bind)) {
|
|
|
|
n = (lws_rops_func_fidx(role, LWS_ROPS_adoption_bind)).
|
|
|
|
adoption_bind(wsi, type, prot);
|
2019-01-13 06:58:21 +08:00
|
|
|
if (n < 0)
|
|
|
|
return -1;
|
|
|
|
if (n) /* did the bind */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type & _LWS_ADOPT_FINISH) {
|
|
|
|
lwsl_debug("%s: leaving bound to role %s\n", __func__,
|
|
|
|
wsi->role_ops->name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
lwsl_warn("%s: adoption bind to role '%s', "
|
|
|
|
"protocol '%s', type 0x%x, failed\n", __func__,
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.vhost->listen_accept_role, prot, type);
|
2019-01-13 06:58:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise ask each of the roles in order of preference if they
|
|
|
|
* want to bind to this accepted socket
|
|
|
|
*/
|
|
|
|
|
|
|
|
LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
if (lws_rops_fidx(ar, LWS_ROPS_adoption_bind) &&
|
|
|
|
(lws_rops_func_fidx(ar, LWS_ROPS_adoption_bind)).
|
|
|
|
adoption_bind(wsi, type, prot))
|
2019-01-13 06:58:21 +08:00
|
|
|
return 0;
|
|
|
|
LWS_FOR_EVERY_AVAILABLE_ROLE_END;
|
|
|
|
|
|
|
|
/* fall back to raw socket role if, eg, h1 not configured */
|
|
|
|
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
if (lws_rops_fidx(&role_ops_raw_skt, LWS_ROPS_adoption_bind) &&
|
|
|
|
(lws_rops_func_fidx(&role_ops_raw_skt, LWS_ROPS_adoption_bind)).
|
|
|
|
adoption_bind(wsi, type, prot))
|
2019-01-13 06:58:21 +08:00
|
|
|
return 0;
|
|
|
|
|
2020-02-28 15:50:15 +00:00
|
|
|
#if defined(LWS_ROLE_RAW_FILE)
|
|
|
|
|
2020-09-20 09:14:46 +01:00
|
|
|
lwsl_notice("%s: falling back to raw file role bind\n", __func__);
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
/* fall back to raw file role if, eg, h1 not configured */
|
|
|
|
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
if (lws_rops_fidx(&role_ops_raw_file, LWS_ROPS_adoption_bind) &&
|
|
|
|
(lws_rops_func_fidx(&role_ops_raw_file, LWS_ROPS_adoption_bind)).
|
|
|
|
adoption_bind(wsi, type, prot))
|
2019-01-13 06:58:21 +08:00
|
|
|
return 0;
|
2020-02-28 15:50:15 +00:00
|
|
|
#endif
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2019-01-13 06:58:21 +08:00
|
|
|
int
|
|
|
|
lws_role_call_client_bind(struct lws *wsi,
|
|
|
|
const struct lws_client_connect_info *i)
|
|
|
|
{
|
|
|
|
LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
if (lws_rops_fidx(ar, LWS_ROPS_client_bind)) {
|
|
|
|
int m = (lws_rops_func_fidx(ar, LWS_ROPS_client_bind)).
|
|
|
|
client_bind(wsi, i);
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
if (m < 0)
|
|
|
|
return m;
|
|
|
|
if (m)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
LWS_FOR_EVERY_AVAILABLE_ROLE_END;
|
|
|
|
|
|
|
|
/* fall back to raw socket role if, eg, h1 not configured */
|
|
|
|
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
if (lws_rops_fidx(&role_ops_raw_skt, LWS_ROPS_client_bind) &&
|
|
|
|
(lws_rops_func_fidx(&role_ops_raw_skt, LWS_ROPS_client_bind)).
|
|
|
|
client_bind(wsi, i))
|
2019-01-13 06:58:21 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
void *
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost,
|
|
|
|
const struct lws_protocols *prot, int size)
|
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
|
2021-01-25 11:40:54 +00:00
|
|
|
if (!vhost || !prot)
|
|
|
|
return NULL;
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
/* allocate the vh priv array only on demand */
|
|
|
|
if (!vhost->protocol_vh_privs) {
|
|
|
|
vhost->protocol_vh_privs = (void **)lws_zalloc(
|
2020-12-12 06:21:40 +00:00
|
|
|
(size_t)vhost->count_protocols * sizeof(void *),
|
2019-01-13 06:58:21 +08:00
|
|
|
"protocol_vh_privs");
|
|
|
|
if (!vhost->protocol_vh_privs)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
|
|
|
|
n++;
|
|
|
|
|
|
|
|
if (n == vhost->count_protocols) {
|
|
|
|
n = 0;
|
|
|
|
while (n < vhost->count_protocols &&
|
|
|
|
strcmp(vhost->protocols[n].name, prot->name))
|
|
|
|
n++;
|
|
|
|
|
|
|
|
if (n == vhost->count_protocols)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
vhost->protocol_vh_privs[n] = lws_zalloc((size_t)size, "vh priv");
|
2019-01-13 06:58:21 +08:00
|
|
|
return vhost->protocol_vh_privs[n];
|
|
|
|
}
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
void *
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_protocol_vh_priv_get(struct lws_vhost *vhost,
|
|
|
|
const struct lws_protocols *prot)
|
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
if (!vhost || !vhost->protocol_vh_privs || !prot)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
|
|
|
|
n++;
|
|
|
|
|
|
|
|
if (n == vhost->count_protocols) {
|
|
|
|
n = 0;
|
|
|
|
while (n < vhost->count_protocols &&
|
|
|
|
strcmp(vhost->protocols[n].name, prot->name))
|
|
|
|
n++;
|
|
|
|
|
|
|
|
if (n == vhost->count_protocols) {
|
|
|
|
lwsl_err("%s: unknown protocol %p\n", __func__, prot);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return vhost->protocol_vh_privs[n];
|
|
|
|
}
|
|
|
|
|
2021-01-30 20:57:38 +00:00
|
|
|
void *
|
|
|
|
lws_vhd_find_by_pvo(struct lws_context *cx, const char *protname,
|
|
|
|
const char *pvo_name, const char *pvo_value)
|
|
|
|
{
|
|
|
|
struct lws_vhost *vh;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
/* let's go through all the vhosts */
|
|
|
|
|
|
|
|
vh = cx->vhost_list;
|
|
|
|
while (vh) {
|
|
|
|
|
2021-01-06 15:08:22 +00:00
|
|
|
if (vh->protocol_vh_privs) {
|
|
|
|
|
2021-01-30 20:57:38 +00:00
|
|
|
for (n = 0; n < vh->count_protocols; n++) {
|
|
|
|
const struct lws_protocol_vhost_options *pv;
|
|
|
|
|
|
|
|
if (strcmp(vh->protocols[n].name, protname))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* this vh has an instance of the required protocol */
|
|
|
|
|
2021-01-06 15:08:22 +00:00
|
|
|
pv = lws_pvo_search(vh->pvo, protname);
|
|
|
|
if (!pv)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pv = lws_pvo_search(pv->options, pvo_name);
|
2021-01-30 20:57:38 +00:00
|
|
|
if (!pv)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* ... he also has a pvo of the right name... */
|
|
|
|
if (!strcmp(pv->value, pvo_value))
|
|
|
|
/*
|
|
|
|
* ... yes, the pvo has the right value too,
|
|
|
|
* return a pointer to this vhost-protocol
|
|
|
|
* private alloc (ie, its "vhd")
|
|
|
|
*/
|
|
|
|
return vh->protocol_vh_privs[n];
|
|
|
|
}
|
2021-01-06 15:08:22 +00:00
|
|
|
} else
|
|
|
|
lwsl_notice("%s: no privs yet on %s\n", __func__, lws_vh_tag(vh));
|
2021-01-30 20:57:38 +00:00
|
|
|
vh = vh->vhost_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
const struct lws_protocol_vhost_options *
|
|
|
|
lws_vhost_protocol_options(struct lws_vhost *vh, const char *name)
|
|
|
|
{
|
|
|
|
const struct lws_protocol_vhost_options *pvo = vh->pvo;
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
while (pvo) {
|
|
|
|
if (!strcmp(pvo->name, name))
|
|
|
|
return pvo;
|
|
|
|
pvo = pvo->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-09-19 09:48:17 +01:00
|
|
|
int
|
|
|
|
lws_protocol_init_vhost(struct lws_vhost *vh, int *any)
|
|
|
|
{
|
|
|
|
const struct lws_protocol_vhost_options *pvo, *pvo1;
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
lws_fakewsi_def_plwsa(&vh->context->pt[0]);
|
2019-09-19 09:48:17 +01:00
|
|
|
int n;
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
lws_fakewsi_prep_plwsa_ctx(vh->context);
|
|
|
|
|
|
|
|
plwsa->vhost = vh;
|
2019-09-19 09:48:17 +01:00
|
|
|
|
|
|
|
/* initialize supported protocols on this vhost */
|
|
|
|
|
|
|
|
for (n = 0; n < vh->count_protocols; n++) {
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
plwsa->protocol = &vh->protocols[n];
|
2019-09-19 09:48:17 +01:00
|
|
|
if (!vh->protocols[n].name)
|
|
|
|
continue;
|
|
|
|
pvo = lws_vhost_protocol_options(vh, vh->protocols[n].name);
|
|
|
|
if (pvo) {
|
|
|
|
/*
|
|
|
|
* linked list of options specific to
|
|
|
|
* vh + protocol
|
|
|
|
*/
|
|
|
|
pvo1 = pvo;
|
|
|
|
pvo = pvo1->options;
|
|
|
|
|
|
|
|
while (pvo) {
|
|
|
|
lwsl_debug(
|
|
|
|
" vhost \"%s\", "
|
|
|
|
"protocol \"%s\", "
|
|
|
|
"option \"%s\"\n",
|
|
|
|
vh->name,
|
|
|
|
vh->protocols[n].name,
|
|
|
|
pvo->name);
|
|
|
|
|
|
|
|
if (!strcmp(pvo->name, "default")) {
|
|
|
|
lwsl_info("Setting default "
|
|
|
|
"protocol for vh %s to %s\n",
|
|
|
|
vh->name,
|
|
|
|
vh->protocols[n].name);
|
2020-12-12 06:21:40 +00:00
|
|
|
vh->default_protocol_index = (unsigned char)n;
|
2019-09-19 09:48:17 +01:00
|
|
|
}
|
|
|
|
if (!strcmp(pvo->name, "raw")) {
|
|
|
|
lwsl_info("Setting raw "
|
|
|
|
"protocol for vh %s to %s\n",
|
|
|
|
vh->name,
|
|
|
|
vh->protocols[n].name);
|
2020-12-12 06:21:40 +00:00
|
|
|
vh->raw_protocol_index = (unsigned char)n;
|
2019-09-19 09:48:17 +01:00
|
|
|
}
|
|
|
|
pvo = pvo->next;
|
|
|
|
}
|
2021-02-16 20:44:20 +00:00
|
|
|
} else
|
|
|
|
lwsl_debug("%s: not instantiating %s.%s\n",
|
|
|
|
__func__, vh->name, vh->protocols[n].name);
|
2019-09-19 09:48:17 +01:00
|
|
|
|
|
|
|
#if defined(LWS_WITH_TLS)
|
|
|
|
if (any)
|
|
|
|
*any |= !!vh->tls.ssl_ctx;
|
|
|
|
#endif
|
|
|
|
|
2021-02-16 20:44:20 +00:00
|
|
|
plwsa->vhost = vh;
|
|
|
|
plwsa->protocol = &vh->protocols[n];
|
|
|
|
|
|
|
|
pvo = lws_vhost_protocol_options(vh, vh->protocols[n].name);
|
|
|
|
|
2019-09-19 09:48:17 +01:00
|
|
|
/*
|
|
|
|
* inform all the protocols that they are doing their
|
|
|
|
* one-time initialization if they want to.
|
|
|
|
*
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
* NOTE the fakewsi is garbage, except the key pointers that are
|
|
|
|
* prepared in case the protocol handler wants to touch them
|
2019-09-19 09:48:17 +01:00
|
|
|
*/
|
2021-02-16 20:44:20 +00:00
|
|
|
|
|
|
|
if (pvo || !vh->pvo) {
|
|
|
|
lwsl_info("%s: init %s.%s\n", __func__, vh->name,
|
|
|
|
vh->protocols[n].name);
|
|
|
|
if (vh->protocols[n].callback((struct lws *)plwsa,
|
2019-09-19 09:48:17 +01:00
|
|
|
LWS_CALLBACK_PROTOCOL_INIT, NULL,
|
2021-02-16 20:44:20 +00:00
|
|
|
(void *)(pvo ? pvo->options : NULL), 0)) {
|
|
|
|
if (vh->protocol_vh_privs && vh->protocol_vh_privs[n]) {
|
|
|
|
lws_free(vh->protocol_vh_privs[n]);
|
|
|
|
vh->protocol_vh_privs[n] = NULL;
|
|
|
|
}
|
2019-09-19 09:48:17 +01:00
|
|
|
lwsl_err("%s: protocol %s failed init\n",
|
|
|
|
__func__, vh->protocols[n].name);
|
|
|
|
|
2021-02-16 20:44:20 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2019-09-19 09:48:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vh->created_vhost_protocols = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
/*
|
|
|
|
* inform every vhost that hasn't already done it, that
|
|
|
|
* his protocols are initializing
|
|
|
|
*/
|
2020-01-02 08:32:23 +00:00
|
|
|
int
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_protocol_init(struct lws_context *context)
|
|
|
|
{
|
|
|
|
struct lws_vhost *vh = context->vhost_list;
|
2021-01-25 11:40:54 +00:00
|
|
|
int any = 0, r = 0;
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
if (context->doing_protocol_init)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
context->doing_protocol_init = 1;
|
|
|
|
|
2021-01-06 15:08:22 +00:00
|
|
|
lwsl_info("%s\n", __func__);
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
while (vh) {
|
|
|
|
|
|
|
|
/* only do the protocol init once for a given vhost */
|
|
|
|
if (vh->created_vhost_protocols ||
|
2019-09-13 13:12:55 +01:00
|
|
|
(lws_check_opt(vh->options, LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT)))
|
2019-01-13 06:58:21 +08:00
|
|
|
goto next;
|
|
|
|
|
2021-01-25 11:40:54 +00:00
|
|
|
if (lws_protocol_init_vhost(vh, &any)) {
|
|
|
|
lwsl_warn("%s: init vhost %s failed\n", __func__, vh->name);
|
|
|
|
r = -1;
|
|
|
|
}
|
2019-01-13 06:58:21 +08:00
|
|
|
next:
|
|
|
|
vh = vh->vhost_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
context->doing_protocol_init = 0;
|
|
|
|
|
2021-01-25 11:40:54 +00:00
|
|
|
if (r)
|
|
|
|
lwsl_warn("%s: some protocols did not init\n", __func__);
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2021-01-25 11:40:54 +00:00
|
|
|
if (!context->protocol_init_done) {
|
|
|
|
|
|
|
|
context->protocol_init_done = 1;
|
|
|
|
lws_finalize_startup(context);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
2020-08-20 06:10:13 +01:00
|
|
|
if (any) {
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_tls_check_all_cert_lifetimes(context);
|
2020-08-20 06:10:13 +01:00
|
|
|
}
|
2019-08-18 10:35:43 +01:00
|
|
|
#endif
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* list of supported protocols and callbacks */
|
|
|
|
|
|
|
|
static const struct lws_protocols protocols_dummy[] = {
|
|
|
|
/* first protocol must always be HTTP handler */
|
|
|
|
|
|
|
|
{
|
|
|
|
"http-only", /* name */
|
|
|
|
lws_callback_http_dummy, /* callback */
|
|
|
|
0, /* per_session_data_size */
|
|
|
|
0, /* rx_buffer_size */
|
|
|
|
0, /* id */
|
|
|
|
NULL, /* user */
|
|
|
|
0 /* tx_packet_size */
|
|
|
|
},
|
|
|
|
/*
|
|
|
|
* the other protocols are provided by lws plugins
|
|
|
|
*/
|
|
|
|
{ NULL, NULL, 0, 0, 0, NULL, 0} /* terminator */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef LWS_PLAT_OPTEE
|
|
|
|
#undef LWS_HAVE_GETENV
|
|
|
|
#endif
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
struct lws_vhost *
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_create_vhost(struct lws_context *context,
|
|
|
|
const struct lws_context_creation_info *info)
|
|
|
|
{
|
2020-08-27 15:37:14 +01:00
|
|
|
struct lws_vhost *vh, **vh1 = &context->vhost_list;
|
2019-01-13 06:58:21 +08:00
|
|
|
const struct lws_http_mount *mounts;
|
|
|
|
const struct lws_protocols *pcols = info->protocols;
|
|
|
|
#ifdef LWS_WITH_PLUGINS
|
|
|
|
struct lws_plugin *plugin = context->plugin_list;
|
|
|
|
#endif
|
|
|
|
struct lws_protocols *lwsp;
|
2020-02-29 12:37:24 +00:00
|
|
|
int m, f = !info->pvo, fx = 0, abs_pcol_count = 0, sec_pcol_count = 0;
|
2019-07-13 11:51:45 -07:00
|
|
|
char buf[96];
|
2019-01-13 06:58:21 +08:00
|
|
|
char *p;
|
2019-09-19 06:54:53 +01:00
|
|
|
#if defined(LWS_WITH_SYS_ASYNC_DNS)
|
|
|
|
extern struct lws_protocols lws_async_dns_protocol;
|
2019-01-13 06:58:21 +08:00
|
|
|
#endif
|
|
|
|
int n;
|
|
|
|
|
2021-03-16 13:32:05 +00:00
|
|
|
if (lws_fi(&info->fic, "vh_create_oom"))
|
|
|
|
vh = NULL;
|
|
|
|
else
|
|
|
|
vh = lws_zalloc(sizeof(*vh)
|
2020-08-27 15:37:14 +01:00
|
|
|
#if defined(LWS_WITH_EVENT_LIBS)
|
|
|
|
+ context->event_loop_ops->evlib_size_vh
|
|
|
|
#endif
|
|
|
|
, __func__);
|
2019-01-13 06:58:21 +08:00
|
|
|
if (!vh)
|
2021-03-16 13:32:05 +00:00
|
|
|
goto early_bail;
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2020-08-27 15:37:14 +01:00
|
|
|
#if defined(LWS_WITH_EVENT_LIBS)
|
|
|
|
vh->evlib_vh = (void *)&vh[1];
|
|
|
|
#endif
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
#if LWS_MAX_SMP > 1
|
2021-04-04 04:06:24 +01:00
|
|
|
lws_mutex_refcount_init(&vh->mr);
|
2019-01-13 06:58:21 +08:00
|
|
|
#endif
|
|
|
|
|
2019-03-10 05:34:02 +08:00
|
|
|
if (!pcols && !info->pprotocols)
|
2019-01-13 06:58:21 +08:00
|
|
|
pcols = &protocols_dummy[0];
|
|
|
|
|
|
|
|
vh->context = context;
|
|
|
|
if (!info->vhost_name)
|
|
|
|
vh->name = "default";
|
|
|
|
else
|
|
|
|
vh->name = info->vhost_name;
|
2021-01-06 15:08:22 +00:00
|
|
|
{
|
|
|
|
char *end = buf + sizeof(buf) - 1;
|
|
|
|
p = buf;
|
|
|
|
|
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%s", vh->name);
|
|
|
|
if (info->iface)
|
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "|%s", info->iface);
|
|
|
|
if (info->port && !(info->port & 0xffff))
|
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "|%u", info->port);
|
|
|
|
}
|
|
|
|
|
|
|
|
__lws_lc_tag(&context->lcg[LWSLCG_VHOST], &vh->lc, "%s|%s|%d", buf,
|
|
|
|
info->iface ? info->iface : "", info->port);
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2021-02-17 10:31:22 +00:00
|
|
|
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
2021-03-16 13:32:05 +00:00
|
|
|
vh->fic.name = "vh";
|
|
|
|
if (info->fic.fi_owner.count)
|
2021-02-17 10:31:22 +00:00
|
|
|
/*
|
|
|
|
* This moves all the lws_fi_t from info->fi to the vhost fi,
|
|
|
|
* leaving it empty
|
|
|
|
*/
|
2021-03-16 13:32:05 +00:00
|
|
|
lws_fi_import(&vh->fic, &info->fic);
|
|
|
|
|
|
|
|
lws_fi_inherit_copy(&vh->fic, &context->fic, "vh", vh->name);
|
|
|
|
if (lws_fi(&vh->fic, "vh_create_oom"))
|
|
|
|
goto bail;
|
2021-02-17 10:31:22 +00:00
|
|
|
#endif
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
|
|
|
vh->http.error_document_404 = info->error_document_404;
|
|
|
|
#endif
|
|
|
|
|
2019-09-13 13:12:55 +01:00
|
|
|
if (lws_check_opt(info->options, LWS_SERVER_OPTION_ONLY_RAW))
|
2019-01-13 06:58:21 +08:00
|
|
|
lwsl_info("%s set to only support RAW\n", vh->name);
|
|
|
|
|
|
|
|
vh->iface = info->iface;
|
2019-08-18 10:35:43 +01:00
|
|
|
#if !defined(LWS_PLAT_FREERTOS) && !defined(OPTEE_TA) && !defined(WIN32)
|
2019-01-13 06:58:21 +08:00
|
|
|
vh->bind_iface = info->bind_iface;
|
2020-05-26 17:05:39 +01:00
|
|
|
#endif
|
|
|
|
#if defined(LWS_WITH_CLIENT)
|
|
|
|
if (info->connect_timeout_secs)
|
2020-12-12 06:21:40 +00:00
|
|
|
vh->connect_timeout_secs = (int)info->connect_timeout_secs;
|
2020-05-26 17:05:39 +01:00
|
|
|
else
|
|
|
|
vh->connect_timeout_secs = 20;
|
2019-01-13 06:58:21 +08:00
|
|
|
#endif
|
2019-09-18 13:09:32 +01:00
|
|
|
/* apply the context default lws_retry */
|
|
|
|
|
|
|
|
if (info->retry_and_idle_policy)
|
|
|
|
vh->retry_policy = info->retry_and_idle_policy;
|
|
|
|
else
|
|
|
|
vh->retry_policy = &context->default_retry;
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2019-03-19 11:53:57 +08:00
|
|
|
/*
|
|
|
|
* let's figure out how many protocols the user is handing us, using the
|
|
|
|
* old or new way depending on what he gave us
|
|
|
|
*/
|
|
|
|
|
2019-03-10 05:34:02 +08:00
|
|
|
if (!pcols)
|
|
|
|
for (vh->count_protocols = 0;
|
|
|
|
info->pprotocols[vh->count_protocols];
|
|
|
|
vh->count_protocols++)
|
|
|
|
;
|
|
|
|
else
|
|
|
|
for (vh->count_protocols = 0;
|
|
|
|
pcols[vh->count_protocols].callback;
|
|
|
|
vh->count_protocols++)
|
|
|
|
;
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
vh->options = info->options;
|
|
|
|
vh->pvo = info->pvo;
|
|
|
|
vh->headers = info->headers;
|
|
|
|
vh->user = info->user;
|
|
|
|
vh->finalize = info->finalize;
|
|
|
|
vh->finalize_arg = info->finalize_arg;
|
|
|
|
vh->listen_accept_role = info->listen_accept_role;
|
|
|
|
vh->listen_accept_protocol = info->listen_accept_protocol;
|
2019-03-25 08:07:28 +08:00
|
|
|
vh->unix_socket_perms = info->unix_socket_perms;
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
if (lws_rops_fidx(ar, LWS_ROPS_init_vhost) &&
|
|
|
|
(lws_rops_func_fidx(ar, LWS_ROPS_init_vhost)).init_vhost(vh, info))
|
|
|
|
return NULL;
|
2019-01-13 06:58:21 +08:00
|
|
|
LWS_FOR_EVERY_AVAILABLE_ROLE_END;
|
|
|
|
|
|
|
|
|
|
|
|
if (info->keepalive_timeout)
|
|
|
|
vh->keepalive_timeout = info->keepalive_timeout;
|
|
|
|
else
|
|
|
|
vh->keepalive_timeout = 5;
|
|
|
|
|
|
|
|
if (info->timeout_secs_ah_idle)
|
2020-12-12 06:21:40 +00:00
|
|
|
vh->timeout_secs_ah_idle = (int)info->timeout_secs_ah_idle;
|
2019-01-13 06:58:21 +08:00
|
|
|
else
|
|
|
|
vh->timeout_secs_ah_idle = 10;
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_TLS)
|
|
|
|
|
|
|
|
vh->tls.alpn = info->alpn;
|
|
|
|
vh->tls.ssl_info_event_mask = info->ssl_info_event_mask;
|
|
|
|
|
|
|
|
if (info->ecdh_curve)
|
|
|
|
lws_strncpy(vh->tls.ecdh_curve, info->ecdh_curve,
|
|
|
|
sizeof(vh->tls.ecdh_curve));
|
|
|
|
|
|
|
|
/* carefully allocate and take a copy of cert + key paths if present */
|
|
|
|
n = 0;
|
|
|
|
if (info->ssl_cert_filepath)
|
|
|
|
n += (int)strlen(info->ssl_cert_filepath) + 1;
|
|
|
|
if (info->ssl_private_key_filepath)
|
|
|
|
n += (int)strlen(info->ssl_private_key_filepath) + 1;
|
|
|
|
|
|
|
|
if (n) {
|
|
|
|
vh->tls.key_path = vh->tls.alloc_cert_path =
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_malloc((unsigned int)n, "vh paths");
|
2019-01-13 06:58:21 +08:00
|
|
|
if (info->ssl_cert_filepath) {
|
|
|
|
n = (int)strlen(info->ssl_cert_filepath) + 1;
|
|
|
|
memcpy(vh->tls.alloc_cert_path,
|
2020-12-12 06:21:40 +00:00
|
|
|
info->ssl_cert_filepath, (unsigned int)n);
|
2019-01-13 06:58:21 +08:00
|
|
|
vh->tls.key_path += n;
|
|
|
|
}
|
|
|
|
if (info->ssl_private_key_filepath)
|
|
|
|
memcpy(vh->tls.key_path, info->ssl_private_key_filepath,
|
|
|
|
strlen(info->ssl_private_key_filepath) + 1);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-03-19 11:53:57 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_ROLE_WS)
|
|
|
|
fx = 1;
|
|
|
|
#endif
|
2019-06-22 06:59:49 +01:00
|
|
|
#if defined(LWS_WITH_ABSTRACT)
|
2019-04-21 19:57:19 +01:00
|
|
|
abs_pcol_count = (int)LWS_ARRAY_SIZE(available_abstract_protocols) - 1;
|
2019-06-22 06:59:49 +01:00
|
|
|
#endif
|
2020-02-29 12:37:24 +00:00
|
|
|
#if defined(LWS_WITH_SECURE_STREAMS)
|
|
|
|
sec_pcol_count = (int)LWS_ARRAY_SIZE(available_secstream_protocols) - 1;
|
|
|
|
#endif
|
2019-04-21 19:57:19 +01:00
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
/*
|
2019-04-21 19:57:19 +01:00
|
|
|
* give the vhost a unified list of protocols including:
|
|
|
|
*
|
2019-09-19 06:54:53 +01:00
|
|
|
* - internal, async_dns if enabled (first vhost only)
|
2019-04-21 19:57:19 +01:00
|
|
|
* - internal, abstracted ones
|
|
|
|
* - the ones that came from plugins
|
|
|
|
* - his user protocols
|
2019-01-13 06:58:21 +08:00
|
|
|
*/
|
2021-03-16 13:32:05 +00:00
|
|
|
|
|
|
|
if (lws_fi(&vh->fic, "vh_create_pcols_oom"))
|
|
|
|
lwsp = NULL;
|
|
|
|
else
|
|
|
|
lwsp = lws_zalloc(sizeof(struct lws_protocols) *
|
2020-12-12 06:21:40 +00:00
|
|
|
((unsigned int)vh->count_protocols +
|
|
|
|
(unsigned int)abs_pcol_count +
|
|
|
|
(unsigned int)sec_pcol_count +
|
|
|
|
(unsigned int)context->plugin_protocol_count +
|
2021-03-16 13:32:05 +00:00
|
|
|
(unsigned int)fx + 1), "vh plugin table");
|
2019-01-13 06:58:21 +08:00
|
|
|
if (!lwsp) {
|
|
|
|
lwsl_err("OOM\n");
|
2021-03-16 13:32:05 +00:00
|
|
|
goto bail;
|
2019-01-13 06:58:21 +08:00
|
|
|
}
|
|
|
|
|
2019-04-21 19:57:19 +01:00
|
|
|
/*
|
|
|
|
* 1: user protocols (from pprotocols or protocols)
|
|
|
|
*/
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
m = vh->count_protocols;
|
2019-03-10 05:34:02 +08:00
|
|
|
if (!pcols) {
|
|
|
|
for (n = 0; n < m; n++)
|
|
|
|
memcpy(&lwsp[n], info->pprotocols[n], sizeof(lwsp[0]));
|
|
|
|
} else
|
2020-12-12 06:21:40 +00:00
|
|
|
memcpy(lwsp, pcols, sizeof(struct lws_protocols) * (unsigned int)m);
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2019-03-19 11:53:57 +08:00
|
|
|
/*
|
2019-04-21 19:57:19 +01:00
|
|
|
* 2: abstract protocols
|
|
|
|
*/
|
2019-06-22 06:59:49 +01:00
|
|
|
#if defined(LWS_WITH_ABSTRACT)
|
2019-04-21 19:57:19 +01:00
|
|
|
for (n = 0; n < abs_pcol_count; n++) {
|
|
|
|
memcpy(&lwsp[m++], available_abstract_protocols[n],
|
|
|
|
sizeof(*lwsp));
|
|
|
|
vh->count_protocols++;
|
|
|
|
}
|
2019-06-22 06:59:49 +01:00
|
|
|
#endif
|
2019-09-19 06:54:53 +01:00
|
|
|
/*
|
|
|
|
* 3: async dns protocol (first vhost only)
|
|
|
|
*/
|
|
|
|
#if defined(LWS_WITH_SYS_ASYNC_DNS)
|
|
|
|
if (!context->vhost_list) {
|
|
|
|
memcpy(&lwsp[m++], &lws_async_dns_protocol,
|
|
|
|
sizeof(struct lws_protocols));
|
|
|
|
vh->count_protocols++;
|
|
|
|
}
|
|
|
|
#endif
|
2019-04-21 19:57:19 +01:00
|
|
|
|
2020-02-29 12:37:24 +00:00
|
|
|
#if defined(LWS_WITH_SECURE_STREAMS)
|
|
|
|
for (n = 0; n < sec_pcol_count; n++) {
|
|
|
|
memcpy(&lwsp[m++], available_secstream_protocols[n],
|
|
|
|
sizeof(*lwsp));
|
|
|
|
vh->count_protocols++;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-04-21 19:57:19 +01:00
|
|
|
/*
|
|
|
|
* 3: For compatibility, all protocols enabled on vhost if only
|
2019-01-13 06:58:21 +08:00
|
|
|
* the default vhost exists. Otherwise only vhosts who ask
|
|
|
|
* for a protocol get it enabled.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
|
|
|
|
f = 0;
|
|
|
|
(void)f;
|
|
|
|
#ifdef LWS_WITH_PLUGINS
|
|
|
|
if (plugin) {
|
|
|
|
while (plugin) {
|
2020-08-27 09:34:35 +01:00
|
|
|
const lws_plugin_protocol_t *plpr =
|
|
|
|
(const lws_plugin_protocol_t *)plugin->hdr;
|
|
|
|
|
|
|
|
for (n = 0; n < plpr->count_protocols; n++) {
|
2019-01-13 06:58:21 +08:00
|
|
|
/*
|
|
|
|
* for compatibility's sake, no pvo implies
|
|
|
|
* allow all protocols
|
|
|
|
*/
|
|
|
|
if (f || lws_vhost_protocol_options(vh,
|
2020-08-27 09:34:35 +01:00
|
|
|
plpr->protocols[n].name)) {
|
2019-01-13 06:58:21 +08:00
|
|
|
memcpy(&lwsp[m],
|
2020-08-27 09:34:35 +01:00
|
|
|
&plpr->protocols[n],
|
2019-01-13 06:58:21 +08:00
|
|
|
sizeof(struct lws_protocols));
|
|
|
|
m++;
|
|
|
|
vh->count_protocols++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
plugin = plugin->list;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-03-19 11:53:57 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_ROLE_WS)
|
2019-04-21 19:57:19 +01:00
|
|
|
memcpy(&lwsp[m++], &lws_ws_proxy, sizeof(*lwsp));
|
2019-03-19 11:53:57 +08:00
|
|
|
vh->count_protocols++;
|
|
|
|
#endif
|
|
|
|
|
2019-04-21 19:57:19 +01:00
|
|
|
vh->protocols = lwsp;
|
|
|
|
vh->allocated_vhost_protocols = 1;
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2019-08-08 16:58:55 +01:00
|
|
|
vh->same_vh_protocol_owner = (struct lws_dll2_owner *)
|
|
|
|
lws_zalloc(sizeof(struct lws_dll2_owner) *
|
2020-12-12 06:21:40 +00:00
|
|
|
(unsigned int)vh->count_protocols, "same vh list");
|
2019-01-13 06:58:21 +08:00
|
|
|
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
|
|
|
vh->http.mount_list = info->mounts;
|
|
|
|
#endif
|
|
|
|
|
2021-01-06 15:08:22 +00:00
|
|
|
#if defined(LWS_WITH_SYS_METRICS) && defined(LWS_WITH_SERVER)
|
|
|
|
{
|
|
|
|
char *end = buf + sizeof(buf) - 1;
|
|
|
|
p = buf;
|
|
|
|
|
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "vh.%s", vh->name);
|
|
|
|
if (info->iface)
|
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ".%s", info->iface);
|
|
|
|
if (info->port && !(info->port & 0xffff))
|
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ".%u", info->port);
|
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ".rx");
|
|
|
|
vh->mt_traffic_rx = lws_metric_create(context, 0, buf);
|
|
|
|
p[-2] = 't';
|
|
|
|
vh->mt_traffic_tx = lws_metric_create(context, 0, buf);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
#ifdef LWS_WITH_UNIX_SOCK
|
|
|
|
if (LWS_UNIX_SOCK_ENABLED(vh)) {
|
|
|
|
lwsl_info("Creating Vhost '%s' path \"%s\", %d protocols\n",
|
|
|
|
vh->name, vh->iface, vh->count_protocols);
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
switch(info->port) {
|
|
|
|
case CONTEXT_PORT_NO_LISTEN:
|
|
|
|
strcpy(buf, "(serving disabled)");
|
|
|
|
break;
|
|
|
|
case CONTEXT_PORT_NO_LISTEN_SERVER:
|
|
|
|
strcpy(buf, "(no listener)");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
lws_snprintf(buf, sizeof(buf), "port %u", info->port);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
lwsl_info("Creating Vhost '%s' %s, %d protocols, IPv6 %s\n",
|
|
|
|
vh->name, buf, vh->count_protocols,
|
|
|
|
LWS_IPV6_ENABLED(vh) ? "on" : "off");
|
|
|
|
}
|
|
|
|
mounts = info->mounts;
|
|
|
|
while (mounts) {
|
|
|
|
(void)mount_protocols[0];
|
|
|
|
lwsl_info(" mounting %s%s to %s\n",
|
|
|
|
mount_protocols[mounts->origin_protocol],
|
2021-03-29 19:56:59 +01:00
|
|
|
mounts->origin ? mounts->origin : "none",
|
|
|
|
mounts->mountpoint);
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
mounts = mounts->mount_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
vh->listen_port = info->port;
|
2019-08-17 21:20:55 +01:00
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
#if defined(LWS_WITH_SOCKS5)
|
|
|
|
vh->socks_proxy_port = 0;
|
|
|
|
vh->socks_proxy_address[0] = '\0';
|
|
|
|
#endif
|
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT) && defined(LWS_CLIENT_HTTP_PROXYING)
|
2019-01-13 06:58:21 +08:00
|
|
|
/* either use proxy from info, or try get it from env var */
|
|
|
|
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
2019-08-17 21:20:55 +01:00
|
|
|
vh->http.http_proxy_port = 0;
|
|
|
|
vh->http.http_proxy_address[0] = '\0';
|
2019-01-13 06:58:21 +08:00
|
|
|
/* http proxy */
|
|
|
|
if (info->http_proxy_address) {
|
|
|
|
/* override for backwards compatibility */
|
|
|
|
if (info->http_proxy_port)
|
|
|
|
vh->http.http_proxy_port = info->http_proxy_port;
|
|
|
|
lws_set_proxy(vh, info->http_proxy_address);
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
#ifdef LWS_HAVE_GETENV
|
2020-01-11 07:58:37 +00:00
|
|
|
#if defined(__COVERITY__)
|
|
|
|
p = NULL;
|
|
|
|
#else
|
|
|
|
p = getenv("http_proxy"); /* coverity[tainted_scalar] */
|
2019-07-13 11:51:45 -07:00
|
|
|
if (p) {
|
|
|
|
lws_strncpy(buf, p, sizeof(buf));
|
|
|
|
lws_set_proxy(vh, buf);
|
|
|
|
}
|
2020-01-11 07:58:37 +00:00
|
|
|
#endif
|
2019-01-13 06:58:21 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(LWS_WITH_SOCKS5)
|
2020-02-18 14:27:27 +00:00
|
|
|
lws_socks5c_ads_server(vh, info);
|
2019-01-13 06:58:21 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
vh->ka_time = info->ka_time;
|
|
|
|
vh->ka_interval = info->ka_interval;
|
|
|
|
vh->ka_probes = info->ka_probes;
|
|
|
|
|
|
|
|
if (vh->options & LWS_SERVER_OPTION_STS)
|
|
|
|
lwsl_notice(" STS enabled\n");
|
|
|
|
|
|
|
|
#ifdef LWS_WITH_ACCESS_LOG
|
|
|
|
if (info->log_filepath) {
|
2021-03-16 13:32:05 +00:00
|
|
|
if (lws_fi(&vh->fic, "vh_create_access_log_open_fail"))
|
|
|
|
vh->log_fd = (int)LWS_INVALID_FILE;
|
|
|
|
else
|
|
|
|
vh->log_fd = lws_open(info->log_filepath,
|
2019-01-13 06:58:21 +08:00
|
|
|
O_CREAT | O_APPEND | O_RDWR, 0600);
|
|
|
|
if (vh->log_fd == (int)LWS_INVALID_FILE) {
|
|
|
|
lwsl_err("unable to open log filepath %s\n",
|
|
|
|
info->log_filepath);
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
#ifndef WIN32
|
2020-12-12 06:21:40 +00:00
|
|
|
if (context->uid != (uid_t)-1)
|
2019-01-13 06:58:21 +08:00
|
|
|
if (chown(info->log_filepath, context->uid,
|
|
|
|
context->gid) == -1)
|
|
|
|
lwsl_err("unable to chown log file %s\n",
|
|
|
|
info->log_filepath);
|
|
|
|
#endif
|
|
|
|
} else
|
|
|
|
vh->log_fd = (int)LWS_INVALID_FILE;
|
|
|
|
#endif
|
2021-03-16 13:32:05 +00:00
|
|
|
if (lws_fi(&vh->fic, "vh_create_ssl_srv") ||
|
|
|
|
lws_context_init_server_ssl(info, vh)) {
|
2019-01-13 06:58:21 +08:00
|
|
|
lwsl_err("%s: lws_context_init_server_ssl failed\n", __func__);
|
|
|
|
goto bail1;
|
|
|
|
}
|
2021-03-16 13:32:05 +00:00
|
|
|
if (lws_fi(&vh->fic, "vh_create_ssl_cli") ||
|
|
|
|
lws_context_init_client_ssl(info, vh)) {
|
2019-01-13 06:58:21 +08:00
|
|
|
lwsl_err("%s: lws_context_init_client_ssl failed\n", __func__);
|
|
|
|
goto bail1;
|
|
|
|
}
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
2021-01-06 15:08:22 +00:00
|
|
|
lws_context_lock(context, __func__);
|
2021-03-16 13:32:05 +00:00
|
|
|
if (lws_fi(&vh->fic, "vh_create_srv_init"))
|
|
|
|
n = -1;
|
|
|
|
else
|
|
|
|
n = _lws_vhost_init_server(info, vh);
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_context_unlock(context);
|
|
|
|
if (n < 0) {
|
|
|
|
lwsl_err("init server failed\n");
|
|
|
|
goto bail1;
|
|
|
|
}
|
2019-08-18 10:35:43 +01:00
|
|
|
#endif
|
2020-08-18 13:33:28 +01:00
|
|
|
|
|
|
|
#if defined(LWS_WITH_SYS_ASYNC_DNS)
|
2019-09-19 06:54:53 +01:00
|
|
|
n = !!context->vhost_list;
|
2020-08-18 13:33:28 +01:00
|
|
|
#endif
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (!(*vh1)) {
|
|
|
|
*vh1 = vh;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
vh1 = &(*vh1)->vhost_next;
|
|
|
|
};
|
|
|
|
|
2019-09-19 06:54:53 +01:00
|
|
|
#if defined(LWS_WITH_SYS_ASYNC_DNS)
|
2021-02-02 17:10:36 +00:00
|
|
|
if (!n)
|
|
|
|
lws_async_dns_init(context);
|
2019-09-19 06:54:53 +01:00
|
|
|
#endif
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
/* for the case we are adding a vhost much later, after server init */
|
|
|
|
|
|
|
|
if (context->protocol_init_done)
|
2021-03-16 13:32:05 +00:00
|
|
|
if (lws_fi(&vh->fic, "vh_create_protocol_init") ||
|
|
|
|
lws_protocol_init(context)) {
|
2019-01-13 06:58:21 +08:00
|
|
|
lwsl_err("%s: lws_protocol_init failed\n", __func__);
|
|
|
|
goto bail1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return vh;
|
|
|
|
|
|
|
|
bail1:
|
|
|
|
lws_vhost_destroy(vh);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
bail:
|
2021-03-16 13:32:05 +00:00
|
|
|
__lws_lc_untag(&vh->lc);
|
|
|
|
lws_fi_destroy(&vh->fic);
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_free(vh);
|
2021-03-16 13:32:05 +00:00
|
|
|
|
|
|
|
early_bail:
|
|
|
|
lws_fi_destroy(&info->fic);
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
int
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_init_vhost_client_ssl(const struct lws_context_creation_info *info,
|
|
|
|
struct lws_vhost *vhost)
|
|
|
|
{
|
|
|
|
struct lws_context_creation_info i;
|
|
|
|
|
|
|
|
memcpy(&i, info, sizeof(i));
|
|
|
|
i.port = CONTEXT_PORT_NO_LISTEN;
|
|
|
|
|
|
|
|
return lws_context_init_client_ssl(&i, vhost);
|
|
|
|
}
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
void
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_cancel_service_pt(struct lws *wsi)
|
|
|
|
{
|
2020-11-16 19:32:58 +00:00
|
|
|
lws_plat_pipe_signal(wsi->a.context, wsi->tsi);
|
2019-01-13 06:58:21 +08:00
|
|
|
}
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
void
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_cancel_service(struct lws_context *context)
|
|
|
|
{
|
|
|
|
struct lws_context_per_thread *pt = &context->pt[0];
|
2020-11-16 19:32:58 +00:00
|
|
|
short m;
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2020-11-16 19:32:58 +00:00
|
|
|
if (context->service_no_longer_possible)
|
2019-01-13 06:58:21 +08:00
|
|
|
return;
|
|
|
|
|
2020-07-02 15:38:53 +01:00
|
|
|
lwsl_debug("%s\n", __func__);
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2020-11-16 19:32:58 +00:00
|
|
|
for (m = 0; m < context->count_threads; m++) {
|
2019-01-13 06:58:21 +08:00
|
|
|
if (pt->pipe_wsi)
|
2020-11-16 19:32:58 +00:00
|
|
|
lws_plat_pipe_signal(pt->context, m);
|
2019-01-13 06:58:21 +08:00
|
|
|
pt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2020-12-24 16:06:50 +00:00
|
|
|
__lws_create_event_pipes(struct lws_context *context)
|
2019-01-13 06:58:21 +08:00
|
|
|
{
|
2020-08-31 08:12:16 +01:00
|
|
|
struct lws_context_per_thread *pt;
|
2019-01-13 06:58:21 +08:00
|
|
|
struct lws *wsi;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the pt event pipes... these are unique in that they are
|
|
|
|
* not bound to a vhost or protocol (both are NULL)
|
|
|
|
*/
|
|
|
|
|
2020-01-15 08:31:28 +00:00
|
|
|
#if LWS_MAX_SMP > 1
|
2019-01-13 06:58:21 +08:00
|
|
|
for (n = 0; n < context->count_threads; n++) {
|
2020-01-15 08:31:28 +00:00
|
|
|
#else
|
|
|
|
n = 0;
|
|
|
|
{
|
|
|
|
#endif
|
2020-08-31 08:12:16 +01:00
|
|
|
pt = &context->pt[n];
|
|
|
|
|
|
|
|
if (pt->pipe_wsi)
|
2020-01-15 08:31:28 +00:00
|
|
|
return 0;
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2020-12-24 16:06:50 +00:00
|
|
|
wsi = __lws_wsi_create_with_role(context, n, &role_ops_pipe);
|
2020-10-04 07:28:41 +01:00
|
|
|
if (!wsi)
|
2019-01-13 06:58:21 +08:00
|
|
|
return 1;
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
__lws_lc_tag(&context->lcg[LWSLCG_WSI], &wsi->lc, "pipe");
|
|
|
|
|
2020-10-04 07:28:41 +01:00
|
|
|
wsi->event_pipe = 1;
|
|
|
|
pt->pipe_wsi = wsi;
|
2020-08-31 08:12:16 +01:00
|
|
|
|
2020-01-15 08:31:28 +00:00
|
|
|
if (!lws_plat_pipe_create(wsi)) {
|
2019-01-13 06:58:21 +08:00
|
|
|
/*
|
|
|
|
* platform code returns 0 if it actually created pipes
|
|
|
|
* and initialized pt->dummy_pipe_fds[]. If it used
|
|
|
|
* some other mechanism outside of signaling in the
|
|
|
|
* normal event loop, we skip treating the pipe as
|
|
|
|
* related to dummy_pipe_fds[], adding it to the fds,
|
|
|
|
* etc.
|
|
|
|
*/
|
|
|
|
|
2020-01-15 08:31:28 +00:00
|
|
|
wsi->desc.sockfd = context->pt[n].dummy_pipe_fds[0];
|
|
|
|
lwsl_debug("event pipe fd %d\n", wsi->desc.sockfd);
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2020-10-04 07:28:41 +01:00
|
|
|
if (lws_wsi_inject_to_loop(pt, wsi))
|
2020-08-31 08:12:16 +01:00
|
|
|
goto bail;
|
2020-01-15 08:31:28 +00:00
|
|
|
}
|
2019-01-13 06:58:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2020-08-31 08:12:16 +01:00
|
|
|
|
|
|
|
bail:
|
|
|
|
|
|
|
|
return 1;
|
2019-01-13 06:58:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lws_destroy_event_pipe(struct lws *wsi)
|
|
|
|
{
|
2020-10-04 07:28:41 +01:00
|
|
|
int n;
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2020-10-04 07:28:41 +01:00
|
|
|
lwsl_info("%s\n", __func__);
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2020-10-04 07:28:41 +01:00
|
|
|
n = lws_wsi_extract_from_loop(wsi);
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_plat_pipe_close(wsi);
|
2020-10-04 07:28:41 +01:00
|
|
|
if (!n)
|
|
|
|
lws_free(wsi);
|
2019-01-13 06:58:21 +08:00
|
|
|
}
|
|
|
|
|
2021-01-22 09:11:22 +00:00
|
|
|
/*
|
|
|
|
* Start close process for any wsi bound to this vhost that belong to the
|
|
|
|
* service thread we are called from. Because of async event lib close, or
|
|
|
|
* protocol staged close on wsi, latency with pts joining in closing their
|
|
|
|
* wsi on the vhost, this may take some time.
|
|
|
|
*
|
|
|
|
* When the wsi count bound to the vhost (from all pts) drops to zero, the
|
|
|
|
* vhost destruction will be finalized.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
__lws_vhost_destroy_pt_wsi_dieback_start(struct lws_vhost *vh)
|
|
|
|
{
|
|
|
|
#if LWS_MAX_SMP > 1
|
|
|
|
/* calling pt thread has done its wsi dieback */
|
|
|
|
int tsi = lws_pthread_self_to_tsi(vh->context);
|
|
|
|
#else
|
|
|
|
int tsi = 0;
|
|
|
|
#endif
|
|
|
|
struct lws_context *ctx = vh->context;
|
|
|
|
struct lws_context_per_thread *pt = &ctx->pt[tsi];
|
|
|
|
unsigned int n;
|
|
|
|
|
|
|
|
#if LWS_MAX_SMP > 1
|
|
|
|
if (vh->close_flow_vs_tsi[lws_pthread_self_to_tsi(vh->context)])
|
|
|
|
/* this pt has already done its bit */
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_CLIENT)
|
|
|
|
/*
|
|
|
|
* destroy any wsi that are associated with us but have no socket
|
|
|
|
* (and will otherwise be missed for destruction)
|
|
|
|
*/
|
|
|
|
lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
|
|
|
|
vh->vh_awaiting_socket_owner.head) {
|
|
|
|
struct lws *w =
|
|
|
|
lws_container_of(d, struct lws, vh_awaiting_socket);
|
|
|
|
|
|
|
|
if (w->tsi == tsi) {
|
|
|
|
|
|
|
|
lwsl_debug("%s: closing aso\n", __func__);
|
|
|
|
lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
|
|
|
|
"awaiting skt");
|
|
|
|
}
|
|
|
|
|
|
|
|
} lws_end_foreach_dll_safe(d, d1);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Close any wsi on this pt bound to the vhost
|
|
|
|
*/
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
while (n < pt->fds_count) {
|
|
|
|
struct lws *wsi = wsi_from_fd(ctx, pt->fds[n].fd);
|
|
|
|
|
|
|
|
if (wsi && wsi->tsi == tsi && wsi->a.vhost == vh) {
|
|
|
|
|
|
|
|
lwsl_debug("%s: pt %d: closing wsi %p: role %s\n",
|
|
|
|
__func__, tsi, wsi, wsi->role_ops->name);
|
|
|
|
|
|
|
|
lws_wsi_close(wsi, LWS_TO_KILL_ASYNC);
|
|
|
|
|
|
|
|
if (pt->pipe_wsi == wsi)
|
|
|
|
pt->pipe_wsi = NULL;
|
|
|
|
}
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if LWS_MAX_SMP > 1
|
|
|
|
/* calling pt thread has done its wsi dieback */
|
|
|
|
vh->close_flow_vs_tsi[lws_pthread_self_to_tsi(vh->context)] = 1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Mark the vhost as being destroyed, so things trying to use it abort.
|
|
|
|
*
|
|
|
|
* Dispose of the listen socket.
|
|
|
|
*/
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
lws_vhost_destroy1(struct lws_vhost *vh)
|
|
|
|
{
|
|
|
|
struct lws_context *context = vh->context;
|
|
|
|
|
|
|
|
lwsl_info("%s\n", __func__);
|
|
|
|
|
|
|
|
lws_context_lock(context, "vhost destroy 1"); /* ---------- context { */
|
|
|
|
|
|
|
|
if (vh->being_destroyed)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
lws_vhost_lock(vh); /* -------------- vh { */
|
|
|
|
|
2021-03-25 08:37:36 +00:00
|
|
|
#if defined(LWS_WITH_TLS_SESSIONS) && defined(LWS_WITH_TLS)
|
|
|
|
lws_tls_session_vh_destroy(vh);
|
|
|
|
#endif
|
|
|
|
|
2021-01-22 09:11:22 +00:00
|
|
|
vh->being_destroyed = 1;
|
|
|
|
lws_dll2_add_tail(&vh->vh_being_destroyed_list,
|
|
|
|
&context->owner_vh_being_destroyed);
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
#if defined(LWS_WITH_NETWORK)
|
|
|
|
/*
|
|
|
|
* PHASE 1: take down or reassign any listen wsi
|
|
|
|
*
|
|
|
|
* Are there other vhosts that are piggybacking on our listen socket?
|
|
|
|
* If so we need to hand the listen socket off to one of the others
|
|
|
|
* so it will remain open.
|
|
|
|
*
|
2021-01-22 09:11:22 +00:00
|
|
|
* If not, close the listen socket now.
|
|
|
|
*
|
|
|
|
* Either way the listen socket response to the vhost close is
|
|
|
|
* immediately performed.
|
2019-01-13 06:58:21 +08:00
|
|
|
*/
|
|
|
|
|
2021-01-22 09:11:22 +00:00
|
|
|
if (vh->lserv_wsi) {
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_start_foreach_ll(struct lws_vhost *, v,
|
|
|
|
context->vhost_list) {
|
|
|
|
if (v != vh &&
|
|
|
|
!v->being_destroyed &&
|
|
|
|
v->listen_port == vh->listen_port &&
|
|
|
|
((!v->iface && !vh->iface) ||
|
|
|
|
(v->iface && vh->iface &&
|
|
|
|
!strcmp(v->iface, vh->iface)))) {
|
|
|
|
/*
|
|
|
|
* this can only be a listen wsi, which is
|
|
|
|
* restricted... it has no protocol or other
|
|
|
|
* bindings or states. So we can simply
|
|
|
|
* swap it to a vhost that has the same
|
|
|
|
* iface + port, but is not closing.
|
|
|
|
*/
|
|
|
|
|
2021-01-22 09:11:22 +00:00
|
|
|
lwsl_notice("%s: listen skt migrate %s -> %s\n",
|
2020-12-29 16:42:25 -08:00
|
|
|
__func__, lws_vh_tag(vh),
|
|
|
|
lws_vh_tag(v));
|
|
|
|
|
|
|
|
assert(v->lserv_wsi == NULL);
|
|
|
|
v->lserv_wsi = vh->lserv_wsi;
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
if (v->lserv_wsi) {
|
2021-04-04 04:06:24 +01:00
|
|
|
/* req cx + vh lock */
|
2021-07-12 06:12:05 +01:00
|
|
|
/*
|
|
|
|
* If the vhost sees it's being destroyed and
|
|
|
|
* in the unbind the number of wsis bound to
|
|
|
|
* it falls to zero, it will destroy the
|
|
|
|
* vhost opportunistically before we can
|
|
|
|
* complete the transfer. Add a fake wsi
|
|
|
|
* bind temporarily to disallow this...
|
|
|
|
*/
|
|
|
|
v->count_bound_wsi++;
|
2021-04-04 04:06:24 +01:00
|
|
|
__lws_vhost_unbind_wsi(vh->lserv_wsi);
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_vhost_bind_wsi(v, v->lserv_wsi);
|
2021-07-12 06:12:05 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* ... remove the fake wsi bind
|
|
|
|
*/
|
|
|
|
v->count_bound_wsi--;
|
|
|
|
|
2021-01-22 09:11:22 +00:00
|
|
|
vh->lserv_wsi = NULL;
|
2019-01-13 06:58:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} lws_end_foreach_ll(v, vhost_next);
|
2021-01-22 09:11:22 +00:00
|
|
|
|
|
|
|
if (vh->lserv_wsi) {
|
|
|
|
/*
|
|
|
|
* we didn't pass it off to another vhost on the same
|
|
|
|
* listen port... let's close it next time around the
|
|
|
|
* event loop without waiting for the logical destroy
|
|
|
|
* of the vhost itself
|
|
|
|
*/
|
|
|
|
lws_set_timeout(vh->lserv_wsi, 1, LWS_TO_KILL_ASYNC);
|
|
|
|
vh->lserv_wsi = NULL;
|
|
|
|
}
|
|
|
|
}
|
2019-01-13 06:58:21 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
lws_vhost_unlock(vh); /* } vh -------------- */
|
|
|
|
|
|
|
|
out:
|
|
|
|
lws_context_unlock(context); /* --------------------------- context { */
|
|
|
|
}
|
|
|
|
|
2019-06-22 06:59:49 +01:00
|
|
|
#if defined(LWS_WITH_ABSTRACT)
|
|
|
|
static int
|
|
|
|
destroy_ais(struct lws_dll2 *d, void *user)
|
|
|
|
{
|
|
|
|
lws_abs_t *ai = lws_container_of(d, lws_abs_t, abstract_instances);
|
|
|
|
|
|
|
|
lws_abs_destroy_instance(&ai);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-01-22 09:11:22 +00:00
|
|
|
/*
|
|
|
|
* Either start close or destroy any wsi on the vhost that belong to this pt,
|
|
|
|
* if SMP mark the vh that we have done it for
|
2021-04-04 04:06:24 +01:00
|
|
|
*
|
|
|
|
* Must not have lock on vh
|
2021-01-22 09:11:22 +00:00
|
|
|
*/
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
void
|
|
|
|
__lws_vhost_destroy2(struct lws_vhost *vh)
|
|
|
|
{
|
|
|
|
const struct lws_protocols *protocol = NULL;
|
|
|
|
struct lws_context *context = vh->context;
|
|
|
|
struct lws wsi;
|
|
|
|
int n;
|
|
|
|
|
2019-12-21 12:13:14 +00:00
|
|
|
vh->being_destroyed = 0;
|
|
|
|
|
2021-02-19 11:31:06 +00:00
|
|
|
// lwsl_info("%s: %s\n", __func__, vh->name);
|
2019-09-08 08:08:55 +01:00
|
|
|
|
2020-05-28 12:48:17 +01:00
|
|
|
#if defined(LWS_WITH_DEPRECATED_THINGS)
|
2019-01-13 06:58:21 +08:00
|
|
|
/*
|
|
|
|
* destroy any pending timed events
|
|
|
|
*/
|
|
|
|
|
|
|
|
while (vh->timed_vh_protocol_list)
|
|
|
|
__lws_timed_callback_remove(vh, vh->timed_vh_protocol_list);
|
2020-05-28 12:48:17 +01:00
|
|
|
#endif
|
2022-03-16 15:24:22 +03:00
|
|
|
/*
|
|
|
|
* remove ourselves from the defer binding list
|
|
|
|
*/
|
|
|
|
lws_start_foreach_llp(struct lws_vhost **, pv,
|
|
|
|
vh->context->no_listener_vhost_list) {
|
|
|
|
if (*pv == vh) {
|
|
|
|
lwsl_debug("deferred iface: removing vh %s\n",
|
|
|
|
(*pv)->name);
|
|
|
|
*pv = vh->no_listener_vhost_list;
|
|
|
|
vh->no_listener_vhost_list = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} lws_end_foreach_llp(pv, no_listener_vhost_list);
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
/*
|
|
|
|
* let the protocols destroy the per-vhost protocol objects
|
|
|
|
*/
|
|
|
|
|
|
|
|
memset(&wsi, 0, sizeof(wsi));
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi.a.context = vh->context;
|
|
|
|
wsi.a.vhost = vh; /* not a real bound wsi */
|
2019-01-13 06:58:21 +08:00
|
|
|
protocol = vh->protocols;
|
|
|
|
if (protocol && vh->created_vhost_protocols) {
|
|
|
|
n = 0;
|
|
|
|
while (n < vh->count_protocols) {
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi.a.protocol = protocol;
|
2019-03-19 11:53:57 +08:00
|
|
|
|
2020-11-16 19:32:58 +00:00
|
|
|
lwsl_debug("%s: protocol destroy\n", __func__);
|
|
|
|
|
2019-03-17 10:03:22 +08:00
|
|
|
if (protocol->callback)
|
|
|
|
protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
|
2019-01-13 06:58:21 +08:00
|
|
|
NULL, NULL, 0);
|
|
|
|
protocol++;
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* remove vhost from context list of vhosts
|
|
|
|
*/
|
|
|
|
|
|
|
|
lws_start_foreach_llp(struct lws_vhost **, pv, context->vhost_list) {
|
|
|
|
if (*pv == vh) {
|
|
|
|
*pv = vh->vhost_next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} lws_end_foreach_llp(pv, vhost_next);
|
|
|
|
|
|
|
|
/* add ourselves to the pending destruction list */
|
|
|
|
|
2020-08-19 06:52:47 +01:00
|
|
|
if (vh->context->vhost_pending_destruction_list != vh) {
|
|
|
|
vh->vhost_next = vh->context->vhost_pending_destruction_list;
|
|
|
|
vh->context->vhost_pending_destruction_list = vh;
|
|
|
|
}
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2020-12-15 14:58:53 +00:00
|
|
|
//lwsl_debug("%s: do dfl '%s'\n", __func__, vh->name);
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
/* remove ourselves from the pending destruction list */
|
|
|
|
|
|
|
|
lws_start_foreach_llp(struct lws_vhost **, pv,
|
|
|
|
context->vhost_pending_destruction_list) {
|
|
|
|
if ((*pv) == vh) {
|
|
|
|
*pv = (*pv)->vhost_next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} lws_end_foreach_llp(pv, vhost_next);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free all the allocations associated with the vhost
|
|
|
|
*/
|
|
|
|
|
|
|
|
protocol = vh->protocols;
|
|
|
|
if (protocol) {
|
|
|
|
n = 0;
|
|
|
|
while (n < vh->count_protocols) {
|
|
|
|
if (vh->protocol_vh_privs &&
|
|
|
|
vh->protocol_vh_privs[n]) {
|
|
|
|
lws_free(vh->protocol_vh_privs[n]);
|
|
|
|
vh->protocol_vh_privs[n] = NULL;
|
|
|
|
}
|
|
|
|
protocol++;
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (vh->protocol_vh_privs)
|
|
|
|
lws_free(vh->protocol_vh_privs);
|
|
|
|
lws_ssl_SSL_CTX_destroy(vh);
|
2019-08-08 16:58:55 +01:00
|
|
|
lws_free(vh->same_vh_protocol_owner);
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2019-08-18 06:29:34 +01:00
|
|
|
if (
|
|
|
|
#if defined(LWS_WITH_PLUGINS)
|
|
|
|
context->plugin_list ||
|
|
|
|
#endif
|
2019-03-12 09:20:58 +08:00
|
|
|
(context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS) ||
|
|
|
|
vh->allocated_vhost_protocols)
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_free((void *)vh->protocols);
|
|
|
|
#if defined(LWS_WITH_NETWORK)
|
|
|
|
LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
if (lws_rops_fidx(ar, LWS_ROPS_destroy_vhost))
|
|
|
|
lws_rops_func_fidx(ar, LWS_ROPS_destroy_vhost).
|
|
|
|
destroy_vhost(vh);
|
2019-01-13 06:58:21 +08:00
|
|
|
LWS_FOR_EVERY_AVAILABLE_ROLE_END;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef LWS_WITH_ACCESS_LOG
|
|
|
|
if (vh->log_fd != (int)LWS_INVALID_FILE)
|
|
|
|
close(vh->log_fd);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (LWS_WITH_TLS)
|
|
|
|
lws_free_set_NULL(vh->tls.alloc_cert_path);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if LWS_MAX_SMP > 1
|
2021-04-04 04:06:24 +01:00
|
|
|
lws_mutex_refcount_destroy(&context->mr);
|
2019-01-13 06:58:21 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_UNIX_SOCK)
|
|
|
|
if (LWS_UNIX_SOCK_ENABLED(vh)) {
|
|
|
|
n = unlink(vh->iface);
|
|
|
|
if (n)
|
|
|
|
lwsl_info("Closing unix socket %s: errno %d\n",
|
|
|
|
vh->iface, errno);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* although async event callbacks may still come for wsi handles with
|
|
|
|
* pending close in the case of asycn event library like libuv,
|
|
|
|
* they do not refer to the vhost. So it's safe to free.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (vh->finalize)
|
|
|
|
vh->finalize(vh, vh->finalize_arg);
|
|
|
|
|
2019-06-22 06:59:49 +01:00
|
|
|
#if defined(LWS_WITH_ABSTRACT)
|
|
|
|
/*
|
|
|
|
* abstract instances
|
|
|
|
*/
|
|
|
|
|
|
|
|
lws_dll2_foreach_safe(&vh->abstract_instances_owner, NULL, destroy_ais);
|
|
|
|
#endif
|
|
|
|
|
2021-01-06 15:08:22 +00:00
|
|
|
#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SYS_METRICS)
|
|
|
|
lws_metric_destroy(&vh->mt_traffic_rx, 0);
|
|
|
|
lws_metric_destroy(&vh->mt_traffic_tx, 0);
|
|
|
|
#endif
|
|
|
|
|
2021-01-22 09:11:22 +00:00
|
|
|
lws_dll2_remove(&vh->vh_being_destroyed_list);
|
|
|
|
|
2021-02-17 10:31:22 +00:00
|
|
|
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
2021-03-16 13:32:05 +00:00
|
|
|
lws_fi_destroy(&vh->fic);
|
2021-02-17 10:31:22 +00:00
|
|
|
#endif
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
__lws_lc_untag(&vh->lc);
|
2021-01-06 15:08:22 +00:00
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
memset(vh, 0, sizeof(*vh));
|
|
|
|
lws_free(vh);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2021-01-22 09:11:22 +00:00
|
|
|
* Starts the vhost destroy process
|
|
|
|
*
|
|
|
|
* Vhosts are not simple to deal with because they are an abstraction that
|
|
|
|
* crosses SMP thread boundaries, a wsi on any pt can bind to any vhost. If we
|
|
|
|
* want another pt to do something to its wsis safely, we have to asynchronously
|
|
|
|
* ask it to do it.
|
|
|
|
*
|
|
|
|
* In addition, with event libs, closing any handles (which are bound to vhosts
|
|
|
|
* in their wsi) can happens asynchronously, so we can't just linearly do some
|
|
|
|
* cleanup flow and free it in one step.
|
|
|
|
*
|
|
|
|
* The vhost destroy is cut into two pieces:
|
|
|
|
*
|
|
|
|
* 1) dispose of the listen socket, either by passing it on to another vhost
|
|
|
|
* that was already sharing it, or just closing it.
|
|
|
|
*
|
|
|
|
* If any wsi bound to the vhost, mark the vhost as in the process of being
|
|
|
|
* destroyed, triggering each pt to close all wsi bound to the vhost next
|
|
|
|
* time around the event loop. Call lws_cancel_service() so all the pts wake
|
|
|
|
* to deal with this without long poll waits making delays.
|
|
|
|
*
|
|
|
|
* 2) When the number of wsis bound to the vhost reaches zero, do the final
|
|
|
|
* vhost destroy flow, this can be triggered from any pt.
|
2019-01-13 06:58:21 +08:00
|
|
|
*/
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
void
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_vhost_destroy(struct lws_vhost *vh)
|
|
|
|
{
|
|
|
|
struct lws_context *context = vh->context;
|
|
|
|
|
|
|
|
lws_context_lock(context, __func__); /* ------ context { */
|
|
|
|
|
2021-01-22 09:11:22 +00:00
|
|
|
/* dispose of the listen socket one way or another */
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_vhost_destroy1(vh);
|
|
|
|
|
2021-01-22 09:11:22 +00:00
|
|
|
/* start async closure of all wsi on this pt thread attached to vh */
|
|
|
|
__lws_vhost_destroy_pt_wsi_dieback_start(vh);
|
|
|
|
|
2021-02-05 13:09:33 +00:00
|
|
|
lwsl_info("%s: count_bound_wsi %d\n", __func__, vh->count_bound_wsi);
|
2020-02-29 12:37:24 +00:00
|
|
|
|
2021-01-22 09:11:22 +00:00
|
|
|
/* if there are none, finalize now since no further chance */
|
2019-01-13 06:58:21 +08:00
|
|
|
if (!vh->count_bound_wsi) {
|
|
|
|
__lws_vhost_destroy2(vh);
|
|
|
|
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2021-01-22 09:11:22 +00:00
|
|
|
/*
|
|
|
|
* We have some wsi bound to this vhost, we have to wait for these to
|
|
|
|
* complete close and unbind before progressing the vhost removal.
|
|
|
|
*
|
|
|
|
* When the last bound wsi on this vh is destroyed we will auto-call
|
|
|
|
* __lws_vhost_destroy2() to finalize vh destruction
|
|
|
|
*/
|
2019-01-13 06:58:21 +08:00
|
|
|
|
2021-01-22 09:11:22 +00:00
|
|
|
#if LWS_MAX_SMP > 1
|
|
|
|
/* alert other pts they also need to do dieback flow for their wsi */
|
|
|
|
lws_cancel_service(context);
|
|
|
|
#endif
|
2019-01-13 06:58:21 +08:00
|
|
|
|
|
|
|
out:
|
|
|
|
lws_context_unlock(context); /* } context ------------------- */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
void *
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_vhost_user(struct lws_vhost *vhost)
|
|
|
|
{
|
|
|
|
return vhost->user;
|
|
|
|
}
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
int
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_get_vhost_listen_port(struct lws_vhost *vhost)
|
|
|
|
{
|
|
|
|
return vhost->listen_port;
|
|
|
|
}
|
|
|
|
|
2019-08-18 06:29:34 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
2020-01-02 08:32:23 +00:00
|
|
|
void
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_context_deprecate(struct lws_context *context, lws_reload_func cb)
|
|
|
|
{
|
|
|
|
struct lws_vhost *vh = context->vhost_list, *vh1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "deprecation" means disable the context from accepting any new
|
|
|
|
* connections and free up listen sockets to be used by a replacement
|
|
|
|
* context.
|
|
|
|
*
|
|
|
|
* Otherwise the deprecated context remains operational, until its
|
|
|
|
* number of connected sockets falls to zero, when it is deleted.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* for each vhost, close his listen socket */
|
|
|
|
|
|
|
|
while (vh) {
|
|
|
|
struct lws *wsi = vh->lserv_wsi;
|
|
|
|
|
|
|
|
if (wsi) {
|
|
|
|
wsi->socket_is_permanently_unusable = 1;
|
|
|
|
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "ctx deprecate");
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.context->deprecation_pending_listen_close_count++;
|
2019-01-13 06:58:21 +08:00
|
|
|
/*
|
|
|
|
* other vhosts can share the listen port, they
|
|
|
|
* point to the same wsi. So zap those too.
|
|
|
|
*/
|
|
|
|
vh1 = context->vhost_list;
|
|
|
|
while (vh1) {
|
|
|
|
if (vh1->lserv_wsi == wsi)
|
|
|
|
vh1->lserv_wsi = NULL;
|
|
|
|
vh1 = vh1->vhost_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vh = vh->vhost_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
context->deprecated = 1;
|
|
|
|
context->deprecation_cb = cb;
|
|
|
|
}
|
2019-08-18 06:29:34 +01:00
|
|
|
#endif
|
2019-07-30 06:02:23 +01:00
|
|
|
|
|
|
|
#if defined(LWS_WITH_NETWORK)
|
2019-09-23 04:23:07 -07:00
|
|
|
|
2019-07-30 06:02:23 +01:00
|
|
|
struct lws_vhost *
|
|
|
|
lws_get_vhost_by_name(struct lws_context *context, const char *name)
|
|
|
|
{
|
|
|
|
lws_start_foreach_ll(struct lws_vhost *, v,
|
|
|
|
context->vhost_list) {
|
2021-01-22 09:11:22 +00:00
|
|
|
if (!v->being_destroyed && !strcmp(v->name, name))
|
2019-07-30 06:02:23 +01:00
|
|
|
return v;
|
|
|
|
|
|
|
|
} lws_end_foreach_ll(v, vhost_next);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-09-23 04:23:07 -07:00
|
|
|
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_CLIENT)
|
|
|
|
/*
|
|
|
|
* This is the logic checking to see if the new connection wsi should have a
|
|
|
|
* pipelining or muxing relationship with an existing "active connection" to
|
|
|
|
* the same endpoint under the same conditions.
|
|
|
|
*
|
|
|
|
* This was originally in the client code but since the list is held on the
|
|
|
|
* vhost (to ensure the same client tls ctx is involved) it's cleaner in vhost.c
|
2020-04-15 19:16:29 +01:00
|
|
|
*
|
|
|
|
* ACTIVE_CONNS_QUEUED: We're queued on an active connection, set *nwsi to that
|
|
|
|
* ACTIVE_CONNS_MUXED: We are joining an active mux conn *nwsi as a child
|
|
|
|
* ACTIVE_CONNS_SOLO: There's no existing conn to join either way
|
2019-09-23 04:23:07 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
2019-12-23 09:25:56 +00:00
|
|
|
lws_vhost_active_conns(struct lws *wsi, struct lws **nwsi, const char *adsin)
|
2019-09-23 04:23:07 -07:00
|
|
|
{
|
2020-12-15 14:58:53 +00:00
|
|
|
#if defined(LWS_WITH_TLS)
|
|
|
|
const char *my_alpn = lws_wsi_client_stash_item(wsi, CIS_ALPN,
|
|
|
|
_WSI_TOKEN_CLIENT_ALPN);
|
|
|
|
#endif
|
|
|
|
#if defined(LWS_WITH_TLS)
|
2021-03-25 13:28:02 +00:00
|
|
|
char newconn_cannot_use_h1 = 0;
|
|
|
|
|
2020-12-15 14:58:53 +00:00
|
|
|
if ((wsi->tls.use_ssl & LCCSCF_USE_SSL) &&
|
2021-03-25 13:28:02 +00:00
|
|
|
my_alpn && !strstr(my_alpn, "http/1.1"))
|
|
|
|
/*
|
|
|
|
* new guy wants to use tls, he specifies the alpn and he does
|
|
|
|
* not list h1 as a choice ==> he can't bind to existing h1
|
|
|
|
*/
|
2020-12-15 14:58:53 +00:00
|
|
|
newconn_cannot_use_h1 = 1;
|
|
|
|
#endif
|
|
|
|
|
2020-02-25 13:28:25 +00:00
|
|
|
if (!lws_dll2_is_detached(&wsi->dll2_cli_txn_queue)) {
|
|
|
|
struct lws *w = lws_container_of(
|
|
|
|
wsi->dll2_cli_txn_queue.owner, struct lws,
|
|
|
|
dll2_cli_txn_queue_owner);
|
|
|
|
*nwsi = w;
|
|
|
|
|
|
|
|
return ACTIVE_CONNS_QUEUED;
|
|
|
|
}
|
|
|
|
|
2020-02-29 12:37:24 +00:00
|
|
|
#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
|
2020-02-25 13:28:25 +00:00
|
|
|
if (wsi->mux.parent_wsi) {
|
|
|
|
/*
|
|
|
|
* We already decided...
|
|
|
|
*/
|
|
|
|
|
|
|
|
*nwsi = wsi->mux.parent_wsi;
|
|
|
|
|
|
|
|
return ACTIVE_CONNS_MUXED;
|
|
|
|
}
|
2020-02-29 12:37:24 +00:00
|
|
|
#endif
|
2020-02-25 13:28:25 +00:00
|
|
|
|
2021-04-04 04:06:24 +01:00
|
|
|
lws_context_lock(wsi->a.context, __func__); /* -------------- cx { */
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
lws_vhost_lock(wsi->a.vhost); /* ----------------------------------- { */
|
2019-09-23 04:23:07 -07:00
|
|
|
|
|
|
|
lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.vhost->dll_cli_active_conns_owner.head) {
|
2019-09-23 04:23:07 -07:00
|
|
|
struct lws *w = lws_container_of(d, struct lws,
|
|
|
|
dll_cli_active_conns);
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: check %s %s %s %s %d %d\n", __func__,
|
|
|
|
lws_wsi_tag(wsi), lws_wsi_tag(w),
|
2020-02-25 13:28:25 +00:00
|
|
|
adsin, w->cli_hostname_copy, wsi->c_port, w->c_port);
|
2019-09-23 04:23:07 -07:00
|
|
|
|
2019-12-23 09:25:56 +00:00
|
|
|
if (w != wsi &&
|
|
|
|
/*
|
|
|
|
* "same internet protocol"... this is a bit tricky,
|
2020-12-15 14:58:53 +00:00
|
|
|
* since h2 start out as h1, and may stay at h1.
|
|
|
|
*
|
|
|
|
* But an idle h1 connection cannot be used by a connection
|
|
|
|
* request that doesn't have http/1.1 in its alpn list...
|
2019-12-23 09:25:56 +00:00
|
|
|
*/
|
|
|
|
(w->role_ops == wsi->role_ops ||
|
|
|
|
(lwsi_role_http(w) && lwsi_role_http(wsi))) &&
|
2021-03-25 13:28:02 +00:00
|
|
|
/* ... same role, or at least both some kind of http */
|
|
|
|
w->cli_hostname_copy && !strcmp(adsin, w->cli_hostname_copy) &&
|
|
|
|
/* same endpoint hostname */
|
2019-09-23 04:23:07 -07:00
|
|
|
#if defined(LWS_WITH_TLS)
|
2021-03-25 13:28:02 +00:00
|
|
|
!(newconn_cannot_use_h1 && w->role_ops == &role_ops_h1) &&
|
|
|
|
/* if we can't use h1, old guy must not be h1 */
|
2019-09-23 04:23:07 -07:00
|
|
|
(wsi->tls.use_ssl & LCCSCF_USE_SSL) ==
|
|
|
|
(w->tls.use_ssl & LCCSCF_USE_SSL) &&
|
2021-03-25 13:28:02 +00:00
|
|
|
/* must both agree on tls use or not */
|
2019-09-23 04:23:07 -07:00
|
|
|
#endif
|
|
|
|
wsi->c_port == w->c_port) {
|
2021-03-25 13:28:02 +00:00
|
|
|
/* same endpoint port */
|
2019-09-23 04:23:07 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* There's already an active connection.
|
|
|
|
*
|
|
|
|
* The server may have told the existing active
|
|
|
|
* connection that it doesn't support pipelining...
|
|
|
|
*/
|
|
|
|
if (w->keepalive_rejected) {
|
2020-02-29 12:37:24 +00:00
|
|
|
lwsl_notice("defeating pipelining due to no "
|
2019-09-23 04:23:07 -07:00
|
|
|
"keepalive on server\n");
|
|
|
|
goto solo;
|
|
|
|
}
|
2020-02-25 13:28:25 +00:00
|
|
|
|
|
|
|
#if defined(LWS_WITH_HTTP2)
|
2019-09-23 04:23:07 -07:00
|
|
|
/*
|
2020-02-25 13:28:25 +00:00
|
|
|
* h2: if in usable state already: just use it without
|
2019-09-23 04:23:07 -07:00
|
|
|
* going through the queue
|
|
|
|
*/
|
2020-01-17 18:54:44 +00:00
|
|
|
if (w->client_h2_alpn && w->client_mux_migrated &&
|
2019-09-23 04:23:07 -07:00
|
|
|
(lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS ||
|
2020-01-30 13:19:11 +00:00
|
|
|
lwsi_state(w) == LRS_ESTABLISHED ||
|
|
|
|
lwsi_state(w) == LRS_IDLING)) {
|
2019-09-23 04:23:07 -07:00
|
|
|
|
2020-01-30 13:19:11 +00:00
|
|
|
lwsl_notice("%s: just join h2 directly 0x%x\n",
|
|
|
|
__func__, lwsi_state(w));
|
|
|
|
|
|
|
|
if (lwsi_state(w) == LRS_IDLING) {
|
|
|
|
// lwsi_set_state(w, LRS_ESTABLISHED);
|
2020-04-15 20:57:00 +01:00
|
|
|
_lws_generic_transaction_completed_active_conn(&w, 0);
|
2020-01-30 13:19:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//lwsi_set_state(w, LRS_H1C_ISSUE_HANDSHAKE2);
|
2019-09-23 04:23:07 -07:00
|
|
|
|
|
|
|
wsi->client_h2_alpn = 1;
|
|
|
|
lws_wsi_h2_adopt(w, wsi);
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
lws_vhost_unlock(wsi->a.vhost); /* } ---------- */
|
2021-04-04 04:06:24 +01:00
|
|
|
lws_context_unlock(wsi->a.context); /* -------------- cx { */
|
2019-09-23 04:23:07 -07:00
|
|
|
|
2020-01-30 13:19:11 +00:00
|
|
|
*nwsi = w;
|
|
|
|
|
2019-09-23 04:23:07 -07:00
|
|
|
return ACTIVE_CONNS_MUXED;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-02-25 13:28:25 +00:00
|
|
|
#if defined(LWS_ROLE_MQTT)
|
|
|
|
/*
|
|
|
|
* MQTT: if in usable state already: just use it without
|
|
|
|
* going through the queue
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (lwsi_role_mqtt(wsi) && w->client_mux_migrated &&
|
|
|
|
lwsi_state(w) == LRS_ESTABLISHED) {
|
|
|
|
|
|
|
|
if (lws_wsi_mqtt_adopt(w, wsi)) {
|
|
|
|
lwsl_notice("%s: join mqtt directly\n", __func__);
|
|
|
|
lws_dll2_remove(&wsi->dll2_cli_txn_queue);
|
|
|
|
wsi->client_mux_substream = 1;
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
lws_vhost_unlock(wsi->a.vhost); /* } ---------- */
|
2021-04-04 04:06:24 +01:00
|
|
|
lws_context_unlock(wsi->a.context); /* -------------- cx { */
|
2020-02-25 13:28:25 +00:00
|
|
|
|
|
|
|
return ACTIVE_CONNS_MUXED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the connection is viable but not yet in a usable
|
|
|
|
* state, let's attach ourselves to it and wait for it
|
|
|
|
* to get there or fail.
|
|
|
|
*/
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_notice("%s: apply %s to txn queue on %s state 0x%lx\n",
|
|
|
|
__func__, lws_wsi_tag(wsi), lws_wsi_tag(w),
|
|
|
|
(unsigned long)w->wsistate);
|
2019-09-23 04:23:07 -07:00
|
|
|
/*
|
|
|
|
* ...let's add ourselves to his transaction queue...
|
2020-01-30 13:19:11 +00:00
|
|
|
* we are adding ourselves at the TAIL
|
2019-09-23 04:23:07 -07:00
|
|
|
*/
|
2020-01-30 13:19:11 +00:00
|
|
|
lws_dll2_add_tail(&wsi->dll2_cli_txn_queue,
|
2019-09-23 04:23:07 -07:00
|
|
|
&w->dll2_cli_txn_queue_owner);
|
|
|
|
|
2020-01-30 13:19:11 +00:00
|
|
|
if (lwsi_state(w) == LRS_IDLING) {
|
|
|
|
// lwsi_set_state(w, LRS_ESTABLISHED);
|
2020-04-15 20:57:00 +01:00
|
|
|
_lws_generic_transaction_completed_active_conn(&w, 0);
|
2020-01-30 13:19:11 +00:00
|
|
|
}
|
|
|
|
|
2019-09-23 04:23:07 -07:00
|
|
|
/*
|
2020-02-25 13:28:25 +00:00
|
|
|
* For eg, h1 next we'd pipeline our headers out on him,
|
2019-09-23 04:23:07 -07:00
|
|
|
* and wait for our turn at client transaction_complete
|
|
|
|
* to take over parsing the rx.
|
|
|
|
*/
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
lws_vhost_unlock(wsi->a.vhost); /* } ---------- */
|
2021-04-04 04:06:24 +01:00
|
|
|
lws_context_unlock(wsi->a.context); /* -------------- cx { */
|
2019-09-23 04:23:07 -07:00
|
|
|
|
|
|
|
*nwsi = w;
|
|
|
|
|
|
|
|
return ACTIVE_CONNS_QUEUED;
|
|
|
|
}
|
|
|
|
|
|
|
|
} lws_end_foreach_dll_safe(d, d1);
|
|
|
|
|
|
|
|
solo:
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
lws_vhost_unlock(wsi->a.vhost); /* } ---------------------------------- */
|
2021-04-04 04:06:24 +01:00
|
|
|
lws_context_unlock(wsi->a.context); /* -------------- cx { */
|
2019-09-23 04:23:07 -07:00
|
|
|
|
|
|
|
/* there is nobody already connected in the same way */
|
|
|
|
|
|
|
|
return ACTIVE_CONNS_SOLO;
|
|
|
|
}
|
|
|
|
#endif
|
2019-07-30 06:02:23 +01:00
|
|
|
#endif
|
2020-12-25 05:54:19 +00:00
|
|
|
|
|
|
|
const char *
|
|
|
|
lws_vh_tag(struct lws_vhost *vh)
|
|
|
|
{
|
|
|
|
return lws_lc_tag(&vh->lc);
|
|
|
|
}
|