Commit Graph

157 Commits

Author SHA1 Message Date
9680d29e8d dcsctp: Support unlimited max_retransmissions
The restart limit for timers can already be limitless, but the
RetransmissionErrorCounter didn't support this. With this change, the
max_retransmissions and max_init_retransmits can be absl::nullopt to
indicate that there should be infinite retries.

Bug: webrtc:13129
Change-Id: Ia6e91cccbc2e1bb77b3fdd7f37436290adc2f483
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/230701
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#34882}
2021-08-31 10:57:48 +00:00
0ca62e3752 dcsctp: Avoid bundling FORWARD-TSN and DATA chunks
dcSCTP seems to be able to provoke usrsctp to send ABORT in some
situations, as described in
https://github.com/sctplab/usrsctp/issues/597. Using a packetdrill
script, it seems as a contributing factor to this behavior is when a
FORWARD-TSN chunk is bundled with a DATA chunk. This is a valid and
recommended pattern in RFC3758:

  "F2) The data sender SHOULD always attempt to bundle an outgoing
       FORWARD TSN with outbound DATA chunks for efficiency."

However, that seems to be a rare event in usrsctp, which generally sends
each FORWARD-TSN in a separate packet.

By doing the same, the assumption is that this scenario will generally
be avoided.

With many browsers and other clients using usrsctp, and which will not
be upgraded for a long time, there is an advantage of avoiding the issue
even if it is according to specification.

Before this change, a FORWARD-TSN was bundled with outgoing DATA and due
to this, it wasn't rate limited as the overhead was very little. With
this change, a rate limiting behavior has been added to avoid sending
too many FORWARD-TSN in small packets. It will be sent every RTT, or
200 ms, whichever is smallest. This is also described in the RFC.

Bug: webrtc:12961
Change-Id: I3d8036a34f999f405958982534bfa0e99e330da3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/229101
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34801}
2021-08-19 11:28:40 +00:00
3ec9e03f73 dcsctp: Removing all references to unordered_map
Replacing with std::map and webrtc::flat_map where applicable.

Bug: webrtc:12689
Change-Id: Id0fdb88bd3d52957b1616911eb487fc581d3b7d8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/229182
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34797}
2021-08-18 19:55:07 +00:00
923d2c237e dcsctp: fixed grammar in one comment, added comment regarding the threading contract
Bug: None
Change-Id: Ia1442a155afb38b0df4ed2c288a9c6b238488b23
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/229080
Commit-Queue: Sergey Sukhanov <sergeysu@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34788}
2021-08-17 15:59:05 +00:00
14ef6338b0 dcsctp: Don't send small packets when cwnd full
The congestion window is unlikely to be even divisible by the size
of a packet, so when the congestion window is almost full, there is
often just a few bytes remaining in it. Before this change, a small
packet was created to fill the remaining bytes in the congestion window,
to make it really full.

Small packets don't add much. The cost of sending a small packet is
often the same as sending a large one, and you usually get lower
throughput sending many small packets compared to few larger ones.'

This mode will only be enabled when the congestion window is large, so
if the congestion window is small - e.g. due to poor network conditions,
it will allow packets to become fragmented into small parts, in order to
fully utilize the congestion window.

Bug: webrtc:12943
Change-Id: I8522459174bc72df569edd57f5cc4a494a4b93a8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228526
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34778}
2021-08-17 09:03:36 +00:00
be9281b92b dcsctp: Increase cwnd by serialized chunk size
For symmetry, as the outstanding_bytes is increased/decreased by
the serialized chunk size (not just the payload) - which is compared
to the congestion window, the congestion window should be increased
by the serialized size of chunks acked - not just their payload.

Bug: webrtc:12943
Change-Id: I0a06033e8ca0d58433138df6442ca80494918cf2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228525
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34775}
2021-08-17 07:04:26 +00:00
d912446f52 dcsctp: Refactor chunk acking
The same code was done for both acking chunks due to moving the
cum-ack-tsn and when acking gap-ack-blocks. Unify them completely
to have a single code path.

