dcsctp: Add Context
In the Socket module, there are a few (two, to be exact right now, but the goal is to have even more) separate "handlers" that are responsible for a feature set. These handlers must have an API to interact with the rest of the socket - and this is the API. Mocks are also added. Bug: webrtc:12614 Change-Id: If19b43bf99a784bba3a42467d0ed3abdd8b4c62c Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/214128 Commit-Queue: Victor Boivie <boivie@webrtc.org> Reviewed-by: Tommi <tommi@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Cr-Commit-Position: refs/heads/master@{#33826}
This commit is contained in:

committed by
Commit Bot

parent
dbcf5d3918
commit
e1d60b0b58
40
net/dcsctp/socket/BUILD.gn
Normal file
40
net/dcsctp/socket/BUILD.gn
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Use of this source code is governed by a BSD-style license
|
||||||
|
# that can be found in the LICENSE file in the root of the source
|
||||||
|
# tree. An additional intellectual property rights grant can be found
|
||||||
|
# in the file PATENTS. All contributing project authors may
|
||||||
|
# be found in the AUTHORS file in the root of the source tree.
|
||||||
|
|
||||||
|
import("../../../webrtc.gni")
|
||||||
|
|
||||||
|
rtc_source_set("context") {
|
||||||
|
sources = [ "context.h" ]
|
||||||
|
deps = [
|
||||||
|
"../common:internal_types",
|
||||||
|
"../packet:sctp_packet",
|
||||||
|
"../public:socket",
|
||||||
|
"../public:types",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtc_include_tests) {
|
||||||
|
rtc_source_set("mock_callbacks") {
|
||||||
|
testonly = true
|
||||||
|
sources = [ "mock_dcsctp_socket_callbacks.h" ]
|
||||||
|
deps = [ "../public:socket" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc_source_set("mock_context") {
|
||||||
|
testonly = true
|
||||||
|
sources = [ "mock_context.h" ]
|
||||||
|
deps = [
|
||||||
|
":context",
|
||||||
|
":mock_callbacks",
|
||||||
|
"../common:internal_types",
|
||||||
|
"../packet:sctp_packet",
|
||||||
|
"../public:socket",
|
||||||
|
"../public:types",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
66
net/dcsctp/socket/context.h
Normal file
66
net/dcsctp/socket/context.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
#ifndef NET_DCSCTP_SOCKET_CONTEXT_H_
|
||||||
|
#define NET_DCSCTP_SOCKET_CONTEXT_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "absl/strings/string_view.h"
|
||||||
|
#include "net/dcsctp/common/internal_types.h"
|
||||||
|
#include "net/dcsctp/packet/sctp_packet.h"
|
||||||
|
#include "net/dcsctp/public/dcsctp_socket.h"
|
||||||
|
#include "net/dcsctp/public/types.h"
|
||||||
|
|
||||||
|
namespace dcsctp {
|
||||||
|
|
||||||
|
// A set of helper methods used by handlers to e.g. send packets.
|
||||||
|
//
|
||||||
|
// Implemented by the TransmissionControlBlock.
|
||||||
|
class Context {
|
||||||
|
public:
|
||||||
|
virtual ~Context() = default;
|
||||||
|
|
||||||
|
// Indicates if a connection has been established.
|
||||||
|
virtual bool is_connection_established() const = 0;
|
||||||
|
|
||||||
|
// Returns this side's initial TSN value.
|
||||||
|
virtual TSN my_initial_tsn() const = 0;
|
||||||
|
|
||||||
|
// Returns the peer's initial TSN value.
|
||||||
|
virtual TSN peer_initial_tsn() const = 0;
|
||||||
|
|
||||||
|
// Returns the socket callbacks.
|
||||||
|
virtual DcSctpSocketCallbacks& callbacks() const = 0;
|
||||||
|
|
||||||
|
// Observes a measured RTT value, in milliseconds.
|
||||||
|
virtual void ObserveRTT(DurationMs rtt_ms) = 0;
|
||||||
|
|
||||||
|
// Returns the current Retransmission Timeout (rto) value, in milliseconds.
|
||||||
|
virtual DurationMs current_rto() const = 0;
|
||||||
|
|
||||||
|
// Increments the transmission error counter, given a human readable reason.
|
||||||
|
virtual bool IncrementTxErrorCounter(absl::string_view reason) = 0;
|
||||||
|
|
||||||
|
// Clears the transmission error counter.
|
||||||
|
virtual void ClearTxErrorCounter() = 0;
|
||||||
|
|
||||||
|
// Returns true if there have been too many retransmission errors.
|
||||||
|
virtual bool HasTooManyTxErrors() const = 0;
|
||||||
|
|
||||||
|
// Returns a PacketBuilder, filled in with the correct verification tag.
|
||||||
|
virtual SctpPacket::Builder PacketBuilder() const = 0;
|
||||||
|
|
||||||
|
// Builds the packet from `builder` and sends it.
|
||||||
|
virtual void Send(SctpPacket::Builder& builder) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dcsctp
|
||||||
|
|
||||||
|
#endif // NET_DCSCTP_SOCKET_CONTEXT_H_
|
72
net/dcsctp/socket/mock_context.h
Normal file
72
net/dcsctp/socket/mock_context.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
#ifndef NET_DCSCTP_SOCKET_MOCK_CONTEXT_H_
|
||||||
|
#define NET_DCSCTP_SOCKET_MOCK_CONTEXT_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "absl/strings/string_view.h"
|
||||||
|
#include "absl/types/optional.h"
|
||||||
|
#include "net/dcsctp/packet/sctp_packet.h"
|
||||||
|
#include "net/dcsctp/public/dcsctp_options.h"
|
||||||
|
#include "net/dcsctp/public/dcsctp_socket.h"
|
||||||
|
#include "net/dcsctp/socket/context.h"
|
||||||
|
#include "net/dcsctp/socket/mock_dcsctp_socket_callbacks.h"
|
||||||
|
#include "test/gmock.h"
|
||||||
|
|
||||||
|
namespace dcsctp {
|
||||||
|
|
||||||
|
class MockContext : public Context {
|
||||||
|
public:
|
||||||
|
static constexpr TSN MyInitialTsn() { return TSN(990); }
|
||||||
|
static constexpr TSN PeerInitialTsn() { return TSN(10); }
|
||||||
|
static constexpr VerificationTag PeerVerificationTag() {
|
||||||
|
return VerificationTag(0x01234567);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit MockContext(MockDcSctpSocketCallbacks* callbacks)
|
||||||
|
: callbacks_(*callbacks) {
|
||||||
|
ON_CALL(*this, is_connection_established)
|
||||||
|
.WillByDefault(testing::Return(true));
|
||||||
|
ON_CALL(*this, my_initial_tsn)
|
||||||
|
.WillByDefault(testing::Return(MyInitialTsn()));
|
||||||
|
ON_CALL(*this, peer_initial_tsn)
|
||||||
|
.WillByDefault(testing::Return(PeerInitialTsn()));
|
||||||
|
ON_CALL(*this, callbacks).WillByDefault(testing::ReturnRef(callbacks_));
|
||||||
|
ON_CALL(*this, current_rto).WillByDefault(testing::Return(DurationMs(123)));
|
||||||
|
ON_CALL(*this, Send).WillByDefault([this](SctpPacket::Builder& builder) {
|
||||||
|
callbacks_.SendPacket(builder.Build());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
MOCK_METHOD(bool, is_connection_established, (), (const, override));
|
||||||
|
MOCK_METHOD(TSN, my_initial_tsn, (), (const, override));
|
||||||
|
MOCK_METHOD(TSN, peer_initial_tsn, (), (const, override));
|
||||||
|
MOCK_METHOD(DcSctpSocketCallbacks&, callbacks, (), (const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD(void, ObserveRTT, (DurationMs rtt_ms), (override));
|
||||||
|
MOCK_METHOD(DurationMs, current_rto, (), (const, override));
|
||||||
|
MOCK_METHOD(bool,
|
||||||
|
IncrementTxErrorCounter,
|
||||||
|
(absl::string_view reason),
|
||||||
|
(override));
|
||||||
|
MOCK_METHOD(void, ClearTxErrorCounter, (), (override));
|
||||||
|
MOCK_METHOD(bool, HasTooManyTxErrors, (), (const, override));
|
||||||
|
SctpPacket::Builder PacketBuilder() const override {
|
||||||
|
return SctpPacket::Builder(PeerVerificationTag(), options_);
|
||||||
|
}
|
||||||
|
MOCK_METHOD(void, Send, (SctpPacket::Builder & builder), (override));
|
||||||
|
|
||||||
|
DcSctpOptions options_;
|
||||||
|
MockDcSctpSocketCallbacks& callbacks_;
|
||||||
|
};
|
||||||
|
} // namespace dcsctp
|
||||||
|
|
||||||
|
#endif // NET_DCSCTP_SOCKET_MOCK_CONTEXT_H_
|
152
net/dcsctp/socket/mock_dcsctp_socket_callbacks.h
Normal file
152
net/dcsctp/socket/mock_dcsctp_socket_callbacks.h
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
#ifndef NET_DCSCTP_SOCKET_MOCK_DCSCTP_SOCKET_CALLBACKS_H_
|
||||||
|
#define NET_DCSCTP_SOCKET_MOCK_DCSCTP_SOCKET_CALLBACKS_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <deque>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/strings/string_view.h"
|
||||||
|
#include "absl/types/optional.h"
|
||||||
|
#include "api/array_view.h"
|
||||||
|
#include "net/dcsctp/public/dcsctp_message.h"
|
||||||
|
#include "net/dcsctp/public/dcsctp_socket.h"
|
||||||
|
#include "net/dcsctp/public/timeout.h"
|
||||||
|
#include "net/dcsctp/public/types.h"
|
||||||
|
#include "net/dcsctp/timer/fake_timeout.h"
|
||||||
|
#include "rtc_base/logging.h"
|
||||||
|
#include "rtc_base/random.h"
|
||||||
|
#include "test/gmock.h"
|
||||||
|
|
||||||
|
namespace dcsctp {
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
// It can be argued if a mocked random number generator should be deterministic
|
||||||
|
// or if it should be have as a "real" random number generator. In this
|
||||||
|
// implementation, each instantiation of `MockDcSctpSocketCallbacks` will have
|
||||||
|
// their `GetRandomInt` return different sequences, but each instantiation will
|
||||||
|
// always generate the same sequence of random numbers. This to make it easier
|
||||||
|
// to compare logs from tests, but still to let e.g. two different sockets (used
|
||||||
|
// in the same test) get different random numbers, so that they don't start e.g.
|
||||||
|
// on the same sequence number. While that isn't an issue in the protocol, it
|
||||||
|
// just makes debugging harder as the two sockets would look exactly the same.
|
||||||
|
//
|
||||||
|
// In a real implementation of `DcSctpSocketCallbacks` the random number
|
||||||
|
// generator backing `GetRandomInt` should be seeded externally and correctly.
|
||||||
|
inline int GetUniqueSeed() {
|
||||||
|
static int seed = 0;
|
||||||
|
return ++seed;
|
||||||
|
}
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
class MockDcSctpSocketCallbacks : public DcSctpSocketCallbacks {
|
||||||
|
public:
|
||||||
|
MockDcSctpSocketCallbacks()
|
||||||
|
: random_(internal::GetUniqueSeed()),
|
||||||
|
timeout_manager_([this]() { return now_; }) {
|
||||||
|
ON_CALL(*this, SendPacket)
|
||||||
|
.WillByDefault([this](rtc::ArrayView<const uint8_t> data) {
|
||||||
|
sent_packets_.emplace_back(
|
||||||
|
std::vector<uint8_t>(data.begin(), data.end()));
|
||||||
|
});
|
||||||
|
ON_CALL(*this, OnMessageReceived)
|
||||||
|
.WillByDefault([this](DcSctpMessage message) {
|
||||||
|
received_messages_.emplace_back(std::move(message));
|
||||||
|
});
|
||||||
|
|
||||||
|
ON_CALL(*this, OnError)
|
||||||
|
.WillByDefault([](ErrorKind error, absl::string_view message) {
|
||||||
|
RTC_LOG(LS_WARNING)
|
||||||
|
<< "Socket error: " << ToString(error) << "; " << message;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
MOCK_METHOD(void,
|
||||||
|
SendPacket,
|
||||||
|
(rtc::ArrayView<const uint8_t> data),
|
||||||
|
(override));
|
||||||
|
|
||||||
|
std::unique_ptr<Timeout> CreateTimeout() override {
|
||||||
|
return timeout_manager_.CreateTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeMs TimeMillis() override { return now_; }
|
||||||
|
|
||||||
|
uint32_t GetRandomInt(uint32_t low, uint32_t high) override {
|
||||||
|
return random_.Rand(low, high);
|
||||||
|
}
|
||||||
|
MOCK_METHOD(void, NotifyOutgoingMessageBufferEmpty, (), (override));
|
||||||
|
|
||||||
|
MOCK_METHOD(void, OnMessageReceived, (DcSctpMessage message), (override));
|
||||||
|
MOCK_METHOD(void,
|
||||||
|
OnError,
|
||||||
|
(ErrorKind error, absl::string_view message),
|
||||||
|
(override));
|
||||||
|
MOCK_METHOD(void,
|
||||||
|
OnAborted,
|
||||||
|
(ErrorKind error, absl::string_view message),
|
||||||
|
(override));
|
||||||
|
MOCK_METHOD(void, OnConnected, (), (override));
|
||||||
|
MOCK_METHOD(void, OnClosed, (), (override));
|
||||||
|
MOCK_METHOD(void, OnConnectionRestarted, (), (override));
|
||||||
|
MOCK_METHOD(void,
|
||||||
|
OnStreamsResetFailed,
|
||||||
|
(rtc::ArrayView<const StreamID> outgoing_streams,
|
||||||
|
absl::string_view reason),
|
||||||
|
(override));
|
||||||
|
MOCK_METHOD(void,
|
||||||
|
OnStreamsResetPerformed,
|
||||||
|
(rtc::ArrayView<const StreamID> outgoing_streams),
|
||||||
|
(override));
|
||||||
|
MOCK_METHOD(void,
|
||||||
|
OnIncomingStreamsReset,
|
||||||
|
(rtc::ArrayView<const StreamID> incoming_streams),
|
||||||
|
(override));
|
||||||
|
MOCK_METHOD(void,
|
||||||
|
OnSentMessageExpired,
|
||||||
|
(StreamID stream_id, PPID ppid, bool unsent),
|
||||||
|
(override));
|
||||||
|
|
||||||
|
bool HasPacket() const { return !sent_packets_.empty(); }
|
||||||
|
|
||||||
|
std::vector<uint8_t> ConsumeSentPacket() {
|
||||||
|
if (sent_packets_.empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> ret = std::move(sent_packets_.front());
|
||||||
|
sent_packets_.pop_front();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
absl::optional<DcSctpMessage> ConsumeReceivedMessage() {
|
||||||
|
if (received_messages_.empty()) {
|
||||||
|
return absl::nullopt;
|
||||||
|
}
|
||||||
|
DcSctpMessage ret = std::move(received_messages_.front());
|
||||||
|
received_messages_.pop_front();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvanceTime(DurationMs duration_ms) { now_ = now_ + duration_ms; }
|
||||||
|
void SetTime(TimeMs now) { now_ = now; }
|
||||||
|
|
||||||
|
std::vector<TimeoutID> RunTimers() { return timeout_manager_.RunTimers(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
TimeMs now_ = TimeMs(0);
|
||||||
|
webrtc::Random random_;
|
||||||
|
FakeTimeoutManager timeout_manager_;
|
||||||
|
std::deque<std::vector<uint8_t>> sent_packets_;
|
||||||
|
std::deque<DcSctpMessage> received_messages_;
|
||||||
|
};
|
||||||
|
} // namespace dcsctp
|
||||||
|
|
||||||
|
#endif // NET_DCSCTP_SOCKET_MOCK_DCSCTP_SOCKET_CALLBACKS_H_
|
Reference in New Issue
Block a user