rustdesk dccf317b01 webrtc: fix the send/cache/ICE-lifetime findings; bound log retention by volume
Continues the review pass. Eight findings, each verified against the
vendored webrtc-rs (0.13 / -data 0.11 / -ice 0.13) rather than inferred:

- a mid-message dc.write() failure returned the error and left the pc
  open, so the peer kept an unterminated FRAG_MORE prefix and appended
  the next message to it - undetectable, since this framing carries no
  length or sequence number, and callers wrap sends in allow_err!. Close
  the stream when fragments are already on the wire.

- one deadline covered the connect-wait, the gate queue and every write.
  A slow ICE/DTLS completion therefore ate the budget and the write
  timed out into a pc.close() an RTT from working; and the gate arm
  closed the pc from a task that never held the permit, aborting a
  healthy sender's fragment sequence - the exact corruption the permit
  exists to prevent. Connection setup gets its own budget, and only the
  arm holding the permit tears down.

- a SESSIONS hit returned a pc built for the first caller, so a replayed
  offer could get an All-policy connection where the mediator had just
  computed Relay-only, with is_relayed() answering from the cached
  handle. It could also hand back a stream the state handler had already
  closed (it closes before it evicts). Reject both; peer_verified stays
  shared, being a fact about the certificate the entry is keyed by.

- the ICE-candidate sender lives in the on_ice_candidate handler and
  close() clears no handler, so the receiver never closed and the
  forwarder loop this API asks callers to write parked on recv() holding
  a stream clone - one leaked task plus one leaked pc per connection.
  The terminal-state handler now drops that closure. Regression test
  included (fails, by 20s timeout, with the drop removed).

- has_turn_server() accepted the RFC 7065 spelling `turn:host:port`,
  which url makes cannot-be-a-base: host_str() is None, so the server
  became a hostless "turn::3478" that still passed the scheme check.
  force_relay then built a Relay-only pc that could only time out. Parse
  host and port out of the path (IPv6 literals included), and make the
  gate require a host.

- is_relayed() read the stats report's `nominated` flag, which
  webrtc-ice sets per checklist entry and never clears, so after a pair
  switch several entries carry it and HashMap order picked the answer.
  Read the selected pair instead - which also drops a redundant stats
  round trip.

- the ICE-server parsing tests rewrote the process-global, on-disk
  `ice-servers` option while sibling loopback tests were building peer
  connections from it. Split parsing out of get_ice_servers so they can
  test it directly; the suite now passes in parallel.

- log retention is a file count, so pairing it with the new 16 MiB size
  criterion let a flooder rotate away every file predating its own
  activity. Keep enough files that ~31 days survives even at full size.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ExUfAkYbq8UC9pQCiLy8TQ
2026-08-22 13:21:01 +08:00
2025-11-20 14:58:10 +08:00
2025-01-20 16:06:27 +08:00
2025-01-20 16:06:27 +08:00
S
Description
No description provided
86 MiB
Languages
Rust 100%