aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/tests/test_sctp_fix.py
blob: 0b2536ab4733fd39081c945cbd23d8ff374e78c6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
"""aiortc's SCTP sender must not leak bytes in flight (see sctp_fix.py).

Replayed against aiortc's own RTCSctpTransport: three chunks sent, the first
lost and the other two acknowledged in a gap block, T3 expires and they are
sent again, then a cumulative ack covers all three. Nothing is outstanding, so
nothing may be counted in flight; before the fix one chunk stayed counted, and
enough of those stop the node from sending anything on that connection.
"""

import asyncio

from aiortc.rtcsctptransport import RTCSctpTransport, SackChunk

import meshbay_node.transport.webrtc.core  # noqa: F401  (applies the fix)


class _Dtls:
    state = "connected"

    def _register_data_receiver(self, *a):
        pass


def _sack(cumulative_tsn: int, gaps: list) -> SackChunk:
    sack = SackChunk()
    sack.cumulative_tsn = cumulative_tsn % 2**32
    sack.gaps = gaps
    sack.duplicates = []
    sack.advertised_rwnd = 1 << 20
    return sack


async def _replay() -> RTCSctpTransport:
    s = RTCSctpTransport(_Dtls())
    s._association_state = s.State.ESTABLISHED

    async def sent(*_a, **_k):
        pass

    s._send_chunk = sent
    for name in ("_t3_start", "_t3_restart", "_t3_cancel"):
        setattr(s, name, lambda: None)
    s._cwnd = 100_000

    for _ in range(3):
        await s._send(1, 51, b"x" * 1000)
    tsns = [c.tsn for c in s._sent_queue]

    await s._receive_sack_chunk(_sack(tsns[0] - 1, [(1, 2)]))
    s._t3_expired()
    await s._transmit()
    await s._receive_sack_chunk(_sack(tsns[-1], []))
    return s


def test_nothing_outstanding_means_nothing_in_flight():
    s = asyncio.run(_replay())
    assert not s._sent_queue
    assert s._flight_size == 0