10e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*
20e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * libjingle SCTP
30e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Copyright 2012 Google Inc, and Robin Seggelmann
40e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
50e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Redistribution and use in source and binary forms, with or without
60e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * modification, are permitted provided that the following conditions are met:
70e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
80e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *  1. Redistributions of source code must retain the above copyright notice,
90e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     this list of conditions and the following disclaimer.
100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *  2. Redistributions in binary form must reproduce the above copyright notice,
110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     this list of conditions and the following disclaimer in the documentation
120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     and/or other materials provided with the distribution.
130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *  3. The name of the author may not be used to endorse or promote products
140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     derived from this software without specific prior written permission.
150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org */
270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/sctp/sctpdataengine.h"
290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <stdarg.h>
310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <stdio.h>
322a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org#include <sstream>
330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <vector>
340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/base/codec.h"
360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/base/constants.h"
370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/base/streamparams.h"
380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "usrsctplib/usrsctp.h"
39cf81adffe15fa8ea0f333432e41f6d504148f18abuildbot@webrtc.org#include "webrtc/base/buffer.h"
40cf81adffe15fa8ea0f333432e41f6d504148f18abuildbot@webrtc.org#include "webrtc/base/helpers.h"
41cf81adffe15fa8ea0f333432e41f6d504148f18abuildbot@webrtc.org#include "webrtc/base/logging.h"
42cf81adffe15fa8ea0f333432e41f6d504148f18abuildbot@webrtc.org#include "webrtc/base/safe_conversions.h"
430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
442a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.orgnamespace {
452a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.orgtypedef cricket::SctpDataMediaChannel::StreamSet StreamSet;
462a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org// Returns a comma-separated, human-readable list of the stream IDs in 's'
472a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.orgstd::string ListStreams(const StreamSet& s) {
482a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  std::stringstream result;
492a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  bool first = true;
506c1232675bde865816bcbba2d2f3935ab04da61fwu@webrtc.org  for (StreamSet::const_iterator it = s.begin(); it != s.end(); ++it) {
512a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    if (!first) {
522a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      result << ", " << *it;
532a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    } else {
542a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      result << *it;
552a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      first = false;
562a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    }
572a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  }
582a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  return result.str();
592a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org}
602a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
612a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org// Returns a pipe-separated, human-readable list of the SCTP_STREAM_RESET
622a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org// flags in 'flags'
632a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.orgstd::string ListFlags(int flags) {
642a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  std::stringstream result;
652a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  bool first = true;
662a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // Skip past the first 12 chars (strlen("SCTP_STREAM_"))
672a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org#define MAKEFLAG(X) { X, #X + 12}
682a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  struct flaginfo_t {
692a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    int value;
702a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    const char* name;
712a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  } flaginfo[] = {
722a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    MAKEFLAG(SCTP_STREAM_RESET_INCOMING_SSN),
732a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    MAKEFLAG(SCTP_STREAM_RESET_OUTGOING_SSN),
742a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    MAKEFLAG(SCTP_STREAM_RESET_DENIED),
752a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    MAKEFLAG(SCTP_STREAM_RESET_FAILED),
762a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    MAKEFLAG(SCTP_STREAM_CHANGE_DENIED)
772a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  };
782a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org#undef MAKEFLAG
792a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  for (int i = 0; i < ARRAY_SIZE(flaginfo); ++i) {
802a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    if (flags & flaginfo[i].value) {
812a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      if (!first) result << " | ";
822a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      result << flaginfo[i].name;
832a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      first = false;
842a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    }
852a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  }
862a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  return result.str();
872a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org}
882a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
892a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org// Returns a comma-separated, human-readable list of the integers in 'array'.
902a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org// All 'num_elems' of them.
912a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.orgstd::string ListArray(const uint16* array, int num_elems) {
922a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  std::stringstream result;
932a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  for (int i = 0; i < num_elems; ++i) {
942a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    if (i) {
952a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      result << ", " << array[i];
962a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    } else {
972a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      result << array[i];
982a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    }
992a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  }
1002a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  return result.str();
1012a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org}
1022a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org}  // namespace
1032a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
1040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgnamespace cricket {
1052a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.orgtypedef rtc::ScopedMessageData<SctpInboundPacket> InboundPacketMessage;
1062a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.orgtypedef rtc::ScopedMessageData<rtc::Buffer> OutboundPacketMessage;
1070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1084d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org// The biggest SCTP packet.  Starting from a 'safe' wire MTU value of 1280,
1094d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org// take off 80 bytes for DTLS/TURN/TCP/IP overhead.
1104d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.orgstatic const size_t kSctpMtu = 1200;
1110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgenum {
1130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  MSG_SCTPINBOUNDPACKET = 1,   // MessageData is SctpInboundPacket
1142a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  MSG_SCTPOUTBOUNDPACKET = 2,  // MessageData is rtc:Buffer
1150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org};
1160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstruct SctpInboundPacket {
1182a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  rtc::Buffer buffer;
1190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ReceiveDataParams params;
1200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // The |flags| parameter is used by SCTP to distinguish notification packets
1210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // from other types of packets.
1220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int flags;
1230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org};
1240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
125391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org// Helper for logging SCTP messages.
1260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic void debug_sctp_printf(const char *format, ...) {
1270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  char s[255];
1280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  va_list ap;
1290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  va_start(ap, format);
1300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  vsnprintf(s, sizeof(s), format, ap);
131391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  LOG(LS_INFO) << "SCTP: " << s;
1320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  va_end(ap);
1330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
135391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org// Get the PPID to use for the terminating fragment of this type.
136391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.orgstatic SctpDataMediaChannel::PayloadProtocolIdentifier GetPpid(
137391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    cricket::DataMessageType type) {
138391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  switch (type) {
139391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  default:
140391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  case cricket::DMT_NONE:
141391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    return SctpDataMediaChannel::PPID_NONE;
142391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  case cricket::DMT_CONTROL:
143391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    return SctpDataMediaChannel::PPID_CONTROL;
144391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  case cricket::DMT_BINARY:
145391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    return SctpDataMediaChannel::PPID_BINARY_LAST;
146391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  case cricket::DMT_TEXT:
147391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    return SctpDataMediaChannel::PPID_TEXT_LAST;
148391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  };
149391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org}
150391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org
151391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.orgstatic bool GetDataMediaType(
152391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    SctpDataMediaChannel::PayloadProtocolIdentifier ppid,
153391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    cricket::DataMessageType *dest) {
154391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  ASSERT(dest != NULL);
155391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  switch (ppid) {
156391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    case SctpDataMediaChannel::PPID_BINARY_PARTIAL:
157391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    case SctpDataMediaChannel::PPID_BINARY_LAST:
158391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      *dest = cricket::DMT_BINARY;
159391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      return true;
160391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org
161391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    case SctpDataMediaChannel::PPID_TEXT_PARTIAL:
162391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    case SctpDataMediaChannel::PPID_TEXT_LAST:
163391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      *dest = cricket::DMT_TEXT;
164391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      return true;
165391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org
166391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    case SctpDataMediaChannel::PPID_CONTROL:
167391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      *dest = cricket::DMT_CONTROL;
168391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      return true;
169391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org
170391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    case SctpDataMediaChannel::PPID_NONE:
171391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      *dest = cricket::DMT_NONE;
172391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      return true;
173391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org
174391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    default:
175391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      return false;
1760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// This is the callback usrsctp uses when there's data to send on the network
1800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// that has been wrapped appropriatly for the SCTP protocol.
1810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic int OnSctpOutboundPacket(void* addr, void* data, size_t length,
1820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                uint8_t tos, uint8_t set_df) {
1830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(addr);
1840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_VERBOSE) << "global OnSctpOutboundPacket():"
1850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  << "addr: " << addr << "; length: " << length
1860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  << "; tos: " << std::hex << static_cast<int>(tos)
187391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org                  << "; set_df: " << std::hex << static_cast<int>(set_df);
1880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Note: We have to copy the data; the caller will delete it.
1892a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  OutboundPacketMessage* msg =
1902a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org      new OutboundPacketMessage(new rtc::Buffer(data, length));
1912a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  channel->worker_thread()->Post(channel, MSG_SCTPOUTBOUNDPACKET, msg);
1920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return 0;
1930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// This is the callback called from usrsctp when data has been received, after
1960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// a packet has been interpreted and parsed by usrsctp and found to contain
1970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// payload data. It is called by a usrsctp thread. It is assumed this function
1980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// will free the memory used by 'data'.
1990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic int OnSctpInboundPacket(struct socket* sock, union sctp_sockstore addr,
2000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                               void* data, size_t length,
2010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                               struct sctp_rcvinfo rcv, int flags,
2020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                               void* ulp_info) {
2030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(ulp_info);
2040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Post data to the channel's receiver thread (copying it).
2050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // TODO(ldixon): Unclear if copy is needed as this method is responsible for
2060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // memory cleanup. But this does simplify code.
207391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  const SctpDataMediaChannel::PayloadProtocolIdentifier ppid =
208391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      static_cast<SctpDataMediaChannel::PayloadProtocolIdentifier>(
2092a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org          rtc::HostToNetwork32(rcv.rcv_ppid));
210391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  cricket::DataMessageType type = cricket::DMT_NONE;
211391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  if (!GetDataMediaType(ppid, &type) && !(flags & MSG_NOTIFICATION)) {
212391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    // It's neither a notification nor a recognized data packet.  Drop it.
213391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    LOG(LS_ERROR) << "Received an unknown PPID " << ppid
214391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org                  << " on an SCTP packet.  Dropping.";
215391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  } else {
216391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    SctpInboundPacket* packet = new SctpInboundPacket;
217391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    packet->buffer.SetData(data, length);
218391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    packet->params.ssrc = rcv.rcv_sid;
219391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    packet->params.seq_num = rcv.rcv_ssn;
220391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    packet->params.timestamp = rcv.rcv_tsn;
221391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    packet->params.type = type;
222391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    packet->flags = flags;
2232a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    // The ownership of |packet| transfers to |msg|.
2242a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    InboundPacketMessage* msg = new InboundPacketMessage(packet);
2252a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    channel->worker_thread()->Post(channel, MSG_SCTPINBOUNDPACKET, msg);
226391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  }
2270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  free(data);
2280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return 1;
2290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Set the initial value of the static SCTP Data Engines reference count.
2320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgint SctpDataEngine::usrsctp_engines_count = 0;
2330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
234f5b8e7a761959709cf8201685deaf35ed074cb83wu@webrtc.orgSctpDataEngine::SctpDataEngine() {
2350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (usrsctp_engines_count == 0) {
2360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // First argument is udp_encapsulation_port, which is not releveant for our
2370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // AF_CONN use of sctp.
2380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    usrsctp_init(0, cricket::OnSctpOutboundPacket, debug_sctp_printf);
2390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // To turn on/off detailed SCTP debugging. You will also need to have the
2410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // SCTP_DEBUG cpp defines flag.
2420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
2430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // TODO(ldixon): Consider turning this on/off.
2450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    usrsctp_sysctl_set_sctp_ecn_enable(0);
2460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // TODO(ldixon): Consider turning this on/off.
2480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // This is not needed right now (we don't do dynamic address changes):
2490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // If SCTP Auto-ASCONF is enabled, the peer is informed automatically
2500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // when a new address is added or removed. This feature is enabled by
2510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // default.
2520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // usrsctp_sysctl_set_sctp_auto_asconf(0);
2530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // TODO(ldixon): Consider turning this on/off.
2550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Add a blackhole sysctl. Setting it to 1 results in no ABORTs
2560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // being sent in response to INITs, setting it to 2 results
2570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // in no ABORTs being sent for received OOTB packets.
2580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // This is similar to the TCP sysctl.
2590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    //
2600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // See: http://lakerest.net/pipermail/sctp-coders/2012-January/009438.html
2610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // See: http://svnweb.freebsd.org/base?view=revision&revision=229805
2620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // usrsctp_sysctl_set_sctp_blackhole(2);
263391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org
264391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    // Set the number of default outgoing streams.  This is the number we'll
265391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    // send in the SCTP INIT message.  The 'appropriate default' in the
266391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    // second paragraph of
267391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    // http://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-05#section-6.2
268391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    // is cricket::kMaxSctpSid.
269391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    usrsctp_sysctl_set_sctp_nr_outgoing_streams_default(
270391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org        cricket::kMaxSctpSid);
2710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  usrsctp_engines_count++;
2730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
274e4b3e8d10bdf1e112408887533f57c2667f1f7aejiayl@webrtc.org  cricket::DataCodec codec(kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, 0);
275e4b3e8d10bdf1e112408887533f57c2667f1f7aejiayl@webrtc.org  codec.SetParam(kCodecParamPort, kSctpDefaultPort);
276e4b3e8d10bdf1e112408887533f57c2667f1f7aejiayl@webrtc.org  codecs_.push_back(codec);
2770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgSctpDataEngine::~SctpDataEngine() {
280d19ccc188174c1154987ce2512be1bc64905a3bcjiayl@webrtc.org  usrsctp_engines_count--;
281d19ccc188174c1154987ce2512be1bc64905a3bcjiayl@webrtc.org  LOG(LS_VERBOSE) << "usrsctp_engines_count:" << usrsctp_engines_count;
282d19ccc188174c1154987ce2512be1bc64905a3bcjiayl@webrtc.org
283d19ccc188174c1154987ce2512be1bc64905a3bcjiayl@webrtc.org  if (usrsctp_engines_count == 0) {
284d19ccc188174c1154987ce2512be1bc64905a3bcjiayl@webrtc.org    // usrsctp_finish() may fail if it's called too soon after the channels are
285d19ccc188174c1154987ce2512be1bc64905a3bcjiayl@webrtc.org    // closed. Wait and try again until it succeeds for up to 3 seconds.
286d19ccc188174c1154987ce2512be1bc64905a3bcjiayl@webrtc.org    for (size_t i = 0; i < 300; ++i) {
287d19ccc188174c1154987ce2512be1bc64905a3bcjiayl@webrtc.org      if (usrsctp_finish() == 0)
288d19ccc188174c1154987ce2512be1bc64905a3bcjiayl@webrtc.org        return;
289d19ccc188174c1154987ce2512be1bc64905a3bcjiayl@webrtc.org
2902a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org      rtc::Thread::SleepMs(10);
291d19ccc188174c1154987ce2512be1bc64905a3bcjiayl@webrtc.org    }
292d19ccc188174c1154987ce2512be1bc64905a3bcjiayl@webrtc.org    LOG(LS_ERROR) << "Failed to shutdown usrsctp.";
293d19ccc188174c1154987ce2512be1bc64905a3bcjiayl@webrtc.org  }
2940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgDataMediaChannel* SctpDataEngine::CreateChannel(
2970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    DataChannelType data_channel_type) {
2980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (data_channel_type != DCT_SCTP) {
2990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return NULL;
3000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3012a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  return new SctpDataMediaChannel(rtc::Thread::Current());
3020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3042a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.orgSctpDataMediaChannel::SctpDataMediaChannel(rtc::Thread* thread)
3050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    : worker_thread_(thread),
306e4b3e8d10bdf1e112408887533f57c2667f1f7aejiayl@webrtc.org      local_port_(kSctpDefaultPort),
307e4b3e8d10bdf1e112408887533f57c2667f1f7aejiayl@webrtc.org      remote_port_(kSctpDefaultPort),
3080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      sock_(NULL),
3090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      sending_(false),
3100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      receiving_(false),
3110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      debug_name_("SctpDataMediaChannel") {
3120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgSctpDataMediaChannel::~SctpDataMediaChannel() {
3150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  CloseSctpSocket();
3160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgsockaddr_conn SctpDataMediaChannel::GetSctpSockAddr(int port) {
3190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  sockaddr_conn sconn = {0};
3200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  sconn.sconn_family = AF_CONN;
3210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#ifdef HAVE_SCONN_LEN
3220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  sconn.sconn_len = sizeof(sockaddr_conn);
3230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif
3240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Note: conversion from int to uint16_t happens here.
3252a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  sconn.sconn_port = rtc::HostToNetwork16(port);
3260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  sconn.sconn_addr = this;
3270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return sconn;
3280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool SctpDataMediaChannel::OpenSctpSocket() {
3310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (sock_) {
3320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_VERBOSE) << debug_name_
3330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    << "->Ignoring attempt to re-create existing socket.";
3340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
3350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP,
3370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                         cricket::OnSctpInboundPacket, NULL, 0, this);
3380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!sock_) {
3390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket.";
3400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
3410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Make the socket non-blocking. Connect, close, shutdown etc will not block
3440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // the thread waiting for the socket operation to complete.
3450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (usrsctp_set_non_blocking(sock_, 1) < 0) {
3460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking.";
3470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
3480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // This ensures that the usrsctp close call deletes the association. This
3510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // prevents usrsctp from calling OnSctpOutboundPacket with references to
3520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // this class as the address.
3530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  linger linger_opt;
3540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  linger_opt.l_onoff = 1;
3550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  linger_opt.l_linger = 0;
3560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (usrsctp_setsockopt(sock_, SOL_SOCKET, SO_LINGER, &linger_opt,
3570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                         sizeof(linger_opt))) {
3580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SO_LINGER.";
3590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
3600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3622a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // Enable stream ID resets.
3632a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  struct sctp_assoc_value stream_rst;
3642a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  stream_rst.assoc_id = SCTP_ALL_ASSOC;
3652a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  stream_rst.assoc_value = 1;
3662a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET,
3672a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                         &stream_rst, sizeof(stream_rst))) {
3682a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_
3692a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                        << "Failed to set SCTP_ENABLE_STREAM_RESET.";
3702a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    return false;
3712a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  }
3722a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
3732a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // Nagle.
374ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org  uint32_t nodelay = 1;
375ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org  if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay,
376ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org                         sizeof(nodelay))) {
377ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_NODELAY.";
378ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org    return false;
379ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org  }
380ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org
3814d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org  // Disable MTU discovery
3824d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org  struct sctp_paddrparams params;
3834d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org  params.spp_assoc_id = 0;
3844d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org  params.spp_flags = SPP_PMTUD_DISABLE;
3854d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org  params.spp_pathmtu = kSctpMtu;
3864d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org  if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &params,
3874d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org      sizeof(params))) {
3884d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_
3894d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org                        << "Failed to set SCTP_PEER_ADDR_PARAMS.";
3904d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org    return false;
3914d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org  }
3924d81c99f2b415fdcd115b63df3929dc9a73e95b3buildbot@webrtc.org
3930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Subscribe to SCTP event notifications.
3940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int event_types[] = {SCTP_ASSOC_CHANGE,
3950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                       SCTP_PEER_ADDR_CHANGE,
396d156f12e9ee96258b7b79d0e3d8ddab6b4b87fbbwu@webrtc.org                       SCTP_SEND_FAILED_EVENT,
3972a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                       SCTP_SENDER_DRY_EVENT,
3982a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                       SCTP_STREAM_RESET_EVENT};
3990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  struct sctp_event event = {0};
4000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  event.se_assoc_id = SCTP_ALL_ASSOC;
4010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  event.se_on = 1;
4020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (size_t i = 0; i < ARRAY_SIZE(event_types); i++) {
4030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    event.se_type = event_types[i];
4040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_EVENT, &event,
4050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                           sizeof(event)) < 0) {
4060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_EVENT type: "
4070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                          << event.se_type;
4080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
4090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
4100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Register this class as an address for usrsctp. This is used by SCTP to
4130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // direct the packets received (by the created socket) to this class.
4140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  usrsctp_register_address(this);
4150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  sending_ = true;
4160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
4170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
4180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid SctpDataMediaChannel::CloseSctpSocket() {
4200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  sending_ = false;
4210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (sock_) {
4220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // We assume that SO_LINGER option is set to close the association when
4230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // close is called. This means that any pending packets in usrsctp will be
4240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // discarded instead of being sent.
4250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    usrsctp_close(sock_);
4260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    sock_ = NULL;
4270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    usrsctp_deregister_address(this);
4280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
4300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool SctpDataMediaChannel::Connect() {
4320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_VERBOSE) << debug_name_ << "->Connect().";
4330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // If we already have a socket connection, just return.
4350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (sock_) {
4360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << debug_name_ << "->Connect(): Ignored as socket "
4370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                      "is already established.";
4380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
4390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // If no socket (it was closed) try to start it again. This can happen when
4420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // the socket we are connecting to closes, does an sctp shutdown handshake,
4430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // or behaves unexpectedly causing us to perform a CloseSctpSocket.
4440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!sock_ && !OpenSctpSocket()) {
4450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
4460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Note: conversion from int to uint16_t happens on assignment.
4490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  sockaddr_conn local_sconn = GetSctpSockAddr(local_port_);
4500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (usrsctp_bind(sock_, reinterpret_cast<sockaddr *>(&local_sconn),
4510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                   sizeof(local_sconn)) < 0) {
4520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "->Connect(): "
4530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                        << ("Failed usrsctp_bind");
4540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    CloseSctpSocket();
4550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
4560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Note: conversion from int to uint16_t happens on assignment.
4590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  sockaddr_conn remote_sconn = GetSctpSockAddr(remote_port_);
4600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int connect_result = usrsctp_connect(
4610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      sock_, reinterpret_cast<sockaddr *>(&remote_sconn), sizeof(remote_sconn));
4621a04b881e0ef480802fb01b4fbe9bcd5388d2c69henrike@webrtc.org  if (connect_result < 0 && errno != SCTP_EINPROGRESS) {
4631a04b881e0ef480802fb01b4fbe9bcd5388d2c69henrike@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed usrsctp_connect. got errno="
4641a04b881e0ef480802fb01b4fbe9bcd5388d2c69henrike@webrtc.org                        << errno << ", but wanted " << SCTP_EINPROGRESS;
4650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    CloseSctpSocket();
4660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
4670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
4690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
4700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid SctpDataMediaChannel::Disconnect() {
4720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // TODO(ldixon): Consider calling |usrsctp_shutdown(sock_, ...)| to do a
4730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // shutdown handshake and remove the association.
4740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  CloseSctpSocket();
4750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
4760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool SctpDataMediaChannel::SetSend(bool send) {
4780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!sending_ && send) {
4790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return Connect();
4800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (sending_ && !send) {
4820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    Disconnect();
4830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
4850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
4860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool SctpDataMediaChannel::SetReceive(bool receive) {
4880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  receiving_ = receive;
4890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
4900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
4910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool SctpDataMediaChannel::AddSendStream(const StreamParams& stream) {
4932a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  return AddStream(stream);
4940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
4950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool SctpDataMediaChannel::RemoveSendStream(uint32 ssrc) {
4972a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  return ResetStream(ssrc);
4980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
4990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool SctpDataMediaChannel::AddRecvStream(const StreamParams& stream) {
5018485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org  // SCTP DataChannels are always bi-directional and calling AddSendStream will
5028485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org  // enable both sending and receiving on the stream. So AddRecvStream is a
5038485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org  // no-op.
5048485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org  return true;
5050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
5060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool SctpDataMediaChannel::RemoveRecvStream(uint32 ssrc) {
5088485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org  // SCTP DataChannels are always bi-directional and calling RemoveSendStream
5098485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org  // will disable both sending and receiving on the stream. So RemoveRecvStream
5108485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org  // is a no-op.
5118485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org  return true;
5120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
5130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool SctpDataMediaChannel::SendData(
5150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const SendDataParams& params,
5162a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org    const rtc::Buffer& payload,
5170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    SendDataResult* result) {
5180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (result) {
519391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    // Preset |result| to assume an error.  If SendData succeeds, we'll
520391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    // overwrite |*result| once more at the end.
5210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    *result = SDR_ERROR;
5220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!sending_) {
5250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << debug_name_ << "->SendData(...): "
5260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    << "Not sending packet with ssrc=" << params.ssrc
5270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    << " len=" << payload.length() << " before SetSend(true).";
5280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
5290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5315aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  if (params.type != cricket::DMT_CONTROL &&
5322a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      open_streams_.find(params.ssrc) == open_streams_.end()) {
5330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << debug_name_ << "->SendData(...): "
5340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    << "Not sending data because ssrc is unknown: "
5350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    << params.ssrc;
5360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
5370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  //
5400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Send data using SCTP.
541391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  ssize_t send_res = 0;  // result from usrsctp_sendv.
542391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  struct sctp_sendv_spa spa = {0};
543391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  spa.sendv_flags |= SCTP_SEND_SNDINFO_VALID;
544391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  spa.sendv_sndinfo.snd_sid = params.ssrc;
5452a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  spa.sendv_sndinfo.snd_ppid = rtc::HostToNetwork32(
546391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      GetPpid(params.type));
547391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org
548391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  // Ordered implies reliable.
549391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  if (!params.ordered) {
550391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    spa.sendv_sndinfo.snd_flags |= SCTP_UNORDERED;
551391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    if (params.max_rtx_count >= 0 || params.max_rtx_ms == 0) {
552391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
553391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
554391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      spa.sendv_prinfo.pr_value = params.max_rtx_count;
555391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    } else {
556391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
557391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL;
558391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org      spa.sendv_prinfo.pr_value = params.max_rtx_ms;
559391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    }
560391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  }
561391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org
562391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  // We don't fragment.
563391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  send_res = usrsctp_sendv(sock_, payload.data(),
564391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org                           static_cast<size_t>(payload.length()),
565391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org                           NULL, 0, &spa,
5662a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org                           rtc::checked_cast<socklen_t>(sizeof(spa)),
567391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org                           SCTP_SENDV_SPA, 0);
568391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  if (send_res < 0) {
569a7f7834eb84ba9551f91eec23dfa26a211bb93c7jiayl@webrtc.org    if (errno == SCTP_EWOULDBLOCK) {
570d156f12e9ee96258b7b79d0e3d8ddab6b4b87fbbwu@webrtc.org      *result = SDR_BLOCK;
571d156f12e9ee96258b7b79d0e3d8ddab6b4b87fbbwu@webrtc.org      LOG(LS_INFO) << debug_name_ << "->SendData(...): EWOULDBLOCK returned";
572d156f12e9ee96258b7b79d0e3d8ddab6b4b87fbbwu@webrtc.org    } else {
573d156f12e9ee96258b7b79d0e3d8ddab6b4b87fbbwu@webrtc.org      LOG_ERRNO(LS_ERROR) << "ERROR:" << debug_name_
574d156f12e9ee96258b7b79d0e3d8ddab6b4b87fbbwu@webrtc.org                          << "->SendData(...): "
575d156f12e9ee96258b7b79d0e3d8ddab6b4b87fbbwu@webrtc.org                          << " usrsctp_sendv: ";
576d156f12e9ee96258b7b79d0e3d8ddab6b4b87fbbwu@webrtc.org    }
5770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
5780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (result) {
580391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org    // Only way out now is success.
5810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    *result = SDR_SUCCESS;
5820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
5840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
5850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Called by network interface when a packet has been received.
587f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.orgvoid SctpDataMediaChannel::OnPacketReceived(
5882a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org    rtc::Buffer* packet, const rtc::PacketTime& packet_time) {
589391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org  LOG(LS_VERBOSE) << debug_name_ << "->OnPacketReceived(...): " << " length="
590391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org                  << packet->length() << ", sending: " << sending_;
5910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Only give receiving packets to usrsctp after if connected. This enables two
5920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // peers to each make a connect call, but for them not to receive an INIT
5930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // packet before they have called connect; least the last receiver of the INIT
5940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // packet will have called connect, and a connection will be established.
5950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (sending_) {
5960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Pass received packet to SCTP stack. Once processed by usrsctp, the data
5970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // will be will be given to the global OnSctpInboundData, and then,
5980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // marshalled by a Post and handled with OnMessage.
5990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    usrsctp_conninput(this, packet->data(), packet->length(), 0);
6000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
6010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // TODO(ldixon): Consider caching the packet for very slightly better
6020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // reliability.
6030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
6050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid SctpDataMediaChannel::OnInboundPacketFromSctpToChannel(
6070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    SctpInboundPacket* packet) {
6080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_VERBOSE) << debug_name_ << "->OnInboundPacketFromSctpToChannel(...): "
6090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  << "Received SCTP data:"
6100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  << " ssrc=" << packet->params.ssrc
6110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  << " notification: " << (packet->flags & MSG_NOTIFICATION)
612391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org                  << " length=" << packet->buffer.length();
6130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Sending a packet with data == NULL (no data) is SCTPs "close the
6140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // connection" message. This sets sock_ = NULL;
6150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!packet->buffer.length() || !packet->buffer.data()) {
6160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_INFO) << debug_name_ << "->OnInboundPacketFromSctpToChannel(...): "
6170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                   "No data, closing.";
6180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return;
6190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (packet->flags & MSG_NOTIFICATION) {
6210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    OnNotificationFromSctp(&packet->buffer);
6220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
6230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    OnDataFromSctpToChannel(packet->params, &packet->buffer);
6240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
6260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid SctpDataMediaChannel::OnDataFromSctpToChannel(
6282a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org    const ReceiveDataParams& params, rtc::Buffer* buffer) {
6290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (receiving_) {
6300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_VERBOSE) << debug_name_ << "->OnDataFromSctpToChannel(...): "
6318485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org                    << "Posting with length: " << buffer->length()
6328485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org                    << " on stream " << params.ssrc;
6338485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org    // Reports all received messages to upper layers, no matter whether the sid
6348485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org    // is known.
6350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    SignalDataReceived(params, buffer->data(), buffer->length());
6360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
6370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << debug_name_ << "->OnDataFromSctpToChannel(...): "
6380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    << "Not receiving packet with sid=" << params.ssrc
6390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    << " len=" <<  buffer->length()
6400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    << " before SetReceive(true).";
6410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
6430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6442a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.orgbool SctpDataMediaChannel::AddStream(const StreamParams& stream) {
6452a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  if (!stream.has_ssrcs()) {
6462a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    return false;
6472a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  }
6482a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
6492a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  const uint32 ssrc = stream.first_ssrc();
6502a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  if (open_streams_.find(ssrc) != open_streams_.end()) {
6518485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org    LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
6522a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                    << "Not adding data stream '" << stream.id
6532a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                    << "' with ssrc=" << ssrc
6542a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                    << " because stream is already open.";
6552a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    return false;
6562a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  } else if (queued_reset_streams_.find(ssrc) != queued_reset_streams_.end()
6572a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org             || sent_reset_streams_.find(ssrc) != sent_reset_streams_.end()) {
6582a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
6592a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                    << "Not adding data stream '" << stream.id
6602a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                    << "' with ssrc=" << ssrc
6612a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                    << " because stream is still closing.";
6622a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    return false;
6632a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  }
6642a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
6652a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  open_streams_.insert(ssrc);
6662a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  return true;
6672a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org}
6682a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
6692a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.orgbool SctpDataMediaChannel::ResetStream(uint32 ssrc) {
6702a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // We typically get this called twice for the same stream, once each for
6712a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // Send and Recv.
6722a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  StreamSet::iterator found = open_streams_.find(ssrc);
6732a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
6742a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  if (found == open_streams_.end()) {
6752a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    LOG(LS_VERBOSE) << debug_name_ << "->ResetStream(" << ssrc << "): "
6762a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                    << "stream not found.";
6772a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    return false;
6782a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  } else {
6792a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    LOG(LS_VERBOSE) << debug_name_ << "->ResetStream(" << ssrc << "): "
6802a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                    << "Removing and queuing RE-CONFIG chunk.";
6812a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    open_streams_.erase(found);
6822a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  }
6832a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
6842a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // SCTP won't let you have more than one stream reset pending at a time, but
6852a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // you can close multiple streams in a single reset.  So, we keep an internal
6862a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // queue of streams-to-reset, and send them as one reset message in
6872a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // SendQueuedStreamResets().
6882a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  queued_reset_streams_.insert(ssrc);
6892a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
6902a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // Signal our stream-reset logic that it should try to send now, if it can.
6912a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  SendQueuedStreamResets();
6922a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
6932a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // The stream will actually get removed when we get the acknowledgment.
6942a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  return true;
6952a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org}
6962a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
6972a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.orgvoid SctpDataMediaChannel::OnNotificationFromSctp(rtc::Buffer* buffer) {
6980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const sctp_notification& notification =
6990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      reinterpret_cast<const sctp_notification&>(*buffer->data());
7000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ASSERT(notification.sn_header.sn_length == buffer->length());
7010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // TODO(ldixon): handle notifications appropriately.
7030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  switch (notification.sn_header.sn_type) {
7040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_ASSOC_CHANGE:
7050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_VERBOSE) << "SCTP_ASSOC_CHANGE";
7060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      OnNotificationAssocChange(notification.sn_assoc_change);
7070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_REMOTE_ERROR:
7090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_REMOTE_ERROR";
7100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_SHUTDOWN_EVENT:
7120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_SHUTDOWN_EVENT";
7130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_ADAPTATION_INDICATION:
7152a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      LOG(LS_INFO) << "SCTP_ADAPTATION_INDICATION";
7160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_PARTIAL_DELIVERY_EVENT:
7180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_PARTIAL_DELIVERY_EVENT";
7190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_AUTHENTICATION_EVENT:
7210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_AUTHENTICATION_EVENT";
7220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_SENDER_DRY_EVENT:
7242a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      LOG(LS_VERBOSE) << "SCTP_SENDER_DRY_EVENT";
725d156f12e9ee96258b7b79d0e3d8ddab6b4b87fbbwu@webrtc.org      SignalReadyToSend(true);
7260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // TODO(ldixon): Unblock after congestion.
7280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_NOTIFICATIONS_STOPPED_EVENT:
7290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_NOTIFICATIONS_STOPPED_EVENT";
7300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_SEND_FAILED_EVENT:
7320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_SEND_FAILED_EVENT";
7330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_STREAM_RESET_EVENT:
7352a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      OnStreamResetEvent(&notification.sn_strreset_event);
7360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_ASSOC_RESET_EVENT:
7380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_ASSOC_RESET_EVENT";
7390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_STREAM_CHANGE_EVENT:
7410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "SCTP_STREAM_CHANGE_EVENT";
7422a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      // An acknowledgment we get after our stream resets have gone through,
7432a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      // if they've failed.  We log the message, but don't react -- we don't
7442a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      // keep around the last-transmitted set of SSIDs we wanted to close for
7452a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      // error recovery.  It doesn't seem likely to occur, and if so, likely
7462a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      // harmless within the lifetime of a single SCTP association.
7470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    default:
7490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_WARNING) << "Unknown SCTP event: "
7500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                      << notification.sn_header.sn_type;
7510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
7530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
7540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid SctpDataMediaChannel::OnNotificationAssocChange(
7560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const sctp_assoc_change& change) {
7570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  switch (change.sac_state) {
7580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_COMM_UP:
7590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_VERBOSE) << "Association change SCTP_COMM_UP";
7600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_COMM_LOST:
7620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "Association change SCTP_COMM_LOST";
7630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_RESTART:
7650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "Association change SCTP_RESTART";
7660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_SHUTDOWN_COMP:
7680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "Association change SCTP_SHUTDOWN_COMP";
7690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case SCTP_CANT_STR_ASSOC:
7710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "Association change SCTP_CANT_STR_ASSOC";
7720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    default:
7740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "Association change UNKNOWN";
7750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
7760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
7770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
7780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7792a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.orgvoid SctpDataMediaChannel::OnStreamResetEvent(
7802a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    const struct sctp_stream_reset_event* evt) {
7812a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // A stream reset always involves two RE-CONFIG chunks for us -- we always
7822a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // simultaneously reset a sid's sequence number in both directions.  The
7832a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // requesting side transmits a RE-CONFIG chunk and waits for the peer to send
7842a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // one back.  Both sides get this SCTP_STREAM_RESET_EVENT when they receive
7852a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // RE-CONFIGs.
7862a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  const int num_ssrcs = (evt->strreset_length - sizeof(*evt)) /
7872a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      sizeof(evt->strreset_stream_list[0]);
7882a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
7892a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                  << "): Flags = 0x"
7902a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                  << std::hex << evt->strreset_flags << " ("
7912a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                  << ListFlags(evt->strreset_flags) << ")";
7922a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  LOG(LS_VERBOSE) << "Assoc = " << evt->strreset_assoc_id << ", Streams = ["
7932a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                  << ListArray(evt->strreset_stream_list, num_ssrcs)
7942a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                  << "], Open: ["
7952a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                  << ListStreams(open_streams_) << "], Q'd: ["
7962a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                  << ListStreams(queued_reset_streams_) << "], Sent: ["
7972a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                  << ListStreams(sent_reset_streams_) << "]";
7982a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
7992a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // If both sides try to reset some streams at the same time (even if they're
8002a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // disjoint sets), we can get reset failures.
8012a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  if (evt->strreset_flags & SCTP_STREAM_RESET_FAILED) {
8022a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    // OK, just try again.  The stream IDs sent over when the RESET_FAILED flag
8032a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    // is set seem to be garbage values.  Ignore them.
8042a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    queued_reset_streams_.insert(
8052a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        sent_reset_streams_.begin(),
8062a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        sent_reset_streams_.end());
8072a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    sent_reset_streams_.clear();
8082a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
8092a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  } else if (evt->strreset_flags & SCTP_STREAM_RESET_INCOMING_SSN) {
8102a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    // Each side gets an event for each direction of a stream.  That is,
8112a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    // closing sid k will make each side receive INCOMING and OUTGOING reset
8122a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    // events for k.  As per RFC6525, Section 5, paragraph 2, each side will
8132a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    // get an INCOMING event first.
8142a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    for (int i = 0; i < num_ssrcs; i++) {
8152a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      const int stream_id = evt->strreset_stream_list[i];
8162a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
8172a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      // See if this stream ID was closed by our peer or ourselves.
8182a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      StreamSet::iterator it = sent_reset_streams_.find(stream_id);
8192a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
8202a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      // The reset was requested locally.
8212a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      if (it != sent_reset_streams_.end()) {
8222a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
8232a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                        << "): local sid " << stream_id << " acknowledged.";
8242a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        sent_reset_streams_.erase(it);
8252a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
8262a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      } else if ((it = open_streams_.find(stream_id))
8272a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                 != open_streams_.end()) {
8282a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        // The peer requested the reset.
8292a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
8302a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                        << "): closing sid " << stream_id;
8312a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        open_streams_.erase(it);
832f365c83eeda1a21af3740b70798f6ca65c7bc182buildbot@webrtc.org        SignalStreamClosedRemotely(stream_id);
8332a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
8342a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      } else if ((it = queued_reset_streams_.find(stream_id))
8352a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                 != queued_reset_streams_.end()) {
8362a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        // The peer requested the reset, but there was a local reset
8372a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        // queued.
8382a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
8392a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                        << "): double-sided close for sid " << stream_id;
8402a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        // Both sides want the stream closed, and the peer got to send the
8412a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        // RE-CONFIG first.  Treat it like the local Remove(Send|Recv)Stream
8422a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        // finished quickly.
8432a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        queued_reset_streams_.erase(it);
8442a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
8452a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      } else {
8462a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        // This stream is unknown.  Sometimes this can be from an
8472a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        // RESET_FAILED-related retransmit.
8482a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org        LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
8492a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                        << "): Unknown sid " << stream_id;
8502a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      }
8512a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    }
8522a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  }
8532a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
8542b70e77dba449835b2ebc97bbed56b069af711b1jiayl@webrtc.org  // Always try to send the queued RESET because this call indicates that the
8552b70e77dba449835b2ebc97bbed56b069af711b1jiayl@webrtc.org  // last local RESET or remote RESET has made some progress.
8562b70e77dba449835b2ebc97bbed56b069af711b1jiayl@webrtc.org  SendQueuedStreamResets();
8572a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org}
8582a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
859861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org// Puts the specified |param| from the codec identified by |id| into |dest|
860861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org// and returns true.  Or returns false if it wasn't there, leaving |dest|
861861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org// untouched.
862861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.orgstatic bool GetCodecIntParameter(const std::vector<DataCodec>& codecs,
863861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org                                 int id, const std::string& name,
864861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org                                 const std::string& param, int* dest) {
865861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  std::string value;
866861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  Codec match_pattern;
867861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  match_pattern.id = id;
868861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  match_pattern.name = name;
869861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  for (size_t i = 0; i < codecs.size(); ++i) {
870861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org    if (codecs[i].Matches(match_pattern)) {
871861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org      if (codecs[i].GetParam(param, &value)) {
8722a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org        *dest = rtc::FromString<int>(value);
873861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org        return true;
874861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org      }
875861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org    }
876861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  }
877861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  return false;
878861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org}
879861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org
880861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.orgbool SctpDataMediaChannel::SetSendCodecs(const std::vector<DataCodec>& codecs) {
881861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  return GetCodecIntParameter(
882861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org      codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort,
883861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org      &remote_port_);
884861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org}
885861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org
886861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.orgbool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) {
887861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  return GetCodecIntParameter(
888861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org      codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort,
889861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org      &local_port_);
890861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org}
8910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid SctpDataMediaChannel::OnPacketFromSctpToNetwork(
8932a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org    rtc::Buffer* buffer) {
8940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (buffer->length() > kSctpMtu) {
8950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): "
8962a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                  << "SCTP seems to have made a packet that is bigger "
8970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                     "than its official MTU.";
8980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
8997162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  MediaChannel::SendPacket(buffer);
9000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
9010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9022a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.orgbool SctpDataMediaChannel::SendQueuedStreamResets() {
9032a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  if (!sent_reset_streams_.empty() || queued_reset_streams_.empty())
9042a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    return true;
9052a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
9062a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending ["
9072a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                  << ListStreams(queued_reset_streams_) << "], Open: ["
9082a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                  << ListStreams(open_streams_) << "], Sent: ["
9092a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                  << ListStreams(sent_reset_streams_) << "]";
9102a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
9112a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  const size_t num_streams = queued_reset_streams_.size();
9122a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  const size_t num_bytes = sizeof(struct sctp_reset_streams)
9132a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    + (num_streams * sizeof(uint16));
9142a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
9152a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  std::vector<uint8> reset_stream_buf(num_bytes, 0);
9162a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  struct sctp_reset_streams* resetp = reinterpret_cast<sctp_reset_streams*>(
9172a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      &reset_stream_buf[0]);
9182a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  resetp->srs_assoc_id = SCTP_ALL_ASSOC;
9192a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  resetp->srs_flags = SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_OUTGOING;
9202a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  resetp->srs_number_streams = rtc::checked_cast<uint16_t>(num_streams);
9212a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  int result_idx = 0;
9222a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  for (StreamSet::iterator it = queued_reset_streams_.begin();
9232a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org       it != queued_reset_streams_.end(); ++it) {
9242a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    resetp->srs_stream_list[result_idx++] = *it;
9252a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  }
9262a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
92713a42bcb8b909faef285ec36b59740e5696a2295jiayl@webrtc.org  int ret = usrsctp_setsockopt(
92813a42bcb8b909faef285ec36b59740e5696a2295jiayl@webrtc.org      sock_, IPPROTO_SCTP, SCTP_RESET_STREAMS, resetp,
9292a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org      rtc::checked_cast<socklen_t>(reset_stream_buf.size()));
9302a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  if (ret < 0) {
9312a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to send a stream reset for "
9322a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org                        << num_streams << " streams";
9332a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org    return false;
9342a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  }
9352a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
9362a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // sent_reset_streams_ is empty, and all the queued_reset_streams_ go into
9372a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  // it now.
9382a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  queued_reset_streams_.swap(sent_reset_streams_);
9392a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org  return true;
9402a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org}
9412a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org
9422a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.orgvoid SctpDataMediaChannel::OnMessage(rtc::Message* msg) {
9430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  switch (msg->message_id) {
9440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case MSG_SCTPINBOUNDPACKET: {
9452a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org      rtc::scoped_ptr<InboundPacketMessage> pdata(
9462a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org          static_cast<InboundPacketMessage*>(msg->pdata));
9472a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      OnInboundPacketFromSctpToChannel(pdata->data().get());
9480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
9490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
9500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case MSG_SCTPOUTBOUNDPACKET: {
9512a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org      rtc::scoped_ptr<OutboundPacketMessage> pdata(
9522a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org          static_cast<OutboundPacketMessage*>(msg->pdata));
9532a81a3893cea812cfa676ff7553038078c17f56cwu@webrtc.org      OnPacketFromSctpToNetwork(pdata->data().get());
9540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
9550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
9560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
9570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
9580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}  // namespace cricket
959