Bug: webrtc:12943
Change-Id: I3b864e41cc2ec674460517660c23b72a70edf720
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228521
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34773}
2021-08-16 20:20:55 +00:00
abf6188cba dcsctp: Add PacketSender
This is mainly a refactoring commit, to break out packet sending to a
dedicated component.

Bug: webrtc:12943
Change-Id: I78f18933776518caf49737d3952bda97f19ef335
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228565
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34772}
2021-08-16 20:19:53 +00:00
600bb8c79f dcsctp: Migrating to using absl::bind_front
It is now allowed in WebRTC, so let's use it.

Bug: webrtc:12943
Change-Id: I74a0f2fd9c1b9e7b5613ae1c592cf26842b8dddd
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228564
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34768}
2021-08-16 11:51:27 +00:00
8df32eb0e1 dcsctp: Add API to indicate packet send status
Before this change, there was no way for a client to indicate to the
dcSCTP library if a packet that was supposed to be sent, was actually
sent. It was assumed that it always was.

To handle temporary failures better, such as retrying to send packets
that failed to be sent when the send buffer was full, this information
is propagated to the library.

Note that this change only covers the API and adaptations to clients.
The actual implementation to make use of this information is done as a
follow-up change.

Bug: webrtc:12943
Change-Id: I8f9c62e17f1de1566fa6b0f13a57a3db9f4e7684
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228563
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34767}
2021-08-16 11:29:47 +00:00
e0fb45c6d4 dcsctp: Add burst limiter for sent packets
Some deployments, e.g. Chromium, has a limited send buffer. It's
reasonable that it's quite small, as it avoids queuing too much, which
typically results in increased latency for real-time communication. To
avoid SCTP to fill up the entire buffer at once - especially when doing
fast retransmissions - limit the amount of packets that are sent in one
go.

In a typical scenario, SCTP will not send more than three packets for
each incoming packet, which is is the case when a SACK is received which
has acknowledged two large packets, and which also adds the MTU to the
congestion window (due to in slow-start mode), which then may result in
sending three packets. So setting this value to four makes any
retransmission not use that much more of the send buffer.

This is analogous to usrsctp_sysctl_set_sctp_fr_max_burst_default in
usrsctp, which also has the default value of four (4).

Bug: webrtc:12943
Change-Id: Iff76a1668beadc8776fab10312ef9ee26f24e442
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228480
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34744}
2021-08-12 17:22:55 +00:00
d7b7ea6106 dcsctp: remove unused WritePacketHeader method
BUG=None

Change-Id: Ieeb19ef976fe88a66a4a7b985f0600bb01044753
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/226945
Reviewed-by: Victor Boivie <boivie@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@nvidia.com>
Cr-Commit-Position: refs/heads/master@{#34712}
2021-08-11 08:05:39 +00:00
d4716eaf60 dcsctp: Add metrics support
To support implementing RTCSctpTransportStats, a few metrics are needed.

Some more were added that are useful for metric collection in SFUs.

Bug: webrtc:13052
Change-Id: Idafd49e1084922d01d3e6c5860715f63aea08b7d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228243
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34708}
2021-08-10 20:01:46 +00:00
82ea522b27 dcsctp: Track the number of inflight DATA items
This corresponds to one part of sstat_unackdata in RFC6458. The
remaining part is the data in the send queue, which isn't packetized
yet, so it must be estimated. But the DATA items in the retransmission
queue is already determined, so it can be easily tracked and retrieved.

Bug: webrtc:13052
Change-Id: I16c3b5b61eb6b3022d7104e6457d943d5df3d6b9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228240
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34706}
2021-08-10 18:00:26 +00:00
68e98fb248 Use backticks not vertical bars to denote variables in comments for /net
Bug: webrtc:12338
Change-Id: I5b23daa5c6122ad1e6902559e64b60b4285595c7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/226950
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34565}
2021-07-27 16:16:42 +00:00
b0ed12099f Update links to point at main branch
As part of go/coil update code search links to not point to the
"master" branch.

