1 /*
2  *  Copyright (c) 2017 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 #ifndef CALL_RTP_DEMUXER_H_
12 #define CALL_RTP_DEMUXER_H_
13 
14 #include <map>
15 #include <set>
16 #include <string>
17 #include <utility>
18 #include <vector>
19 
20 namespace webrtc {
21 
22 class RtpPacketReceived;
23 class RtpPacketSinkInterface;
24 
25 // This struct describes the criteria that will be used to match packets to a
26 // specific sink.
27 struct RtpDemuxerCriteria {
28   RtpDemuxerCriteria();
29   ~RtpDemuxerCriteria();
30 
31   // If not the empty string, will match packets with this MID.
32   std::string mid;
33 
34   // If not the empty string, will match packets with this as their RTP stream
35   // ID or repaired RTP stream ID.
36   // Note that if both MID and RSID are specified, this will only match packets
37   // that have both specified (either through RTP header extensions, SSRC
38   // latching or RTCP).
39   std::string rsid;
40 
41   // Will match packets with any of these SSRCs.
42   std::set<uint32_t> ssrcs;
43 
44   // Will match packets with any of these payload types.
45   std::set<uint8_t> payload_types;
46 
47   // Return string representation of demux criteria to facilitate logging
48   std::string ToString() const;
49 };
50 
51 // This class represents the RTP demuxing, for a single RTP session (i.e., one
52 // SSRC space, see RFC 7656). It isn't thread aware, leaving responsibility of
53 // multithreading issues to the user of this class.
54 // The demuxing algorithm follows the sketch given in the BUNDLE draft:
55 // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-38#section-10.2
56 // with modifications to support RTP stream IDs also.
57 //
58 // When a packet is received, the RtpDemuxer will route according to the
59 // following rules:
60 // 1. If the packet contains the MID header extension, and no sink has been
61 //    added with that MID as a criteria, the packet is not routed.
62 // 2. If the packet has the MID header extension, but no RSID or RRID extension,
63 //    and the MID is bound to a sink, then bind its SSRC to the same sink and
64 //    forward the packet to that sink. Note that rebinding to the same sink is
65 //    not an error. (Later packets with that SSRC would therefore be forwarded
66 //    to the same sink, whether they have the MID header extension or not.)
67 // 3. If the packet has the MID header extension and either the RSID or RRID
68 //    extension, and the MID, RSID (or RRID) pair is bound to a sink, then bind
69 //    its SSRC to the same sink and forward the packet to that sink. Later
70 //    packets with that SSRC will be forwarded to the same sink.
71 // 4. If the packet has the RSID or RRID header extension, but no MID extension,
72 //    and the RSID or RRID is bound to an RSID sink, then bind its SSRC to the
73 //    same sink and forward the packet to that sink. Later packets with that
74 //    SSRC will be forwarded to the same sink.
75 // 5. If the packet's SSRC is bound to an SSRC through a previous call to
76 //    AddSink, then forward the packet to that sink. Note that the RtpDemuxer
77 //    will not verify the payload type even if included in the sink's criteria.
78 //    The sink is expected to do the check in its handler.
79 // 6. If the packet's payload type is bound to exactly one payload type sink
80 //    through an earlier call to AddSink, then forward the packet to that sink.
81 // 7. Otherwise, the packet is not routed.
82 //
83 // In summary, the routing algorithm will always try to first match MID and RSID
84 // (including through SSRC binding), match SSRC directly as needed, and use
85 // payload types only if all else fails.
86 class RtpDemuxer {
87  public:
88   // Maximum number of unique SSRC bindings allowed. This limit is to prevent
89   // memory overuse attacks due to a malicious peer sending many packets with
90   // different SSRCs.
91   static constexpr int kMaxSsrcBindings = 1000;
92 
93   // Returns a string that contains all the attributes of the given packet
94   // relevant for demuxing.
95   static std::string DescribePacket(const RtpPacketReceived& packet);
96 
97   RtpDemuxer();
98   ~RtpDemuxer();
99 
100   RtpDemuxer(const RtpDemuxer&) = delete;
101   void operator=(const RtpDemuxer&) = delete;
102 
103   // Registers a sink that will be notified when RTP packets match its given
104   // criteria according to the algorithm described in the class description.
105   // Returns true if the sink was successfully added.
106   // Returns false in the following situations:
107   // - Only MID is specified and the MID is already registered.
108   // - Only RSID is specified and the RSID is already registered.
109   // - Both MID and RSID is specified and the (MID, RSID) pair is already
110   //   registered.
111   // - Any of the criteria SSRCs are already registered.
112   // If false is returned, no changes are made to the demuxer state.
113   bool AddSink(const RtpDemuxerCriteria& criteria,
114                RtpPacketSinkInterface* sink);
115 
116   // Registers a sink. Multiple SSRCs may be mapped to the same sink, but
117   // each SSRC may only be mapped to one sink. The return value reports
118   // whether the association has been recorded or rejected. Rejection may occur
119   // if the SSRC has already been associated with a sink. The previously added
120   // sink is *not* forgotten.
121   bool AddSink(uint32_t ssrc, RtpPacketSinkInterface* sink);
122 
123   // Registers a sink's association to an RSID. Only one sink may be associated
124   // with a given RSID. Null pointer is not allowed.
125   void AddSink(const std::string& rsid, RtpPacketSinkInterface* sink);
126 
127   // Removes a sink. Return value reports if anything was actually removed.
128   // Null pointer is not allowed.
129   bool RemoveSink(const RtpPacketSinkInterface* sink);
130 
131   // Demuxes the given packet and forwards it to the chosen sink. Returns true
132   // if the packet was forwarded and false if the packet was dropped.
133   bool OnRtpPacket(const RtpPacketReceived& packet);
134 
135   // Configure whether to look at the MID header extension when demuxing
136   // incoming RTP packets. By default this is enabled.
set_use_mid(bool use_mid)137   void set_use_mid(bool use_mid) { use_mid_ = use_mid; }
138 
139  private:
140   // Returns true if adding a sink with the given criteria would cause conflicts
141   // with the existing criteria and should be rejected.
142   bool CriteriaWouldConflict(const RtpDemuxerCriteria& criteria) const;
143 
144   // Runs the demux algorithm on the given packet and returns the sink that
145   // should receive the packet.
146   // Will record any SSRC<->ID associations along the way.
147   // If the packet should be dropped, this method returns null.
148   RtpPacketSinkInterface* ResolveSink(const RtpPacketReceived& packet);
149 
150   // Used by the ResolveSink algorithm.
151   RtpPacketSinkInterface* ResolveSinkByMid(const std::string& mid,
152                                            uint32_t ssrc);
153   RtpPacketSinkInterface* ResolveSinkByMidRsid(const std::string& mid,
154                                                const std::string& rsid,
155                                                uint32_t ssrc);
156   RtpPacketSinkInterface* ResolveSinkByRsid(const std::string& rsid,
157                                             uint32_t ssrc);
158   RtpPacketSinkInterface* ResolveSinkByPayloadType(uint8_t payload_type,
159                                                    uint32_t ssrc);
160 
161   // Regenerate the known_mids_ set from information in the sink_by_mid_ and
162   // sink_by_mid_and_rsid_ maps.
163   void RefreshKnownMids();
164 
165   // Map each sink by its component attributes to facilitate quick lookups.
166   // Payload Type mapping is a multimap because if two sinks register for the
167   // same payload type, both AddSinks succeed but we must know not to demux on
168   // that attribute since it is ambiguous.
169   // Note: Mappings are only modified by AddSink/RemoveSink (except for
170   // SSRC mapping which receives all MID, payload type, or RSID to SSRC bindings
171   // discovered when demuxing packets).
172   std::map<std::string, RtpPacketSinkInterface*> sink_by_mid_;
173   std::map<uint32_t, RtpPacketSinkInterface*> sink_by_ssrc_;
174   std::multimap<uint8_t, RtpPacketSinkInterface*> sinks_by_pt_;
175   std::map<std::pair<std::string, std::string>, RtpPacketSinkInterface*>
176       sink_by_mid_and_rsid_;
177   std::map<std::string, RtpPacketSinkInterface*> sink_by_rsid_;
178 
179   // Tracks all the MIDs that have been identified in added criteria. Used to
180   // determine if a packet should be dropped right away because the MID is
181   // unknown.
182   std::set<std::string> known_mids_;
183 
184   // Records learned mappings of MID --> SSRC and RSID --> SSRC as packets are
185   // received.
186   // This is stored separately from the sink mappings because if a sink is
187   // removed we want to still remember these associations.
188   std::map<uint32_t, std::string> mid_by_ssrc_;
189   std::map<uint32_t, std::string> rsid_by_ssrc_;
190 
191   // Adds a binding from the SSRC to the given sink.
192   void AddSsrcSinkBinding(uint32_t ssrc, RtpPacketSinkInterface* sink);
193 
194   bool use_mid_ = true;
195 };
196 
197 }  // namespace webrtc
198 
199 #endif  // CALL_RTP_DEMUXER_H_
200