tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SipccSdpMediaSection.cpp (12812B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "sdp/SipccSdpMediaSection.h"
      8 
      9 #include <ostream>
     10 
     11 #include "sdp/SdpParser.h"
     12 
     13 extern "C" {
     14 #include "sipcc_sdp.h"
     15 }
     16 
     17 #ifdef CRLF
     18 #  undef CRLF
     19 #endif
     20 #define CRLF "\r\n"
     21 
     22 namespace mozilla {
     23 
     24 SipccSdpMediaSection::SipccSdpMediaSection(
     25    const SipccSdpMediaSection& aOrig,
     26    const SipccSdpAttributeList* sessionLevel)
     27    : SdpMediaSection(aOrig),
     28      mMediaType(aOrig.mMediaType),
     29      mPort(aOrig.mPort),
     30      mPortCount(aOrig.mPortCount),
     31      mProtocol(aOrig.mProtocol),
     32      mFormats(aOrig.mFormats),
     33      mConnection(new SdpConnection(*aOrig.mConnection)),
     34      mBandwidths(aOrig.mBandwidths),
     35      mAttributeList(aOrig.mAttributeList, sessionLevel) {}
     36 
     37 unsigned int SipccSdpMediaSection::GetPort() const { return mPort; }
     38 
     39 void SipccSdpMediaSection::SetPort(unsigned int port) { mPort = port; }
     40 
     41 unsigned int SipccSdpMediaSection::GetPortCount() const { return mPortCount; }
     42 
     43 SdpMediaSection::Protocol SipccSdpMediaSection::GetProtocol() const {
     44  return mProtocol;
     45 }
     46 
     47 const SdpConnection& SipccSdpMediaSection::GetConnection() const {
     48  return *mConnection;
     49 }
     50 
     51 SdpConnection& SipccSdpMediaSection::GetConnection() { return *mConnection; }
     52 
     53 uint32_t SipccSdpMediaSection::GetBandwidth(const std::string& type) const {
     54  auto found = mBandwidths.find(type);
     55  if (found == mBandwidths.end()) {
     56    return 0;
     57  }
     58  return found->second;
     59 }
     60 
     61 const std::vector<std::string>& SipccSdpMediaSection::GetFormats() const {
     62  return mFormats;
     63 }
     64 
     65 const SdpAttributeList& SipccSdpMediaSection::GetAttributeList() const {
     66  return mAttributeList;
     67 }
     68 
     69 SdpAttributeList& SipccSdpMediaSection::GetAttributeList() {
     70  return mAttributeList;
     71 }
     72 
     73 SdpDirectionAttribute SipccSdpMediaSection::GetDirectionAttribute() const {
     74  return SdpDirectionAttribute(mAttributeList.GetDirection());
     75 }
     76 
     77 bool SipccSdpMediaSection::Load(sdp_t* sdp, uint16_t level,
     78                                InternalResults& results) {
     79  switch (sdp_get_media_type(sdp, level)) {
     80    case SDP_MEDIA_AUDIO:
     81      mMediaType = kAudio;
     82      break;
     83    case SDP_MEDIA_VIDEO:
     84      mMediaType = kVideo;
     85      break;
     86    case SDP_MEDIA_APPLICATION:
     87      mMediaType = kApplication;
     88      break;
     89    case SDP_MEDIA_TEXT:
     90      mMediaType = kText;
     91      break;
     92 
     93    default:
     94      results.AddParseError(sdp_get_media_line_number(sdp, level),
     95                            "Unsupported media section type");
     96      return false;
     97  }
     98 
     99  mPort = sdp_get_media_portnum(sdp, level);
    100  int32_t pc = sdp_get_media_portcount(sdp, level);
    101  if (pc == SDP_INVALID_VALUE) {
    102    // SDP_INVALID_VALUE (ie; -2) is used when there is no port count. :(
    103    mPortCount = 0;
    104  } else if (pc > static_cast<int32_t>(UINT16_MAX) || pc < 0) {
    105    results.AddParseError(sdp_get_media_line_number(sdp, level),
    106                          "Invalid port count");
    107    return false;
    108  } else {
    109    mPortCount = pc;
    110  }
    111 
    112  if (!LoadProtocol(sdp, level, results)) {
    113    return false;
    114  }
    115 
    116  if (!LoadFormats(sdp, level, results)) {
    117    return false;
    118  }
    119 
    120  if (!mAttributeList.Load(sdp, level, results)) {
    121    return false;
    122  }
    123 
    124  if (!ValidateSimulcast(sdp, level, results)) {
    125    return false;
    126  }
    127 
    128  if (!mBandwidths.Load(sdp, level, results)) {
    129    return false;
    130  }
    131 
    132  return LoadConnection(sdp, level, results);
    133 }
    134 
    135 bool SipccSdpMediaSection::LoadProtocol(sdp_t* sdp, uint16_t level,
    136                                        InternalResults& results) {
    137  switch (sdp_get_media_transport(sdp, level)) {
    138    case SDP_TRANSPORT_RTPAVP:
    139      mProtocol = kRtpAvp;
    140      break;
    141    case SDP_TRANSPORT_RTPSAVP:
    142      mProtocol = kRtpSavp;
    143      break;
    144    case SDP_TRANSPORT_RTPAVPF:
    145      mProtocol = kRtpAvpf;
    146      break;
    147    case SDP_TRANSPORT_RTPSAVPF:
    148      mProtocol = kRtpSavpf;
    149      break;
    150    case SDP_TRANSPORT_UDPTLSRTPSAVP:
    151      mProtocol = kUdpTlsRtpSavp;
    152      break;
    153    case SDP_TRANSPORT_UDPTLSRTPSAVPF:
    154      mProtocol = kUdpTlsRtpSavpf;
    155      break;
    156    case SDP_TRANSPORT_TCPDTLSRTPSAVP:
    157      mProtocol = kTcpDtlsRtpSavp;
    158      break;
    159    case SDP_TRANSPORT_TCPDTLSRTPSAVPF:
    160      mProtocol = kTcpDtlsRtpSavpf;
    161      break;
    162    case SDP_TRANSPORT_DTLSSCTP:
    163      mProtocol = kDtlsSctp;
    164      break;
    165    case SDP_TRANSPORT_UDPDTLSSCTP:
    166      mProtocol = kUdpDtlsSctp;
    167      break;
    168    case SDP_TRANSPORT_TCPDTLSSCTP:
    169      mProtocol = kTcpDtlsSctp;
    170      break;
    171 
    172    default:
    173      results.AddParseError(sdp_get_media_line_number(sdp, level),
    174                            "Unsupported media transport type");
    175      return false;
    176  }
    177  return true;
    178 }
    179 
    180 bool SipccSdpMediaSection::LoadFormats(sdp_t* sdp, uint16_t level,
    181                                       InternalResults& results) {
    182  sdp_media_e mtype = sdp_get_media_type(sdp, level);
    183 
    184  if (mtype == SDP_MEDIA_APPLICATION) {
    185    sdp_transport_e ttype = sdp_get_media_transport(sdp, level);
    186    if ((ttype == SDP_TRANSPORT_UDPDTLSSCTP) ||
    187        (ttype == SDP_TRANSPORT_TCPDTLSSCTP)) {
    188      if (sdp_get_media_sctp_fmt(sdp, level) ==
    189          SDP_SCTP_MEDIA_FMT_WEBRTC_DATACHANNEL) {
    190        mFormats.push_back("webrtc-datachannel");
    191      }
    192    } else {
    193      uint32_t ptype = sdp_get_media_sctp_port(sdp, level);
    194      std::ostringstream osPayloadType;
    195      osPayloadType << ptype;
    196      mFormats.push_back(osPayloadType.str());
    197    }
    198  } else if (mtype == SDP_MEDIA_AUDIO || mtype == SDP_MEDIA_VIDEO) {
    199    uint16_t count = sdp_get_media_num_payload_types(sdp, level);
    200    for (uint16_t i = 0; i < count; ++i) {
    201      sdp_payload_ind_e indicator;  // we ignore this, which is fine
    202      uint32_t ptype =
    203          sdp_get_media_payload_type(sdp, level, i + 1, &indicator);
    204 
    205      if (GET_DYN_PAYLOAD_TYPE_VALUE(ptype) > UINT8_MAX) {
    206        results.AddParseError(sdp_get_media_line_number(sdp, level),
    207                              "Format is too large");
    208        return false;
    209      }
    210 
    211      std::ostringstream osPayloadType;
    212      // sipcc stores payload types in a funny way. When sipcc and the SDP it
    213      // parsed differ on what payload type number should be used for a given
    214      // codec, sipcc's value goes in the lower byte, and the SDP's value in
    215      // the upper byte. When they do not differ, only the lower byte is used.
    216      // We want what was in the SDP, verbatim.
    217      osPayloadType << GET_DYN_PAYLOAD_TYPE_VALUE(ptype);
    218      mFormats.push_back(osPayloadType.str());
    219    }
    220  }
    221 
    222  return true;
    223 }
    224 
    225 bool SipccSdpMediaSection::ValidateSimulcast(sdp_t* sdp, uint16_t level,
    226                                             InternalResults& results) const {
    227  if (!GetAttributeList().HasAttribute(SdpAttribute::kSimulcastAttribute)) {
    228    return true;
    229  }
    230 
    231  const SdpSimulcastAttribute& simulcast(GetAttributeList().GetSimulcast());
    232  if (!ValidateSimulcastVersions(sdp, level, simulcast.sendVersions, sdp::kSend,
    233                                 results)) {
    234    return false;
    235  }
    236  if (!ValidateSimulcastVersions(sdp, level, simulcast.recvVersions, sdp::kRecv,
    237                                 results)) {
    238    return false;
    239  }
    240  return true;
    241 }
    242 
    243 bool SipccSdpMediaSection::ValidateSimulcastVersions(
    244    sdp_t* sdp, uint16_t level, const SdpSimulcastAttribute::Versions& versions,
    245    sdp::Direction direction, InternalResults& results) const {
    246  for (const SdpSimulcastAttribute::Version& version : versions) {
    247    for (const SdpSimulcastAttribute::Encoding& encoding : version.choices) {
    248      const SdpRidAttributeList::Rid* ridAttr = FindRid(encoding.rid);
    249      if (!ridAttr || (ridAttr->direction != direction)) {
    250        std::ostringstream os;
    251        os << "No rid attribute for \'" << encoding.rid << "\'";
    252        results.AddParseError(sdp_get_media_line_number(sdp, level), os.str());
    253        results.AddParseError(sdp_get_media_line_number(sdp, level), os.str());
    254        return false;
    255      }
    256    }
    257  }
    258  return true;
    259 }
    260 
    261 bool SipccSdpMediaSection::LoadConnection(sdp_t* sdp, uint16_t level,
    262                                          InternalResults& results) {
    263  if (!sdp_connection_valid(sdp, level)) {
    264    level = SDP_SESSION_LEVEL;
    265    if (!sdp_connection_valid(sdp, level)) {
    266      results.AddParseError(sdp_get_media_line_number(sdp, level),
    267                            "Missing c= line");
    268      return false;
    269    }
    270  }
    271 
    272  sdp_nettype_e type = sdp_get_conn_nettype(sdp, level);
    273  if (type != SDP_NT_INTERNET) {
    274    results.AddParseError(sdp_get_media_line_number(sdp, level),
    275                          "Unsupported network type");
    276    return false;
    277  }
    278 
    279  sdp::AddrType addrType;
    280  switch (sdp_get_conn_addrtype(sdp, level)) {
    281    case SDP_AT_IP4:
    282      addrType = sdp::kIPv4;
    283      break;
    284    case SDP_AT_IP6:
    285      addrType = sdp::kIPv6;
    286      break;
    287    default:
    288      results.AddParseError(sdp_get_media_line_number(sdp, level),
    289                            "Unsupported address type");
    290      return false;
    291  }
    292 
    293  std::string address = sdp_get_conn_address(sdp, level);
    294  int16_t ttl = static_cast<uint16_t>(sdp_get_mcast_ttl(sdp, level));
    295  if (ttl < 0) {
    296    ttl = 0;
    297  }
    298  int32_t numAddr =
    299      static_cast<uint32_t>(sdp_get_mcast_num_of_addresses(sdp, level));
    300  if (numAddr < 0) {
    301    numAddr = 0;
    302  }
    303  mConnection = MakeUnique<SdpConnection>(addrType, address, ttl, numAddr);
    304  return true;
    305 }
    306 
    307 void SipccSdpMediaSection::AddCodec(const std::string& pt,
    308                                    const std::string& name, uint32_t clockrate,
    309                                    uint16_t channels) {
    310  mFormats.push_back(pt);
    311 
    312  SdpRtpmapAttributeList* rtpmap = new SdpRtpmapAttributeList();
    313  if (mAttributeList.HasAttribute(SdpAttribute::kRtpmapAttribute)) {
    314    const SdpRtpmapAttributeList& old = mAttributeList.GetRtpmap();
    315    for (auto it = old.mRtpmaps.begin(); it != old.mRtpmaps.end(); ++it) {
    316      rtpmap->mRtpmaps.push_back(*it);
    317    }
    318  }
    319  SdpRtpmapAttributeList::CodecType codec = SdpRtpmapAttributeList::kOtherCodec;
    320  if (name == "opus") {
    321    codec = SdpRtpmapAttributeList::kOpus;
    322  } else if (name == "G722") {
    323    codec = SdpRtpmapAttributeList::kG722;
    324  } else if (name == "PCMU") {
    325    codec = SdpRtpmapAttributeList::kPCMU;
    326  } else if (name == "PCMA") {
    327    codec = SdpRtpmapAttributeList::kPCMA;
    328  } else if (name == "VP8") {
    329    codec = SdpRtpmapAttributeList::kVP8;
    330  } else if (name == "VP9") {
    331    codec = SdpRtpmapAttributeList::kVP9;
    332  } else if (name == "H264") {
    333    codec = SdpRtpmapAttributeList::kH264;
    334  }
    335 
    336  rtpmap->PushEntry(pt, codec, name, clockrate, channels);
    337  mAttributeList.SetAttribute(rtpmap);
    338 }
    339 
    340 void SipccSdpMediaSection::ClearCodecs() {
    341  mFormats.clear();
    342  mAttributeList.RemoveAttribute(SdpAttribute::kRtpmapAttribute);
    343  mAttributeList.RemoveAttribute(SdpAttribute::kFmtpAttribute);
    344  mAttributeList.RemoveAttribute(SdpAttribute::kSctpmapAttribute);
    345  mAttributeList.RemoveAttribute(SdpAttribute::kRtcpFbAttribute);
    346 }
    347 
    348 void SipccSdpMediaSection::AddDataChannel(const std::string& name,
    349                                          uint16_t port, uint16_t streams,
    350                                          uint32_t message_size) {
    351  // Only one allowed, for now. This may change as the specs (and deployments)
    352  // evolve.
    353  mFormats.clear();
    354  if ((mProtocol == kUdpDtlsSctp) || (mProtocol == kTcpDtlsSctp)) {
    355    // new data channel format according to draft 21
    356    mFormats.push_back(name);
    357    mAttributeList.SetAttribute(
    358        new SdpNumberAttribute(SdpAttribute::kSctpPortAttribute, port));
    359    if (message_size) {
    360      mAttributeList.SetAttribute(new SdpNumberAttribute(
    361          SdpAttribute::kMaxMessageSizeAttribute, message_size));
    362    }
    363  } else {
    364    // old data channels format according to draft 05
    365    std::string port_str = std::to_string(port);
    366    mFormats.push_back(port_str);
    367    SdpSctpmapAttributeList* sctpmap = new SdpSctpmapAttributeList();
    368    sctpmap->PushEntry(port_str, name, streams);
    369    mAttributeList.SetAttribute(sctpmap);
    370    if (message_size) {
    371      // This is a workaround to allow detecting Firefox's w/o EOR support
    372      mAttributeList.SetAttribute(new SdpNumberAttribute(
    373          SdpAttribute::kMaxMessageSizeAttribute, message_size));
    374    }
    375  }
    376 }
    377 
    378 void SipccSdpMediaSection::Serialize(std::ostream& os) const {
    379  os << "m=" << mMediaType << " " << mPort;
    380  if (mPortCount) {
    381    os << "/" << mPortCount;
    382  }
    383  os << " " << mProtocol;
    384  for (auto i = mFormats.begin(); i != mFormats.end(); ++i) {
    385    os << " " << (*i);
    386  }
    387  os << CRLF;
    388 
    389  // We dont do i=
    390 
    391  if (mConnection) {
    392    os << *mConnection;
    393  }
    394 
    395  mBandwidths.Serialize(os);
    396 
    397  // We dont do k= because they're evil
    398 
    399  os << mAttributeList;
    400 }
    401 
    402 }  // namespace mozilla