Bug: chromium:1226942
Change-Id: I0ae9e84ecc660f789a69fe0b226f93bbc39a8a66
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/226081
Commit-Queue: Tony Herre <toprice@chromium.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34531}
2021-07-22 16:41:26 +00:00
bf15e567e8 dcsctp: Abandon chunks consistently
The previous logic to abandon chunks when partial reliability was used
was a bit too eager and trigger happy.

 * Chunks with limited retransmissions should only be abandoned when a
   chunk is really considered lost. It should follow the same rules as
   for retransmitting chunks - that it must be nacked three times or
   due to a T3-RTX expiration. Before this change, a single SACK not
   referencing it would be enough to abandon it. This resulted in a lot
   of unnecessary sent FORWARD-TSN and undelivered messages - especially
   if running with zero retransmissions.

   The logic to expire chunks by limited retransmissions will now only
   be applied when a chunk is actually nacked.

 * The second partial reliability trigger - expiration time - wasn't
   evaluated when producing a middle chunk of a larger message.

A number of test cases were added and updated as chunks will now be
abandoned immediately instead of first scheduled for retransmission and
later abandoned.

Bug: webrtc:12961
Change-Id: I0ae17b2672568bdbdc32073a99d4c24b09ff5fe9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/225548
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34458}
2021-07-12 22:47:51 +00:00
813a087e84 dcsctp: Add packet capture support in unit tests
This is needed to be able to debug test cases when they fail.

Bug: webrtc:12961
Change-Id: I39bfe532709d02acb328ff5fdd005d33be4dc31c
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/225544
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34452}
2021-07-10 18:37:46 +00:00
5e726da14b dcsctp: Extract logging packet observer as utility
It is useful for more than just the transport.

Bug: webrtc:12961
Change-Id: Iad064c8fb707ca589a1c232e17436338fb06623d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/225543
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34451}
2021-07-10 18:23:06 +00:00
25ab3228f3 Replace assert() with RTC_DCHECK().
CL partially auto-generated with:

git grep -l "\bassert(" | grep "\.[c|h]" | \
  xargs sed -i 's/\bassert(/RTC_DCHECK(/g'

And with:

git grep -l "RTC_DCHECK(false)" |  \
  xargs sed -i 's/RTC_DCHECK(false)/RTC_NOTREACHED()/g'

With some manual changes to include "rtc_base/checks.h" where
needed.

A follow-up CL will remove assert() from Obj-C code as well
and remove the #include of <assert.h>.

The choice to replace with RTC_DCHECK is because assert()
is because RTC_DCHECK has similar behavior as assert()
based on NDEBUG.

This CL also contains manual changes to switch from
basic RTC_DCHECK to other (preferred) versions like
RTC_DCHECK_GT (and similar).

Bug: webrtc:6779
Change-Id: I00bed8886e03d685a2f42324e34aef2c9b7a63b0
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/224846
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34442}
2021-07-09 07:49:43 +00:00
8bd26e12ed dcsctp: Only reset paused streams when peer acks
When a single stream is reset, and an outgoing SSN reset request is sent
and later acked by the peer sending a reconfiguration response with
status=Performed, the sender should unpause the paused stream and reset
the SSNs of that (ordered) stream. But only the single stream that was
paused, and not all streams. In this scenario, dcSCTP would - when the
peer acked the SSN reset request - reset the SSN of all streams.

This was found by orphis@webrtc.org using a data channel test
application. The peer, if it's a usrsctp client, will ABORT with
PROTOCOL_VIOLATION as it has already seen that SSN on that stream but
with a different TSN.

This bug was introduced when implementing the Round Robin scheduler in
https://webrtc-review.googlesource.com/c/src/+/219682. The FCFS
scheduler prior to this change was implemented correctly.

Bug: webrtc:12952
Change-Id: I3ea144a1df303145f69a5b03aada7f448c8c8163
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/225266
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34436}
2021-07-08 10:49:11 +00:00
c362eb2d1c dcsctp: Add mocks
This is for convenience to the users of dcSCTP, which may want to have
unit tests where the socket is mocked. And since it's best practice not
to mock other teams' or project's classes, a mock will be provided by
the upstream project - this one.

