File: sdes.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (201 lines) | stat: -rw-r--r-- 7,698 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"

#include <string.h>

#include <cstdint>
#include <string>
#include <utility>
#include <vector>

#include "absl/strings/string_view.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/rtcp_packet.h"
#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"

namespace webrtc {
namespace rtcp {
// Source Description (SDES) (RFC 3550).
//
//         0                   1                   2                   3
//         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
//        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// header |V=2|P|    SC   |  PT=SDES=202  |             length            |
//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// chunk  |                          SSRC/CSRC_1                          |
//   1    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//        |                           SDES items                          |
//        |                              ...                              |
//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// chunk  |                          SSRC/CSRC_2                          |
//   2    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//        |                           SDES items                          |
//        |                              ...                              |
//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// Canonical End-Point Identifier SDES Item (CNAME)
//
//    0                   1                   2                   3
//    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
//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//   |    CNAME=1    |     length    | user and domain name        ...
//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
namespace {
const uint8_t kTerminatorTag = 0;
const uint8_t kCnameTag = 1;

size_t ChunkSize(const Sdes::Chunk& chunk) {
  // Chunk:
  // SSRC/CSRC (4 bytes) | CNAME=1 (1 byte) | length (1 byte) | cname | padding.
  size_t chunk_payload_size = 4 + 1 + 1 + chunk.cname.size();
  size_t padding_size = 4 - (chunk_payload_size % 4);  // Minimum 1.
  return chunk_payload_size + padding_size;
}
}  // namespace

Sdes::Sdes() : block_length_(RtcpPacket::kHeaderLength) {}

Sdes::~Sdes() {}

bool Sdes::Parse(const CommonHeader& packet) {
  RTC_DCHECK_EQ(packet.type(), kPacketType);

  uint8_t number_of_chunks = packet.count();
  std::vector<Chunk> chunks;  // Read chunk into temporary array, so that in
                              // case of an error original array would stay
                              // unchanged.
  size_t block_length = kHeaderLength;

  if (packet.payload_size_bytes() % 4 != 0) {
    RTC_LOG(LS_WARNING) << "Invalid payload size "
                        << packet.payload_size_bytes()
                        << " bytes for a valid Sdes packet. Size should be"
                           " multiple of 4 bytes";
  }
  const uint8_t* const payload_end =
      packet.payload() + packet.payload_size_bytes();
  const uint8_t* looking_at = packet.payload();
  chunks.resize(number_of_chunks);
  for (size_t i = 0; i < number_of_chunks;) {
    // Each chunk consumes at least 8 bytes.
    if (payload_end - looking_at < 8) {
      RTC_LOG(LS_WARNING) << "Not enough space left for chunk #" << (i + 1);
      return false;
    }
    chunks[i].ssrc = ByteReader<uint32_t>::ReadBigEndian(looking_at);
    looking_at += sizeof(uint32_t);
    bool cname_found = false;

    uint8_t item_type;
    while ((item_type = *(looking_at++)) != kTerminatorTag) {
      if (looking_at >= payload_end) {
        RTC_LOG(LS_WARNING)
            << "Unexpected end of packet while reading chunk #" << (i + 1)
            << ". Expected to find size of the text.";
        return false;
      }
      uint8_t item_length = *(looking_at++);
      const size_t kTerminatorSize = 1;
      if (looking_at + item_length + kTerminatorSize > payload_end) {
        RTC_LOG(LS_WARNING)
            << "Unexpected end of packet while reading chunk #" << (i + 1)
            << ". Expected to find text of size " << item_length;
        return false;
      }
      if (item_type == kCnameTag) {
        if (cname_found) {
          RTC_LOG(LS_WARNING)
              << "Found extra CNAME for same ssrc in chunk #" << (i + 1);
          return false;
        }
        cname_found = true;
        chunks[i].cname.assign(reinterpret_cast<const char*>(looking_at),
                               item_length);
      }
      looking_at += item_length;
    }
    if (cname_found) {
      // block_length calculates length of the packet that would be generated by
      // Build/Create functions. Adjust it same way WithCName function does.
      block_length += ChunkSize(chunks[i]);
      ++i;
    } else {
      // RFC states CNAME item is mandatory.
      // But same time it allows chunk without items.
      // So while parsing, ignore all chunks without cname,
      // but do not fail the parse.
      RTC_LOG(LS_WARNING) << "CNAME not found for ssrc " << chunks[i].ssrc;
      --number_of_chunks;
      chunks.resize(number_of_chunks);
    }
    // Adjust to 32bit boundary.
    looking_at += (payload_end - looking_at) % 4;
  }

  chunks_ = std::move(chunks);
  block_length_ = block_length;
  return true;
}

bool Sdes::AddCName(uint32_t ssrc, absl::string_view cname) {
  RTC_DCHECK_LE(cname.length(), 0xffu);
  if (chunks_.size() >= kMaxNumberOfChunks) {
    RTC_LOG(LS_WARNING) << "Max SDES chunks reached.";
    return false;
  }
  Chunk chunk;
  chunk.ssrc = ssrc;
  chunk.cname = std::string(cname);
  chunks_.push_back(chunk);
  block_length_ += ChunkSize(chunk);
  return true;
}

size_t Sdes::BlockLength() const {
  return block_length_;
}

bool Sdes::Create(uint8_t* packet,
                  size_t* index,
                  size_t max_length,
                  PacketReadyCallback callback) const {
  while (*index + BlockLength() > max_length) {
    if (!OnBufferFull(packet, index, callback))
      return false;
  }
  const size_t index_end = *index + BlockLength();
  CreateHeader(chunks_.size(), kPacketType, HeaderLength(), packet, index);

  for (const Sdes::Chunk& chunk : chunks_) {
    ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 0], chunk.ssrc);
    ByteWriter<uint8_t>::WriteBigEndian(&packet[*index + 4], kCnameTag);
    ByteWriter<uint8_t>::WriteBigEndian(
        &packet[*index + 5], static_cast<uint8_t>(chunk.cname.size()));
    memcpy(&packet[*index + 6], chunk.cname.data(), chunk.cname.size());
    *index += (6 + chunk.cname.size());

    // In each chunk, the list of items must be terminated by one or more null
    // octets. The next chunk must start on a 32-bit boundary.
    // CNAME (1 byte) | length (1 byte) | name | padding.
    size_t padding_size = 4 - ((6 + chunk.cname.size()) % 4);
    const int kPadding = 0;
    memset(packet + *index, kPadding, padding_size);
    *index += padding_size;
  }

  RTC_CHECK_EQ(*index, index_end);
  return true;
}
}  // namespace rtcp
}  // namespace webrtc