This provides a way to get ahold of LWS_WITH_CONMON telemetry from Secure
Streams, it works the same with direct onward connections or via the proxy.
You can mark streamtypes with a "perf": true policy attribute... this
causes the onward connections on those streamtypes to collect information
about the connection performance, and the unsorted DNS results.
Streams with that policy attribute receive extra data in their rx callback,
with the LWSSS_FLAG_PERF_JSON flag set on it, containing JSON describing the
performance of the onward connection taken from CONMON data, in a JSON
representation. Streams without the "perf" attribute set never receive
this extra rx.
The received JSON is based on the CONMON struct info and looks like
{"peer":"46.105.127.147","dns_us":596,"sockconn_us":31382,"tls_us":28180,"txn_resp_us:23015,"dns":["2001:41d0:2:ee93::1","46.105.127.147"]}
A new minimal example minimal-secure-streams-perf is added that collects
this data on an HTTP GET from warmcat.com, and is built with a -client
version as well if LWS_WITH_SECURE_STREAMS_PROXY_API is set, that operates
via the ss proxy and produces the same result at the client.
Really not having any logs makes it difficult to know what is really
happening, but if that's you're thing this will align debug and release
modes to just have ERR and USER if you give WITH_NO_LOGS
There are a few build options that are trying to keep and report
various statistics
- DETAILED_LATENCY
- SERVER_STATUS
- WITH_STATS
remove all those and establish a generic rplacement, lws_metrics.
lws_metrics makes its stats available via an lws_system ops function
pointer that the user code can set.
Openmetrics export is supported, for, eg, prometheus scraping.
The state tracking and violation detection is very powerful at enforcing
only legal transitions, but if it's busy, we don't get to see which stream
had to problem. Add a pointer to the handle lc tag, do that rather than
just pass the handle so we can deal with ss and sspc handles cleanly.
The various stream transitions for direct ss, SSPC, smd, and
different protocols are all handled in different code, let's
stop hoping for the best and add a state transition validation
function that is used everywhere we pass a state change to a
user callback, and knows what is valid for the user state()
callback to see next, given the last state it was shown.
Let's assert if lws manages to violate that so we can find
where the problem is and provide a stricter guarantee about
what user state handler will see, no matter if ss or sspc
or other cases.
To facilitate that, move the states to start from 1, where
0 indicates the state unset.
Let's allow the proxy to pass back what the policy says about
the size of dsh buffer the client side of this streamtype
should have.
Defer clientsize dsh generation until we got the info back
from the proxy in the response to the initial packet. If
it's zero / unset in the policy, just go with 32KB.
Let's add a byte on the first message that sspc clients send,
indicating the version of the serialization protocol that the
client was built with.
Start the version at 1, we will add some more changes in other
patches and call v1 (now it has the versioning baked in)
the first real supported serialization version, this patch must
be applied with the next patches to actually represent v1
protocol changes.
This doesn't require user setting, the client is told what version
it supports in LWS_SSS_CLIENT_PROTOCOL_VERSION. The proxy knows
what version(s) it can support and loudly hangs up on the client
if it doesn't understand its protocol version.
This is a huge patch that should be a global NOP.
For unix type platforms it enables -Wconversion to issue warnings (-> error)
for all automatic casts that seem less than ideal but are normally concealed
by the toolchain.
This is things like passing an int to a size_t argument. Once enabled, I
went through all args on my default build (which build most things) and
tried to make the removed default cast explicit.
With that approach it neither change nor bloat the code, since it compiles
to whatever it was doing before, just with the casts made explicit... in a
few cases I changed some length args from int to size_t but largely left
the causes alone.
From now on, new code that is relying on less than ideal casting
will complain and nudge me to improve it by warnings.
This adds some new objects and helpers for keeping and logging
info on grouped allocations, a group is, eg, SS handles or client
wsis.
Allocated objects get a context-unique "tag" string intended to replace
%p / wsi pointers etc. Pointers quickly become confusing when
allocations are freed and reused, the tag string won't repeat
until you produce 2^64 objects in a context.
In addition the tag string documents the object group, with prefixes
like "wsi-" or "vh-" and contain object-specific additional
information like the vhost name, address / port or the role of the wsi.
At creation time the lws code can use a format string and args
to add whatever group-specific info makes sense, eg, a wsi bound
to a secure stream can also append the guid of the secure stream,
it's copied into the new object tag and so is still available
cleanly after the stream is destroyed if the wsi outlives it.
Since client_connect and request_tx can be called from code that expects
the ss handle to be in scope, these calls can't deal with destroying the
ss handle and must pass the lws_ss_state_return_t disposition back to
the caller to handle.
Currently only the low 8 bits of an SS state are proxied in a total packet
length of 8 octets. Keep that format and behaviour since all the defined
states fit in 8 bits, but also allow for 32-bit states using a packet length
of 11 octets with the same command.
This lets us proxy user states (from http mapping) which start at a user
base of 1000.
At the moment you can define and set per-stream metadata at the client,
which will be string-substituted and if configured in the policy, set in
related outgoing protocol specific content like h1 headers.
This patch extends the metadata concept to also check incoming protocol-
specific content like h1 headers and where it matches the binding in the
streamtype's metadata entry, make it available to the client by name, via
a new lws_ss_get_metadata() api.
Currently warmcat.com has additional headers for
server: lwsws (well-known header name)
test-custom-header: hello (custom header name)
minimal-secure-streams test is updated to try to recover these both
in direct and -client (via proxy) versions. The corresponding metadata
part of the "mintest" stream policy from warmcat.com is
{
"srv": "server:"
}, {
"test": "test-custom-header:"
},
If built direct, or at the proxy, the stream has access to the static
policy metadata definitions and can store the rx metadata in the stream
metadata allocation, with heap-allocated a value. For client side that
talks to a proxy, only the proxy knows the policy, and it returns rx
metadata inside the serialized link to the client, which stores it on
the heap attached to the stream.
In addition an optimization for mapping static policy metadata definitions
to individual stream handle metadata is changed to match by name.
Before this we simply proxy the CREATING state from the proxy
version of the stream to the client version of the stream.
However this can result in disordering of onward connection
attempt request happening before the client has called back its
CREATING (*state()), meaning that any metadata set in the
state handler is missed for the onward connection.
This patch suppresses the CREATING forwarded from the proxy
and instead does its own local CREATING state callback at the
time the proxy indicates that the remote stream creation
(ie, with the requested policy streamtype) succeeded.
This then guarantees that the client has seen CREATING, and
had a chance to set metadata there, before the onward connection
request goes out. Since metadata has higher priority at the
writeable than the onward connection request it also means
any metadata set in client CREATING gets sync'd to the proxy
before the onward connection.
Helpers remove casts and derefs.
Add additional pointer arithmetic in client_pss_to_sspc_h() helper to
remove dependency on handle_offset being the first thing in the userdata
Make the helper names explicit for different proxy and client pss handling,
so it should be clearer that client helpers belong in a client section and
vice versa.
We compute the refragmented flags when cutting up large client serialized
payload blocks. But we had a bug where we didn't actually apply it and
applied the original client flags on the fragments.
That causes a crisis because EOM is used to mark end of post body and
complete the transaction, that is then happening on the first fragment.
This one-liner corrects it to use the computed, refragmented flags on the
dsh fragments and eliminate the problem.
Correct a comment about payload layout and add detailed comments about
dsh handling at proxy.
Increase the post size so it shows up fragmentation issues at the proxy.
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).
This differentiates between client connections for retry / writeable requests
and explicit lws_ss_client_connect() api calls. The former effectively uses
retry / backoff, and the latter resets the retry / backoff.
If you receive ALL_RETRIES_FAILED due to the retry policy, you can do whatever
you need to do there and call lws_ss_client_connect() to try to connect again
with a fresh, reset retry / backoff state.
- Add low level system message distibution framework
- Add support for local Secure Streams to participate using _lws_smd streamtype
- Add apit test and minimal example
- Add SS proxy support for _lws_smd
See minimal-secure-streams-smd README.md
Secure Streams is an optional layer on top of lws that separates policy
like endpoint selection and tls cert validation into a device JSON
policy document.
Code that wants to open a client connection just specifies a streamtype name,
and no longer deals with details like the endpoint, the protocol (!) or anything
else other than payloads and optionally generic metadata; the JSON policy
contains all the details for each streamtype. h1, h2, ws and mqtt client
connections are supported.
Logical secure streams outlive any particular connection and supports "nailed-up"
connectivity regardless of underlying connection stability.