Only initialize usrsctp when it's used and uninitialize when it's not being used.
BUG=chromium:612366, webrtc:5909 R=deadbeef@webrtc.org Review URL: https://codereview.webrtc.org/1995993002 . Cr-Commit-Position: refs/heads/master@{#12816}
This commit is contained in:
parent
e725f7c73e
commit
7d01331eca
@ -20,6 +20,7 @@
|
||||
#include "usrsctplib/usrsctp.h"
|
||||
#include "webrtc/base/arraysize.h"
|
||||
#include "webrtc/base/copyonwritebuffer.h"
|
||||
#include "webrtc/base/criticalsection.h"
|
||||
#include "webrtc/base/helpers.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/safe_conversions.h"
|
||||
@ -27,8 +28,29 @@
|
||||
#include "webrtc/media/base/mediaconstants.h"
|
||||
#include "webrtc/media/base/streamparams.h"
|
||||
|
||||
namespace cricket {
|
||||
// The biggest SCTP packet. Starting from a 'safe' wire MTU value of 1280,
|
||||
// take off 80 bytes for DTLS/TURN/TCP/IP overhead.
|
||||
static const size_t kSctpMtu = 1200;
|
||||
|
||||
// The size of the SCTP association send buffer. 256kB, the usrsctp default.
|
||||
static const int kSendBufferSize = 262144;
|
||||
|
||||
struct SctpInboundPacket {
|
||||
rtc::CopyOnWriteBuffer buffer;
|
||||
ReceiveDataParams params;
|
||||
// The |flags| parameter is used by SCTP to distinguish notification packets
|
||||
// from other types of packets.
|
||||
int flags;
|
||||
};
|
||||
|
||||
namespace {
|
||||
typedef cricket::SctpDataMediaChannel::StreamSet StreamSet;
|
||||
// Set the initial value of the static SCTP Data Engines reference count.
|
||||
int g_usrsctp_usage_count = 0;
|
||||
rtc::GlobalLockPod g_usrsctp_lock_;
|
||||
|
||||
typedef SctpDataMediaChannel::StreamSet StreamSet;
|
||||
|
||||
// Returns a comma-separated, human-readable list of the stream IDs in 's'
|
||||
std::string ListStreams(const StreamSet& s) {
|
||||
std::stringstream result;
|
||||
@ -85,78 +107,62 @@ std::string ListArray(const uint16_t* array, int num_elems) {
|
||||
}
|
||||
return result.str();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace cricket {
|
||||
typedef rtc::ScopedMessageData<SctpInboundPacket> InboundPacketMessage;
|
||||
typedef rtc::ScopedMessageData<rtc::CopyOnWriteBuffer> OutboundPacketMessage;
|
||||
|
||||
// The biggest SCTP packet. Starting from a 'safe' wire MTU value of 1280,
|
||||
// take off 80 bytes for DTLS/TURN/TCP/IP overhead.
|
||||
static const size_t kSctpMtu = 1200;
|
||||
|
||||
// The size of the SCTP association send buffer. 256kB, the usrsctp default.
|
||||
static const int kSendBufferSize = 262144;
|
||||
enum {
|
||||
MSG_SCTPINBOUNDPACKET = 1, // MessageData is SctpInboundPacket
|
||||
MSG_SCTPOUTBOUNDPACKET = 2, // MessageData is rtc:Buffer
|
||||
};
|
||||
|
||||
struct SctpInboundPacket {
|
||||
rtc::CopyOnWriteBuffer buffer;
|
||||
ReceiveDataParams params;
|
||||
// The |flags| parameter is used by SCTP to distinguish notification packets
|
||||
// from other types of packets.
|
||||
int flags;
|
||||
};
|
||||
|
||||
// Helper for logging SCTP messages.
|
||||
static void debug_sctp_printf(const char *format, ...) {
|
||||
void DebugSctpPrintf(const char* format, ...) {
|
||||
#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
|
||||
char s[255];
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vsnprintf(s, sizeof(s), format, ap);
|
||||
LOG(LS_INFO) << "SCTP: " << s;
|
||||
va_end(ap);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get the PPID to use for the terminating fragment of this type.
|
||||
static SctpDataMediaChannel::PayloadProtocolIdentifier GetPpid(
|
||||
cricket::DataMessageType type) {
|
||||
SctpDataMediaChannel::PayloadProtocolIdentifier GetPpid(DataMessageType type) {
|
||||
switch (type) {
|
||||
default:
|
||||
case cricket::DMT_NONE:
|
||||
case DMT_NONE:
|
||||
return SctpDataMediaChannel::PPID_NONE;
|
||||
case cricket::DMT_CONTROL:
|
||||
case DMT_CONTROL:
|
||||
return SctpDataMediaChannel::PPID_CONTROL;
|
||||
case cricket::DMT_BINARY:
|
||||
case DMT_BINARY:
|
||||
return SctpDataMediaChannel::PPID_BINARY_LAST;
|
||||
case cricket::DMT_TEXT:
|
||||
case DMT_TEXT:
|
||||
return SctpDataMediaChannel::PPID_TEXT_LAST;
|
||||
};
|
||||
}
|
||||
|
||||
static bool GetDataMediaType(
|
||||
SctpDataMediaChannel::PayloadProtocolIdentifier ppid,
|
||||
cricket::DataMessageType *dest) {
|
||||
bool GetDataMediaType(SctpDataMediaChannel::PayloadProtocolIdentifier ppid,
|
||||
DataMessageType* dest) {
|
||||
ASSERT(dest != NULL);
|
||||
switch (ppid) {
|
||||
case SctpDataMediaChannel::PPID_BINARY_PARTIAL:
|
||||
case SctpDataMediaChannel::PPID_BINARY_LAST:
|
||||
*dest = cricket::DMT_BINARY;
|
||||
*dest = DMT_BINARY;
|
||||
return true;
|
||||
|
||||
case SctpDataMediaChannel::PPID_TEXT_PARTIAL:
|
||||
case SctpDataMediaChannel::PPID_TEXT_LAST:
|
||||
*dest = cricket::DMT_TEXT;
|
||||
*dest = DMT_TEXT;
|
||||
return true;
|
||||
|
||||
case SctpDataMediaChannel::PPID_CONTROL:
|
||||
*dest = cricket::DMT_CONTROL;
|
||||
*dest = DMT_CONTROL;
|
||||
return true;
|
||||
|
||||
case SctpDataMediaChannel::PPID_NONE:
|
||||
*dest = cricket::DMT_NONE;
|
||||
*dest = DMT_NONE;
|
||||
return true;
|
||||
|
||||
default:
|
||||
@ -165,7 +171,7 @@ static bool GetDataMediaType(
|
||||
}
|
||||
|
||||
// Log the packet in text2pcap format, if log level is at LS_VERBOSE.
|
||||
static void VerboseLogPacket(const void *data, size_t length, int direction) {
|
||||
void VerboseLogPacket(const void* data, size_t length, int direction) {
|
||||
if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) {
|
||||
char *dump_buf;
|
||||
// Some downstream project uses an older version of usrsctp that expects
|
||||
@ -181,8 +187,11 @@ static void VerboseLogPacket(const void *data, size_t length, int direction) {
|
||||
|
||||
// This is the callback usrsctp uses when there's data to send on the network
|
||||
// that has been wrapped appropriatly for the SCTP protocol.
|
||||
static int OnSctpOutboundPacket(void* addr, void* data, size_t length,
|
||||
uint8_t tos, uint8_t set_df) {
|
||||
int OnSctpOutboundPacket(void* addr,
|
||||
void* data,
|
||||
size_t length,
|
||||
uint8_t tos,
|
||||
uint8_t set_df) {
|
||||
SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(addr);
|
||||
LOG(LS_VERBOSE) << "global OnSctpOutboundPacket():"
|
||||
<< "addr: " << addr << "; length: " << length
|
||||
@ -201,10 +210,13 @@ static int OnSctpOutboundPacket(void* addr, void* data, size_t length,
|
||||
// a packet has been interpreted and parsed by usrsctp and found to contain
|
||||
// payload data. It is called by a usrsctp thread. It is assumed this function
|
||||
// will free the memory used by 'data'.
|
||||
static int OnSctpInboundPacket(struct socket* sock, union sctp_sockstore addr,
|
||||
void* data, size_t length,
|
||||
struct sctp_rcvinfo rcv, int flags,
|
||||
void* ulp_info) {
|
||||
int OnSctpInboundPacket(struct socket* sock,
|
||||
union sctp_sockstore addr,
|
||||
void* data,
|
||||
size_t length,
|
||||
struct sctp_rcvinfo rcv,
|
||||
int flags,
|
||||
void* ulp_info) {
|
||||
SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(ulp_info);
|
||||
// Post data to the channel's receiver thread (copying it).
|
||||
// TODO(ldixon): Unclear if copy is needed as this method is responsible for
|
||||
@ -212,7 +224,7 @@ static int OnSctpInboundPacket(struct socket* sock, union sctp_sockstore addr,
|
||||
const SctpDataMediaChannel::PayloadProtocolIdentifier ppid =
|
||||
static_cast<SctpDataMediaChannel::PayloadProtocolIdentifier>(
|
||||
rtc::HostToNetwork32(rcv.rcv_ppid));
|
||||
cricket::DataMessageType type = cricket::DMT_NONE;
|
||||
DataMessageType type = DMT_NONE;
|
||||
if (!GetDataMediaType(ppid, &type) && !(flags & MSG_NOTIFICATION)) {
|
||||
// It's neither a notification nor a recognized data packet. Drop it.
|
||||
LOG(LS_ERROR) << "Received an unknown PPID " << ppid
|
||||
@ -233,78 +245,94 @@ static int OnSctpInboundPacket(struct socket* sock, union sctp_sockstore addr,
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Set the initial value of the static SCTP Data Engines reference count.
|
||||
int SctpDataEngine::usrsctp_engines_count = 0;
|
||||
void InitializeUsrSctp() {
|
||||
LOG(LS_INFO) << __FUNCTION__;
|
||||
// First argument is udp_encapsulation_port, which is not releveant for our
|
||||
// AF_CONN use of sctp.
|
||||
usrsctp_init(0, &OnSctpOutboundPacket, &DebugSctpPrintf);
|
||||
|
||||
SctpDataEngine::SctpDataEngine() {
|
||||
if (usrsctp_engines_count == 0) {
|
||||
// First argument is udp_encapsulation_port, which is not releveant for our
|
||||
// AF_CONN use of sctp.
|
||||
usrsctp_init(0, cricket::OnSctpOutboundPacket, debug_sctp_printf);
|
||||
// To turn on/off detailed SCTP debugging. You will also need to have the
|
||||
// SCTP_DEBUG cpp defines flag.
|
||||
// usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
|
||||
|
||||
// To turn on/off detailed SCTP debugging. You will also need to have the
|
||||
// SCTP_DEBUG cpp defines flag.
|
||||
// usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
|
||||
// TODO(ldixon): Consider turning this on/off.
|
||||
usrsctp_sysctl_set_sctp_ecn_enable(0);
|
||||
|
||||
// TODO(ldixon): Consider turning this on/off.
|
||||
usrsctp_sysctl_set_sctp_ecn_enable(0);
|
||||
// This is harmless, but we should find out when the library default
|
||||
// changes.
|
||||
int send_size = usrsctp_sysctl_get_sctp_sendspace();
|
||||
if (send_size != kSendBufferSize) {
|
||||
LOG(LS_ERROR) << "Got different send size than expected: " << send_size;
|
||||
}
|
||||
|
||||
// This is harmless, but we should find out when the library default
|
||||
// changes.
|
||||
int send_size = usrsctp_sysctl_get_sctp_sendspace();
|
||||
if (send_size != kSendBufferSize) {
|
||||
LOG(LS_ERROR) << "Got different send size than expected: " << send_size;
|
||||
// TODO(ldixon): Consider turning this on/off.
|
||||
// This is not needed right now (we don't do dynamic address changes):
|
||||
// If SCTP Auto-ASCONF is enabled, the peer is informed automatically
|
||||
// when a new address is added or removed. This feature is enabled by
|
||||
// default.
|
||||
// usrsctp_sysctl_set_sctp_auto_asconf(0);
|
||||
|
||||
// TODO(ldixon): Consider turning this on/off.
|
||||
// Add a blackhole sysctl. Setting it to 1 results in no ABORTs
|
||||
// being sent in response to INITs, setting it to 2 results
|
||||
// in no ABORTs being sent for received OOTB packets.
|
||||
// This is similar to the TCP sysctl.
|
||||
//
|
||||
// See: http://lakerest.net/pipermail/sctp-coders/2012-January/009438.html
|
||||
// See: http://svnweb.freebsd.org/base?view=revision&revision=229805
|
||||
// usrsctp_sysctl_set_sctp_blackhole(2);
|
||||
|
||||
// Set the number of default outgoing streams. This is the number we'll
|
||||
// send in the SCTP INIT message. The 'appropriate default' in the
|
||||
// second paragraph of
|
||||
// http://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-05#section-6.2
|
||||
// is kMaxSctpSid.
|
||||
usrsctp_sysctl_set_sctp_nr_outgoing_streams_default(kMaxSctpSid);
|
||||
}
|
||||
|
||||
void UninitializeUsrSctp() {
|
||||
LOG(LS_INFO) << __FUNCTION__;
|
||||
// usrsctp_finish() may fail if it's called too soon after the channels are
|
||||
// closed. Wait and try again until it succeeds for up to 3 seconds.
|
||||
for (size_t i = 0; i < 300; ++i) {
|
||||
if (usrsctp_finish() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(ldixon): Consider turning this on/off.
|
||||
// This is not needed right now (we don't do dynamic address changes):
|
||||
// If SCTP Auto-ASCONF is enabled, the peer is informed automatically
|
||||
// when a new address is added or removed. This feature is enabled by
|
||||
// default.
|
||||
// usrsctp_sysctl_set_sctp_auto_asconf(0);
|
||||
|
||||
// TODO(ldixon): Consider turning this on/off.
|
||||
// Add a blackhole sysctl. Setting it to 1 results in no ABORTs
|
||||
// being sent in response to INITs, setting it to 2 results
|
||||
// in no ABORTs being sent for received OOTB packets.
|
||||
// This is similar to the TCP sysctl.
|
||||
//
|
||||
// See: http://lakerest.net/pipermail/sctp-coders/2012-January/009438.html
|
||||
// See: http://svnweb.freebsd.org/base?view=revision&revision=229805
|
||||
// usrsctp_sysctl_set_sctp_blackhole(2);
|
||||
|
||||
// Set the number of default outgoing streams. This is the number we'll
|
||||
// send in the SCTP INIT message. The 'appropriate default' in the
|
||||
// second paragraph of
|
||||
// http://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-05#section-6.2
|
||||
// is cricket::kMaxSctpSid.
|
||||
usrsctp_sysctl_set_sctp_nr_outgoing_streams_default(
|
||||
cricket::kMaxSctpSid);
|
||||
rtc::Thread::SleepMs(10);
|
||||
}
|
||||
usrsctp_engines_count++;
|
||||
LOG(LS_ERROR) << "Failed to shutdown usrsctp.";
|
||||
}
|
||||
|
||||
cricket::DataCodec codec(kGoogleSctpDataCodecId, kGoogleSctpDataCodecName);
|
||||
void IncrementUsrSctpUsageCount() {
|
||||
rtc::GlobalLockScope lock(&g_usrsctp_lock_);
|
||||
if (!g_usrsctp_usage_count) {
|
||||
InitializeUsrSctp();
|
||||
}
|
||||
++g_usrsctp_usage_count;
|
||||
}
|
||||
|
||||
void DecrementUsrSctpUsageCount() {
|
||||
rtc::GlobalLockScope lock(&g_usrsctp_lock_);
|
||||
--g_usrsctp_usage_count;
|
||||
if (!g_usrsctp_usage_count) {
|
||||
UninitializeUsrSctp();
|
||||
}
|
||||
}
|
||||
|
||||
DataCodec GetSctpDataCodec() {
|
||||
DataCodec codec(kGoogleSctpDataCodecId, kGoogleSctpDataCodecName);
|
||||
codec.SetParam(kCodecParamPort, kSctpDefaultPort);
|
||||
codecs_.push_back(codec);
|
||||
return codec;
|
||||
}
|
||||
|
||||
SctpDataEngine::~SctpDataEngine() {
|
||||
usrsctp_engines_count--;
|
||||
LOG(LS_VERBOSE) << "usrsctp_engines_count:" << usrsctp_engines_count;
|
||||
} // namespace
|
||||
|
||||
if (usrsctp_engines_count == 0) {
|
||||
// usrsctp_finish() may fail if it's called too soon after the channels are
|
||||
// closed. Wait and try again until it succeeds for up to 3 seconds.
|
||||
for (size_t i = 0; i < 300; ++i) {
|
||||
if (usrsctp_finish() == 0)
|
||||
return;
|
||||
SctpDataEngine::SctpDataEngine() : codecs_(1, GetSctpDataCodec()) {}
|
||||
|
||||
rtc::Thread::SleepMs(10);
|
||||
}
|
||||
LOG(LS_ERROR) << "Failed to shutdown usrsctp.";
|
||||
}
|
||||
}
|
||||
SctpDataEngine::~SctpDataEngine() {}
|
||||
|
||||
// Called on the worker thread.
|
||||
DataMediaChannel* SctpDataEngine::CreateChannel(
|
||||
DataChannelType data_channel_type) {
|
||||
if (data_channel_type != DCT_SCTP) {
|
||||
@ -314,7 +342,7 @@ DataMediaChannel* SctpDataEngine::CreateChannel(
|
||||
}
|
||||
|
||||
// static
|
||||
SctpDataMediaChannel* SctpDataEngine::GetChannelFromSocket(
|
||||
SctpDataMediaChannel* SctpDataMediaChannel::GetChannelFromSocket(
|
||||
struct socket* sock) {
|
||||
struct sockaddr* addrs = nullptr;
|
||||
int naddrs = usrsctp_getladdrs(sock, 0, &addrs);
|
||||
@ -336,8 +364,8 @@ SctpDataMediaChannel* SctpDataEngine::GetChannelFromSocket(
|
||||
}
|
||||
|
||||
// static
|
||||
int SctpDataEngine::SendThresholdCallback(struct socket* sock,
|
||||
uint32_t sb_free) {
|
||||
int SctpDataMediaChannel::SendThresholdCallback(struct socket* sock,
|
||||
uint32_t sb_free) {
|
||||
// Fired on our I/O thread. SctpDataMediaChannel::OnPacketReceived() gets
|
||||
// a packet containing acknowledgments, which goes into usrsctp_conninput,
|
||||
// and then back here.
|
||||
@ -389,17 +417,19 @@ bool SctpDataMediaChannel::OpenSctpSocket() {
|
||||
return false;
|
||||
}
|
||||
|
||||
IncrementUsrSctpUsageCount();
|
||||
|
||||
// If kSendBufferSize isn't reflective of reality, we log an error, but we
|
||||
// still have to do something reasonable here. Look up what the buffer's
|
||||
// real size is and set our threshold to something reasonable.
|
||||
const static int kSendThreshold = usrsctp_sysctl_get_sctp_sendspace() / 2;
|
||||
|
||||
sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP,
|
||||
cricket::OnSctpInboundPacket,
|
||||
&SctpDataEngine::SendThresholdCallback,
|
||||
kSendThreshold, this);
|
||||
sock_ = usrsctp_socket(
|
||||
AF_CONN, SOCK_STREAM, IPPROTO_SCTP, OnSctpInboundPacket,
|
||||
&SctpDataMediaChannel::SendThresholdCallback, kSendThreshold, this);
|
||||
if (!sock_) {
|
||||
LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket.";
|
||||
DecrementUsrSctpUsageCount();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -488,6 +518,8 @@ void SctpDataMediaChannel::CloseSctpSocket() {
|
||||
usrsctp_close(sock_);
|
||||
sock_ = NULL;
|
||||
usrsctp_deregister_address(this);
|
||||
|
||||
DecrementUsrSctpUsageCount();
|
||||
}
|
||||
}
|
||||
|
||||
@ -599,7 +631,7 @@ bool SctpDataMediaChannel::SendData(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (params.type != cricket::DMT_CONTROL &&
|
||||
if (params.type != DMT_CONTROL &&
|
||||
open_streams_.find(params.ssrc) == open_streams_.end()) {
|
||||
LOG(LS_WARNING) << debug_name_ << "->SendData(...): "
|
||||
<< "Not sending data because ssrc is unknown: "
|
||||
@ -717,7 +749,7 @@ bool SctpDataMediaChannel::AddStream(const StreamParams& stream) {
|
||||
}
|
||||
|
||||
const uint32_t ssrc = stream.first_ssrc();
|
||||
if (ssrc >= cricket::kMaxSctpSid) {
|
||||
if (ssrc >= kMaxSctpSid) {
|
||||
LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
|
||||
<< "Not adding data stream '" << stream.id
|
||||
<< "' with ssrc=" << ssrc
|
||||
@ -984,8 +1016,9 @@ void SctpDataMediaChannel::OnPacketFromSctpToNetwork(
|
||||
}
|
||||
|
||||
bool SctpDataMediaChannel::SendQueuedStreamResets() {
|
||||
if (!sent_reset_streams_.empty() || queued_reset_streams_.empty())
|
||||
if (!sent_reset_streams_.empty() || queued_reset_streams_.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending ["
|
||||
<< ListStreams(queued_reset_streams_) << "], Open: ["
|
||||
|
||||
@ -25,6 +25,7 @@ enum PreservedErrno {
|
||||
} // namespace cricket
|
||||
|
||||
#include "webrtc/base/copyonwritebuffer.h"
|
||||
#include "webrtc/base/gtest_prod_util.h"
|
||||
#include "webrtc/media/base/codec.h"
|
||||
#include "webrtc/media/base/mediachannel.h"
|
||||
#include "webrtc/media/base/mediaengine.h"
|
||||
@ -75,19 +76,13 @@ class SctpDataMediaChannel;
|
||||
class SctpDataEngine : public DataEngineInterface, public sigslot::has_slots<> {
|
||||
public:
|
||||
SctpDataEngine();
|
||||
virtual ~SctpDataEngine();
|
||||
~SctpDataEngine() override;
|
||||
|
||||
virtual DataMediaChannel* CreateChannel(DataChannelType data_channel_type);
|
||||
|
||||
virtual const std::vector<DataCodec>& data_codecs() { return codecs_; }
|
||||
|
||||
static int SendThresholdCallback(struct socket* sock, uint32_t sb_free);
|
||||
DataMediaChannel* CreateChannel(DataChannelType data_channel_type) override;
|
||||
const std::vector<DataCodec>& data_codecs() override { return codecs_; }
|
||||
|
||||
private:
|
||||
static int usrsctp_engines_count;
|
||||
std::vector<DataCodec> codecs_;
|
||||
|
||||
static SctpDataMediaChannel* GetChannelFromSocket(struct socket* sock);
|
||||
const std::vector<DataCodec> codecs_;
|
||||
};
|
||||
|
||||
// TODO(ldixon): Make into a special type of TypedMessageData.
|
||||
@ -161,11 +156,16 @@ class SctpDataMediaChannel : public DataMediaChannel,
|
||||
|
||||
void OnSendThresholdCallback();
|
||||
// Helper for debugging.
|
||||
void set_debug_name(const std::string& debug_name) {
|
||||
void set_debug_name_for_testing(const char* debug_name) {
|
||||
debug_name_ = debug_name;
|
||||
}
|
||||
const std::string& debug_name() const { return debug_name_; }
|
||||
const struct socket* socket() const { return sock_; }
|
||||
|
||||
private:
|
||||
FRIEND_TEST_ALL_PREFIXES(SctpDataMediaChannelTest, EngineSignalsRightChannel);
|
||||
static int SendThresholdCallback(struct socket* sock, uint32_t sb_free);
|
||||
static SctpDataMediaChannel* GetChannelFromSocket(struct socket* sock);
|
||||
|
||||
private:
|
||||
sockaddr_conn GetSctpSockAddr(int port);
|
||||
|
||||
@ -229,8 +229,8 @@ class SctpDataMediaChannel : public DataMediaChannel,
|
||||
StreamSet queued_reset_streams_;
|
||||
StreamSet sent_reset_streams_;
|
||||
|
||||
// A human-readable name for debugging messages.
|
||||
std::string debug_name_;
|
||||
// A static human-readable name for debugging messages.
|
||||
const char* debug_name_;
|
||||
};
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
@ -29,13 +29,14 @@
|
||||
#include "webrtc/media/base/mediaconstants.h"
|
||||
#include "webrtc/media/sctp/sctpdataengine.h"
|
||||
|
||||
namespace cricket {
|
||||
enum {
|
||||
MSG_PACKET = 1,
|
||||
};
|
||||
|
||||
// Fake NetworkInterface that sends/receives sctp packets. The one in
|
||||
// webrtc/media/base/fakenetworkinterface.h only works with rtp/rtcp.
|
||||
class SctpFakeNetworkInterface : public cricket::MediaChannel::NetworkInterface,
|
||||
class SctpFakeNetworkInterface : public MediaChannel::NetworkInterface,
|
||||
public rtc::MessageHandler {
|
||||
public:
|
||||
explicit SctpFakeNetworkInterface(rtc::Thread* thread)
|
||||
@ -43,7 +44,7 @@ class SctpFakeNetworkInterface : public cricket::MediaChannel::NetworkInterface,
|
||||
dest_(NULL) {
|
||||
}
|
||||
|
||||
void SetDestination(cricket::DataMediaChannel* dest) { dest_ = dest; }
|
||||
void SetDestination(DataMediaChannel* dest) { dest_ = dest; }
|
||||
|
||||
protected:
|
||||
// Called to send raw packet down the wire (e.g. SCTP an packet).
|
||||
@ -91,7 +92,7 @@ class SctpFakeNetworkInterface : public cricket::MediaChannel::NetworkInterface,
|
||||
private:
|
||||
// Not owned by this class.
|
||||
rtc::Thread* thread_;
|
||||
cricket::DataMediaChannel* dest_;
|
||||
DataMediaChannel* dest_;
|
||||
};
|
||||
|
||||
// This is essentially a buffer to hold recieved data. It stores only the last
|
||||
@ -106,11 +107,12 @@ class SctpFakeDataReceiver : public sigslot::has_slots<> {
|
||||
void Clear() {
|
||||
received_ = false;
|
||||
last_data_ = "";
|
||||
last_params_ = cricket::ReceiveDataParams();
|
||||
last_params_ = ReceiveDataParams();
|
||||
}
|
||||
|
||||
virtual void OnDataReceived(const cricket::ReceiveDataParams& params,
|
||||
const char* data, size_t length) {
|
||||
virtual void OnDataReceived(const ReceiveDataParams& params,
|
||||
const char* data,
|
||||
size_t length) {
|
||||
received_ = true;
|
||||
last_data_ = std::string(data, length);
|
||||
last_params_ = params;
|
||||
@ -118,12 +120,12 @@ class SctpFakeDataReceiver : public sigslot::has_slots<> {
|
||||
|
||||
bool received() const { return received_; }
|
||||
std::string last_data() const { return last_data_; }
|
||||
cricket::ReceiveDataParams last_params() const { return last_params_; }
|
||||
ReceiveDataParams last_params() const { return last_params_; }
|
||||
|
||||
private:
|
||||
bool received_;
|
||||
std::string last_data_;
|
||||
cricket::ReceiveDataParams last_params_;
|
||||
ReceiveDataParams last_params_;
|
||||
};
|
||||
|
||||
class SignalReadyToSendObserver : public sigslot::has_slots<> {
|
||||
@ -147,7 +149,7 @@ class SignalReadyToSendObserver : public sigslot::has_slots<> {
|
||||
class SignalChannelClosedObserver : public sigslot::has_slots<> {
|
||||
public:
|
||||
SignalChannelClosedObserver() {}
|
||||
void BindSelf(cricket::SctpDataMediaChannel* channel) {
|
||||
void BindSelf(SctpDataMediaChannel* channel) {
|
||||
channel->SignalStreamClosedRemotely.connect(
|
||||
this, &SignalChannelClosedObserver::OnStreamClosed);
|
||||
}
|
||||
@ -168,12 +170,12 @@ class SignalChannelClosedObserver : public sigslot::has_slots<> {
|
||||
|
||||
class SignalChannelClosedReopener : public sigslot::has_slots<> {
|
||||
public:
|
||||
SignalChannelClosedReopener(cricket::SctpDataMediaChannel* channel,
|
||||
cricket::SctpDataMediaChannel* peer)
|
||||
SignalChannelClosedReopener(SctpDataMediaChannel* channel,
|
||||
SctpDataMediaChannel* peer)
|
||||
: channel_(channel), peer_(peer) {}
|
||||
|
||||
void OnStreamClosed(int stream) {
|
||||
cricket::StreamParams p(cricket::StreamParams::CreateLegacy(stream));
|
||||
StreamParams p(StreamParams::CreateLegacy(stream));
|
||||
channel_->AddSendStream(p);
|
||||
channel_->AddRecvStream(p);
|
||||
peer_->AddSendStream(p);
|
||||
@ -186,8 +188,8 @@ class SignalChannelClosedReopener : public sigslot::has_slots<> {
|
||||
}
|
||||
|
||||
private:
|
||||
cricket::SctpDataMediaChannel* channel_;
|
||||
cricket::SctpDataMediaChannel* peer_;
|
||||
SctpDataMediaChannel* channel_;
|
||||
SctpDataMediaChannel* peer_;
|
||||
std::vector<int> streams_;
|
||||
};
|
||||
|
||||
@ -200,9 +202,7 @@ class SctpDataMediaChannelTest : public testing::Test,
|
||||
static void SetUpTestCase() {
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
engine_.reset(new cricket::SctpDataEngine());
|
||||
}
|
||||
virtual void SetUp() { engine_.reset(new SctpDataEngine()); }
|
||||
|
||||
void SetupConnectedChannels() {
|
||||
net1_.reset(new SctpFakeNetworkInterface(rtc::Thread::Current()));
|
||||
@ -212,11 +212,11 @@ class SctpDataMediaChannelTest : public testing::Test,
|
||||
chan1_ready_to_send_count_ = 0;
|
||||
chan2_ready_to_send_count_ = 0;
|
||||
chan1_.reset(CreateChannel(net1_.get(), recv1_.get()));
|
||||
chan1_->set_debug_name("chan1/connector");
|
||||
chan1_->set_debug_name_for_testing("chan1/connector");
|
||||
chan1_->SignalReadyToSend.connect(
|
||||
this, &SctpDataMediaChannelTest::OnChan1ReadyToSend);
|
||||
chan2_.reset(CreateChannel(net2_.get(), recv2_.get()));
|
||||
chan2_->set_debug_name("chan2/listener");
|
||||
chan2_->set_debug_name_for_testing("chan2/listener");
|
||||
chan2_->SignalReadyToSend.connect(
|
||||
this, &SctpDataMediaChannelTest::OnChan2ReadyToSend);
|
||||
// Setup two connected channels ready to send and receive.
|
||||
@ -254,7 +254,7 @@ class SctpDataMediaChannelTest : public testing::Test,
|
||||
|
||||
bool AddStream(int ssrc) {
|
||||
bool ret = true;
|
||||
cricket::StreamParams p(cricket::StreamParams::CreateLegacy(ssrc));
|
||||
StreamParams p(StreamParams::CreateLegacy(ssrc));
|
||||
ret = ret && chan1_->AddSendStream(p);
|
||||
ret = ret && chan1_->AddRecvStream(p);
|
||||
ret = ret && chan2_->AddSendStream(p);
|
||||
@ -262,11 +262,10 @@ class SctpDataMediaChannelTest : public testing::Test,
|
||||
return ret;
|
||||
}
|
||||
|
||||
cricket::SctpDataMediaChannel* CreateChannel(
|
||||
SctpFakeNetworkInterface* net, SctpFakeDataReceiver* recv) {
|
||||
cricket::SctpDataMediaChannel* channel =
|
||||
static_cast<cricket::SctpDataMediaChannel*>(engine_->CreateChannel(
|
||||
cricket::DCT_SCTP));
|
||||
SctpDataMediaChannel* CreateChannel(SctpFakeNetworkInterface* net,
|
||||
SctpFakeDataReceiver* recv) {
|
||||
SctpDataMediaChannel* channel =
|
||||
static_cast<SctpDataMediaChannel*>(engine_->CreateChannel(DCT_SCTP));
|
||||
channel->SetInterface(net);
|
||||
// When data is received, pass it to the SctpFakeDataReceiver.
|
||||
channel->SignalDataReceived.connect(
|
||||
@ -274,11 +273,11 @@ class SctpDataMediaChannelTest : public testing::Test,
|
||||
return channel;
|
||||
}
|
||||
|
||||
bool SendData(cricket::SctpDataMediaChannel* chan,
|
||||
bool SendData(SctpDataMediaChannel* chan,
|
||||
uint32_t ssrc,
|
||||
const std::string& msg,
|
||||
cricket::SendDataResult* result) {
|
||||
cricket::SendDataParams params;
|
||||
SendDataResult* result) {
|
||||
SendDataParams params;
|
||||
params.ssrc = ssrc;
|
||||
|
||||
return chan->SendData(params, rtc::CopyOnWriteBuffer(
|
||||
@ -304,21 +303,21 @@ class SctpDataMediaChannelTest : public testing::Test,
|
||||
return !thread->IsQuitting();
|
||||
}
|
||||
|
||||
cricket::SctpDataMediaChannel* channel1() { return chan1_.get(); }
|
||||
cricket::SctpDataMediaChannel* channel2() { return chan2_.get(); }
|
||||
SctpDataMediaChannel* channel1() { return chan1_.get(); }
|
||||
SctpDataMediaChannel* channel2() { return chan2_.get(); }
|
||||
SctpFakeDataReceiver* receiver1() { return recv1_.get(); }
|
||||
SctpFakeDataReceiver* receiver2() { return recv2_.get(); }
|
||||
|
||||
int channel1_ready_to_send_count() { return chan1_ready_to_send_count_; }
|
||||
int channel2_ready_to_send_count() { return chan2_ready_to_send_count_; }
|
||||
private:
|
||||
std::unique_ptr<cricket::SctpDataEngine> engine_;
|
||||
std::unique_ptr<SctpDataEngine> engine_;
|
||||
std::unique_ptr<SctpFakeNetworkInterface> net1_;
|
||||
std::unique_ptr<SctpFakeNetworkInterface> net2_;
|
||||
std::unique_ptr<SctpFakeDataReceiver> recv1_;
|
||||
std::unique_ptr<SctpFakeDataReceiver> recv2_;
|
||||
std::unique_ptr<cricket::SctpDataMediaChannel> chan1_;
|
||||
std::unique_ptr<cricket::SctpDataMediaChannel> chan2_;
|
||||
std::unique_ptr<SctpDataMediaChannel> chan1_;
|
||||
std::unique_ptr<SctpDataMediaChannel> chan2_;
|
||||
|
||||
int chan1_ready_to_send_count_;
|
||||
int chan2_ready_to_send_count_;
|
||||
@ -345,12 +344,12 @@ TEST_F(SctpDataMediaChannelTest, SignalReadyToSend) {
|
||||
channel2()->SignalReadyToSend.connect(&signal_observer_2,
|
||||
&SignalReadyToSendObserver::OnSignaled);
|
||||
|
||||
cricket::SendDataResult result;
|
||||
SendDataResult result;
|
||||
ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
|
||||
EXPECT_EQ(cricket::SDR_SUCCESS, result);
|
||||
EXPECT_EQ(SDR_SUCCESS, result);
|
||||
EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
|
||||
ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
|
||||
EXPECT_EQ(cricket::SDR_SUCCESS, result);
|
||||
EXPECT_EQ(SDR_SUCCESS, result);
|
||||
EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
|
||||
|
||||
EXPECT_TRUE_WAIT(signal_observer_1.IsSignaled(true), 1000);
|
||||
@ -360,10 +359,10 @@ TEST_F(SctpDataMediaChannelTest, SignalReadyToSend) {
|
||||
TEST_F(SctpDataMediaChannelTest, SendData) {
|
||||
SetupConnectedChannels();
|
||||
|
||||
cricket::SendDataResult result;
|
||||
SendDataResult result;
|
||||
LOG(LS_VERBOSE) << "chan1 sending: 'hello?' -----------------------------";
|
||||
ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
|
||||
EXPECT_EQ(cricket::SDR_SUCCESS, result);
|
||||
EXPECT_EQ(SDR_SUCCESS, result);
|
||||
EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
|
||||
LOG(LS_VERBOSE) << "recv2.received=" << receiver2()->received()
|
||||
<< ", recv2.last_params.ssrc="
|
||||
@ -376,7 +375,7 @@ TEST_F(SctpDataMediaChannelTest, SendData) {
|
||||
|
||||
LOG(LS_VERBOSE) << "chan2 sending: 'hi chan1' -----------------------------";
|
||||
ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
|
||||
EXPECT_EQ(cricket::SDR_SUCCESS, result);
|
||||
EXPECT_EQ(SDR_SUCCESS, result);
|
||||
EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
|
||||
LOG(LS_VERBOSE) << "recv1.received=" << receiver1()->received()
|
||||
<< ", recv1.last_params.ssrc="
|
||||
@ -392,8 +391,8 @@ TEST_F(SctpDataMediaChannelTest, SendData) {
|
||||
TEST_F(SctpDataMediaChannelTest, SendDataBlocked) {
|
||||
SetupConnectedChannels();
|
||||
|
||||
cricket::SendDataResult result;
|
||||
cricket::SendDataParams params;
|
||||
SendDataResult result;
|
||||
SendDataParams params;
|
||||
params.ssrc = 1;
|
||||
|
||||
std::vector<char> buffer(1024 * 64, 0);
|
||||
@ -401,11 +400,11 @@ TEST_F(SctpDataMediaChannelTest, SendDataBlocked) {
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
channel1()->SendData(
|
||||
params, rtc::CopyOnWriteBuffer(&buffer[0], buffer.size()), &result);
|
||||
if (result == cricket::SDR_BLOCK)
|
||||
if (result == SDR_BLOCK)
|
||||
break;
|
||||
}
|
||||
|
||||
EXPECT_EQ(cricket::SDR_BLOCK, result);
|
||||
EXPECT_EQ(SDR_BLOCK, result);
|
||||
}
|
||||
|
||||
TEST_F(SctpDataMediaChannelTest, ClosesRemoteStream) {
|
||||
@ -414,12 +413,12 @@ TEST_F(SctpDataMediaChannelTest, ClosesRemoteStream) {
|
||||
chan_1_sig_receiver.BindSelf(channel1());
|
||||
chan_2_sig_receiver.BindSelf(channel2());
|
||||
|
||||
cricket::SendDataResult result;
|
||||
SendDataResult result;
|
||||
ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
|
||||
EXPECT_EQ(cricket::SDR_SUCCESS, result);
|
||||
EXPECT_EQ(SDR_SUCCESS, result);
|
||||
EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
|
||||
ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
|
||||
EXPECT_EQ(cricket::SDR_SUCCESS, result);
|
||||
EXPECT_EQ(SDR_SUCCESS, result);
|
||||
EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
|
||||
|
||||
// Close channel 1. Channel 2 should notify us.
|
||||
@ -434,12 +433,12 @@ TEST_F(SctpDataMediaChannelTest, ClosesTwoRemoteStreams) {
|
||||
chan_1_sig_receiver.BindSelf(channel1());
|
||||
chan_2_sig_receiver.BindSelf(channel2());
|
||||
|
||||
cricket::SendDataResult result;
|
||||
SendDataResult result;
|
||||
ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
|
||||
EXPECT_EQ(cricket::SDR_SUCCESS, result);
|
||||
EXPECT_EQ(SDR_SUCCESS, result);
|
||||
EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
|
||||
ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
|
||||
EXPECT_EQ(cricket::SDR_SUCCESS, result);
|
||||
EXPECT_EQ(SDR_SUCCESS, result);
|
||||
EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
|
||||
|
||||
// Close two streams on one side.
|
||||
@ -457,12 +456,12 @@ TEST_F(SctpDataMediaChannelTest, ClosesStreamsOnBothSides) {
|
||||
chan_1_sig_receiver.BindSelf(channel1());
|
||||
chan_2_sig_receiver.BindSelf(channel2());
|
||||
|
||||
cricket::SendDataResult result;
|
||||
SendDataResult result;
|
||||
ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
|
||||
EXPECT_EQ(cricket::SDR_SUCCESS, result);
|
||||
EXPECT_EQ(SDR_SUCCESS, result);
|
||||
EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
|
||||
ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
|
||||
EXPECT_EQ(cricket::SDR_SUCCESS, result);
|
||||
EXPECT_EQ(SDR_SUCCESS, result);
|
||||
EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
|
||||
|
||||
// Close one stream on channel1(), while closing three streams on
|
||||
@ -484,7 +483,7 @@ TEST_F(SctpDataMediaChannelTest, EngineSignalsRightChannel) {
|
||||
EXPECT_TRUE_WAIT(channel1()->socket() != NULL, 1000);
|
||||
struct socket *sock = const_cast<struct socket*>(channel1()->socket());
|
||||
int prior_count = channel1_ready_to_send_count();
|
||||
cricket::SctpDataEngine::SendThresholdCallback(sock, 0);
|
||||
SctpDataMediaChannel::SendThresholdCallback(sock, 0);
|
||||
EXPECT_GT(channel1_ready_to_send_count(), prior_count);
|
||||
}
|
||||
|
||||
@ -503,12 +502,12 @@ TEST_F(SctpDataMediaChannelTest, RefusesHighNumberedChannels) {
|
||||
TEST_F(SctpDataMediaChannelTest, MAYBE_ReusesAStream) {
|
||||
// Shut down channel 1, then open it up again for reuse.
|
||||
SetupConnectedChannels();
|
||||
cricket::SendDataResult result;
|
||||
SendDataResult result;
|
||||
SignalChannelClosedObserver chan_2_sig_receiver;
|
||||
chan_2_sig_receiver.BindSelf(channel2());
|
||||
|
||||
ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
|
||||
EXPECT_EQ(cricket::SDR_SUCCESS, result);
|
||||
EXPECT_EQ(SDR_SUCCESS, result);
|
||||
EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
|
||||
|
||||
channel1()->RemoveSendStream(1);
|
||||
@ -518,8 +517,10 @@ TEST_F(SctpDataMediaChannelTest, MAYBE_ReusesAStream) {
|
||||
// Create a new channel 1.
|
||||
AddStream(1);
|
||||
ASSERT_TRUE(SendData(channel1(), 1, "hi?", &result));
|
||||
EXPECT_EQ(cricket::SDR_SUCCESS, result);
|
||||
EXPECT_EQ(SDR_SUCCESS, result);
|
||||
EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hi?"), 1000);
|
||||
channel1()->RemoveSendStream(1);
|
||||
EXPECT_TRUE_WAIT(chan_2_sig_receiver.StreamCloseCount(1) == 2, 1000);
|
||||
}
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user