Bug: webrtc:12614
Change-Id: I65d5d21097e7feda9162567560d3838759c962fc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/224161
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34385}
2021-06-29 10:19:11 +00:00
6a11c844fd dcsctp: Add DcSctpSocketFactory
The factory allows us to isolate the implementation from users who only
need to depend directly on the public folder now.

Bug: webrtc:12614
Change-Id: Ied09cf772ed427eaf17a7b5705f587da57405640
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220939
Commit-Queue: Florent Castelli <orphis@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34330}
2021-06-18 09:59:40 +00:00
c20f1563b6 dcsctp: Don't sent more packets before COOKIE ACK
While in the COOKIE ECHO state, there is a TCB and there might be data
in the send buffer, and RFC4960 allows the COOKIE ECHO chunk to bundle
additional DATA chunks in the same packet, but there mustn't be more
than one such packet sent, and that packet must have a COOKIE ECHO chunk
as the first chunk in it.

When the COOKIE ACK chunk has been received, the socket is allowed to
send multiple packets.

Previously, this was state managed by the socket and not the TCB, as
the socket is responsible for moving between the different states. And
when the COOKIE ECHO chunk was sent, the TCB was instructed to only send
a single packet by the socket.

However, if there were retransmissions or anything else that could
result in calling TransmissionControlBlock::SendBufferedChunks, it would
do as instructed and send those, even if the socket was in a state where
that wasn't allowed.

When the peer was dcSCTP, this didn't cause any issues as dcSCTP tries
to be tolerant in what it receives (but strict in what it sends, except
for when there are bugs). When the peer was usrsctp, it would send an
ABORT for each received packet that didn't have a COOKIE ECHO as the
first chunk, and then restart the handshake (sending an INIT). So this
resulted in a longer handshake, but the connection would eventually be
correctly established and any DATA chunks that resulted in the ABORTs
would've been retransmitted.

By making the TCB aware of that particular state, and to make it
responsible for creating the SCTP packet with the COOKIE ECHO chunk
first, and also to only send a single packet when it is in that state,
there will not be any way to bypass this limitation.

Also, while not explicitly mentioned in the RFC, the retransmission
timer will not affect resending any outstanding DATA chunks that were
bundled together with the COOKIE ECHO chunk, as then there would be two
timers that both would drive resending COOKIE ECHO and DATA chunks.

Bug: webrtc:12880
Change-Id: I76f215a03cceab5bafe9f16eb4775f3dc68a6f05
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/222645
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34329}
2021-06-18 08:50:59 +00:00
d579e6bc7b dcsctp: Do explicit bounds checking in bounded IO
The previous approach was that the caller was responsible for ensuring
that any buffer passed in to the Bounded IO wrappers, and that any
offset from where sub-readers were created were valid. The called would
always do a validation of the data and return proper error messages
if they were not.

This didn't pan out. https://crbug.com/1216758 found an overflow that
fooled the validation logic and the fuzzer could read out-of-bounds,
although it would always crash in that particular case.

There was already bounds checking, but under DCHECKs. This CL changes
that so that any bounds checking is done with CHECKS, as would've been
done in Rust. It's better to crash than to read arbitrary memory.

Bug: chromium:1216758
Change-Id: I89b52f0758495b5fe46f926c142870a263b96314
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/221743
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34303}
2021-06-16 13:02:32 +00:00
b56a63e470 dcsctp: Prevent overflow of missing parameters
This was found when fuzzing. If the specified number of parameter count
was larger than std::numeric_limits<size_t>::max()/2, the comparison
would overflow and read out-of-bounds. This would only apply to 32-bit
platforms and it would lead to a crash as it would access all of the
virtual memory range, and more.

Fixed: chromium:1216758
Change-Id: I2193d3ed078120b6c3e4645c0b16b9f230055e8d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/221742
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34256}
2021-06-09 14:12:53 +00:00
1c7ff0d001 dcsctp: Stay in stream if not producing fragment
If there is only little space left in a packet, and the remaining data
for a partially sent message is much larger, it will not generate a
small fragment for this message. This is to avoid fragmenting a message
into too many packets, as that increases the risk of losing messages
when partial reliability is enabled.

