Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
    npro  
 Modern all-safe Rust Network Protocol library supporting h1, h2, h3, ws, wt sans-IO and with socket IO + tls
git clone https://npro.rs/repo/npro
 
root / fuzz / seeds / ws-client / ws-client-rsv1-no-ext.ws
Author[]Andy Green <andy@warmcat.com> 2026-10-04 12:26 UTC
Committer[]Andy Green <andy@warmcat.com> 2026-10-05 06:32 UTC
Tree6d0fa52c4b7466986ab011daee06790b9db08009   Raw Patch
 
npro-core, npro-test: follow C's state table to bd9c8170
npro-core, npro-test: follow C's state table to bd9c8170

C's series measuring its state table's coverage tested the rows its
suite never fired, fixed what that found, and dropped the rows nothing
can fire.  23 of those were rows npro has, and npro drops them too:

 - h1 client TRANSPORT_UP from WAITING_SSL, WAITING_CONNECT,
   H1C_ISSUE_HANDSHAKE, H1C_ISSUE_HANDSHAKE2 and
   H2_WAITING_TO_SEND_HEADERS (only the idle leader's UNCONNECTED one
   stays), and h1 / any server TRANSPORT_UP from SSL_INIT
 - QUEUED from H1C_ISSUE_HANDSHAKE2, REQ_ISSUE from IDLING, and
   REQ_HDRS_SENT / REQ_HDRS_SENT_BODY from WAITING_CONNECT
 - the h1 server's BODY_BEGIN from ESTABLISHED, and its BODY_DISCARD,
   TXN_COMPLETING and TXN_COMPLETED from ISSUING_FILE and
   AWAITING_FILE_READ
 - server RAW_UPGRADED from H1_UPGRADE and SSL_INIT, the h1 client's
   RAW_UPGRADED, and TLS_ACCEPT_QUEUED from SSL_INIT

No row npro has was added or reordered.  The comments follow C's on the
rows only an app misusing the api reaches, and on the crossed ws close,
which only ws over a mux stream gets to.

C's table rows are now R(...) and its trace names each row by its line
in wsi-state.c as it fires (LRSROW).  scripts/sync-c-states.sh keeps the
table with each line's number, the rows fired in rows-fired.txt, and
C's README.wsi-state-machines.md beside them, and runs C's suite in the
three builds C measures coverage over: the default, one adding socks5,
mqtt, the proxies, the async queue, fault injection and email, and one
with tls accepts on a worker.  CTEST_ARGS reaches ctest, to leave out a
test failing for reasons outside the state machines.  The comparison
test names C's row by its line when it fails.

