OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/base/checks.h" | 11 #include "webrtc/base/checks.h" |
12 #include "webrtc/call/rtp_demuxer.h" | 12 #include "webrtc/call/rtp_demuxer.h" |
13 #include "webrtc/call/rtp_packet_sink_interface.h" | 13 #include "webrtc/call/rtp_packet_sink_interface.h" |
| 14 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h" |
14 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_received.h" | 15 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_received.h" |
15 | 16 |
16 namespace webrtc { | 17 namespace webrtc { |
17 | 18 |
18 namespace { | 19 namespace { |
19 | 20 |
| 21 constexpr size_t kMaxProcessedSsrcs = 1000; // Prevent memory overuse. |
| 22 |
20 template <typename Key, typename Value> | 23 template <typename Key, typename Value> |
21 bool MultimapAssociationExists(const std::multimap<Key, Value>& multimap, | 24 bool MultimapAssociationExists(const std::multimap<Key, Value>& multimap, |
22 Key key, | 25 Key key, |
23 Value val) { | 26 Value val) { |
24 auto it_range = multimap.equal_range(key); | 27 auto it_range = multimap.equal_range(key); |
25 using Reference = typename std::multimap<Key, Value>::const_reference; | 28 using Reference = typename std::multimap<Key, Value>::const_reference; |
26 return std::any_of(it_range.first, it_range.second, | 29 return std::any_of(it_range.first, it_range.second, |
27 [val](Reference elem) { return elem.second == val; }); | 30 [val](Reference elem) { return elem.second == val; }); |
28 } | 31 } |
29 | 32 |
| 33 template <typename Key, typename Value> |
| 34 size_t RemoveFromMultimapByValue(std::multimap<Key, Value*>* multimap, |
| 35 const Value* value) { |
| 36 size_t count = 0; |
| 37 for (auto it = multimap->begin(); it != multimap->end();) { |
| 38 if (it->second == value) { |
| 39 it = multimap->erase(it); |
| 40 ++count; |
| 41 } else { |
| 42 ++it; |
| 43 } |
| 44 } |
| 45 return count; |
| 46 } |
| 47 |
30 } // namespace | 48 } // namespace |
31 | 49 |
32 RtpDemuxer::RtpDemuxer() {} | 50 RtpDemuxer::RtpDemuxer() {} |
33 | 51 |
34 RtpDemuxer::~RtpDemuxer() { | 52 RtpDemuxer::~RtpDemuxer() { |
35 RTC_DCHECK(sinks_.empty()); | 53 RTC_DCHECK(sinks_.empty()); |
36 } | 54 } |
37 | 55 |
38 void RtpDemuxer::AddSink(uint32_t ssrc, RtpPacketSinkInterface* sink) { | 56 void RtpDemuxer::AddSink(uint32_t ssrc, RtpPacketSinkInterface* sink) { |
39 RTC_DCHECK(sink); | 57 RecordSsrcToSinkAssociation(ssrc, sink); |
40 RTC_DCHECK(!MultimapAssociationExists(sinks_, ssrc, sink)); | |
41 sinks_.emplace(ssrc, sink); | |
42 } | 58 } |
43 | 59 |
44 size_t RtpDemuxer::RemoveSink(const RtpPacketSinkInterface* sink) { | 60 void RtpDemuxer::AddSink(const std::string& rsid, |
| 61 RtpPacketSinkInterface* sink) { |
| 62 RTC_DCHECK(StreamId::IsLegalName(rsid)); |
45 RTC_DCHECK(sink); | 63 RTC_DCHECK(sink); |
46 size_t count = 0; | 64 RTC_DCHECK(!MultimapAssociationExists(rsid_sinks_, rsid, sink)); |
47 for (auto it = sinks_.begin(); it != sinks_.end(); ) { | 65 |
48 if (it->second == sink) { | 66 rsid_sinks_.emplace(rsid, sink); |
49 it = sinks_.erase(it); | 67 |
50 ++count; | 68 // This RSID might now map to an SSRC which we saw earlier. |
51 } else { | 69 processed_ssrcs_.clear(); |
52 ++it; | 70 } |
53 } | 71 |
| 72 bool RtpDemuxer::RemoveSink(const RtpPacketSinkInterface* sink) { |
| 73 RTC_DCHECK(sink); |
| 74 return (RemoveFromMultimapByValue(&sinks_, sink) + |
| 75 RemoveFromMultimapByValue(&rsid_sinks_, sink)) > 0; |
| 76 } |
| 77 |
| 78 void RtpDemuxer::RecordSsrcToSinkAssociation(uint32_t ssrc, |
| 79 RtpPacketSinkInterface* sink) { |
| 80 RTC_DCHECK(sink); |
| 81 // The association might already have been set by a different |
| 82 // configuration source. |
| 83 if (!MultimapAssociationExists(sinks_, ssrc, sink)) { |
| 84 sinks_.emplace(ssrc, sink); |
54 } | 85 } |
55 return count; | |
56 } | 86 } |
57 | 87 |
58 bool RtpDemuxer::OnRtpPacket(const RtpPacketReceived& packet) { | 88 bool RtpDemuxer::OnRtpPacket(const RtpPacketReceived& packet) { |
59 bool found = false; | 89 FindSsrcAssociations(packet); |
60 auto it_range = sinks_.equal_range(packet.Ssrc()); | 90 auto it_range = sinks_.equal_range(packet.Ssrc()); |
61 for (auto it = it_range.first; it != it_range.second; ++it) { | 91 for (auto it = it_range.first; it != it_range.second; ++it) { |
62 found = true; | |
63 it->second->OnRtpPacket(packet); | 92 it->second->OnRtpPacket(packet); |
64 } | 93 } |
65 return found; | 94 return it_range.first != it_range.second; |
| 95 } |
| 96 |
| 97 void RtpDemuxer::FindSsrcAssociations(const RtpPacketReceived& packet) { |
| 98 // Avoid expensive string comparisons for RSID by looking the sinks up only |
| 99 // by SSRC whenever possible. |
| 100 if (processed_ssrcs_.find(packet.Ssrc()) != processed_ssrcs_.cend()) { |
| 101 return; |
| 102 } |
| 103 |
| 104 // RSID-based associations: |
| 105 std::string rsid; |
| 106 if (packet.GetExtension<RtpStreamId>(&rsid)) { |
| 107 // All streams associated with this RSID need to be marked as associated |
| 108 // with this SSRC (if they aren't already). |
| 109 auto it_range = rsid_sinks_.equal_range(rsid); |
| 110 for (auto it = it_range.first; it != it_range.second; ++it) { |
| 111 RecordSsrcToSinkAssociation(packet.Ssrc(), it->second); |
| 112 } |
| 113 |
| 114 // To prevent memory-overuse attacks, forget this RSID. Future packets |
| 115 // with this RSID, but a different SSRC, will not spawn new associations. |
| 116 rsid_sinks_.erase(it_range.first, it_range.second); |
| 117 } |
| 118 |
| 119 if (processed_ssrcs_.size() < kMaxProcessedSsrcs) { // Prevent memory overuse |
| 120 processed_ssrcs_.insert(packet.Ssrc()); // Avoid re-examining in-depth. |
| 121 } |
66 } | 122 } |
67 | 123 |
68 } // namespace webrtc | 124 } // namespace webrtc |
OLD | NEW |