And when a stream doesn't want to generate a too small fragment, the
scheduler should _not_ switch streams. It should only switch streams
when a message has been fully sent. Previously, it would switch stream
when a stream doesn't want to produce a message, but as noted above,
that could happen for other reasons.

This required some refactoring, which also increased its robustness by
now only doing explicit stream switching on fully produced messages.

Bug: webrtc:12832
Change-Id: Icb213774fd0d26fba5640b00aac0407d393e4bfc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220937
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34197}
2021-06-02 09:45:59 +00:00
803fdc4106 dcsctp: Stay within stream while producing from it
The way that the "next stream" was picked when round-robin cycling was
flawed. When a message was produced in its entirety, the "next stream"
would be put at a stream identifier value that was just larger than what
was previously used. And then, for each fragment that was to be created,
it would try to resolve the nearest stream (above or equal to that
number) that had messages to send - always starting from that stream id
that didn't necessarily point to the stream for which fragments were
actually produced.

For example, if the previous stream ID for which a message was fully
produced on was 5, then the next_stream_id would be set to 6, and then
when producing next fragment, it might have produced something from
stream_id=1, because that was the only stream with messages in it. It
wouldn't update next_stream_id at this time; it would still be 6.

After a single fragment had been produced from that stream, a message
was queued on stream_id=6. The next time a fragment was to be produced,
it would not continue one stream_id=1, but instead pick the new stream,
which would suddenly produce a new fragment (with B flag set) while the
previous message (from stream_id=1) wasn't finished yet.

The fix is simple; Just ensure that we continue iterating from where we
ever produce a fragment from.

Bug: webrtc:12832
Change-Id: Icc761c572ed200db607a7609dab1ac6a8aeb2f04
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220938
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34190}
2021-06-01 17:24:06 +00:00
7b4fd5ca59 dcsctp: Determine chunks to be retransmitted fast
Before this CL, before sending out any chunk, all inflight data chunks
were inspected to find out if they were supposed to be retransmitted.

When the congestion window is large, this is a lot of data chunks to
inspect, which takes time.

By having a separate collection for chunks to be retransmitted, this
becomes a much faster operation. In most cases, constant in time.

Bug: webrtc:12799
Change-Id: I0d43ba7a88656eead26d5e0b9c4735622a8d080e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219626
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34178}
2021-05-31 21:07:17 +00:00
c48a49cd0d dcsctp: Find out quickly if to send FORWARD-TSN
There is no need to iterate through all outstanding data chunks to know
if a FORWARD-TSN can be sent. As the FORWARD-TSN will just move the
cumulative TSN ack, if a chunk is found that is not to be expired,
there is no need to continue any further. This makes it much faster
to know if to send a FORWARD-TSN when the congestion window is large.

Bug: webrtc:12799
Change-Id: I58bce408ae9814c8d3d7bbb480b0037a2cf88dd7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219625
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34176}
2021-05-31 20:22:57 +00:00
27d2be3583 dcsctp: Optimize SACK generation
Before this CL, a SACK was generated from scratch based on information
about each received fragment, to generate correct gap-ack-blocks.

When there was a lot of data in the data tracker (due to packet loss),
this took considerate time, as generating a SACK was O(N), where N is
the amount of fragments in the data tracker.

By instead having precomputed gap-ack-blocks that are continuously
updated, generating a SACK is much faster and the memory usage goes down
a bit as well.

Bug: webrtc:12799
Change-Id: I924752c1d6d31f06d27246e10b595e9ccb19320f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220763
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34171}
2021-05-31 16:30:21 +00:00
261eec5456 dcsctp: Allow more outstanding fragments
There limit that decides if an incoming TSN should be accepted or not
was decided based on very small transfers with no packet loss. But in
simulations where a socket tries to send a lot of data and when there
is moderate packet loss, the number of tracker data chunks on the
receive side will be considerably higher than what the limit was.

