tor-browser

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

sdes.cc (7696B)


      1 /*
      2 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 #include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
     12 
     13 #include <cstdint>
     14 #include <cstring>
     15 #include <string>
     16 #include <utility>
     17 #include <vector>
     18 
     19 #include "absl/strings/string_view.h"
     20 #include "modules/rtp_rtcp/source/byte_io.h"
     21 #include "modules/rtp_rtcp/source/rtcp_packet.h"
     22 #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
     23 #include "rtc_base/checks.h"
     24 #include "rtc_base/logging.h"
     25 
     26 namespace webrtc {
     27 namespace rtcp {
     28 // Source Description (SDES) (RFC 3550).
     29 //
     30 //         0                   1                   2                   3
     31 //         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     32 //        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     33 // header |V=2|P|    SC   |  PT=SDES=202  |             length            |
     34 //        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
     35 // chunk  |                          SSRC/CSRC_1                          |
     36 //   1    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     37 //        |                           SDES items                          |
     38 //        |                              ...                              |
     39 //        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
     40 // chunk  |                          SSRC/CSRC_2                          |
     41 //   2    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     42 //        |                           SDES items                          |
     43 //        |                              ...                              |
     44 //        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
     45 //
     46 // Canonical End-Point Identifier SDES Item (CNAME)
     47 //
     48 //    0                   1                   2                   3
     49 //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     50 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     51 //   |    CNAME=1    |     length    | user and domain name        ...
     52 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     53 namespace {
     54 const uint8_t kTerminatorTag = 0;
     55 const uint8_t kCnameTag = 1;
     56 
     57 size_t ChunkSize(const Sdes::Chunk& chunk) {
     58  // Chunk:
     59  // SSRC/CSRC (4 bytes) | CNAME=1 (1 byte) | length (1 byte) | cname | padding.
     60  size_t chunk_payload_size = 4 + 1 + 1 + chunk.cname.size();
     61  size_t padding_size = 4 - (chunk_payload_size % 4);  // Minimum 1.
     62  return chunk_payload_size + padding_size;
     63 }
     64 }  // namespace
     65 
     66 Sdes::Sdes() : block_length_(RtcpPacket::kHeaderLength) {}
     67 
     68 Sdes::~Sdes() {}
     69 
     70 bool Sdes::Parse(const CommonHeader& packet) {
     71  RTC_DCHECK_EQ(packet.type(), kPacketType);
     72 
     73  uint8_t number_of_chunks = packet.count();
     74  std::vector<Chunk> chunks;  // Read chunk into temporary array, so that in
     75                              // case of an error original array would stay
     76                              // unchanged.
     77  size_t block_length = kHeaderLength;
     78 
     79  if (packet.payload_size_bytes() % 4 != 0) {
     80    RTC_LOG(LS_WARNING) << "Invalid payload size "
     81                        << packet.payload_size_bytes()
     82                        << " bytes for a valid Sdes packet. Size should be"
     83                           " multiple of 4 bytes";
     84  }
     85  const uint8_t* const payload_end =
     86      packet.payload() + packet.payload_size_bytes();
     87  const uint8_t* looking_at = packet.payload();
     88  chunks.resize(number_of_chunks);
     89  for (size_t i = 0; i < number_of_chunks;) {
     90    // Each chunk consumes at least 8 bytes.
     91    if (payload_end - looking_at < 8) {
     92      RTC_LOG(LS_WARNING) << "Not enough space left for chunk #" << (i + 1);
     93      return false;
     94    }
     95    chunks[i].ssrc = ByteReader<uint32_t>::ReadBigEndian(looking_at);
     96    looking_at += sizeof(uint32_t);
     97    bool cname_found = false;
     98 
     99    uint8_t item_type;
    100    while ((item_type = *(looking_at++)) != kTerminatorTag) {
    101      if (looking_at >= payload_end) {
    102        RTC_LOG(LS_WARNING)
    103            << "Unexpected end of packet while reading chunk #" << (i + 1)
    104            << ". Expected to find size of the text.";
    105        return false;
    106      }
    107      uint8_t item_length = *(looking_at++);
    108      const size_t kTerminatorSize = 1;
    109      if (looking_at + item_length + kTerminatorSize > payload_end) {
    110        RTC_LOG(LS_WARNING)
    111            << "Unexpected end of packet while reading chunk #" << (i + 1)
    112            << ". Expected to find text of size " << item_length;
    113        return false;
    114      }
    115      if (item_type == kCnameTag) {
    116        if (cname_found) {
    117          RTC_LOG(LS_WARNING)
    118              << "Found extra CNAME for same ssrc in chunk #" << (i + 1);
    119          return false;
    120        }
    121        cname_found = true;
    122        chunks[i].cname.assign(reinterpret_cast<const char*>(looking_at),
    123                               item_length);
    124      }
    125      looking_at += item_length;
    126    }
    127    if (cname_found) {
    128      // block_length calculates length of the packet that would be generated by
    129      // Build/Create functions. Adjust it same way WithCName function does.
    130      block_length += ChunkSize(chunks[i]);
    131      ++i;
    132    } else {
    133      // RFC states CNAME item is mandatory.
    134      // But same time it allows chunk without items.
    135      // So while parsing, ignore all chunks without cname,
    136      // but do not fail the parse.
    137      RTC_LOG(LS_WARNING) << "CNAME not found for ssrc " << chunks[i].ssrc;
    138      --number_of_chunks;
    139      chunks.resize(number_of_chunks);
    140    }
    141    // Adjust to 32bit boundary.
    142    looking_at += (payload_end - looking_at) % 4;
    143  }
    144 
    145  chunks_ = std::move(chunks);
    146  block_length_ = block_length;
    147  return true;
    148 }
    149 
    150 bool Sdes::AddCName(uint32_t ssrc, absl::string_view cname) {
    151  RTC_DCHECK_LE(cname.length(), 0xffu);
    152  if (chunks_.size() >= kMaxNumberOfChunks) {
    153    RTC_LOG(LS_WARNING) << "Max SDES chunks reached.";
    154    return false;
    155  }
    156  Chunk chunk;
    157  chunk.ssrc = ssrc;
    158  chunk.cname = std::string(cname);
    159  chunks_.push_back(chunk);
    160  block_length_ += ChunkSize(chunk);
    161  return true;
    162 }
    163 
    164 size_t Sdes::BlockLength() const {
    165  return block_length_;
    166 }
    167 
    168 bool Sdes::Create(uint8_t* packet,
    169                  size_t* index,
    170                  size_t max_length,
    171                  PacketReadyCallback callback) const {
    172  while (*index + BlockLength() > max_length) {
    173    if (!OnBufferFull(packet, index, callback))
    174      return false;
    175  }
    176  const size_t index_end = *index + BlockLength();
    177  CreateHeader(chunks_.size(), kPacketType, HeaderLength(), packet, index);
    178 
    179  for (const Sdes::Chunk& chunk : chunks_) {
    180    ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 0], chunk.ssrc);
    181    ByteWriter<uint8_t>::WriteBigEndian(&packet[*index + 4], kCnameTag);
    182    ByteWriter<uint8_t>::WriteBigEndian(
    183        &packet[*index + 5], static_cast<uint8_t>(chunk.cname.size()));
    184    memcpy(&packet[*index + 6], chunk.cname.data(), chunk.cname.size());
    185    *index += (6 + chunk.cname.size());
    186 
    187    // In each chunk, the list of items must be terminated by one or more null
    188    // octets. The next chunk must start on a 32-bit boundary.
    189    // CNAME (1 byte) | length (1 byte) | name | padding.
    190    size_t padding_size = 4 - ((6 + chunk.cname.size()) % 4);
    191    const int kPadding = 0;
    192    memset(packet + *index, kPadding, padding_size);
    193    *index += padding_size;
    194  }
    195 
    196  RTC_CHECK_EQ(*index, index_end);
    197  return true;
    198 }
    199 }  // namespace rtcp
    200 }  // namespace webrtc