1/* 2 * libjingle 3 * Copyright 2013, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "talk/app/webrtc/test/peerconnectiontestwrapper.h" 29#include "talk/app/webrtc/test/mockpeerconnectionobservers.h" 30#include "webrtc/base/gunit.h" 31#include "webrtc/base/logging.h" 32#include "webrtc/base/ssladapter.h" 33#include "webrtc/base/sslstreamadapter.h" 34#include "webrtc/base/stringencode.h" 35#include "webrtc/base/stringutils.h" 36 37#define MAYBE_SKIP_TEST(feature) \ 38 if (!(feature())) { \ 39 LOG(LS_INFO) << "Feature disabled... skipping"; \ 40 return; \ 41 } 42 43using webrtc::DataChannelInterface; 44using webrtc::FakeConstraints; 45using webrtc::MediaConstraintsInterface; 46using webrtc::MediaStreamInterface; 47using webrtc::PeerConnectionInterface; 48 49namespace { 50 51const char kExternalGiceUfrag[] = "1234567890123456"; 52const char kExternalGicePwd[] = "123456789012345678901234"; 53const size_t kMaxWait = 10000; 54 55void RemoveLinesFromSdp(const std::string& line_start, 56 std::string* sdp) { 57 const char kSdpLineEnd[] = "\r\n"; 58 size_t ssrc_pos = 0; 59 while ((ssrc_pos = sdp->find(line_start, ssrc_pos)) != 60 std::string::npos) { 61 size_t end_ssrc = sdp->find(kSdpLineEnd, ssrc_pos); 62 sdp->erase(ssrc_pos, end_ssrc - ssrc_pos + strlen(kSdpLineEnd)); 63 } 64} 65 66// Add |newlines| to the |message| after |line|. 67void InjectAfter(const std::string& line, 68 const std::string& newlines, 69 std::string* message) { 70 const std::string tmp = line + newlines; 71 rtc::replace_substrs(line.c_str(), line.length(), 72 tmp.c_str(), tmp.length(), message); 73} 74 75void Replace(const std::string& line, 76 const std::string& newlines, 77 std::string* message) { 78 rtc::replace_substrs(line.c_str(), line.length(), 79 newlines.c_str(), newlines.length(), message); 80} 81 82void UseExternalSdes(std::string* sdp) { 83 // Remove current crypto specification. 84 RemoveLinesFromSdp("a=crypto", sdp); 85 RemoveLinesFromSdp("a=fingerprint", sdp); 86 // Add external crypto. 87 const char kAudioSdes[] = 88 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 " 89 "inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR\r\n"; 90 const char kVideoSdes[] = 91 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 " 92 "inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj\r\n"; 93 const char kDataSdes[] = 94 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 " 95 "inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj\r\n"; 96 InjectAfter("a=mid:audio\r\n", kAudioSdes, sdp); 97 InjectAfter("a=mid:video\r\n", kVideoSdes, sdp); 98 InjectAfter("a=mid:data\r\n", kDataSdes, sdp); 99} 100 101void UseGice(std::string* sdp) { 102 InjectAfter("t=0 0\r\n", "a=ice-options:google-ice\r\n", sdp); 103 104 std::string ufragline = "a=ice-ufrag:"; 105 std::string pwdline = "a=ice-pwd:"; 106 RemoveLinesFromSdp(ufragline, sdp); 107 RemoveLinesFromSdp(pwdline, sdp); 108 ufragline.append(kExternalGiceUfrag); 109 ufragline.append("\r\n"); 110 pwdline.append(kExternalGicePwd); 111 pwdline.append("\r\n"); 112 const std::string ufrag_pwd = ufragline + pwdline; 113 114 InjectAfter("a=mid:audio\r\n", ufrag_pwd, sdp); 115 InjectAfter("a=mid:video\r\n", ufrag_pwd, sdp); 116 InjectAfter("a=mid:data\r\n", ufrag_pwd, sdp); 117} 118 119void RemoveBundle(std::string* sdp) { 120 RemoveLinesFromSdp("a=group:BUNDLE", sdp); 121} 122 123} // namespace 124 125class PeerConnectionEndToEndTest 126 : public sigslot::has_slots<>, 127 public testing::Test { 128 public: 129 typedef std::vector<rtc::scoped_refptr<DataChannelInterface> > 130 DataChannelList; 131 132 PeerConnectionEndToEndTest() 133 : caller_(new rtc::RefCountedObject<PeerConnectionTestWrapper>( 134 "caller")), 135 callee_(new rtc::RefCountedObject<PeerConnectionTestWrapper>( 136 "callee")) { 137 rtc::InitializeSSL(NULL); 138 } 139 140 void CreatePcs() { 141 CreatePcs(NULL); 142 } 143 144 void CreatePcs(const MediaConstraintsInterface* pc_constraints) { 145 EXPECT_TRUE(caller_->CreatePc(pc_constraints)); 146 EXPECT_TRUE(callee_->CreatePc(pc_constraints)); 147 PeerConnectionTestWrapper::Connect(caller_.get(), callee_.get()); 148 149 caller_->SignalOnDataChannel.connect( 150 this, &PeerConnectionEndToEndTest::OnCallerAddedDataChanel); 151 callee_->SignalOnDataChannel.connect( 152 this, &PeerConnectionEndToEndTest::OnCalleeAddedDataChannel); 153 } 154 155 void GetAndAddUserMedia() { 156 FakeConstraints audio_constraints; 157 FakeConstraints video_constraints; 158 GetAndAddUserMedia(true, audio_constraints, true, video_constraints); 159 } 160 161 void GetAndAddUserMedia(bool audio, FakeConstraints audio_constraints, 162 bool video, FakeConstraints video_constraints) { 163 caller_->GetAndAddUserMedia(audio, audio_constraints, 164 video, video_constraints); 165 callee_->GetAndAddUserMedia(audio, audio_constraints, 166 video, video_constraints); 167 } 168 169 void Negotiate() { 170 caller_->CreateOffer(NULL); 171 } 172 173 void WaitForCallEstablished() { 174 caller_->WaitForCallEstablished(); 175 callee_->WaitForCallEstablished(); 176 } 177 178 void WaitForConnection() { 179 caller_->WaitForConnection(); 180 callee_->WaitForConnection(); 181 } 182 183 void SetupLegacySdpConverter() { 184 caller_->SignalOnSdpCreated.connect( 185 this, &PeerConnectionEndToEndTest::ConvertToLegacySdp); 186 callee_->SignalOnSdpCreated.connect( 187 this, &PeerConnectionEndToEndTest::ConvertToLegacySdp); 188 } 189 190 void ConvertToLegacySdp(std::string* sdp) { 191 UseExternalSdes(sdp); 192 UseGice(sdp); 193 RemoveBundle(sdp); 194 LOG(LS_INFO) << "ConvertToLegacySdp: " << *sdp; 195 } 196 197 void SetupGiceConverter() { 198 caller_->SignalOnIceCandidateCreated.connect( 199 this, &PeerConnectionEndToEndTest::AddGiceCredsToCandidate); 200 callee_->SignalOnIceCandidateCreated.connect( 201 this, &PeerConnectionEndToEndTest::AddGiceCredsToCandidate); 202 } 203 204 void AddGiceCredsToCandidate(std::string* sdp) { 205 std::string gice_creds = " username "; 206 gice_creds.append(kExternalGiceUfrag); 207 gice_creds.append(" password "); 208 gice_creds.append(kExternalGicePwd); 209 gice_creds.append("\r\n"); 210 Replace("\r\n", gice_creds, sdp); 211 LOG(LS_INFO) << "AddGiceCredsToCandidate: " << *sdp; 212 } 213 214 void OnCallerAddedDataChanel(DataChannelInterface* dc) { 215 caller_signaled_data_channels_.push_back(dc); 216 } 217 218 void OnCalleeAddedDataChannel(DataChannelInterface* dc) { 219 callee_signaled_data_channels_.push_back(dc); 220 } 221 222 // Tests that |dc1| and |dc2| can send to and receive from each other. 223 void TestDataChannelSendAndReceive( 224 DataChannelInterface* dc1, DataChannelInterface* dc2) { 225 rtc::scoped_ptr<webrtc::MockDataChannelObserver> dc1_observer( 226 new webrtc::MockDataChannelObserver(dc1)); 227 228 rtc::scoped_ptr<webrtc::MockDataChannelObserver> dc2_observer( 229 new webrtc::MockDataChannelObserver(dc2)); 230 231 static const std::string kDummyData = "abcdefg"; 232 webrtc::DataBuffer buffer(kDummyData); 233 EXPECT_TRUE(dc1->Send(buffer)); 234 EXPECT_EQ_WAIT(kDummyData, dc2_observer->last_message(), kMaxWait); 235 236 EXPECT_TRUE(dc2->Send(buffer)); 237 EXPECT_EQ_WAIT(kDummyData, dc1_observer->last_message(), kMaxWait); 238 239 EXPECT_EQ(1U, dc1_observer->received_message_count()); 240 EXPECT_EQ(1U, dc2_observer->received_message_count()); 241 } 242 243 void WaitForDataChannelsToOpen(DataChannelInterface* local_dc, 244 const DataChannelList& remote_dc_list, 245 size_t remote_dc_index) { 246 EXPECT_EQ_WAIT(DataChannelInterface::kOpen, local_dc->state(), kMaxWait); 247 248 EXPECT_TRUE_WAIT(remote_dc_list.size() > remote_dc_index, kMaxWait); 249 EXPECT_EQ_WAIT(DataChannelInterface::kOpen, 250 remote_dc_list[remote_dc_index]->state(), 251 kMaxWait); 252 EXPECT_EQ(local_dc->id(), remote_dc_list[remote_dc_index]->id()); 253 } 254 255 void CloseDataChannels(DataChannelInterface* local_dc, 256 const DataChannelList& remote_dc_list, 257 size_t remote_dc_index) { 258 local_dc->Close(); 259 EXPECT_EQ_WAIT(DataChannelInterface::kClosed, local_dc->state(), kMaxWait); 260 EXPECT_EQ_WAIT(DataChannelInterface::kClosed, 261 remote_dc_list[remote_dc_index]->state(), 262 kMaxWait); 263 } 264 265 ~PeerConnectionEndToEndTest() { 266 rtc::CleanupSSL(); 267 } 268 269 protected: 270 rtc::scoped_refptr<PeerConnectionTestWrapper> caller_; 271 rtc::scoped_refptr<PeerConnectionTestWrapper> callee_; 272 DataChannelList caller_signaled_data_channels_; 273 DataChannelList callee_signaled_data_channels_; 274}; 275 276// Disable for TSan v2, see 277// https://code.google.com/p/webrtc/issues/detail?id=1205 for details. 278#if !defined(THREAD_SANITIZER) 279 280TEST_F(PeerConnectionEndToEndTest, Call) { 281 CreatePcs(); 282 GetAndAddUserMedia(); 283 Negotiate(); 284 WaitForCallEstablished(); 285} 286 287// Disabled per b/14899892 288TEST_F(PeerConnectionEndToEndTest, DISABLED_CallWithLegacySdp) { 289 FakeConstraints pc_constraints; 290 pc_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, 291 false); 292 CreatePcs(&pc_constraints); 293 SetupLegacySdpConverter(); 294 SetupGiceConverter(); 295 GetAndAddUserMedia(); 296 Negotiate(); 297 WaitForCallEstablished(); 298} 299 300// Verifies that a DataChannel created before the negotiation can transition to 301// "OPEN" and transfer data. 302TEST_F(PeerConnectionEndToEndTest, CreateDataChannelBeforeNegotiate) { 303 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); 304 305 CreatePcs(); 306 307 webrtc::DataChannelInit init; 308 rtc::scoped_refptr<DataChannelInterface> caller_dc( 309 caller_->CreateDataChannel("data", init)); 310 rtc::scoped_refptr<DataChannelInterface> callee_dc( 311 callee_->CreateDataChannel("data", init)); 312 313 Negotiate(); 314 WaitForConnection(); 315 316 WaitForDataChannelsToOpen(caller_dc, callee_signaled_data_channels_, 0); 317 WaitForDataChannelsToOpen(callee_dc, caller_signaled_data_channels_, 0); 318 319 TestDataChannelSendAndReceive(caller_dc, callee_signaled_data_channels_[0]); 320 TestDataChannelSendAndReceive(callee_dc, caller_signaled_data_channels_[0]); 321 322 CloseDataChannels(caller_dc, callee_signaled_data_channels_, 0); 323 CloseDataChannels(callee_dc, caller_signaled_data_channels_, 0); 324} 325 326// Verifies that a DataChannel created after the negotiation can transition to 327// "OPEN" and transfer data. 328TEST_F(PeerConnectionEndToEndTest, CreateDataChannelAfterNegotiate) { 329 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); 330 331 CreatePcs(); 332 333 webrtc::DataChannelInit init; 334 335 // This DataChannel is for creating the data content in the negotiation. 336 rtc::scoped_refptr<DataChannelInterface> dummy( 337 caller_->CreateDataChannel("data", init)); 338 Negotiate(); 339 WaitForConnection(); 340 341 // Creates new DataChannels after the negotiation and verifies their states. 342 rtc::scoped_refptr<DataChannelInterface> caller_dc( 343 caller_->CreateDataChannel("hello", init)); 344 rtc::scoped_refptr<DataChannelInterface> callee_dc( 345 callee_->CreateDataChannel("hello", init)); 346 347 WaitForDataChannelsToOpen(caller_dc, callee_signaled_data_channels_, 1); 348 WaitForDataChannelsToOpen(callee_dc, caller_signaled_data_channels_, 0); 349 350 TestDataChannelSendAndReceive(caller_dc, callee_signaled_data_channels_[1]); 351 TestDataChannelSendAndReceive(callee_dc, caller_signaled_data_channels_[0]); 352 353 CloseDataChannels(caller_dc, callee_signaled_data_channels_, 1); 354 CloseDataChannels(callee_dc, caller_signaled_data_channels_, 0); 355} 356 357// Verifies that DataChannel IDs are even/odd based on the DTLS roles. 358TEST_F(PeerConnectionEndToEndTest, DataChannelIdAssignment) { 359 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); 360 361 CreatePcs(); 362 363 webrtc::DataChannelInit init; 364 rtc::scoped_refptr<DataChannelInterface> caller_dc_1( 365 caller_->CreateDataChannel("data", init)); 366 rtc::scoped_refptr<DataChannelInterface> callee_dc_1( 367 callee_->CreateDataChannel("data", init)); 368 369 Negotiate(); 370 WaitForConnection(); 371 372 EXPECT_EQ(1U, caller_dc_1->id() % 2); 373 EXPECT_EQ(0U, callee_dc_1->id() % 2); 374 375 rtc::scoped_refptr<DataChannelInterface> caller_dc_2( 376 caller_->CreateDataChannel("data", init)); 377 rtc::scoped_refptr<DataChannelInterface> callee_dc_2( 378 callee_->CreateDataChannel("data", init)); 379 380 EXPECT_EQ(1U, caller_dc_2->id() % 2); 381 EXPECT_EQ(0U, callee_dc_2->id() % 2); 382} 383 384// Verifies that the message is received by the right remote DataChannel when 385// there are multiple DataChannels. 386TEST_F(PeerConnectionEndToEndTest, 387 MessageTransferBetweenTwoPairsOfDataChannels) { 388 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); 389 390 CreatePcs(); 391 392 webrtc::DataChannelInit init; 393 394 rtc::scoped_refptr<DataChannelInterface> caller_dc_1( 395 caller_->CreateDataChannel("data", init)); 396 rtc::scoped_refptr<DataChannelInterface> caller_dc_2( 397 caller_->CreateDataChannel("data", init)); 398 399 Negotiate(); 400 WaitForConnection(); 401 WaitForDataChannelsToOpen(caller_dc_1, callee_signaled_data_channels_, 0); 402 WaitForDataChannelsToOpen(caller_dc_2, callee_signaled_data_channels_, 1); 403 404 rtc::scoped_ptr<webrtc::MockDataChannelObserver> dc_1_observer( 405 new webrtc::MockDataChannelObserver(callee_signaled_data_channels_[0])); 406 407 rtc::scoped_ptr<webrtc::MockDataChannelObserver> dc_2_observer( 408 new webrtc::MockDataChannelObserver(callee_signaled_data_channels_[1])); 409 410 const std::string message_1 = "hello 1"; 411 const std::string message_2 = "hello 2"; 412 413 caller_dc_1->Send(webrtc::DataBuffer(message_1)); 414 EXPECT_EQ_WAIT(message_1, dc_1_observer->last_message(), kMaxWait); 415 416 caller_dc_2->Send(webrtc::DataBuffer(message_2)); 417 EXPECT_EQ_WAIT(message_2, dc_2_observer->last_message(), kMaxWait); 418 419 EXPECT_EQ(1U, dc_1_observer->received_message_count()); 420 EXPECT_EQ(1U, dc_2_observer->received_message_count()); 421} 422#endif // if !defined(THREAD_SANITIZER) 423