Set the limit to allow high data rate also on moderate packet loss.

Bug: webrtc:12799
Change-Id: I6ca237e5609d8b511e9b10c919da33dca7420c01
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220761
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34169}
2021-05-31 14:12:04 +00:00
8267724a85 dcsctp: Announce send buffer watermark as a_rwnd
The receive buffer mustn't be full; If it's full, and a message can't be
assembled, the socket can't accept more data. To avoid this, there is
a high watermark limit that, when reached, will make the socket only
accept chunks that advance the cumulative ack TSN.

Before this CL, the announced receiver window size in every sent SACK
was based on what the receive buffer could maximally be, which means
that in really high data rate applications, the amount of outstanding
data could actually fill the receive buffer (due to packet loss, that
prevents messages from being reassembled). As the socket started
behaving more conservatively when the high watermark limit was reached,
this resulted in unnecessary T3-RTXes. But by announcing the high
watermark limit instead, the sender will stay within it, and will have
a peer socket that behaves as expected.

Bug: webrtc:12799
Change-Id: Ife2f409914a230640217553c54f60d05843efc70
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220762
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34168}
2021-05-31 14:10:34 +00:00
5d4c3c5128 dcsctp: Add more unit tests for DataTracker
There were some missing unit tests that are now written. When doing
this, it was found that SACKs weren't sent for duplicate received
chunks, which they should be according to the spec.

Bug: webrtc:12614
Change-Id: I8296473c0c8cbaf0329785de95e9b9945f254339
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220607
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34165}
2021-05-31 13:09:24 +00:00
5429d71022 dcsctp: Allow heartbeats to be disabled
This is useful in tests and in scenarios where the connection is
monitored externally and the heartbeat monitoring would be of no use.

Bug: webrtc:12614
Change-Id: Ida4f4e2e40fc4d2aa0c27ae9431f434da4cc8313
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220766
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34164}
2021-05-31 12:19:38 +00:00
236ac50628 dcsctp: Add public API for BufferedAmountLow
This adds native support for the RTCDataChannel properties:
https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/bufferedAmount
https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/bufferedAmountLowThreshold

And the RTCDataChannel event:
https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/onbufferedamountlow

The old callback, NotifyOutgoingMessageBufferEmpty, is deprecated as it
didn't work very well. It will not be triggered and will be removed
as soon as all users of it are gone. There is a new callback,
OnTotalBufferedAmountLow, that serves the same purpose but also allows
setting an arbitrary limit when it should be triggered (See
DcSctpOptions::total_buffered_amount_low_threshold).

Bug: webrtc:12794
Change-Id: Ic1c92f174eff8a1acda0b5fd3dcc45bd1cfa2704
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219691
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34144}
2021-05-27 15:27:27 +00:00
bd9031bf22 dcsctp: Add OnTotalBufferedAmountLow in Send Queue
This is similar to Change-Id: I12a16f44f775da3711f3aa52a68a0bf24f70d2f8
but with the entire send buffer as scope, not a single stream.

This can be used by clients to take alternate action (such as delaying
transmission or using other buffering) if the send buffer ever becomes
full, as they can now be notified when the send buffer is no longer
full.

Bug: webrtc:12794
Change-Id: Icf3be3b118888ffb5ced955fd7ba4826a37140f9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220360
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34143}
2021-05-27 14:38:18 +00:00
791adafa09 dcsctp: Add OnBufferedAmountLow in Send Queue
This adds the necessary properties and callback to the Send Queue to
support the bufferedAmount & bufferedAmountLowThreshold properties and
the bufferedamountlow event in RTCDataChannel.

The public API changes and socket support comes in a follow-up CL.

Bug: webrtc:12794
Change-Id: I12a16f44f775da3711f3aa52a68a0bf24f70d2f8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219690
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34142}
2021-05-27 13:16:28 +00:00
7d2e669a38 dcsctp: Allocate TSN for end of abandoned message
If a not fully sent message is abandoned, there must be a TSN
representing the end of that message (even if that fragment is never
sent), as the receiver can otherwise reject the next sent message as it
hasn't seen any end of the previous one.

