Home | History | Annotate | Download | only in sctp
      1 /*
      2  * libjingle
      3  * Copyright 2012 Google Inc. and Robin Seggelmann
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "talk/media/sctp/sctpdataengine.h"
     29 
     30 #include <stdarg.h>
     31 #include <stdio.h>
     32 #include <sstream>
     33 #include <vector>
     34 
     35 #include "talk/media/base/codec.h"
     36 #include "talk/media/base/constants.h"
     37 #include "talk/media/base/streamparams.h"
     38 #include "usrsctplib/usrsctp.h"
     39 #include "webrtc/base/arraysize.h"
     40 #include "webrtc/base/buffer.h"
     41 #include "webrtc/base/helpers.h"
     42 #include "webrtc/base/logging.h"
     43 #include "webrtc/base/safe_conversions.h"
     44 
     45 namespace {
     46 typedef cricket::SctpDataMediaChannel::StreamSet StreamSet;
     47 // Returns a comma-separated, human-readable list of the stream IDs in 's'
     48 std::string ListStreams(const StreamSet& s) {
     49   std::stringstream result;
     50   bool first = true;
     51   for (StreamSet::const_iterator it = s.begin(); it != s.end(); ++it) {
     52     if (!first) {
     53       result << ", " << *it;
     54     } else {
     55       result << *it;
     56       first = false;
     57     }
     58   }
     59   return result.str();
     60 }
     61 
     62 // Returns a pipe-separated, human-readable list of the SCTP_STREAM_RESET
     63 // flags in 'flags'
     64 std::string ListFlags(int flags) {
     65   std::stringstream result;
     66   bool first = true;
     67   // Skip past the first 12 chars (strlen("SCTP_STREAM_"))
     68 #define MAKEFLAG(X) { X, #X + 12}
     69   struct flaginfo_t {
     70     int value;
     71     const char* name;
     72   } flaginfo[] = {
     73     MAKEFLAG(SCTP_STREAM_RESET_INCOMING_SSN),
     74     MAKEFLAG(SCTP_STREAM_RESET_OUTGOING_SSN),
     75     MAKEFLAG(SCTP_STREAM_RESET_DENIED),
     76     MAKEFLAG(SCTP_STREAM_RESET_FAILED),
     77     MAKEFLAG(SCTP_STREAM_CHANGE_DENIED)
     78   };
     79 #undef MAKEFLAG
     80   for (int i = 0; i < arraysize(flaginfo); ++i) {
     81     if (flags & flaginfo[i].value) {
     82       if (!first) result << " | ";
     83       result << flaginfo[i].name;
     84       first = false;
     85     }
     86   }
     87   return result.str();
     88 }
     89 
     90 // Returns a comma-separated, human-readable list of the integers in 'array'.
     91 // All 'num_elems' of them.
     92 std::string ListArray(const uint16_t* array, int num_elems) {
     93   std::stringstream result;
     94   for (int i = 0; i < num_elems; ++i) {
     95     if (i) {
     96       result << ", " << array[i];
     97     } else {
     98       result << array[i];
     99     }
    100   }
    101   return result.str();
    102 }
    103 }  // namespace
    104 
    105 namespace cricket {
    106 typedef rtc::ScopedMessageData<SctpInboundPacket> InboundPacketMessage;
    107 typedef rtc::ScopedMessageData<rtc::Buffer> OutboundPacketMessage;
    108 
    109 // The biggest SCTP packet.  Starting from a 'safe' wire MTU value of 1280,
    110 // take off 80 bytes for DTLS/TURN/TCP/IP overhead.
    111 static const size_t kSctpMtu = 1200;
    112 
    113 // The size of the SCTP association send buffer.  256kB, the usrsctp default.
    114 static const int kSendBufferSize = 262144;
    115 enum {
    116   MSG_SCTPINBOUNDPACKET = 1,   // MessageData is SctpInboundPacket
    117   MSG_SCTPOUTBOUNDPACKET = 2,  // MessageData is rtc:Buffer
    118 };
    119 
    120 struct SctpInboundPacket {
    121   rtc::Buffer buffer;
    122   ReceiveDataParams params;
    123   // The |flags| parameter is used by SCTP to distinguish notification packets
    124   // from other types of packets.
    125   int flags;
    126 };
    127 
    128 // Helper for logging SCTP messages.
    129 static void debug_sctp_printf(const char *format, ...) {
    130   char s[255];
    131   va_list ap;
    132   va_start(ap, format);
    133   vsnprintf(s, sizeof(s), format, ap);
    134   LOG(LS_INFO) << "SCTP: " << s;
    135   va_end(ap);
    136 }
    137 
    138 // Get the PPID to use for the terminating fragment of this type.
    139 static SctpDataMediaChannel::PayloadProtocolIdentifier GetPpid(
    140     cricket::DataMessageType type) {
    141   switch (type) {
    142   default:
    143   case cricket::DMT_NONE:
    144     return SctpDataMediaChannel::PPID_NONE;
    145   case cricket::DMT_CONTROL:
    146     return SctpDataMediaChannel::PPID_CONTROL;
    147   case cricket::DMT_BINARY:
    148     return SctpDataMediaChannel::PPID_BINARY_LAST;
    149   case cricket::DMT_TEXT:
    150     return SctpDataMediaChannel::PPID_TEXT_LAST;
    151   };
    152 }
    153 
    154 static bool GetDataMediaType(
    155     SctpDataMediaChannel::PayloadProtocolIdentifier ppid,
    156     cricket::DataMessageType *dest) {
    157   ASSERT(dest != NULL);
    158   switch (ppid) {
    159     case SctpDataMediaChannel::PPID_BINARY_PARTIAL:
    160     case SctpDataMediaChannel::PPID_BINARY_LAST:
    161       *dest = cricket::DMT_BINARY;
    162       return true;
    163 
    164     case SctpDataMediaChannel::PPID_TEXT_PARTIAL:
    165     case SctpDataMediaChannel::PPID_TEXT_LAST:
    166       *dest = cricket::DMT_TEXT;
    167       return true;
    168 
    169     case SctpDataMediaChannel::PPID_CONTROL:
    170       *dest = cricket::DMT_CONTROL;
    171       return true;
    172 
    173     case SctpDataMediaChannel::PPID_NONE:
    174       *dest = cricket::DMT_NONE;
    175       return true;
    176 
    177     default:
    178       return false;
    179   }
    180 }
    181 
    182 // Log the packet in text2pcap format, if log level is at LS_VERBOSE.
    183 static void VerboseLogPacket(void *data, size_t length, int direction) {
    184   if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) {
    185     char *dump_buf;
    186     if ((dump_buf = usrsctp_dumppacket(
    187              data, length, direction)) != NULL) {
    188       LOG(LS_VERBOSE) << dump_buf;
    189       usrsctp_freedumpbuffer(dump_buf);
    190     }
    191   }
    192 }
    193 
    194 // This is the callback usrsctp uses when there's data to send on the network
    195 // that has been wrapped appropriatly for the SCTP protocol.
    196 static int OnSctpOutboundPacket(void* addr, void* data, size_t length,
    197                                 uint8_t tos, uint8_t set_df) {
    198   SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(addr);
    199   LOG(LS_VERBOSE) << "global OnSctpOutboundPacket():"
    200                   << "addr: " << addr << "; length: " << length
    201                   << "; tos: " << std::hex << static_cast<int>(tos)
    202                   << "; set_df: " << std::hex << static_cast<int>(set_df);
    203 
    204   VerboseLogPacket(addr, length, SCTP_DUMP_OUTBOUND);
    205   // Note: We have to copy the data; the caller will delete it.
    206   auto* msg = new OutboundPacketMessage(
    207       new rtc::Buffer(reinterpret_cast<uint8_t*>(data), length));
    208   channel->worker_thread()->Post(channel, MSG_SCTPOUTBOUNDPACKET, msg);
    209   return 0;
    210 }
    211 
    212 // This is the callback called from usrsctp when data has been received, after
    213 // a packet has been interpreted and parsed by usrsctp and found to contain
    214 // payload data. It is called by a usrsctp thread. It is assumed this function
    215 // will free the memory used by 'data'.
    216 static int OnSctpInboundPacket(struct socket* sock, union sctp_sockstore addr,
    217                                void* data, size_t length,
    218                                struct sctp_rcvinfo rcv, int flags,
    219                                void* ulp_info) {
    220   SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(ulp_info);
    221   // Post data to the channel's receiver thread (copying it).
    222   // TODO(ldixon): Unclear if copy is needed as this method is responsible for
    223   // memory cleanup. But this does simplify code.
    224   const SctpDataMediaChannel::PayloadProtocolIdentifier ppid =
    225       static_cast<SctpDataMediaChannel::PayloadProtocolIdentifier>(
    226           rtc::HostToNetwork32(rcv.rcv_ppid));
    227   cricket::DataMessageType type = cricket::DMT_NONE;
    228   if (!GetDataMediaType(ppid, &type) && !(flags & MSG_NOTIFICATION)) {
    229     // It's neither a notification nor a recognized data packet.  Drop it.
    230     LOG(LS_ERROR) << "Received an unknown PPID " << ppid
    231                   << " on an SCTP packet.  Dropping.";
    232   } else {
    233     SctpInboundPacket* packet = new SctpInboundPacket;
    234     packet->buffer.SetData(reinterpret_cast<uint8_t*>(data), length);
    235     packet->params.ssrc = rcv.rcv_sid;
    236     packet->params.seq_num = rcv.rcv_ssn;
    237     packet->params.timestamp = rcv.rcv_tsn;
    238     packet->params.type = type;
    239     packet->flags = flags;
    240     // The ownership of |packet| transfers to |msg|.
    241     InboundPacketMessage* msg = new InboundPacketMessage(packet);
    242     channel->worker_thread()->Post(channel, MSG_SCTPINBOUNDPACKET, msg);
    243   }
    244   free(data);
    245   return 1;
    246 }
    247 
    248 // Set the initial value of the static SCTP Data Engines reference count.
    249 int SctpDataEngine::usrsctp_engines_count = 0;
    250 
    251 SctpDataEngine::SctpDataEngine() {
    252   if (usrsctp_engines_count == 0) {
    253     // First argument is udp_encapsulation_port, which is not releveant for our
    254     // AF_CONN use of sctp.
    255     usrsctp_init(0, cricket::OnSctpOutboundPacket, debug_sctp_printf);
    256 
    257     // To turn on/off detailed SCTP debugging. You will also need to have the
    258     // SCTP_DEBUG cpp defines flag.
    259     // usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
    260 
    261     // TODO(ldixon): Consider turning this on/off.
    262     usrsctp_sysctl_set_sctp_ecn_enable(0);
    263 
    264     // This is harmless, but we should find out when the library default
    265     // changes.
    266     int send_size = usrsctp_sysctl_get_sctp_sendspace();
    267     if (send_size != kSendBufferSize) {
    268       LOG(LS_ERROR) << "Got different send size than expected: " << send_size;
    269     }
    270 
    271     // TODO(ldixon): Consider turning this on/off.
    272     // This is not needed right now (we don't do dynamic address changes):
    273     // If SCTP Auto-ASCONF is enabled, the peer is informed automatically
    274     // when a new address is added or removed. This feature is enabled by
    275     // default.
    276     // usrsctp_sysctl_set_sctp_auto_asconf(0);
    277 
    278     // TODO(ldixon): Consider turning this on/off.
    279     // Add a blackhole sysctl. Setting it to 1 results in no ABORTs
    280     // being sent in response to INITs, setting it to 2 results
    281     // in no ABORTs being sent for received OOTB packets.
    282     // This is similar to the TCP sysctl.
    283     //
    284     // See: http://lakerest.net/pipermail/sctp-coders/2012-January/009438.html
    285     // See: http://svnweb.freebsd.org/base?view=revision&revision=229805
    286     // usrsctp_sysctl_set_sctp_blackhole(2);
    287 
    288     // Set the number of default outgoing streams.  This is the number we'll
    289     // send in the SCTP INIT message.  The 'appropriate default' in the
    290     // second paragraph of
    291     // http://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-05#section-6.2
    292     // is cricket::kMaxSctpSid.
    293     usrsctp_sysctl_set_sctp_nr_outgoing_streams_default(
    294         cricket::kMaxSctpSid);
    295   }
    296   usrsctp_engines_count++;
    297 
    298   cricket::DataCodec codec(kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, 0);
    299   codec.SetParam(kCodecParamPort, kSctpDefaultPort);
    300   codecs_.push_back(codec);
    301 }
    302 
    303 SctpDataEngine::~SctpDataEngine() {
    304   usrsctp_engines_count--;
    305   LOG(LS_VERBOSE) << "usrsctp_engines_count:" << usrsctp_engines_count;
    306 
    307   if (usrsctp_engines_count == 0) {
    308     // usrsctp_finish() may fail if it's called too soon after the channels are
    309     // closed. Wait and try again until it succeeds for up to 3 seconds.
    310     for (size_t i = 0; i < 300; ++i) {
    311       if (usrsctp_finish() == 0)
    312         return;
    313 
    314       rtc::Thread::SleepMs(10);
    315     }
    316     LOG(LS_ERROR) << "Failed to shutdown usrsctp.";
    317   }
    318 }
    319 
    320 DataMediaChannel* SctpDataEngine::CreateChannel(
    321     DataChannelType data_channel_type) {
    322   if (data_channel_type != DCT_SCTP) {
    323     return NULL;
    324   }
    325   return new SctpDataMediaChannel(rtc::Thread::Current());
    326 }
    327 
    328 // static
    329 SctpDataMediaChannel* SctpDataEngine::GetChannelFromSocket(
    330     struct socket* sock) {
    331   struct sockaddr* addrs = nullptr;
    332   int naddrs = usrsctp_getladdrs(sock, 0, &addrs);
    333   if (naddrs <= 0 || addrs[0].sa_family != AF_CONN) {
    334     return nullptr;
    335   }
    336   // usrsctp_getladdrs() returns the addresses bound to this socket, which
    337   // contains the SctpDataMediaChannel* as sconn_addr.  Read the pointer,
    338   // then free the list of addresses once we have the pointer.  We only open
    339   // AF_CONN sockets, and they should all have the sconn_addr set to the
    340   // pointer that created them, so [0] is as good as any other.
    341   struct sockaddr_conn* sconn =
    342       reinterpret_cast<struct sockaddr_conn*>(&addrs[0]);
    343   SctpDataMediaChannel* channel =
    344       reinterpret_cast<SctpDataMediaChannel*>(sconn->sconn_addr);
    345   usrsctp_freeladdrs(addrs);
    346 
    347   return channel;
    348 }
    349 
    350 // static
    351 int SctpDataEngine::SendThresholdCallback(struct socket* sock,
    352                                           uint32_t sb_free) {
    353   // Fired on our I/O thread.  SctpDataMediaChannel::OnPacketReceived() gets
    354   // a packet containing acknowledgments, which goes into usrsctp_conninput,
    355   // and then back here.
    356   SctpDataMediaChannel* channel = GetChannelFromSocket(sock);
    357   if (!channel) {
    358     LOG(LS_ERROR) << "SendThresholdCallback: Failed to get channel for socket "
    359                   << sock;
    360     return 0;
    361   }
    362   channel->OnSendThresholdCallback();
    363   return 0;
    364 }
    365 
    366 SctpDataMediaChannel::SctpDataMediaChannel(rtc::Thread* thread)
    367     : worker_thread_(thread),
    368       local_port_(kSctpDefaultPort),
    369       remote_port_(kSctpDefaultPort),
    370       sock_(NULL),
    371       sending_(false),
    372       receiving_(false),
    373       debug_name_("SctpDataMediaChannel") {
    374 }
    375 
    376 SctpDataMediaChannel::~SctpDataMediaChannel() {
    377   CloseSctpSocket();
    378 }
    379 
    380 void SctpDataMediaChannel::OnSendThresholdCallback() {
    381   RTC_DCHECK(rtc::Thread::Current() == worker_thread_);
    382   SignalReadyToSend(true);
    383 }
    384 
    385 sockaddr_conn SctpDataMediaChannel::GetSctpSockAddr(int port) {
    386   sockaddr_conn sconn = {0};
    387   sconn.sconn_family = AF_CONN;
    388 #ifdef HAVE_SCONN_LEN
    389   sconn.sconn_len = sizeof(sockaddr_conn);
    390 #endif
    391   // Note: conversion from int to uint16_t happens here.
    392   sconn.sconn_port = rtc::HostToNetwork16(port);
    393   sconn.sconn_addr = this;
    394   return sconn;
    395 }
    396 
    397 bool SctpDataMediaChannel::OpenSctpSocket() {
    398   if (sock_) {
    399     LOG(LS_VERBOSE) << debug_name_
    400                     << "->Ignoring attempt to re-create existing socket.";
    401     return false;
    402   }
    403 
    404   // If kSendBufferSize isn't reflective of reality, we log an error, but we
    405   // still have to do something reasonable here.  Look up what the buffer's
    406   // real size is and set our threshold to something reasonable.
    407   const static int kSendThreshold = usrsctp_sysctl_get_sctp_sendspace() / 2;
    408 
    409   sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP,
    410                          cricket::OnSctpInboundPacket,
    411                          &SctpDataEngine::SendThresholdCallback,
    412                          kSendThreshold, this);
    413   if (!sock_) {
    414     LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket.";
    415     return false;
    416   }
    417 
    418   // Make the socket non-blocking. Connect, close, shutdown etc will not block
    419   // the thread waiting for the socket operation to complete.
    420   if (usrsctp_set_non_blocking(sock_, 1) < 0) {
    421     LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking.";
    422     return false;
    423   }
    424 
    425   // This ensures that the usrsctp close call deletes the association. This
    426   // prevents usrsctp from calling OnSctpOutboundPacket with references to
    427   // this class as the address.
    428   linger linger_opt;
    429   linger_opt.l_onoff = 1;
    430   linger_opt.l_linger = 0;
    431   if (usrsctp_setsockopt(sock_, SOL_SOCKET, SO_LINGER, &linger_opt,
    432                          sizeof(linger_opt))) {
    433     LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SO_LINGER.";
    434     return false;
    435   }
    436 
    437   // Enable stream ID resets.
    438   struct sctp_assoc_value stream_rst;
    439   stream_rst.assoc_id = SCTP_ALL_ASSOC;
    440   stream_rst.assoc_value = 1;
    441   if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET,
    442                          &stream_rst, sizeof(stream_rst))) {
    443     LOG_ERRNO(LS_ERROR) << debug_name_
    444                         << "Failed to set SCTP_ENABLE_STREAM_RESET.";
    445     return false;
    446   }
    447 
    448   // Nagle.
    449   uint32_t nodelay = 1;
    450   if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay,
    451                          sizeof(nodelay))) {
    452     LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_NODELAY.";
    453     return false;
    454   }
    455 
    456   // Disable MTU discovery
    457   sctp_paddrparams params = {{0}};
    458   params.spp_assoc_id = 0;
    459   params.spp_flags = SPP_PMTUD_DISABLE;
    460   params.spp_pathmtu = kSctpMtu;
    461   if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &params,
    462       sizeof(params))) {
    463     LOG_ERRNO(LS_ERROR) << debug_name_
    464                         << "Failed to set SCTP_PEER_ADDR_PARAMS.";
    465     return false;
    466   }
    467 
    468   // Subscribe to SCTP event notifications.
    469   int event_types[] = {SCTP_ASSOC_CHANGE,
    470                        SCTP_PEER_ADDR_CHANGE,
    471                        SCTP_SEND_FAILED_EVENT,
    472                        SCTP_SENDER_DRY_EVENT,
    473                        SCTP_STREAM_RESET_EVENT};
    474   struct sctp_event event = {0};
    475   event.se_assoc_id = SCTP_ALL_ASSOC;
    476   event.se_on = 1;
    477   for (size_t i = 0; i < arraysize(event_types); i++) {
    478     event.se_type = event_types[i];
    479     if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_EVENT, &event,
    480                            sizeof(event)) < 0) {
    481       LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_EVENT type: "
    482                           << event.se_type;
    483       return false;
    484     }
    485   }
    486 
    487   // Register this class as an address for usrsctp. This is used by SCTP to
    488   // direct the packets received (by the created socket) to this class.
    489   usrsctp_register_address(this);
    490   sending_ = true;
    491   return true;
    492 }
    493 
    494 void SctpDataMediaChannel::CloseSctpSocket() {
    495   sending_ = false;
    496   if (sock_) {
    497     // We assume that SO_LINGER option is set to close the association when
    498     // close is called. This means that any pending packets in usrsctp will be
    499     // discarded instead of being sent.
    500     usrsctp_close(sock_);
    501     sock_ = NULL;
    502     usrsctp_deregister_address(this);
    503   }
    504 }
    505 
    506 bool SctpDataMediaChannel::Connect() {
    507   LOG(LS_VERBOSE) << debug_name_ << "->Connect().";
    508 
    509   // If we already have a socket connection, just return.
    510   if (sock_) {
    511     LOG(LS_WARNING) << debug_name_ << "->Connect(): Ignored as socket "
    512                                       "is already established.";
    513     return true;
    514   }
    515 
    516   // If no socket (it was closed) try to start it again. This can happen when
    517   // the socket we are connecting to closes, does an sctp shutdown handshake,
    518   // or behaves unexpectedly causing us to perform a CloseSctpSocket.
    519   if (!sock_ && !OpenSctpSocket()) {
    520     return false;
    521   }
    522 
    523   // Note: conversion from int to uint16_t happens on assignment.
    524   sockaddr_conn local_sconn = GetSctpSockAddr(local_port_);
    525   if (usrsctp_bind(sock_, reinterpret_cast<sockaddr *>(&local_sconn),
    526                    sizeof(local_sconn)) < 0) {
    527     LOG_ERRNO(LS_ERROR) << debug_name_ << "->Connect(): "
    528                         << ("Failed usrsctp_bind");
    529     CloseSctpSocket();
    530     return false;
    531   }
    532 
    533   // Note: conversion from int to uint16_t happens on assignment.
    534   sockaddr_conn remote_sconn = GetSctpSockAddr(remote_port_);
    535   int connect_result = usrsctp_connect(
    536       sock_, reinterpret_cast<sockaddr *>(&remote_sconn), sizeof(remote_sconn));
    537   if (connect_result < 0 && errno != SCTP_EINPROGRESS) {
    538     LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed usrsctp_connect. got errno="
    539                         << errno << ", but wanted " << SCTP_EINPROGRESS;
    540     CloseSctpSocket();
    541     return false;
    542   }
    543   return true;
    544 }
    545 
    546 void SctpDataMediaChannel::Disconnect() {
    547   // TODO(ldixon): Consider calling |usrsctp_shutdown(sock_, ...)| to do a
    548   // shutdown handshake and remove the association.
    549   CloseSctpSocket();
    550 }
    551 
    552 bool SctpDataMediaChannel::SetSend(bool send) {
    553   if (!sending_ && send) {
    554     return Connect();
    555   }
    556   if (sending_ && !send) {
    557     Disconnect();
    558   }
    559   return true;
    560 }
    561 
    562 bool SctpDataMediaChannel::SetReceive(bool receive) {
    563   receiving_ = receive;
    564   return true;
    565 }
    566 
    567 bool SctpDataMediaChannel::SetSendParameters(const DataSendParameters& params) {
    568   return SetSendCodecs(params.codecs);
    569 }
    570 
    571 bool SctpDataMediaChannel::SetRecvParameters(const DataRecvParameters& params) {
    572   return SetRecvCodecs(params.codecs);
    573 }
    574 
    575 bool SctpDataMediaChannel::AddSendStream(const StreamParams& stream) {
    576   return AddStream(stream);
    577 }
    578 
    579 bool SctpDataMediaChannel::RemoveSendStream(uint32_t ssrc) {
    580   return ResetStream(ssrc);
    581 }
    582 
    583 bool SctpDataMediaChannel::AddRecvStream(const StreamParams& stream) {
    584   // SCTP DataChannels are always bi-directional and calling AddSendStream will
    585   // enable both sending and receiving on the stream. So AddRecvStream is a
    586   // no-op.
    587   return true;
    588 }
    589 
    590 bool SctpDataMediaChannel::RemoveRecvStream(uint32_t ssrc) {
    591   // SCTP DataChannels are always bi-directional and calling RemoveSendStream
    592   // will disable both sending and receiving on the stream. So RemoveRecvStream
    593   // is a no-op.
    594   return true;
    595 }
    596 
    597 bool SctpDataMediaChannel::SendData(
    598     const SendDataParams& params,
    599     const rtc::Buffer& payload,
    600     SendDataResult* result) {
    601   if (result) {
    602     // Preset |result| to assume an error.  If SendData succeeds, we'll
    603     // overwrite |*result| once more at the end.
    604     *result = SDR_ERROR;
    605   }
    606 
    607   if (!sending_) {
    608     LOG(LS_WARNING) << debug_name_ << "->SendData(...): "
    609                     << "Not sending packet with ssrc=" << params.ssrc
    610                     << " len=" << payload.size() << " before SetSend(true).";
    611     return false;
    612   }
    613 
    614   if (params.type != cricket::DMT_CONTROL &&
    615       open_streams_.find(params.ssrc) == open_streams_.end()) {
    616     LOG(LS_WARNING) << debug_name_ << "->SendData(...): "
    617                     << "Not sending data because ssrc is unknown: "
    618                     << params.ssrc;
    619     return false;
    620   }
    621 
    622   //
    623   // Send data using SCTP.
    624   ssize_t send_res = 0;  // result from usrsctp_sendv.
    625   struct sctp_sendv_spa spa = {0};
    626   spa.sendv_flags |= SCTP_SEND_SNDINFO_VALID;
    627   spa.sendv_sndinfo.snd_sid = params.ssrc;
    628   spa.sendv_sndinfo.snd_ppid = rtc::HostToNetwork32(
    629       GetPpid(params.type));
    630 
    631   // Ordered implies reliable.
    632   if (!params.ordered) {
    633     spa.sendv_sndinfo.snd_flags |= SCTP_UNORDERED;
    634     if (params.max_rtx_count >= 0 || params.max_rtx_ms == 0) {
    635       spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
    636       spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
    637       spa.sendv_prinfo.pr_value = params.max_rtx_count;
    638     } else {
    639       spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
    640       spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL;
    641       spa.sendv_prinfo.pr_value = params.max_rtx_ms;
    642     }
    643   }
    644 
    645   // We don't fragment.
    646   send_res = usrsctp_sendv(
    647       sock_, payload.data(), static_cast<size_t>(payload.size()), NULL, 0, &spa,
    648       rtc::checked_cast<socklen_t>(sizeof(spa)), SCTP_SENDV_SPA, 0);
    649   if (send_res < 0) {
    650     if (errno == SCTP_EWOULDBLOCK) {
    651       *result = SDR_BLOCK;
    652       LOG(LS_INFO) << debug_name_ << "->SendData(...): EWOULDBLOCK returned";
    653     } else {
    654       LOG_ERRNO(LS_ERROR) << "ERROR:" << debug_name_
    655                           << "->SendData(...): "
    656                           << " usrsctp_sendv: ";
    657     }
    658     return false;
    659   }
    660   if (result) {
    661     // Only way out now is success.
    662     *result = SDR_SUCCESS;
    663   }
    664   return true;
    665 }
    666 
    667 // Called by network interface when a packet has been received.
    668 void SctpDataMediaChannel::OnPacketReceived(
    669     rtc::Buffer* packet, const rtc::PacketTime& packet_time) {
    670   RTC_DCHECK(rtc::Thread::Current() == worker_thread_);
    671   LOG(LS_VERBOSE) << debug_name_ << "->OnPacketReceived(...): "
    672                   << " length=" << packet->size() << ", sending: " << sending_;
    673   // Only give receiving packets to usrsctp after if connected. This enables two
    674   // peers to each make a connect call, but for them not to receive an INIT
    675   // packet before they have called connect; least the last receiver of the INIT
    676   // packet will have called connect, and a connection will be established.
    677   if (sending_) {
    678     // Pass received packet to SCTP stack. Once processed by usrsctp, the data
    679     // will be will be given to the global OnSctpInboundData, and then,
    680     // marshalled by a Post and handled with OnMessage.
    681     VerboseLogPacket(packet->data(), packet->size(), SCTP_DUMP_INBOUND);
    682     usrsctp_conninput(this, packet->data(), packet->size(), 0);
    683   } else {
    684     // TODO(ldixon): Consider caching the packet for very slightly better
    685     // reliability.
    686   }
    687 }
    688 
    689 void SctpDataMediaChannel::OnInboundPacketFromSctpToChannel(
    690     SctpInboundPacket* packet) {
    691   LOG(LS_VERBOSE) << debug_name_ << "->OnInboundPacketFromSctpToChannel(...): "
    692                   << "Received SCTP data:"
    693                   << " ssrc=" << packet->params.ssrc
    694                   << " notification: " << (packet->flags & MSG_NOTIFICATION)
    695                   << " length=" << packet->buffer.size();
    696   // Sending a packet with data == NULL (no data) is SCTPs "close the
    697   // connection" message. This sets sock_ = NULL;
    698   if (!packet->buffer.size() || !packet->buffer.data()) {
    699     LOG(LS_INFO) << debug_name_ << "->OnInboundPacketFromSctpToChannel(...): "
    700                                    "No data, closing.";
    701     return;
    702   }
    703   if (packet->flags & MSG_NOTIFICATION) {
    704     OnNotificationFromSctp(&packet->buffer);
    705   } else {
    706     OnDataFromSctpToChannel(packet->params, &packet->buffer);
    707   }
    708 }
    709 
    710 void SctpDataMediaChannel::OnDataFromSctpToChannel(
    711     const ReceiveDataParams& params, rtc::Buffer* buffer) {
    712   if (receiving_) {
    713     LOG(LS_VERBOSE) << debug_name_ << "->OnDataFromSctpToChannel(...): "
    714                     << "Posting with length: " << buffer->size()
    715                     << " on stream " << params.ssrc;
    716     // Reports all received messages to upper layers, no matter whether the sid
    717     // is known.
    718     SignalDataReceived(params, buffer->data<char>(), buffer->size());
    719   } else {
    720     LOG(LS_WARNING) << debug_name_ << "->OnDataFromSctpToChannel(...): "
    721                     << "Not receiving packet with sid=" << params.ssrc
    722                     << " len=" << buffer->size() << " before SetReceive(true).";
    723   }
    724 }
    725 
    726 bool SctpDataMediaChannel::AddStream(const StreamParams& stream) {
    727   if (!stream.has_ssrcs()) {
    728     return false;
    729   }
    730 
    731   const uint32_t ssrc = stream.first_ssrc();
    732   if (ssrc >= cricket::kMaxSctpSid) {
    733     LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
    734                     << "Not adding data stream '" << stream.id
    735                     << "' with ssrc=" << ssrc
    736                     << " because stream ssrc is too high.";
    737     return false;
    738   } else if (open_streams_.find(ssrc) != open_streams_.end()) {
    739     LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
    740                     << "Not adding data stream '" << stream.id
    741                     << "' with ssrc=" << ssrc
    742                     << " because stream is already open.";
    743     return false;
    744   } else if (queued_reset_streams_.find(ssrc) != queued_reset_streams_.end()
    745              || sent_reset_streams_.find(ssrc) != sent_reset_streams_.end()) {
    746     LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
    747                     << "Not adding data stream '" << stream.id
    748                     << "' with ssrc=" << ssrc
    749                     << " because stream is still closing.";
    750     return false;
    751   }
    752 
    753   open_streams_.insert(ssrc);
    754   return true;
    755 }
    756 
    757 bool SctpDataMediaChannel::ResetStream(uint32_t ssrc) {
    758   // We typically get this called twice for the same stream, once each for
    759   // Send and Recv.
    760   StreamSet::iterator found = open_streams_.find(ssrc);
    761 
    762   if (found == open_streams_.end()) {
    763     LOG(LS_VERBOSE) << debug_name_ << "->ResetStream(" << ssrc << "): "
    764                     << "stream not found.";
    765     return false;
    766   } else {
    767     LOG(LS_VERBOSE) << debug_name_ << "->ResetStream(" << ssrc << "): "
    768                     << "Removing and queuing RE-CONFIG chunk.";
    769     open_streams_.erase(found);
    770   }
    771 
    772   // SCTP won't let you have more than one stream reset pending at a time, but
    773   // you can close multiple streams in a single reset.  So, we keep an internal
    774   // queue of streams-to-reset, and send them as one reset message in
    775   // SendQueuedStreamResets().
    776   queued_reset_streams_.insert(ssrc);
    777 
    778   // Signal our stream-reset logic that it should try to send now, if it can.
    779   SendQueuedStreamResets();
    780 
    781   // The stream will actually get removed when we get the acknowledgment.
    782   return true;
    783 }
    784 
    785 void SctpDataMediaChannel::OnNotificationFromSctp(rtc::Buffer* buffer) {
    786   const sctp_notification& notification =
    787       reinterpret_cast<const sctp_notification&>(*buffer->data());
    788   ASSERT(notification.sn_header.sn_length == buffer->size());
    789 
    790   // TODO(ldixon): handle notifications appropriately.
    791   switch (notification.sn_header.sn_type) {
    792     case SCTP_ASSOC_CHANGE:
    793       LOG(LS_VERBOSE) << "SCTP_ASSOC_CHANGE";
    794       OnNotificationAssocChange(notification.sn_assoc_change);
    795       break;
    796     case SCTP_REMOTE_ERROR:
    797       LOG(LS_INFO) << "SCTP_REMOTE_ERROR";
    798       break;
    799     case SCTP_SHUTDOWN_EVENT:
    800       LOG(LS_INFO) << "SCTP_SHUTDOWN_EVENT";
    801       break;
    802     case SCTP_ADAPTATION_INDICATION:
    803       LOG(LS_INFO) << "SCTP_ADAPTATION_INDICATION";
    804       break;
    805     case SCTP_PARTIAL_DELIVERY_EVENT:
    806       LOG(LS_INFO) << "SCTP_PARTIAL_DELIVERY_EVENT";
    807       break;
    808     case SCTP_AUTHENTICATION_EVENT:
    809       LOG(LS_INFO) << "SCTP_AUTHENTICATION_EVENT";
    810       break;
    811     case SCTP_SENDER_DRY_EVENT:
    812       LOG(LS_VERBOSE) << "SCTP_SENDER_DRY_EVENT";
    813       SignalReadyToSend(true);
    814       break;
    815     // TODO(ldixon): Unblock after congestion.
    816     case SCTP_NOTIFICATIONS_STOPPED_EVENT:
    817       LOG(LS_INFO) << "SCTP_NOTIFICATIONS_STOPPED_EVENT";
    818       break;
    819     case SCTP_SEND_FAILED_EVENT:
    820       LOG(LS_INFO) << "SCTP_SEND_FAILED_EVENT";
    821       break;
    822     case SCTP_STREAM_RESET_EVENT:
    823       OnStreamResetEvent(&notification.sn_strreset_event);
    824       break;
    825     case SCTP_ASSOC_RESET_EVENT:
    826       LOG(LS_INFO) << "SCTP_ASSOC_RESET_EVENT";
    827       break;
    828     case SCTP_STREAM_CHANGE_EVENT:
    829       LOG(LS_INFO) << "SCTP_STREAM_CHANGE_EVENT";
    830       // An acknowledgment we get after our stream resets have gone through,
    831       // if they've failed.  We log the message, but don't react -- we don't
    832       // keep around the last-transmitted set of SSIDs we wanted to close for
    833       // error recovery.  It doesn't seem likely to occur, and if so, likely
    834       // harmless within the lifetime of a single SCTP association.
    835       break;
    836     default:
    837       LOG(LS_WARNING) << "Unknown SCTP event: "
    838                       << notification.sn_header.sn_type;
    839       break;
    840   }
    841 }
    842 
    843 void SctpDataMediaChannel::OnNotificationAssocChange(
    844     const sctp_assoc_change& change) {
    845   switch (change.sac_state) {
    846     case SCTP_COMM_UP:
    847       LOG(LS_VERBOSE) << "Association change SCTP_COMM_UP";
    848       break;
    849     case SCTP_COMM_LOST:
    850       LOG(LS_INFO) << "Association change SCTP_COMM_LOST";
    851       break;
    852     case SCTP_RESTART:
    853       LOG(LS_INFO) << "Association change SCTP_RESTART";
    854       break;
    855     case SCTP_SHUTDOWN_COMP:
    856       LOG(LS_INFO) << "Association change SCTP_SHUTDOWN_COMP";
    857       break;
    858     case SCTP_CANT_STR_ASSOC:
    859       LOG(LS_INFO) << "Association change SCTP_CANT_STR_ASSOC";
    860       break;
    861     default:
    862       LOG(LS_INFO) << "Association change UNKNOWN";
    863       break;
    864   }
    865 }
    866 
    867 void SctpDataMediaChannel::OnStreamResetEvent(
    868     const struct sctp_stream_reset_event* evt) {
    869   // A stream reset always involves two RE-CONFIG chunks for us -- we always
    870   // simultaneously reset a sid's sequence number in both directions.  The
    871   // requesting side transmits a RE-CONFIG chunk and waits for the peer to send
    872   // one back.  Both sides get this SCTP_STREAM_RESET_EVENT when they receive
    873   // RE-CONFIGs.
    874   const int num_ssrcs = (evt->strreset_length - sizeof(*evt)) /
    875       sizeof(evt->strreset_stream_list[0]);
    876   LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
    877                   << "): Flags = 0x"
    878                   << std::hex << evt->strreset_flags << " ("
    879                   << ListFlags(evt->strreset_flags) << ")";
    880   LOG(LS_VERBOSE) << "Assoc = " << evt->strreset_assoc_id << ", Streams = ["
    881                   << ListArray(evt->strreset_stream_list, num_ssrcs)
    882                   << "], Open: ["
    883                   << ListStreams(open_streams_) << "], Q'd: ["
    884                   << ListStreams(queued_reset_streams_) << "], Sent: ["
    885                   << ListStreams(sent_reset_streams_) << "]";
    886 
    887   // If both sides try to reset some streams at the same time (even if they're
    888   // disjoint sets), we can get reset failures.
    889   if (evt->strreset_flags & SCTP_STREAM_RESET_FAILED) {
    890     // OK, just try again.  The stream IDs sent over when the RESET_FAILED flag
    891     // is set seem to be garbage values.  Ignore them.
    892     queued_reset_streams_.insert(
    893         sent_reset_streams_.begin(),
    894         sent_reset_streams_.end());
    895     sent_reset_streams_.clear();
    896 
    897   } else if (evt->strreset_flags & SCTP_STREAM_RESET_INCOMING_SSN) {
    898     // Each side gets an event for each direction of a stream.  That is,
    899     // closing sid k will make each side receive INCOMING and OUTGOING reset
    900     // events for k.  As per RFC6525, Section 5, paragraph 2, each side will
    901     // get an INCOMING event first.
    902     for (int i = 0; i < num_ssrcs; i++) {
    903       const int stream_id = evt->strreset_stream_list[i];
    904 
    905       // See if this stream ID was closed by our peer or ourselves.
    906       StreamSet::iterator it = sent_reset_streams_.find(stream_id);
    907 
    908       // The reset was requested locally.
    909       if (it != sent_reset_streams_.end()) {
    910         LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
    911                         << "): local sid " << stream_id << " acknowledged.";
    912         sent_reset_streams_.erase(it);
    913 
    914       } else if ((it = open_streams_.find(stream_id))
    915                  != open_streams_.end()) {
    916         // The peer requested the reset.
    917         LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
    918                         << "): closing sid " << stream_id;
    919         open_streams_.erase(it);
    920         SignalStreamClosedRemotely(stream_id);
    921 
    922       } else if ((it = queued_reset_streams_.find(stream_id))
    923                  != queued_reset_streams_.end()) {
    924         // The peer requested the reset, but there was a local reset
    925         // queued.
    926         LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
    927                         << "): double-sided close for sid " << stream_id;
    928         // Both sides want the stream closed, and the peer got to send the
    929         // RE-CONFIG first.  Treat it like the local Remove(Send|Recv)Stream
    930         // finished quickly.
    931         queued_reset_streams_.erase(it);
    932 
    933       } else {
    934         // This stream is unknown.  Sometimes this can be from an
    935         // RESET_FAILED-related retransmit.
    936         LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
    937                         << "): Unknown sid " << stream_id;
    938       }
    939     }
    940   }
    941 
    942   // Always try to send the queued RESET because this call indicates that the
    943   // last local RESET or remote RESET has made some progress.
    944   SendQueuedStreamResets();
    945 }
    946 
    947 // Puts the specified |param| from the codec identified by |id| into |dest|
    948 // and returns true.  Or returns false if it wasn't there, leaving |dest|
    949 // untouched.
    950 static bool GetCodecIntParameter(const std::vector<DataCodec>& codecs,
    951                                  int id, const std::string& name,
    952                                  const std::string& param, int* dest) {
    953   std::string value;
    954   Codec match_pattern;
    955   match_pattern.id = id;
    956   match_pattern.name = name;
    957   for (size_t i = 0; i < codecs.size(); ++i) {
    958     if (codecs[i].Matches(match_pattern)) {
    959       if (codecs[i].GetParam(param, &value)) {
    960         *dest = rtc::FromString<int>(value);
    961         return true;
    962       }
    963     }
    964   }
    965   return false;
    966 }
    967 
    968 bool SctpDataMediaChannel::SetSendCodecs(const std::vector<DataCodec>& codecs) {
    969   return GetCodecIntParameter(
    970       codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort,
    971       &remote_port_);
    972 }
    973 
    974 bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) {
    975   return GetCodecIntParameter(
    976       codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort,
    977       &local_port_);
    978 }
    979 
    980 void SctpDataMediaChannel::OnPacketFromSctpToNetwork(
    981     rtc::Buffer* buffer) {
    982   // usrsctp seems to interpret the MTU we give it strangely -- it seems to
    983   // give us back packets bigger than that MTU, if only by a fixed amount.
    984   // This is that amount that we've observed.
    985   const int kSctpOverhead = 76;
    986   if (buffer->size() > (kSctpOverhead + kSctpMtu)) {
    987     LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): "
    988                   << "SCTP seems to have made a packet that is bigger "
    989                   << "than its official MTU: " << buffer->size()
    990                   << " vs max of " << kSctpMtu
    991                   << " even after adding " << kSctpOverhead
    992                   << " extra SCTP overhead";
    993   }
    994   MediaChannel::SendPacket(buffer, rtc::PacketOptions());
    995 }
    996 
    997 bool SctpDataMediaChannel::SendQueuedStreamResets() {
    998   if (!sent_reset_streams_.empty() || queued_reset_streams_.empty())
    999     return true;
   1000 
   1001   LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending ["
   1002                   << ListStreams(queued_reset_streams_) << "], Open: ["
   1003                   << ListStreams(open_streams_) << "], Sent: ["
   1004                   << ListStreams(sent_reset_streams_) << "]";
   1005 
   1006   const size_t num_streams = queued_reset_streams_.size();
   1007   const size_t num_bytes =
   1008       sizeof(struct sctp_reset_streams) + (num_streams * sizeof(uint16_t));
   1009 
   1010   std::vector<uint8_t> reset_stream_buf(num_bytes, 0);
   1011   struct sctp_reset_streams* resetp = reinterpret_cast<sctp_reset_streams*>(
   1012       &reset_stream_buf[0]);
   1013   resetp->srs_assoc_id = SCTP_ALL_ASSOC;
   1014   resetp->srs_flags = SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_OUTGOING;
   1015   resetp->srs_number_streams = rtc::checked_cast<uint16_t>(num_streams);
   1016   int result_idx = 0;
   1017   for (StreamSet::iterator it = queued_reset_streams_.begin();
   1018        it != queued_reset_streams_.end(); ++it) {
   1019     resetp->srs_stream_list[result_idx++] = *it;
   1020   }
   1021 
   1022   int ret = usrsctp_setsockopt(
   1023       sock_, IPPROTO_SCTP, SCTP_RESET_STREAMS, resetp,
   1024       rtc::checked_cast<socklen_t>(reset_stream_buf.size()));
   1025   if (ret < 0) {
   1026     LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to send a stream reset for "
   1027                         << num_streams << " streams";
   1028     return false;
   1029   }
   1030 
   1031   // sent_reset_streams_ is empty, and all the queued_reset_streams_ go into
   1032   // it now.
   1033   queued_reset_streams_.swap(sent_reset_streams_);
   1034   return true;
   1035 }
   1036 
   1037 void SctpDataMediaChannel::OnMessage(rtc::Message* msg) {
   1038   switch (msg->message_id) {
   1039     case MSG_SCTPINBOUNDPACKET: {
   1040       rtc::scoped_ptr<InboundPacketMessage> pdata(
   1041           static_cast<InboundPacketMessage*>(msg->pdata));
   1042       OnInboundPacketFromSctpToChannel(pdata->data().get());
   1043       break;
   1044     }
   1045     case MSG_SCTPOUTBOUNDPACKET: {
   1046       rtc::scoped_ptr<OutboundPacketMessage> pdata(
   1047           static_cast<OutboundPacketMessage*>(msg->pdata));
   1048       OnPacketFromSctpToNetwork(pdata->data().get());
   1049       break;
   1050     }
   1051   }
   1052 }
   1053 }  // namespace cricket
   1054