A stateless-by-default DTLS ClientHello probe that classifies a host:port
as DEAD/LIVE/COMPLETED/REJECTED in ~1 RTT off the server's first flight,
sitting in front of the full handshake.
Probe (smartthings_local/protocol/dtls_probe.py):
- Stateless liveness mode (default): stops at HelloVerifyRequest and never
sends the cookie'd second ClientHello, so by RFC 6347 §4.2.1 it leaves
no association on the device — safe to run before a real connect.
- Diagnostic mode (stateless=False): drives the handshake further to
capture cipher/cert-chain/CertificateRequest or a fatal Alert, for
OCF-PKI-wall characterization (#16). Kept out of hot reconnect paths.
- Retransmit + retries: services OpenSSL's DTLS retransmit timer so a
single dropped ClientHello no longer reads as a false DEAD.
MQTT bridge (mqtt_demo):
- Stateless pre-flight gate in session_once() rejects a silent/rebooting
device or wrong port in ~3s (retries=1) instead of eating the 12s
HANDSHAKE_TIMEOUT_S per reconnect.
- OCF-band port autodiscovery when OCF_PORT is unset: races the band in
parallel and returns on the first port to answer LIVE (~1 RTT, abandoning
the dead-port probes), cached across reconnects; the stateless gate
leaves no orphan, preserving the fixed-source-port §4.2.8 invariant.
Validated on real hardware (dryer 49155 / oven 49154): parallel discovery
resolves both ports in <1s, connect with no orphan cooldown, and a wrong
pinned port rejected in ~3s.
Tests: probe behaviour (retransmit recovery, stateless single-flight
guard, silent-port flight budget, diagnostic continuation) and bridge
port-resolution (pinned gate, parallel discovery early-exit, cache).