A long explanation can be found at
https://github.com/sctplab/usrsctp/issues/592#issuecomment-849047689

Bug: webrtc:12812
Change-Id: I09c571bd6dd2774b0c147d4e5ddac67d2aa64fea
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220361
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34140}
2021-05-27 08:53:42 +00:00
9700d88b1a dcsctp: Avoid recalculation of outstanding bytes
Recalculating outstanding bytes is expensive when the congestion window
is large, as it iterates over all inflight data chunks. By doing it
incrementally, it will be a constant operation in most cases, and
in the remaining cases, a function of the number of chunks acked in a
single SACK, which is typically just a few chunks.

Implementing this fix required some refactoring to calculate it
correctly (and to be honest, it was likely done incorrectly previously).

Previously, the state of an item in the retransmission queue was
simplified as "in flight", "acked", "nacked", "abandoned", but these
were not completely orthogonal. A chunk could be abandoned while it was
in-flight or it could be abandoned because it was lost. The difference
between these if that chunk should be accounted for in
outstanding_bytes() or not.

Unit tests have been added to verify this.

Bug: webrtc:12799
Change-Id: I72341538bb0c4f8f89555b08f0c8a28815f0f828
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219623
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34139}
2021-05-27 07:40:11 +00:00
c09c58134a dcsctp: Limit the size of generated SACK chunks
Today, there is no actual limit on how large a SACK chunk can be. And
having limits is good to be able to stay within the MTU.

This commit adds a limit to the number of reported duplicate TSNs as
well as the number of reported gap-ack-blocks in a SACK chunk. These
limits are never expected to be reached in a real-life situation.

Bug: webrtc:12614
Change-Id: Ib2c143714a214cd3d961e8a52dac26a04b909b80
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219464
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34108}
2021-05-25 07:56:56 +00:00
93faab1b51 dcsctp: Implement Round Robin scheduler
Bug: webrtc:12793
Change-Id: I19adb292443def42ee54df67c4869b980db7b7c0
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219682
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34093}
2021-05-23 17:49:52 +00:00
2440d34075 dcsctp: Rename FCFSSendQueue to RRSendQueue
The current send queue implements SCTP_SS_FCFS as defined in
https://datatracker.ietf.org/doc/html/rfc8260#section-3.1, but that has
always been known to be a temporary solution. The end goal is to
implement a Weighted Fair Queueing Scheduler (SCTP_SS_WFQ), but that's
likely to take some time.

Meanwhile, a round robin scheduler (SCTP_SS_RR) will be used to avoid
some issues with the current scheduler, such as a single data channel
completely blocking all others if it sends a lot of messages.

In this first commit, the code has simply been renamed and is still
implementing first-come-first-served. That will be fixed in follow-up
CLS.

Bug: webrtc:12793
Change-Id: Idc03b1594551bfe1ddbe1710872814b9fdf60cc9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219684
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34090}
2021-05-22 20:56:13 +00:00
32ee3b88ea dcsctp: Ensure RTO is always greater than RTT
The retransmission timeout (RTO) value is updated on every measured
RTT and is a function of the RTT value and its stability. In reality,
the RTT is never constant - it fluctuates, which makes the RTO become
much larger than the RTT. But for extremely stable RTTs, which we get
in simulations, the RTO value can become the same as the RTT, and that
makes expiration timers be scheduled to the RTT value, and will race
with packets that are expected to stop the expiration timer. And that
race should be avoided in simulations.

So ensuring that the RTO value is always greater, if only be a single
millisecond, will work fine in these simulations.

Bug: webrtc:12614
Change-Id: I30cf9c97e50449849ab35de52696c618d8498128
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219680
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34084}
2021-05-21 20:08:29 +00:00
3a45d32d4e dcsctp: Report duplicate TSNs
Reporting the duplicate TSNs is a SHOULD in the RFC, and using the
duplicate TNSs is a MAY, and in reality I haven't seen an implementation
use it yet. However, it's good for debugging and for stats generation.

