128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org/*
25f93d0a140515e3b8cdd1b9a4c6f5871144e5deejlmiller@webrtc.org * libjingle
35f93d0a140515e3b8cdd1b9a4c6f5871144e5deejlmiller@webrtc.org * Copyright 2012 Google Inc. and Robin Seggelmann
428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org *
528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org * Redistribution and use in source and binary forms, with or without
628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org * modification, are permitted provided that the following conditions are met:
728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org *
828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org *  1. Redistributions of source code must retain the above copyright notice,
928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org *     this list of conditions and the following disclaimer.
1028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org *  2. Redistributions in binary form must reproduce the above copyright notice,
1128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org *     this list of conditions and the following disclaimer in the documentation
1228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org *     and/or other materials provided with the distribution.
1328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org *  3. The name of the author may not be used to endorse or promote products
1428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org *     derived from this software without specific prior written permission.
1528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org *
1628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
1728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
1928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org */
2728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
2828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include "talk/media/sctp/sctpdataengine.h"
2928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
3028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include <stdarg.h>
3128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include <stdio.h>
32f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org#include <sstream>
3328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include <vector>
3428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
3528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include "talk/media/base/codec.h"
3628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include "talk/media/base/constants.h"
3728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include "talk/media/base/streamparams.h"
3828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include "usrsctplib/usrsctp.h"
395237aaf243d29732f59557361b7a993c0a18cf0etfarina#include "webrtc/base/arraysize.h"
40a09a99950ec40aef6421e4ba35eee7196b7a6e68buildbot@webrtc.org#include "webrtc/base/buffer.h"
41a09a99950ec40aef6421e4ba35eee7196b7a6e68buildbot@webrtc.org#include "webrtc/base/helpers.h"
42a09a99950ec40aef6421e4ba35eee7196b7a6e68buildbot@webrtc.org#include "webrtc/base/logging.h"
43a09a99950ec40aef6421e4ba35eee7196b7a6e68buildbot@webrtc.org#include "webrtc/base/safe_conversions.h"
4428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
45f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.orgnamespace {
46f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.orgtypedef cricket::SctpDataMediaChannel::StreamSet StreamSet;
47f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org// Returns a comma-separated, human-readable list of the stream IDs in 's'
48f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.orgstd::string ListStreams(const StreamSet& s) {
49f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  std::stringstream result;
50f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  bool first = true;
51e00265ed492c4d61f5ef04f9138739289bac6b98wu@webrtc.org  for (StreamSet::const_iterator it = s.begin(); it != s.end(); ++it) {
52f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    if (!first) {
53f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      result << ", " << *it;
54f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    } else {
55f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      result << *it;
56f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      first = false;
57f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    }
58f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  }
59f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  return result.str();
60f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org}
61f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
62f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org// Returns a pipe-separated, human-readable list of the SCTP_STREAM_RESET
63f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org// flags in 'flags'
64f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.orgstd::string ListFlags(int flags) {
65f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  std::stringstream result;
66f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  bool first = true;
67f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // Skip past the first 12 chars (strlen("SCTP_STREAM_"))
68f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org#define MAKEFLAG(X) { X, #X + 12}
69f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  struct flaginfo_t {
70f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    int value;
71f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    const char* name;
72f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  } flaginfo[] = {
73f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    MAKEFLAG(SCTP_STREAM_RESET_INCOMING_SSN),
74f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    MAKEFLAG(SCTP_STREAM_RESET_OUTGOING_SSN),
75f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    MAKEFLAG(SCTP_STREAM_RESET_DENIED),
76f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    MAKEFLAG(SCTP_STREAM_RESET_FAILED),
77f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    MAKEFLAG(SCTP_STREAM_CHANGE_DENIED)
78f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  };
79f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org#undef MAKEFLAG
805237aaf243d29732f59557361b7a993c0a18cf0etfarina  for (int i = 0; i < arraysize(flaginfo); ++i) {
81f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    if (flags & flaginfo[i].value) {
82f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      if (!first) result << " | ";
83f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      result << flaginfo[i].name;
84f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      first = false;
85f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    }
86f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  }
87f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  return result.str();
88f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org}
89f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
90f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org// Returns a comma-separated, human-readable list of the integers in 'array'.
91f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org// All 'num_elems' of them.
920c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boströmstd::string ListArray(const uint16_t* array, int num_elems) {
93f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  std::stringstream result;
94f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  for (int i = 0; i < num_elems; ++i) {
95f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    if (i) {
96f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      result << ", " << array[i];
97f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    } else {
98f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      result << array[i];
99f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    }
100f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  }
101f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  return result.str();
102f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org}
103f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org}  // namespace
104f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
10528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgnamespace cricket {
106d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.orgtypedef rtc::ScopedMessageData<SctpInboundPacket> InboundPacketMessage;
107d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.orgtypedef rtc::ScopedMessageData<rtc::Buffer> OutboundPacketMessage;
10828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
109624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.org// The biggest SCTP packet.  Starting from a 'safe' wire MTU value of 1280,
110624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.org// take off 80 bytes for DTLS/TURN/TCP/IP overhead.
111624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.orgstatic const size_t kSctpMtu = 1200;
11228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
113e8386d21992b6683b6fadd315ea631875b4256fbLally Singh// The size of the SCTP association send buffer.  256kB, the usrsctp default.
114e8386d21992b6683b6fadd315ea631875b4256fbLally Singhstatic const int kSendBufferSize = 262144;
11528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgenum {
11628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  MSG_SCTPINBOUNDPACKET = 1,   // MessageData is SctpInboundPacket
117d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org  MSG_SCTPOUTBOUNDPACKET = 2,  // MessageData is rtc:Buffer
11828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org};
11928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
12028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgstruct SctpInboundPacket {
121d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org  rtc::Buffer buffer;
12228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  ReceiveDataParams params;
12328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // The |flags| parameter is used by SCTP to distinguish notification packets
12428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // from other types of packets.
12528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  int flags;
12628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org};
12728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
1281112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org// Helper for logging SCTP messages.
12928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgstatic void debug_sctp_printf(const char *format, ...) {
13028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  char s[255];
13128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  va_list ap;
13228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  va_start(ap, format);
13328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  vsnprintf(s, sizeof(s), format, ap);
1341112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  LOG(LS_INFO) << "SCTP: " << s;
13528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  va_end(ap);
13628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
13728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
1381112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org// Get the PPID to use for the terminating fragment of this type.
1391112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.orgstatic SctpDataMediaChannel::PayloadProtocolIdentifier GetPpid(
1401112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    cricket::DataMessageType type) {
1411112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  switch (type) {
1421112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  default:
1431112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  case cricket::DMT_NONE:
1441112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    return SctpDataMediaChannel::PPID_NONE;
1451112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  case cricket::DMT_CONTROL:
1461112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    return SctpDataMediaChannel::PPID_CONTROL;
1471112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  case cricket::DMT_BINARY:
1481112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    return SctpDataMediaChannel::PPID_BINARY_LAST;
1491112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  case cricket::DMT_TEXT:
1501112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    return SctpDataMediaChannel::PPID_TEXT_LAST;
1511112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  };
1521112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org}
1531112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org
1541112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.orgstatic bool GetDataMediaType(
1551112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    SctpDataMediaChannel::PayloadProtocolIdentifier ppid,
1561112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    cricket::DataMessageType *dest) {
1571112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  ASSERT(dest != NULL);
1581112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  switch (ppid) {
1591112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    case SctpDataMediaChannel::PPID_BINARY_PARTIAL:
1601112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    case SctpDataMediaChannel::PPID_BINARY_LAST:
1611112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      *dest = cricket::DMT_BINARY;
1621112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      return true;
1631112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org
1641112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    case SctpDataMediaChannel::PPID_TEXT_PARTIAL:
1651112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    case SctpDataMediaChannel::PPID_TEXT_LAST:
1661112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      *dest = cricket::DMT_TEXT;
1671112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      return true;
1681112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org
1691112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    case SctpDataMediaChannel::PPID_CONTROL:
1701112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      *dest = cricket::DMT_CONTROL;
1711112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      return true;
1721112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org
1731112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    case SctpDataMediaChannel::PPID_NONE:
1741112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      *dest = cricket::DMT_NONE;
1751112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      return true;
1761112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org
1771112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    default:
1781112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      return false;
17928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
18028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
18128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
1824c277bb938854a6a174e8bfece0bc9a7928da1abLally Singh// Log the packet in text2pcap format, if log level is at LS_VERBOSE.
183e8386d21992b6683b6fadd315ea631875b4256fbLally Singhstatic void VerboseLogPacket(void *data, size_t length, int direction) {
1844c277bb938854a6a174e8bfece0bc9a7928da1abLally Singh  if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) {
1854c277bb938854a6a174e8bfece0bc9a7928da1abLally Singh    char *dump_buf;
1864c277bb938854a6a174e8bfece0bc9a7928da1abLally Singh    if ((dump_buf = usrsctp_dumppacket(
187e8386d21992b6683b6fadd315ea631875b4256fbLally Singh             data, length, direction)) != NULL) {
1884c277bb938854a6a174e8bfece0bc9a7928da1abLally Singh      LOG(LS_VERBOSE) << dump_buf;
1894c277bb938854a6a174e8bfece0bc9a7928da1abLally Singh      usrsctp_freedumpbuffer(dump_buf);
1904c277bb938854a6a174e8bfece0bc9a7928da1abLally Singh    }
1914c277bb938854a6a174e8bfece0bc9a7928da1abLally Singh  }
1924c277bb938854a6a174e8bfece0bc9a7928da1abLally Singh}
1934c277bb938854a6a174e8bfece0bc9a7928da1abLally Singh
19428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// This is the callback usrsctp uses when there's data to send on the network
19528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// that has been wrapped appropriatly for the SCTP protocol.
19628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgstatic int OnSctpOutboundPacket(void* addr, void* data, size_t length,
19728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                                uint8_t tos, uint8_t set_df) {
19828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(addr);
19928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  LOG(LS_VERBOSE) << "global OnSctpOutboundPacket():"
20028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                  << "addr: " << addr << "; length: " << length
20128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                  << "; tos: " << std::hex << static_cast<int>(tos)
2021112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org                  << "; set_df: " << std::hex << static_cast<int>(set_df);
2034c277bb938854a6a174e8bfece0bc9a7928da1abLally Singh
2044c277bb938854a6a174e8bfece0bc9a7928da1abLally Singh  VerboseLogPacket(addr, length, SCTP_DUMP_OUTBOUND);
20528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Note: We have to copy the data; the caller will delete it.
2069478437fdea4eb31b92ffe0c10368fe5bc9b9e16Karl Wiberg  auto* msg = new OutboundPacketMessage(
2079478437fdea4eb31b92ffe0c10368fe5bc9b9e16Karl Wiberg      new rtc::Buffer(reinterpret_cast<uint8_t*>(data), length));
208f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  channel->worker_thread()->Post(channel, MSG_SCTPOUTBOUNDPACKET, msg);
20928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return 0;
21028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
21128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
21228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// This is the callback called from usrsctp when data has been received, after
21328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// a packet has been interpreted and parsed by usrsctp and found to contain
21428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// payload data. It is called by a usrsctp thread. It is assumed this function
21528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// will free the memory used by 'data'.
21628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgstatic int OnSctpInboundPacket(struct socket* sock, union sctp_sockstore addr,
21728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                               void* data, size_t length,
21828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                               struct sctp_rcvinfo rcv, int flags,
21928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                               void* ulp_info) {
22028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(ulp_info);
22128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Post data to the channel's receiver thread (copying it).
22228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // TODO(ldixon): Unclear if copy is needed as this method is responsible for
22328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // memory cleanup. But this does simplify code.
2241112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  const SctpDataMediaChannel::PayloadProtocolIdentifier ppid =
2251112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      static_cast<SctpDataMediaChannel::PayloadProtocolIdentifier>(
226d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org          rtc::HostToNetwork32(rcv.rcv_ppid));
2271112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  cricket::DataMessageType type = cricket::DMT_NONE;
2281112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  if (!GetDataMediaType(ppid, &type) && !(flags & MSG_NOTIFICATION)) {
2291112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    // It's neither a notification nor a recognized data packet.  Drop it.
2301112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    LOG(LS_ERROR) << "Received an unknown PPID " << ppid
2311112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org                  << " on an SCTP packet.  Dropping.";
2321112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  } else {
2331112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    SctpInboundPacket* packet = new SctpInboundPacket;
2349478437fdea4eb31b92ffe0c10368fe5bc9b9e16Karl Wiberg    packet->buffer.SetData(reinterpret_cast<uint8_t*>(data), length);
2351112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    packet->params.ssrc = rcv.rcv_sid;
2361112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    packet->params.seq_num = rcv.rcv_ssn;
2371112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    packet->params.timestamp = rcv.rcv_tsn;
2381112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    packet->params.type = type;
2391112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    packet->flags = flags;
240f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    // The ownership of |packet| transfers to |msg|.
241f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    InboundPacketMessage* msg = new InboundPacketMessage(packet);
242f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    channel->worker_thread()->Post(channel, MSG_SCTPINBOUNDPACKET, msg);
2431112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  }
24428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  free(data);
24528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return 1;
24628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
24728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
24828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// Set the initial value of the static SCTP Data Engines reference count.
24928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgint SctpDataEngine::usrsctp_engines_count = 0;
25028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
2510de29504ab7ac923401c8e4e154f3b72038dbcc2wu@webrtc.orgSctpDataEngine::SctpDataEngine() {
25228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (usrsctp_engines_count == 0) {
25328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // First argument is udp_encapsulation_port, which is not releveant for our
25428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // AF_CONN use of sctp.
25528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    usrsctp_init(0, cricket::OnSctpOutboundPacket, debug_sctp_printf);
25628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
25728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // To turn on/off detailed SCTP debugging. You will also need to have the
25828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // SCTP_DEBUG cpp defines flag.
25928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
26028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
26128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // TODO(ldixon): Consider turning this on/off.
26228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    usrsctp_sysctl_set_sctp_ecn_enable(0);
26328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
264e8386d21992b6683b6fadd315ea631875b4256fbLally Singh    // This is harmless, but we should find out when the library default
265e8386d21992b6683b6fadd315ea631875b4256fbLally Singh    // changes.
266e8386d21992b6683b6fadd315ea631875b4256fbLally Singh    int send_size = usrsctp_sysctl_get_sctp_sendspace();
267e8386d21992b6683b6fadd315ea631875b4256fbLally Singh    if (send_size != kSendBufferSize) {
268e8386d21992b6683b6fadd315ea631875b4256fbLally Singh      LOG(LS_ERROR) << "Got different send size than expected: " << send_size;
269e8386d21992b6683b6fadd315ea631875b4256fbLally Singh    }
270e8386d21992b6683b6fadd315ea631875b4256fbLally Singh
27128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // TODO(ldixon): Consider turning this on/off.
27228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // This is not needed right now (we don't do dynamic address changes):
27328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // If SCTP Auto-ASCONF is enabled, the peer is informed automatically
27428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // when a new address is added or removed. This feature is enabled by
27528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // default.
27628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // usrsctp_sysctl_set_sctp_auto_asconf(0);
27728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
27828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // TODO(ldixon): Consider turning this on/off.
27928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // Add a blackhole sysctl. Setting it to 1 results in no ABORTs
28028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // being sent in response to INITs, setting it to 2 results
28128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // in no ABORTs being sent for received OOTB packets.
28228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // This is similar to the TCP sysctl.
28328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    //
28428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // See: http://lakerest.net/pipermail/sctp-coders/2012-January/009438.html
28528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // See: http://svnweb.freebsd.org/base?view=revision&revision=229805
28628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // usrsctp_sysctl_set_sctp_blackhole(2);
2871112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org
2881112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    // Set the number of default outgoing streams.  This is the number we'll
2891112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    // send in the SCTP INIT message.  The 'appropriate default' in the
2901112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    // second paragraph of
2911112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    // http://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-05#section-6.2
2921112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    // is cricket::kMaxSctpSid.
2931112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    usrsctp_sysctl_set_sctp_nr_outgoing_streams_default(
2941112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org        cricket::kMaxSctpSid);
29528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
29628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  usrsctp_engines_count++;
29728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
2989c16c39e613ebc5cdfa8ca5818a62ef5c3b18bd7jiayl@webrtc.org  cricket::DataCodec codec(kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, 0);
2999c16c39e613ebc5cdfa8ca5818a62ef5c3b18bd7jiayl@webrtc.org  codec.SetParam(kCodecParamPort, kSctpDefaultPort);
3009c16c39e613ebc5cdfa8ca5818a62ef5c3b18bd7jiayl@webrtc.org  codecs_.push_back(codec);
30128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
30228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
30328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgSctpDataEngine::~SctpDataEngine() {
304f8063d34deefb55b4a0e5091fc59d5d5e58e43d8jiayl@webrtc.org  usrsctp_engines_count--;
305f8063d34deefb55b4a0e5091fc59d5d5e58e43d8jiayl@webrtc.org  LOG(LS_VERBOSE) << "usrsctp_engines_count:" << usrsctp_engines_count;
306f8063d34deefb55b4a0e5091fc59d5d5e58e43d8jiayl@webrtc.org
307f8063d34deefb55b4a0e5091fc59d5d5e58e43d8jiayl@webrtc.org  if (usrsctp_engines_count == 0) {
308f8063d34deefb55b4a0e5091fc59d5d5e58e43d8jiayl@webrtc.org    // usrsctp_finish() may fail if it's called too soon after the channels are
309f8063d34deefb55b4a0e5091fc59d5d5e58e43d8jiayl@webrtc.org    // closed. Wait and try again until it succeeds for up to 3 seconds.
310f8063d34deefb55b4a0e5091fc59d5d5e58e43d8jiayl@webrtc.org    for (size_t i = 0; i < 300; ++i) {
311f8063d34deefb55b4a0e5091fc59d5d5e58e43d8jiayl@webrtc.org      if (usrsctp_finish() == 0)
312f8063d34deefb55b4a0e5091fc59d5d5e58e43d8jiayl@webrtc.org        return;
313f8063d34deefb55b4a0e5091fc59d5d5e58e43d8jiayl@webrtc.org
314d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org      rtc::Thread::SleepMs(10);
315f8063d34deefb55b4a0e5091fc59d5d5e58e43d8jiayl@webrtc.org    }
316f8063d34deefb55b4a0e5091fc59d5d5e58e43d8jiayl@webrtc.org    LOG(LS_ERROR) << "Failed to shutdown usrsctp.";
317f8063d34deefb55b4a0e5091fc59d5d5e58e43d8jiayl@webrtc.org  }
31828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
31928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
32028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgDataMediaChannel* SctpDataEngine::CreateChannel(
32128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    DataChannelType data_channel_type) {
32228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (data_channel_type != DCT_SCTP) {
32328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return NULL;
32428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
3257391881f9762ccadeeb0249560b33cf2bcfaf7f9tommi  return new SctpDataMediaChannel(rtc::Thread::Current());
32628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
32728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
328e8386d21992b6683b6fadd315ea631875b4256fbLally Singh// static
329e8386d21992b6683b6fadd315ea631875b4256fbLally SinghSctpDataMediaChannel* SctpDataEngine::GetChannelFromSocket(
330e8386d21992b6683b6fadd315ea631875b4256fbLally Singh    struct socket* sock) {
331e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  struct sockaddr* addrs = nullptr;
332e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  int naddrs = usrsctp_getladdrs(sock, 0, &addrs);
333e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  if (naddrs <= 0 || addrs[0].sa_family != AF_CONN) {
334e8386d21992b6683b6fadd315ea631875b4256fbLally Singh    return nullptr;
335e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  }
336e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // usrsctp_getladdrs() returns the addresses bound to this socket, which
337e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // contains the SctpDataMediaChannel* as sconn_addr.  Read the pointer,
338e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // then free the list of addresses once we have the pointer.  We only open
339e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // AF_CONN sockets, and they should all have the sconn_addr set to the
340e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // pointer that created them, so [0] is as good as any other.
341e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  struct sockaddr_conn* sconn =
342e8386d21992b6683b6fadd315ea631875b4256fbLally Singh      reinterpret_cast<struct sockaddr_conn*>(&addrs[0]);
343e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  SctpDataMediaChannel* channel =
344e8386d21992b6683b6fadd315ea631875b4256fbLally Singh      reinterpret_cast<SctpDataMediaChannel*>(sconn->sconn_addr);
345e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  usrsctp_freeladdrs(addrs);
346e8386d21992b6683b6fadd315ea631875b4256fbLally Singh
347e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  return channel;
348e8386d21992b6683b6fadd315ea631875b4256fbLally Singh}
349e8386d21992b6683b6fadd315ea631875b4256fbLally Singh
350e8386d21992b6683b6fadd315ea631875b4256fbLally Singh// static
351e8386d21992b6683b6fadd315ea631875b4256fbLally Singhint SctpDataEngine::SendThresholdCallback(struct socket* sock,
352e8386d21992b6683b6fadd315ea631875b4256fbLally Singh                                          uint32_t sb_free) {
353e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // Fired on our I/O thread.  SctpDataMediaChannel::OnPacketReceived() gets
354e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // a packet containing acknowledgments, which goes into usrsctp_conninput,
355e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // and then back here.
356e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  SctpDataMediaChannel* channel = GetChannelFromSocket(sock);
357e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  if (!channel) {
358e8386d21992b6683b6fadd315ea631875b4256fbLally Singh    LOG(LS_ERROR) << "SendThresholdCallback: Failed to get channel for socket "
359e8386d21992b6683b6fadd315ea631875b4256fbLally Singh                  << sock;
360e8386d21992b6683b6fadd315ea631875b4256fbLally Singh    return 0;
361e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  }
362e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  channel->OnSendThresholdCallback();
363e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  return 0;
364e8386d21992b6683b6fadd315ea631875b4256fbLally Singh}
365e8386d21992b6683b6fadd315ea631875b4256fbLally Singh
366d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.orgSctpDataMediaChannel::SctpDataMediaChannel(rtc::Thread* thread)
36728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    : worker_thread_(thread),
3689c16c39e613ebc5cdfa8ca5818a62ef5c3b18bd7jiayl@webrtc.org      local_port_(kSctpDefaultPort),
3699c16c39e613ebc5cdfa8ca5818a62ef5c3b18bd7jiayl@webrtc.org      remote_port_(kSctpDefaultPort),
37028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      sock_(NULL),
37128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      sending_(false),
37228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      receiving_(false),
37328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      debug_name_("SctpDataMediaChannel") {
37428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
37528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
37628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgSctpDataMediaChannel::~SctpDataMediaChannel() {
37728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  CloseSctpSocket();
37828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
37928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
380e8386d21992b6683b6fadd315ea631875b4256fbLally Singhvoid SctpDataMediaChannel::OnSendThresholdCallback() {
38191d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(rtc::Thread::Current() == worker_thread_);
382e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  SignalReadyToSend(true);
383e8386d21992b6683b6fadd315ea631875b4256fbLally Singh}
384e8386d21992b6683b6fadd315ea631875b4256fbLally Singh
38528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgsockaddr_conn SctpDataMediaChannel::GetSctpSockAddr(int port) {
38628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  sockaddr_conn sconn = {0};
38728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  sconn.sconn_family = AF_CONN;
38828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#ifdef HAVE_SCONN_LEN
38928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  sconn.sconn_len = sizeof(sockaddr_conn);
39028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#endif
39128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Note: conversion from int to uint16_t happens here.
392d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org  sconn.sconn_port = rtc::HostToNetwork16(port);
39328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  sconn.sconn_addr = this;
39428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return sconn;
39528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
39628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
39728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgbool SctpDataMediaChannel::OpenSctpSocket() {
39828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (sock_) {
39928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_VERBOSE) << debug_name_
40028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                    << "->Ignoring attempt to re-create existing socket.";
40128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
40228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
403e8386d21992b6683b6fadd315ea631875b4256fbLally Singh
404e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // If kSendBufferSize isn't reflective of reality, we log an error, but we
405e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // still have to do something reasonable here.  Look up what the buffer's
406e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // real size is and set our threshold to something reasonable.
407e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  const static int kSendThreshold = usrsctp_sysctl_get_sctp_sendspace() / 2;
408e8386d21992b6683b6fadd315ea631875b4256fbLally Singh
40928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP,
410e8386d21992b6683b6fadd315ea631875b4256fbLally Singh                         cricket::OnSctpInboundPacket,
411e8386d21992b6683b6fadd315ea631875b4256fbLally Singh                         &SctpDataEngine::SendThresholdCallback,
412e8386d21992b6683b6fadd315ea631875b4256fbLally Singh                         kSendThreshold, this);
41328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!sock_) {
41428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket.";
41528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
41628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
41728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
41828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Make the socket non-blocking. Connect, close, shutdown etc will not block
41928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // the thread waiting for the socket operation to complete.
42028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (usrsctp_set_non_blocking(sock_, 1) < 0) {
42128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking.";
42228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
42328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
42428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
42528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // This ensures that the usrsctp close call deletes the association. This
42628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // prevents usrsctp from calling OnSctpOutboundPacket with references to
42728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // this class as the address.
42828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  linger linger_opt;
42928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  linger_opt.l_onoff = 1;
43028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  linger_opt.l_linger = 0;
43128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (usrsctp_setsockopt(sock_, SOL_SOCKET, SO_LINGER, &linger_opt,
43228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                         sizeof(linger_opt))) {
43328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SO_LINGER.";
43428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
43528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
43628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
437f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // Enable stream ID resets.
438f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  struct sctp_assoc_value stream_rst;
439f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  stream_rst.assoc_id = SCTP_ALL_ASSOC;
440f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  stream_rst.assoc_value = 1;
441f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET,
442f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                         &stream_rst, sizeof(stream_rst))) {
443f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_
444f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                        << "Failed to set SCTP_ENABLE_STREAM_RESET.";
445f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    return false;
446f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  }
447f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
448f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // Nagle.
449a59696b2a5f0c138d4176249bac223ad6c4316d5sergeyu@chromium.org  uint32_t nodelay = 1;
450a59696b2a5f0c138d4176249bac223ad6c4316d5sergeyu@chromium.org  if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay,
451a59696b2a5f0c138d4176249bac223ad6c4316d5sergeyu@chromium.org                         sizeof(nodelay))) {
452a59696b2a5f0c138d4176249bac223ad6c4316d5sergeyu@chromium.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_NODELAY.";
453a59696b2a5f0c138d4176249bac223ad6c4316d5sergeyu@chromium.org    return false;
454a59696b2a5f0c138d4176249bac223ad6c4316d5sergeyu@chromium.org  }
455a59696b2a5f0c138d4176249bac223ad6c4316d5sergeyu@chromium.org
456624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.org  // Disable MTU discovery
457e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  sctp_paddrparams params = {{0}};
458624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.org  params.spp_assoc_id = 0;
459624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.org  params.spp_flags = SPP_PMTUD_DISABLE;
460624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.org  params.spp_pathmtu = kSctpMtu;
461624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.org  if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &params,
462624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.org      sizeof(params))) {
463624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_
464624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.org                        << "Failed to set SCTP_PEER_ADDR_PARAMS.";
465624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.org    return false;
466624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.org  }
467624a504f5ba0c2ca2a9a138e6d3ed1c1937b8df4buildbot@webrtc.org
46828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Subscribe to SCTP event notifications.
46928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  int event_types[] = {SCTP_ASSOC_CHANGE,
47028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                       SCTP_PEER_ADDR_CHANGE,
471d64719d8954262fee94e7615422f3d027dc1ae6bwu@webrtc.org                       SCTP_SEND_FAILED_EVENT,
472f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                       SCTP_SENDER_DRY_EVENT,
473f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                       SCTP_STREAM_RESET_EVENT};
47428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  struct sctp_event event = {0};
47528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  event.se_assoc_id = SCTP_ALL_ASSOC;
47628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  event.se_on = 1;
4775237aaf243d29732f59557361b7a993c0a18cf0etfarina  for (size_t i = 0; i < arraysize(event_types); i++) {
47828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    event.se_type = event_types[i];
47928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_EVENT, &event,
48028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                           sizeof(event)) < 0) {
48128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_EVENT type: "
48228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                          << event.se_type;
48328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      return false;
48428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    }
48528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
48628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
48728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Register this class as an address for usrsctp. This is used by SCTP to
48828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // direct the packets received (by the created socket) to this class.
48928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  usrsctp_register_address(this);
49028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  sending_ = true;
49128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return true;
49228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
49328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
49428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgvoid SctpDataMediaChannel::CloseSctpSocket() {
49528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  sending_ = false;
49628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (sock_) {
49728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // We assume that SO_LINGER option is set to close the association when
49828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // close is called. This means that any pending packets in usrsctp will be
49928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // discarded instead of being sent.
50028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    usrsctp_close(sock_);
50128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    sock_ = NULL;
50228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    usrsctp_deregister_address(this);
50328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
50428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
50528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
50628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgbool SctpDataMediaChannel::Connect() {
50728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  LOG(LS_VERBOSE) << debug_name_ << "->Connect().";
50828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
50928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // If we already have a socket connection, just return.
51028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (sock_) {
51128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_WARNING) << debug_name_ << "->Connect(): Ignored as socket "
51228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                                      "is already established.";
51328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return true;
51428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
51528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
51628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // If no socket (it was closed) try to start it again. This can happen when
51728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // the socket we are connecting to closes, does an sctp shutdown handshake,
51828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // or behaves unexpectedly causing us to perform a CloseSctpSocket.
51928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!sock_ && !OpenSctpSocket()) {
52028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
52128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
52228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
52328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Note: conversion from int to uint16_t happens on assignment.
52428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  sockaddr_conn local_sconn = GetSctpSockAddr(local_port_);
52528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (usrsctp_bind(sock_, reinterpret_cast<sockaddr *>(&local_sconn),
52628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                   sizeof(local_sconn)) < 0) {
52728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "->Connect(): "
52828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                        << ("Failed usrsctp_bind");
52928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    CloseSctpSocket();
53028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
53128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
53228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
53328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Note: conversion from int to uint16_t happens on assignment.
53428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  sockaddr_conn remote_sconn = GetSctpSockAddr(remote_port_);
53528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  int connect_result = usrsctp_connect(
53628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      sock_, reinterpret_cast<sockaddr *>(&remote_sconn), sizeof(remote_sconn));
53728654cbc2256230c978f41cbaf550bc2e9c2f2dbhenrike@webrtc.org  if (connect_result < 0 && errno != SCTP_EINPROGRESS) {
53828654cbc2256230c978f41cbaf550bc2e9c2f2dbhenrike@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed usrsctp_connect. got errno="
53928654cbc2256230c978f41cbaf550bc2e9c2f2dbhenrike@webrtc.org                        << errno << ", but wanted " << SCTP_EINPROGRESS;
54028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    CloseSctpSocket();
54128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
54228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
54328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return true;
54428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
54528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
54628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgvoid SctpDataMediaChannel::Disconnect() {
54728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // TODO(ldixon): Consider calling |usrsctp_shutdown(sock_, ...)| to do a
54828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // shutdown handshake and remove the association.
54928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  CloseSctpSocket();
55028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
55128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
55228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgbool SctpDataMediaChannel::SetSend(bool send) {
55328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!sending_ && send) {
55428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return Connect();
55528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
55628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (sending_ && !send) {
55728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    Disconnect();
55828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
55928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return true;
56028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
56128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
56228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgbool SctpDataMediaChannel::SetReceive(bool receive) {
56328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  receiving_ = receive;
56428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return true;
56528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
56628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
567b071a19019a0a2173cc139c960d6ef6946a1c581Fredrik Solenbergbool SctpDataMediaChannel::SetSendParameters(const DataSendParameters& params) {
568b071a19019a0a2173cc139c960d6ef6946a1c581Fredrik Solenberg  return SetSendCodecs(params.codecs);
569b071a19019a0a2173cc139c960d6ef6946a1c581Fredrik Solenberg}
570b071a19019a0a2173cc139c960d6ef6946a1c581Fredrik Solenberg
571b071a19019a0a2173cc139c960d6ef6946a1c581Fredrik Solenbergbool SctpDataMediaChannel::SetRecvParameters(const DataRecvParameters& params) {
572b071a19019a0a2173cc139c960d6ef6946a1c581Fredrik Solenberg  return SetRecvCodecs(params.codecs);
573b071a19019a0a2173cc139c960d6ef6946a1c581Fredrik Solenberg}
574b071a19019a0a2173cc139c960d6ef6946a1c581Fredrik Solenberg
57528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgbool SctpDataMediaChannel::AddSendStream(const StreamParams& stream) {
576f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  return AddStream(stream);
57728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
57828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
5790c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boströmbool SctpDataMediaChannel::RemoveSendStream(uint32_t ssrc) {
580f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  return ResetStream(ssrc);
58128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
58228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
58328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgbool SctpDataMediaChannel::AddRecvStream(const StreamParams& stream) {
584aebb1ade9d760841f243e380fa22b7ecff2d3ecchenrika@webrtc.org  // SCTP DataChannels are always bi-directional and calling AddSendStream will
585aebb1ade9d760841f243e380fa22b7ecff2d3ecchenrika@webrtc.org  // enable both sending and receiving on the stream. So AddRecvStream is a
586aebb1ade9d760841f243e380fa22b7ecff2d3ecchenrika@webrtc.org  // no-op.
587aebb1ade9d760841f243e380fa22b7ecff2d3ecchenrika@webrtc.org  return true;
58828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
58928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
5900c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boströmbool SctpDataMediaChannel::RemoveRecvStream(uint32_t ssrc) {
591aebb1ade9d760841f243e380fa22b7ecff2d3ecchenrika@webrtc.org  // SCTP DataChannels are always bi-directional and calling RemoveSendStream
592aebb1ade9d760841f243e380fa22b7ecff2d3ecchenrika@webrtc.org  // will disable both sending and receiving on the stream. So RemoveRecvStream
593aebb1ade9d760841f243e380fa22b7ecff2d3ecchenrika@webrtc.org  // is a no-op.
594aebb1ade9d760841f243e380fa22b7ecff2d3ecchenrika@webrtc.org  return true;
59528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
59628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
59728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgbool SctpDataMediaChannel::SendData(
59828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    const SendDataParams& params,
599d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org    const rtc::Buffer& payload,
60028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    SendDataResult* result) {
60128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (result) {
6021112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    // Preset |result| to assume an error.  If SendData succeeds, we'll
6031112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    // overwrite |*result| once more at the end.
60428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    *result = SDR_ERROR;
60528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
60628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
60728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!sending_) {
60828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_WARNING) << debug_name_ << "->SendData(...): "
60928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                    << "Not sending packet with ssrc=" << params.ssrc
610eebcab5ce99d3e8641dd92a569916b0d24e29fcakwiberg@webrtc.org                    << " len=" << payload.size() << " before SetSend(true).";
61128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
61228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
61328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
61491053e7c5a743f4a92f5079844b0747c927f3bbdwu@webrtc.org  if (params.type != cricket::DMT_CONTROL &&
615f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      open_streams_.find(params.ssrc) == open_streams_.end()) {
61628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_WARNING) << debug_name_ << "->SendData(...): "
61728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                    << "Not sending data because ssrc is unknown: "
61828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                    << params.ssrc;
61928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
62028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
62128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
62228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  //
62328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Send data using SCTP.
6241112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  ssize_t send_res = 0;  // result from usrsctp_sendv.
6251112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  struct sctp_sendv_spa spa = {0};
6261112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  spa.sendv_flags |= SCTP_SEND_SNDINFO_VALID;
6271112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  spa.sendv_sndinfo.snd_sid = params.ssrc;
628d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org  spa.sendv_sndinfo.snd_ppid = rtc::HostToNetwork32(
6291112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      GetPpid(params.type));
6301112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org
6311112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  // Ordered implies reliable.
6321112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  if (!params.ordered) {
6331112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    spa.sendv_sndinfo.snd_flags |= SCTP_UNORDERED;
6341112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    if (params.max_rtx_count >= 0 || params.max_rtx_ms == 0) {
6351112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
6361112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
6371112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      spa.sendv_prinfo.pr_value = params.max_rtx_count;
6381112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    } else {
6391112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
6401112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL;
6411112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org      spa.sendv_prinfo.pr_value = params.max_rtx_ms;
6421112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    }
6431112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  }
6441112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org
6451112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  // We don't fragment.
646eebcab5ce99d3e8641dd92a569916b0d24e29fcakwiberg@webrtc.org  send_res = usrsctp_sendv(
647eebcab5ce99d3e8641dd92a569916b0d24e29fcakwiberg@webrtc.org      sock_, payload.data(), static_cast<size_t>(payload.size()), NULL, 0, &spa,
648eebcab5ce99d3e8641dd92a569916b0d24e29fcakwiberg@webrtc.org      rtc::checked_cast<socklen_t>(sizeof(spa)), SCTP_SENDV_SPA, 0);
6491112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org  if (send_res < 0) {
650f7026cd7c84b7c10894972ba03d8d7b9c04a99f0jiayl@webrtc.org    if (errno == SCTP_EWOULDBLOCK) {
651d64719d8954262fee94e7615422f3d027dc1ae6bwu@webrtc.org      *result = SDR_BLOCK;
652d64719d8954262fee94e7615422f3d027dc1ae6bwu@webrtc.org      LOG(LS_INFO) << debug_name_ << "->SendData(...): EWOULDBLOCK returned";
653d64719d8954262fee94e7615422f3d027dc1ae6bwu@webrtc.org    } else {
654d64719d8954262fee94e7615422f3d027dc1ae6bwu@webrtc.org      LOG_ERRNO(LS_ERROR) << "ERROR:" << debug_name_
655d64719d8954262fee94e7615422f3d027dc1ae6bwu@webrtc.org                          << "->SendData(...): "
656d64719d8954262fee94e7615422f3d027dc1ae6bwu@webrtc.org                          << " usrsctp_sendv: ";
657d64719d8954262fee94e7615422f3d027dc1ae6bwu@webrtc.org    }
65828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
65928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
66028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (result) {
6611112c30e1e5f5c7b4b517c4954ef3f15b989a996mallinath@webrtc.org    // Only way out now is success.
66228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    *result = SDR_SUCCESS;
66328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
66428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return true;
66528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
66628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
66728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// Called by network interface when a packet has been received.
668a9890800e078105f21f0a21358ee59a0b3736af6wu@webrtc.orgvoid SctpDataMediaChannel::OnPacketReceived(
669d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org    rtc::Buffer* packet, const rtc::PacketTime& packet_time) {
67091d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(rtc::Thread::Current() == worker_thread_);
671eebcab5ce99d3e8641dd92a569916b0d24e29fcakwiberg@webrtc.org  LOG(LS_VERBOSE) << debug_name_ << "->OnPacketReceived(...): "
672eebcab5ce99d3e8641dd92a569916b0d24e29fcakwiberg@webrtc.org                  << " length=" << packet->size() << ", sending: " << sending_;
67328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Only give receiving packets to usrsctp after if connected. This enables two
67428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // peers to each make a connect call, but for them not to receive an INIT
67528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // packet before they have called connect; least the last receiver of the INIT
67628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // packet will have called connect, and a connection will be established.
67728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (sending_) {
67828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // Pass received packet to SCTP stack. Once processed by usrsctp, the data
67928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // will be will be given to the global OnSctpInboundData, and then,
68028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // marshalled by a Post and handled with OnMessage.
6814c277bb938854a6a174e8bfece0bc9a7928da1abLally Singh    VerboseLogPacket(packet->data(), packet->size(), SCTP_DUMP_INBOUND);
682eebcab5ce99d3e8641dd92a569916b0d24e29fcakwiberg@webrtc.org    usrsctp_conninput(this, packet->data(), packet->size(), 0);
68328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  } else {
68428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // TODO(ldixon): Consider caching the packet for very slightly better
68528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // reliability.
68628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
68728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
68828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
68928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgvoid SctpDataMediaChannel::OnInboundPacketFromSctpToChannel(
69028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    SctpInboundPacket* packet) {
69128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  LOG(LS_VERBOSE) << debug_name_ << "->OnInboundPacketFromSctpToChannel(...): "
69228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                  << "Received SCTP data:"
69328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                  << " ssrc=" << packet->params.ssrc
69428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                  << " notification: " << (packet->flags & MSG_NOTIFICATION)
695eebcab5ce99d3e8641dd92a569916b0d24e29fcakwiberg@webrtc.org                  << " length=" << packet->buffer.size();
69628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Sending a packet with data == NULL (no data) is SCTPs "close the
69728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // connection" message. This sets sock_ = NULL;
698eebcab5ce99d3e8641dd92a569916b0d24e29fcakwiberg@webrtc.org  if (!packet->buffer.size() || !packet->buffer.data()) {
69928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_INFO) << debug_name_ << "->OnInboundPacketFromSctpToChannel(...): "
70028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                                   "No data, closing.";
70128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return;
70228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
70328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (packet->flags & MSG_NOTIFICATION) {
70428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    OnNotificationFromSctp(&packet->buffer);
70528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  } else {
70628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    OnDataFromSctpToChannel(packet->params, &packet->buffer);
70728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
70828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
70928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
71028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgvoid SctpDataMediaChannel::OnDataFromSctpToChannel(
711d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org    const ReceiveDataParams& params, rtc::Buffer* buffer) {
71228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (receiving_) {
71328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_VERBOSE) << debug_name_ << "->OnDataFromSctpToChannel(...): "
714eebcab5ce99d3e8641dd92a569916b0d24e29fcakwiberg@webrtc.org                    << "Posting with length: " << buffer->size()
715aebb1ade9d760841f243e380fa22b7ecff2d3ecchenrika@webrtc.org                    << " on stream " << params.ssrc;
716aebb1ade9d760841f243e380fa22b7ecff2d3ecchenrika@webrtc.org    // Reports all received messages to upper layers, no matter whether the sid
717aebb1ade9d760841f243e380fa22b7ecff2d3ecchenrika@webrtc.org    // is known.
7189478437fdea4eb31b92ffe0c10368fe5bc9b9e16Karl Wiberg    SignalDataReceived(params, buffer->data<char>(), buffer->size());
71928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  } else {
72028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_WARNING) << debug_name_ << "->OnDataFromSctpToChannel(...): "
72128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                    << "Not receiving packet with sid=" << params.ssrc
722eebcab5ce99d3e8641dd92a569916b0d24e29fcakwiberg@webrtc.org                    << " len=" << buffer->size() << " before SetReceive(true).";
72328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
72428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
72528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
726f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.orgbool SctpDataMediaChannel::AddStream(const StreamParams& stream) {
727f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  if (!stream.has_ssrcs()) {
728f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    return false;
729f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  }
730f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
7310c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  const uint32_t ssrc = stream.first_ssrc();
73227ed3cc28cf950456a0c66d7a10656a96832feddlally  if (ssrc >= cricket::kMaxSctpSid) {
73327ed3cc28cf950456a0c66d7a10656a96832feddlally    LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
73427ed3cc28cf950456a0c66d7a10656a96832feddlally                    << "Not adding data stream '" << stream.id
73527ed3cc28cf950456a0c66d7a10656a96832feddlally                    << "' with ssrc=" << ssrc
73627ed3cc28cf950456a0c66d7a10656a96832feddlally                    << " because stream ssrc is too high.";
73727ed3cc28cf950456a0c66d7a10656a96832feddlally    return false;
73827ed3cc28cf950456a0c66d7a10656a96832feddlally  } else if (open_streams_.find(ssrc) != open_streams_.end()) {
739aebb1ade9d760841f243e380fa22b7ecff2d3ecchenrika@webrtc.org    LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
740f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                    << "Not adding data stream '" << stream.id
741f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                    << "' with ssrc=" << ssrc
742f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                    << " because stream is already open.";
743f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    return false;
744f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  } else if (queued_reset_streams_.find(ssrc) != queued_reset_streams_.end()
745f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org             || sent_reset_streams_.find(ssrc) != sent_reset_streams_.end()) {
746f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
747f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                    << "Not adding data stream '" << stream.id
748f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                    << "' with ssrc=" << ssrc
749f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                    << " because stream is still closing.";
750f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    return false;
751f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  }
752f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
753f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  open_streams_.insert(ssrc);
754f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  return true;
755f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org}
756f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
7570c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boströmbool SctpDataMediaChannel::ResetStream(uint32_t ssrc) {
758f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // We typically get this called twice for the same stream, once each for
759f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // Send and Recv.
760f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  StreamSet::iterator found = open_streams_.find(ssrc);
761f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
762f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  if (found == open_streams_.end()) {
763f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    LOG(LS_VERBOSE) << debug_name_ << "->ResetStream(" << ssrc << "): "
764f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                    << "stream not found.";
765f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    return false;
766f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  } else {
767f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    LOG(LS_VERBOSE) << debug_name_ << "->ResetStream(" << ssrc << "): "
768f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                    << "Removing and queuing RE-CONFIG chunk.";
769f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    open_streams_.erase(found);
770f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  }
771f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
772f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // SCTP won't let you have more than one stream reset pending at a time, but
773f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // you can close multiple streams in a single reset.  So, we keep an internal
774f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // queue of streams-to-reset, and send them as one reset message in
775f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // SendQueuedStreamResets().
776f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  queued_reset_streams_.insert(ssrc);
777f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
778f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // Signal our stream-reset logic that it should try to send now, if it can.
779f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  SendQueuedStreamResets();
780f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
781f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // The stream will actually get removed when we get the acknowledgment.
782f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  return true;
783f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org}
784f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
785d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.orgvoid SctpDataMediaChannel::OnNotificationFromSctp(rtc::Buffer* buffer) {
78628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  const sctp_notification& notification =
78728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      reinterpret_cast<const sctp_notification&>(*buffer->data());
788eebcab5ce99d3e8641dd92a569916b0d24e29fcakwiberg@webrtc.org  ASSERT(notification.sn_header.sn_length == buffer->size());
78928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
79028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // TODO(ldixon): handle notifications appropriately.
79128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  switch (notification.sn_header.sn_type) {
79228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_ASSOC_CHANGE:
79328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_VERBOSE) << "SCTP_ASSOC_CHANGE";
79428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      OnNotificationAssocChange(notification.sn_assoc_change);
79528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
79628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_REMOTE_ERROR:
79728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_REMOTE_ERROR";
79828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
79928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_SHUTDOWN_EVENT:
80028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_SHUTDOWN_EVENT";
80128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
80228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_ADAPTATION_INDICATION:
803f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      LOG(LS_INFO) << "SCTP_ADAPTATION_INDICATION";
80428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
80528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_PARTIAL_DELIVERY_EVENT:
80628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_PARTIAL_DELIVERY_EVENT";
80728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
80828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_AUTHENTICATION_EVENT:
80928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_AUTHENTICATION_EVENT";
81028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
81128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_SENDER_DRY_EVENT:
812f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      LOG(LS_VERBOSE) << "SCTP_SENDER_DRY_EVENT";
813d64719d8954262fee94e7615422f3d027dc1ae6bwu@webrtc.org      SignalReadyToSend(true);
81428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
81528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // TODO(ldixon): Unblock after congestion.
81628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_NOTIFICATIONS_STOPPED_EVENT:
81728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_NOTIFICATIONS_STOPPED_EVENT";
81828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
81928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_SEND_FAILED_EVENT:
82028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_SEND_FAILED_EVENT";
82128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
82228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_STREAM_RESET_EVENT:
823f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      OnStreamResetEvent(&notification.sn_strreset_event);
82428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
82528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_ASSOC_RESET_EVENT:
82628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_ASSOC_RESET_EVENT";
82728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
82828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_STREAM_CHANGE_EVENT:
82928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_STREAM_CHANGE_EVENT";
830f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      // An acknowledgment we get after our stream resets have gone through,
831f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      // if they've failed.  We log the message, but don't react -- we don't
832f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      // keep around the last-transmitted set of SSIDs we wanted to close for
833f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      // error recovery.  It doesn't seem likely to occur, and if so, likely
834f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      // harmless within the lifetime of a single SCTP association.
83528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
83628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    default:
83728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_WARNING) << "Unknown SCTP event: "
83828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                      << notification.sn_header.sn_type;
83928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
84028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
84128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
84228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
84328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgvoid SctpDataMediaChannel::OnNotificationAssocChange(
84428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    const sctp_assoc_change& change) {
84528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  switch (change.sac_state) {
84628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_COMM_UP:
84728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_VERBOSE) << "Association change SCTP_COMM_UP";
84828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
84928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_COMM_LOST:
85028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_INFO) << "Association change SCTP_COMM_LOST";
85128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
85228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_RESTART:
85328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_INFO) << "Association change SCTP_RESTART";
85428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
85528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_SHUTDOWN_COMP:
85628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_INFO) << "Association change SCTP_SHUTDOWN_COMP";
85728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
85828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case SCTP_CANT_STR_ASSOC:
85928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_INFO) << "Association change SCTP_CANT_STR_ASSOC";
86028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
86128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    default:
86228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      LOG(LS_INFO) << "Association change UNKNOWN";
86328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
86428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
86528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
86628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
867f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.orgvoid SctpDataMediaChannel::OnStreamResetEvent(
868f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    const struct sctp_stream_reset_event* evt) {
869f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // A stream reset always involves two RE-CONFIG chunks for us -- we always
870f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // simultaneously reset a sid's sequence number in both directions.  The
871f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // requesting side transmits a RE-CONFIG chunk and waits for the peer to send
872f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // one back.  Both sides get this SCTP_STREAM_RESET_EVENT when they receive
873f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // RE-CONFIGs.
874f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  const int num_ssrcs = (evt->strreset_length - sizeof(*evt)) /
875f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      sizeof(evt->strreset_stream_list[0]);
876f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
877f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                  << "): Flags = 0x"
878f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                  << std::hex << evt->strreset_flags << " ("
879f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                  << ListFlags(evt->strreset_flags) << ")";
880f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  LOG(LS_VERBOSE) << "Assoc = " << evt->strreset_assoc_id << ", Streams = ["
881f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                  << ListArray(evt->strreset_stream_list, num_ssrcs)
882f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                  << "], Open: ["
883f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                  << ListStreams(open_streams_) << "], Q'd: ["
884f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                  << ListStreams(queued_reset_streams_) << "], Sent: ["
885f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                  << ListStreams(sent_reset_streams_) << "]";
886f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
887f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // If both sides try to reset some streams at the same time (even if they're
888f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // disjoint sets), we can get reset failures.
889f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  if (evt->strreset_flags & SCTP_STREAM_RESET_FAILED) {
890f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    // OK, just try again.  The stream IDs sent over when the RESET_FAILED flag
891f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    // is set seem to be garbage values.  Ignore them.
892f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    queued_reset_streams_.insert(
893f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        sent_reset_streams_.begin(),
894f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        sent_reset_streams_.end());
895f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    sent_reset_streams_.clear();
896f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
897f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  } else if (evt->strreset_flags & SCTP_STREAM_RESET_INCOMING_SSN) {
898f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    // Each side gets an event for each direction of a stream.  That is,
899f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    // closing sid k will make each side receive INCOMING and OUTGOING reset
900f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    // events for k.  As per RFC6525, Section 5, paragraph 2, each side will
901f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    // get an INCOMING event first.
902f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    for (int i = 0; i < num_ssrcs; i++) {
903f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      const int stream_id = evt->strreset_stream_list[i];
904f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
905f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      // See if this stream ID was closed by our peer or ourselves.
906f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      StreamSet::iterator it = sent_reset_streams_.find(stream_id);
907f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
908f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      // The reset was requested locally.
909f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      if (it != sent_reset_streams_.end()) {
910f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
911f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                        << "): local sid " << stream_id << " acknowledged.";
912f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        sent_reset_streams_.erase(it);
913f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
914f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      } else if ((it = open_streams_.find(stream_id))
915f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                 != open_streams_.end()) {
916f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        // The peer requested the reset.
917f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
918f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                        << "): closing sid " << stream_id;
919f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        open_streams_.erase(it);
9201d66be22c8f929e1170f288472aac9d4b44b7a05buildbot@webrtc.org        SignalStreamClosedRemotely(stream_id);
921f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
922f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      } else if ((it = queued_reset_streams_.find(stream_id))
923f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                 != queued_reset_streams_.end()) {
924f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        // The peer requested the reset, but there was a local reset
925f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        // queued.
926f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
927f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                        << "): double-sided close for sid " << stream_id;
928f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        // Both sides want the stream closed, and the peer got to send the
929f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        // RE-CONFIG first.  Treat it like the local Remove(Send|Recv)Stream
930f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        // finished quickly.
931f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        queued_reset_streams_.erase(it);
932f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
933f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      } else {
934f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        // This stream is unknown.  Sometimes this can be from an
935f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        // RESET_FAILED-related retransmit.
936f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org        LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
937f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                        << "): Unknown sid " << stream_id;
938f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      }
939f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    }
940f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  }
941f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
9421a6c6281ca028e4fbba5c015ed7166ffc34bae9cjiayl@webrtc.org  // Always try to send the queued RESET because this call indicates that the
9431a6c6281ca028e4fbba5c015ed7166ffc34bae9cjiayl@webrtc.org  // last local RESET or remote RESET has made some progress.
9441a6c6281ca028e4fbba5c015ed7166ffc34bae9cjiayl@webrtc.org  SendQueuedStreamResets();
945f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org}
946f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
94778187525665490922748d79377bcb351579e03c0wu@webrtc.org// Puts the specified |param| from the codec identified by |id| into |dest|
94878187525665490922748d79377bcb351579e03c0wu@webrtc.org// and returns true.  Or returns false if it wasn't there, leaving |dest|
94978187525665490922748d79377bcb351579e03c0wu@webrtc.org// untouched.
95078187525665490922748d79377bcb351579e03c0wu@webrtc.orgstatic bool GetCodecIntParameter(const std::vector<DataCodec>& codecs,
95178187525665490922748d79377bcb351579e03c0wu@webrtc.org                                 int id, const std::string& name,
95278187525665490922748d79377bcb351579e03c0wu@webrtc.org                                 const std::string& param, int* dest) {
95378187525665490922748d79377bcb351579e03c0wu@webrtc.org  std::string value;
95478187525665490922748d79377bcb351579e03c0wu@webrtc.org  Codec match_pattern;
95578187525665490922748d79377bcb351579e03c0wu@webrtc.org  match_pattern.id = id;
95678187525665490922748d79377bcb351579e03c0wu@webrtc.org  match_pattern.name = name;
95778187525665490922748d79377bcb351579e03c0wu@webrtc.org  for (size_t i = 0; i < codecs.size(); ++i) {
95878187525665490922748d79377bcb351579e03c0wu@webrtc.org    if (codecs[i].Matches(match_pattern)) {
95978187525665490922748d79377bcb351579e03c0wu@webrtc.org      if (codecs[i].GetParam(param, &value)) {
960d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org        *dest = rtc::FromString<int>(value);
96178187525665490922748d79377bcb351579e03c0wu@webrtc.org        return true;
96278187525665490922748d79377bcb351579e03c0wu@webrtc.org      }
96378187525665490922748d79377bcb351579e03c0wu@webrtc.org    }
96478187525665490922748d79377bcb351579e03c0wu@webrtc.org  }
96578187525665490922748d79377bcb351579e03c0wu@webrtc.org  return false;
96678187525665490922748d79377bcb351579e03c0wu@webrtc.org}
96778187525665490922748d79377bcb351579e03c0wu@webrtc.org
96878187525665490922748d79377bcb351579e03c0wu@webrtc.orgbool SctpDataMediaChannel::SetSendCodecs(const std::vector<DataCodec>& codecs) {
96978187525665490922748d79377bcb351579e03c0wu@webrtc.org  return GetCodecIntParameter(
97078187525665490922748d79377bcb351579e03c0wu@webrtc.org      codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort,
97178187525665490922748d79377bcb351579e03c0wu@webrtc.org      &remote_port_);
97278187525665490922748d79377bcb351579e03c0wu@webrtc.org}
97378187525665490922748d79377bcb351579e03c0wu@webrtc.org
97478187525665490922748d79377bcb351579e03c0wu@webrtc.orgbool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) {
97578187525665490922748d79377bcb351579e03c0wu@webrtc.org  return GetCodecIntParameter(
97678187525665490922748d79377bcb351579e03c0wu@webrtc.org      codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort,
97778187525665490922748d79377bcb351579e03c0wu@webrtc.org      &local_port_);
97878187525665490922748d79377bcb351579e03c0wu@webrtc.org}
97928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
98028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgvoid SctpDataMediaChannel::OnPacketFromSctpToNetwork(
981d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org    rtc::Buffer* buffer) {
982e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // usrsctp seems to interpret the MTU we give it strangely -- it seems to
983e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // give us back packets bigger than that MTU, if only by a fixed amount.
984e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  // This is that amount that we've observed.
985e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  const int kSctpOverhead = 76;
986e8386d21992b6683b6fadd315ea631875b4256fbLally Singh  if (buffer->size() > (kSctpOverhead + kSctpMtu)) {
98728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): "
988f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                  << "SCTP seems to have made a packet that is bigger "
989e8386d21992b6683b6fadd315ea631875b4256fbLally Singh                  << "than its official MTU: " << buffer->size()
990e8386d21992b6683b6fadd315ea631875b4256fbLally Singh                  << " vs max of " << kSctpMtu
991e8386d21992b6683b6fadd315ea631875b4256fbLally Singh                  << " even after adding " << kSctpOverhead
992e8386d21992b6683b6fadd315ea631875b4256fbLally Singh                  << " extra SCTP overhead";
99328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
994c1aeaf0dc37d96f31c92f893f4e30e7a5f7cc2b7stefan  MediaChannel::SendPacket(buffer, rtc::PacketOptions());
99528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
99628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
997f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.orgbool SctpDataMediaChannel::SendQueuedStreamResets() {
998f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  if (!sent_reset_streams_.empty() || queued_reset_streams_.empty())
999f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    return true;
1000f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
1001f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending ["
1002f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                  << ListStreams(queued_reset_streams_) << "], Open: ["
1003f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                  << ListStreams(open_streams_) << "], Sent: ["
1004f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                  << ListStreams(sent_reset_streams_) << "]";
1005f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
1006f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  const size_t num_streams = queued_reset_streams_.size();
10070c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  const size_t num_bytes =
10080c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström      sizeof(struct sctp_reset_streams) + (num_streams * sizeof(uint16_t));
1009f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
10100c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  std::vector<uint8_t> reset_stream_buf(num_bytes, 0);
1011f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  struct sctp_reset_streams* resetp = reinterpret_cast<sctp_reset_streams*>(
1012f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      &reset_stream_buf[0]);
1013f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  resetp->srs_assoc_id = SCTP_ALL_ASSOC;
1014f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  resetp->srs_flags = SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_OUTGOING;
1015d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org  resetp->srs_number_streams = rtc::checked_cast<uint16_t>(num_streams);
1016f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  int result_idx = 0;
1017f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  for (StreamSet::iterator it = queued_reset_streams_.begin();
1018f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org       it != queued_reset_streams_.end(); ++it) {
1019f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    resetp->srs_stream_list[result_idx++] = *it;
1020f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  }
1021f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
1022a576faf82a692c9422dcdc3278394ed25e6ee4f7jiayl@webrtc.org  int ret = usrsctp_setsockopt(
1023a576faf82a692c9422dcdc3278394ed25e6ee4f7jiayl@webrtc.org      sock_, IPPROTO_SCTP, SCTP_RESET_STREAMS, resetp,
1024d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org      rtc::checked_cast<socklen_t>(reset_stream_buf.size()));
1025f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  if (ret < 0) {
1026f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to send a stream reset for "
1027f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org                        << num_streams << " streams";
1028f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    return false;
1029f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  }
1030f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
1031f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // sent_reset_streams_ is empty, and all the queued_reset_streams_ go into
1032f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // it now.
1033f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  queued_reset_streams_.swap(sent_reset_streams_);
1034f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  return true;
1035f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org}
1036f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org
1037d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.orgvoid SctpDataMediaChannel::OnMessage(rtc::Message* msg) {
103828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  switch (msg->message_id) {
103928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case MSG_SCTPINBOUNDPACKET: {
1040d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org      rtc::scoped_ptr<InboundPacketMessage> pdata(
1041f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org          static_cast<InboundPacketMessage*>(msg->pdata));
1042f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      OnInboundPacketFromSctpToChannel(pdata->data().get());
104328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
104428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    }
104528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    case MSG_SCTPOUTBOUNDPACKET: {
1046d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org      rtc::scoped_ptr<OutboundPacketMessage> pdata(
1047f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org          static_cast<OutboundPacketMessage*>(msg->pdata));
1048f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org      OnPacketFromSctpToNetwork(pdata->data().get());
104928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
105028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    }
105128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
105228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
105328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}  // namespace cricket
1054