| Index: talk/media/sctp/sctpdataengine.cc
|
| diff --git a/talk/media/sctp/sctpdataengine.cc b/talk/media/sctp/sctpdataengine.cc
|
| index 8c8a6a192fa25833c3de66c0587b9ed7ed3bccb3..4fc3d43dbc86968254141ee80e28c9ea0bbceca4 100644
|
| --- a/talk/media/sctp/sctpdataengine.cc
|
| +++ b/talk/media/sctp/sctpdataengine.cc
|
| @@ -109,6 +109,8 @@ typedef rtc::ScopedMessageData<rtc::Buffer> OutboundPacketMessage;
|
| // 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
|
| @@ -177,11 +179,11 @@ static bool GetDataMediaType(
|
| }
|
|
|
| // Log the packet in text2pcap format, if log level is at LS_VERBOSE.
|
| -static void VerboseLogPacket(void *addr, size_t length, int direction) {
|
| +static void VerboseLogPacket(void *data, size_t length, int direction) {
|
| if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) {
|
| char *dump_buf;
|
| if ((dump_buf = usrsctp_dumppacket(
|
| - addr, length, direction)) != NULL) {
|
| + data, length, direction)) != NULL) {
|
| LOG(LS_VERBOSE) << dump_buf;
|
| usrsctp_freedumpbuffer(dump_buf);
|
| }
|
| @@ -258,6 +260,13 @@ SctpDataEngine::SctpDataEngine() {
|
| // 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;
|
| + }
|
| +
|
| // 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
|
| @@ -315,6 +324,44 @@ DataMediaChannel* SctpDataEngine::CreateChannel(
|
| return new SctpDataMediaChannel(rtc::Thread::Current());
|
| }
|
|
|
| +// static
|
| +SctpDataMediaChannel* SctpDataEngine::GetChannelFromSocket(
|
| + struct socket* sock) {
|
| + struct sockaddr* addrs = nullptr;
|
| + int naddrs = usrsctp_getladdrs(sock, 0, &addrs);
|
| + if (naddrs <= 0 || addrs[0].sa_family != AF_CONN) {
|
| + return nullptr;
|
| + }
|
| + // usrsctp_getladdrs() returns the addresses bound to this socket, which
|
| + // contains the SctpDataMediaChannel* as sconn_addr. Read the pointer,
|
| + // then free the list of addresses once we have the pointer. We only open
|
| + // AF_CONN sockets, and they should all have the sconn_addr set to the
|
| + // pointer that created them, so [0] is as good as any other.
|
| + struct sockaddr_conn* sconn =
|
| + reinterpret_cast<struct sockaddr_conn*>(&addrs[0]);
|
| + SctpDataMediaChannel* channel =
|
| + reinterpret_cast<SctpDataMediaChannel*>(sconn->sconn_addr);
|
| + usrsctp_freeladdrs(addrs);
|
| +
|
| + return channel;
|
| +}
|
| +
|
| +// static
|
| +int SctpDataEngine::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.
|
| + SctpDataMediaChannel* channel = GetChannelFromSocket(sock);
|
| + if (!channel) {
|
| + LOG(LS_ERROR) << "SendThresholdCallback: Failed to get channel for socket "
|
| + << sock;
|
| + return 0;
|
| + }
|
| + channel->OnSendThresholdCallback();
|
| + return 0;
|
| +}
|
| +
|
| SctpDataMediaChannel::SctpDataMediaChannel(rtc::Thread* thread)
|
| : worker_thread_(thread),
|
| local_port_(kSctpDefaultPort),
|
| @@ -329,6 +376,11 @@ SctpDataMediaChannel::~SctpDataMediaChannel() {
|
| CloseSctpSocket();
|
| }
|
|
|
| +void SctpDataMediaChannel::OnSendThresholdCallback() {
|
| + DCHECK(rtc::Thread::Current() == worker_thread_);
|
| + SignalReadyToSend(true);
|
| +}
|
| +
|
| sockaddr_conn SctpDataMediaChannel::GetSctpSockAddr(int port) {
|
| sockaddr_conn sconn = {0};
|
| sconn.sconn_family = AF_CONN;
|
| @@ -347,8 +399,16 @@ bool SctpDataMediaChannel::OpenSctpSocket() {
|
| << "->Ignoring attempt to re-create existing socket.";
|
| return false;
|
| }
|
| +
|
| + // 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, NULL, 0, this);
|
| + cricket::OnSctpInboundPacket,
|
| + &SctpDataEngine::SendThresholdCallback,
|
| + kSendThreshold, this);
|
| if (!sock_) {
|
| LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket.";
|
| return false;
|
| @@ -393,7 +453,7 @@ bool SctpDataMediaChannel::OpenSctpSocket() {
|
| }
|
|
|
| // Disable MTU discovery
|
| - struct sctp_paddrparams params = {{0}};
|
| + sctp_paddrparams params = {{0}};
|
| params.spp_assoc_id = 0;
|
| params.spp_flags = SPP_PMTUD_DISABLE;
|
| params.spp_pathmtu = kSctpMtu;
|
| @@ -598,6 +658,7 @@ bool SctpDataMediaChannel::SendData(
|
| // Called by network interface when a packet has been received.
|
| void SctpDataMediaChannel::OnPacketReceived(
|
| rtc::Buffer* packet, const rtc::PacketTime& packet_time) {
|
| + DCHECK(rtc::Thread::Current() == worker_thread_);
|
| LOG(LS_VERBOSE) << debug_name_ << "->OnPacketReceived(...): "
|
| << " length=" << packet->size() << ", sending: " << sending_;
|
| // Only give receiving packets to usrsctp after if connected. This enables two
|
| @@ -608,7 +669,6 @@ void SctpDataMediaChannel::OnPacketReceived(
|
| // Pass received packet to SCTP stack. Once processed by usrsctp, the data
|
| // will be will be given to the global OnSctpInboundData, and then,
|
| // marshalled by a Post and handled with OnMessage.
|
| -
|
| VerboseLogPacket(packet->data(), packet->size(), SCTP_DUMP_INBOUND);
|
| usrsctp_conninput(this, packet->data(), packet->size(), 0);
|
| } else {
|
| @@ -904,10 +964,17 @@ bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) {
|
|
|
| void SctpDataMediaChannel::OnPacketFromSctpToNetwork(
|
| rtc::Buffer* buffer) {
|
| - if (buffer->size() > kSctpMtu) {
|
| + // usrsctp seems to interpret the MTU we give it strangely -- it seems to
|
| + // give us back packets bigger than that MTU, if only by a fixed amount.
|
| + // This is that amount that we've observed.
|
| + const int kSctpOverhead = 76;
|
| + if (buffer->size() > (kSctpOverhead + kSctpMtu)) {
|
| LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): "
|
| << "SCTP seems to have made a packet that is bigger "
|
| - "than its official MTU.";
|
| + << "than its official MTU: " << buffer->size()
|
| + << " vs max of " << kSctpMtu
|
| + << " even after adding " << kSctpOverhead
|
| + << " extra SCTP overhead";
|
| }
|
| MediaChannel::SendPacket(buffer);
|
| }
|
|
|