Bug: webrtc:12614
Change-Id: I1cc3f86961a8d289708cbf50d98dedfd25077955
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219462
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34053}
2021-05-19 12:57:03 +00:00
92bd9020af dcsctp: Restrict fuzzing input length
Restricting the fizzing input length according to the instructions at
https://chromium.googlesource.com/chromium/src/testing/libfuzzer/+/HEAD/getting_started.md#common-tricks

Without this limit, it finds inputs that are unreasonably large (160kB+)
that just make the ASAN built fuzzer hit the default timeout of 60s.

Bug: webrtc:12614
Change-Id: I1417f22698fba8d9bd2c56f8c3d51850b8f00f54
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219161
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34034}
2021-05-18 09:22:37 +00:00
cfa932f6fc dcsctp: Bump rto_min to 220 ms
The minimum RTO time shouldn't be lower than the delayed ack timeout
of the peer to avoid sending retransmissions before the peer has
actually intended to reply.

In usrsctp, the default delayed ack timeout is 200ms and configurable
using the `sctp_delayed_sack_time_default` option. In dcsctp, it's
min(RTO/2, 200ms), to avoid this issue.

Bug: webrtc:12614
Change-Id: Ie84c331334af660d66b1a7d90d20f5cf7e2a5103
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219100
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34026}
2021-05-17 17:41:21 +00:00
a30362cc75 dcsctp: Add socket fuzzer helper
The socket fuzzer is build as a structure-aware fuzzer where the full
public API is exercised as well as receival of SCTP packets with random
sequences of valid chunks.

It begins by putting the socket in a defined starting state and then,
based on the fuzzing data, performs a sequence of operations on the
socket such as receiving packets, sending data, resetting streams or
expiring timers.

This is the first iteration, and when running it a while and analyzing
code coverage, it will be modified to perform better. It could probably
be a little more random.

Bug: webrtc:12614
Change-Id: I50d6ffaecef5722be5cf666fee2f0de7d15cc2e8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/218500
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33998}
2021-05-12 15:06:17 +00:00
50a0b1219e dcsctp: Avoid transition back to ShutdownPending
When a socket is shutting down, either explicitly by the ULP calling
Shutdown(), or when the socket receives a SHUTDOWN chunk, the socket
should send all outstanding data and when all is sent and acked,
_then_ it should continue the shutdown protocol.

As it currently doesn't calculate correctly when all data has been sent,
as NACKED chunks are not included in what it believes is remaining in
the retransmission queue, it will shut down prematurely and may go back
to a previous state (ShutdownPending) from ShutdownSent or
ShutdownAckSent.

This is a workaround that just avoids the illegal state transition as
that puts the socket in an inconsistent state. The bug is merely
theoretical as WebRTC doesn't currently gracefully shut down a SCTP
socket, but just terminates the DTLS transport.

As TODOs mention, this will be fixed correctly a bit later.

Bug: webrtc:12739
Change-Id: Ibde2acc3a6aca701ac178d6181028404d470a5d5
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/218340
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33982}
2021-05-11 16:04:42 +00:00
d3b186e3d6 dcsctp: Support message with low lifetime
While it's not strictly defined, the expectation is that sending a
message with a lifetime parameter set to zero (0) ms should allow it to
be sent if it can be sent without being buffered. If it can't be
directly sent, it should be discarded.

This is initial support for it. Small messages can now be delivered fine
if they are not to be buffered, but fragmented messages could be partly
sent (if this fills up the congestion window), which means that the
message will then fail to be sent whenever the congestion window frees
up again. It would be better to - at a higher level - realize early that
the message can't be sent in full, and discard it without sending
anything. But that's an optimization that can be done later.

A few off-by-one errors were found when strictly defining that the
message is alive during its entire lifetime. It will expire just _after_
its lifetime.

Sending messages with a lifetime of zero may not supported in all
libraries, so a workaround would be to set a very small timeout instead,
which is tested as well.

Bug: webrtc:12614
Change-Id: I9a00bedb639ad7b3b565b750ef2a49c9020745f1
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/217562
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33977}
2021-05-11 08:44:14 +00:00