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 "rtc_base/strings/string_builder.h"
14 #include "test/gtest.h"
15 #include "test/rtcp_packet_parser.h"
16 
17 using webrtc::rtcp::Sdes;
18 
19 namespace webrtc {
20 namespace {
21 const uint32_t kSenderSsrc = 0x12345678;
22 const uint8_t kPadding = 0;
23 const uint8_t kTerminatorTag = 0;
24 const uint8_t kCnameTag = 1;
25 const uint8_t kNameTag = 2;
26 const uint8_t kEmailTag = 3;
27 }  // namespace
28 
TEST(RtcpPacketSdesTest,CreateAndParseWithoutChunks)29 TEST(RtcpPacketSdesTest, CreateAndParseWithoutChunks) {
30   Sdes sdes;
31 
32   rtc::Buffer packet = sdes.Build();
33   Sdes parsed;
34   EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed));
35 
36   EXPECT_EQ(0u, parsed.chunks().size());
37 }
38 
TEST(RtcpPacketSdesTest,CreateAndParseWithOneChunk)39 TEST(RtcpPacketSdesTest, CreateAndParseWithOneChunk) {
40   const std::string kCname = "alice@host";
41 
42   Sdes sdes;
43   EXPECT_TRUE(sdes.AddCName(kSenderSsrc, kCname));
44 
45   rtc::Buffer packet = sdes.Build();
46   Sdes sdes_parsed;
47   EXPECT_TRUE(test::ParseSinglePacket(packet, &sdes_parsed));
48   const Sdes& parsed = sdes_parsed;  // Ensure accessors are const.
49 
50   EXPECT_EQ(1u, parsed.chunks().size());
51   EXPECT_EQ(kSenderSsrc, parsed.chunks()[0].ssrc);
52   EXPECT_EQ(kCname, parsed.chunks()[0].cname);
53 }
54 
TEST(RtcpPacketSdesTest,CreateAndParseWithMultipleChunks)55 TEST(RtcpPacketSdesTest, CreateAndParseWithMultipleChunks) {
56   Sdes sdes;
57   EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 0, "a"));
58   EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 1, "ab"));
59   EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 2, "abc"));
60   EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 3, "abcd"));
61   EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 4, "abcde"));
62   EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 5, "abcdef"));
63 
64   rtc::Buffer packet = sdes.Build();
65   Sdes parsed;
66   EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed));
67 
68   EXPECT_EQ(6u, parsed.chunks().size());
69   EXPECT_EQ(kSenderSsrc + 5, parsed.chunks()[5].ssrc);
70   EXPECT_EQ("abcdef", parsed.chunks()[5].cname);
71 }
72 
TEST(RtcpPacketSdesTest,CreateWithTooManyChunks)73 TEST(RtcpPacketSdesTest, CreateWithTooManyChunks) {
74   const size_t kMaxChunks = (1 << 5) - 1;
75   Sdes sdes;
76   for (size_t i = 0; i < kMaxChunks; ++i) {
77     uint32_t ssrc = kSenderSsrc + i;
78     rtc::StringBuilder oss;
79     oss << "cname" << i;
80     EXPECT_TRUE(sdes.AddCName(ssrc, oss.str()));
81   }
82   EXPECT_FALSE(sdes.AddCName(kSenderSsrc + kMaxChunks, "foo"));
83 }
84 
TEST(RtcpPacketSdesTest,CreateAndParseCnameItemWithEmptyString)85 TEST(RtcpPacketSdesTest, CreateAndParseCnameItemWithEmptyString) {
86   Sdes sdes;
87   EXPECT_TRUE(sdes.AddCName(kSenderSsrc, ""));
88 
89   rtc::Buffer packet = sdes.Build();
90   Sdes parsed;
91   EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed));
92 
93   EXPECT_EQ(1u, parsed.chunks().size());
94   EXPECT_EQ(kSenderSsrc, parsed.chunks()[0].ssrc);
95   EXPECT_EQ("", parsed.chunks()[0].cname);
96 }
97 
TEST(RtcpPacketSdesTest,ParseSkipsNonCNameField)98 TEST(RtcpPacketSdesTest, ParseSkipsNonCNameField) {
99   const uint8_t kName[] = "abc";
100   const uint8_t kCname[] = "de";
101   const uint8_t kValidPacket[] = {
102       0x81, 202,       0x00,      0x04,           0x12,     0x34,     0x56,
103       0x78, kNameTag,  3,         kName[0],       kName[1], kName[2], kCnameTag,
104       2,    kCname[0], kCname[1], kTerminatorTag, kPadding, kPadding};
105   // Sanity checks packet was assembled correctly.
106   ASSERT_EQ(0u, sizeof(kValidPacket) % 4);
107   ASSERT_EQ(kValidPacket[3] + 1u, sizeof(kValidPacket) / 4);
108 
109   Sdes parsed;
110   EXPECT_TRUE(test::ParseSinglePacket(kValidPacket, &parsed));
111 
112   EXPECT_EQ(1u, parsed.chunks().size());
113   EXPECT_EQ(kSenderSsrc, parsed.chunks()[0].ssrc);
114   EXPECT_EQ("de", parsed.chunks()[0].cname);
115 }
116 
TEST(RtcpPacketSdesTest,ParseSkipsChunksWithoutCName)117 TEST(RtcpPacketSdesTest, ParseSkipsChunksWithoutCName) {
118   const uint8_t kName[] = "ab";
119   const uint8_t kEmail[] = "de";
120   const uint8_t kCname[] = "def";
121   const uint8_t kPacket[] = {
122       0x82,           202,      0x00,      0x07,      0x12,
123       0x34,           0x56,     0x78,  // 1st chunk.
124       kNameTag,       3,        kName[0],  kName[1],  kName[2],
125       kEmailTag,      2,        kEmail[0], kEmail[1], kTerminatorTag,
126       kPadding,       kPadding, 0x23,      0x45,      0x67,
127       0x89,  // 2nd chunk.
128       kCnameTag,      3,        kCname[0], kCname[1], kCname[2],
129       kTerminatorTag, kPadding, kPadding};
130   // Sanity checks packet was assembled correctly.
131   ASSERT_EQ(0u, sizeof(kPacket) % 4);
132   ASSERT_EQ(kPacket[3] + 1u, sizeof(kPacket) / 4);
133 
134   Sdes parsed;
135   EXPECT_TRUE(test::ParseSinglePacket(kPacket, &parsed));
136   ASSERT_EQ(1u, parsed.chunks().size());
137   EXPECT_EQ(0x23456789u, parsed.chunks()[0].ssrc);
138   EXPECT_EQ("def", parsed.chunks()[0].cname);
139 }
140 
TEST(RtcpPacketSdesTest,ParseFailsWithoutChunkItemTerminator)141 TEST(RtcpPacketSdesTest, ParseFailsWithoutChunkItemTerminator) {
142   const uint8_t kName[] = "abc";
143   const uint8_t kCname[] = "d";
144   // No place for next chunk item.
145   const uint8_t kInvalidPacket[] = {
146       0x81,     202, 0x00,     0x03,     0x12,     0x34,      0x56, 0x78,
147       kNameTag, 3,   kName[0], kName[1], kName[2], kCnameTag, 1,    kCname[0]};
148   // Sanity checks packet was assembled correctly.
149   ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
150   ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
151 
152   Sdes parsed;
153   EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed));
154 }
155 
TEST(RtcpPacketSdesTest,ParseFailsWithDamagedChunkItem)156 TEST(RtcpPacketSdesTest, ParseFailsWithDamagedChunkItem) {
157   const uint8_t kName[] = "ab";
158   const uint8_t kCname[] = "d";
159   // Next chunk item has non-terminator type, but not the size.
160   const uint8_t kInvalidPacket[] = {
161       0x81,     202, 0x00,     0x03,     0x12,      0x34, 0x56,      0x78,
162       kNameTag, 2,   kName[0], kName[1], kCnameTag, 1,    kCname[0], kEmailTag};
163   // Sanity checks packet was assembled correctly.
164   ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
165   ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
166 
167   Sdes parsed;
168   EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed));
169 }
170 
TEST(RtcpPacketSdesTest,ParseFailsWithTooLongChunkItem)171 TEST(RtcpPacketSdesTest, ParseFailsWithTooLongChunkItem) {
172   const uint8_t kName[] = "abc";
173   const uint8_t kCname[] = "d";
174   // Last chunk item has length that goes beyond the buffer end.
175   const uint8_t kInvalidPacket[] = {
176       0x81,     202, 0x00,     0x03,     0x12,     0x34,      0x56, 0x78,
177       kNameTag, 3,   kName[0], kName[1], kName[2], kCnameTag, 2,    kCname[0]};
178   // Sanity checks packet was assembled correctly.
179   ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
180   ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
181 
182   Sdes parsed;
183   EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed));
184 }
185 
TEST(RtcpPacketSdesTest,ParseFailsWithTwoCNames)186 TEST(RtcpPacketSdesTest, ParseFailsWithTwoCNames) {
187   const uint8_t kCname1[] = "a";
188   const uint8_t kCname2[] = "de";
189   const uint8_t kInvalidPacket[] = {
190       0x81,       202,           0x00, 0x03,       0x12,      0x34, 0x56,
191       0x78,       kCnameTag,     1,    kCname1[0], kCnameTag, 2,    kCname2[0],
192       kCname2[1], kTerminatorTag};
193   // Sanity checks packet was assembled correctly.
194   ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
195   ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
196 
197   Sdes parsed;
198   EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed));
199 }
200 
TEST(RtcpPacketSdesTest,ParseFailsWithTooLittleSpaceForNextChunk)201 TEST(RtcpPacketSdesTest, ParseFailsWithTooLittleSpaceForNextChunk) {
202   const uint8_t kCname[] = "a";
203   const uint8_t kEmail[] = "de";
204   // Two chunks are promised in the header, but no place for the second chunk.
205   const uint8_t kInvalidPacket[] = {
206       0x82,           202,  0x00,      0x04,      0x12, 0x34,      0x56,
207       0x78,  // 1st chunk.
208       kCnameTag,      1,    kCname[0], kEmailTag, 2,    kEmail[0], kEmail[1],
209       kTerminatorTag, 0x23, 0x45,      0x67,      0x89};  // 2nd chunk.
210   // Sanity checks packet was assembled correctly.
211   ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
212   ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
213 
214   Sdes parsed;
215   EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed));
216 }
217 
TEST(RtcpPacketSdesTest,ParsedSdesCanBeReusedForBuilding)218 TEST(RtcpPacketSdesTest, ParsedSdesCanBeReusedForBuilding) {
219   Sdes source;
220   const std::string kAlice = "alice@host";
221   const std::string kBob = "bob@host";
222   source.AddCName(kSenderSsrc, kAlice);
223 
224   rtc::Buffer packet1 = source.Build();
225   Sdes middle;
226   test::ParseSinglePacket(packet1, &middle);
227 
228   EXPECT_EQ(source.BlockLength(), middle.BlockLength());
229 
230   middle.AddCName(kSenderSsrc + 1, kBob);
231 
232   rtc::Buffer packet2 = middle.Build();
233   Sdes destination;
234   test::ParseSinglePacket(packet2, &destination);
235 
236   EXPECT_EQ(middle.BlockLength(), destination.BlockLength());
237 
238   EXPECT_EQ(2u, destination.chunks().size());
239   EXPECT_EQ(kSenderSsrc, destination.chunks()[0].ssrc);
240   EXPECT_EQ(kAlice, destination.chunks()[0].cname);
241   EXPECT_EQ(kSenderSsrc + 1, destination.chunks()[1].ssrc);
242   EXPECT_EQ(kBob, destination.chunks()[1].cname);
243 }
244 }  // namespace webrtc
245