Skip to content

refuse unsupported quic client streams without closing the connection - #229

Merged
fabracht merged 1 commit into
mainfrom
quic-client-bidi-flows
Oct 12, 2026
Merged

fabracht merged 1 commit into
mainfrom
quic-client-bidi-flows

Conversation

@fabracht

Copy link
Copy Markdown
Contributor

Part of #207. The broker closed the whole QUIC connection with ERROR_PROTOCOL_L0 for any client-opened bidirectional stream that was not a flow discard. MQoQ §9.10 says the acceptor checks the flow header and, if it is invalid or unsupported, aborts that stream with an error code. §11 keeps flow errors isolated so the connection survives.

What changes:

  • User-defined flows (0x14) are recognised on both stream types and refused with ERROR_FLOW_REFUSED, the same code our client uses since refuse quic user-defined flows on server streams #204. Before, a unidirectional one was read as MQTT: 14 02 68 69 closed the connection as a malformed packet, and 14 61 70 70 was left open waiting for bytes.
  • A server data flow header from the client, or a client data flow whose flow ID has the server bit set, is refused with ERROR_BAD_FLOW_ID (§9.4, §9.10: an initiator/type mismatch on a data flow is a level 1 flow error). Before, a unidirectional one was accepted as a data flow.
  • A control flow header on any stream but the control stream, and a bidirectional stream without a flow header, are refused with ERROR_STREAM_TYPE.
  • A bidirectional client data flow is refused with ERROR_FLOW_REFUSED. Serving it on its own stream, as §9.1.2 requires for its acks and PINGRESP, is the next PR.
  • A discard is only a header followed directly by FIN (§9.16). Before, a header with the discard flags followed by data was treated as a discard and the data dropped.
  • A discard removes the flow's subscriptions before the broker answers with FIN. Before, the flow state went but its subscriptions stayed, so messages were still delivered to the discarded flow.
  • A unidirectional flow that ends inside a packet is logged as a warning. §9.13.1 asks for ERROR_INCOMPLETE_PACKET, but once the client has finished a unidirectional stream nothing can be sent back on it.

quic_flow_streams.rs covers each case. Against main, 7 of its 10 tests fail. The 3 that pass are the controls: a unidirectional data flow is still served, a discard ended by FIN is still answered with FIN, and a unidirectional flow ending inside a packet still keeps the session. The subscription test also checks that without a discard the aborted flow keeps receiving.

@fabracht
fabracht merged commit 91e5aad into main Oct 12, 2026
16 checks passed
@fabracht
fabracht deleted the quic-client-bidi-flows branch October 12, 2026 03:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant