Skip to content

Commit 477b75f

Browse files
authored
[SCTP] Socket (part 2) (#1533)
1 parent 83e1509 commit 477b75f

File tree

93 files changed

+2914
-414
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+2914
-414
lines changed

worker/fuzzer/src/RTC/SCTP/association/FuzzerStateCookie.cpp

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ void FuzzerRtcSctpStateCookie::Fuzz(const uint8_t* data, size_t len)
2222

2323
if (len < RTC::SCTP::StateCookie::StateCookieLength + 5)
2424
{
25-
Utils::Byte::Set4Bytes(clonedData, 0, RTC::SCTP::StateCookie::MagicValue1);
26-
Utils::Byte::Set2Bytes(clonedData, 34, RTC::SCTP::StateCookie::MagicValue2);
25+
Utils::Byte::Set4Bytes(clonedData, 0, RTC::SCTP::StateCookie::Magic1);
26+
Utils::Byte::Set2Bytes(
27+
clonedData,
28+
RTC::SCTP::StateCookie::NegotiatedCapabilitiesOffset,
29+
RTC::SCTP::StateCookie::Magic2);
2730
}
2831
}
2932

@@ -36,33 +39,33 @@ void FuzzerRtcSctpStateCookie::Fuzz(const uint8_t* data, size_t len)
3639
return;
3740
}
3841

39-
stateCookie->GetMyVerificationTag();
40-
stateCookie->GetPeerVerificationTag();
41-
stateCookie->GetMyInitialTsn();
42-
stateCookie->GetPeerInitialTsn();
43-
stateCookie->GetMyAdvertisedReceiverWindowCredit();
42+
stateCookie->GetLocalVerificationTag();
43+
stateCookie->GetRemoteVerificationTag();
44+
stateCookie->GetLocalInitialTsn();
45+
stateCookie->GetRemoteInitialTsn();
46+
stateCookie->GetRemoteAdvertisedReceiverWindowCredit();
4447
stateCookie->GetTieTag();
4548
stateCookie->GetNegotiatedCapabilities();
4649

4750
stateCookie->Serialize(StateCookieSerializeBuffer, len);
4851

49-
stateCookie->GetMyVerificationTag();
50-
stateCookie->GetPeerVerificationTag();
51-
stateCookie->GetMyInitialTsn();
52-
stateCookie->GetPeerInitialTsn();
53-
stateCookie->GetMyAdvertisedReceiverWindowCredit();
52+
stateCookie->GetLocalVerificationTag();
53+
stateCookie->GetRemoteVerificationTag();
54+
stateCookie->GetLocalInitialTsn();
55+
stateCookie->GetRemoteInitialTsn();
56+
stateCookie->GetRemoteAdvertisedReceiverWindowCredit();
5457
stateCookie->GetTieTag();
5558
stateCookie->GetNegotiatedCapabilities();
5659

5760
auto* clonedStateCookie = stateCookie->Clone(StateCookieCloneBuffer, len);
5861

5962
delete stateCookie;
6063

61-
clonedStateCookie->GetMyVerificationTag();
62-
clonedStateCookie->GetPeerVerificationTag();
63-
clonedStateCookie->GetMyInitialTsn();
64-
clonedStateCookie->GetPeerInitialTsn();
65-
clonedStateCookie->GetMyAdvertisedReceiverWindowCredit();
64+
clonedStateCookie->GetLocalVerificationTag();
65+
clonedStateCookie->GetRemoteVerificationTag();
66+
clonedStateCookie->GetLocalInitialTsn();
67+
clonedStateCookie->GetRemoteInitialTsn();
68+
clonedStateCookie->GetRemoteAdvertisedReceiverWindowCredit();
6669
clonedStateCookie->GetTieTag();
6770
clonedStateCookie->GetNegotiatedCapabilities();
6871

worker/fuzzer/src/RTC/SCTP/packet/FuzzerPacket.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ void FuzzerRtcSctpPacket::Fuzz(const uint8_t* data, size_t len)
3636
packet->GetChecksum();
3737
packet->ValidateCRC32cChecksum();
3838
packet->SetChecksum(999999);
39-
packet->SetCRC32cChecksum();
39+
packet->WriteCRC32cChecksum();
4040
packet->ValidateCRC32cChecksum();
4141
packet->HasChunks();
4242
packet->GetChunksCount();
@@ -58,7 +58,7 @@ void FuzzerRtcSctpPacket::Fuzz(const uint8_t* data, size_t len)
5858
clonedPacket->GetChecksum();
5959
clonedPacket->ValidateCRC32cChecksum();
6060
clonedPacket->SetChecksum(999999);
61-
clonedPacket->SetCRC32cChecksum();
61+
clonedPacket->WriteCRC32cChecksum();
6262
clonedPacket->ValidateCRC32cChecksum();
6363
clonedPacket->HasChunks();
6464
clonedPacket->GetChunksCount();

