1 /*
2  *  Copyright 2018 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 "pc/jsep_transport_controller.h"
12 
13 #include <map>
14 #include <memory>
15 
16 #include "p2p/base/dtls_transport_factory.h"
17 #include "p2p/base/fake_dtls_transport.h"
18 #include "p2p/base/fake_ice_transport.h"
19 #include "p2p/base/transport_info.h"
20 #include "rtc_base/gunit.h"
21 #include "rtc_base/thread.h"
22 #include "test/gtest.h"
23 
24 using cricket::Candidate;
25 using cricket::Candidates;
26 using cricket::FakeDtlsTransport;
27 using webrtc::SdpType;
28 
29 static const int kTimeout = 100;
30 static const char kIceUfrag1[] = "u0001";
31 static const char kIcePwd1[] = "TESTICEPWD00000000000001";
32 static const char kIceUfrag2[] = "u0002";
33 static const char kIcePwd2[] = "TESTICEPWD00000000000002";
34 static const char kIceUfrag3[] = "u0003";
35 static const char kIcePwd3[] = "TESTICEPWD00000000000003";
36 static const char kAudioMid1[] = "audio1";
37 static const char kAudioMid2[] = "audio2";
38 static const char kVideoMid1[] = "video1";
39 static const char kVideoMid2[] = "video2";
40 static const char kDataMid1[] = "data1";
41 
42 namespace webrtc {
43 
44 class FakeIceTransportFactory : public webrtc::IceTransportFactory {
45  public:
46   ~FakeIceTransportFactory() override = default;
CreateIceTransport(const std::string & transport_name,int component,IceTransportInit init)47   rtc::scoped_refptr<IceTransportInterface> CreateIceTransport(
48       const std::string& transport_name,
49       int component,
50       IceTransportInit init) override {
51     return new rtc::RefCountedObject<cricket::FakeIceTransportWrapper>(
52         std::make_unique<cricket::FakeIceTransport>(transport_name, component));
53   }
54 };
55 
56 class FakeDtlsTransportFactory : public cricket::DtlsTransportFactory {
57  public:
CreateDtlsTransport(cricket::IceTransportInternal * ice,const webrtc::CryptoOptions & crypto_options,rtc::SSLProtocolVersion max_version)58   std::unique_ptr<cricket::DtlsTransportInternal> CreateDtlsTransport(
59       cricket::IceTransportInternal* ice,
60       const webrtc::CryptoOptions& crypto_options,
61       rtc::SSLProtocolVersion max_version) override {
62     return std::make_unique<FakeDtlsTransport>(
63         static_cast<cricket::FakeIceTransport*>(ice));
64   }
65 };
66 
67 class JsepTransportControllerTest : public JsepTransportController::Observer,
68                                     public ::testing::Test,
69                                     public sigslot::has_slots<> {
70  public:
JsepTransportControllerTest()71   JsepTransportControllerTest() : signaling_thread_(rtc::Thread::Current()) {
72     fake_ice_transport_factory_ = std::make_unique<FakeIceTransportFactory>();
73     fake_dtls_transport_factory_ = std::make_unique<FakeDtlsTransportFactory>();
74   }
75 
CreateJsepTransportController(JsepTransportController::Config config,rtc::Thread * network_thread=rtc::Thread::Current (),cricket::PortAllocator * port_allocator=nullptr)76   void CreateJsepTransportController(
77       JsepTransportController::Config config,
78       rtc::Thread* network_thread = rtc::Thread::Current(),
79       cricket::PortAllocator* port_allocator = nullptr) {
80     config.transport_observer = this;
81     config.rtcp_handler = [](const rtc::CopyOnWriteBuffer& packet,
82                              int64_t packet_time_us) { RTC_NOTREACHED(); };
83     config.ice_transport_factory = fake_ice_transport_factory_.get();
84     config.dtls_transport_factory = fake_dtls_transport_factory_.get();
85     config.on_dtls_handshake_error_ = [](rtc::SSLHandshakeError s) {};
86     transport_controller_ = std::make_unique<JsepTransportController>(
87         network_thread, port_allocator, nullptr /* async_resolver_factory */,
88         config);
89     network_thread->Invoke<void>(RTC_FROM_HERE,
90                                  [&] { ConnectTransportControllerSignals(); });
91   }
92 
ConnectTransportControllerSignals()93   void ConnectTransportControllerSignals() {
94     transport_controller_->SubscribeIceConnectionState(
95         [this](cricket::IceConnectionState s) {
96           JsepTransportControllerTest::OnConnectionState(s);
97         });
98     transport_controller_->SubscribeConnectionState(
99         [this](PeerConnectionInterface::PeerConnectionState s) {
100           JsepTransportControllerTest::OnCombinedConnectionState(s);
101         });
102     transport_controller_->SubscribeStandardizedIceConnectionState(
103         [this](PeerConnectionInterface::IceConnectionState s) {
104           JsepTransportControllerTest::OnStandardizedIceConnectionState(s);
105         });
106     transport_controller_->SubscribeIceGatheringState(
107         [this](cricket::IceGatheringState s) {
108           JsepTransportControllerTest::OnGatheringState(s);
109         });
110     transport_controller_->SubscribeIceCandidateGathered(
111         [this](const std::string& transport,
112                const std::vector<cricket::Candidate>& candidates) {
113           JsepTransportControllerTest::OnCandidatesGathered(transport,
114                                                             candidates);
115         });
116   }
117 
118   std::unique_ptr<cricket::SessionDescription>
CreateSessionDescriptionWithoutBundle()119   CreateSessionDescriptionWithoutBundle() {
120     auto description = std::make_unique<cricket::SessionDescription>();
121     AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
122                     cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
123                     nullptr);
124     AddVideoSection(description.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
125                     cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
126                     nullptr);
127     return description;
128   }
129 
130   std::unique_ptr<cricket::SessionDescription>
CreateSessionDescriptionWithBundleGroup()131   CreateSessionDescriptionWithBundleGroup() {
132     auto description = CreateSessionDescriptionWithoutBundle();
133     cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
134     bundle_group.AddContentName(kAudioMid1);
135     bundle_group.AddContentName(kVideoMid1);
136     description->AddGroup(bundle_group);
137 
138     return description;
139   }
140 
141   std::unique_ptr<cricket::SessionDescription>
CreateSessionDescriptionWithBundledData()142   CreateSessionDescriptionWithBundledData() {
143     auto description = CreateSessionDescriptionWithoutBundle();
144     AddDataSection(description.get(), kDataMid1,
145                    cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
146                    cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
147                    nullptr);
148     cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
149     bundle_group.AddContentName(kAudioMid1);
150     bundle_group.AddContentName(kVideoMid1);
151     bundle_group.AddContentName(kDataMid1);
152     description->AddGroup(bundle_group);
153     return description;
154   }
155 
AddAudioSection(cricket::SessionDescription * description,const std::string & mid,const std::string & ufrag,const std::string & pwd,cricket::IceMode ice_mode,cricket::ConnectionRole conn_role,rtc::scoped_refptr<rtc::RTCCertificate> cert)156   void AddAudioSection(cricket::SessionDescription* description,
157                        const std::string& mid,
158                        const std::string& ufrag,
159                        const std::string& pwd,
160                        cricket::IceMode ice_mode,
161                        cricket::ConnectionRole conn_role,
162                        rtc::scoped_refptr<rtc::RTCCertificate> cert) {
163     std::unique_ptr<cricket::AudioContentDescription> audio(
164         new cricket::AudioContentDescription());
165     // Set RTCP-mux to be true because the default policy is "mux required".
166     audio->set_rtcp_mux(true);
167     description->AddContent(mid, cricket::MediaProtocolType::kRtp,
168                             /*rejected=*/false, std::move(audio));
169     AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
170   }
171 
AddVideoSection(cricket::SessionDescription * description,const std::string & mid,const std::string & ufrag,const std::string & pwd,cricket::IceMode ice_mode,cricket::ConnectionRole conn_role,rtc::scoped_refptr<rtc::RTCCertificate> cert)172   void AddVideoSection(cricket::SessionDescription* description,
173                        const std::string& mid,
174                        const std::string& ufrag,
175                        const std::string& pwd,
176                        cricket::IceMode ice_mode,
177                        cricket::ConnectionRole conn_role,
178                        rtc::scoped_refptr<rtc::RTCCertificate> cert) {
179     std::unique_ptr<cricket::VideoContentDescription> video(
180         new cricket::VideoContentDescription());
181     // Set RTCP-mux to be true because the default policy is "mux required".
182     video->set_rtcp_mux(true);
183     description->AddContent(mid, cricket::MediaProtocolType::kRtp,
184                             /*rejected=*/false, std::move(video));
185     AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
186   }
187 
AddDataSection(cricket::SessionDescription * description,const std::string & mid,cricket::MediaProtocolType protocol_type,const std::string & ufrag,const std::string & pwd,cricket::IceMode ice_mode,cricket::ConnectionRole conn_role,rtc::scoped_refptr<rtc::RTCCertificate> cert)188   void AddDataSection(cricket::SessionDescription* description,
189                       const std::string& mid,
190                       cricket::MediaProtocolType protocol_type,
191                       const std::string& ufrag,
192                       const std::string& pwd,
193                       cricket::IceMode ice_mode,
194                       cricket::ConnectionRole conn_role,
195                       rtc::scoped_refptr<rtc::RTCCertificate> cert) {
196     RTC_CHECK(protocol_type == cricket::MediaProtocolType::kSctp);
197     std::unique_ptr<cricket::SctpDataContentDescription> data(
198         new cricket::SctpDataContentDescription());
199     data->set_rtcp_mux(true);
200     description->AddContent(mid, protocol_type,
201                             /*rejected=*/false, std::move(data));
202     AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert);
203   }
204 
AddTransportInfo(cricket::SessionDescription * description,const std::string & mid,const std::string & ufrag,const std::string & pwd,cricket::IceMode ice_mode,cricket::ConnectionRole conn_role,rtc::scoped_refptr<rtc::RTCCertificate> cert)205   void AddTransportInfo(cricket::SessionDescription* description,
206                         const std::string& mid,
207                         const std::string& ufrag,
208                         const std::string& pwd,
209                         cricket::IceMode ice_mode,
210                         cricket::ConnectionRole conn_role,
211                         rtc::scoped_refptr<rtc::RTCCertificate> cert) {
212     std::unique_ptr<rtc::SSLFingerprint> fingerprint;
213     if (cert) {
214       fingerprint = rtc::SSLFingerprint::CreateFromCertificate(*cert);
215     }
216 
217     cricket::TransportDescription transport_desc(std::vector<std::string>(),
218                                                  ufrag, pwd, ice_mode,
219                                                  conn_role, fingerprint.get());
220     description->AddTransportInfo(cricket::TransportInfo(mid, transport_desc));
221   }
222 
CreateIceConfig(int receiving_timeout,cricket::ContinualGatheringPolicy continual_gathering_policy)223   cricket::IceConfig CreateIceConfig(
224       int receiving_timeout,
225       cricket::ContinualGatheringPolicy continual_gathering_policy) {
226     cricket::IceConfig config;
227     config.receiving_timeout = receiving_timeout;
228     config.continual_gathering_policy = continual_gathering_policy;
229     return config;
230   }
231 
CreateCandidate(const std::string & transport_name,int component)232   Candidate CreateCandidate(const std::string& transport_name, int component) {
233     Candidate c;
234     c.set_transport_name(transport_name);
235     c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
236     c.set_component(component);
237     c.set_protocol(cricket::UDP_PROTOCOL_NAME);
238     c.set_priority(1);
239     return c;
240   }
241 
CreateLocalDescriptionAndCompleteConnectionOnNetworkThread()242   void CreateLocalDescriptionAndCompleteConnectionOnNetworkThread() {
243     if (!network_thread_->IsCurrent()) {
244       network_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
245         CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
246       });
247       return;
248     }
249 
250     auto description = CreateSessionDescriptionWithBundleGroup();
251     EXPECT_TRUE(transport_controller_
252                     ->SetLocalDescription(SdpType::kOffer, description.get())
253                     .ok());
254 
255     transport_controller_->MaybeStartGathering();
256     auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
257         transport_controller_->GetDtlsTransport(kAudioMid1));
258     auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
259         transport_controller_->GetDtlsTransport(kVideoMid1));
260     fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
261         fake_audio_dtls->fake_ice_transport(),
262         CreateCandidate(kAudioMid1, /*component=*/1));
263     fake_video_dtls->fake_ice_transport()->SignalCandidateGathered(
264         fake_video_dtls->fake_ice_transport(),
265         CreateCandidate(kVideoMid1, /*component=*/1));
266     fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
267     fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
268     fake_audio_dtls->fake_ice_transport()->SetConnectionCount(2);
269     fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
270     fake_audio_dtls->SetReceiving(true);
271     fake_video_dtls->SetReceiving(true);
272     fake_audio_dtls->SetWritable(true);
273     fake_video_dtls->SetWritable(true);
274     fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
275     fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
276   }
277 
278  protected:
OnConnectionState(cricket::IceConnectionState state)279   void OnConnectionState(cricket::IceConnectionState state) {
280     ice_signaled_on_thread_ = rtc::Thread::Current();
281     connection_state_ = state;
282     ++connection_state_signal_count_;
283   }
284 
OnStandardizedIceConnectionState(PeerConnectionInterface::IceConnectionState state)285   void OnStandardizedIceConnectionState(
286       PeerConnectionInterface::IceConnectionState state) {
287     ice_signaled_on_thread_ = rtc::Thread::Current();
288     ice_connection_state_ = state;
289     ++ice_connection_state_signal_count_;
290   }
291 
OnCombinedConnectionState(PeerConnectionInterface::PeerConnectionState state)292   void OnCombinedConnectionState(
293       PeerConnectionInterface::PeerConnectionState state) {
294     RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
295                      << static_cast<int>(state);
296     ice_signaled_on_thread_ = rtc::Thread::Current();
297     combined_connection_state_ = state;
298     ++combined_connection_state_signal_count_;
299   }
300 
OnGatheringState(cricket::IceGatheringState state)301   void OnGatheringState(cricket::IceGatheringState state) {
302     ice_signaled_on_thread_ = rtc::Thread::Current();
303     gathering_state_ = state;
304     ++gathering_state_signal_count_;
305   }
306 
OnCandidatesGathered(const std::string & transport_name,const Candidates & candidates)307   void OnCandidatesGathered(const std::string& transport_name,
308                             const Candidates& candidates) {
309     ice_signaled_on_thread_ = rtc::Thread::Current();
310     candidates_[transport_name].insert(candidates_[transport_name].end(),
311                                        candidates.begin(), candidates.end());
312     ++candidates_signal_count_;
313   }
314 
315   // JsepTransportController::Observer overrides.
OnTransportChanged(const std::string & mid,RtpTransportInternal * rtp_transport,rtc::scoped_refptr<DtlsTransport> dtls_transport,DataChannelTransportInterface * data_channel_transport)316   bool OnTransportChanged(
317       const std::string& mid,
318       RtpTransportInternal* rtp_transport,
319       rtc::scoped_refptr<DtlsTransport> dtls_transport,
320       DataChannelTransportInterface* data_channel_transport) override {
321     changed_rtp_transport_by_mid_[mid] = rtp_transport;
322     if (dtls_transport) {
323       changed_dtls_transport_by_mid_[mid] = dtls_transport->internal();
324     } else {
325       changed_dtls_transport_by_mid_[mid] = nullptr;
326     }
327     return true;
328   }
329 
330   // Information received from signals from transport controller.
331   cricket::IceConnectionState connection_state_ =
332       cricket::kIceConnectionConnecting;
333   PeerConnectionInterface::IceConnectionState ice_connection_state_ =
334       PeerConnectionInterface::kIceConnectionNew;
335   PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
336       PeerConnectionInterface::PeerConnectionState::kNew;
337   bool receiving_ = false;
338   cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
339   // transport_name => candidates
340   std::map<std::string, Candidates> candidates_;
341   // Counts of each signal emitted.
342   int connection_state_signal_count_ = 0;
343   int ice_connection_state_signal_count_ = 0;
344   int combined_connection_state_signal_count_ = 0;
345   int receiving_signal_count_ = 0;
346   int gathering_state_signal_count_ = 0;
347   int candidates_signal_count_ = 0;
348 
349   // |network_thread_| should be destroyed after |transport_controller_|
350   std::unique_ptr<rtc::Thread> network_thread_;
351   std::unique_ptr<FakeIceTransportFactory> fake_ice_transport_factory_;
352   std::unique_ptr<FakeDtlsTransportFactory> fake_dtls_transport_factory_;
353   rtc::Thread* const signaling_thread_ = nullptr;
354   rtc::Thread* ice_signaled_on_thread_ = nullptr;
355   // Used to verify the SignalRtpTransportChanged/SignalDtlsTransportChanged are
356   // signaled correctly.
357   std::map<std::string, RtpTransportInternal*> changed_rtp_transport_by_mid_;
358   std::map<std::string, cricket::DtlsTransportInternal*>
359       changed_dtls_transport_by_mid_;
360 
361   // Transport controller needs to be destroyed first, because it may issue
362   // callbacks that modify the changed_*_by_mid in the destructor.
363   std::unique_ptr<JsepTransportController> transport_controller_;
364 };
365 
TEST_F(JsepTransportControllerTest,GetRtpTransport)366 TEST_F(JsepTransportControllerTest, GetRtpTransport) {
367   CreateJsepTransportController(JsepTransportController::Config());
368   auto description = CreateSessionDescriptionWithoutBundle();
369   EXPECT_TRUE(transport_controller_
370                   ->SetLocalDescription(SdpType::kOffer, description.get())
371                   .ok());
372   auto audio_rtp_transport = transport_controller_->GetRtpTransport(kAudioMid1);
373   auto video_rtp_transport = transport_controller_->GetRtpTransport(kVideoMid1);
374   EXPECT_NE(nullptr, audio_rtp_transport);
375   EXPECT_NE(nullptr, video_rtp_transport);
376   EXPECT_NE(audio_rtp_transport, video_rtp_transport);
377   // Return nullptr for non-existing ones.
378   EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid2));
379 }
380 
TEST_F(JsepTransportControllerTest,GetDtlsTransport)381 TEST_F(JsepTransportControllerTest, GetDtlsTransport) {
382   JsepTransportController::Config config;
383   config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
384   CreateJsepTransportController(config);
385   auto description = CreateSessionDescriptionWithoutBundle();
386   EXPECT_TRUE(transport_controller_
387                   ->SetLocalDescription(SdpType::kOffer, description.get())
388                   .ok());
389   EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
390   EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
391   EXPECT_NE(nullptr,
392             transport_controller_->LookupDtlsTransportByMid(kAudioMid1));
393   EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
394   EXPECT_NE(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
395   EXPECT_NE(nullptr,
396             transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
397   // Lookup for all MIDs should return different transports (no bundle)
398   EXPECT_NE(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
399             transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
400   // Return nullptr for non-existing ones.
401   EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kVideoMid2));
402   EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2));
403   EXPECT_EQ(nullptr,
404             transport_controller_->LookupDtlsTransportByMid(kVideoMid2));
405   // Take a pointer to a transport, shut down the transport controller,
406   // and verify that the resulting container is empty.
407   auto dtls_transport =
408       transport_controller_->LookupDtlsTransportByMid(kVideoMid1);
409   webrtc::DtlsTransport* my_transport =
410       static_cast<DtlsTransport*>(dtls_transport.get());
411   EXPECT_NE(nullptr, my_transport->internal());
412   transport_controller_.reset();
413   EXPECT_EQ(nullptr, my_transport->internal());
414 }
415 
TEST_F(JsepTransportControllerTest,GetDtlsTransportWithRtcpMux)416 TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) {
417   JsepTransportController::Config config;
418   config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
419   CreateJsepTransportController(config);
420   auto description = CreateSessionDescriptionWithoutBundle();
421   EXPECT_TRUE(transport_controller_
422                   ->SetLocalDescription(SdpType::kOffer, description.get())
423                   .ok());
424   EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1));
425   EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
426   EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
427   EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
428 }
429 
TEST_F(JsepTransportControllerTest,SetIceConfig)430 TEST_F(JsepTransportControllerTest, SetIceConfig) {
431   CreateJsepTransportController(JsepTransportController::Config());
432   auto description = CreateSessionDescriptionWithoutBundle();
433   EXPECT_TRUE(transport_controller_
434                   ->SetLocalDescription(SdpType::kOffer, description.get())
435                   .ok());
436 
437   transport_controller_->SetIceConfig(
438       CreateIceConfig(kTimeout, cricket::GATHER_CONTINUALLY));
439   FakeDtlsTransport* fake_audio_dtls = static_cast<FakeDtlsTransport*>(
440       transport_controller_->GetDtlsTransport(kAudioMid1));
441   ASSERT_NE(nullptr, fake_audio_dtls);
442   EXPECT_EQ(kTimeout,
443             fake_audio_dtls->fake_ice_transport()->receiving_timeout());
444   EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
445 
446   // Test that value stored in controller is applied to new transports.
447   AddAudioSection(description.get(), kAudioMid2, kIceUfrag1, kIcePwd1,
448                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
449                   nullptr);
450 
451   EXPECT_TRUE(transport_controller_
452                   ->SetLocalDescription(SdpType::kOffer, description.get())
453                   .ok());
454   fake_audio_dtls = static_cast<FakeDtlsTransport*>(
455       transport_controller_->GetDtlsTransport(kAudioMid2));
456   ASSERT_NE(nullptr, fake_audio_dtls);
457   EXPECT_EQ(kTimeout,
458             fake_audio_dtls->fake_ice_transport()->receiving_timeout());
459   EXPECT_TRUE(fake_audio_dtls->fake_ice_transport()->gather_continually());
460 }
461 
462 // Tests the getter and setter of the ICE restart flag.
TEST_F(JsepTransportControllerTest,NeedIceRestart)463 TEST_F(JsepTransportControllerTest, NeedIceRestart) {
464   CreateJsepTransportController(JsepTransportController::Config());
465   auto description = CreateSessionDescriptionWithoutBundle();
466   EXPECT_TRUE(transport_controller_
467                   ->SetLocalDescription(SdpType::kOffer, description.get())
468                   .ok());
469   EXPECT_TRUE(transport_controller_
470                   ->SetRemoteDescription(SdpType::kAnswer, description.get())
471                   .ok());
472 
473   // Initially NeedsIceRestart should return false.
474   EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
475   EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid1));
476   // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning
477   // true.
478   transport_controller_->SetNeedsIceRestartFlag();
479   EXPECT_TRUE(transport_controller_->NeedsIceRestart(kAudioMid1));
480   EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
481   // For a nonexistent transport, false should be returned.
482   EXPECT_FALSE(transport_controller_->NeedsIceRestart(kVideoMid2));
483 
484   // Reset the ice_ufrag/ice_pwd for audio.
485   auto audio_transport_info = description->GetTransportInfoByName(kAudioMid1);
486   audio_transport_info->description.ice_ufrag = kIceUfrag2;
487   audio_transport_info->description.ice_pwd = kIcePwd2;
488   EXPECT_TRUE(transport_controller_
489                   ->SetLocalDescription(SdpType::kOffer, description.get())
490                   .ok());
491   // Because the ICE is only restarted for audio, NeedsIceRestart is expected to
492   // return false for audio and true for video.
493   EXPECT_FALSE(transport_controller_->NeedsIceRestart(kAudioMid1));
494   EXPECT_TRUE(transport_controller_->NeedsIceRestart(kVideoMid1));
495 }
496 
TEST_F(JsepTransportControllerTest,MaybeStartGathering)497 TEST_F(JsepTransportControllerTest, MaybeStartGathering) {
498   CreateJsepTransportController(JsepTransportController::Config());
499   auto description = CreateSessionDescriptionWithBundleGroup();
500   EXPECT_TRUE(transport_controller_
501                   ->SetLocalDescription(SdpType::kOffer, description.get())
502                   .ok());
503   // After setting the local description, we should be able to start gathering
504   // candidates.
505   transport_controller_->MaybeStartGathering();
506   EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
507   EXPECT_EQ(1, gathering_state_signal_count_);
508 }
509 
TEST_F(JsepTransportControllerTest,AddRemoveRemoteCandidates)510 TEST_F(JsepTransportControllerTest, AddRemoveRemoteCandidates) {
511   CreateJsepTransportController(JsepTransportController::Config());
512   auto description = CreateSessionDescriptionWithoutBundle();
513   transport_controller_->SetLocalDescription(SdpType::kOffer,
514                                              description.get());
515   transport_controller_->SetRemoteDescription(SdpType::kAnswer,
516                                               description.get());
517   auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
518       transport_controller_->GetDtlsTransport(kAudioMid1));
519   ASSERT_NE(nullptr, fake_audio_dtls);
520   Candidates candidates;
521   candidates.push_back(
522       CreateCandidate(kAudioMid1, cricket::ICE_CANDIDATE_COMPONENT_RTP));
523   EXPECT_TRUE(
524       transport_controller_->AddRemoteCandidates(kAudioMid1, candidates).ok());
525   EXPECT_EQ(1U,
526             fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
527 
528   EXPECT_TRUE(transport_controller_->RemoveRemoteCandidates(candidates).ok());
529   EXPECT_EQ(0U,
530             fake_audio_dtls->fake_ice_transport()->remote_candidates().size());
531 }
532 
TEST_F(JsepTransportControllerTest,SetAndGetLocalCertificate)533 TEST_F(JsepTransportControllerTest, SetAndGetLocalCertificate) {
534   CreateJsepTransportController(JsepTransportController::Config());
535 
536   rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
537       rtc::RTCCertificate::Create(
538           rtc::SSLIdentity::Create("session1", rtc::KT_DEFAULT));
539   rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
540 
541   auto description = std::make_unique<cricket::SessionDescription>();
542   AddAudioSection(description.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
543                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
544                   certificate1);
545 
546   // Apply the local certificate.
547   EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
548   // Apply the local description.
549   EXPECT_TRUE(transport_controller_
550                   ->SetLocalDescription(SdpType::kOffer, description.get())
551                   .ok());
552   returned_certificate = transport_controller_->GetLocalCertificate(kAudioMid1);
553   EXPECT_TRUE(returned_certificate);
554   EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
555             returned_certificate->identity()->certificate().ToPEMString());
556 
557   // Should fail if called for a nonexistant transport.
558   EXPECT_EQ(nullptr, transport_controller_->GetLocalCertificate(kVideoMid1));
559 
560   // Shouldn't be able to change the identity once set.
561   rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
562       rtc::RTCCertificate::Create(
563           rtc::SSLIdentity::Create("session2", rtc::KT_DEFAULT));
564   EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
565 }
566 
TEST_F(JsepTransportControllerTest,GetRemoteSSLCertChain)567 TEST_F(JsepTransportControllerTest, GetRemoteSSLCertChain) {
568   CreateJsepTransportController(JsepTransportController::Config());
569   auto description = CreateSessionDescriptionWithBundleGroup();
570   EXPECT_TRUE(transport_controller_
571                   ->SetLocalDescription(SdpType::kOffer, description.get())
572                   .ok());
573   rtc::FakeSSLCertificate fake_certificate("fake_data");
574 
575   auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
576       transport_controller_->GetDtlsTransport(kAudioMid1));
577   fake_audio_dtls->SetRemoteSSLCertificate(&fake_certificate);
578   std::unique_ptr<rtc::SSLCertChain> returned_cert_chain =
579       transport_controller_->GetRemoteSSLCertChain(kAudioMid1);
580   ASSERT_TRUE(returned_cert_chain);
581   ASSERT_EQ(1u, returned_cert_chain->GetSize());
582   EXPECT_EQ(fake_certificate.ToPEMString(),
583             returned_cert_chain->Get(0).ToPEMString());
584 
585   // Should fail if called for a nonexistant transport.
586   EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain(kAudioMid2));
587 }
588 
TEST_F(JsepTransportControllerTest,GetDtlsRole)589 TEST_F(JsepTransportControllerTest, GetDtlsRole) {
590   CreateJsepTransportController(JsepTransportController::Config());
591   auto offer_certificate = rtc::RTCCertificate::Create(
592       rtc::SSLIdentity::Create("offer", rtc::KT_DEFAULT));
593   auto answer_certificate = rtc::RTCCertificate::Create(
594       rtc::SSLIdentity::Create("answer", rtc::KT_DEFAULT));
595   transport_controller_->SetLocalCertificate(offer_certificate);
596 
597   auto offer_desc = std::make_unique<cricket::SessionDescription>();
598   AddAudioSection(offer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
599                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
600                   offer_certificate);
601   auto answer_desc = std::make_unique<cricket::SessionDescription>();
602   AddAudioSection(answer_desc.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
603                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
604                   answer_certificate);
605 
606   EXPECT_TRUE(transport_controller_
607                   ->SetLocalDescription(SdpType::kOffer, offer_desc.get())
608                   .ok());
609 
610   absl::optional<rtc::SSLRole> role =
611       transport_controller_->GetDtlsRole(kAudioMid1);
612   // The DTLS role is not decided yet.
613   EXPECT_FALSE(role);
614   EXPECT_TRUE(transport_controller_
615                   ->SetRemoteDescription(SdpType::kAnswer, answer_desc.get())
616                   .ok());
617   role = transport_controller_->GetDtlsRole(kAudioMid1);
618 
619   ASSERT_TRUE(role);
620   EXPECT_EQ(rtc::SSL_CLIENT, *role);
621 }
622 
TEST_F(JsepTransportControllerTest,GetStats)623 TEST_F(JsepTransportControllerTest, GetStats) {
624   CreateJsepTransportController(JsepTransportController::Config());
625   auto description = CreateSessionDescriptionWithBundleGroup();
626   EXPECT_TRUE(transport_controller_
627                   ->SetLocalDescription(SdpType::kOffer, description.get())
628                   .ok());
629 
630   cricket::TransportStats stats;
631   EXPECT_TRUE(transport_controller_->GetStats(kAudioMid1, &stats));
632   EXPECT_EQ(kAudioMid1, stats.transport_name);
633   EXPECT_EQ(1u, stats.channel_stats.size());
634   // Return false for non-existing transport.
635   EXPECT_FALSE(transport_controller_->GetStats(kAudioMid2, &stats));
636 }
637 
TEST_F(JsepTransportControllerTest,SignalConnectionStateFailed)638 TEST_F(JsepTransportControllerTest, SignalConnectionStateFailed) {
639   CreateJsepTransportController(JsepTransportController::Config());
640   auto description = CreateSessionDescriptionWithoutBundle();
641   EXPECT_TRUE(transport_controller_
642                   ->SetLocalDescription(SdpType::kOffer, description.get())
643                   .ok());
644 
645   auto fake_ice = static_cast<cricket::FakeIceTransport*>(
646       transport_controller_->GetDtlsTransport(kAudioMid1)->ice_transport());
647   fake_ice->SetCandidatesGatheringComplete();
648   fake_ice->SetConnectionCount(1);
649   // The connection stats will be failed if there is no active connection.
650   fake_ice->SetConnectionCount(0);
651   EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
652   EXPECT_EQ(1, connection_state_signal_count_);
653   EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
654                  ice_connection_state_, kTimeout);
655   EXPECT_EQ(1, ice_connection_state_signal_count_);
656   EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
657                  combined_connection_state_, kTimeout);
658   EXPECT_EQ(1, combined_connection_state_signal_count_);
659 }
660 
TEST_F(JsepTransportControllerTest,SignalConnectionStateConnectedNoMediaTransport)661 TEST_F(JsepTransportControllerTest,
662        SignalConnectionStateConnectedNoMediaTransport) {
663   CreateJsepTransportController(JsepTransportController::Config());
664   auto description = CreateSessionDescriptionWithoutBundle();
665   EXPECT_TRUE(transport_controller_
666                   ->SetLocalDescription(SdpType::kOffer, description.get())
667                   .ok());
668 
669   auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
670       transport_controller_->GetDtlsTransport(kAudioMid1));
671   auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
672       transport_controller_->GetDtlsTransport(kVideoMid1));
673 
674   // First, have one transport connect, and another fail, to ensure that
675   // the first transport connecting didn't trigger a "connected" state signal.
676   // We should only get a signal when all are connected.
677   fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
678   fake_audio_dtls->SetWritable(true);
679   fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
680   // Decrease the number of the connection to trigger the signal.
681   fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
682   fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
683   fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
684 
685   EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
686   EXPECT_EQ(1, connection_state_signal_count_);
687   EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
688                  ice_connection_state_, kTimeout);
689   EXPECT_EQ(2, ice_connection_state_signal_count_);
690   EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
691                  combined_connection_state_, kTimeout);
692   EXPECT_EQ(2, combined_connection_state_signal_count_);
693 
694   fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
695   fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
696   // Set the connection count to be 2 and the cricket::FakeIceTransport will set
697   // the transport state to be STATE_CONNECTING.
698   fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
699   fake_video_dtls->SetWritable(true);
700   EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
701   EXPECT_EQ(2, connection_state_signal_count_);
702   EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
703                  ice_connection_state_, kTimeout);
704   EXPECT_EQ(3, ice_connection_state_signal_count_);
705   EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
706                  combined_connection_state_, kTimeout);
707   EXPECT_EQ(3, combined_connection_state_signal_count_);
708 }
709 
TEST_F(JsepTransportControllerTest,SignalConnectionStateComplete)710 TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
711   CreateJsepTransportController(JsepTransportController::Config());
712   auto description = CreateSessionDescriptionWithoutBundle();
713   EXPECT_TRUE(transport_controller_
714                   ->SetLocalDescription(SdpType::kOffer, description.get())
715                   .ok());
716 
717   auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
718       transport_controller_->GetDtlsTransport(kAudioMid1));
719   auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
720       transport_controller_->GetDtlsTransport(kVideoMid1));
721 
722   // First, have one transport connect, and another fail, to ensure that
723   // the first transport connecting didn't trigger a "connected" state signal.
724   // We should only get a signal when all are connected.
725   fake_audio_dtls->fake_ice_transport()->SetTransportState(
726       IceTransportState::kCompleted,
727       cricket::IceTransportState::STATE_COMPLETED);
728   fake_audio_dtls->SetWritable(true);
729   fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
730 
731   EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
732                  ice_connection_state_, kTimeout);
733   EXPECT_EQ(1, ice_connection_state_signal_count_);
734   EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
735                  combined_connection_state_, kTimeout);
736   EXPECT_EQ(1, combined_connection_state_signal_count_);
737 
738   fake_video_dtls->fake_ice_transport()->SetTransportState(
739       IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
740   fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
741 
742   EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
743   EXPECT_EQ(1, connection_state_signal_count_);
744   EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
745                  ice_connection_state_, kTimeout);
746   EXPECT_EQ(2, ice_connection_state_signal_count_);
747   EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
748                  combined_connection_state_, kTimeout);
749   EXPECT_EQ(2, combined_connection_state_signal_count_);
750 
751   fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
752   fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
753   // Set the connection count to be 1 and the cricket::FakeIceTransport will set
754   // the transport state to be STATE_COMPLETED.
755   fake_video_dtls->fake_ice_transport()->SetTransportState(
756       IceTransportState::kCompleted,
757       cricket::IceTransportState::STATE_COMPLETED);
758   fake_video_dtls->SetWritable(true);
759   EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
760   EXPECT_EQ(3, connection_state_signal_count_);
761   EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
762                  ice_connection_state_, kTimeout);
763   EXPECT_EQ(3, ice_connection_state_signal_count_);
764   EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
765                  combined_connection_state_, kTimeout);
766   EXPECT_EQ(3, combined_connection_state_signal_count_);
767 }
768 
TEST_F(JsepTransportControllerTest,SignalIceGatheringStateGathering)769 TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
770   CreateJsepTransportController(JsepTransportController::Config());
771   auto description = CreateSessionDescriptionWithoutBundle();
772   EXPECT_TRUE(transport_controller_
773                   ->SetLocalDescription(SdpType::kOffer, description.get())
774                   .ok());
775 
776   auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
777       transport_controller_->GetDtlsTransport(kAudioMid1));
778   fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
779   // Should be in the gathering state as soon as any transport starts gathering.
780   EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
781   EXPECT_EQ(1, gathering_state_signal_count_);
782 }
783 
TEST_F(JsepTransportControllerTest,SignalIceGatheringStateComplete)784 TEST_F(JsepTransportControllerTest, SignalIceGatheringStateComplete) {
785   CreateJsepTransportController(JsepTransportController::Config());
786   auto description = CreateSessionDescriptionWithoutBundle();
787   EXPECT_TRUE(transport_controller_
788                   ->SetLocalDescription(SdpType::kOffer, description.get())
789                   .ok());
790 
791   auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
792       transport_controller_->GetDtlsTransport(kAudioMid1));
793   auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
794       transport_controller_->GetDtlsTransport(kVideoMid1));
795 
796   fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
797   EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
798   EXPECT_EQ(1, gathering_state_signal_count_);
799 
800   // Have one transport finish gathering, to make sure gathering
801   // completion wasn't signalled if only one transport finished gathering.
802   fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
803   EXPECT_EQ(1, gathering_state_signal_count_);
804 
805   fake_video_dtls->fake_ice_transport()->MaybeStartGathering();
806   EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
807   EXPECT_EQ(1, gathering_state_signal_count_);
808 
809   fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
810   EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
811   EXPECT_EQ(2, gathering_state_signal_count_);
812 }
813 
814 // Test that when the last transport that hasn't finished connecting and/or
815 // gathering is destroyed, the aggregate state jumps to "completed". This can
816 // happen if, for example, we have an audio and video transport, the audio
817 // transport completes, then we start bundling video on the audio transport.
TEST_F(JsepTransportControllerTest,SignalingWhenLastIncompleteTransportDestroyed)818 TEST_F(JsepTransportControllerTest,
819        SignalingWhenLastIncompleteTransportDestroyed) {
820   CreateJsepTransportController(JsepTransportController::Config());
821   auto description = CreateSessionDescriptionWithBundleGroup();
822   EXPECT_TRUE(transport_controller_
823                   ->SetLocalDescription(SdpType::kOffer, description.get())
824                   .ok());
825 
826   auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
827       transport_controller_->GetDtlsTransport(kAudioMid1));
828   auto fake_video_dtls = static_cast<FakeDtlsTransport*>(
829       transport_controller_->GetDtlsTransport(kVideoMid1));
830   EXPECT_NE(fake_audio_dtls, fake_video_dtls);
831 
832   fake_audio_dtls->fake_ice_transport()->MaybeStartGathering();
833   EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
834   EXPECT_EQ(1, gathering_state_signal_count_);
835 
836   // Let the audio transport complete.
837   fake_audio_dtls->SetWritable(true);
838   fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
839   fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
840   fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
841   EXPECT_EQ(1, gathering_state_signal_count_);
842 
843   // Set the remote description and enable the bundle.
844   EXPECT_TRUE(transport_controller_
845                   ->SetRemoteDescription(SdpType::kAnswer, description.get())
846                   .ok());
847   // The BUNDLE should be enabled, the incomplete video transport should be
848   // deleted and the states shoud be updated.
849   fake_video_dtls = static_cast<FakeDtlsTransport*>(
850       transport_controller_->GetDtlsTransport(kVideoMid1));
851   EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
852   EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
853   EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
854             ice_connection_state_);
855   EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
856             combined_connection_state_);
857   EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
858   EXPECT_EQ(2, gathering_state_signal_count_);
859 }
860 
TEST_F(JsepTransportControllerTest,SignalCandidatesGathered)861 TEST_F(JsepTransportControllerTest, SignalCandidatesGathered) {
862   CreateJsepTransportController(JsepTransportController::Config());
863   auto description = CreateSessionDescriptionWithBundleGroup();
864   EXPECT_TRUE(transport_controller_
865                   ->SetLocalDescription(SdpType::kOffer, description.get())
866                   .ok());
867   transport_controller_->MaybeStartGathering();
868 
869   auto fake_audio_dtls = static_cast<FakeDtlsTransport*>(
870       transport_controller_->GetDtlsTransport(kAudioMid1));
871   fake_audio_dtls->fake_ice_transport()->SignalCandidateGathered(
872       fake_audio_dtls->fake_ice_transport(), CreateCandidate(kAudioMid1, 1));
873   EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
874   EXPECT_EQ(1u, candidates_[kAudioMid1].size());
875 }
876 
TEST_F(JsepTransportControllerTest,IceSignalingOccursOnNetworkThread)877 TEST_F(JsepTransportControllerTest, IceSignalingOccursOnNetworkThread) {
878   network_thread_ = rtc::Thread::CreateWithSocketServer();
879   network_thread_->Start();
880   EXPECT_EQ(ice_signaled_on_thread_, nullptr);
881   CreateJsepTransportController(JsepTransportController::Config(),
882                                 network_thread_.get(),
883                                 /*port_allocator=*/nullptr);
884   CreateLocalDescriptionAndCompleteConnectionOnNetworkThread();
885 
886   // connecting --> connected --> completed
887   EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
888   EXPECT_EQ(2, connection_state_signal_count_);
889 
890   // new --> gathering --> complete
891   EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
892   EXPECT_EQ(2, gathering_state_signal_count_);
893 
894   EXPECT_EQ_WAIT(1u, candidates_[kAudioMid1].size(), kTimeout);
895   EXPECT_EQ_WAIT(1u, candidates_[kVideoMid1].size(), kTimeout);
896   EXPECT_EQ(2, candidates_signal_count_);
897 
898   EXPECT_EQ(ice_signaled_on_thread_, network_thread_.get());
899 
900   network_thread_->Invoke<void>(RTC_FROM_HERE,
901                                 [&] { transport_controller_.reset(); });
902 }
903 
904 // Test that if the TransportController was created with the
905 // |redetermine_role_on_ice_restart| parameter set to false, the role is *not*
906 // redetermined on an ICE restart.
TEST_F(JsepTransportControllerTest,IceRoleNotRedetermined)907 TEST_F(JsepTransportControllerTest, IceRoleNotRedetermined) {
908   JsepTransportController::Config config;
909   config.redetermine_role_on_ice_restart = false;
910 
911   CreateJsepTransportController(config);
912   // Let the |transport_controller_| be the controlled side initially.
913   auto remote_offer = std::make_unique<cricket::SessionDescription>();
914   AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
915                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
916                   nullptr);
917   auto local_answer = std::make_unique<cricket::SessionDescription>();
918   AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
919                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
920                   nullptr);
921 
922   EXPECT_TRUE(transport_controller_
923                   ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
924                   .ok());
925   EXPECT_TRUE(transport_controller_
926                   ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
927                   .ok());
928 
929   auto fake_dtls = static_cast<FakeDtlsTransport*>(
930       transport_controller_->GetDtlsTransport(kAudioMid1));
931   EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
932             fake_dtls->fake_ice_transport()->GetIceRole());
933 
934   // New offer will trigger the ICE restart.
935   auto restart_local_offer = std::make_unique<cricket::SessionDescription>();
936   AddAudioSection(restart_local_offer.get(), kAudioMid1, kIceUfrag3, kIcePwd3,
937                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
938                   nullptr);
939   EXPECT_TRUE(
940       transport_controller_
941           ->SetLocalDescription(SdpType::kOffer, restart_local_offer.get())
942           .ok());
943   EXPECT_EQ(cricket::ICEROLE_CONTROLLED,
944             fake_dtls->fake_ice_transport()->GetIceRole());
945 }
946 
947 // Tests ICE-Lite mode in remote answer.
TEST_F(JsepTransportControllerTest,SetIceRoleWhenIceLiteInRemoteAnswer)948 TEST_F(JsepTransportControllerTest, SetIceRoleWhenIceLiteInRemoteAnswer) {
949   CreateJsepTransportController(JsepTransportController::Config());
950   auto local_offer = std::make_unique<cricket::SessionDescription>();
951   AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
952                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
953                   nullptr);
954   EXPECT_TRUE(transport_controller_
955                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
956                   .ok());
957   auto fake_dtls = static_cast<FakeDtlsTransport*>(
958       transport_controller_->GetDtlsTransport(kAudioMid1));
959   EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
960             fake_dtls->fake_ice_transport()->GetIceRole());
961   EXPECT_EQ(cricket::ICEMODE_FULL,
962             fake_dtls->fake_ice_transport()->remote_ice_mode());
963 
964   auto remote_answer = std::make_unique<cricket::SessionDescription>();
965   AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
966                   cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_PASSIVE,
967                   nullptr);
968   EXPECT_TRUE(transport_controller_
969                   ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
970                   .ok());
971   EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
972             fake_dtls->fake_ice_transport()->GetIceRole());
973   EXPECT_EQ(cricket::ICEMODE_LITE,
974             fake_dtls->fake_ice_transport()->remote_ice_mode());
975 }
976 
977 // Tests that the ICE role remains "controlling" if a subsequent offer that
978 // does an ICE restart is received from an ICE lite endpoint. Regression test
979 // for: https://crbug.com/710760
TEST_F(JsepTransportControllerTest,IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint)980 TEST_F(JsepTransportControllerTest,
981        IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) {
982   CreateJsepTransportController(JsepTransportController::Config());
983   auto remote_offer = std::make_unique<cricket::SessionDescription>();
984   AddAudioSection(remote_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
985                   cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
986                   nullptr);
987   auto local_answer = std::make_unique<cricket::SessionDescription>();
988   AddAudioSection(local_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
989                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
990                   nullptr);
991   // Initial Offer/Answer exchange. If the remote offerer is ICE-Lite, then the
992   // local side is the controlling.
993   EXPECT_TRUE(transport_controller_
994                   ->SetRemoteDescription(SdpType::kOffer, remote_offer.get())
995                   .ok());
996   EXPECT_TRUE(transport_controller_
997                   ->SetLocalDescription(SdpType::kAnswer, local_answer.get())
998                   .ok());
999   auto fake_dtls = static_cast<FakeDtlsTransport*>(
1000       transport_controller_->GetDtlsTransport(kAudioMid1));
1001   EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1002             fake_dtls->fake_ice_transport()->GetIceRole());
1003 
1004   // In the subsequence remote offer triggers an ICE restart.
1005   auto remote_offer2 = std::make_unique<cricket::SessionDescription>();
1006   AddAudioSection(remote_offer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1007                   cricket::ICEMODE_LITE, cricket::CONNECTIONROLE_ACTPASS,
1008                   nullptr);
1009   auto local_answer2 = std::make_unique<cricket::SessionDescription>();
1010   AddAudioSection(local_answer2.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1011                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1012                   nullptr);
1013   EXPECT_TRUE(transport_controller_
1014                   ->SetRemoteDescription(SdpType::kOffer, remote_offer2.get())
1015                   .ok());
1016   EXPECT_TRUE(transport_controller_
1017                   ->SetLocalDescription(SdpType::kAnswer, local_answer2.get())
1018                   .ok());
1019   fake_dtls = static_cast<FakeDtlsTransport*>(
1020       transport_controller_->GetDtlsTransport(kAudioMid1));
1021   // The local side is still the controlling role since the remote side is using
1022   // ICE-Lite.
1023   EXPECT_EQ(cricket::ICEROLE_CONTROLLING,
1024             fake_dtls->fake_ice_transport()->GetIceRole());
1025 }
1026 
1027 // Tests that the SDP has more than one audio/video m= sections.
TEST_F(JsepTransportControllerTest,MultipleMediaSectionsOfSameTypeWithBundle)1028 TEST_F(JsepTransportControllerTest, MultipleMediaSectionsOfSameTypeWithBundle) {
1029   CreateJsepTransportController(JsepTransportController::Config());
1030   cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1031   bundle_group.AddContentName(kAudioMid1);
1032   bundle_group.AddContentName(kAudioMid2);
1033   bundle_group.AddContentName(kVideoMid1);
1034   bundle_group.AddContentName(kDataMid1);
1035 
1036   auto local_offer = std::make_unique<cricket::SessionDescription>();
1037   AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1038                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1039                   nullptr);
1040   AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1041                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1042                   nullptr);
1043   AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1044                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1045                   nullptr);
1046   AddDataSection(local_offer.get(), kDataMid1,
1047                  cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1048                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1049                  nullptr);
1050 
1051   auto remote_answer = std::make_unique<cricket::SessionDescription>();
1052   AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1053                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1054                   nullptr);
1055   AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1056                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1057                   nullptr);
1058   AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1059                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1060                   nullptr);
1061   AddDataSection(remote_answer.get(), kDataMid1,
1062                  cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1063                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1064                  nullptr);
1065 
1066   local_offer->AddGroup(bundle_group);
1067   remote_answer->AddGroup(bundle_group);
1068 
1069   EXPECT_TRUE(transport_controller_
1070                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1071                   .ok());
1072   EXPECT_TRUE(transport_controller_
1073                   ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1074                   .ok());
1075   // Verify that all the sections are bundled on kAudio1.
1076   auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1077   auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1078   auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1079   auto transport4 = transport_controller_->GetRtpTransport(kDataMid1);
1080   EXPECT_EQ(transport1, transport2);
1081   EXPECT_EQ(transport1, transport3);
1082   EXPECT_EQ(transport1, transport4);
1083 
1084   EXPECT_EQ(transport_controller_->LookupDtlsTransportByMid(kAudioMid1),
1085             transport_controller_->LookupDtlsTransportByMid(kVideoMid1));
1086 
1087   // Verify the OnRtpTransport/DtlsTransportChanged signals are fired correctly.
1088   auto it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1089   ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1090   EXPECT_EQ(transport1, it->second);
1091   it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1092   ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1093   EXPECT_EQ(transport1, it->second);
1094   it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1095   ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1096   EXPECT_EQ(transport1, it->second);
1097   // Verify the DtlsTransport for the SCTP data channel is reset correctly.
1098   auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1099   ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1100 }
1101 
1102 // Tests that only a subset of all the m= sections are bundled.
TEST_F(JsepTransportControllerTest,BundleSubsetOfMediaSections)1103 TEST_F(JsepTransportControllerTest, BundleSubsetOfMediaSections) {
1104   CreateJsepTransportController(JsepTransportController::Config());
1105   cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1106   bundle_group.AddContentName(kAudioMid1);
1107   bundle_group.AddContentName(kVideoMid1);
1108 
1109   auto local_offer = std::make_unique<cricket::SessionDescription>();
1110   AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1111                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1112                   nullptr);
1113   AddAudioSection(local_offer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1114                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1115                   nullptr);
1116   AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1117                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1118                   nullptr);
1119 
1120   auto remote_answer = std::make_unique<cricket::SessionDescription>();
1121   AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1122                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1123                   nullptr);
1124   AddAudioSection(remote_answer.get(), kAudioMid2, kIceUfrag2, kIcePwd2,
1125                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1126                   nullptr);
1127   AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1128                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1129                   nullptr);
1130 
1131   local_offer->AddGroup(bundle_group);
1132   remote_answer->AddGroup(bundle_group);
1133   EXPECT_TRUE(transport_controller_
1134                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1135                   .ok());
1136   EXPECT_TRUE(transport_controller_
1137                   ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1138                   .ok());
1139 
1140   // Verifiy that only |kAudio1| and |kVideo1| are bundled.
1141   auto transport1 = transport_controller_->GetRtpTransport(kAudioMid1);
1142   auto transport2 = transport_controller_->GetRtpTransport(kAudioMid2);
1143   auto transport3 = transport_controller_->GetRtpTransport(kVideoMid1);
1144   EXPECT_NE(transport1, transport2);
1145   EXPECT_EQ(transport1, transport3);
1146 
1147   auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1148   ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1149   EXPECT_EQ(transport1, it->second);
1150   it = changed_rtp_transport_by_mid_.find(kAudioMid2);
1151   EXPECT_TRUE(transport2 == it->second);
1152 }
1153 
1154 // Tests that the initial offer/answer only have data section and audio/video
1155 // sections are added in the subsequent offer.
TEST_F(JsepTransportControllerTest,BundleOnDataSectionInSubsequentOffer)1156 TEST_F(JsepTransportControllerTest, BundleOnDataSectionInSubsequentOffer) {
1157   CreateJsepTransportController(JsepTransportController::Config());
1158   cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1159   bundle_group.AddContentName(kDataMid1);
1160 
1161   auto local_offer = std::make_unique<cricket::SessionDescription>();
1162   AddDataSection(local_offer.get(), kDataMid1,
1163                  cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1164                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1165                  nullptr);
1166   auto remote_answer = std::make_unique<cricket::SessionDescription>();
1167   AddDataSection(remote_answer.get(), kDataMid1,
1168                  cricket::MediaProtocolType::kSctp, kIceUfrag1, kIcePwd1,
1169                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1170                  nullptr);
1171   local_offer->AddGroup(bundle_group);
1172   remote_answer->AddGroup(bundle_group);
1173 
1174   EXPECT_TRUE(transport_controller_
1175                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1176                   .ok());
1177   EXPECT_TRUE(transport_controller_
1178                   ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1179                   .ok());
1180   auto data_transport = transport_controller_->GetRtpTransport(kDataMid1);
1181 
1182   // Add audio/video sections in subsequent offer.
1183   AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1184                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1185                   nullptr);
1186   AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1187                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1188                   nullptr);
1189   AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag2, kIcePwd2,
1190                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1191                   nullptr);
1192   AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag3, kIcePwd3,
1193                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1194                   nullptr);
1195 
1196   // Reset the bundle group and do another offer/answer exchange.
1197   bundle_group.AddContentName(kAudioMid1);
1198   bundle_group.AddContentName(kVideoMid1);
1199   local_offer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1200   remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1201   local_offer->AddGroup(bundle_group);
1202   remote_answer->AddGroup(bundle_group);
1203 
1204   EXPECT_TRUE(transport_controller_
1205                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1206                   .ok());
1207   EXPECT_TRUE(transport_controller_
1208                   ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1209                   .ok());
1210 
1211   auto audio_transport = transport_controller_->GetRtpTransport(kAudioMid1);
1212   auto video_transport = transport_controller_->GetRtpTransport(kVideoMid1);
1213   EXPECT_EQ(data_transport, audio_transport);
1214   EXPECT_EQ(data_transport, video_transport);
1215 }
1216 
TEST_F(JsepTransportControllerTest,VideoDataRejectedInAnswer)1217 TEST_F(JsepTransportControllerTest, VideoDataRejectedInAnswer) {
1218   CreateJsepTransportController(JsepTransportController::Config());
1219   cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1220   bundle_group.AddContentName(kAudioMid1);
1221   bundle_group.AddContentName(kVideoMid1);
1222   bundle_group.AddContentName(kDataMid1);
1223 
1224   auto local_offer = std::make_unique<cricket::SessionDescription>();
1225   AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1226                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1227                   nullptr);
1228   AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1229                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1230                   nullptr);
1231   AddDataSection(local_offer.get(), kDataMid1,
1232                  cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1233                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1234                  nullptr);
1235 
1236   auto remote_answer = std::make_unique<cricket::SessionDescription>();
1237   AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1238                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1239                   nullptr);
1240   AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1241                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1242                   nullptr);
1243   AddDataSection(remote_answer.get(), kDataMid1,
1244                  cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1245                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1246                  nullptr);
1247   // Reject video and data section.
1248   remote_answer->contents()[1].rejected = true;
1249   remote_answer->contents()[2].rejected = true;
1250 
1251   local_offer->AddGroup(bundle_group);
1252   remote_answer->AddGroup(bundle_group);
1253 
1254   EXPECT_TRUE(transport_controller_
1255                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1256                   .ok());
1257   EXPECT_TRUE(transport_controller_
1258                   ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1259                   .ok());
1260 
1261   // Verify the RtpTransport/DtlsTransport is destroyed correctly.
1262   EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1263   EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1264   // Verify the signals are fired correctly.
1265   auto it = changed_rtp_transport_by_mid_.find(kVideoMid1);
1266   ASSERT_TRUE(it != changed_rtp_transport_by_mid_.end());
1267   EXPECT_EQ(nullptr, it->second);
1268   auto it2 = changed_dtls_transport_by_mid_.find(kDataMid1);
1269   ASSERT_TRUE(it2 != changed_dtls_transport_by_mid_.end());
1270   EXPECT_EQ(nullptr, it2->second);
1271 }
1272 
1273 // Tests that changing the bundled MID in subsequent offer/answer exchange is
1274 // not supported.
1275 // TODO(bugs.webrtc.org/6704): Change this test to expect success once issue is
1276 // fixed
TEST_F(JsepTransportControllerTest,ChangeBundledMidNotSupported)1277 TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) {
1278   CreateJsepTransportController(JsepTransportController::Config());
1279   cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1280   bundle_group.AddContentName(kAudioMid1);
1281   bundle_group.AddContentName(kVideoMid1);
1282 
1283   auto local_offer = std::make_unique<cricket::SessionDescription>();
1284   AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1285                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1286                   nullptr);
1287   AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1288                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1289                   nullptr);
1290 
1291   auto remote_answer = std::make_unique<cricket::SessionDescription>();
1292   AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1293                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1294                   nullptr);
1295   AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1296                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1297                   nullptr);
1298 
1299   local_offer->AddGroup(bundle_group);
1300   remote_answer->AddGroup(bundle_group);
1301   EXPECT_TRUE(transport_controller_
1302                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1303                   .ok());
1304   EXPECT_TRUE(transport_controller_
1305                   ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1306                   .ok());
1307   EXPECT_EQ(transport_controller_->GetRtpTransport(kAudioMid1),
1308             transport_controller_->GetRtpTransport(kVideoMid1));
1309 
1310   // Reorder the bundle group.
1311   EXPECT_TRUE(bundle_group.RemoveContentName(kAudioMid1));
1312   bundle_group.AddContentName(kAudioMid1);
1313   // The answerer uses the new bundle group and now the bundle mid is changed to
1314   // |kVideo1|.
1315   remote_answer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1316   remote_answer->AddGroup(bundle_group);
1317   EXPECT_TRUE(transport_controller_
1318                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1319                   .ok());
1320   EXPECT_FALSE(transport_controller_
1321                    ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1322                    .ok());
1323 }
1324 // Test that rejecting only the first m= section of a BUNDLE group is treated as
1325 // an error, but rejecting all of them works as expected.
TEST_F(JsepTransportControllerTest,RejectFirstContentInBundleGroup)1326 TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) {
1327   CreateJsepTransportController(JsepTransportController::Config());
1328   cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1329   bundle_group.AddContentName(kAudioMid1);
1330   bundle_group.AddContentName(kVideoMid1);
1331   bundle_group.AddContentName(kDataMid1);
1332 
1333   auto local_offer = std::make_unique<cricket::SessionDescription>();
1334   AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1335                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1336                   nullptr);
1337   AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1338                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1339                   nullptr);
1340   AddDataSection(local_offer.get(), kDataMid1,
1341                  cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1342                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1343                  nullptr);
1344 
1345   auto remote_answer = std::make_unique<cricket::SessionDescription>();
1346   AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1347                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1348                   nullptr);
1349   AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2,
1350                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1351                   nullptr);
1352   AddDataSection(remote_answer.get(), kDataMid1,
1353                  cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3,
1354                  cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1355                  nullptr);
1356   // Reject audio content in answer.
1357   remote_answer->contents()[0].rejected = true;
1358 
1359   local_offer->AddGroup(bundle_group);
1360   remote_answer->AddGroup(bundle_group);
1361 
1362   EXPECT_TRUE(transport_controller_
1363                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1364                   .ok());
1365   EXPECT_FALSE(transport_controller_
1366                    ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1367                    .ok());
1368 
1369   // Reject all the contents.
1370   remote_answer->contents()[1].rejected = true;
1371   remote_answer->contents()[2].rejected = true;
1372   EXPECT_TRUE(transport_controller_
1373                   ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1374                   .ok());
1375   EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1));
1376   EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1));
1377   EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1));
1378 }
1379 
1380 // Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire
1381 // is used.
TEST_F(JsepTransportControllerTest,ApplyNonRtcpMuxOfferWhenMuxingRequired)1382 TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) {
1383   JsepTransportController::Config config;
1384   config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1385   CreateJsepTransportController(config);
1386   auto local_offer = std::make_unique<cricket::SessionDescription>();
1387   AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1388                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1389                   nullptr);
1390 
1391   local_offer->contents()[0].media_description()->set_rtcp_mux(false);
1392   // Applying a non-RTCP-mux offer is expected to fail.
1393   EXPECT_FALSE(transport_controller_
1394                    ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1395                    .ok());
1396 }
1397 
1398 // Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire
1399 // is used.
TEST_F(JsepTransportControllerTest,ApplyNonRtcpMuxAnswerWhenMuxingRequired)1400 TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) {
1401   JsepTransportController::Config config;
1402   config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
1403   CreateJsepTransportController(config);
1404   auto local_offer = std::make_unique<cricket::SessionDescription>();
1405   AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1406                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1407                   nullptr);
1408   EXPECT_TRUE(transport_controller_
1409                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1410                   .ok());
1411 
1412   auto remote_answer = std::make_unique<cricket::SessionDescription>();
1413   AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1414                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE,
1415                   nullptr);
1416   // Applying a non-RTCP-mux answer is expected to fail.
1417   remote_answer->contents()[0].media_description()->set_rtcp_mux(false);
1418   EXPECT_FALSE(transport_controller_
1419                    ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1420                    .ok());
1421 }
1422 
1423 // This tests that the BUNDLE group in answer should be a subset of the offered
1424 // group.
TEST_F(JsepTransportControllerTest,AddContentToBundleGroupInAnswerNotSupported)1425 TEST_F(JsepTransportControllerTest,
1426        AddContentToBundleGroupInAnswerNotSupported) {
1427   CreateJsepTransportController(JsepTransportController::Config());
1428   auto local_offer = CreateSessionDescriptionWithoutBundle();
1429   auto remote_answer = CreateSessionDescriptionWithoutBundle();
1430 
1431   cricket::ContentGroup offer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1432   offer_bundle_group.AddContentName(kAudioMid1);
1433   local_offer->AddGroup(offer_bundle_group);
1434 
1435   cricket::ContentGroup answer_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1436   answer_bundle_group.AddContentName(kAudioMid1);
1437   answer_bundle_group.AddContentName(kVideoMid1);
1438   remote_answer->AddGroup(answer_bundle_group);
1439   EXPECT_TRUE(transport_controller_
1440                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1441                   .ok());
1442   EXPECT_FALSE(transport_controller_
1443                    ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1444                    .ok());
1445 }
1446 
1447 // This tests that the BUNDLE group with non-existing MID should be rejectd.
TEST_F(JsepTransportControllerTest,RejectBundleGroupWithNonExistingMid)1448 TEST_F(JsepTransportControllerTest, RejectBundleGroupWithNonExistingMid) {
1449   CreateJsepTransportController(JsepTransportController::Config());
1450   auto local_offer = CreateSessionDescriptionWithoutBundle();
1451   auto remote_answer = CreateSessionDescriptionWithoutBundle();
1452 
1453   cricket::ContentGroup invalid_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1454   // The BUNDLE group is invalid because there is no data section in the
1455   // description.
1456   invalid_bundle_group.AddContentName(kDataMid1);
1457   local_offer->AddGroup(invalid_bundle_group);
1458   remote_answer->AddGroup(invalid_bundle_group);
1459 
1460   EXPECT_FALSE(transport_controller_
1461                    ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1462                    .ok());
1463   EXPECT_FALSE(transport_controller_
1464                    ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1465                    .ok());
1466 }
1467 
1468 // This tests that an answer shouldn't be able to remove an m= section from an
1469 // established group without rejecting it.
TEST_F(JsepTransportControllerTest,RemoveContentFromBundleGroup)1470 TEST_F(JsepTransportControllerTest, RemoveContentFromBundleGroup) {
1471   CreateJsepTransportController(JsepTransportController::Config());
1472 
1473   auto local_offer = CreateSessionDescriptionWithBundleGroup();
1474   auto remote_answer = CreateSessionDescriptionWithBundleGroup();
1475   EXPECT_TRUE(transport_controller_
1476                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1477                   .ok());
1478   EXPECT_TRUE(transport_controller_
1479                   ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1480                   .ok());
1481 
1482   // Do an re-offer/answer.
1483   EXPECT_TRUE(transport_controller_
1484                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1485                   .ok());
1486   auto new_answer = CreateSessionDescriptionWithoutBundle();
1487   cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1488   //  The answer removes video from the BUNDLE group without rejecting it is
1489   //  invalid.
1490   new_bundle_group.AddContentName(kAudioMid1);
1491   new_answer->AddGroup(new_bundle_group);
1492 
1493   // Applying invalid answer is expected to fail.
1494   EXPECT_FALSE(transport_controller_
1495                    ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1496                    .ok());
1497 
1498   // Rejected the video content.
1499   auto video_content = new_answer->GetContentByName(kVideoMid1);
1500   ASSERT_TRUE(video_content);
1501   video_content->rejected = true;
1502   EXPECT_TRUE(transport_controller_
1503                   ->SetRemoteDescription(SdpType::kAnswer, new_answer.get())
1504                   .ok());
1505 }
1506 
1507 // Test that the JsepTransportController can process a new local and remote
1508 // description that changes the tagged BUNDLE group with the max-bundle policy
1509 // specified.
1510 // This is a regression test for bugs.webrtc.org/9954
TEST_F(JsepTransportControllerTest,ChangeTaggedMediaSectionMaxBundle)1511 TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
1512   CreateJsepTransportController(JsepTransportController::Config());
1513 
1514   auto local_offer = std::make_unique<cricket::SessionDescription>();
1515   AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1,
1516                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1517                   nullptr);
1518   cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1519   bundle_group.AddContentName(kAudioMid1);
1520   local_offer->AddGroup(bundle_group);
1521   EXPECT_TRUE(transport_controller_
1522                   ->SetLocalDescription(SdpType::kOffer, local_offer.get())
1523                   .ok());
1524 
1525   std::unique_ptr<cricket::SessionDescription> remote_answer(
1526       local_offer->Clone());
1527   EXPECT_TRUE(transport_controller_
1528                   ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get())
1529                   .ok());
1530 
1531   std::unique_ptr<cricket::SessionDescription> local_reoffer(
1532       local_offer->Clone());
1533   local_reoffer->contents()[0].rejected = true;
1534   AddVideoSection(local_reoffer.get(), kVideoMid1, kIceUfrag1, kIcePwd1,
1535                   cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS,
1536                   nullptr);
1537   local_reoffer->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1538   cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
1539   new_bundle_group.AddContentName(kVideoMid1);
1540   local_reoffer->AddGroup(new_bundle_group);
1541 
1542   EXPECT_TRUE(transport_controller_
1543                   ->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
1544                   .ok());
1545 
1546   std::unique_ptr<cricket::SessionDescription> remote_reanswer(
1547       local_reoffer->Clone());
1548   EXPECT_TRUE(
1549       transport_controller_
1550           ->SetRemoteDescription(SdpType::kAnswer, remote_reanswer.get())
1551           .ok());
1552 }
1553 
1554 }  // namespace webrtc
1555