These oracles are from this container: 712 tests pass in the three
builds, with api-test-ss-server-accept left out, which fails every run
in the worker build here (its listening sockets do not open with
LWS_MAX_SMP=2).  The container has no IPv6 and no gnutls, so C's rows
for a client's next address and quic to tcp do not fire here as they do
where C measures.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019kg5Eemy68ZaqDBcUJQG6J
diff --git a/crates/npro-core/src/state/table.rs b/crates/npro-core/src/state/table.rs index 064de47..5b492a4 100644 --- a/crates/npro-core/src/state/table.rs +++ b/crates/npro-core/src/state/table.rs @@ -115,19 +115,8 @@ pub(super) const fn row( // the transport finished: a server starts on the request, an h1 // client on sending one, the rest are up Event::TransportUp => match (role, side, from, site_role) { - ( - Role::H1, - Client, - St::Unconnected - | St::WaitingSsl - | St::WaitingConnect - | St::H1cIssueHandshake - | St::H1cIssueHandshake2, - None, - ) => live(Live::H1cIssueHandshake2), - (Role::H1, Client, St::H2WaitingToSendHeaders, None) => { - live(Live::H2WaitingToSendHeaders) - } + // inherited from an idle leader + (Role::H1, Client, St::Unconnected, None) => live(Live::H1cIssueHandshake2), ( Role::RawSkt, Client, @@ -137,12 +126,11 @@ pub(super) const fn row( | St::WaitingProxyReply, None, ) => live(Live::Established), - (Role::H1, Server, St::SslAckPending | St::AwaitingSslAccept | St::SslInit, None) => { + // the accept on a worker is AWAITING_SSL_ACCEPT + (Role::H1, Server, St::SslAckPending | St::AwaitingSslAccept, None) => { live(Live::Headers) } - (_, Server, St::SslAckPending | St::AwaitingSslAccept | St::SslInit, None) => { - live(Live::Established) - } + (_, Server, St::SslAckPending | St::AwaitingSslAccept, None) => live(Live::Established), // the non-tls fallback established the connection before the // accept path reports the transport up (_, Server, St::Established, None) => live(Live::Established), @@ -164,16 +152,14 @@ pub(super) const fn row( // a client request queued on, or issued by, a connection Event::Queued => match (side, from, site_role) { - (Client, St::Unconnected | St::H1cIssueHandshake2, None) => { - live(Live::H2WaitingToSendHeaders) - } + (Client, St::Unconnected, None) => live(Live::H2WaitingToSendHeaders), _ => None, }, Event::ReqIssue => match (role, side, from, site_role) { ( Role::H1, Client, - St::H2WaitingToSendHeaders | St::Established | St::Idling | St::WaitingServerReply, + St::H2WaitingToSendHeaders | St::Established | St::WaitingServerReply, None, ) => live(Live::H1cIssueHandshake2), _ => None, @@ -184,10 +170,7 @@ pub(super) const fn row( ( Role::H1, Client, - St::WaitingSsl - | St::WaitingConnect - | St::H1cIssueHandshake - | St::H1cIssueHandshake2, + St::WaitingSsl | St::H1cIssueHandshake | St::H1cIssueHandshake2, None, ) => live(Live::WaitingServerReply), _ => None, @@ -196,10 +179,7 @@ pub(super) const fn row( ( Role::H1, Client, - St::WaitingSsl - | St::WaitingConnect - | St::H1cIssueHandshake - | St::H1cIssueHandshake2, + St::WaitingSsl | St::H1cIssueHandshake | St::H1cIssueHandshake2, None, ) => live(Live::IssueHttpBody), _ => None, @@ -221,8 +201,11 @@ pub(super) const fn row( // transaction ends, from wherever it had got to Event::TxnCompleted => match (role, side, from, site_role) { (Role::H1, Client, St::Established, None) => live(Live::Idling), + // only an app reading on past the end of an unframed body (_, Client, St::Idling, None) => live(Live::Idling), (Role::H1, Server, St::TxnCompleting, None) => live(Live::TxnCompleted), + // from H1_UPGRADE, the upgrade refused; from TXN_COMPLETED, only + // an app completing twice ( Role::H1, Server, @@ -231,15 +214,15 @@ pub(super) const fn row( | St::DiscardBody | St::DoingTransaction | St::H1Upgrade - | St::TxnCompleted - | St::IssuingFile - | St::AwaitingFileRead, + | St::TxnCompleted, None, ) => live(Live::TxnCompleted), _ => None, }, - // request headers: the h1 server decides on the upgrade + // request headers: the h1 server decides on the upgrade; from + // ESTABLISHED, the next request after a file completion the app did + // not complete Event::ReqHdrsComplete => match (role, side, from, site_role) { (Role::H1, Server, St::Headers | St::Established, None) => live(Live::H1Upgrade), _ => None, @@ -257,7 +240,7 @@ pub(super) const fn row( // the request body Event::BodyBegin => match (role, side, from, site_role) { - (Role::H1, Server, St::Established | St::DoingTransaction, None) => live(Live::Body), + (Role::H1, Server, St::DoingTransaction, None) => live(Live::Body), _ => None, }, // an h1 body is complete before its answer is: the next request, @@ -266,8 +249,9 @@ pub(super) const fn row( (Role::H1, Server, St::Body, None) => live(Live::DoingTransaction), _ => None, }, - // the user completed the transaction before reading the body, maybe - // with a read of a file out on a worker, reaped by the completion + // the user completed the transaction before reading the body, or + // its completion waited for the answer to go and finds the body + // unread Event::BodyDiscard => match (role, side, from, site_role) { ( Role::H1, @@ -276,8 +260,6 @@ pub(super) const fn row( | St::Established | St::DoingTransaction | St::H1Upgrade - | St::IssuingFile - | St::AwaitingFileRead | St::TxnCompleting, None, ) => live(Live::DiscardBody), @@ -285,7 +267,9 @@ pub(super) const fn row( }, // the user completed the transaction with its answer still queued: - // completion waits for that to go + // completion waits for that to go. From DISCARD_BODY only an app + // writing after it completed reaches it, from TXN_COMPLETED only one + // answering again, and from TXN_COMPLETING only one completing twice Event::TxnCompleting => match (role, side, from, site_role) { ( Role::H1, @@ -296,9 +280,7 @@ pub(super) const fn row( | St::DoingTransaction | St::H1Upgrade | St::TxnCompleted - | St::IssuingFile - | St::TxnCompleting - | St::AwaitingFileRead, + | St::TxnCompleting, None, ) => live(Live::TxnCompleting), _ => None, @@ -399,30 +381,15 @@ pub(super) const fn row( _ => None, }, - // raw: from the request, the upgrade, the non-tls fallback on a tls - // listener, a kept-alive connection or a listener already raw; an h1 - // client's own raw upgrade + // raw, on a server: from the request, the non-tls fallback on a tls + // listener, or a later request on a kept-alive connection or a + // listener already raw Event::RawUpgraded => match (role, side, from, site_role) { - ( - _, - Server, - St::Headers | St::H1Upgrade | St::SslInit | St::SslAckPending | St::Established, - Some(_), - ) => change( + (_, Server, St::Headers | St::SslAckPending | St::Established, Some(_)) => change( RoleTo::Site, SideTo::Keep, RoleState::Live(Live::Established), ), - ( - Role::H1, - Client, - St::Established | St::WaitingServerReply, - None | Some(Role::RawSkt), - ) => change( - RoleTo::Named(Role::RawSkt), - SideTo::Keep, - RoleState::Live(Live::Established), - ), _ => None, }, @@ -487,9 +454,7 @@ pub(super) const fn row( _ => None, }, Event::TlsAcceptQueued => match (side, from, site_role) { - (Server, St::SslInit | St::SslAckPending, None) => { - transport(Transport::AwaitingSslAccept) - } + (Server, St::SslAckPending, None) => transport(Transport::AwaitingSslAccept), _ => None, }, Event::ConnFailed => match (side, site_role) { @@ -512,7 +477,10 @@ pub(super) const fn row( _ => None, }, // the peer's CLOSE, perhaps beating the one we were about to send: - // answer his and drop ours + // answer his and drop ours. Only ws over a mux stream gets that far, + // since its network connection goes on reading for its other + // streams; a ws connection of its own reads nothing more until its + // close has gone Event::WsPeerClose => match (role, from, site_role) { (Role::Ws, St::Established | St::WaitingToSendClose, None) => { close(Close::ReturnedClose) diff --git a/crates/npro-test/states/C-COMMIT b/crates/npro-test/states/C-COMMIT index 277d0a9..7590317 100644 --- a/crates/npro-test/states/C-COMMIT +++ b/crates/npro-test/states/C-COMMIT @@ -1 +1 @@ -2dc2a33c572e6131298898cb6c1ba73c1a9f456e client: mux queue deadline and idle check only exist with a mux role +bd9c8170d7d492e8bb3c5a68e470ff21d673fd3e client: a quic wsi racing tcp reads its server's first datagram diff --git a/crates/npro-test/states/README.lws.md b/crates/npro-test/states/README.lws.md new file mode 100644 index 0000000..665ada2 --- /dev/null +++ b/crates/npro-test/states/README.lws.md @@ -0,0 +1,423 @@ +# wsi state machines + +## The problem this solves + +A `struct lws` (wsi) has one state word, `wsistate`, and for most of the +life of the library its dynamic part was a single flat enum, `LRS_*`, with +36 values. Reading the transition trace from the whole ctest suite showed +that those 36 values are really the states of four independent machines that +happen to share one slot: + +|machine|what it tracks| +|---|---| +|transport|getting a socket to the peer: dns, connect, proxy / socks, the tls handshake or accept| +|carrier|the protocol handshake on top of the socket: h1 first request and reply, h2 preface and settings, mqtt connack, the h1 server's upgrade decision| +|transaction|the http request / response cycle and its body and file phases, or "established" for roles that have no transactions| +|close|the polite ws close, draining buffered tx, the staged tcp shutdown, dead| + +Because one slot can only hold one value, whenever two of these were active +at once (a ws connection in the middle of a close handshake, a client being +retargeted by a redirect, an h1 server holding a completed transaction while +the next request's headers arrive) the second machine's state was carried in +a per-wsi bool. Those bools were the real hazard: some resets cleared them +and some did not, and each reader had to know which bools qualified which +state. Of 203 distinct edges observed in ctest, 99 crossed from one machine +into another. + +The machines now each own their own bits of the word, are set only through +their own setters, and are listed in per-machine transition tables that a +debug build asserts against. This document is the specification of those +machines. The tables in `lib/sansio/wsi-state.c` are authoritative; this +describes what they mean. + +## The state word + +``` + 31 30 24 23 20 19 16 15 12 11 10 9 8 7 0 + [u][role ][carrier][transp] [ close ][- - ][nest][pocb][ state ] +``` + +|bits|holds|read with|set with| +|---|---|---|---| +|0-9|the live state: the transaction machine's `LRS_` value with its `LWSIFS_POCB` / `LWSIFS_NOT_EST` qualifiers|`lwsi_state_live()`|`lws_wsi_event()`| +|12-15|close machine, `enum lws_close_phase` `LCS_*`|`lwsi_close()`, and `lwsi_close_started()` for "`__lws_close_free_wsi()` has been entered"|`lws_wsi_event()`, a row to a close phase| +|16-19|transport machine, `enum lws_transport_phase` `LTS_*`|`lwsi_transport()`|`lws_wsi_event()`, a row to a transport phase| +|20-23|carrier machine, `enum lws_carrier_phase` `LCR_*`|`lwsi_carrier()`|`lws_wsi_event()` routes handshake states here| +|24-29|role flags: client / server side, h2 encapsulation|`lwsi_role_*()`|`lws_wsi_event()`, a row that names a side| +|30|`LWSIFS_SKT_UNUSABLE`: the socket is known dead, take the abortive close path|`lwsi_skt_unusable()`|`lwsi_set_skt_unusable()`| + +`lwsi_state()` still returns a single `LRS_` value for the many readers that +only need to know "what is this connection doing right now": it reports the +close machine if one is set, else the transport machine, else the carrier +handshake if one is in progress, else the live state. That precedence is +what the old flat enum was approximating. `lwsi_state_live()` reads the +live bits underneath a close, so what the connection was doing when it +started to close stays visible. + +Bit 30 is an attribute of the live state rather than a machine: it +survives a live-state change, and `lws_role_transition()` carries it +across a role change, except that a restart to `LRS_UNCONNECTED` (redirect, +auth retry, h3 to tcp fallback) drops it, since the new connection has its +own socket. + +## Transport machine + +Client side, in order: + +``` +UNCONNECTED -> WAITING_DNS -> WAITING_CONNECT -> [proxy] -> [WAITING_SSL] -> (carrier) +``` + +where `[proxy]` is `WAITING_PROXY_REPLY` for an http CONNECT proxy, or +`WAITING_SOCKS_GREETING_REPLY -> [WAITING_SOCKS_AUTH_REPLY ->] +WAITING_SOCKS_CONNECT_REPLY` for socks5. `WAITING_SSL -> WAITING_CONNECT` +is a retry on another address or transport, the quic to tcp fallback. `WAITING_DNS -> +UNCONNECTED` is the dns retry. + +Server side, for a tls listener: `SSL_INIT -> SSL_ACK_PENDING` (accept in +progress, may bounce through `AWAITING_SSL_ACCEPT` when the accept is on an +async worker) and then the first carrier or transaction state. + +Two terminal sub-phases report as `UNCONNECTED` to `lwsi_state()` but are +distinct in the bits: + +- `LTS_FAILED`: the connect was reported failed to the user + (`lws_inform_client_conn_fail()`); the close must not report it again. + It can be entered from any phase, including from an established + connection when a happy-eyeballs leader passes on its powers. +- `LTS_RESTARTING`: `lws_client_reset()` is retargeting the wsi; it has no + live state until the pickup's `lws_role_transition(UNCONNECTED)`. Only a + client can be in it, and no live state may be set while it is. + +The transport phase ends implicitly: setting any live or carrier state +clears the transport bits. + +## Carrier machine + +|role|phases| +|---|---| +|h1 client|`H1C_ISSUE_HANDSHAKE` (before tls) -> `H1C_ISSUE_HANDSHAKE2` (sending the first request) -> `WAITING_SERVER_REPLY` (first response headers)| +|h2 client|`H2_AWAIT_PREFACE` -> `H2_WAITING_TO_SEND_HEADERS` (per stream) -> `WAITING_SERVER_REPLY`| +|h2 server|`H2_AWAIT_PREFACE` -> `H2_AWAIT_SETTINGS`| +|h3 client|`H2_WAITING_TO_SEND_HEADERS` -> `WAITING_SERVER_REPLY`| +|h1 server|`H1_UPGRADE`: an Upgrade: header was seen, deciding between ws, h2c and refusing| +|mqtt client|`MQTTC_IDLE` -> `MQTTC_AWAIT_CONNACK`| + +The carrier is `LCR_ESTABLISHED` from the first transaction state onward. +Carrier and transaction are sequential, not stacked, and the same `LRS_` +names are reused per transaction: an h1 client re-enters +`H1C_ISSUE_HANDSHAKE2` and `WAITING_SERVER_REPLY` for each pipelined request. +A handshake-named state is routed into the carrier bits only while the +carrier is not yet established; afterwards it is a per-transaction phase in +the live bits. So "is this client still waiting for its first +response" is `lwsi_carrier() == LCR_WAITING_SERVER_REPLY`, while "is a +response pending" is `lwsi_hdrs_pending()`. + +## Transaction machine + +### h1 server + +``` +HEADERS ---(request parsed)---> ESTABLISHED ---> DOING_TRANSACTION <------+ + ^ | | \--> ISSUING_FILE <-> AWAITING_FILE_READ + | | \-------> BODY ---(body complete)--+ + | | | \--> DISCARD_BODY + | v | | + +-------------- TXN_COMPLETED <------------------+---------+ +``` + +- `HEADERS`: idle between requests, or reading one. A server is in + `HEADERS` from accept until it has a request to act on. +- `ESTABLISHED`: acting on a parsed request; the user callback is being + driven. It also carries `H1_UPGRADE` out to the carrier when the request + asked for one. +- `DOING_TRANSACTION`: a mount action (cgi, proxy, file) is in progress, + or the request body is complete and its answer is still to come. What + the peer sent after the request is the next pipelined one: it stays + parked until the transaction completes. +- `BODY` / `DISCARD_BODY`: a request body is being delivered, or drained + because the user finished before reading it. An h1 body that completes + goes on to `DOING_TRANSACTION`, whatever answers it. +- `ISSUING_FILE` / `AWAITING_FILE_READ`: a file is being served, the latter + while an async read is out on a worker. The user may complete the + transaction from either: the completion reaps a read still out. The + answer is then short of its framing, and an h1 connection is closed + (as for any answer completed short of the `Content-Length` lws added); + an h2 or h3 stream goes on as from anywhere else, to `TXN_COMPLETING` or + `DISCARD_BODY`. +- `TXN_COMPLETING`: the user completed the transaction while its response + was still queued, by the transport or the compressor. Nothing more is + read; when the queue has gone (the role's `tx_drained`), the completion + happens, to `TXN_COMPLETED`, or first `DISCARD_BODY` for a request body + still unread. +- `TXN_COMPLETED`: `lws_http_transaction_completed()` ran; hold here until + the connection is writable and buffered tx has drained, then back to + `HEADERS` for keep-alive or close. + +### h2 and h3 server streams + +A stream is born `HEADERS`. From there `DEFERRING_ACTION` (headers complete, +the action is deferred to POLLOUT and any body is stashed) or straight to +`DOING_TRANSACTION`; `DEFERRING_ACTION -> ESTABLISHED` when it runs. The +same `BODY`, `ISSUING_FILE`, `AWAITING_FILE_READ` and `TXN_COMPLETING` +phases apply. A mux stream has no `TXN_COMPLETED`: completion closes the +stream. The h2 network +connection itself sits in `ESTABLISHED` after settings, as does an h3 +server's own unidirectional control streams. + +### h1 client + +``` +(carrier) --> ESTABLISHED --> IDLING + | ^ | + | +-- WAITING_SERVER_REPLY <-- ISSUE_HTTP_BODY <-- H1C_ISSUE_HANDSHAKE2 + +---------------^ +``` + +- `ESTABLISHED`: response headers received, the response body is being + delivered. +- `ISSUE_HTTP_BODY`: request headers sent, the user is supplying a body. +- `WAITING_SERVER_REPLY`: a request is out, response headers pending. A + 1xx interim response rewinds to here. +- `IDLING`: keep-alive, nothing in flight; the connection is kept warm for + the `keep_warm_secs` of the request that last used it, and a new request + to the same endpoint in that time is handed the connection (it re-enters + `H1C_ISSUE_HANDSHAKE2` from the pipeline queue). Nothing turns up: the + keep-warm timeout closes it in good order. + +### h2 and h3 client streams + +A stream is born in `H2_WAITING_TO_SEND_HEADERS`, sends its headers +(`ISSUE_HTTP_BODY` if it has a body) and waits in `WAITING_SERVER_REPLY`; +the response headers bring it to `ESTABLISHED` and `BODY`. The network +connection is `ESTABLISHED` from the moment its own first request moves to +the sid-1 child (it carries streams only from then on), goes `IDLING` when +its last stream closes with nothing queued (`LAST_STREAM_CLOSED`) and is +revived to `ESTABLISHED` when a new one joins (`CONN_REUSED`), so on every +client `ESTABLISHED` means a response is in flight and `IDLING` means +nothing is. While `IDLING` the connection is kept warm for the +`keep_warm_secs` of the request that last used it, with its tcp + tls +already up for a new request to the same endpoint; the peer's PINGs and +WINDOW_UPDATEs do not extend that, only a new stream (which drops the +timeout) does. Nothing joins: the keep-warm timeout closes it in good +order. + +`IDLING` does not carry `POCB`, but a kept-warm mux connection still +services its own POLLOUT: for a network connection POLLOUT is the +connection's business (its pps queue, and the walk of children wanting to +write), not the transaction's. Skipping it would leave a POLLOUT that was +already asserted when the last stream closed set forever, spinning the +event loop. + +### Other roles + +raw sockets, raw files, pipes, dbus, mqtt and quic have no transactions: +they enter `ESTABLISHED` when usable and stay there. For a raw client the +adoption callback has been delivered exactly when `lwsi_carrier()` is +`LCR_ESTABLISHED`. + +## Close machine + +The close machine runs on top of the others without disturbing them. + +``` + +--> WAITING_TO_SEND_CLOSE --> AWAITING_CLOSE_ACK --+ +(ws, we close) | | + | v +(ws, peer closed) --> RETURNED_CLOSE --> FLUSHING_BEFORE_CLOSE --> [SHUTDOWN] --> DEAD_SOCKET --> USER_TOLD + ^ +(anything else) --> CLOSING -----------------+ + ^ +(live, raw / h3) --> CLOSE_WHEN_FLUSHED -----+ +``` + +- `WAITING_TO_SEND_CLOSE`: we initiated a ws close and have a CLOSE frame + to send (initiator only, on every side and carrier). +- `AWAITING_CLOSE_ACK`: our CLOSE was sent, waiting for the peer's. +- `RETURNED_CLOSE`: the peer's CLOSE arrived first; we answer it as a PONG + would be, then close. One encoding on both sides. +- `CLOSING`: `__lws_close_free_wsi()` has been entered with nothing yet to + wait for. `lwsi_state()` goes on reporting the live state underneath. +- `FLUSHING_BEFORE_CLOSE`: the close drains buffered tx first. Entered from + any state by `lws_close_free_wsi()` when a partial is outstanding. +- `CLOSE_WHEN_FLUSHED`: a live connection is to be closed once its buffered + tx has drained: `lws_raw_transaction_completed()` on a raw socket, an h3 + stream whose action completed. Until the close is entered what it sends + still goes; entering the close makes the flush the close's own. + `lwsi_state()` reports it as `FLUSHING_BEFORE_CLOSE`. +- `SHUTDOWN`: server side only, tcp half-close sent, waiting for the peer's + FIN so the close is not seen as abortive; never on a raw socket or without + a socket. +- `DEAD_SOCKET`: out of the fd table, being freed. `USER_TOLD` is the same + state after the user's CLOSED callback ran. + +The phases are numbered `CLOSE_WHEN_FLUSHED`, `CLOSING`, +`WAITING_TO_SEND_CLOSE`, `RETURNED_CLOSE`, `AWAITING_CLOSE_ACK`, +`FLUSHING_BEFORE_CLOSE`, `SHUTDOWN`, `DEAD_SOCKET`, `USER_TOLD`, and the +machine only goes forwards: an event that would take a wsi to an +earlier phase than the one it is in has no row, even from a row that +accepts any source state. So a late `lws_raw_transaction_completed()` on a +connection whose close already went further cannot start it again, and a +check like `lwsi_close(wsi) >= LCS_DEAD_SOCKET` stays true once it is. + +Invariants the checker enforces: an unusable socket never enters +`WAITING_TO_SEND_CLOSE`, `RETURNED_CLOSE`, `AWAITING_CLOSE_ACK` or +`SHUTDOWN`; `RETURNED_CLOSE` only on a ws role; `SHUTDOWN` only on a server +wsi with a socket; the close phase never goes backwards. + +## Role changes + +A role or side change is an event like any other: the row names the role +and side that follow, or takes them from the site (the ops argument of +`lws_wsi_event_role()` for adoption, the client bind and a restart, which +are the site's to choose), from the mux parent (a fresh child is its +parent's), or from a wsi the site says the new one is like +(`lws_wsi_event_x()`, for our own h3 control streams and a wsi taking over +a quic connection). So the h1 to h2 / ws upgrades, quic to h3 at ALPN, the +client's sid-1 migration, a stream let onto its connection, webtransport, +raw, and the restart to `UNCONNECTED` on redirect or fallback all read as +`ev=NAME` on a `role_transition` edge in the trace. The only role write +without an event is a wsi's birth, where the creator hands in the ops. + +Underneath, `lws_wsi_role_transition_ev()` rewrites the whole word: side +flags, a transport or carrier state into its bits over an `UNCONNECTED` +live state, or a live state with the carrier marked established. + +## Build options + +|option|effect| +|---|---| +|`LWS_WITH_STATE_TRACE`|append each distinct `(role, state) -> (role, state)` edge the process performs, once, to `$LWS_STATE_TRACE_FILE` (stderr if unset), as `LRS h1/S:HEADERS -> h1/S:ESTABLISHED set_state <wsi tag>`. Attributes show as `+unusable`, `+failed`, `+restarting`, `+closing`, `+told`. Also append, the first time the process fires each row of the event table, `LRSROW 366 h1 S ESTABLISHED REQ_HDRS_COMPLETE`: the row's source line in `wsi-state.c`, then its own role, side, from state (`ANY` for any) and event. A row counts when it is matched, including one whose edge changes nothing the `LRS` lines show, eg, a state to itself| +|`LWS_WITH_STATE_CHECK`|look every edge up: a live-state edge must be one the event table produces, a phase or role change must carry an event's name (the engine made it from a row) or be a birth; `abort()` on one that is not, or that breaks an invariant, logging `unlisted wsi state edge ...` or `invariant broken on wsi state edge ...`; an event with no row aborts too| + +Both are off by default and change nothing about what any transition does. +To regenerate the observed edge set, build with the trace on and run + +``` +LWS_STATE_TRACE_FILE=/tmp/edges.txt ctest +``` + +then `sort -u` the file. The event table in `wsi-state.c` is the +transition function itself; its rows were derived from the observed edge +set over the ctest suite and the fuzz seed corpus plus the statically +present edges nothing reaches. A new edge is either an omission in the +table or a bug at the site. + +### Row coverage + +Which rows of the event table the tests fire, from the same trace: + +``` +rm -f /tmp/t ; LWS_STATE_TRACE_FILE=/tmp/t ctest -j4 +scripts/state-row-coverage.sh /tmp/t +``` + +The script lists each row no `LRSROW` line names, as +`wsi-state.c:<line>: role side from event`, then per row role how many +rows fired out of how many there are. It takes several trace files, so +the runs of differently configured builds add up. The rows are known by +their line numbers, so the trace must come from a build of the same +`wsi-state.c` the script reads (`$LWS_WSI_STATE_C`, by default the one in +its own tree). A row only some build options can reach needs a build with +them: the default build has no `LWS_WITH_ASYNC_QUEUE`, `LWS_WITH_SOCKS5`, +`LWS_ROLE_MQTT`, `LWS_WITH_HTTP_PROXY`, `LWS_ROLE_RAW_PROXY` or +`LWS_WITH_SYS_FAULT_INJECTION` (the seeded ws client transcripts of +`api-test-sansio`), and the tls accept on a worker needs +`LWS_WITH_ASYNC_QUEUE` with `LWS_MAX_SMP` above 1. A row no build fires +is either dead, or its comment says which configuration reaches it. + +### Rows no test fires + +Over the default build, one adding those options and `LWS_WITH_EMAIL`, and +one with `LWS_WITH_ASYNC_QUEUE` and `LWS_MAX_SMP=2`, these rows are never +fired, by role, side, from state and event: + +Reachable, but not by lws on its own: + +|row|what reaches it| +|---|---| +|`quic C WAITING_CONNECT TRANSPORT_UP`|the quic handshake finishing while the tcp fallback racer's connect is still pending: on loopback that wants packet filtering, which no portable test has| +|`quic * UNCONNECTED STREAM_OPENED`|the peer opening another stream on a quic connection whose alpn is not h3: lws has no api to open another raw quic stream, so only a foreign peer does| +|`h3 S ESTABLISHED BODY_DISCARD`, `h3 S DOING_TRANSACTION BODY_DISCARD`, `h3 S BODY BODY_DISCARD`, `h3 S ISSUING_FILE BODY_DISCARD`, `h3 S AWAITING_FILE_READ BODY_DISCARD`|as the h2 ones, but an h3 stream counts its unacknowledged frames as queued, so a completion only finds nothing queued when everything it wrote was acknowledged: an app completing without answering, or a file stalled on a peer withholding stream credit, which lws' own client grants as it reads| +|`h3 S AWAITING_FILE_READ TXN_COMPLETING`|a file answer given up on with its read held on a worker (`LWS_WITH_ASYNC_QUEUE`), which the sansio h2 case holds but nothing can hold on real sockets| +|`h2 S HEADERS TXN_COMPLETING`|an h2c upgrade's stream 1 answered before its action with an answer written at once, while the connection still holds part of the 101; the answers before the action are a status page, written later, or a redirect, which the h1 handshake gives before the upgrade| + +Only by an app misusing the api: + +|row|what reaches it| +|---|---| +|`h1 S ESTABLISHED REQ_HDRS_COMPLETE`, `* S ESTABLISHED RAW_UPGRADED`|the next request after a file completion the app did not complete| +|`h1 S DISCARD_BODY TXN_COMPLETING`, `h1 S TXN_COMPLETED TXN_COMPLETING`|writing after completing| +|`h1 S TXN_COMPLETING TXN_COMPLETING`, `h2 S TXN_COMPLETING TXN_COMPLETING`, `h1 S TXN_COMPLETED TXN_COMPLETED`|completing twice| +|`* C IDLING TXN_COMPLETED`|reading on past the end of an unframed response body| + +Defensive, no path known to reach them: + +|row|why it is there| +|---|---| +|`* C UNCONNECTED ALPN_DONE`, `* C WAITING_CONNECT ALPN_DONE`|the h3 alpn walk looks for children in these states, which no path is known to leave them in| +|`h3 * ESTABLISHED BODY_BEGIN`|DATA on a stream whose body completed with its request headers kept, a proxy leg's: only beyond its Content-Length, which is refused first| +|`h3 S DISCARD_BODY TXN_COMPLETING`|entering DISCARD_BODY wants nothing unacknowledged, so the stream would have to write after completing| + +## Events + +The sites of the carrier and transaction machines do not name the state +they want; they report what happened with `lws_wsi_event(wsi, LWS_WSIEV_*)` +and the event table in `wsi-state.c` says what state that lands in, by +role, side and current state. The same event lands in different states by +role (request headers complete is `H1_UPGRADE` on an h1 server and +`DEFERRING_ACTION` on a mux stream), and a site does not choose. The +site-local facts that used to pick the state (is a body pending, was an +upgrade asked for) are distinct events instead, so the information is in +the word rather than in a bool beside it. An event with no row is a bug +at the site: the state is left alone, an error is logged, and +`LWS_WITH_STATE_CHECK` aborts. The trace shows the event on each edge as +`ev=NAME`. Nothing else writes any of the four machines, a role or a +side: there is no setter for them outside `wsi-state.c`, only the events, +and a wsi's birth. + +The transport and close machines are driven the same way: a row whose +target is a transport or close phase (`XT()` / `XC()` in the table) sets +that machine's bits, over whatever the others were doing. Their events +read as what happened on the wire or in the close flow: `DNS_START`, +`CONNECT_START`, `TLS_START`, `TLS_ACCEPT_PENDING`, `CONN_FAILED`, +`RETARGET`; `WS_CLOSE_INITIATED`, `WS_CLOSE_SENT`, `WS_PEER_CLOSE`, +`CLOSE_FLUSH`, `CLOSE_STAGED`, `SOCKET_GONE`, `USER_TOLD`. + +An established raw client whose own protocol starts tls on it (STARTTLS, +`lws_tls_client_upgrade()`) goes back into the transport machine: `TLS_START` +from `ESTABLISHED` sets `WAITING_SSL` over the established carrier, and +`TRANSPORT_UP` returns it to `ESTABLISHED`. That combination, +`lwsi_tls_upgrading()`, is how the rest of lws knows the user was already +told the connection is up: he is told again when the tls is up, and a +handshake that fails is his close, not a failure to connect. + +The events, with the states they lead to: + +|event|h1 server|h2 / h3 server stream|h1 client|h2 / h3 client stream| +|---|---|---|---|---| +|request headers complete, no upgrade|`ESTABLISHED`|`DEFERRING_ACTION` or `DOING_TRANSACTION`||| +|request headers complete, upgrade asked|`H1_UPGRADE`|||| +|action deferred now runs||`ESTABLISHED`||| +|action started|`DOING_TRANSACTION`|`DOING_TRANSACTION`||| +|file serving started|`ISSUING_FILE`|`ISSUING_FILE`||| +|file read handed to a worker / returned|`AWAITING_FILE_READ` / `ISSUING_FILE`|same||| +|file sent|`ESTABLISHED`|`ESTABLISHED`||| +|body starts|`BODY`|`BODY`||`BODY`| +|body complete|`DOING_TRANSACTION`|`ESTABLISHED`||| +|user finished before the body|`DISCARD_BODY`|||| +|transaction completed|`TXN_COMPLETED`|(stream closes)|`IDLING`, or `H1C_ISSUE_HANDSHAKE2` with a pipelined next|| +|writable after completion, tx drained|`HEADERS`|||| +|request headers sent, body pending|||`ISSUE_HTTP_BODY`|`ISSUE_HTTP_BODY`| +|request headers sent, no body|||`WAITING_SERVER_REPLY`|`WAITING_SERVER_REPLY`| +|request body sent|||`WAITING_SERVER_REPLY`|`WAITING_SERVER_REPLY`| +|response headers complete|||`ESTABLISHED` (role may change to ws)|`ESTABLISHED` (or ws encapsulated)| +|1xx interim response|||`WAITING_SERVER_REPLY`|| +|auth challenge, retrying|||`H1C_ISSUE_HANDSHAKE2`|| +|stream opened by the peer||`HEADERS`||| +|stream let onto its connection||||`H2_WAITING_TO_SEND_HEADERS`| +|last stream closed, nothing queued (connection)||||`IDLING`| +|idle connection gets a new stream (connection)||||`ESTABLISHED`| + +`ESTABLISHED` means one thing on each side: on a server, acting on a +parsed request; on a client, a response in flight. diff --git a/crates/npro-test/states/README.md b/crates/npro-test/states/README.md index 832a178..0d2ec7d 100644 --- a/crates/npro-test/states/README.md +++ b/crates/npro-test/states/README.md @@ -7,21 +7,36 @@ tree at the commit in `C-COMMIT`, are what `tests/states.rs` holds them to. | file | what it is | |---|---| -| `wsi-event-edges.txt` | the rows of C's event table, `lws_wsi_event_edges[]`, verbatim | -| `edges.txt` | every distinct state edge C's ctest suite took, from a build with `LWS_WITH_STATE_TRACE`, sorted, with each connection's tag removed | -| `C-COMMIT` | the C commit both came from | - -The test drives every state npro's machines can reach from a connection's -birth with every event, both through npro and through a model of C's -machines written in C's terms that reads its rows from -`wsi-event-edges.txt`, and requires them to agree: on refusing it, on the -machines after, on the setter, and on the trace line. Then every edge in -`edges.txt` between npro's roles must be one npro takes. - -The C suite ran with `LWS_WITH_STATE_CHECK` too, which aborts on any edge -the table does not allow, and passed: the observed edges are all the -table's. `edges.txt` holds every role's edges, not only npro's, so that -the roles arriving later are checked against the same run. +| `wsi-event-edges.txt` | C's event table, `lws_wsi_event_edges[]`, each line prefixed by its line in `wsi-state.c`, by which C's trace names a row | +| `edges.txt` | every distinct state edge C's ctest suite took, from builds with `LWS_WITH_STATE_TRACE`, sorted, with each connection's tag removed | +| `rows-fired.txt` | every row of the table the suite fired: C's `LRSROW` lines | +| `README.lws.md` | C's `README.wsi-state-machines.md`, whose "Rows no test fires" says which rows the suite never fires, and why | +| `C-COMMIT` | the C commit all of them came from | + +The suite runs in the three builds C's README measures coverage over: the +default, one adding the options some rows need (socks5, mqtt, the http +and raw proxies, the async queue, fault injection, email), and one with +tls accepts on a worker. Each has `LWS_WITH_STATE_CHECK` too, which +aborts on any edge the table does not allow, and every test passed: the +observed edges are all the table's. + +The tests: + +- drive every state npro's machines can reach from a connection's birth + with every event, both through npro and through a model of C's machines + written in C's terms that reads its rows from `wsi-event-edges.txt`, and + require them to agree: on refusing it, on the machines after, on the + setter, and on the trace line; +- require every edge in `edges.txt` between npro's roles to be one npro + takes; +- require every row npro's machines can fire to be one C's suite fires, + or one C's README lists as never fired, with why. + +`edges.txt` and `rows-fired.txt` hold every role's, not only npro's, so +that the roles arriving later are checked against the same runs. A few +edges depend on timing, such as a stream closing while a file is still +being served, so two runs can differ by an edge or two. A refresh that +only adds edges like that needs no more than saying so. ## Refreshing @@ -29,5 +44,6 @@ the roles arriving later are checked against the same run. scripts/sync-c-states.sh ~/libwebsockets ``` -builds C with the trace and the check, runs its ctest suite, and replaces -these files. Say in the commit what moved, and why npro follows it. +builds C three times with the trace and the check, runs its ctest suite in +each, and replaces these files. Say in the commit what moved, and why npro +follows it. diff --git a/crates/npro-test/states/edges.txt b/crates/npro-test/states/edges.txt index 21b112a..db435ab 100644 --- a/crates/npro-test/states/edges.txt +++ b/crates/npro-test/states/edges.txt @@ -5,13 +5,17 @@ LRS (none)/-:(zero) -> pipe/-:UNCONNECTED role_transition LRS (none)/-:(zero) -> raw-file/-:UNCONNECTED role_transition LRS (none)/-:UNCONNECTED -> (none)/S:UNCONNECTED role_transition ev=SERVER_SIDE LRS (none)/-:UNCONNECTED -> h1/C:UNCONNECTED role_transition ev=CLIENT_BIND +LRS (none)/-:UNCONNECTED -> mqtt/C:UNCONNECTED role_transition ev=CLIENT_BIND +LRS (none)/-:UNCONNECTED -> raw-proxy/C:UNCONNECTED role_transition ev=CLIENT_BIND LRS (none)/-:UNCONNECTED -> raw-skt/C:UNCONNECTED role_transition ev=CLIENT_BIND LRS (none)/S:UNCONNECTED -> h1/S:HEADERS role_transition ev=ADOPTED LRS (none)/S:UNCONNECTED -> h1/S:SSL_INIT role_transition ev=ADOPTED_TLS LRS (none)/S:UNCONNECTED -> h2/C:UNCONNECTED role_transition ev=MUX_INSERTED LRS (none)/S:UNCONNECTED -> h2/S:H2_AWAIT_PREFACE role_transition ev=H2_SELECTED LRS (none)/S:UNCONNECTED -> h2/S:UNCONNECTED role_transition ev=MUX_INSERTED +LRS (none)/S:UNCONNECTED -> mqtt/C:UNCONNECTED role_transition ev=MUX_INSERTED LRS (none)/S:UNCONNECTED -> raw-file/S:ESTABLISHED role_transition ev=ADOPTED +LRS (none)/S:UNCONNECTED -> raw-proxy/S:ESTABLISHED role_transition ev=ADOPTED LRS (none)/S:UNCONNECTED -> raw-skt/S:ESTABLISHED role_transition ev=ADOPTED LRS (none)/S:UNCONNECTED -> raw-skt/S:SSL_INIT role_transition ev=ADOPTED_TLS LRS h1/C:DEAD_SOCKET -> h1/C:DEAD_SOCKET+told set_close ev=USER_TOLD @@ -21,7 +25,9 @@ LRS h1/C:DEAD_SOCKET+restarting -> h1/C:DEAD_SOCKET+restarting+unusable set_unus LRS h1/C:DEAD_SOCKET+restarting+unusable -> h1/C:UNCONNECTED role_transition ev=RESTART LRS h1/C:DEAD_SOCKET+told -> h1/C:DEAD_SOCKET+told+unusable set_unusable LRS h1/C:DEAD_SOCKET+told+unusable -> h1/C:DEAD_SOCKET+told set_unusable +LRS h1/C:DEAD_SOCKET+unusable -> h1/C:DEAD_SOCKET+told+unusable set_close ev=USER_TOLD LRS h1/C:ESTABLISHED -> h1/C:ESTABLISHED+closing set_close ev=CLOSE_ENTERED +LRS h1/C:ESTABLISHED -> h1/C:H1C_ISSUE_HANDSHAKE2 set_state ev=REQ_ISSUE LRS h1/C:ESTABLISHED -> h1/C:IDLING set_state ev=TXN_COMPLETED LRS h1/C:ESTABLISHED -> h1/C:UNCONNECTED+failed set_transport ev=CONN_FAILED LRS h1/C:ESTABLISHED -> h1/C:UNCONNECTED+restarting set_transport ev=RETARGET @@ -41,8 +47,11 @@ LRS h1/C:H2_WAITING_TO_SEND_HEADERS -> h1/C:H2_WAITING_TO_SEND_HEADERS+unusable LRS h1/C:H2_WAITING_TO_SEND_HEADERS+closing -> h1/C:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h1/C:H2_WAITING_TO_SEND_HEADERS+unusable -> h1/C:UNCONNECTED+failed+unusable set_transport ev=CONN_FAILED LRS h1/C:IDLING -> h1/C:IDLING+closing set_close ev=CLOSE_ENTERED +LRS h1/C:IDLING -> h1/C:IDLING+unusable set_unusable LRS h1/C:IDLING -> h1/C:UNCONNECTED+failed set_transport ev=CONN_FAILED LRS h1/C:IDLING+closing -> h1/C:DEAD_SOCKET set_close ev=SOCKET_GONE +LRS h1/C:IDLING+closing+unusable -> h1/C:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE +LRS h1/C:IDLING+unusable -> h1/C:IDLING+closing+unusable set_close ev=CLOSE_ENTERED LRS h1/C:ISSUE_HTTP_BODY -> h1/C:WAITING_SERVER_REPLY set_state ev=REQ_BODY_SENT LRS h1/C:UNCONNECTED -> h1/C:H1C_ISSUE_HANDSHAKE2 set_state ev=TRANSPORT_UP LRS h1/C:UNCONNECTED -> h1/C:H2_WAITING_TO_SEND_HEADERS set_state ev=QUEUED @@ -60,6 +69,7 @@ LRS h1/C:WAITING_CONNECT -> h1/C:H1C_ISSUE_HANDSHAKE set_state ev=SOCKET_CONNECT LRS h1/C:WAITING_CONNECT -> h1/C:UNCONNECTED+failed set_transport ev=CONN_FAILED LRS h1/C:WAITING_CONNECT -> h1/C:WAITING_CONNECT+closing set_close ev=CLOSE_ENTERED LRS h1/C:WAITING_CONNECT -> h1/C:WAITING_PROXY_REPLY set_transport ev=PROXY_CONNECT_SENT +LRS h1/C:WAITING_CONNECT -> h1/C:WAITING_SOCKS_GREETING_REPLY set_transport ev=SOCKS_GREETING_SENT LRS h1/C:WAITING_CONNECT+closing -> h1/C:WAITING_CONNECT+closing+unusable set_unusable LRS h1/C:WAITING_CONNECT+closing+unusable -> h1/C:UNCONNECTED+failed+closing+unusable set_transport ev=CONN_FAILED LRS h1/C:WAITING_DNS -> h1/C:UNCONNECTED set_transport ev=DNS_RETRY @@ -68,20 +78,34 @@ LRS h1/C:WAITING_DNS -> h1/C:WAITING_CONNECT set_transport ev=CONNECT_START LRS h1/C:WAITING_DNS -> h1/C:WAITING_DNS+unusable set_unusable LRS h1/C:WAITING_PROXY_REPLY -> h1/C:H1C_ISSUE_HANDSHAKE set_state ev=SOCKET_CONNECTED LRS h1/C:WAITING_SERVER_REPLY -> h1/C:ESTABLISHED set_state ev=RESP_HDRS +LRS h1/C:WAITING_SERVER_REPLY -> h1/C:H1C_ISSUE_HANDSHAKE2 set_state ev=REQ_ISSUE LRS h1/C:WAITING_SERVER_REPLY -> h1/C:UNCONNECTED+failed set_transport ev=CONN_FAILED LRS h1/C:WAITING_SERVER_REPLY -> h1/C:WAITING_SERVER_REPLY+closing set_close ev=CLOSE_ENTERED LRS h1/C:WAITING_SERVER_REPLY -> h1/C:WAITING_SERVER_REPLY+unusable set_unusable LRS h1/C:WAITING_SERVER_REPLY -> ws/C:ESTABLISHED role_transition ev=WS_UPGRADED LRS h1/C:WAITING_SERVER_REPLY+closing -> h1/C:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h1/C:WAITING_SERVER_REPLY+unusable -> h1/C:UNCONNECTED+failed+unusable set_transport ev=CONN_FAILED +LRS h1/C:WAITING_SOCKS_AUTH_REPLY -> h1/C:WAITING_SOCKS_CONNECT_REPLY set_transport ev=SOCKS_CONNECT_SENT +LRS h1/C:WAITING_SOCKS_CONNECT_REPLY -> h1/C:H1C_ISSUE_HANDSHAKE set_state ev=SOCKET_CONNECTED +LRS h1/C:WAITING_SOCKS_GREETING_REPLY -> h1/C:WAITING_SOCKS_AUTH_REPLY set_transport ev=SOCKS_AUTH_SENT +LRS h1/C:WAITING_SOCKS_GREETING_REPLY -> h1/C:WAITING_SOCKS_CONNECT_REPLY set_transport ev=SOCKS_CONNECT_SENT LRS h1/C:WAITING_SSL -> h1/C:ISSUE_HTTP_BODY set_state ev=REQ_HDRS_SENT_BODY LRS h1/C:WAITING_SSL -> h1/C:WAITING_SERVER_REPLY set_state ev=REQ_HDRS_SENT -LRS h1/C:WAITING_SSL -> h1/C:WAITING_SSL+unusable set_unusable LRS h1/C:WAITING_SSL -> h2/C:H2_AWAIT_PREFACE role_transition ev=H2_SELECTED -LRS h1/C:WAITING_SSL+unusable -> h1/C:UNCONNECTED+failed+unusable set_transport ev=CONN_FAILED +LRS h1/S:AWAITING_FILE_READ -> h1/S:AWAITING_FILE_READ+closing set_close ev=CLOSE_ENTERED +LRS h1/S:AWAITING_FILE_READ -> h1/S:ISSUING_FILE set_state ev=FILE_READ_DONE +LRS h1/S:AWAITING_FILE_READ+closing -> h1/S:SHUTDOWN set_close ev=CLOSE_STAGED +LRS h1/S:AWAITING_SSL_ACCEPT -> h1/S:AWAITING_SSL_ACCEPT+unusable set_unusable +LRS h1/S:AWAITING_SSL_ACCEPT -> h1/S:HEADERS set_state ev=TRANSPORT_UP +LRS h1/S:AWAITING_SSL_ACCEPT -> h1/S:SSL_ACK_PENDING set_transport ev=TLS_ACCEPT_PENDING +LRS h1/S:AWAITING_SSL_ACCEPT+closing+unusable -> h1/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE +LRS h1/S:AWAITING_SSL_ACCEPT+unusable -> h1/S:AWAITING_SSL_ACCEPT+closing+unusable set_close ev=CLOSE_ENTERED LRS h1/S:BODY -> h1/S:BODY+closing set_close ev=CLOSE_ENTERED LRS h1/S:BODY -> h1/S:DISCARD_BODY set_state ev=BODY_DISCARD LRS h1/S:BODY -> h1/S:DOING_TRANSACTION set_state ev=BODY_COMPLETE +LRS h1/S:BODY -> h1/S:ISSUING_FILE set_state ev=FILE_BEGIN +LRS h1/S:BODY -> h1/S:TXN_COMPLETED set_state ev=TXN_COMPLETED +LRS h1/S:BODY -> h1/S:TXN_COMPLETING set_state ev=TXN_COMPLETING LRS h1/S:BODY+closing -> h1/S:SHUTDOWN set_close ev=CLOSE_STAGED LRS h1/S:DEAD_SOCKET -> h1/S:DEAD_SOCKET+told set_close ev=USER_TOLD LRS h1/S:DEAD_SOCKET -> h1/S:DEAD_SOCKET+unusable set_unusable @@ -100,14 +124,17 @@ LRS h1/S:DOING_TRANSACTION -> h1/S:TXN_COMPLETING set_state ev=TXN_COMPLETING LRS h1/S:DOING_TRANSACTION+closing -> h1/S:SHUTDOWN set_close ev=CLOSE_STAGED LRS h1/S:DOING_TRANSACTION+closing+unusable -> h1/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE LRS h1/S:DOING_TRANSACTION+unusable -> h1/S:DOING_TRANSACTION+closing+unusable set_close ev=CLOSE_ENTERED +LRS h1/S:ESTABLISHED -> h1/S:DISCARD_BODY set_state ev=BODY_DISCARD LRS h1/S:ESTABLISHED -> h1/S:DOING_TRANSACTION set_state ev=ACTION_BEGIN LRS h1/S:ESTABLISHED -> h1/S:ESTABLISHED+closing set_close ev=CLOSE_ENTERED LRS h1/S:ESTABLISHED -> h1/S:ISSUING_FILE set_state ev=FILE_BEGIN LRS h1/S:ESTABLISHED -> h1/S:TXN_COMPLETED set_state ev=TXN_COMPLETED +LRS h1/S:ESTABLISHED -> h1/S:TXN_COMPLETING set_state ev=TXN_COMPLETING LRS h1/S:ESTABLISHED+closing -> h1/S:SHUTDOWN set_close ev=CLOSE_STAGED LRS h1/S:H1_UPGRADE -> h1/S:DISCARD_BODY set_state ev=BODY_DISCARD LRS h1/S:H1_UPGRADE -> h1/S:ESTABLISHED set_state ev=REQ_PLAIN_HTTP LRS h1/S:H1_UPGRADE -> h1/S:H1_UPGRADE+closing set_close ev=CLOSE_ENTERED +LRS h1/S:H1_UPGRADE -> h1/S:ISSUING_FILE set_state ev=FILE_BEGIN LRS h1/S:H1_UPGRADE -> h1/S:TXN_COMPLETED set_state ev=TXN_COMPLETED LRS h1/S:H1_UPGRADE -> h1/S:TXN_COMPLETING set_state ev=TXN_COMPLETING LRS h1/S:H1_UPGRADE -> h2/S:H2_AWAIT_PREFACE role_transition ev=H2_SELECTED @@ -117,10 +144,12 @@ LRS h1/S:HEADERS -> h1/S:H1_UPGRADE set_state ev=REQ_HDRS_COMPLETE LRS h1/S:HEADERS -> h1/S:HEADERS+closing set_close ev=CLOSE_ENTERED LRS h1/S:HEADERS -> h1/S:HEADERS+unusable set_unusable LRS h1/S:HEADERS -> h2/S:H2_AWAIT_PREFACE role_transition ev=H2_SELECTED +LRS h1/S:HEADERS -> raw-skt/S:ESTABLISHED role_transition ev=RAW_UPGRADED LRS h1/S:HEADERS+closing -> h1/S:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h1/S:HEADERS+closing -> h1/S:SHUTDOWN set_close ev=CLOSE_STAGED LRS h1/S:HEADERS+closing+unusable -> h1/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE LRS h1/S:HEADERS+unusable -> h1/S:HEADERS+closing+unusable set_close ev=CLOSE_ENTERED +LRS h1/S:ISSUING_FILE -> h1/S:AWAITING_FILE_READ set_state ev=FILE_READ_QUEUED LRS h1/S:ISSUING_FILE -> h1/S:ESTABLISHED set_state ev=FILE_COMPLETE LRS h1/S:ISSUING_FILE -> h1/S:ISSUING_FILE+unusable set_unusable LRS h1/S:ISSUING_FILE+closing+unusable -> h1/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE @@ -128,14 +157,17 @@ LRS h1/S:ISSUING_FILE+unusable -> h1/S:ISSUING_FILE+closing+unusable set_close e LRS h1/S:SHUTDOWN -> h1/S:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h1/S:SHUTDOWN -> h1/S:SHUTDOWN+unusable set_unusable LRS h1/S:SHUTDOWN+unusable -> h1/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE +LRS h1/S:SSL_ACK_PENDING -> h1/S:AWAITING_SSL_ACCEPT set_transport ev=TLS_ACCEPT_QUEUED LRS h1/S:SSL_ACK_PENDING -> h1/S:HEADERS set_state ev=TRANSPORT_UP LRS h1/S:SSL_ACK_PENDING -> h1/S:SSL_ACK_PENDING+closing set_close ev=CLOSE_ENTERED LRS h1/S:SSL_ACK_PENDING -> h1/S:SSL_ACK_PENDING+unusable set_unusable -LRS h1/S:SSL_ACK_PENDING+closing -> h1/S:SHUTDOWN set_close ev=CLOSE_STAGED +LRS h1/S:SSL_ACK_PENDING -> raw-skt/S:ESTABLISHED role_transition ev=RAW_UPGRADED +LRS h1/S:SSL_ACK_PENDING+closing -> h1/S:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h1/S:SSL_ACK_PENDING+closing+unusable -> h1/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE LRS h1/S:SSL_ACK_PENDING+unusable -> h1/S:SSL_ACK_PENDING+closing+unusable set_close ev=CLOSE_ENTERED LRS h1/S:SSL_INIT -> h1/S:SSL_ACK_PENDING set_transport ev=TLS_ACCEPT_PENDING LRS h1/S:TXN_COMPLETED -> h1/S:HEADERS set_state ev=TXN_DRAINED +LRS h1/S:TXN_COMPLETING -> h1/S:DISCARD_BODY set_state ev=BODY_DISCARD LRS h1/S:TXN_COMPLETING -> h1/S:TXN_COMPLETED set_state ev=TXN_COMPLETED LRS h2/C:BODY -> h2/C:BODY+closing set_close ev=CLOSE_ENTERED LRS h2/C:BODY -> h2/C:BODY+unusable set_unusable @@ -154,13 +186,10 @@ LRS h2/C:DEAD_SOCKET+unusable -> h2/C:DEAD_SOCKET set_unusable LRS h2/C:DEAD_SOCKET+unusable -> h2/C:DEAD_SOCKET+told+unusable set_close ev=USER_TOLD LRS h2/C:ESTABLISHED -> h2/C:BODY set_state ev=BODY_BEGIN LRS h2/C:ESTABLISHED -> h2/C:ESTABLISHED+closing set_close ev=CLOSE_ENTERED -LRS h2/C:ESTABLISHED -> h2/C:ESTABLISHED+unusable set_unusable LRS h2/C:ESTABLISHED -> h2/C:IDLING set_state ev=LAST_STREAM_CLOSED LRS h2/C:ESTABLISHED -> h2/C:UNCONNECTED+failed set_transport ev=CONN_FAILED LRS h2/C:ESTABLISHED -> h2/C:UNCONNECTED+restarting set_transport ev=RETARGET LRS h2/C:ESTABLISHED+closing -> h2/C:DEAD_SOCKET set_close ev=SOCKET_GONE -LRS h2/C:ESTABLISHED+closing+unusable -> h2/C:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE -LRS h2/C:ESTABLISHED+unusable -> h2/C:ESTABLISHED+closing+unusable set_close ev=CLOSE_ENTERED LRS h2/C:H2_AWAIT_PREFACE -> h2/C:H2_WAITING_TO_SEND_HEADERS set_state ev=H2_PREFACE_SENT LRS h2/C:H2_WAITING_TO_SEND_HEADERS -> h2/C:ESTABLISHED set_state ev=MUX_MIGRATED LRS h2/C:H2_WAITING_TO_SEND_HEADERS -> h2/C:H2_WAITING_TO_SEND_HEADERS+closing set_close ev=CLOSE_ENTERED @@ -173,6 +202,7 @@ LRS h2/C:H2_WAITING_TO_SEND_HEADERS+unusable -> h2/C:H2_WAITING_TO_SEND_HEADERS+ LRS h2/C:IDLING -> h2/C:ESTABLISHED set_state ev=CONN_REUSED LRS h2/C:IDLING -> h2/C:IDLING+closing set_close ev=CLOSE_ENTERED LRS h2/C:IDLING+closing -> h2/C:DEAD_SOCKET set_close ev=SOCKET_GONE +LRS h2/C:ISSUE_HTTP_BODY -> h2/C:ESTABLISHED set_state ev=RESP_HDRS LRS h2/C:ISSUE_HTTP_BODY -> h2/C:WAITING_SERVER_REPLY set_state ev=REQ_BODY_SENT LRS h2/C:UNCONNECTED -> h2/C:H2_WAITING_TO_SEND_HEADERS role_transition ev=MUX_STREAM_ADOPTED LRS h2/C:UNCONNECTED+failed -> h2/C:UNCONNECTED+failed+closing set_close ev=CLOSE_ENTERED @@ -186,8 +216,17 @@ LRS h2/C:WAITING_SERVER_REPLY -> ws/Ce:ESTABLISHED role_transition ev=WS_UPGRADE LRS h2/C:WAITING_SERVER_REPLY+closing -> h2/C:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h2/C:WAITING_SERVER_REPLY+closing+unusable -> h2/C:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE LRS h2/C:WAITING_SERVER_REPLY+unusable -> h2/C:WAITING_SERVER_REPLY+closing+unusable set_close ev=CLOSE_ENTERED +LRS h2/S:AWAITING_FILE_READ -> h2/S:AWAITING_FILE_READ+unusable set_unusable +LRS h2/S:AWAITING_FILE_READ -> h2/S:DISCARD_BODY set_state ev=BODY_DISCARD +LRS h2/S:AWAITING_FILE_READ -> h2/S:ISSUING_FILE set_state ev=FILE_READ_DONE +LRS h2/S:AWAITING_FILE_READ -> h2/S:TXN_COMPLETING set_state ev=TXN_COMPLETING +LRS h2/S:AWAITING_FILE_READ+closing+unusable -> h2/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE +LRS h2/S:AWAITING_FILE_READ+unusable -> h2/S:AWAITING_FILE_READ+closing+unusable set_close ev=CLOSE_ENTERED LRS h2/S:BODY -> h2/S:BODY+closing set_close ev=CLOSE_ENTERED +LRS h2/S:BODY -> h2/S:DISCARD_BODY set_state ev=BODY_DISCARD LRS h2/S:BODY -> h2/S:ESTABLISHED set_state ev=BODY_COMPLETE +LRS h2/S:BODY -> h2/S:ISSUING_FILE set_state ev=FILE_BEGIN +LRS h2/S:BODY -> h2/S:TXN_COMPLETING set_state ev=TXN_COMPLETING LRS h2/S:BODY+closing -> h2/S:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h2/S:DEAD_SOCKET -> h2/S:DEAD_SOCKET+told set_close ev=USER_TOLD LRS h2/S:DEAD_SOCKET -> h2/S:DEAD_SOCKET+unusable set_unusable @@ -201,9 +240,16 @@ LRS h2/S:DEFERRING_ACTION -> h2/S:ESTABLISHED set_state ev=ACTION_DEFERRED_RUN LRS h2/S:DEFERRING_ACTION+closing -> h2/S:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h2/S:DEFERRING_ACTION+closing+unusable -> h2/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE LRS h2/S:DEFERRING_ACTION+unusable -> h2/S:DEFERRING_ACTION+closing+unusable set_close ev=CLOSE_ENTERED +LRS h2/S:DISCARD_BODY -> h2/S:DISCARD_BODY+closing set_close ev=CLOSE_ENTERED +LRS h2/S:DISCARD_BODY -> h2/S:TXN_COMPLETING set_state ev=TXN_COMPLETING +LRS h2/S:DISCARD_BODY+closing -> h2/S:DEAD_SOCKET set_close ev=SOCKET_GONE +LRS h2/S:DOING_TRANSACTION -> h2/S:DISCARD_BODY set_state ev=BODY_DISCARD LRS h2/S:DOING_TRANSACTION -> h2/S:DOING_TRANSACTION+closing set_close ev=CLOSE_ENTERED +LRS h2/S:DOING_TRANSACTION -> h2/S:ISSUING_FILE set_state ev=FILE_BEGIN +LRS h2/S:DOING_TRANSACTION -> h2/S:TXN_COMPLETING set_state ev=TXN_COMPLETING LRS h2/S:DOING_TRANSACTION+closing -> h2/S:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h2/S:ESTABLISHED -> h2/S:BODY set_state ev=BODY_BEGIN +LRS h2/S:ESTABLISHED -> h2/S:DISCARD_BODY set_state ev=BODY_DISCARD LRS h2/S:ESTABLISHED -> h2/S:DOING_TRANSACTION set_state ev=ACTION_BEGIN LRS h2/S:ESTABLISHED -> h2/S:ESTABLISHED+closing set_close ev=CLOSE_ENTERED LRS h2/S:ESTABLISHED -> h2/S:ESTABLISHED+unusable set_unusable @@ -214,6 +260,7 @@ LRS h2/S:ESTABLISHED+closing -> h2/S:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h2/S:ESTABLISHED+closing -> h2/S:SHUTDOWN set_close ev=CLOSE_STAGED LRS h2/S:ESTABLISHED+closing+unusable -> h2/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE LRS h2/S:ESTABLISHED+unusable -> h2/S:ESTABLISHED+closing+unusable set_close ev=CLOSE_ENTERED +LRS h2/S:FLUSHING_BEFORE_CLOSE -> h2/S:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h2/S:H2_AWAIT_PREFACE -> h2/S:H2_AWAIT_PREFACE+closing set_close ev=CLOSE_ENTERED LRS h2/S:H2_AWAIT_PREFACE -> h2/S:H2_AWAIT_PREFACE+unusable set_unusable LRS h2/S:H2_AWAIT_PREFACE -> h2/S:H2_AWAIT_SETTINGS set_state ev=H2_PREFACE_RX @@ -222,34 +269,65 @@ LRS h2/S:H2_AWAIT_PREFACE+closing+unusable -> h2/S:DEAD_SOCKET+unusable set_clos LRS h2/S:H2_AWAIT_PREFACE+unusable -> h2/S:H2_AWAIT_PREFACE+closing+unusable set_close ev=CLOSE_ENTERED LRS h2/S:H2_AWAIT_SETTINGS -> h2/S:ESTABLISHED set_state ev=H2_SETTINGS_ACKED LRS h2/S:HEADERS -> h2/S:DEFERRING_ACTION set_state ev=REQ_HDRS_COMPLETE +LRS h2/S:HEADERS -> h2/S:DOING_TRANSACTION set_state ev=ACTION_BEGIN LRS h2/S:HEADERS -> h2/S:HEADERS+closing set_close ev=CLOSE_ENTERED LRS h2/S:HEADERS -> h2/S:HEADERS+unusable set_unusable LRS h2/S:HEADERS -> h2/S:ISSUING_FILE set_state ev=FILE_BEGIN LRS h2/S:HEADERS+closing -> h2/S:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h2/S:HEADERS+closing+unusable -> h2/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE LRS h2/S:HEADERS+unusable -> h2/S:HEADERS+closing+unusable set_close ev=CLOSE_ENTERED +LRS h2/S:ISSUING_FILE -> h2/S:AWAITING_FILE_READ set_state ev=FILE_READ_QUEUED +LRS h2/S:ISSUING_FILE -> h2/S:DISCARD_BODY set_state ev=BODY_DISCARD LRS h2/S:ISSUING_FILE -> h2/S:ESTABLISHED set_state ev=FILE_COMPLETE LRS h2/S:ISSUING_FILE -> h2/S:ISSUING_FILE+closing set_close ev=CLOSE_ENTERED LRS h2/S:ISSUING_FILE -> h2/S:ISSUING_FILE+unusable set_unusable +LRS h2/S:ISSUING_FILE -> h2/S:TXN_COMPLETING set_state ev=TXN_COMPLETING LRS h2/S:ISSUING_FILE+closing -> h2/S:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h2/S:ISSUING_FILE+closing+unusable -> h2/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE LRS h2/S:ISSUING_FILE+unusable -> h2/S:ISSUING_FILE+closing+unusable set_close ev=CLOSE_ENTERED LRS h2/S:SHUTDOWN -> h2/S:DEAD_SOCKET set_close ev=SOCKET_GONE LRS h2/S:SHUTDOWN -> h2/S:SHUTDOWN+unusable set_unusable LRS h2/S:SHUTDOWN+unusable -> h2/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE +LRS h2/S:TXN_COMPLETING -> h2/S:DISCARD_BODY set_state ev=BODY_DISCARD LRS h2/S:TXN_COMPLETING -> h2/S:TXN_COMPLETING+closing set_close ev=CLOSE_ENTERED LRS h2/S:TXN_COMPLETING -> h2/S:TXN_COMPLETING+unusable set_unusable LRS h2/S:TXN_COMPLETING+closing -> h2/S:DEAD_SOCKET set_close ev=SOCKET_GONE +LRS h2/S:TXN_COMPLETING+closing -> h2/S:FLUSHING_BEFORE_CLOSE set_close ev=CLOSE_FLUSH LRS h2/S:TXN_COMPLETING+closing+unusable -> h2/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE LRS h2/S:TXN_COMPLETING+unusable -> h2/S:TXN_COMPLETING+closing+unusable set_close ev=CLOSE_ENTERED LRS h2/S:UNCONNECTED -> h2/S:HEADERS set_state ev=STREAM_OPENED LRS listen/-:DEAD_SOCKET -> listen/-:DEAD_SOCKET+unusable set_unusable LRS listen/-:DEAD_SOCKET+unusable -> listen/-:DEAD_SOCKET set_unusable LRS listen/-:UNCONNECTED -> listen/-:UNCONNECTED+closing set_close ev=CLOSE_ENTERED -LRS listen/-:UNCONNECTED -> listen/-:UNCONNECTED+unusable set_unusable LRS listen/-:UNCONNECTED+closing -> listen/-:DEAD_SOCKET set_close ev=SOCKET_GONE -LRS listen/-:UNCONNECTED+closing+unusable -> listen/-:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE -LRS listen/-:UNCONNECTED+unusable -> listen/-:UNCONNECTED+closing+unusable set_close ev=CLOSE_ENTERED +LRS mqtt/C:DEAD_SOCKET -> mqtt/C:DEAD_SOCKET+told set_close ev=USER_TOLD +LRS mqtt/C:DEAD_SOCKET -> mqtt/C:DEAD_SOCKET+unusable set_unusable +LRS mqtt/C:DEAD_SOCKET+told -> mqtt/C:DEAD_SOCKET+told+unusable set_unusable +LRS mqtt/C:DEAD_SOCKET+told+unusable -> mqtt/C:DEAD_SOCKET+told set_unusable +LRS mqtt/C:DEAD_SOCKET+unusable -> mqtt/C:DEAD_SOCKET set_unusable +LRS mqtt/C:DEAD_SOCKET+unusable -> mqtt/C:DEAD_SOCKET+told+unusable set_close ev=USER_TOLD +LRS mqtt/C:ESTABLISHED -> mqtt/C:ESTABLISHED+closing set_close ev=CLOSE_ENTERED +LRS mqtt/C:ESTABLISHED -> mqtt/C:ESTABLISHED+unusable set_unusable +LRS mqtt/C:ESTABLISHED+closing -> mqtt/C:DEAD_SOCKET set_close ev=SOCKET_GONE +LRS mqtt/C:ESTABLISHED+closing+unusable -> mqtt/C:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE +LRS mqtt/C:ESTABLISHED+unusable -> mqtt/C:ESTABLISHED+closing+unusable set_close ev=CLOSE_ENTERED +LRS mqtt/C:H2_WAITING_TO_SEND_HEADERS -> mqtt/C:ESTABLISHED role_transition ev=MUX_STREAM_ADOPTED +LRS mqtt/C:H2_WAITING_TO_SEND_HEADERS -> mqtt/C:H2_WAITING_TO_SEND_HEADERS+closing set_close ev=CLOSE_ENTERED +LRS mqtt/C:H2_WAITING_TO_SEND_HEADERS+closing -> mqtt/C:DEAD_SOCKET set_close ev=SOCKET_GONE +LRS mqtt/C:MQTTC_AWAIT_CONNACK -> mqtt/C:ESTABLISHED set_state ev=MQTT_CONNACK +LRS mqtt/C:MQTTC_IDLE -> mqtt/C:MQTTC_AWAIT_CONNACK set_state ev=MQTT_CONNECT_SENT +LRS mqtt/C:UNCONNECTED -> mqtt/C:ESTABLISHED role_transition ev=MUX_STREAM_ADOPTED +LRS mqtt/C:UNCONNECTED -> mqtt/C:H2_WAITING_TO_SEND_HEADERS set_state ev=QUEUED +LRS mqtt/C:UNCONNECTED -> mqtt/C:WAITING_DNS set_transport ev=DNS_START +LRS mqtt/C:WAITING_CONNECT -> mqtt/C:MQTTC_IDLE set_state ev=TRANSPORT_UP +LRS mqtt/C:WAITING_CONNECT -> mqtt/C:WAITING_PROXY_REPLY set_transport ev=PROXY_CONNECT_SENT +LRS mqtt/C:WAITING_CONNECT -> mqtt/C:WAITING_SOCKS_GREETING_REPLY set_transport ev=SOCKS_GREETING_SENT +LRS mqtt/C:WAITING_CONNECT -> mqtt/C:WAITING_SSL set_transport ev=TLS_START +LRS mqtt/C:WAITING_DNS -> mqtt/C:WAITING_CONNECT set_transport ev=CONNECT_START +LRS mqtt/C:WAITING_PROXY_REPLY -> mqtt/C:MQTTC_IDLE set_state ev=TRANSPORT_UP +LRS mqtt/C:WAITING_SOCKS_CONNECT_REPLY -> mqtt/C:MQTTC_IDLE set_state ev=TRANSPORT_UP +LRS mqtt/C:WAITING_SOCKS_GREETING_REPLY -> mqtt/C:WAITING_SOCKS_CONNECT_REPLY set_transport ev=SOCKS_CONNECT_SENT +LRS mqtt/C:WAITING_SSL -> mqtt/C:MQTTC_IDLE set_state ev=TRANSPORT_UP LRS netlink/-:DEAD_SOCKET -> netlink/-:DEAD_SOCKET+unusable set_unusable LRS netlink/-:DEAD_SOCKET+unusable -> netlink/-:DEAD_SOCKET set_unusable LRS netlink/-:UNCONNECTED -> netlink/-:UNCONNECTED+closing set_close ev=CLOSE_ENTERED @@ -263,6 +341,27 @@ LRS raw-file/-:ESTABLISHED+unusable -> raw-file/-:ESTABLISHED set_unusable LRS raw-file/-:UNCONNECTED -> raw-file/-:ESTABLISHED role_transition ev=ADOPTED LRS raw-file/S:ESTABLISHED -> raw-file/S:ESTABLISHED+unusable set_unusable LRS raw-file/S:ESTABLISHED+unusable -> raw-file/S:ESTABLISHED set_unusable +LRS raw-proxy/C:DEAD_SOCKET -> raw-proxy/C:DEAD_SOCKET+told set_close ev=USER_TOLD +LRS raw-proxy/C:DEAD_SOCKET+told -> raw-proxy/C:DEAD_SOCKET+told+unusable set_unusable +LRS raw-proxy/C:DEAD_SOCKET+told+unusable -> raw-proxy/C:DEAD_SOCKET+told set_unusable +LRS raw-proxy/C:ESTABLISHED -> raw-proxy/C:ESTABLISHED+closing set_close ev=CLOSE_ENTERED +LRS raw-proxy/C:ESTABLISHED+closing -> raw-proxy/C:DEAD_SOCKET set_close ev=SOCKET_GONE +LRS raw-proxy/C:UNCONNECTED -> raw-proxy/C:WAITING_DNS set_transport ev=DNS_START +LRS raw-proxy/C:WAITING_CONNECT -> raw-proxy/C:ESTABLISHED set_state ev=TRANSPORT_UP +LRS raw-proxy/C:WAITING_CONNECT -> raw-proxy/C:WAITING_PROXY_REPLY set_transport ev=PROXY_CONNECT_SENT +LRS raw-proxy/C:WAITING_CONNECT -> raw-proxy/C:WAITING_SOCKS_GREETING_REPLY set_transport ev=SOCKS_GREETING_SENT +LRS raw-proxy/C:WAITING_CONNECT -> raw-proxy/C:WAITING_SSL set_transport ev=TLS_START +LRS raw-proxy/C:WAITING_DNS -> raw-proxy/C:WAITING_CONNECT set_transport ev=CONNECT_START +LRS raw-proxy/C:WAITING_PROXY_REPLY -> raw-proxy/C:ESTABLISHED set_state ev=TRANSPORT_UP +LRS raw-proxy/C:WAITING_SOCKS_CONNECT_REPLY -> raw-proxy/C:ESTABLISHED set_state ev=TRANSPORT_UP +LRS raw-proxy/C:WAITING_SOCKS_GREETING_REPLY -> raw-proxy/C:WAITING_SOCKS_CONNECT_REPLY set_transport ev=SOCKS_CONNECT_SENT +LRS raw-proxy/C:WAITING_SSL -> raw-proxy/C:ESTABLISHED set_state ev=TRANSPORT_UP +LRS raw-proxy/S:DEAD_SOCKET -> raw-proxy/S:DEAD_SOCKET+told set_close ev=USER_TOLD +LRS raw-proxy/S:DEAD_SOCKET+told -> raw-proxy/S:DEAD_SOCKET+told+unusable set_unusable +LRS raw-proxy/S:DEAD_SOCKET+told+unusable -> raw-proxy/S:DEAD_SOCKET+told set_unusable +LRS raw-proxy/S:ESTABLISHED -> raw-proxy/S:ESTABLISHED+closing set_close ev=CLOSE_ENTERED +LRS raw-proxy/S:ESTABLISHED+closing -> raw-proxy/S:SHUTDOWN set_close ev=CLOSE_STAGED +LRS raw-proxy/S:SHUTDOWN -> raw-proxy/S:DEAD_SOCKET set_close ev=SOCKET_GONE LRS raw-skt/C:DEAD_SOCKET+failed -> raw-skt/C:DEAD_SOCKET+failed+unusable set_unusable LRS raw-skt/C:DEAD_SOCKET+failed+unusable -> raw-skt/C:DEAD_SOCKET+failed set_unusable LRS raw-skt/C:DEAD_SOCKET+told -> raw-skt/C:DEAD_SOCKET+told+unusable set_unusable @@ -270,6 +369,7 @@ LRS raw-skt/C:DEAD_SOCKET+told+unusable -> raw-skt/C:DEAD_SOCKET+told set_unusab LRS raw-skt/C:DEAD_SOCKET+unusable -> raw-skt/C:DEAD_SOCKET+told+unusable set_close ev=USER_TOLD LRS raw-skt/C:ESTABLISHED -> raw-skt/C:ESTABLISHED+closing set_close ev=CLOSE_ENTERED LRS raw-skt/C:ESTABLISHED -> raw-skt/C:ESTABLISHED+unusable set_unusable +LRS raw-skt/C:ESTABLISHED -> raw-skt/C:WAITING_SSL set_transport ev=TLS_START LRS raw-skt/C:ESTABLISHED+closing -> raw-skt/C:ESTABLISHED+closing+unusable set_unusable LRS raw-skt/C:ESTABLISHED+closing+unusable -> raw-skt/C:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE LRS raw-skt/C:ESTABLISHED+unusable -> raw-skt/C:ESTABLISHED+closing+unusable set_close ev=CLOSE_ENTERED @@ -281,22 +381,35 @@ LRS raw-skt/C:UNCONNECTED+failed+closing+unusable -> raw-skt/C:DEAD_SOCKET+faile LRS raw-skt/C:WAITING_CONNECT -> raw-skt/C:ESTABLISHED set_state ev=TRANSPORT_UP LRS raw-skt/C:WAITING_CONNECT -> raw-skt/C:UNCONNECTED+failed set_transport ev=CONN_FAILED LRS raw-skt/C:WAITING_CONNECT -> raw-skt/C:WAITING_PROXY_REPLY set_transport ev=PROXY_CONNECT_SENT +LRS raw-skt/C:WAITING_CONNECT -> raw-skt/C:WAITING_SOCKS_GREETING_REPLY set_transport ev=SOCKS_GREETING_SENT LRS raw-skt/C:WAITING_CONNECT -> raw-skt/C:WAITING_SSL set_transport ev=TLS_START LRS raw-skt/C:WAITING_DNS -> raw-skt/C:WAITING_CONNECT set_transport ev=CONNECT_START LRS raw-skt/C:WAITING_PROXY_REPLY -> raw-skt/C:ESTABLISHED set_state ev=TRANSPORT_UP LRS raw-skt/C:WAITING_PROXY_REPLY -> raw-skt/C:WAITING_SSL set_transport ev=TLS_START +LRS raw-skt/C:WAITING_SOCKS_CONNECT_REPLY -> raw-skt/C:ESTABLISHED set_state ev=TRANSPORT_UP +LRS raw-skt/C:WAITING_SOCKS_CONNECT_REPLY -> raw-skt/C:WAITING_SSL set_transport ev=TLS_START +LRS raw-skt/C:WAITING_SOCKS_GREETING_REPLY -> raw-skt/C:WAITING_SOCKS_CONNECT_REPLY set_transport ev=SOCKS_CONNECT_SENT LRS raw-skt/C:WAITING_SSL -> raw-skt/C:ESTABLISHED set_state ev=TRANSPORT_UP +LRS raw-skt/C:WAITING_SSL -> raw-skt/C:UNCONNECTED+failed set_transport ev=CONN_FAILED +LRS raw-skt/S:AWAITING_SSL_ACCEPT -> raw-skt/S:ESTABLISHED set_state ev=TRANSPORT_UP +LRS raw-skt/S:AWAITING_SSL_ACCEPT -> raw-skt/S:SSL_ACK_PENDING set_transport ev=TLS_ACCEPT_PENDING LRS raw-skt/S:DEAD_SOCKET+told -> raw-skt/S:DEAD_SOCKET+told+unusable set_unusable LRS raw-skt/S:DEAD_SOCKET+told+unusable -> raw-skt/S:DEAD_SOCKET+told set_unusable LRS raw-skt/S:DEAD_SOCKET+unusable -> raw-skt/S:DEAD_SOCKET+told+unusable set_close ev=USER_TOLD LRS raw-skt/S:ESTABLISHED -> raw-skt/S:ESTABLISHED+closing set_close ev=CLOSE_ENTERED +LRS raw-skt/S:ESTABLISHED -> raw-skt/S:ESTABLISHED+unusable set_unusable LRS raw-skt/S:ESTABLISHED -> raw-skt/S:FLUSHING_BEFORE_CLOSE set_close ev=CLOSE_WHEN_FLUSHED LRS raw-skt/S:ESTABLISHED+closing -> raw-skt/S:ESTABLISHED+closing+unusable set_unusable LRS raw-skt/S:ESTABLISHED+closing+unusable -> raw-skt/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE +LRS raw-skt/S:ESTABLISHED+unusable -> raw-skt/S:ESTABLISHED+closing+unusable set_close ev=CLOSE_ENTERED LRS raw-skt/S:FLUSHING_BEFORE_CLOSE -> raw-skt/S:FLUSHING_BEFORE_CLOSE set_close ev=CLOSE_ENTERED LRS raw-skt/S:FLUSHING_BEFORE_CLOSE -> raw-skt/S:FLUSHING_BEFORE_CLOSE+unusable set_unusable LRS raw-skt/S:FLUSHING_BEFORE_CLOSE+unusable -> raw-skt/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE +LRS raw-skt/S:SSL_ACK_PENDING -> raw-skt/S:AWAITING_SSL_ACCEPT set_transport ev=TLS_ACCEPT_QUEUED LRS raw-skt/S:SSL_ACK_PENDING -> raw-skt/S:ESTABLISHED set_state ev=TRANSPORT_UP +LRS raw-skt/S:SSL_ACK_PENDING -> raw-skt/S:SSL_ACK_PENDING+unusable set_unusable +LRS raw-skt/S:SSL_ACK_PENDING+closing+unusable -> raw-skt/S:DEAD_SOCKET+unusable set_close ev=SOCKET_GONE +LRS raw-skt/S:SSL_ACK_PENDING+unusable -> raw-skt/S:SSL_ACK_PENDING+closing+unusable set_close ev=CLOSE_ENTERED LRS raw-skt/S:SSL_INIT -> raw-skt/S:SSL_ACK_PENDING set_transport ev=TLS_ACCEPT_PENDING LRS ws/C:AWAITING_CLOSE_ACK -> ws/C:DEAD_SOCKET set_close ev=SOCKET_GONE LRS ws/C:DEAD_SOCKET -> ws/C:DEAD_SOCKET+told set_close ev=USER_TOLD @@ -371,3 +484,4 @@ LRS ws/Se:FLUSHING_BEFORE_CLOSE+unusable -> ws/Se:DEAD_SOCKET+unusable set_close LRS ws/Se:RETURNED_CLOSE -> ws/Se:DEAD_SOCKET set_close ev=SOCKET_GONE LRS ws/Se:RETURNED_CLOSE -> ws/Se:FLUSHING_BEFORE_CLOSE set_close ev=CLOSE_FLUSH LRS ws/Se:WAITING_TO_SEND_CLOSE -> ws/Se:AWAITING_CLOSE_ACK set_close ev=WS_CLOSE_SENT +LRS ws/Se:WAITING_TO_SEND_CLOSE -> ws/Se:RETURNED_CLOSE set_close ev=WS_PEER_CLOSE diff --git a/crates/npro-test/states/rows-fired.txt b/crates/npro-test/states/rows-fired.txt new file mode 100644 index 0000000..7290274 --- /dev/null +++ b/crates/npro-test/states/rows-fired.txt @@ -0,0 +1,152 @@ +LRSROW 278 h1 C UNCONNECTED TRANSPORT_UP +LRSROW 280 mqtt C WAITING_CONNECT TRANSPORT_UP +LRSROW 281 mqtt C WAITING_SSL TRANSPORT_UP +LRSROW 282 mqtt C WAITING_SOCKS_CONNECT_REPLY TRANSPORT_UP +LRSROW 283 mqtt C WAITING_PROXY_REPLY TRANSPORT_UP +LRSROW 284 raw-skt C WAITING_CONNECT TRANSPORT_UP +LRSROW 285 raw-skt C WAITING_SSL TRANSPORT_UP +LRSROW 286 raw-skt C WAITING_SOCKS_CONNECT_REPLY TRANSPORT_UP +LRSROW 287 raw-skt C WAITING_PROXY_REPLY TRANSPORT_UP +LRSROW 293 raw-proxy C WAITING_CONNECT TRANSPORT_UP +LRSROW 294 raw-proxy C WAITING_SSL TRANSPORT_UP +LRSROW 295 raw-proxy C WAITING_SOCKS_CONNECT_REPLY TRANSPORT_UP +LRSROW 296 raw-proxy C WAITING_PROXY_REPLY TRANSPORT_UP +LRSROW 300 h1 S SSL_ACK_PENDING TRANSPORT_UP +LRSROW 302 h1 S AWAITING_SSL_ACCEPT TRANSPORT_UP +LRSROW 303 * S SSL_ACK_PENDING TRANSPORT_UP +LRSROW 304 * S AWAITING_SSL_ACCEPT TRANSPORT_UP +LRSROW 306 * S ESTABLISHED TRANSPORT_UP +LRSROW 311 h1 C WAITING_CONNECT SOCKET_CONNECTED +LRSROW 313 h1 C WAITING_SOCKS_CONNECT_REPLY SOCKET_CONNECTED +LRSROW 314 h1 C WAITING_PROXY_REPLY SOCKET_CONNECTED +LRSROW 315 h1 C H1C_ISSUE_HANDSHAKE2 SOCKET_CONNECTED +LRSROW 319 * C UNCONNECTED QUEUED +LRSROW 320 h1 C H2_WAITING_TO_SEND_HEADERS REQ_ISSUE +LRSROW 322 h1 C ESTABLISHED REQ_ISSUE +LRSROW 323 h1 C WAITING_SERVER_REPLY REQ_ISSUE +LRSROW 326 h1 C WAITING_SSL REQ_HDRS_SENT +LRSROW 327 h1 C H1C_ISSUE_HANDSHAKE REQ_HDRS_SENT +LRSROW 328 h1 C H1C_ISSUE_HANDSHAKE2 REQ_HDRS_SENT +LRSROW 329 h2 C H2_WAITING_TO_SEND_HEADERS REQ_HDRS_SENT +LRSROW 331 h1 C WAITING_SSL REQ_HDRS_SENT_BODY +LRSROW 332 h1 C H1C_ISSUE_HANDSHAKE REQ_HDRS_SENT_BODY +LRSROW 333 h1 C H1C_ISSUE_HANDSHAKE2 REQ_HDRS_SENT_BODY +LRSROW 334 h2 C H2_WAITING_TO_SEND_HEADERS REQ_HDRS_SENT_BODY +LRSROW 336 * C ISSUE_HTTP_BODY REQ_BODY_SENT +LRSROW 337 h1 C ESTABLISHED RESP_INTERIM +LRSROW 339 h1 C WAITING_SERVER_REPLY RESP_INTERIM +LRSROW 342 h1 C ESTABLISHED TXN_COMPLETED +LRSROW 344 h2 C ESTABLISHED LAST_STREAM_CLOSED +LRSROW 346 h2 C IDLING CONN_REUSED +LRSROW 350 mqtt C MQTTC_IDLE MQTT_CONNECT_SENT +LRSROW 351 mqtt C MQTTC_AWAIT_CONNACK MQTT_CONNACK +LRSROW 354 h2 S H2_AWAIT_PREFACE H2_PREFACE_RX +LRSROW 355 h2 S H2_AWAIT_SETTINGS H2_SETTINGS_ACKED +LRSROW 358 h1 S HEADERS REQ_HDRS_COMPLETE +LRSROW 360 h2 S HEADERS REQ_HDRS_COMPLETE +LRSROW 362 h1 S H1_UPGRADE REQ_PLAIN_HTTP +LRSROW 363 h2 S DEFERRING_ACTION ACTION_DEFERRED_RUN +LRSROW 367 h1 S ESTABLISHED ACTION_BEGIN +LRSROW 368 h2 S HEADERS ACTION_BEGIN +LRSROW 369 h2 S ESTABLISHED ACTION_BEGIN +LRSROW 373 h1 S DOING_TRANSACTION BODY_BEGIN +LRSROW 374 h2 * ESTABLISHED BODY_BEGIN +LRSROW 382 h1 S BODY BODY_COMPLETE +LRSROW 383 h2 S BODY BODY_COMPLETE +LRSROW 386 h2 S ISSUING_FILE BODY_COMPLETE +LRSROW 388 h1 S BODY BODY_DISCARD +LRSROW 390 h1 S ESTABLISHED BODY_DISCARD +LRSROW 391 h1 S DOING_TRANSACTION BODY_DISCARD +LRSROW 392 h1 S H1_UPGRADE BODY_DISCARD +LRSROW 394 h2 S ESTABLISHED BODY_DISCARD +LRSROW 395 h2 S DOING_TRANSACTION BODY_DISCARD +LRSROW 398 h2 S BODY BODY_DISCARD +LRSROW 400 h2 S ISSUING_FILE BODY_DISCARD +LRSROW 403 h2 S AWAITING_FILE_READ BODY_DISCARD +LRSROW 411 h1 S ESTABLISHED TXN_COMPLETING +LRSROW 412 h1 S BODY TXN_COMPLETING +LRSROW 414 h1 S DOING_TRANSACTION TXN_COMPLETING +LRSROW 415 h1 S H1_UPGRADE TXN_COMPLETING +LRSROW 419 h2 S ESTABLISHED TXN_COMPLETING +LRSROW 420 h2 S DOING_TRANSACTION TXN_COMPLETING +LRSROW 421 h2 S BODY TXN_COMPLETING +LRSROW 422 h2 S DISCARD_BODY TXN_COMPLETING +LRSROW 423 h2 S ISSUING_FILE TXN_COMPLETING +LRSROW 436 h2 S AWAITING_FILE_READ TXN_COMPLETING +LRSROW 439 h1 S TXN_COMPLETING TXN_COMPLETED +LRSROW 440 h1 S TXN_COMPLETING BODY_DISCARD +LRSROW 441 h2 S TXN_COMPLETING BODY_DISCARD +LRSROW 444 h1 S ESTABLISHED TXN_COMPLETED +LRSROW 445 h1 S BODY TXN_COMPLETED +LRSROW 446 h1 S DISCARD_BODY TXN_COMPLETED +LRSROW 447 h1 S DOING_TRANSACTION TXN_COMPLETED +LRSROW 448 h1 S H1_UPGRADE TXN_COMPLETED +LRSROW 450 h1 S TXN_COMPLETED TXN_DRAINED +LRSROW 453 * S ESTABLISHED FILE_BEGIN +LRSROW 454 h2 S HEADERS FILE_BEGIN +LRSROW 455 * S DOING_TRANSACTION FILE_BEGIN +LRSROW 456 * S BODY FILE_BEGIN +LRSROW 457 h1 S H1_UPGRADE FILE_BEGIN +LRSROW 459 * S ISSUING_FILE FILE_READ_QUEUED +LRSROW 460 * S AWAITING_FILE_READ FILE_READ_DONE +LRSROW 461 * S ISSUING_FILE FILE_COMPLETE +LRSROW 466 (none) - UNCONNECTED SERVER_SIDE +LRSROW 467 * * UNCONNECTED ADOPTED_TLS +LRSROW 468 * * UNCONNECTED ADOPTED +LRSROW 469 * * UNCONNECTED ADOPTED +LRSROW 470 * * UNCONNECTED CLIENT_BIND +LRSROW 471 * C ANY RESTART +LRSROW 474 (none) * UNCONNECTED MUX_INSERTED +LRSROW 475 h2 S UNCONNECTED STREAM_OPENED +LRSROW 476 h2 C UNCONNECTED STREAM_OPENED +LRSROW 482 * * UNCONNECTED MUX_STREAM_ADOPTED +LRSROW 483 * * H1C_ISSUE_HANDSHAKE2 MUX_STREAM_ADOPTED +LRSROW 487 * * UNCONNECTED MUX_STREAM_ADOPTED +LRSROW 488 * * H2_WAITING_TO_SEND_HEADERS MUX_STREAM_ADOPTED +LRSROW 509 h2 C H2_WAITING_TO_SEND_HEADERS MUX_MIGRATED +LRSROW 512 h1 S HEADERS H2_SELECTED +LRSROW 513 h1 S H1_UPGRADE H2_SELECTED +LRSROW 514 (none) S UNCONNECTED H2_SELECTED +LRSROW 515 h1 C H1C_ISSUE_HANDSHAKE H2_SELECTED +LRSROW 516 h1 C WAITING_SSL H2_SELECTED +LRSROW 517 h2 C H2_AWAIT_PREFACE H2_PREFACE_SENT +LRSROW 520 h1 S H1_UPGRADE WS_UPGRADED +LRSROW 521 h2 S ESTABLISHED WS_UPGRADED +LRSROW 523 h1 C WAITING_SERVER_REPLY WS_UPGRADED +LRSROW 524 h2 C WAITING_SERVER_REPLY WS_UPGRADED +LRSROW 528 * C WAITING_SERVER_REPLY RESP_HDRS +LRSROW 530 * C ISSUE_HTTP_BODY RESP_HDRS +LRSROW 535 * S HEADERS RAW_UPGRADED +LRSROW 537 * S SSL_ACK_PENDING RAW_UPGRADED +LRSROW 542 * C UNCONNECTED DNS_START +LRSROW 543 * C WAITING_DNS DNS_RETRY +LRSROW 544 * C UNCONNECTED CONNECT_START +LRSROW 545 * C WAITING_DNS CONNECT_START +LRSROW 548 * C WAITING_CONNECT PROXY_CONNECT_SENT +LRSROW 549 * C WAITING_CONNECT SOCKS_GREETING_SENT +LRSROW 550 * C WAITING_SOCKS_GREETING_REPLY SOCKS_AUTH_SENT +LRSROW 551 * C WAITING_SOCKS_GREETING_REPLY SOCKS_CONNECT_SENT +LRSROW 552 * C WAITING_SOCKS_AUTH_REPLY SOCKS_CONNECT_SENT +LRSROW 553 * C WAITING_CONNECT TLS_START +LRSROW 554 * C WAITING_PROXY_REPLY TLS_START +LRSROW 555 * C WAITING_SOCKS_CONNECT_REPLY TLS_START +LRSROW 556 * C H1C_ISSUE_HANDSHAKE TLS_START +LRSROW 557 * C WAITING_SSL TLS_START +LRSROW 562 raw-skt C ESTABLISHED TLS_START +LRSROW 563 * S SSL_INIT TLS_ACCEPT_PENDING +LRSROW 564 * S SSL_ACK_PENDING TLS_ACCEPT_PENDING +LRSROW 566 * S AWAITING_SSL_ACCEPT TLS_ACCEPT_PENDING +LRSROW 567 * S SSL_ACK_PENDING TLS_ACCEPT_QUEUED +LRSROW 568 * C ANY CONN_FAILED +LRSROW 569 * C ANY RETARGET +LRSROW 573 ws * ESTABLISHED WS_CLOSE_INITIATED +LRSROW 574 ws * WAITING_TO_SEND_CLOSE WS_CLOSE_SENT +LRSROW 575 ws * ESTABLISHED WS_PEER_CLOSE +LRSROW 582 ws * WAITING_TO_SEND_CLOSE WS_PEER_CLOSE +LRSROW 587 * * FLUSHING_BEFORE_CLOSE CLOSE_ENTERED +LRSROW 588 * * ANY CLOSE_ENTERED +LRSROW 589 * * ANY CLOSE_FLUSH +LRSROW 590 * * ANY CLOSE_WHEN_FLUSHED +LRSROW 591 * S ANY CLOSE_STAGED +LRSROW 592 * * ANY SOCKET_GONE +LRSROW 593 * * DEAD_SOCKET USER_TOLD diff --git a/crates/npro-test/states/wsi-event-edges.txt b/crates/npro-test/states/wsi-event-edges.txt index ef8634d..ae61422 100644 --- a/crates/npro-test/states/wsi-event-edges.txt +++ b/crates/npro-test/states/wsi-event-edges.txt @@ -1,343 +1,321 @@ - /* - * the transport finished: a server starts on the request, an h1 client - * on sending one, an mqtt client on its CONNECT, the rest are up - */ - { "h1", "C", LRS_UNCONNECTED, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2 }, /* inherited from an idle leader */ - { "h1", "C", LRS_WAITING_SSL, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2 }, - { "h1", "C", LRS_WAITING_CONNECT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2 }, - { "h1", "C", LRS_H1C_ISSUE_HANDSHAKE, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2 }, - { "h1", "C", LRS_H1C_ISSUE_HANDSHAKE2, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2 }, - { "h1", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_H2_WAITING_TO_SEND_HEADERS }, - { "h2", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_H2_WAITING_TO_SEND_HEADERS }, - { "mqtt", "C", LRS_UNCONNECTED, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_MQTTC_IDLE }, - { "mqtt", "C", LRS_WAITING_CONNECT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_MQTTC_IDLE }, - { "mqtt", "C", LRS_WAITING_SSL, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_MQTTC_IDLE }, - { "mqtt", "C", LRS_WAITING_SOCKS_CONNECT_REPLY, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_MQTTC_IDLE }, - { "mqtt", "C", LRS_WAITING_PROXY_REPLY, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_MQTTC_IDLE }, - { "raw-skt", "C", LRS_WAITING_CONNECT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - { "raw-skt", "C", LRS_WAITING_SSL, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - { "raw-skt", "C", LRS_WAITING_SOCKS_CONNECT_REPLY, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - { "raw-skt", "C", LRS_WAITING_PROXY_REPLY, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - /* the raw proxy's onward connections are raw clients too */ - { "raw-proxy", "C", LRS_WAITING_CONNECT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - { "raw-proxy", "C", LRS_WAITING_SSL, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - { "raw-proxy", "C", LRS_WAITING_SOCKS_CONNECT_REPLY, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - { "raw-proxy", "C", LRS_WAITING_PROXY_REPLY, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - { "quic", "C", LRS_WAITING_SSL, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - { "quic", "C", LRS_WAITING_CONNECT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - { "quic", "S", LRS_SSL_INIT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - { "h1", "S", LRS_SSL_ACK_PENDING, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_HEADERS }, - { "h1", "S", LRS_AWAITING_SSL_ACCEPT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_HEADERS }, - { "h1", "S", LRS_SSL_INIT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_HEADERS }, - { "*", "S", LRS_SSL_ACK_PENDING, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - { "*", "S", LRS_AWAITING_SSL_ACCEPT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - { "*", "S", LRS_SSL_INIT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - /* the non-tls fallback already established the wsi before the accept path reports the transport up */ - { "*", "S", LRS_ESTABLISHED, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - /* 0-RTT: the ALPN migration ran inside the handshake, so handshake-done finds the new nwsi established */ - { "quic", "*", LRS_ESTABLISHED, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED }, - - /* an h1 client's tcp is up before its tls */ - { "h1", "C", LRS_WAITING_CONNECT, LWS_WSIEV_SOCKET_CONNECTED, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE }, - /* a socks or http CONNECT tunnel coming up is the socket connecting, for the protocol */ - { "h1", "C", LRS_WAITING_SOCKS_CONNECT_REPLY, LWS_WSIEV_SOCKET_CONNECTED, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE }, - { "h1", "C", LRS_WAITING_PROXY_REPLY, LWS_WSIEV_SOCKET_CONNECTED, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE }, - { "h1", "C", LRS_H1C_ISSUE_HANDSHAKE2, LWS_WSIEV_SOCKET_CONNECTED, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2 }, - - /* a client request queued on, or issued by, a connection */ - /* any client role may queue behind a leader: raw-skt and mqtt do too */ - { "*", "C", LRS_UNCONNECTED, LWS_WSIEV_QUEUED, NULL, NULL, LRS_H2_WAITING_TO_SEND_HEADERS }, - { "*", "C", LRS_H1C_ISSUE_HANDSHAKE2, LWS_WSIEV_QUEUED, NULL, NULL, LRS_H2_WAITING_TO_SEND_HEADERS }, - { "h1", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_REQ_ISSUE, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2 }, - { "quic", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_REQ_ISSUE, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2 }, /* h3 queue pickup */ - { "h1", "C", LRS_ESTABLISHED, LWS_WSIEV_REQ_ISSUE, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2 }, - { "h1", "C", LRS_IDLING, LWS_WSIEV_REQ_ISSUE, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2 }, - { "h1", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_REQ_ISSUE, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2 }, - - /* the request goes out, then its response is pending */ - { "h1", "C", LRS_WAITING_SSL, LWS_WSIEV_REQ_HDRS_SENT, NULL, NULL, LRS_WAITING_SERVER_REPLY }, - { "h1", "C", LRS_WAITING_CONNECT, LWS_WSIEV_REQ_HDRS_SENT, NULL, NULL, LRS_WAITING_SERVER_REPLY }, - { "h1", "C", LRS_H1C_ISSUE_HANDSHAKE, LWS_WSIEV_REQ_HDRS_SENT, NULL, NULL, LRS_WAITING_SERVER_REPLY }, - { "h1", "C", LRS_H1C_ISSUE_HANDSHAKE2, LWS_WSIEV_REQ_HDRS_SENT, NULL, NULL, LRS_WAITING_SERVER_REPLY }, - { "h2", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_REQ_HDRS_SENT, NULL, NULL, LRS_WAITING_SERVER_REPLY }, - { "h3", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_REQ_HDRS_SENT, NULL, NULL, LRS_WAITING_SERVER_REPLY }, - { "h1", "C", LRS_WAITING_SSL, LWS_WSIEV_REQ_HDRS_SENT_BODY, NULL, NULL, LRS_ISSUE_HTTP_BODY }, - { "h1", "C", LRS_WAITING_CONNECT, LWS_WSIEV_REQ_HDRS_SENT_BODY, NULL, NULL, LRS_ISSUE_HTTP_BODY }, - { "h1", "C", LRS_H1C_ISSUE_HANDSHAKE, LWS_WSIEV_REQ_HDRS_SENT_BODY, NULL, NULL, LRS_ISSUE_HTTP_BODY }, - { "h1", "C", LRS_H1C_ISSUE_HANDSHAKE2, LWS_WSIEV_REQ_HDRS_SENT_BODY, NULL, NULL, LRS_ISSUE_HTTP_BODY }, - { "h2", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_REQ_HDRS_SENT_BODY, NULL, NULL, LRS_ISSUE_HTTP_BODY }, - { "h3", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_REQ_HDRS_SENT_BODY, NULL, NULL, LRS_ISSUE_HTTP_BODY }, - { "*", "C", LRS_ISSUE_HTTP_BODY, LWS_WSIEV_REQ_BODY_SENT, NULL, NULL, LRS_WAITING_SERVER_REPLY }, - { "h1", "C", LRS_ESTABLISHED, LWS_WSIEV_RESP_INTERIM, NULL, NULL, LRS_WAITING_SERVER_REPLY }, - /* a ws client takes no response headers but the 101's: it is still waiting */ - { "h1", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_RESP_INTERIM, NULL, NULL, LRS_WAITING_SERVER_REPLY }, - - /* the response is done: idle, or an idle connection is picked up */ - { "h1", "C", LRS_ESTABLISHED, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_IDLING }, - { "*", "C", LRS_IDLING, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_IDLING }, - { "h2", "C", LRS_ESTABLISHED, LWS_WSIEV_LAST_STREAM_CLOSED, NULL, NULL, LRS_IDLING }, - { "quic", "C", LRS_ESTABLISHED, LWS_WSIEV_LAST_STREAM_CLOSED, NULL, NULL, LRS_IDLING }, - { "h2", "C", LRS_IDLING, LWS_WSIEV_CONN_REUSED, NULL, NULL, LRS_ESTABLISHED }, - { "quic", "C", LRS_IDLING, LWS_WSIEV_CONN_REUSED, NULL, NULL, LRS_ESTABLISHED }, - - /* mqtt client handshake */ - { "mqtt", "C", LRS_MQTTC_IDLE, LWS_WSIEV_MQTT_CONNECT_SENT, NULL, NULL, LRS_MQTTC_AWAIT_CONNACK }, - { "mqtt", "C", LRS_MQTTC_AWAIT_CONNACK, LWS_WSIEV_MQTT_CONNACK, NULL, NULL, LRS_ESTABLISHED }, - - /* h2 connection preface */ - { "h2", "S", LRS_H2_AWAIT_PREFACE, LWS_WSIEV_H2_PREFACE_RX, NULL, NULL, LRS_H2_AWAIT_SETTINGS }, - { "h2", "S", LRS_H2_AWAIT_SETTINGS, LWS_WSIEV_H2_SETTINGS_ACKED, NULL, NULL, LRS_ESTABLISHED }, - - /* request headers: h1 decides on the upgrade, mux streams defer the action */ - { "h1", "S", LRS_HEADERS, LWS_WSIEV_REQ_HDRS_COMPLETE, NULL, NULL, LRS_H1_UPGRADE }, - { "h1", "S", LRS_ESTABLISHED, LWS_WSIEV_REQ_HDRS_COMPLETE, NULL, NULL, LRS_H1_UPGRADE }, - { "h2", "S", LRS_HEADERS, LWS_WSIEV_REQ_HDRS_COMPLETE, NULL, NULL, LRS_DEFERRING_ACTION }, - { "h2", "S", LRS_ESTABLISHED, LWS_WSIEV_REQ_HDRS_COMPLETE, NULL, NULL, LRS_DEFERRING_ACTION }, - { "h3", "S", LRS_HEADERS, LWS_WSIEV_REQ_HDRS_COMPLETE, NULL, NULL, LRS_DEFERRING_ACTION }, - { "h3", "S", LRS_ESTABLISHED, LWS_WSIEV_REQ_HDRS_COMPLETE, NULL, NULL, LRS_DEFERRING_ACTION }, - { "h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_REQ_PLAIN_HTTP, NULL, NULL, LRS_ESTABLISHED }, - { "h2", "S", LRS_DEFERRING_ACTION, LWS_WSIEV_ACTION_DEFERRED_RUN, NULL, NULL, LRS_ESTABLISHED }, - { "h3", "S", LRS_DEFERRING_ACTION, LWS_WSIEV_ACTION_DEFERRED_RUN, NULL, NULL, LRS_ESTABLISHED }, - - /* acting on the request */ - { "h1", "S", LRS_ESTABLISHED, LWS_WSIEV_ACTION_BEGIN, NULL, NULL, LRS_DOING_TRANSACTION }, - { "h2", "S", LRS_HEADERS, LWS_WSIEV_ACTION_BEGIN, NULL, NULL, LRS_DOING_TRANSACTION }, - { "h2", "S", LRS_ESTABLISHED, LWS_WSIEV_ACTION_BEGIN, NULL, NULL, LRS_DOING_TRANSACTION }, - { "h3", "S", LRS_HEADERS, LWS_WSIEV_ACTION_BEGIN, NULL, NULL, LRS_DOING_TRANSACTION }, - { "h3", "S", LRS_ESTABLISHED, LWS_WSIEV_ACTION_BEGIN, NULL, NULL, LRS_DOING_TRANSACTION }, - - /* request body */ - { "h1", "S", LRS_ESTABLISHED, LWS_WSIEV_BODY_BEGIN, NULL, NULL, LRS_BODY }, - { "h1", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_BODY_BEGIN, NULL, NULL, LRS_BODY }, - { "h2", "*", LRS_ESTABLISHED, LWS_WSIEV_BODY_BEGIN, NULL, NULL, LRS_BODY }, - { "h2", "*", LRS_HEADERS, LWS_WSIEV_BODY_BEGIN, NULL, NULL, LRS_BODY }, - { "h3", "*", LRS_ESTABLISHED, LWS_WSIEV_BODY_BEGIN, NULL, NULL, LRS_BODY }, - { "h3", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_BODY_BEGIN, NULL, NULL, LRS_BODY }, /* action ran, body follows: as h1 */ - { "h2", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_BODY_BEGIN, NULL, NULL, LRS_BODY }, /* same on h2 */ - /* - * an h1 body is complete before its answer is: the connection's next - * request, pipelined behind it, waits parked for the transaction - */ - { "h1", "S", LRS_BODY, LWS_WSIEV_BODY_COMPLETE, NULL, NULL, LRS_DOING_TRANSACTION }, - { "h2", "S", LRS_BODY, LWS_WSIEV_BODY_COMPLETE, NULL, NULL, LRS_ESTABLISHED }, - { "h3", "S", LRS_BODY, LWS_WSIEV_BODY_COMPLETE, NULL, NULL, LRS_ESTABLISHED }, - /* the body completion callback may itself have started serving a file (C-522) */ - { "h2", "S", LRS_ISSUING_FILE, LWS_WSIEV_BODY_COMPLETE, NULL, NULL, LRS_ISSUING_FILE }, - { "h3", "S", LRS_ISSUING_FILE, LWS_WSIEV_BODY_COMPLETE, NULL, NULL, LRS_ISSUING_FILE }, - { "h2", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_BODY_COMPLETE, NULL, NULL, LRS_AWAITING_FILE_READ }, - { "h3", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_BODY_COMPLETE, NULL, NULL, LRS_AWAITING_FILE_READ }, - { "h1", "S", LRS_BODY, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - /* the user may complete the transaction before the body was ever delivered */ - { "h1", "S", LRS_ESTABLISHED, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h1", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h1", "S", LRS_ISSUING_FILE, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - /* the completion runs for mux streams too: there DISCARD_BODY drops the stash and closes the stream */ - { "h2", "S", LRS_ESTABLISHED, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h2", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h2", "S", LRS_DEFERRING_ACTION, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h3", "S", LRS_ESTABLISHED, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h3", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h3", "S", LRS_DEFERRING_ACTION, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h2", "S", LRS_HEADERS, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h3", "S", LRS_HEADERS, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h2", "S", LRS_BODY, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h3", "S", LRS_BODY, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h2", "S", LRS_ISSUING_FILE, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h3", "S", LRS_ISSUING_FILE, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - /* ...or abandoned with a read of the file out on a worker, reaped by the completion */ - { "h1", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h2", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h3", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - - /* the h1 transaction ends and the connection is reused */ - /* - * the user completed it with its response still queued: completion - * waits for that to go, from wherever the transaction had got to - */ - { "h1", "S", LRS_ESTABLISHED, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h1", "S", LRS_BODY, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h1", "S", LRS_DISCARD_BODY, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h1", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h1", "S", LRS_TXN_COMPLETED, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h1", "S", LRS_ISSUING_FILE, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h1", "S", LRS_TXN_COMPLETING, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h2", "S", LRS_HEADERS, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h2", "S", LRS_DEFERRING_ACTION, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h2", "S", LRS_ESTABLISHED, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h2", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h2", "S", LRS_BODY, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h2", "S", LRS_DISCARD_BODY, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h2", "S", LRS_ISSUING_FILE, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h2", "S", LRS_TXN_COMPLETING, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h3", "S", LRS_HEADERS, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h3", "S", LRS_DEFERRING_ACTION, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h3", "S", LRS_ESTABLISHED, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h3", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h3", "S", LRS_BODY, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h3", "S", LRS_DISCARD_BODY, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h3", "S", LRS_ISSUING_FILE, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h3", "S", LRS_TXN_COMPLETING, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - /* - * a file being served, a read of it out on a worker, that the app - * completed from under (an h2 / h3 body completion, its own timer): - * the completion waits for the answer queued so far as any other - */ - { "h1", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h2", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - { "h3", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING }, - /* ...and once it has, it completes, or first discards an unread body */ - { "h1", "S", LRS_TXN_COMPLETING, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED }, - { "h1", "S", LRS_TXN_COMPLETING, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h2", "S", LRS_TXN_COMPLETING, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - { "h3", "S", LRS_TXN_COMPLETING, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY }, - - { "h1", "S", LRS_ESTABLISHED, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED }, - { "h1", "S", LRS_BODY, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED }, - { "h1", "S", LRS_DISCARD_BODY, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED }, - { "h1", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED }, - { "h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED }, /* upgrade refused */ - { "h1", "S", LRS_TXN_COMPLETED, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED }, - { "h1", "S", LRS_ISSUING_FILE, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED }, /* completed from the file-complete callback */ - { "h1", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED }, /* or abandoned with a read out on a worker */ - { "h1", "S", LRS_TXN_COMPLETED, LWS_WSIEV_TXN_DRAINED, NULL, NULL, LRS_HEADERS }, - - /* serving a file */ - { "*", "S", LRS_ESTABLISHED, LWS_WSIEV_FILE_BEGIN, NULL, NULL, LRS_ISSUING_FILE }, - { "h2", "S", LRS_HEADERS, LWS_WSIEV_FILE_BEGIN, NULL, NULL, LRS_ISSUING_FILE }, /* h2c upgrade stream 1 */ - { "*", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_FILE_BEGIN, NULL, NULL, LRS_ISSUING_FILE }, - { "*", "S", LRS_BODY, LWS_WSIEV_FILE_BEGIN, NULL, NULL, LRS_ISSUING_FILE }, /* served from HTTP_BODY_COMPLETION */ - { "h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_FILE_BEGIN, NULL, NULL, LRS_ISSUING_FILE }, /* served from HTTP_CONFIRM_UPGRADE */ - { "*", "S", LRS_ISSUING_FILE, LWS_WSIEV_FILE_READ_QUEUED, NULL, NULL, LRS_AWAITING_FILE_READ }, - { "*", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_FILE_READ_DONE, NULL, NULL, LRS_ISSUING_FILE }, - { "*", "S", LRS_ISSUING_FILE, LWS_WSIEV_FILE_COMPLETE, NULL, NULL, LRS_ESTABLISHED }, - - /* ---- role changes ---- */ - - /* birth on a server, adoption, the client bind, a restart */ - { "(none)", "-", LRS_UNCONNECTED, LWS_WSIEV_SERVER_SIDE, NULL, "S", LRS_UNCONNECTED }, - { "*", "*", LRS_UNCONNECTED, LWS_WSIEV_ADOPTED_TLS, "?", NULL, LRS_SSL_INIT }, - { "*", "*", LRS_UNCONNECTED, LWS_WSIEV_ADOPTED, "h1", NULL, LRS_HEADERS }, - { "*", "*", LRS_UNCONNECTED, LWS_WSIEV_ADOPTED, "?", NULL, LRS_ESTABLISHED }, - { "*", "*", LRS_UNCONNECTED, LWS_WSIEV_CLIENT_BIND, "?", "C", LRS_UNCONNECTED }, - { "*", "C", ANY, LWS_WSIEV_RESTART, "?", "C", LRS_UNCONNECTED }, - - /* mux children: a fresh child is its parent's; a server's opened stream reads its request */ - { "(none)", "*", LRS_UNCONNECTED, LWS_WSIEV_MUX_INSERTED, "P", "P", LRS_UNCONNECTED }, - { "h2", "S", LRS_UNCONNECTED, LWS_WSIEV_STREAM_OPENED, NULL, NULL, LRS_HEADERS }, - { "h2", "C", LRS_UNCONNECTED, LWS_WSIEV_STREAM_OPENED, NULL, NULL, LRS_UNCONNECTED }, - { "quic", "S", LRS_UNCONNECTED, LWS_WSIEV_STREAM_OPENED, "h3", NULL, LRS_HEADERS }, - { "quic", "C", LRS_UNCONNECTED, LWS_WSIEV_STREAM_OPENED, "h3", NULL, LRS_ESTABLISHED }, - { "quic", "*", LRS_UNCONNECTED, LWS_WSIEV_STREAM_OPENED, "quic", NULL, LRS_ESTABLISHED }, - - /* a client stream is let onto its connection: h2 / h3 send a request, mqtt is up */ - { "*", "*", LRS_UNCONNECTED, LWS_WSIEV_MUX_STREAM_ADOPTED, "h2", "P", LRS_H2_WAITING_TO_SEND_HEADERS }, - { "*", "*", LRS_H1C_ISSUE_HANDSHAKE2, LWS_WSIEV_MUX_STREAM_ADOPTED, "h2", "P", LRS_H2_WAITING_TO_SEND_HEADERS }, - { "*", "*", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_MUX_STREAM_ADOPTED, "h2", "P", LRS_H2_WAITING_TO_SEND_HEADERS }, - { "*", "*", LRS_UNCONNECTED, LWS_WSIEV_MUX_STREAM_ADOPTED, "h3", "P", LRS_H2_WAITING_TO_SEND_HEADERS }, - { "*", "*", LRS_H1C_ISSUE_HANDSHAKE2, LWS_WSIEV_MUX_STREAM_ADOPTED, "h3", "P", LRS_H2_WAITING_TO_SEND_HEADERS }, - { "*", "*", LRS_WAITING_CONNECT, LWS_WSIEV_MUX_STREAM_ADOPTED, "h3", "P", LRS_H2_WAITING_TO_SEND_HEADERS }, - { "*", "*", LRS_WAITING_SSL, LWS_WSIEV_MUX_STREAM_ADOPTED, "h3", "P", LRS_H2_WAITING_TO_SEND_HEADERS }, - { "*", "*", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_MUX_STREAM_ADOPTED, "h3", "P", LRS_H2_WAITING_TO_SEND_HEADERS }, - { "*", "*", LRS_UNCONNECTED, LWS_WSIEV_MUX_STREAM_ADOPTED, "mqtt", "P", LRS_ESTABLISHED }, - { "*", "*", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_MUX_STREAM_ADOPTED, "mqtt", "P", LRS_ESTABLISHED }, - { "*", "*", LRS_ESTABLISHED, LWS_WSIEV_MUX_STREAM_ADOPTED, "mqtt", "P", LRS_ESTABLISHED }, - - /* our own h3 unidirectional streams, and a wsi taking over a quic connection */ - { "(none)", "*", LRS_UNCONNECTED, LWS_WSIEV_CONTROL_STREAM_OPENED, "h3", "L", LRS_ESTABLISHED }, - { "(none)", "*", LRS_UNCONNECTED, LWS_WSIEV_CONN_TAKEOVER, "?", "L", LRS_ESTABLISHED }, - - /* the quic handshake chose h3 (a client stream sends, a server stream reads) or not */ - { "*", "C", LRS_UNCONNECTED, LWS_WSIEV_ALPN_DONE, "h3", NULL, LRS_H2_WAITING_TO_SEND_HEADERS }, - { "*", "C", LRS_WAITING_CONNECT, LWS_WSIEV_ALPN_DONE, "h3", NULL, LRS_H2_WAITING_TO_SEND_HEADERS }, - { "quic", "C", ANY, LWS_WSIEV_ALPN_DONE, "h3", NULL, LRS_H2_WAITING_TO_SEND_HEADERS }, - { "quic", "S", ANY, LWS_WSIEV_ALPN_DONE, "h3", NULL, LRS_HEADERS }, - { "quic", "*", ANY, LWS_WSIEV_ALPN_DONE, "quic", NULL, LRS_ESTABLISHED }, - - /* - * the h2 client nwsi hands its own request to the sid-1 child and is - * from then on the carrier of streams only: established - */ - { "h2", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_MUX_MIGRATED, NULL, NULL, LRS_ESTABLISHED }, - - /* h2: chosen by alpn, h2c upgrade or prior knowledge; the client preface */ - { "h1", "S", LRS_HEADERS, LWS_WSIEV_H2_SELECTED, "h2", NULL, LRS_H2_AWAIT_PREFACE }, - { "h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_H2_SELECTED, "h2", NULL, LRS_H2_AWAIT_PREFACE }, - { "(none)", "S", LRS_UNCONNECTED, LWS_WSIEV_H2_SELECTED, "h2", NULL, LRS_H2_AWAIT_PREFACE }, - { "h1", "C", LRS_H1C_ISSUE_HANDSHAKE, LWS_WSIEV_H2_SELECTED, "h2", NULL, LRS_H2_AWAIT_PREFACE }, - { "h1", "C", LRS_WAITING_SSL, LWS_WSIEV_H2_SELECTED, "h2", NULL, LRS_H2_AWAIT_PREFACE }, - { "h1", "C", LRS_UNCONNECTED, LWS_WSIEV_H2_SELECTED, "h2", NULL, LRS_H2_AWAIT_PREFACE }, - { "h2", "C", LRS_H2_AWAIT_PREFACE, LWS_WSIEV_H2_PREFACE_SENT, NULL, NULL, LRS_H2_WAITING_TO_SEND_HEADERS }, - - /* ws upgrade, on a server from the upgrade decision, on a client from the 101 */ - { "h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_WS_UPGRADED, "ws", NULL, LRS_ESTABLISHED }, - { "h2", "S", LRS_ESTABLISHED, LWS_WSIEV_WS_UPGRADED, "ws", "Se", LRS_ESTABLISHED }, - { "h3", "S", LRS_ESTABLISHED, LWS_WSIEV_WS_UPGRADED, "ws", "Se", LRS_ESTABLISHED }, /* RFC 9220 */ - { "h1", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_WS_UPGRADED, "ws", NULL, LRS_ESTABLISHED }, - { "h2", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_WS_UPGRADED, "ws", "Ce", LRS_ESTABLISHED }, - - /* the client's response headers; webtransport; raw */ - { "*", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_RESP_HDRS, NULL, NULL, LRS_ESTABLISHED }, - /* a server may answer before the request body is finished (401, 413...) */ - { "*", "C", LRS_ISSUE_HTTP_BODY, LWS_WSIEV_RESP_HDRS, NULL, NULL, LRS_ESTABLISHED }, - { "h3", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_WT_SESSION, "wt", NULL, LRS_ESTABLISHED }, - { "h3", "S", ANY, LWS_WSIEV_WT_SESSION, "wt", NULL, LRS_ESTABLISHED }, - { "h3", "*", ANY, LWS_WSIEV_WT_STREAM, "wt", NULL, LRS_ESTABLISHED }, - { "(none)", "*", LRS_UNCONNECTED, LWS_WSIEV_WT_STREAM, "wt", "L", LRS_ESTABLISHED }, - { "*", "S", LRS_HEADERS, LWS_WSIEV_RAW_UPGRADED, "?", NULL, LRS_ESTABLISHED }, - { "*", "S", LRS_H1_UPGRADE, LWS_WSIEV_RAW_UPGRADED, "?", NULL, LRS_ESTABLISHED }, - /* the non-tls fallback on a tls listener, from the first byte peek in the accept */ - { "*", "S", LRS_SSL_INIT, LWS_WSIEV_RAW_UPGRADED, "?", NULL, LRS_ESTABLISHED }, - { "*", "S", LRS_SSL_ACK_PENDING, LWS_WSIEV_RAW_UPGRADED, "?", NULL, LRS_ESTABLISHED }, - /* a later request on a kept-alive connection, and a listener already in the raw role */ - { "*", "S", LRS_ESTABLISHED, LWS_WSIEV_RAW_UPGRADED, "?", NULL, LRS_ESTABLISHED }, - { "h1", "C", LRS_ESTABLISHED, LWS_WSIEV_RAW_UPGRADED, "raw-skt", NULL, LRS_ESTABLISHED }, - { "h1", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_RAW_UPGRADED, "raw-skt", NULL, LRS_ESTABLISHED }, - /* ---- transport machine ---- */ - - { "*", "C", LRS_UNCONNECTED, LWS_WSIEV_DNS_START, NULL, NULL, XT(LTS_WAITING_DNS) }, - { "*", "C", LRS_WAITING_DNS, LWS_WSIEV_DNS_RETRY, NULL, NULL, XT(LTS_NONE) }, - { "*", "C", LRS_UNCONNECTED, LWS_WSIEV_CONNECT_START, NULL, NULL, XT(LTS_WAITING_CONNECT) }, - { "*", "C", LRS_WAITING_DNS, LWS_WSIEV_CONNECT_START, NULL, NULL, XT(LTS_WAITING_CONNECT) }, - { "*", "C", LRS_WAITING_CONNECT, LWS_WSIEV_CONNECT_START, NULL, NULL, XT(LTS_WAITING_CONNECT) }, /* next address */ - { "*", "C", LRS_WAITING_SSL, LWS_WSIEV_CONNECT_START, NULL, NULL, XT(LTS_WAITING_CONNECT) }, /* quic to tcp */ - { "*", "C", LRS_WAITING_CONNECT, LWS_WSIEV_PROXY_CONNECT_SENT, NULL, NULL, XT(LTS_WAITING_PROXY_REPLY) }, - { "*", "C", LRS_WAITING_CONNECT, LWS_WSIEV_SOCKS_GREETING_SENT, NULL, NULL, XT(LTS_WAITING_SOCKS_GREETING_REPLY) }, - { "*", "C", LRS_WAITING_SOCKS_GREETING_REPLY, LWS_WSIEV_SOCKS_AUTH_SENT, NULL, NULL, XT(LTS_WAITING_SOCKS_AUTH_REPLY) }, - { "*", "C", LRS_WAITING_SOCKS_GREETING_REPLY, LWS_WSIEV_SOCKS_CONNECT_SENT, NULL, NULL, XT(LTS_WAITING_SOCKS_CONNECT_REPLY) }, - { "*", "C", LRS_WAITING_SOCKS_AUTH_REPLY, LWS_WSIEV_SOCKS_CONNECT_SENT, NULL, NULL, XT(LTS_WAITING_SOCKS_CONNECT_REPLY) }, - { "*", "C", LRS_WAITING_CONNECT, LWS_WSIEV_TLS_START, NULL, NULL, XT(LTS_WAITING_SSL) }, - { "*", "C", LRS_WAITING_PROXY_REPLY, LWS_WSIEV_TLS_START, NULL, NULL, XT(LTS_WAITING_SSL) }, - { "*", "C", LRS_WAITING_SOCKS_CONNECT_REPLY, LWS_WSIEV_TLS_START, NULL, NULL, XT(LTS_WAITING_SSL) }, - { "*", "C", LRS_H1C_ISSUE_HANDSHAKE, LWS_WSIEV_TLS_START, NULL, NULL, XT(LTS_WAITING_SSL) }, - { "*", "C", LRS_WAITING_SSL, LWS_WSIEV_TLS_START, NULL, NULL, XT(LTS_WAITING_SSL) }, /* more service */ - /* STARTTLS: an established raw client starts tls inside its protocol */ - { "raw-skt", "C", LRS_ESTABLISHED, LWS_WSIEV_TLS_START, NULL, NULL, XT(LTS_WAITING_SSL) }, - { "*", "S", LRS_SSL_INIT, LWS_WSIEV_TLS_ACCEPT_PENDING, NULL, NULL, XT(LTS_SSL_ACK_PENDING) }, - { "*", "S", LRS_SSL_ACK_PENDING, LWS_WSIEV_TLS_ACCEPT_PENDING, NULL, NULL, XT(LTS_SSL_ACK_PENDING) }, - { "*", "S", LRS_AWAITING_SSL_ACCEPT, LWS_WSIEV_TLS_ACCEPT_PENDING, NULL, NULL, XT(LTS_SSL_ACK_PENDING) }, - { "*", "S", LRS_SSL_INIT, LWS_WSIEV_TLS_ACCEPT_QUEUED, NULL, NULL, XT(LTS_AWAITING_SSL_ACCEPT) }, - { "*", "S", LRS_SSL_ACK_PENDING, LWS_WSIEV_TLS_ACCEPT_QUEUED, NULL, NULL, XT(LTS_AWAITING_SSL_ACCEPT) }, - { "*", "C", ANY, LWS_WSIEV_CONN_FAILED, NULL, NULL, XT(LTS_FAILED) }, - { "*", "C", ANY, LWS_WSIEV_RETARGET, NULL, NULL, XT(LTS_RESTARTING) }, - - /* ---- close machine: the polite ws close is specific, the rest can come from anywhere ---- */ - - { "ws", "*", LRS_ESTABLISHED, LWS_WSIEV_WS_CLOSE_INITIATED, NULL, NULL, XC(LCS_WAITING_TO_SEND_CLOSE) }, - { "ws", "*", LRS_WAITING_TO_SEND_CLOSE, LWS_WSIEV_WS_CLOSE_SENT, NULL, NULL, XC(LCS_AWAITING_CLOSE_ACK) }, - { "ws", "*", LRS_ESTABLISHED, LWS_WSIEV_WS_PEER_CLOSE, NULL, NULL, XC(LCS_RETURNED_CLOSE) }, - /* his CLOSE beat the one we were about to send: answer his and drop ours */ - { "ws", "*", LRS_WAITING_TO_SEND_CLOSE, LWS_WSIEV_WS_PEER_CLOSE, NULL, NULL, XC(LCS_RETURNED_CLOSE) }, - /* - * the close is entered: a flush the live connection had begun is now - * the close's own, else the close has begun with nothing to wait for - */ - { "*", "*", LRS_FLUSHING_BEFORE_CLOSE, LWS_WSIEV_CLOSE_ENTERED, NULL, NULL, XC(LCS_FLUSHING_BEFORE_CLOSE) }, - { "*", "*", ANY, LWS_WSIEV_CLOSE_ENTERED, NULL, NULL, XC(LCS_CLOSING) }, - { "*", "*", ANY, LWS_WSIEV_CLOSE_FLUSH, NULL, NULL, XC(LCS_FLUSHING_BEFORE_CLOSE) }, - { "*", "*", ANY, LWS_WSIEV_CLOSE_WHEN_FLUSHED, NULL, NULL, XC(LCS_CLOSE_WHEN_FLUSHED) }, - { "*", "S", ANY, LWS_WSIEV_CLOSE_STAGED, NULL, NULL, XC(LCS_SHUTDOWN) }, - { "*", "*", ANY, LWS_WSIEV_SOCKET_GONE, NULL, NULL, XC(LCS_DEAD_SOCKET) }, - { "*", "*", LRS_DEAD_SOCKET, LWS_WSIEV_USER_TOLD, NULL, NULL, XC(LCS_USER_TOLD) }, - +274 /* +275 * the transport finished: a server starts on the request, an h1 client +276 * on sending one, an mqtt client on its CONNECT, the rest are up +277 */ +278 R("h1", "C", LRS_UNCONNECTED, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2), /* inherited from an idle leader */ +279 /* mqtt over tls, or through a socks5 (LWS_WITH_SOCKS5) or http CONNECT proxy */ +280 R("mqtt", "C", LRS_WAITING_CONNECT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_MQTTC_IDLE), +281 R("mqtt", "C", LRS_WAITING_SSL, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_MQTTC_IDLE), +282 R("mqtt", "C", LRS_WAITING_SOCKS_CONNECT_REPLY, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_MQTTC_IDLE), +283 R("mqtt", "C", LRS_WAITING_PROXY_REPLY, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_MQTTC_IDLE), +284 R("raw-skt", "C", LRS_WAITING_CONNECT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +285 R("raw-skt", "C", LRS_WAITING_SSL, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +286 R("raw-skt", "C", LRS_WAITING_SOCKS_CONNECT_REPLY, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +287 R("raw-skt", "C", LRS_WAITING_PROXY_REPLY, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +288 /* +289 * the raw proxy's onward connections are raw clients too +290 * (LWS_ROLE_RAW_PROXY, protocol_lws_raw_proxy; the plugin never asks +291 * for tls, an app's own raw-proxy client may) +292 */ +293 R("raw-proxy", "C", LRS_WAITING_CONNECT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +294 R("raw-proxy", "C", LRS_WAITING_SSL, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +295 R("raw-proxy", "C", LRS_WAITING_SOCKS_CONNECT_REPLY, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +296 R("raw-proxy", "C", LRS_WAITING_PROXY_REPLY, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +297 R("quic", "C", LRS_WAITING_SSL, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +298 R("quic", "C", LRS_WAITING_CONNECT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +299 R("quic", "S", LRS_SSL_INIT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +300 R("h1", "S", LRS_SSL_ACK_PENDING, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_HEADERS), +301 /* the accept on a worker: LWS_WITH_ASYNC_QUEUE with LWS_MAX_SMP > 1 */ +302 R("h1", "S", LRS_AWAITING_SSL_ACCEPT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_HEADERS), +303 R("*", "S", LRS_SSL_ACK_PENDING, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +304 R("*", "S", LRS_AWAITING_SSL_ACCEPT, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +305 /* the non-tls fallback already established the wsi before the accept path reports the transport up */ +306 R("*", "S", LRS_ESTABLISHED, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +307 /* 0-RTT: the ALPN migration ran inside the handshake, so handshake-done finds the new nwsi established */ +308 R("quic", "*", LRS_ESTABLISHED, LWS_WSIEV_TRANSPORT_UP, NULL, NULL, LRS_ESTABLISHED), +309 +310 /* an h1 client's tcp is up before its tls */ +311 R("h1", "C", LRS_WAITING_CONNECT, LWS_WSIEV_SOCKET_CONNECTED, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE), +312 /* a socks or http CONNECT tunnel coming up is the socket connecting, for the protocol */ +313 R("h1", "C", LRS_WAITING_SOCKS_CONNECT_REPLY, LWS_WSIEV_SOCKET_CONNECTED, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE), +314 R("h1", "C", LRS_WAITING_PROXY_REPLY, LWS_WSIEV_SOCKET_CONNECTED, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE), +315 R("h1", "C", LRS_H1C_ISSUE_HANDSHAKE2, LWS_WSIEV_SOCKET_CONNECTED, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2), +316 +317 /* a client request queued on, or issued by, a connection */ +318 /* any client role may queue behind a leader: raw-skt and mqtt do too */ +319 R("*", "C", LRS_UNCONNECTED, LWS_WSIEV_QUEUED, NULL, NULL, LRS_H2_WAITING_TO_SEND_HEADERS), +320 R("h1", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_REQ_ISSUE, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2), +321 R("quic", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_REQ_ISSUE, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2), /* h3 queue pickup */ +322 R("h1", "C", LRS_ESTABLISHED, LWS_WSIEV_REQ_ISSUE, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2), +323 R("h1", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_REQ_ISSUE, NULL, NULL, LRS_H1C_ISSUE_HANDSHAKE2), +324 +325 /* the request goes out, then its response is pending */ +326 R("h1", "C", LRS_WAITING_SSL, LWS_WSIEV_REQ_HDRS_SENT, NULL, NULL, LRS_WAITING_SERVER_REPLY), +327 R("h1", "C", LRS_H1C_ISSUE_HANDSHAKE, LWS_WSIEV_REQ_HDRS_SENT, NULL, NULL, LRS_WAITING_SERVER_REPLY), +328 R("h1", "C", LRS_H1C_ISSUE_HANDSHAKE2, LWS_WSIEV_REQ_HDRS_SENT, NULL, NULL, LRS_WAITING_SERVER_REPLY), +329 R("h2", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_REQ_HDRS_SENT, NULL, NULL, LRS_WAITING_SERVER_REPLY), +330 R("h3", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_REQ_HDRS_SENT, NULL, NULL, LRS_WAITING_SERVER_REPLY), +331 R("h1", "C", LRS_WAITING_SSL, LWS_WSIEV_REQ_HDRS_SENT_BODY, NULL, NULL, LRS_ISSUE_HTTP_BODY), +332 R("h1", "C", LRS_H1C_ISSUE_HANDSHAKE, LWS_WSIEV_REQ_HDRS_SENT_BODY, NULL, NULL, LRS_ISSUE_HTTP_BODY), +333 R("h1", "C", LRS_H1C_ISSUE_HANDSHAKE2, LWS_WSIEV_REQ_HDRS_SENT_BODY, NULL, NULL, LRS_ISSUE_HTTP_BODY), +334 R("h2", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_REQ_HDRS_SENT_BODY, NULL, NULL, LRS_ISSUE_HTTP_BODY), +335 R("h3", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_REQ_HDRS_SENT_BODY, NULL, NULL, LRS_ISSUE_HTTP_BODY), +336 R("*", "C", LRS_ISSUE_HTTP_BODY, LWS_WSIEV_REQ_BODY_SENT, NULL, NULL, LRS_WAITING_SERVER_REPLY), +337 R("h1", "C", LRS_ESTABLISHED, LWS_WSIEV_RESP_INTERIM, NULL, NULL, LRS_WAITING_SERVER_REPLY), +338 /* a ws client takes no response headers but the 101's: it is still waiting */ +339 R("h1", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_RESP_INTERIM, NULL, NULL, LRS_WAITING_SERVER_REPLY), +340 +341 /* the response is done: idle, or an idle connection is picked up */ +342 R("h1", "C", LRS_ESTABLISHED, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_IDLING), +343 R("*", "C", LRS_IDLING, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_IDLING), /* only an app reading on past the end of an unframed body */ +344 R("h2", "C", LRS_ESTABLISHED, LWS_WSIEV_LAST_STREAM_CLOSED, NULL, NULL, LRS_IDLING), +345 R("quic", "C", LRS_ESTABLISHED, LWS_WSIEV_LAST_STREAM_CLOSED, NULL, NULL, LRS_IDLING), +346 R("h2", "C", LRS_IDLING, LWS_WSIEV_CONN_REUSED, NULL, NULL, LRS_ESTABLISHED), +347 R("quic", "C", LRS_IDLING, LWS_WSIEV_CONN_REUSED, NULL, NULL, LRS_ESTABLISHED), +348 +349 /* mqtt client handshake */ +350 R("mqtt", "C", LRS_MQTTC_IDLE, LWS_WSIEV_MQTT_CONNECT_SENT, NULL, NULL, LRS_MQTTC_AWAIT_CONNACK), +351 R("mqtt", "C", LRS_MQTTC_AWAIT_CONNACK, LWS_WSIEV_MQTT_CONNACK, NULL, NULL, LRS_ESTABLISHED), +352 +353 /* h2 connection preface */ +354 R("h2", "S", LRS_H2_AWAIT_PREFACE, LWS_WSIEV_H2_PREFACE_RX, NULL, NULL, LRS_H2_AWAIT_SETTINGS), +355 R("h2", "S", LRS_H2_AWAIT_SETTINGS, LWS_WSIEV_H2_SETTINGS_ACKED, NULL, NULL, LRS_ESTABLISHED), +356 +357 /* request headers: h1 decides on the upgrade, mux streams defer the action */ +358 R("h1", "S", LRS_HEADERS, LWS_WSIEV_REQ_HDRS_COMPLETE, NULL, NULL, LRS_H1_UPGRADE), +359 R("h1", "S", LRS_ESTABLISHED, LWS_WSIEV_REQ_HDRS_COMPLETE, NULL, NULL, LRS_H1_UPGRADE), /* the next request, after a file completion the app did not complete */ +360 R("h2", "S", LRS_HEADERS, LWS_WSIEV_REQ_HDRS_COMPLETE, NULL, NULL, LRS_DEFERRING_ACTION), +361 R("h3", "S", LRS_HEADERS, LWS_WSIEV_REQ_HDRS_COMPLETE, NULL, NULL, LRS_DEFERRING_ACTION), +362 R("h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_REQ_PLAIN_HTTP, NULL, NULL, LRS_ESTABLISHED), +363 R("h2", "S", LRS_DEFERRING_ACTION, LWS_WSIEV_ACTION_DEFERRED_RUN, NULL, NULL, LRS_ESTABLISHED), +364 R("h3", "S", LRS_DEFERRING_ACTION, LWS_WSIEV_ACTION_DEFERRED_RUN, NULL, NULL, LRS_ESTABLISHED), +365 +366 /* acting on the request */ +367 R("h1", "S", LRS_ESTABLISHED, LWS_WSIEV_ACTION_BEGIN, NULL, NULL, LRS_DOING_TRANSACTION), +368 R("h2", "S", LRS_HEADERS, LWS_WSIEV_ACTION_BEGIN, NULL, NULL, LRS_DOING_TRANSACTION), +369 R("h2", "S", LRS_ESTABLISHED, LWS_WSIEV_ACTION_BEGIN, NULL, NULL, LRS_DOING_TRANSACTION), +370 R("h3", "S", LRS_ESTABLISHED, LWS_WSIEV_ACTION_BEGIN, NULL, NULL, LRS_DOING_TRANSACTION), +371 +372 /* request body */ +373 R("h1", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_BODY_BEGIN, NULL, NULL, LRS_BODY), +374 R("h2", "*", LRS_ESTABLISHED, LWS_WSIEV_BODY_BEGIN, NULL, NULL, LRS_BODY), +375 R("h3", "*", LRS_ESTABLISHED, LWS_WSIEV_BODY_BEGIN, NULL, NULL, LRS_BODY), +376 R("h3", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_BODY_BEGIN, NULL, NULL, LRS_BODY), /* action ran, body follows: as h1 */ +377 R("h2", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_BODY_BEGIN, NULL, NULL, LRS_BODY), /* same on h2 */ +378 /* +379 * an h1 body is complete before its answer is: the connection's next +380 * request, pipelined behind it, waits parked for the transaction +381 */ +382 R("h1", "S", LRS_BODY, LWS_WSIEV_BODY_COMPLETE, NULL, NULL, LRS_DOING_TRANSACTION), +383 R("h2", "S", LRS_BODY, LWS_WSIEV_BODY_COMPLETE, NULL, NULL, LRS_ESTABLISHED), +384 R("h3", "S", LRS_BODY, LWS_WSIEV_BODY_COMPLETE, NULL, NULL, LRS_ESTABLISHED), +385 /* the body completion callback may itself have started serving a file (C-522) */ +386 R("h2", "S", LRS_ISSUING_FILE, LWS_WSIEV_BODY_COMPLETE, NULL, NULL, LRS_ISSUING_FILE), +387 R("h3", "S", LRS_ISSUING_FILE, LWS_WSIEV_BODY_COMPLETE, NULL, NULL, LRS_ISSUING_FILE), +388 R("h1", "S", LRS_BODY, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +389 /* the user may complete the transaction before the body was ever delivered */ +390 R("h1", "S", LRS_ESTABLISHED, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +391 R("h1", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +392 R("h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +393 /* the completion runs for mux streams too: there DISCARD_BODY drops the stash and closes the stream */ +394 R("h2", "S", LRS_ESTABLISHED, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +395 R("h2", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +396 R("h3", "S", LRS_ESTABLISHED, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +397 R("h3", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +398 R("h2", "S", LRS_BODY, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +399 R("h3", "S", LRS_BODY, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +400 R("h2", "S", LRS_ISSUING_FILE, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +401 R("h3", "S", LRS_ISSUING_FILE, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +402 /* ...or abandoned with a read of the file out on a worker, reaped by the completion */ +403 R("h2", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +404 R("h3", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +405 +406 /* the h1 transaction ends and the connection is reused */ +407 /* +408 * the user completed it with its response still queued: completion +409 * waits for that to go, from wherever the transaction had got to +410 */ +411 R("h1", "S", LRS_ESTABLISHED, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +412 R("h1", "S", LRS_BODY, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +413 R("h1", "S", LRS_DISCARD_BODY, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), /* only an app writing after it completed */ +414 R("h1", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +415 R("h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +416 R("h1", "S", LRS_TXN_COMPLETED, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), /* only an app answering again after it completed */ +417 R("h1", "S", LRS_TXN_COMPLETING, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), /* only an app completing twice */ +418 R("h2", "S", LRS_HEADERS, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +419 R("h2", "S", LRS_ESTABLISHED, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +420 R("h2", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +421 R("h2", "S", LRS_BODY, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +422 R("h2", "S", LRS_DISCARD_BODY, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +423 R("h2", "S", LRS_ISSUING_FILE, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +424 R("h2", "S", LRS_TXN_COMPLETING, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), /* only an app completing twice */ +425 R("h3", "S", LRS_ESTABLISHED, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +426 R("h3", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +427 R("h3", "S", LRS_BODY, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +428 R("h3", "S", LRS_DISCARD_BODY, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +429 R("h3", "S", LRS_ISSUING_FILE, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +430 R("h3", "S", LRS_TXN_COMPLETING, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +431 /* +432 * a file being served, a read of it out on a worker, that the app +433 * completed from under (an h2 / h3 body completion, its own timer): +434 * the completion waits for the answer queued so far as any other +435 */ +436 R("h2", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +437 R("h3", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_TXN_COMPLETING, NULL, NULL, LRS_TXN_COMPLETING), +438 /* ...and once it has, it completes, or first discards an unread body */ +439 R("h1", "S", LRS_TXN_COMPLETING, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED), +440 R("h1", "S", LRS_TXN_COMPLETING, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +441 R("h2", "S", LRS_TXN_COMPLETING, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +442 R("h3", "S", LRS_TXN_COMPLETING, LWS_WSIEV_BODY_DISCARD, NULL, NULL, LRS_DISCARD_BODY), +443 +444 R("h1", "S", LRS_ESTABLISHED, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED), +445 R("h1", "S", LRS_BODY, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED), +446 R("h1", "S", LRS_DISCARD_BODY, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED), +447 R("h1", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED), +448 R("h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED), /* upgrade refused */ +449 R("h1", "S", LRS_TXN_COMPLETED, LWS_WSIEV_TXN_COMPLETED, NULL, NULL, LRS_TXN_COMPLETED), /* only an app completing twice */ +450 R("h1", "S", LRS_TXN_COMPLETED, LWS_WSIEV_TXN_DRAINED, NULL, NULL, LRS_HEADERS), +451 +452 /* serving a file */ +453 R("*", "S", LRS_ESTABLISHED, LWS_WSIEV_FILE_BEGIN, NULL, NULL, LRS_ISSUING_FILE), +454 R("h2", "S", LRS_HEADERS, LWS_WSIEV_FILE_BEGIN, NULL, NULL, LRS_ISSUING_FILE), /* h2c upgrade stream 1 */ +455 R("*", "S", LRS_DOING_TRANSACTION, LWS_WSIEV_FILE_BEGIN, NULL, NULL, LRS_ISSUING_FILE), +456 R("*", "S", LRS_BODY, LWS_WSIEV_FILE_BEGIN, NULL, NULL, LRS_ISSUING_FILE), /* served from HTTP_BODY_COMPLETION */ +457 R("h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_FILE_BEGIN, NULL, NULL, LRS_ISSUING_FILE), /* served from HTTP_CONFIRM_UPGRADE */ +458 /* a file read on a worker: LWS_WITH_ASYNC_QUEUE */ +459 R("*", "S", LRS_ISSUING_FILE, LWS_WSIEV_FILE_READ_QUEUED, NULL, NULL, LRS_AWAITING_FILE_READ), +460 R("*", "S", LRS_AWAITING_FILE_READ, LWS_WSIEV_FILE_READ_DONE, NULL, NULL, LRS_ISSUING_FILE), +461 R("*", "S", LRS_ISSUING_FILE, LWS_WSIEV_FILE_COMPLETE, NULL, NULL, LRS_ESTABLISHED), +462 +463 /* ---- role changes ---- */ +464 +465 /* birth on a server, adoption, the client bind, a restart */ +466 R("(none)", "-", LRS_UNCONNECTED, LWS_WSIEV_SERVER_SIDE, NULL, "S", LRS_UNCONNECTED), +467 R("*", "*", LRS_UNCONNECTED, LWS_WSIEV_ADOPTED_TLS, "?", NULL, LRS_SSL_INIT), +468 R("*", "*", LRS_UNCONNECTED, LWS_WSIEV_ADOPTED, "h1", NULL, LRS_HEADERS), +469 R("*", "*", LRS_UNCONNECTED, LWS_WSIEV_ADOPTED, "?", NULL, LRS_ESTABLISHED), +470 R("*", "*", LRS_UNCONNECTED, LWS_WSIEV_CLIENT_BIND, "?", "C", LRS_UNCONNECTED), +471 R("*", "C", ANY, LWS_WSIEV_RESTART, "?", "C", LRS_UNCONNECTED), +472 +473 /* mux children: a fresh child is its parent's; a server's opened stream reads its request */ +474 R("(none)", "*", LRS_UNCONNECTED, LWS_WSIEV_MUX_INSERTED, "P", "P", LRS_UNCONNECTED), +475 R("h2", "S", LRS_UNCONNECTED, LWS_WSIEV_STREAM_OPENED, NULL, NULL, LRS_HEADERS), +476 R("h2", "C", LRS_UNCONNECTED, LWS_WSIEV_STREAM_OPENED, NULL, NULL, LRS_UNCONNECTED), +477 R("quic", "S", LRS_UNCONNECTED, LWS_WSIEV_STREAM_OPENED, "h3", NULL, LRS_HEADERS), +478 R("quic", "C", LRS_UNCONNECTED, LWS_WSIEV_STREAM_OPENED, "h3", NULL, LRS_ESTABLISHED), +479 R("quic", "*", LRS_UNCONNECTED, LWS_WSIEV_STREAM_OPENED, "quic", NULL, LRS_ESTABLISHED), +480 +481 /* a client stream is let onto its connection: h2 / h3 send a request, mqtt is up */ +482 R("*", "*", LRS_UNCONNECTED, LWS_WSIEV_MUX_STREAM_ADOPTED, "h2", "P", LRS_H2_WAITING_TO_SEND_HEADERS), +483 R("*", "*", LRS_H1C_ISSUE_HANDSHAKE2, LWS_WSIEV_MUX_STREAM_ADOPTED, "h2", "P", LRS_H2_WAITING_TO_SEND_HEADERS), +484 R("*", "*", LRS_UNCONNECTED, LWS_WSIEV_MUX_STREAM_ADOPTED, "h3", "P", LRS_H2_WAITING_TO_SEND_HEADERS), +485 R("*", "*", LRS_H1C_ISSUE_HANDSHAKE2, LWS_WSIEV_MUX_STREAM_ADOPTED, "h3", "P", LRS_H2_WAITING_TO_SEND_HEADERS), +486 R("*", "*", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_MUX_STREAM_ADOPTED, "h3", "P", LRS_H2_WAITING_TO_SEND_HEADERS), +487 R("*", "*", LRS_UNCONNECTED, LWS_WSIEV_MUX_STREAM_ADOPTED, "mqtt", "P", LRS_ESTABLISHED), +488 R("*", "*", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_MUX_STREAM_ADOPTED, "mqtt", "P", LRS_ESTABLISHED), +489 +490 /* our own h3 unidirectional streams, and a wsi taking over a quic connection */ +491 R("(none)", "*", LRS_UNCONNECTED, LWS_WSIEV_CONTROL_STREAM_OPENED, "h3", "L", LRS_ESTABLISHED), +492 R("(none)", "*", LRS_UNCONNECTED, LWS_WSIEV_CONN_TAKEOVER, "?", "L", LRS_ESTABLISHED), +493 +494 /* the quic handshake chose h3 (a client stream sends, a server stream reads) or not */ +495 /* +496 * the h3 alpn walk moves children it finds unconnected or connecting; +497 * no path is known to leave one so, but the walk asks +498 */ +499 R("*", "C", LRS_UNCONNECTED, LWS_WSIEV_ALPN_DONE, "h3", NULL, LRS_H2_WAITING_TO_SEND_HEADERS), +500 R("*", "C", LRS_WAITING_CONNECT, LWS_WSIEV_ALPN_DONE, "h3", NULL, LRS_H2_WAITING_TO_SEND_HEADERS), +501 R("quic", "C", ANY, LWS_WSIEV_ALPN_DONE, "h3", NULL, LRS_H2_WAITING_TO_SEND_HEADERS), +502 R("quic", "S", ANY, LWS_WSIEV_ALPN_DONE, "h3", NULL, LRS_HEADERS), +503 R("quic", "*", ANY, LWS_WSIEV_ALPN_DONE, "quic", NULL, LRS_ESTABLISHED), +504 +505 /* +506 * the h2 client nwsi hands its own request to the sid-1 child and is +507 * from then on the carrier of streams only: established +508 */ +509 R("h2", "C", LRS_H2_WAITING_TO_SEND_HEADERS, LWS_WSIEV_MUX_MIGRATED, NULL, NULL, LRS_ESTABLISHED), +510 +511 /* h2: chosen by alpn, h2c upgrade or prior knowledge; the client preface */ +512 R("h1", "S", LRS_HEADERS, LWS_WSIEV_H2_SELECTED, "h2", NULL, LRS_H2_AWAIT_PREFACE), +513 R("h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_H2_SELECTED, "h2", NULL, LRS_H2_AWAIT_PREFACE), +514 R("(none)", "S", LRS_UNCONNECTED, LWS_WSIEV_H2_SELECTED, "h2", NULL, LRS_H2_AWAIT_PREFACE), +515 R("h1", "C", LRS_H1C_ISSUE_HANDSHAKE, LWS_WSIEV_H2_SELECTED, "h2", NULL, LRS_H2_AWAIT_PREFACE), +516 R("h1", "C", LRS_WAITING_SSL, LWS_WSIEV_H2_SELECTED, "h2", NULL, LRS_H2_AWAIT_PREFACE), +517 R("h2", "C", LRS_H2_AWAIT_PREFACE, LWS_WSIEV_H2_PREFACE_SENT, NULL, NULL, LRS_H2_WAITING_TO_SEND_HEADERS), +518 +519 /* ws upgrade, on a server from the upgrade decision, on a client from the 101 */ +520 R("h1", "S", LRS_H1_UPGRADE, LWS_WSIEV_WS_UPGRADED, "ws", NULL, LRS_ESTABLISHED), +521 R("h2", "S", LRS_ESTABLISHED, LWS_WSIEV_WS_UPGRADED, "ws", "Se", LRS_ESTABLISHED), +522 R("h3", "S", LRS_ESTABLISHED, LWS_WSIEV_WS_UPGRADED, "ws", "Se", LRS_ESTABLISHED), /* RFC 9220 */ +523 R("h1", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_WS_UPGRADED, "ws", NULL, LRS_ESTABLISHED), +524 R("h2", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_WS_UPGRADED, "ws", "Ce", LRS_ESTABLISHED), +525 R("h3", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_WS_UPGRADED, "ws", "Ce", LRS_ESTABLISHED), /* RFC 9220 */ +526 +527 /* the client's response headers; webtransport; raw */ +528 R("*", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_RESP_HDRS, NULL, NULL, LRS_ESTABLISHED), +529 /* a server may answer before the request body is finished (401, 413...) */ +530 R("*", "C", LRS_ISSUE_HTTP_BODY, LWS_WSIEV_RESP_HDRS, NULL, NULL, LRS_ESTABLISHED), +531 R("h3", "C", LRS_WAITING_SERVER_REPLY, LWS_WSIEV_WT_SESSION, "wt", NULL, LRS_ESTABLISHED), +532 R("h3", "S", ANY, LWS_WSIEV_WT_SESSION, "wt", NULL, LRS_ESTABLISHED), +533 R("h3", "*", ANY, LWS_WSIEV_WT_STREAM, "wt", NULL, LRS_ESTABLISHED), +534 R("(none)", "*", LRS_UNCONNECTED, LWS_WSIEV_WT_STREAM, "wt", "L", LRS_ESTABLISHED), +535 R("*", "S", LRS_HEADERS, LWS_WSIEV_RAW_UPGRADED, "?", NULL, LRS_ESTABLISHED), +536 /* the non-tls fallback on a tls listener, from the first byte peek in the accept */ +537 R("*", "S", LRS_SSL_ACK_PENDING, LWS_WSIEV_RAW_UPGRADED, "?", NULL, LRS_ESTABLISHED), +538 /* a later request on a kept-alive connection, and a listener already in the raw role */ +539 R("*", "S", LRS_ESTABLISHED, LWS_WSIEV_RAW_UPGRADED, "?", NULL, LRS_ESTABLISHED), +540 /* ---- transport machine ---- */ +541 +542 R("*", "C", LRS_UNCONNECTED, LWS_WSIEV_DNS_START, NULL, NULL, XT(LTS_WAITING_DNS)), +543 R("*", "C", LRS_WAITING_DNS, LWS_WSIEV_DNS_RETRY, NULL, NULL, XT(LTS_NONE)), +544 R("*", "C", LRS_UNCONNECTED, LWS_WSIEV_CONNECT_START, NULL, NULL, XT(LTS_WAITING_CONNECT)), +545 R("*", "C", LRS_WAITING_DNS, LWS_WSIEV_CONNECT_START, NULL, NULL, XT(LTS_WAITING_CONNECT)), +546 R("*", "C", LRS_WAITING_CONNECT, LWS_WSIEV_CONNECT_START, NULL, NULL, XT(LTS_WAITING_CONNECT)), /* next address */ +547 R("*", "C", LRS_WAITING_SSL, LWS_WSIEV_CONNECT_START, NULL, NULL, XT(LTS_WAITING_CONNECT)), /* quic to tcp */ +548 R("*", "C", LRS_WAITING_CONNECT, LWS_WSIEV_PROXY_CONNECT_SENT, NULL, NULL, XT(LTS_WAITING_PROXY_REPLY)), +549 R("*", "C", LRS_WAITING_CONNECT, LWS_WSIEV_SOCKS_GREETING_SENT, NULL, NULL, XT(LTS_WAITING_SOCKS_GREETING_REPLY)), +550 R("*", "C", LRS_WAITING_SOCKS_GREETING_REPLY, LWS_WSIEV_SOCKS_AUTH_SENT, NULL, NULL, XT(LTS_WAITING_SOCKS_AUTH_REPLY)), +551 R("*", "C", LRS_WAITING_SOCKS_GREETING_REPLY, LWS_WSIEV_SOCKS_CONNECT_SENT, NULL, NULL, XT(LTS_WAITING_SOCKS_CONNECT_REPLY)), +552 R("*", "C", LRS_WAITING_SOCKS_AUTH_REPLY, LWS_WSIEV_SOCKS_CONNECT_SENT, NULL, NULL, XT(LTS_WAITING_SOCKS_CONNECT_REPLY)), +553 R("*", "C", LRS_WAITING_CONNECT, LWS_WSIEV_TLS_START, NULL, NULL, XT(LTS_WAITING_SSL)), +554 R("*", "C", LRS_WAITING_PROXY_REPLY, LWS_WSIEV_TLS_START, NULL, NULL, XT(LTS_WAITING_SSL)), +555 R("*", "C", LRS_WAITING_SOCKS_CONNECT_REPLY, LWS_WSIEV_TLS_START, NULL, NULL, XT(LTS_WAITING_SSL)), +556 R("*", "C", LRS_H1C_ISSUE_HANDSHAKE, LWS_WSIEV_TLS_START, NULL, NULL, XT(LTS_WAITING_SSL)), +557 R("*", "C", LRS_WAITING_SSL, LWS_WSIEV_TLS_START, NULL, NULL, XT(LTS_WAITING_SSL)), /* more service */ +558 /* +559 * STARTTLS: an established raw client starts tls inside its protocol +560 * (the smtp client, LWS_WITH_EMAIL) +561 */ +562 R("raw-skt", "C", LRS_ESTABLISHED, LWS_WSIEV_TLS_START, NULL, NULL, XT(LTS_WAITING_SSL)), +563 R("*", "S", LRS_SSL_INIT, LWS_WSIEV_TLS_ACCEPT_PENDING, NULL, NULL, XT(LTS_SSL_ACK_PENDING)), +564 R("*", "S", LRS_SSL_ACK_PENDING, LWS_WSIEV_TLS_ACCEPT_PENDING, NULL, NULL, XT(LTS_SSL_ACK_PENDING)), +565 /* each step of the accept on a worker: LWS_WITH_ASYNC_QUEUE with LWS_MAX_SMP > 1 */ +566 R("*", "S", LRS_AWAITING_SSL_ACCEPT, LWS_WSIEV_TLS_ACCEPT_PENDING, NULL, NULL, XT(LTS_SSL_ACK_PENDING)), +567 R("*", "S", LRS_SSL_ACK_PENDING, LWS_WSIEV_TLS_ACCEPT_QUEUED, NULL, NULL, XT(LTS_AWAITING_SSL_ACCEPT)), +568 R("*", "C", ANY, LWS_WSIEV_CONN_FAILED, NULL, NULL, XT(LTS_FAILED)), +569 R("*", "C", ANY, LWS_WSIEV_RETARGET, NULL, NULL, XT(LTS_RESTARTING)), +570 +571 /* ---- close machine: the polite ws close is specific, the rest can come from anywhere ---- */ +572 +573 R("ws", "*", LRS_ESTABLISHED, LWS_WSIEV_WS_CLOSE_INITIATED, NULL, NULL, XC(LCS_WAITING_TO_SEND_CLOSE)), +574 R("ws", "*", LRS_WAITING_TO_SEND_CLOSE, LWS_WSIEV_WS_CLOSE_SENT, NULL, NULL, XC(LCS_AWAITING_CLOSE_ACK)), +575 R("ws", "*", LRS_ESTABLISHED, LWS_WSIEV_WS_PEER_CLOSE, NULL, NULL, XC(LCS_RETURNED_CLOSE)), +576 /* +577 * his CLOSE beat the one we were about to send: answer his and drop +578 * ours. Only ws over a mux stream gets here: its network connection +579 * goes on reading for its other streams, where a ws connection of its +580 * own reads nothing more until its close has gone +581 */ +582 R("ws", "*", LRS_WAITING_TO_SEND_CLOSE, LWS_WSIEV_WS_PEER_CLOSE, NULL, NULL, XC(LCS_RETURNED_CLOSE)), +583 /* +584 * the close is entered: a flush the live connection had begun is now +585 * the close's own, else the close has begun with nothing to wait for +586 */ +587 R("*", "*", LRS_FLUSHING_BEFORE_CLOSE, LWS_WSIEV_CLOSE_ENTERED, NULL, NULL, XC(LCS_FLUSHING_BEFORE_CLOSE)), +588 R("*", "*", ANY, LWS_WSIEV_CLOSE_ENTERED, NULL, NULL, XC(LCS_CLOSING)), +589 R("*", "*", ANY, LWS_WSIEV_CLOSE_FLUSH, NULL, NULL, XC(LCS_FLUSHING_BEFORE_CLOSE)), +590 R("*", "*", ANY, LWS_WSIEV_CLOSE_WHEN_FLUSHED, NULL, NULL, XC(LCS_CLOSE_WHEN_FLUSHED)), +591 R("*", "S", ANY, LWS_WSIEV_CLOSE_STAGED, NULL, NULL, XC(LCS_SHUTDOWN)), +592 R("*", "*", ANY, LWS_WSIEV_SOCKET_GONE, NULL, NULL, XC(LCS_DEAD_SOCKET)), +593 R("*", "*", LRS_DEAD_SOCKET, LWS_WSIEV_USER_TOLD, NULL, NULL, XC(LCS_USER_TOLD)), +594 diff --git a/crates/npro-test/tests/states.rs b/crates/npro-test/tests/states.rs index bac4213..8cc5475 100644 --- a/crates/npro-test/tests/states.rs +++ b/crates/npro-test/tests/states.rs @@ -233,6 +233,8 @@ mod states { #[derive(Clone, Debug)] struct Row { + /// The row's line in C's wsi-state.c, by which C's trace names it. + line: u32, role: String, side: String, from: Option<String>, @@ -298,12 +300,14 @@ mod states { let text = fs::read_to_string(states_dir().join("wsi-event-edges.txt")).unwrap(); let mut rows = Vec::new(); + // each line of the table, after its line in wsi-state.c and a tab; + // a row is R(role, side, from, event, to_role, to_side, to) for line in text.lines() { - let line = line.trim(); - if !line.starts_with('{') { + let (n, src) = line.split_once('\t').unwrap(); + let Some(row) = src.trim().strip_prefix("R(") else { continue; - } - let body = &line[1..line.find('}').unwrap()]; + }; + let body = &row[..row.find("),").unwrap()]; let f: Vec<&str> = body.split(',').map(str::trim).collect(); assert_eq!(f.len(), 7, "row {line}"); @@ -320,6 +324,7 @@ mod states { }; rows.push(Row { + line: n.parse().unwrap(), role: f[0].trim_matches('"').to_owned(), side: f[1].trim_matches('"').to_owned(), from, @@ -329,7 +334,7 @@ mod states { to, }); } - assert!(rows.len() > 200, "only {} rows read", rows.len()); + assert!(rows.len() > 150, "only {} rows read", rows.len()); rows } @@ -343,12 +348,17 @@ mod states { Refused, } - /// `lws_wsi_event_x()`, with `LWS_WITH_STATE_CHECK`'s check of the result. - fn c_event(rows: &[Row], w: &Word, ev: &str, ops: Option<&'static str>) -> COutcome { + /// The row of C's table an event matches: the first, as in C. + fn c_row<'a>( + rows: &'a [Row], + w: &Word, + ev: &str, + ops: Option<&'static str>, + ) -> Option<&'a Row> { let from = w.reported(); let w_side = w.side.to_string(); - let Some(r) = rows.iter().find(|r| { + rows.iter().find(|r| { r.ev == ev && r.from.as_deref().is_none_or(|f| f == from) && (r.role == "*" || r.role == w.role) @@ -359,7 +369,12 @@ mod states { (Some(t), Some(o)) => t != "P" && t == o, (None, Some(_)) => false, } - }) else { + }) + } + + /// `lws_wsi_event_x()`, with `LWS_WITH_STATE_CHECK`'s check of the result. + fn c_event(rows: &[Row], w: &Word, ev: &str, ops: Option<&'static str>) -> COutcome { + let Some(r) = c_row(rows, w, ev, ops) else { return COutcome::Refused; }; @@ -556,7 +571,12 @@ mod states { Some(role) => n.event_as(ev, role), }; let theirs = c_event(&rows, &w, ev.name(), site.map(Role::name)); - let what = format!("{} ev={} site={site:?}", w.fmt(), ev.name()); + // C's row, by its line in wsi-state.c, if one matches + let row = c_row(&rows, &w, ev.name(), site.map(Role::name)).map_or_else( + || "no row".to_owned(), + |r| format!("wsi-state.c:{}", r.line), + ); + let what = format!("{} ev={} site={site:?} ({row})", w.fmt(), ev.name()); match (ours, theirs) { (Err(_), COutcome::Refused) => {} diff --git a/scripts/sync-c-states.sh b/scripts/sync-c-states.sh index 3bf0340..8e6c853 100755 --- a/scripts/sync-c-states.sh +++ b/scripts/sync-c-states.sh @@ -4,16 +4,34 @@ # # scripts/sync-c-states.sh /path/to/libwebsockets [build dir] # -# The rows of C's event table go to crates/npro-test/states/, verbatim, and -# the state edges C's ctest suite takes beside them, from a build with -# LWS_WITH_STATE_TRACE and LWS_WITH_STATE_CHECK (so the suite also aborts on -# any edge the table does not allow). The C commit is recorded in C-COMMIT. -# The checkout should be clean, as for sync-c-oracle.sh. +# Into crates/npro-test/states/, replacing what is there: # -# The build goes to <checkout>/build-npro-states unless a build dir is -# given; it is reconfigured each time. It is a default build without h3, -# which needs gnutls; C's ctest-background.sh needs netstat or ss to see its -# test servers come up. The suite takes some minutes. +# wsi-event-edges.txt the rows of C's event table, each line of the table +# prefixed by its line in wsi-state.c, which is how +# C's trace names a row +# edges.txt every distinct state edge C's ctest suite takes, +# sorted, without each connection's tag +# rows-fired.txt every row of the table the suite fires, from C's +# LRSROW lines +# README.lws.md C's README.wsi-state-machines.md, which lists the +# rows no test fires and why +# C-COMMIT the C commit +# +# The suite runs in the three builds C's README measures coverage over: the +# default, one adding the options some rows need, and one with tls accepts +# on a worker. Each has LWS_WITH_STATE_TRACE and LWS_WITH_STATE_CHECK, so +# the suite also aborts on any edge the table does not allow. h3 is left +# out, since it needs gnutls. +# +# The builds go to <build dir>-<name>, by default <checkout>/build-npro- +# states-<name>; they are reconfigured each time. C's ctest-background.sh +# needs netstat or ss to see its test servers come up. Expect most of an +# hour. The checkout should be clean, as for sync-c-oracle.sh. +# +# Any failing test stops the sync: the edges are only an oracle from a +# suite that passes. CTEST_ARGS is passed to every ctest, eg, +# CTEST_ARGS="-E api-test-foo" to leave out a test that fails for reasons +# outside the state machines; the commit names it, and why. set -eu @@ -26,6 +44,7 @@ c="$1" b="${2:-$c/build-npro-states}" here="$(cd "$(dirname "$0")/.." && pwd)" dst="$here/crates/npro-test/states" +jobs="${SAI_PARALLEL:-4}" if [ -n "$(git -C "$c" status --porcelain -- lib include CMakeLists.txt)" ]; then echo "$c has uncommitted changes" >&2 @@ -36,28 +55,47 @@ if ! command -v netstat >/dev/null 2>&1 && ! command -v ss >/dev/null 2>&1; then exit 1 fi -cmake -S "$c" -B "$b" -DCMAKE_BUILD_TYPE=DEBUG \ - -DLWS_WITH_STATE_TRACE=ON -DLWS_WITH_STATE_CHECK=ON \ - -DLWS_WITH_HTTP3=OFF -DLWS_WITH_MINIMAL_EXAMPLES=ON \ - -DLWS_WITHOUT_EXTENSIONS=OFF -DLWS_WITH_ZLIB=ON \ - -DLWS_WITH_SYS_FAULT_INJECTION=ON -cmake --build "$b" -j "${SAI_PARALLEL:-4}" - raw="$(mktemp)" trap 'rm -f "$raw"' EXIT -(cd "$b" && LWS_STATE_TRACE_FILE="$raw" ctest -j "${SAI_PARALLEL:-4}" --timeout 180) -# the table's rows, between its opening and its closing brace +# run C's suite in one build: $1 its name, the rest its cmake options +suite() { + name="$1" + shift + echo "== C build: $name" + cmake -S "$c" -B "$b-$name" -DCMAKE_BUILD_TYPE=DEBUG \ + -DLWS_WITH_STATE_TRACE=ON -DLWS_WITH_STATE_CHECK=ON \ + -DLWS_WITH_HTTP3=OFF -DLWS_WITH_MINIMAL_EXAMPLES=ON \ + -DLWS_WITHOUT_EXTENSIONS=OFF -DLWS_WITH_ZLIB=ON "$@" + cmake --build "$b-$name" -j "$jobs" + # shellcheck disable=SC2086 + (cd "$b-$name" && LWS_STATE_TRACE_FILE="$raw" \ + ctest -j "$jobs" --timeout 180 ${CTEST_ARGS:-}) +} + +suite default +suite options -DLWS_WITH_ASYNC_QUEUE=ON -DLWS_WITH_SOCKS5=ON \ + -DLWS_ROLE_MQTT=ON -DLWS_WITH_HTTP_PROXY=ON -DLWS_ROLE_RAW_PROXY=ON \ + -DLWS_WITH_SYS_FAULT_INJECTION=ON -DLWS_WITH_EMAIL=ON +suite worker -DLWS_WITH_ASYNC_QUEUE=ON -DLWS_MAX_SMP=2 + +# the table, each line with its line in wsi-state.c awk '/^static const struct lws_wsi_event_edge lws_wsi_event_edges\[\] = \{/ { f = 1; next } f && /^\};/ { exit } - f' "$c/lib/sansio/wsi-state.c" > "$dst/wsi-event-edges.txt" + f { printf "%d\t%s\n", NR, $0 }' "$c/lib/sansio/wsi-state.c" > "$dst/wsi-event-edges.txt" # each edge once, without the connection's tag: "LRS from -> to how [ev=X]" -sed -E -e 's/^(LRS [^ ]+ -> [^ ]+ [^ ]+) .*( ev=[A-Z0-9_]+)$/\1\2/' -e t \ - -e 's/^(LRS [^ ]+ -> [^ ]+ [^ ]+) .*$/\1/' "$raw" | +grep '^LRS ' "$raw" | + sed -E -e 's/^(LRS [^ ]+ -> [^ ]+ [^ ]+) .*( ev=[A-Z0-9_]+)$/\1\2/' -e t \ + -e 's/^(LRS [^ ]+ -> [^ ]+ [^ ]+) .*$/\1/' | LC_ALL=C sort -u > "$dst/edges.txt" +# each row fired, once: "LRSROW <line> role side from event" +grep '^LRSROW ' "$raw" | sort -u -k2,2n > "$dst/rows-fired.txt" + +cp "$c/READMEs/README.wsi-state-machines.md" "$dst/README.lws.md" git -C "$c" log -1 --format='%H %s' > "$dst/C-COMMIT" -echo "$(grep -c '^[[:space:]]*{' "$dst/wsi-event-edges.txt") rows and" \ +echo "$(grep -c ' [[:space:]]*R(' "$dst/wsi-event-edges.txt") rows," \ + "$(wc -l < "$dst/rows-fired.txt") fired, and" \ "$(wc -l < "$dst/edges.txt") edges from $(cut -c1-12 "$dst/C-COMMIT")"
Page fetched 0s ago, creation time: 9ms (vhost etag hits: 0%, cache hits: 0%)