worker/include/RTC/SCTP/TODO_SCTP.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,3 @@ Here some notes about our future SCTP implementation.
1212
However, in step 4 `WebRtcTransport::OnDtlsTransportApplicationDataReceived()` should instead call `RTC::SCTP::Packet::parse()` and `Transport::ReceiveSctpPacket()` with a `SCTP::Packet` instance instead than `data` and `len`. In fact it should be named `Transport::ReceiveSctpPacket()` instead of the current `Transport::ReceiveSctpData()`.
1313

1414
Same in `PipeTransport` and `PlainTransport`.
15-
16-
## TODO
17-
18-
- Try to remove all `friend class`.
19-
20-
- In `HeartbeatChunk` the `HeartbeatInfoParameter` should be mandatory when parsing. Or should we add some `Validate()` method?

worker/include/RTC/SCTP/association/NegotiatedCapabilities.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
#define MS_RTC_SCTP_NEGOTIATED_CAPABILITIES_HPP
33

44
#include "common.hpp"
5+
#include "RTC/SCTP/association/SocketOptions.hpp"
6+
#include "RTC/SCTP/packet/chunks/InitAckChunk.hpp"
7+
#include "RTC/SCTP/packet/chunks/InitChunk.hpp"
8+
#include <variant> // std::variant, std::visit()
59

