Skip to content

Commit e953db0

Browse files
committed
fixup! fix(core/thp): keep reading when writes are blocked
1 parent bff72cd commit e953db0

1 file changed

Lines changed: 24 additions & 27 deletions

File tree

core/src/trezor/wire/thp/channel.py

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -436,49 +436,46 @@ async def write_encrypted_payload(self, ctrl_byte: int, payload: AnyBytes) -> No
436436

437437
header = PacketHeader(ctrl_byte, self.get_channel_id_int(), payload_len)
438438

439+
ack_latency_ms = self.channel_cache.get_int(CHANNEL_ACK_LATENCY_MS) or 0
440+
441+
# ACK is needed before sending more data
442+
ABP.set_sending_allowed(self.channel_cache, False)
443+
444+
# allows preempting this channel, if another channel becomes active
445+
self.last_write_ms = utime.ticks_ms()
446+
439447
async def _write_loop() -> None:
440448
"""Send the payload and wait for an ACK with retransmissions."""
449+
from trezor.loop import sleep
441450

442-
ack_latency_ms = self.channel_cache.get_int(CHANNEL_ACK_LATENCY_MS) or 0
443451
if __debug__:
444452
self._log(f"Sending {len(payload)} bytes, latency: {ack_latency_ms} ms")
445453

446-
# ACK is needed before sending more data
447-
ABP.set_sending_allowed(self.channel_cache, False)
448-
449-
# allows preempting this channel, if another channel becomes active
450-
self.last_write_ms = utime.ticks_ms()
451-
452454
for i in range(_MAX_RETRANSMISSION_COUNT):
453455
await self._write_payload_once(header, payload)
454-
455456
# Channel's estimated latency + a variable delay (from 200ms till ~3.52s)
456457
timeout_ms = ack_latency_ms + round(10300 - 1010000 / (100 + i))
457-
try:
458-
# wait and return after receiving an ACK, or raise in case of an unexpected message.
459-
await self.recv_payload(
460-
expected_ctrl_byte=None, timeout_ms=timeout_ms
461-
)
462-
except Timeout:
463-
if __debug__:
464-
log.warning(__name__, "Retransmit after %d ms", timeout_ms)
465-
continue
466-
467-
ack_latency_ms = utime.ticks_diff(utime.ticks_ms(), self.last_write_ms)
468-
# Limit estimated latency to avoid integer overflows and too long delays
469-
ack_latency_ms = max(0, min(800, ack_latency_ms))
470-
self.channel_cache.set_int(CHANNEL_ACK_LATENCY_MS, ack_latency_ms)
471-
472-
# `ABP.set_sending_allowed()` will be called after a valid ACK
473-
if ABP.is_sending_allowed(self.channel_cache):
474-
return
458+
await sleep(timeout_ms)
459+
if __debug__:
460+
log.warning(__name__, "Retransmit after %d ms", timeout_ms)
475461

476462
# restart event loop due to unresponsive channel
477463
raise Timeout("THP retransmission timeout")
478464

465+
async def _wait_for_ack() -> None:
466+
while not ABP.is_sending_allowed(self.channel_cache):
467+
# `ABP.set_sending_allowed()` will be called after a valid ACK
468+
await self.recv_payload(expected_ctrl_byte=None)
469+
470+
# wait and return after receiving an ACK, or raise in case of an unexpected message / retransmission timeout.
479471
try:
480-
return await _write_loop()
472+
await race(_wait_for_ack(), _write_loop())
481473
finally:
474+
ack_latency_ms = utime.ticks_diff(utime.ticks_ms(), self.last_write_ms)
475+
# Limit estimated latency to avoid integer overflows and too long delays
476+
ack_latency_ms = max(0, min(800, ack_latency_ms))
477+
self.channel_cache.set_int(CHANNEL_ACK_LATENCY_MS, ack_latency_ms)
478+
482479
# Make sure to use the next `seq_bit` for the next payload
483480
ABP.set_send_seq_bit_to_opposite(self.channel_cache)
484481

0 commit comments

Comments
 (0)