610
namespace RTC
711
{
@@ -14,6 +18,19 @@ namespace RTC
1418
*/
1519
struct NegotiatedCapabilities
1620
{
21+
using InitOrInitAckChunkVariant = std::variant<const InitChunk*, const InitAckChunk*>;
22+
23+
/**
24+
* Create a NegotiatedCapabilities struct. Intended to be used during
25+
* the SCTP association handshake flow.
26+
*
27+
* @remarks
28+
* Given `remoteChunk` must be an INIT or an INIT_ACK Chunk. Otherwise
29+
* it will fail in compilation time.
30+
*/
31+
static NegotiatedCapabilities Factory(
32+
SocketOptions socketOptions, InitOrInitAckChunkVariant remoteChunk);
33+
1734
/**
1835
* Negotiated maximum number of outbound streams (OS).
1936
*/

worker/include/RTC/SCTP/association/Socket.hpp

Lines changed: 162 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,25 @@
22
#define MS_RTC_SCTP_SOCKET_HPP
33

44
#include "common.hpp"
5-
#include "RTC/Consts.hpp"
5+
#include "RTC/SCTP/association/NegotiatedCapabilities.hpp"
6+
#include "RTC/SCTP/association/SocketMetrics.hpp"
7+
#include "RTC/SCTP/association/SocketOptions.hpp"
68
#include "RTC/SCTP/association/TransmissionControlBlock.hpp"
7-
#include "RTC/SCTP/packet/parameters/ZeroChecksumAcceptableParameter.hpp"
9+
#include "RTC/SCTP/packet/Chunk.hpp"
10+
#include "RTC/SCTP/packet/Packet.hpp"
11+
#include "RTC/SCTP/packet/chunks/AbortAssociationChunk.hpp"
12+
#include "RTC/SCTP/packet/chunks/DataChunk.hpp"
13+
#include "RTC/SCTP/packet/chunks/HeartbeatRequestChunk.hpp"
14+
#include "RTC/SCTP/packet/chunks/InitAckChunk.hpp"
15+
#include "RTC/SCTP/packet/chunks/InitChunk.hpp"
16+
#include "RTC/SCTP/packet/chunks/OperationErrorChunk.hpp"
17+
#include "RTC/SCTP/packet/chunks/SackChunk.hpp"
18+
#include "RTC/SCTP/packet/chunks/ShutdownAckChunk.hpp"
19+
#include "RTC/SCTP/packet/chunks/ShutdownCompleteChunk.hpp"
20+
#include "RTC/SCTP/packet/chunks/UnknownChunk.hpp"
21+
#include "handles/BackoffTimerHandle.hpp"
22+
#include <string>
23+
#include <string_view>
824

925
namespace RTC
1026
{
@@ -16,82 +32,168 @@ namespace RTC
1632
*
1733
* It manages all Packet and Chunk dispatching and the connection flow.
1834
*/
19-
class Socket
35+
class Socket : public BackoffTimerHandle::Listener
2036
{
2137
public:
22-
struct SocketOptions
38+
class Listener
2339
{
24-
/**
25-
* Signaled local port.
26-
*/
27-
uint16_t localPort{ 0 };
28-
/**
29-
* Signaled destination port.
30-
*/
31-
uint16_t destinationPort{ 0 };
32-
/**
33-
* Announced maximum number of outbound streams (OS).
34-
* NOTE: We use maximum value by default.
35-
*/
36-
uint16_t maxOutboundStreams{ 65535 };
37-
/**
38-
* Announced maximum number of inbound streams (MIS).
39-
* NOTE: We use maximum value by default.
40-
*/
41-
uint16_t maxInboundStreams{ 65535 };
42-
/**
43-
* Maximum received window buffer size. It must be larger than the
44-
* largest sized message we want to be able to receive.
45-
*
46-
* @remarks
47-
* Default value copied from dcSCTP library.
48-
*/
49-
uint32_t myAdvertisedReceiverWindowCredit{ 5 * 1024 * 1024 };
50-
/**
51-
* Use Partial Reliability Extension.
52-
* @see RFC 3758.
53-
*/
54-
bool partialReliability{ false };
55-
/**
56-
* Use Stream Schedulers and User Message Interleaving (I-DATA Chunks).
57-
* @see RFC 8260.
58-
*/
59-
bool messageInterleaving{ false };
60-
/**
61-
* Alternate error detection method for Zero Checksum.
62-
*
63-
* @remarks
64-
* This feature is only enabled if both peers signal their wish to use
65-
* the same (non-zero) Zero Checksum Alternate Error Detection Method.
66-
*
67-
* @see RFC 9653.
68-
*/
69-
ZeroChecksumAcceptableParameter::AlternateErrorDetectionMethod zeroCheksumAlternateErrorDetectionMethod{
70-
ZeroChecksumAcceptableParameter::AlternateErrorDetectionMethod::NONE
71-
};
72-
/**
73-
* Maximum size of a SCTP packet. It doesn't include any overhead of
74-
* DTLS, TURN, UDP or IP headers.
75-
*/
76-
size_t mtu{ RTC::Consts::MaxSafeMtuSizeForSctp };
40+
public:
41+
virtual ~Listener() = default;
42+
43+
public:
44+
virtual void OnSocketSendSctpPacket(const Socket* socket, Packet* packet) const = 0;
45+
};
46+
47+
public:
48+
/**
49+
* SCTP association state.
50+
*/
51+
enum class State
52+
{
53+
CLOSED,
54+
COOKIE_WAIT,
55+
// NOTE: TCB is valid in these states:
56+
COOKIE_ECHOED,
57+
ESTABLISHED,
58+
SHUTDOWN_PENDING,
59+
SHUTDOWN_SENT,
60+
SHUTDOWN_RECEIVED,
61+
SHUTDOWN_ACK_SENT,
7762
};
7863

64+
/**
65+
* Struct holding local verification tag and initial TSN between having
66+
* sent the INIT Chunk until the connection is established (there is no
67+
* TCB in between).
68+
*
69+
* @remarks
70+
* This is how dcSCTP does, despite RFC 9260 states that the TCB should
71+
* also be created when an INIT Chunk is sent.
72+
*/
73+
struct PreTransmissionControlBlock
74+
{
75+
uint32_t localVerificationTag{ 0 };
76+
uint32_t localInitialTsn{ 0 };
77+
};
78+
79+
public:
80+
static constexpr std::string_view State2String(State state);
81+
7982
public:
80-
explicit Socket(SocketOptions options);
83+
explicit Socket(SocketOptions options, Listener* listener);
8184

8285
~Socket();
8386

8487
void Dump(int indentation = 0) const;
8588

89+
/**
90+
* Initiate the SCTP association with the remote peer. It sends an INIT
91+
* Chunk.
92+
*
93+
* @remarks
94+
* The Socket must be in Closed state.
95+
*/
96+
void Associate();
97+
98+
/**
99+
* Receive a Packet received from the peer.
100+
*/
101+
void ReceivePacket(const Packet* receivedPacket);
102+
86103
private:
104+
void SetState(State state, const std::string& reason);
105+
106+
void AddCapabilitiesParametersToInitOrInitAckChunk(Chunk* chunk) const;
107+
108+
void CreateTransmissionControlBlock(
109+
uint32_t localVerificationTag,
110+
uint32_t remoteVerificationTag,
111+
uint32_t localInitialTsn,
112+
uint32_t remoteInitialTsn,
113+
uint32_t localAdvertisedReceiverWindowCredit,
114+
uint64_t tieTag,
115+
const NegotiatedCapabilities& negotiatedCapabilities);
116+
117+
Packet* CreatePacket() const;
118+
119+
Packet* CreatePacketWithVerificationTag(uint32_t verificationTag) const;
120+
121+
/**
122+
* Notify the parent about a Packet to be sent to the peer.
123+
*
124+
* This method also writes the Packet checksum field depending on the value
125+
* of `writeChecksum`. If it's explicitly set then it's honored. Otherwise
126+
* the checksum field is written based on whether Zero Checksum has been
127+
* negotiated or not.
128+
*
129+
* @remarks
130+
* This method does not delete the given `packet`. The caller must do it
131+
* after invoking this method.
132+
*/
133+
void SendPacket(Packet* packet, std::optional<bool> writeChecksum = std::nullopt);
134+
87135
void SendInitChunk();
88136

137+
void SendShutdownAckChunk();
138+
139+
bool ValidateReceivedPacket(const Packet* receivedPacket);
140+
141+
bool ProcessReceivedChunk(const Packet* receivedPacket, const Chunk* receivedChunk);
142+
143+
void ProcessReceivedDataChunk(const Packet* receivedPacket, const DataChunk* receivedDataChunk);
144+
145+
void ProcessReceivedInitChunk(const Packet* receivedPacket, const InitChunk* receivedInitChunk);
146+
147+
void ProcessReceivedInitAckChunk(
148+
const Packet* receivedPacket, const InitAckChunk* receivedInitAckChunk);
149+
150+
void ProcessReceivedSackChunk(const Packet* receivedPacket, const SackChunk* receivedSackChunk);
151+
152+
void ProcessReceivedHeartbeatRequestChunk(
153+
const Packet* receivedPacket, const HeartbeatRequestChunk* receivedHeartbeatRequestChunk);
154+
155+
bool ProcessReceivedUnknownChunk(
156+
const Packet* receivedPacket, const UnknownChunk* receivedUnknownChunk);
157+
158+
void OnT1InitTimer(uint64_t& baseTimeout, bool& stop);
159+
160+
void OnT1CookieTimer(uint64_t& baseTimeout, bool& stop);
161+
162+
void OnT2ShutdownTimer(uint64_t& baseTimeout, bool& stop);
163+
164+
template<typename... States>
165+
void AssertState(States... expectedStates) const;
166+
167+
template<typename... States>
168+
void AssertNotState(States... unexpectedStates) const;
169+
170+
void AssertHasTcb() const;
171+
172+
/* Pure virtual methods inherited from BackoffTimerHandle::Listener. */
173+
public:
174+
void OnTimer(BackoffTimerHandle* backoffTimer, uint64_t& baseTimeout, bool& stop) override;
175+
89176
private:
90177
// Socket options given in th econstructor.
91-
Socket::SocketOptions options;
178+
const SocketOptions options;
179+
// Listener.
180+
const Listener* listener{ nullptr };
181+
// SCTP association state.
182+
State state{ State::CLOSED };
183+
// Metrics.
184+
SocketMetrics metrics{};
185+
// To keep settings between sending of INIT Chunk and establishment of
186+
// the connection.
187+
PreTransmissionControlBlock preTcb;
92188
// Once the SCTP association is established a Transmission Control Block
93-
// is created (and also when we are the initiator of the association).
189+
// is created.
94190
std::unique_ptr<TransmissionControlBlock> tcb;
191+
// T1-init timer.
192+
const std::unique_ptr<BackoffTimerHandle> t1InitTimer;
193+
// T1-cookie timer.
194+
const std::unique_ptr<BackoffTimerHandle> t1CookieTimer;
195+
// T2-shutdown timer.
196+
const std::unique_ptr<BackoffTimerHandle> t2ShutdownTimer;
95197
};
96198
} // namespace SCTP
97199
} // namespace RTC

0 commit comments

Comments
 (0)