1 /* 2 * libjingle 3 * Copyright 2004 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 <cstring> 29 #include <sstream> 30 #include <deque> 31 #include <map> 32 33 #include "talk/base/base64.h" 34 #include "talk/base/common.h" 35 #include "talk/base/dscp.h" 36 #include "talk/base/gunit.h" 37 #include "talk/base/helpers.h" 38 #include "talk/base/logging.h" 39 #include "talk/base/natserver.h" 40 #include "talk/base/natsocketfactory.h" 41 #include "talk/base/stringencode.h" 42 #include "talk/p2p/base/basicpacketsocketfactory.h" 43 #include "talk/p2p/base/constants.h" 44 #include "talk/p2p/base/parsing.h" 45 #include "talk/p2p/base/portallocator.h" 46 #include "talk/p2p/base/p2ptransport.h" 47 #include "talk/p2p/base/relayport.h" 48 #include "talk/p2p/base/relayserver.h" 49 #include "talk/p2p/base/session.h" 50 #include "talk/p2p/base/sessionclient.h" 51 #include "talk/p2p/base/sessionmanager.h" 52 #include "talk/p2p/base/stunport.h" 53 #include "talk/p2p/base/stunserver.h" 54 #include "talk/p2p/base/transportchannel.h" 55 #include "talk/p2p/base/transportchannelproxy.h" 56 #include "talk/p2p/base/udpport.h" 57 #include "talk/xmpp/constants.h" 58 59 using cricket::SignalingProtocol; 60 using cricket::PROTOCOL_HYBRID; 61 using cricket::PROTOCOL_JINGLE; 62 using cricket::PROTOCOL_GINGLE; 63 64 static const std::string kInitiator = "init (at) init.com"; 65 static const std::string kResponder = "resp (at) resp.com"; 66 // Expected from test random number generator. 67 static const std::string kSessionId = "9254631414740579489"; 68 // TODO: When we need to test more than one transport type, 69 // allow this to be injected like the content types are. 70 static const std::string kTransportType = "http://www.google.com/transport/p2p"; 71 72 // Controls how long we wait for a session to send messages that we 73 // expect, in milliseconds. We put it high to avoid flaky tests. 74 static const int kEventTimeout = 5000; 75 76 static const int kNumPorts = 2; 77 static const int kPort0 = 28653; 78 static const int kPortStep = 5; 79 80 static const std::string kNotifyNick1 = "derekcheng_google.com^59422C27"; 81 static const std::string kNotifyNick2 = "someoneelses_google.com^7abd6a7a20"; 82 static const uint32 kNotifyAudioSsrc1 = 2625839801U; 83 static const uint32 kNotifyAudioSsrc2 = 2529430427U; 84 static const uint32 kNotifyVideoSsrc1 = 3; 85 static const uint32 kNotifyVideoSsrc2 = 2; 86 87 static const std::string kViewRequestNick = "param_google.com^16A3CDBE"; 88 static const uint32 kViewRequestSsrc = 4; 89 static const int kViewRequestWidth = 320; 90 static const int kViewRequestHeight = 200; 91 static const int kViewRequestFrameRate = 15; 92 93 int GetPort(int port_index) { 94 return kPort0 + (port_index * kPortStep); 95 } 96 97 std::string GetPortString(int port_index) { 98 return talk_base::ToString(GetPort(port_index)); 99 } 100 101 // Only works for port_index < 10, which is fine for our purposes. 102 std::string GetUsername(int port_index) { 103 return "username" + std::string(8, talk_base::ToString(port_index)[0]); 104 } 105 106 // Only works for port_index < 10, which is fine for our purposes. 107 std::string GetPassword(int port_index) { 108 return "password" + std::string(8, talk_base::ToString(port_index)[0]); 109 } 110 111 std::string IqAck(const std::string& id, 112 const std::string& from, 113 const std::string& to) { 114 return "<cli:iq" 115 " to=\"" + to + "\"" 116 " id=\"" + id + "\"" 117 " type=\"result\"" 118 " from=\"" + from + "\"" 119 " xmlns:cli=\"jabber:client\"" 120 "/>"; 121 } 122 123 std::string IqSet(const std::string& id, 124 const std::string& from, 125 const std::string& to, 126 const std::string& content) { 127 return "<cli:iq" 128 " to=\"" + to + "\"" 129 " type=\"set\"" 130 " from=\"" + from + "\"" 131 " id=\"" + id + "\"" 132 " xmlns:cli=\"jabber:client\"" 133 ">" 134 + content + 135 "</cli:iq>"; 136 } 137 138 std::string IqError(const std::string& id, 139 const std::string& from, 140 const std::string& to, 141 const std::string& content) { 142 return "<cli:error" 143 " to=\"" + to + "\"" 144 " type=\"error\"" 145 " from=\"" + from + "\"" 146 " id=\"" + id + "\"" 147 " xmlns:cli=\"jabber:client\"" 148 ">" 149 + content + 150 "</cli:error>"; 151 } 152 153 std::string GingleSessionXml(const std::string& type, 154 const std::string& content) { 155 return "<session" 156 " xmlns=\"http://www.google.com/session\"" 157 " type=\"" + type + "\"" 158 " id=\"" + kSessionId + "\"" 159 " initiator=\"" + kInitiator + "\"" 160 ">" 161 + content + 162 "</session>"; 163 } 164 165 std::string GingleDescriptionXml(const std::string& content_type) { 166 return "<description" 167 " xmlns=\"" + content_type + "\"" 168 "/>"; 169 } 170 171 std::string P2pCandidateXml(const std::string& name, int port_index) { 172 // Port will update the rtcp username by +1 on the last character. So we need 173 // to compensate here. See Port::username_fragment() for detail. 174 std::string username = GetUsername(port_index); 175 // TODO: Use the component id instead of the channel name to 176 // determinte if we need to covert the username here. 177 if (name == "rtcp" || name == "video_rtcp" || name == "chanb") { 178 char next_ch = username[username.size() - 1]; 179 ASSERT(username.size() > 0); 180 talk_base::Base64::GetNextBase64Char(next_ch, &next_ch); 181 username[username.size() - 1] = next_ch; 182 } 183 return "<candidate" 184 " name=\"" + name + "\"" 185 " address=\"127.0.0.1\"" 186 " port=\"" + GetPortString(port_index) + "\"" 187 " preference=\"0.99\"" 188 " username=\"" + username + "\"" 189 " protocol=\"udp\"" 190 " generation=\"0\"" 191 " password=\"" + GetPassword(port_index) + "\"" 192 " type=\"local\"" 193 " network=\"network\"" 194 "/>"; 195 } 196 197 std::string JingleActionXml(const std::string& action, 198 const std::string& content) { 199 return "<jingle" 200 " xmlns=\"urn:xmpp:jingle:1\"" 201 " action=\"" + action + "\"" 202 " sid=\"" + kSessionId + "\"" 203 ">" 204 + content + 205 "</jingle>"; 206 } 207 208 std::string JingleInitiateActionXml(const std::string& content) { 209 return "<jingle" 210 " xmlns=\"urn:xmpp:jingle:1\"" 211 " action=\"session-initiate\"" 212 " sid=\"" + kSessionId + "\"" 213 " initiator=\"" + kInitiator + "\"" 214 ">" 215 + content + 216 "</jingle>"; 217 } 218 219 std::string JingleGroupInfoXml(const std::string& content_name_a, 220 const std::string& content_name_b) { 221 std::string group_info = "<jin:group" 222 " type=\"BUNDLE\"" 223 " xmlns:jin=\"google:jingle\"" 224 ">"; 225 if (!content_name_a.empty()) 226 group_info += "<content name=\"" + content_name_a + "\"" 227 "/>"; 228 if (!content_name_b.empty()) 229 group_info += "<content name=\"" + content_name_b + "\"" 230 "/>"; 231 group_info += "</jin:group>"; 232 return group_info; 233 } 234 235 236 std::string JingleEmptyContentXml(const std::string& content_name, 237 const std::string& content_type, 238 const std::string& transport_type) { 239 return "<content" 240 " name=\"" + content_name + "\"" 241 " creator=\"initiator\"" 242 ">" 243 "<description" 244 " xmlns=\"" + content_type + "\"" 245 "/>" 246 "<transport" 247 " xmlns=\"" + transport_type + "\"" 248 "/>" 249 "</content>"; 250 } 251 252 std::string JingleContentXml(const std::string& content_name, 253 const std::string& content_type, 254 const std::string& transport_type, 255 const std::string& transport_main) { 256 std::string transport = transport_type.empty() ? "" : 257 "<transport" 258 " xmlns=\"" + transport_type + "\"" 259 ">" 260 + transport_main + 261 "</transport>"; 262 263 return"<content" 264 " name=\"" + content_name + "\"" 265 " creator=\"initiator\"" 266 ">" 267 "<description" 268 " xmlns=\"" + content_type + "\"" 269 "/>" 270 + transport + 271 "</content>"; 272 } 273 274 std::string JingleTransportContentXml(const std::string& content_name, 275 const std::string& transport_type, 276 const std::string& content) { 277 return "<content" 278 " name=\"" + content_name + "\"" 279 " creator=\"initiator\"" 280 ">" 281 "<transport" 282 " xmlns=\"" + transport_type + "\"" 283 ">" 284 + content + 285 "</transport>" 286 "</content>"; 287 } 288 289 std::string GingleInitiateXml(const std::string& content_type) { 290 return GingleSessionXml( 291 "initiate", 292 GingleDescriptionXml(content_type)); 293 } 294 295 std::string JingleInitiateXml(const std::string& content_name_a, 296 const std::string& content_type_a, 297 const std::string& content_name_b, 298 const std::string& content_type_b, 299 bool bundle = false) { 300 std::string content_xml; 301 if (content_name_b.empty()) { 302 content_xml = JingleEmptyContentXml( 303 content_name_a, content_type_a, kTransportType); 304 } else { 305 content_xml = JingleEmptyContentXml( 306 content_name_a, content_type_a, kTransportType) + 307 JingleEmptyContentXml( 308 content_name_b, content_type_b, kTransportType); 309 if (bundle) { 310 content_xml += JingleGroupInfoXml(content_name_a, content_name_b); 311 } 312 } 313 return JingleInitiateActionXml(content_xml); 314 } 315 316 std::string GingleAcceptXml(const std::string& content_type) { 317 return GingleSessionXml( 318 "accept", 319 GingleDescriptionXml(content_type)); 320 } 321 322 std::string JingleAcceptXml(const std::string& content_name_a, 323 const std::string& content_type_a, 324 const std::string& content_name_b, 325 const std::string& content_type_b, 326 bool bundle = false) { 327 std::string content_xml; 328 if (content_name_b.empty()) { 329 content_xml = JingleEmptyContentXml( 330 content_name_a, content_type_a, kTransportType); 331 } else { 332 content_xml = JingleEmptyContentXml( 333 content_name_a, content_type_a, kTransportType) + 334 JingleEmptyContentXml( 335 content_name_b, content_type_b, kTransportType); 336 } 337 if (bundle) { 338 content_xml += JingleGroupInfoXml(content_name_a, content_name_b); 339 } 340 341 return JingleActionXml("session-accept", content_xml); 342 } 343 344 std::string Gingle2CandidatesXml(const std::string& channel_name, 345 int port_index0, 346 int port_index1) { 347 return GingleSessionXml( 348 "candidates", 349 P2pCandidateXml(channel_name, port_index0) + 350 P2pCandidateXml(channel_name, port_index1)); 351 } 352 353 std::string Gingle4CandidatesXml(const std::string& channel_name_a, 354 int port_index0, 355 int port_index1, 356 const std::string& channel_name_b, 357 int port_index2, 358 int port_index3) { 359 return GingleSessionXml( 360 "candidates", 361 P2pCandidateXml(channel_name_a, port_index0) + 362 P2pCandidateXml(channel_name_a, port_index1) + 363 P2pCandidateXml(channel_name_b, port_index2) + 364 P2pCandidateXml(channel_name_b, port_index3)); 365 } 366 367 std::string Jingle2TransportInfoXml(const std::string& content_name, 368 const std::string& channel_name, 369 int port_index0, 370 int port_index1) { 371 return JingleActionXml( 372 "transport-info", 373 JingleTransportContentXml( 374 content_name, kTransportType, 375 P2pCandidateXml(channel_name, port_index0) + 376 P2pCandidateXml(channel_name, port_index1))); 377 } 378 379 std::string Jingle4TransportInfoXml(const std::string& content_name, 380 const std::string& channel_name_a, 381 int port_index0, 382 int port_index1, 383 const std::string& channel_name_b, 384 int port_index2, 385 int port_index3) { 386 return JingleActionXml( 387 "transport-info", 388 JingleTransportContentXml( 389 content_name, kTransportType, 390 P2pCandidateXml(channel_name_a, port_index0) + 391 P2pCandidateXml(channel_name_a, port_index1) + 392 P2pCandidateXml(channel_name_b, port_index2) + 393 P2pCandidateXml(channel_name_b, port_index3))); 394 } 395 396 std::string JingleDescriptionInfoXml(const std::string& content_name, 397 const std::string& content_type) { 398 return JingleActionXml( 399 "description-info", 400 JingleContentXml(content_name, content_type, "", "")); 401 } 402 403 std::string GingleRejectXml(const std::string& reason) { 404 return GingleSessionXml( 405 "reject", 406 "<" + reason + "/>"); 407 } 408 409 std::string JingleTerminateXml(const std::string& reason) { 410 return JingleActionXml( 411 "session-terminate", 412 "<reason><" + reason + "/></reason>"); 413 } 414 415 std::string GingleTerminateXml(const std::string& reason) { 416 return GingleSessionXml( 417 "terminate", 418 "<" + reason + "/>"); 419 } 420 421 std::string GingleRedirectXml(const std::string& intitiate, 422 const std::string& target) { 423 return intitiate + 424 "<error code=\"302\" type=\"modify\">" 425 "<redirect xmlns=\"http://www.google.com/session\">" 426 "xmpp:" + target + 427 "</redirect>" 428 "</error>"; 429 } 430 431 std::string JingleRedirectXml(const std::string& intitiate, 432 const std::string& target) { 433 return intitiate + 434 "<error code=\"302\" type=\"modify\">" 435 "<redirect xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\">" 436 "xmpp:" + target + 437 "</redirect>" 438 "</error>"; 439 } 440 441 std::string InitiateXml(SignalingProtocol protocol, 442 const std::string& gingle_content_type, 443 const std::string& content_name_a, 444 const std::string& content_type_a, 445 const std::string& content_name_b, 446 const std::string& content_type_b, 447 bool bundle = false) { 448 switch (protocol) { 449 case PROTOCOL_JINGLE: 450 return JingleInitiateXml(content_name_a, content_type_a, 451 content_name_b, content_type_b, 452 bundle); 453 case PROTOCOL_GINGLE: 454 return GingleInitiateXml(gingle_content_type); 455 case PROTOCOL_HYBRID: 456 return JingleInitiateXml(content_name_a, content_type_a, 457 content_name_b, content_type_b) + 458 GingleInitiateXml(gingle_content_type); 459 } 460 return ""; 461 } 462 463 std::string InitiateXml(SignalingProtocol protocol, 464 const std::string& content_name, 465 const std::string& content_type) { 466 return InitiateXml(protocol, 467 content_type, 468 content_name, content_type, 469 "", ""); 470 } 471 472 std::string AcceptXml(SignalingProtocol protocol, 473 const std::string& gingle_content_type, 474 const std::string& content_name_a, 475 const std::string& content_type_a, 476 const std::string& content_name_b, 477 const std::string& content_type_b, 478 bool bundle = false) { 479 switch (protocol) { 480 case PROTOCOL_JINGLE: 481 return JingleAcceptXml(content_name_a, content_type_a, 482 content_name_b, content_type_b, bundle); 483 case PROTOCOL_GINGLE: 484 return GingleAcceptXml(gingle_content_type); 485 case PROTOCOL_HYBRID: 486 return 487 JingleAcceptXml(content_name_a, content_type_a, 488 content_name_b, content_type_b) + 489 GingleAcceptXml(gingle_content_type); 490 } 491 return ""; 492 } 493 494 495 std::string AcceptXml(SignalingProtocol protocol, 496 const std::string& content_name, 497 const std::string& content_type, 498 bool bundle = false) { 499 return AcceptXml(protocol, 500 content_type, 501 content_name, content_type, 502 "", ""); 503 } 504 505 std::string TransportInfo2Xml(SignalingProtocol protocol, 506 const std::string& content_name, 507 const std::string& channel_name, 508 int port_index0, 509 int port_index1) { 510 switch (protocol) { 511 case PROTOCOL_JINGLE: 512 return Jingle2TransportInfoXml( 513 content_name, 514 channel_name, port_index0, port_index1); 515 case PROTOCOL_GINGLE: 516 return Gingle2CandidatesXml( 517 channel_name, port_index0, port_index1); 518 case PROTOCOL_HYBRID: 519 return 520 Jingle2TransportInfoXml( 521 content_name, 522 channel_name, port_index0, port_index1) + 523 Gingle2CandidatesXml( 524 channel_name, port_index0, port_index1); 525 } 526 return ""; 527 } 528 529 std::string TransportInfo4Xml(SignalingProtocol protocol, 530 const std::string& content_name, 531 const std::string& channel_name_a, 532 int port_index0, 533 int port_index1, 534 const std::string& channel_name_b, 535 int port_index2, 536 int port_index3) { 537 switch (protocol) { 538 case PROTOCOL_JINGLE: 539 return Jingle4TransportInfoXml( 540 content_name, 541 channel_name_a, port_index0, port_index1, 542 channel_name_b, port_index2, port_index3); 543 case PROTOCOL_GINGLE: 544 return Gingle4CandidatesXml( 545 channel_name_a, port_index0, port_index1, 546 channel_name_b, port_index2, port_index3); 547 case PROTOCOL_HYBRID: 548 return 549 Jingle4TransportInfoXml( 550 content_name, 551 channel_name_a, port_index0, port_index1, 552 channel_name_b, port_index2, port_index3) + 553 Gingle4CandidatesXml( 554 channel_name_a, port_index0, port_index1, 555 channel_name_b, port_index2, port_index3); 556 } 557 return ""; 558 } 559 560 std::string RejectXml(SignalingProtocol protocol, 561 const std::string& reason) { 562 switch (protocol) { 563 case PROTOCOL_JINGLE: 564 return JingleTerminateXml(reason); 565 case PROTOCOL_GINGLE: 566 return GingleRejectXml(reason); 567 case PROTOCOL_HYBRID: 568 return JingleTerminateXml(reason) + 569 GingleRejectXml(reason); 570 } 571 return ""; 572 } 573 574 std::string TerminateXml(SignalingProtocol protocol, 575 const std::string& reason) { 576 switch (protocol) { 577 case PROTOCOL_JINGLE: 578 return JingleTerminateXml(reason); 579 case PROTOCOL_GINGLE: 580 return GingleTerminateXml(reason); 581 case PROTOCOL_HYBRID: 582 return JingleTerminateXml(reason) + 583 GingleTerminateXml(reason); 584 } 585 return ""; 586 } 587 588 std::string RedirectXml(SignalingProtocol protocol, 589 const std::string& initiate, 590 const std::string& target) { 591 switch (protocol) { 592 case PROTOCOL_JINGLE: 593 return JingleRedirectXml(initiate, target); 594 case PROTOCOL_GINGLE: 595 return GingleRedirectXml(initiate, target); 596 default: 597 break; 598 } 599 return ""; 600 } 601 602 // TODO: Break out and join with fakeportallocator.h 603 class TestPortAllocatorSession : public cricket::PortAllocatorSession { 604 public: 605 TestPortAllocatorSession(const std::string& content_name, 606 int component, 607 const std::string& ice_ufrag, 608 const std::string& ice_pwd, 609 const int port_offset) 610 : PortAllocatorSession(content_name, component, ice_ufrag, ice_pwd, 0), 611 port_offset_(port_offset), 612 ports_(kNumPorts), 613 address_("127.0.0.1", 0), 614 network_("network", "unittest", 615 talk_base::IPAddress(INADDR_LOOPBACK), 8), 616 socket_factory_(talk_base::Thread::Current()), 617 running_(false), 618 port_(28653) { 619 network_.AddIP(address_.ipaddr()); 620 } 621 622 ~TestPortAllocatorSession() { 623 for (size_t i = 0; i < ports_.size(); i++) 624 delete ports_[i]; 625 } 626 627 virtual void StartGettingPorts() { 628 for (int i = 0; i < kNumPorts; i++) { 629 int index = port_offset_ + i; 630 ports_[i] = cricket::UDPPort::Create( 631 talk_base::Thread::Current(), &socket_factory_, 632 &network_, address_.ipaddr(), GetPort(index), GetPort(index), 633 GetUsername(index), GetPassword(index)); 634 AddPort(ports_[i]); 635 } 636 running_ = true; 637 } 638 639 virtual void StopGettingPorts() { running_ = false; } 640 virtual bool IsGettingPorts() { return running_; } 641 642 void AddPort(cricket::Port* port) { 643 port->set_component(component_); 644 port->set_generation(0); 645 port->SignalDestroyed.connect( 646 this, &TestPortAllocatorSession::OnPortDestroyed); 647 port->SignalPortComplete.connect( 648 this, &TestPortAllocatorSession::OnPortComplete); 649 port->PrepareAddress(); 650 SignalPortReady(this, port); 651 } 652 653 void OnPortDestroyed(cricket::PortInterface* port) { 654 for (size_t i = 0; i < ports_.size(); i++) { 655 if (ports_[i] == port) 656 ports_[i] = NULL; 657 } 658 } 659 660 void OnPortComplete(cricket::Port* port) { 661 SignalCandidatesReady(this, port->Candidates()); 662 } 663 664 private: 665 int port_offset_; 666 std::vector<cricket::Port*> ports_; 667 talk_base::SocketAddress address_; 668 talk_base::Network network_; 669 talk_base::BasicPacketSocketFactory socket_factory_; 670 bool running_; 671 int port_; 672 }; 673 674 class TestPortAllocator : public cricket::PortAllocator { 675 public: 676 TestPortAllocator() : port_offset_(0) {} 677 678 virtual cricket::PortAllocatorSession* 679 CreateSessionInternal( 680 const std::string& content_name, 681 int component, 682 const std::string& ice_ufrag, 683 const std::string& ice_pwd) { 684 port_offset_ += 2; 685 return new TestPortAllocatorSession(content_name, component, 686 ice_ufrag, ice_pwd, port_offset_ - 2); 687 } 688 689 int port_offset_; 690 }; 691 692 class TestContentDescription : public cricket::ContentDescription { 693 public: 694 explicit TestContentDescription(const std::string& gingle_content_type, 695 const std::string& content_type) 696 : gingle_content_type(gingle_content_type), 697 content_type(content_type) { 698 } 699 virtual ContentDescription* Copy() const { 700 return new TestContentDescription(*this); 701 } 702 703 std::string gingle_content_type; 704 std::string content_type; 705 }; 706 707 cricket::SessionDescription* NewTestSessionDescription( 708 const std::string gingle_content_type, 709 const std::string& content_name_a, const std::string& content_type_a, 710 const std::string& content_name_b, const std::string& content_type_b) { 711 712 cricket::SessionDescription* offer = new cricket::SessionDescription(); 713 offer->AddContent(content_name_a, content_type_a, 714 new TestContentDescription(gingle_content_type, 715 content_type_a)); 716 cricket::TransportDescription desc(cricket::NS_GINGLE_P2P, 717 std::string(), std::string()); 718 offer->AddTransportInfo(cricket::TransportInfo(content_name_a, desc)); 719 720 if (content_name_a != content_name_b) { 721 offer->AddContent(content_name_b, content_type_b, 722 new TestContentDescription(gingle_content_type, 723 content_type_b)); 724 offer->AddTransportInfo(cricket::TransportInfo(content_name_b, desc)); 725 } 726 return offer; 727 } 728 729 cricket::SessionDescription* NewTestSessionDescription( 730 const std::string& content_name, const std::string& content_type) { 731 732 cricket::SessionDescription* offer = new cricket::SessionDescription(); 733 offer->AddContent(content_name, content_type, 734 new TestContentDescription(content_type, 735 content_type)); 736 offer->AddTransportInfo(cricket::TransportInfo 737 (content_name, cricket::TransportDescription( 738 cricket::NS_GINGLE_P2P, 739 std::string(), std::string()))); 740 return offer; 741 } 742 743 struct TestSessionClient: public cricket::SessionClient, 744 public sigslot::has_slots<> { 745 public: 746 TestSessionClient() { 747 } 748 749 ~TestSessionClient() { 750 } 751 752 virtual bool ParseContent(SignalingProtocol protocol, 753 const buzz::XmlElement* elem, 754 cricket::ContentDescription** content, 755 cricket::ParseError* error) { 756 std::string content_type; 757 std::string gingle_content_type; 758 if (protocol == PROTOCOL_GINGLE) { 759 gingle_content_type = elem->Name().Namespace(); 760 } else { 761 content_type = elem->Name().Namespace(); 762 } 763 764 *content = new TestContentDescription(gingle_content_type, content_type); 765 return true; 766 } 767 768 virtual bool WriteContent(SignalingProtocol protocol, 769 const cricket::ContentDescription* untyped_content, 770 buzz::XmlElement** elem, 771 cricket::WriteError* error) { 772 const TestContentDescription* content = 773 static_cast<const TestContentDescription*>(untyped_content); 774 std::string content_type = (protocol == PROTOCOL_GINGLE ? 775 content->gingle_content_type : 776 content->content_type); 777 *elem = new buzz::XmlElement( 778 buzz::QName(content_type, "description"), true); 779 return true; 780 } 781 782 void OnSessionCreate(cricket::Session* session, bool initiate) { 783 } 784 785 void OnSessionDestroy(cricket::Session* session) { 786 } 787 }; 788 789 struct ChannelHandler : sigslot::has_slots<> { 790 explicit ChannelHandler(cricket::TransportChannel* p, const std::string& name) 791 : channel(p), last_readable(false), last_writable(false), data_count(0), 792 last_size(0), name(name) { 793 p->SignalReadableState.connect(this, &ChannelHandler::OnReadableState); 794 p->SignalWritableState.connect(this, &ChannelHandler::OnWritableState); 795 p->SignalReadPacket.connect(this, &ChannelHandler::OnReadPacket); 796 } 797 798 bool writable() const { 799 return last_writable && channel->writable(); 800 } 801 802 bool readable() const { 803 return last_readable && channel->readable(); 804 } 805 806 void OnReadableState(cricket::TransportChannel* p) { 807 EXPECT_EQ(channel, p); 808 last_readable = channel->readable(); 809 } 810 811 void OnWritableState(cricket::TransportChannel* p) { 812 EXPECT_EQ(channel, p); 813 last_writable = channel->writable(); 814 } 815 816 void OnReadPacket(cricket::TransportChannel* p, const char* buf, 817 size_t size, const talk_base::PacketTime& time, int flags) { 818 if (memcmp(buf, name.c_str(), name.size()) != 0) 819 return; // drop packet if packet doesn't belong to this channel. This 820 // can happen when transport channels are muxed together. 821 buf += name.size(); // Remove channel name from the message. 822 size -= name.size(); // Decrement size by channel name string size. 823 EXPECT_EQ(channel, p); 824 EXPECT_LE(size, sizeof(last_data)); 825 data_count += 1; 826 last_size = size; 827 std::memcpy(last_data, buf, size); 828 } 829 830 void Send(const char* data, size_t size) { 831 std::string data_with_id(name); 832 data_with_id += data; 833 int result = channel->SendPacket(data_with_id.c_str(), data_with_id.size(), 834 talk_base::DSCP_NO_CHANGE, 0); 835 EXPECT_EQ(static_cast<int>(data_with_id.size()), result); 836 } 837 838 cricket::TransportChannel* channel; 839 bool last_readable, last_writable; 840 int data_count; 841 char last_data[4096]; 842 size_t last_size; 843 std::string name; 844 }; 845 846 void PrintStanza(const std::string& message, 847 const buzz::XmlElement* stanza) { 848 printf("%s: %s\n", message.c_str(), stanza->Str().c_str()); 849 } 850 851 class TestClient : public sigslot::has_slots<> { 852 public: 853 // TODO: Add channel_component_a/b as inputs to the ctor. 854 TestClient(cricket::PortAllocator* port_allocator, 855 int* next_message_id, 856 const std::string& local_name, 857 SignalingProtocol start_protocol, 858 const std::string& content_type, 859 const std::string& content_name_a, 860 const std::string& channel_name_a, 861 const std::string& content_name_b, 862 const std::string& channel_name_b) { 863 Construct(port_allocator, next_message_id, local_name, start_protocol, 864 content_type, content_name_a, channel_name_a, 865 content_name_b, channel_name_b); 866 } 867 868 ~TestClient() { 869 if (session) { 870 session_manager->DestroySession(session); 871 EXPECT_EQ(1U, session_destroyed_count); 872 } 873 delete session_manager; 874 delete client; 875 for (std::deque<buzz::XmlElement*>::iterator it = sent_stanzas.begin(); 876 it != sent_stanzas.end(); ++it) { 877 delete *it; 878 } 879 } 880 881 void Construct(cricket::PortAllocator* pa, 882 int* message_id, 883 const std::string& lname, 884 SignalingProtocol protocol, 885 const std::string& cont_type, 886 const std::string& cont_name_a, 887 const std::string& chan_name_a, 888 const std::string& cont_name_b, 889 const std::string& chan_name_b) { 890 port_allocator_ = pa; 891 next_message_id = message_id; 892 local_name = lname; 893 start_protocol = protocol; 894 content_type = cont_type; 895 content_name_a = cont_name_a; 896 channel_name_a = chan_name_a; 897 content_name_b = cont_name_b; 898 channel_name_b = chan_name_b; 899 session_created_count = 0; 900 session_destroyed_count = 0; 901 session_remote_description_update_count = 0; 902 new_local_description = false; 903 new_remote_description = false; 904 last_content_action = cricket::CA_OFFER; 905 last_content_source = cricket::CS_LOCAL; 906 session = NULL; 907 last_session_state = cricket::BaseSession::STATE_INIT; 908 blow_up_on_error = true; 909 error_count = 0; 910 911 session_manager = new cricket::SessionManager(port_allocator_); 912 session_manager->SignalSessionCreate.connect( 913 this, &TestClient::OnSessionCreate); 914 session_manager->SignalSessionDestroy.connect( 915 this, &TestClient::OnSessionDestroy); 916 session_manager->SignalOutgoingMessage.connect( 917 this, &TestClient::OnOutgoingMessage); 918 919 client = new TestSessionClient(); 920 session_manager->AddClient(content_type, client); 921 EXPECT_EQ(client, session_manager->GetClient(content_type)); 922 } 923 924 uint32 sent_stanza_count() const { 925 return static_cast<uint32>(sent_stanzas.size()); 926 } 927 928 const buzz::XmlElement* stanza() const { 929 return last_expected_sent_stanza.get(); 930 } 931 932 cricket::BaseSession::State session_state() const { 933 EXPECT_EQ(last_session_state, session->state()); 934 return session->state(); 935 } 936 937 void SetSessionState(cricket::BaseSession::State state) { 938 session->SetState(state); 939 EXPECT_EQ_WAIT(last_session_state, session->state(), kEventTimeout); 940 } 941 942 void CreateSession() { 943 session_manager->CreateSession(local_name, content_type); 944 } 945 946 void DeliverStanza(const buzz::XmlElement* stanza) { 947 session_manager->OnIncomingMessage(stanza); 948 } 949 950 void DeliverStanza(const std::string& str) { 951 buzz::XmlElement* stanza = buzz::XmlElement::ForStr(str); 952 session_manager->OnIncomingMessage(stanza); 953 delete stanza; 954 } 955 956 void DeliverAckToLastStanza() { 957 const buzz::XmlElement* orig_stanza = stanza(); 958 const buzz::XmlElement* response_stanza = 959 buzz::XmlElement::ForStr(IqAck(orig_stanza->Attr(buzz::QN_IQ), "", "")); 960 session_manager->OnIncomingResponse(orig_stanza, response_stanza); 961 delete response_stanza; 962 } 963 964 void ExpectSentStanza(const std::string& expected) { 965 EXPECT_TRUE(!sent_stanzas.empty()) << 966 "Found no stanza when expected " << expected; 967 968 last_expected_sent_stanza.reset(sent_stanzas.front()); 969 sent_stanzas.pop_front(); 970 971 std::string actual = last_expected_sent_stanza->Str(); 972 EXPECT_EQ(expected, actual); 973 } 974 975 void SkipUnsentStanza() { 976 GetNextOutgoingMessageID(); 977 } 978 979 bool HasTransport(const std::string& content_name) const { 980 ASSERT(session != NULL); 981 const cricket::Transport* transport = session->GetTransport(content_name); 982 return transport != NULL && (kTransportType == transport->type()); 983 } 984 985 bool HasChannel(const std::string& content_name, 986 int component) const { 987 ASSERT(session != NULL); 988 const cricket::TransportChannel* channel = 989 session->GetChannel(content_name, component); 990 return channel != NULL && (component == channel->component()); 991 } 992 993 cricket::TransportChannel* GetChannel(const std::string& content_name, 994 int component) const { 995 ASSERT(session != NULL); 996 return session->GetChannel(content_name, component); 997 } 998 999 void OnSessionCreate(cricket::Session* created_session, bool initiate) { 1000 session_created_count += 1; 1001 1002 session = created_session; 1003 session->set_current_protocol(start_protocol); 1004 session->SignalState.connect(this, &TestClient::OnSessionState); 1005 session->SignalError.connect(this, &TestClient::OnSessionError); 1006 session->SignalRemoteDescriptionUpdate.connect( 1007 this, &TestClient::OnSessionRemoteDescriptionUpdate); 1008 session->SignalNewLocalDescription.connect( 1009 this, &TestClient::OnNewLocalDescription); 1010 session->SignalNewRemoteDescription.connect( 1011 this, &TestClient::OnNewRemoteDescription); 1012 1013 CreateChannels(); 1014 } 1015 1016 void OnSessionDestroy(cricket::Session *session) { 1017 session_destroyed_count += 1; 1018 } 1019 1020 void OnSessionState(cricket::BaseSession* session, 1021 cricket::BaseSession::State state) { 1022 // EXPECT_EQ does not allow use of this, hence the tmp variable. 1023 cricket::BaseSession* tmp = this->session; 1024 EXPECT_EQ(tmp, session); 1025 last_session_state = state; 1026 } 1027 1028 void OnSessionError(cricket::BaseSession* session, 1029 cricket::BaseSession::Error error) { 1030 // EXPECT_EQ does not allow use of this, hence the tmp variable. 1031 cricket::BaseSession* tmp = this->session; 1032 EXPECT_EQ(tmp, session); 1033 if (blow_up_on_error) { 1034 EXPECT_TRUE(false); 1035 } else { 1036 error_count++; 1037 } 1038 } 1039 1040 void OnSessionRemoteDescriptionUpdate(cricket::BaseSession* session, 1041 const cricket::ContentInfos& contents) { 1042 session_remote_description_update_count++; 1043 } 1044 1045 void OnNewLocalDescription(cricket::BaseSession* session, 1046 cricket::ContentAction action) { 1047 new_local_description = true; 1048 last_content_action = action; 1049 last_content_source = cricket::CS_LOCAL; 1050 } 1051 1052 void OnNewRemoteDescription(cricket::BaseSession* session, 1053 cricket::ContentAction action) { 1054 new_remote_description = true; 1055 last_content_action = action; 1056 last_content_source = cricket::CS_REMOTE; 1057 } 1058 1059 void PrepareCandidates() { 1060 session_manager->OnSignalingReady(); 1061 } 1062 1063 void OnOutgoingMessage(cricket::SessionManager* manager, 1064 const buzz::XmlElement* stanza) { 1065 buzz::XmlElement* elem = new buzz::XmlElement(*stanza); 1066 EXPECT_TRUE(elem->Name() == buzz::QN_IQ); 1067 EXPECT_TRUE(elem->HasAttr(buzz::QN_TO)); 1068 EXPECT_FALSE(elem->HasAttr(buzz::QN_FROM)); 1069 EXPECT_TRUE(elem->HasAttr(buzz::QN_TYPE)); 1070 EXPECT_TRUE((elem->Attr(buzz::QN_TYPE) == "set") || 1071 (elem->Attr(buzz::QN_TYPE) == "result") || 1072 (elem->Attr(buzz::QN_TYPE) == "error")); 1073 1074 elem->SetAttr(buzz::QN_FROM, local_name); 1075 if (elem->Attr(buzz::QN_TYPE) == "set") { 1076 EXPECT_FALSE(elem->HasAttr(buzz::QN_ID)); 1077 elem->SetAttr(buzz::QN_ID, GetNextOutgoingMessageID()); 1078 } 1079 1080 // Uncommenting this is useful for debugging. 1081 // PrintStanza("OutgoingMessage", elem); 1082 sent_stanzas.push_back(elem); 1083 } 1084 1085 std::string GetNextOutgoingMessageID() { 1086 int message_id = (*next_message_id)++; 1087 std::ostringstream ost; 1088 ost << message_id; 1089 return ost.str(); 1090 } 1091 1092 void CreateChannels() { 1093 ASSERT(session != NULL); 1094 // We either have a single content with multiple components (RTP/RTCP), or 1095 // multiple contents with single components, but not both. 1096 int component_a = 1; 1097 int component_b = (content_name_a == content_name_b) ? 2 : 1; 1098 chan_a.reset(new ChannelHandler( 1099 session->CreateChannel(content_name_a, channel_name_a, component_a), 1100 channel_name_a)); 1101 chan_b.reset(new ChannelHandler( 1102 session->CreateChannel(content_name_b, channel_name_b, component_b), 1103 channel_name_b)); 1104 } 1105 1106 int* next_message_id; 1107 std::string local_name; 1108 SignalingProtocol start_protocol; 1109 std::string content_type; 1110 std::string content_name_a; 1111 std::string channel_name_a; 1112 std::string content_name_b; 1113 std::string channel_name_b; 1114 1115 uint32 session_created_count; 1116 uint32 session_destroyed_count; 1117 uint32 session_remote_description_update_count; 1118 bool new_local_description; 1119 bool new_remote_description; 1120 cricket::ContentAction last_content_action; 1121 cricket::ContentSource last_content_source; 1122 std::deque<buzz::XmlElement*> sent_stanzas; 1123 talk_base::scoped_ptr<buzz::XmlElement> last_expected_sent_stanza; 1124 1125 cricket::SessionManager* session_manager; 1126 TestSessionClient* client; 1127 cricket::PortAllocator* port_allocator_; 1128 cricket::Session* session; 1129 cricket::BaseSession::State last_session_state; 1130 talk_base::scoped_ptr<ChannelHandler> chan_a; 1131 talk_base::scoped_ptr<ChannelHandler> chan_b; 1132 bool blow_up_on_error; 1133 int error_count; 1134 }; 1135 1136 class SessionTest : public testing::Test { 1137 protected: 1138 virtual void SetUp() { 1139 // Seed needed for each test to satisfy expectations. 1140 talk_base::SetRandomTestMode(true); 1141 } 1142 1143 virtual void TearDown() { 1144 talk_base::SetRandomTestMode(false); 1145 } 1146 1147 // Tests sending data between two clients, over two channels. 1148 void TestSendRecv(ChannelHandler* chan1a, 1149 ChannelHandler* chan1b, 1150 ChannelHandler* chan2a, 1151 ChannelHandler* chan2b) { 1152 const char* dat1a = "spamspamspamspamspamspamspambakedbeansspam"; 1153 const char* dat2a = "mapssnaebdekabmapsmapsmapsmapsmapsmapsmaps"; 1154 const char* dat1b = "Lobster Thermidor a Crevette with a mornay sauce..."; 1155 const char* dat2b = "...ecuas yanrom a htiw etteverC a rodimrehT retsboL"; 1156 1157 for (int i = 0; i < 20; i++) { 1158 chan1a->Send(dat1a, strlen(dat1a)); 1159 chan1b->Send(dat1b, strlen(dat1b)); 1160 chan2a->Send(dat2a, strlen(dat2a)); 1161 chan2b->Send(dat2b, strlen(dat2b)); 1162 1163 EXPECT_EQ_WAIT(i + 1, chan1a->data_count, kEventTimeout); 1164 EXPECT_EQ_WAIT(i + 1, chan1b->data_count, kEventTimeout); 1165 EXPECT_EQ_WAIT(i + 1, chan2a->data_count, kEventTimeout); 1166 EXPECT_EQ_WAIT(i + 1, chan2b->data_count, kEventTimeout); 1167 1168 EXPECT_EQ(strlen(dat2a), chan1a->last_size); 1169 EXPECT_EQ(strlen(dat2b), chan1b->last_size); 1170 EXPECT_EQ(strlen(dat1a), chan2a->last_size); 1171 EXPECT_EQ(strlen(dat1b), chan2b->last_size); 1172 1173 EXPECT_EQ(0, std::memcmp(chan1a->last_data, dat2a, 1174 strlen(dat2a))); 1175 EXPECT_EQ(0, std::memcmp(chan1b->last_data, dat2b, 1176 strlen(dat2b))); 1177 EXPECT_EQ(0, std::memcmp(chan2a->last_data, dat1a, 1178 strlen(dat1a))); 1179 EXPECT_EQ(0, std::memcmp(chan2b->last_data, dat1b, 1180 strlen(dat1b))); 1181 } 1182 } 1183 1184 // Test an initiate from one client to another, each with 1185 // independent initial protocols. Checks for the correct initiates, 1186 // candidates, and accept messages, and tests that working network 1187 // channels are established. 1188 void TestSession(SignalingProtocol initiator_protocol, 1189 SignalingProtocol responder_protocol, 1190 SignalingProtocol resulting_protocol, 1191 const std::string& gingle_content_type, 1192 const std::string& content_type, 1193 const std::string& content_name_a, 1194 const std::string& channel_name_a, 1195 const std::string& content_name_b, 1196 const std::string& channel_name_b, 1197 const std::string& initiate_xml, 1198 const std::string& transport_info_a_xml, 1199 const std::string& transport_info_b_xml, 1200 const std::string& transport_info_reply_a_xml, 1201 const std::string& transport_info_reply_b_xml, 1202 const std::string& accept_xml, 1203 bool bundle = false) { 1204 talk_base::scoped_ptr<cricket::PortAllocator> allocator( 1205 new TestPortAllocator()); 1206 int next_message_id = 0; 1207 1208 talk_base::scoped_ptr<TestClient> initiator( 1209 new TestClient(allocator.get(), &next_message_id, 1210 kInitiator, initiator_protocol, 1211 content_type, 1212 content_name_a, channel_name_a, 1213 content_name_b, channel_name_b)); 1214 talk_base::scoped_ptr<TestClient> responder( 1215 new TestClient(allocator.get(), &next_message_id, 1216 kResponder, responder_protocol, 1217 content_type, 1218 content_name_a, channel_name_a, 1219 content_name_b, channel_name_b)); 1220 1221 // Create Session and check channels and state. 1222 initiator->CreateSession(); 1223 EXPECT_EQ(1U, initiator->session_created_count); 1224 EXPECT_EQ(kSessionId, initiator->session->id()); 1225 EXPECT_EQ(initiator->session->local_name(), kInitiator); 1226 EXPECT_EQ(cricket::BaseSession::STATE_INIT, 1227 initiator->session_state()); 1228 1229 // See comment in CreateChannels about how we choose component IDs. 1230 int component_a = 1; 1231 int component_b = (content_name_a == content_name_b) ? 2 : 1; 1232 EXPECT_TRUE(initiator->HasTransport(content_name_a)); 1233 EXPECT_TRUE(initiator->HasChannel(content_name_a, component_a)); 1234 EXPECT_TRUE(initiator->HasTransport(content_name_b)); 1235 EXPECT_TRUE(initiator->HasChannel(content_name_b, component_b)); 1236 1237 // Initiate and expect initiate message sent. 1238 cricket::SessionDescription* offer = NewTestSessionDescription( 1239 gingle_content_type, 1240 content_name_a, content_type, 1241 content_name_b, content_type); 1242 if (bundle) { 1243 cricket::ContentGroup group(cricket::GROUP_TYPE_BUNDLE); 1244 group.AddContentName(content_name_a); 1245 group.AddContentName(content_name_b); 1246 EXPECT_TRUE(group.HasContentName(content_name_a)); 1247 EXPECT_TRUE(group.HasContentName(content_name_b)); 1248 offer->AddGroup(group); 1249 } 1250 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); 1251 EXPECT_EQ(initiator->session->remote_name(), kResponder); 1252 EXPECT_EQ(initiator->session->local_description(), offer); 1253 1254 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1255 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, 1256 initiator->session_state()); 1257 1258 initiator->ExpectSentStanza( 1259 IqSet("0", kInitiator, kResponder, initiate_xml)); 1260 1261 // Deliver the initiate. Expect ack and session created with 1262 // transports. 1263 responder->DeliverStanza(initiator->stanza()); 1264 responder->ExpectSentStanza( 1265 IqAck("0", kResponder, kInitiator)); 1266 EXPECT_EQ(0U, responder->sent_stanza_count()); 1267 1268 EXPECT_EQ(1U, responder->session_created_count); 1269 EXPECT_EQ(kSessionId, responder->session->id()); 1270 EXPECT_EQ(responder->session->local_name(), kResponder); 1271 EXPECT_EQ(responder->session->remote_name(), kInitiator); 1272 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, 1273 responder->session_state()); 1274 1275 EXPECT_TRUE(responder->HasTransport(content_name_a)); 1276 EXPECT_TRUE(responder->HasChannel(content_name_a, component_a)); 1277 EXPECT_TRUE(responder->HasTransport(content_name_b)); 1278 EXPECT_TRUE(responder->HasChannel(content_name_b, component_b)); 1279 1280 // Expect transport-info message from initiator. 1281 // But don't send candidates until initiate ack is received. 1282 initiator->PrepareCandidates(); 1283 WAIT(initiator->sent_stanza_count() > 0, 100); 1284 EXPECT_EQ(0U, initiator->sent_stanza_count()); 1285 initiator->DeliverAckToLastStanza(); 1286 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1287 initiator->ExpectSentStanza( 1288 IqSet("1", kInitiator, kResponder, transport_info_a_xml)); 1289 1290 // Deliver transport-info and expect ack. 1291 responder->DeliverStanza(initiator->stanza()); 1292 responder->ExpectSentStanza( 1293 IqAck("1", kResponder, kInitiator)); 1294 1295 if (!transport_info_b_xml.empty()) { 1296 // Expect second transport-info message from initiator. 1297 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1298 initiator->ExpectSentStanza( 1299 IqSet("2", kInitiator, kResponder, transport_info_b_xml)); 1300 EXPECT_EQ(0U, initiator->sent_stanza_count()); 1301 1302 // Deliver second transport-info message and expect ack. 1303 responder->DeliverStanza(initiator->stanza()); 1304 responder->ExpectSentStanza( 1305 IqAck("2", kResponder, kInitiator)); 1306 } else { 1307 EXPECT_EQ(0U, initiator->sent_stanza_count()); 1308 EXPECT_EQ(0U, responder->sent_stanza_count()); 1309 initiator->SkipUnsentStanza(); 1310 } 1311 1312 // Expect reply transport-info message from responder. 1313 responder->PrepareCandidates(); 1314 EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); 1315 responder->ExpectSentStanza( 1316 IqSet("3", kResponder, kInitiator, transport_info_reply_a_xml)); 1317 1318 // Deliver reply transport-info and expect ack. 1319 initiator->DeliverStanza(responder->stanza()); 1320 initiator->ExpectSentStanza( 1321 IqAck("3", kInitiator, kResponder)); 1322 1323 if (!transport_info_reply_b_xml.empty()) { 1324 // Expect second reply transport-info message from responder. 1325 EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); 1326 responder->ExpectSentStanza( 1327 IqSet("4", kResponder, kInitiator, transport_info_reply_b_xml)); 1328 EXPECT_EQ(0U, responder->sent_stanza_count()); 1329 1330 // Deliver second reply transport-info message and expect ack. 1331 initiator->DeliverStanza(responder->stanza()); 1332 initiator->ExpectSentStanza( 1333 IqAck("4", kInitiator, kResponder)); 1334 EXPECT_EQ(0U, initiator->sent_stanza_count()); 1335 } else { 1336 EXPECT_EQ(0U, initiator->sent_stanza_count()); 1337 EXPECT_EQ(0U, responder->sent_stanza_count()); 1338 responder->SkipUnsentStanza(); 1339 } 1340 1341 // The channels should be able to become writable at this point. This 1342 // requires pinging, so it may take a little while. 1343 EXPECT_TRUE_WAIT(initiator->chan_a->writable() && 1344 initiator->chan_a->readable(), kEventTimeout); 1345 EXPECT_TRUE_WAIT(initiator->chan_b->writable() && 1346 initiator->chan_b->readable(), kEventTimeout); 1347 EXPECT_TRUE_WAIT(responder->chan_a->writable() && 1348 responder->chan_a->readable(), kEventTimeout); 1349 EXPECT_TRUE_WAIT(responder->chan_b->writable() && 1350 responder->chan_b->readable(), kEventTimeout); 1351 1352 // Accept the session and expect accept stanza. 1353 cricket::SessionDescription* answer = NewTestSessionDescription( 1354 gingle_content_type, 1355 content_name_a, content_type, 1356 content_name_b, content_type); 1357 if (bundle) { 1358 cricket::ContentGroup group(cricket::GROUP_TYPE_BUNDLE); 1359 group.AddContentName(content_name_a); 1360 group.AddContentName(content_name_b); 1361 EXPECT_TRUE(group.HasContentName(content_name_a)); 1362 EXPECT_TRUE(group.HasContentName(content_name_b)); 1363 answer->AddGroup(group); 1364 } 1365 EXPECT_TRUE(responder->session->Accept(answer)); 1366 EXPECT_EQ(responder->session->local_description(), answer); 1367 1368 responder->ExpectSentStanza( 1369 IqSet("5", kResponder, kInitiator, accept_xml)); 1370 1371 EXPECT_EQ(0U, responder->sent_stanza_count()); 1372 1373 // Deliver the accept message and expect an ack. 1374 initiator->DeliverStanza(responder->stanza()); 1375 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1376 initiator->ExpectSentStanza( 1377 IqAck("5", kInitiator, kResponder)); 1378 EXPECT_EQ(0U, initiator->sent_stanza_count()); 1379 1380 // Both sessions should be in progress and have functioning 1381 // channels. 1382 EXPECT_EQ(resulting_protocol, initiator->session->current_protocol()); 1383 EXPECT_EQ(resulting_protocol, responder->session->current_protocol()); 1384 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, 1385 initiator->session_state(), kEventTimeout); 1386 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, 1387 responder->session_state(), kEventTimeout); 1388 if (bundle) { 1389 cricket::TransportChannel* initiator_chan_a = initiator->chan_a->channel; 1390 cricket::TransportChannel* initiator_chan_b = initiator->chan_b->channel; 1391 1392 // Since we know these are TransportChannelProxy, type cast it. 1393 cricket::TransportChannelProxy* initiator_proxy_chan_a = 1394 static_cast<cricket::TransportChannelProxy*>(initiator_chan_a); 1395 cricket::TransportChannelProxy* initiator_proxy_chan_b = 1396 static_cast<cricket::TransportChannelProxy*>(initiator_chan_b); 1397 EXPECT_TRUE(initiator_proxy_chan_a->impl() != NULL); 1398 EXPECT_TRUE(initiator_proxy_chan_b->impl() != NULL); 1399 EXPECT_EQ(initiator_proxy_chan_a->impl(), initiator_proxy_chan_b->impl()); 1400 1401 cricket::TransportChannel* responder_chan_a = responder->chan_a->channel; 1402 cricket::TransportChannel* responder_chan_b = responder->chan_b->channel; 1403 1404 // Since we know these are TransportChannelProxy, type cast it. 1405 cricket::TransportChannelProxy* responder_proxy_chan_a = 1406 static_cast<cricket::TransportChannelProxy*>(responder_chan_a); 1407 cricket::TransportChannelProxy* responder_proxy_chan_b = 1408 static_cast<cricket::TransportChannelProxy*>(responder_chan_b); 1409 EXPECT_TRUE(responder_proxy_chan_a->impl() != NULL); 1410 EXPECT_TRUE(responder_proxy_chan_b->impl() != NULL); 1411 EXPECT_EQ(responder_proxy_chan_a->impl(), responder_proxy_chan_b->impl()); 1412 } 1413 TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(), 1414 responder->chan_a.get(), responder->chan_b.get()); 1415 1416 if (resulting_protocol == PROTOCOL_JINGLE) { 1417 // Deliver a description-info message to the initiator and check if the 1418 // content description changes. 1419 EXPECT_EQ(0U, initiator->session_remote_description_update_count); 1420 1421 const cricket::SessionDescription* old_session_desc = 1422 initiator->session->remote_description(); 1423 const cricket::ContentInfo* old_content_a = 1424 old_session_desc->GetContentByName(content_name_a); 1425 const cricket::ContentDescription* old_content_desc_a = 1426 old_content_a->description; 1427 const cricket::ContentInfo* old_content_b = 1428 old_session_desc->GetContentByName(content_name_b); 1429 const cricket::ContentDescription* old_content_desc_b = 1430 old_content_b->description; 1431 EXPECT_TRUE(old_content_desc_a != NULL); 1432 EXPECT_TRUE(old_content_desc_b != NULL); 1433 1434 LOG(LS_INFO) << "A " << old_content_a->name; 1435 LOG(LS_INFO) << "B " << old_content_b->name; 1436 1437 std::string description_info_xml = 1438 JingleDescriptionInfoXml(content_name_a, content_type); 1439 initiator->DeliverStanza( 1440 IqSet("6", kResponder, kInitiator, description_info_xml)); 1441 responder->SkipUnsentStanza(); 1442 EXPECT_EQ(1U, initiator->session_remote_description_update_count); 1443 1444 const cricket::SessionDescription* new_session_desc = 1445 initiator->session->remote_description(); 1446 const cricket::ContentInfo* new_content_a = 1447 new_session_desc->GetContentByName(content_name_a); 1448 const cricket::ContentDescription* new_content_desc_a = 1449 new_content_a->description; 1450 const cricket::ContentInfo* new_content_b = 1451 new_session_desc->GetContentByName(content_name_b); 1452 const cricket::ContentDescription* new_content_desc_b = 1453 new_content_b->description; 1454 EXPECT_TRUE(new_content_desc_a != NULL); 1455 EXPECT_TRUE(new_content_desc_b != NULL); 1456 1457 // TODO: We used to replace contents from an update, but 1458 // that no longer works with partial updates. We need to figure out 1459 // a way to merge patial updates into contents. For now, users of 1460 // Session should listen to SignalRemoteDescriptionUpdate and handle 1461 // updates. They should not expect remote_description to be the 1462 // latest value. 1463 // See session.cc OnDescriptionInfoMessage. 1464 1465 // EXPECT_NE(old_content_desc_a, new_content_desc_a); 1466 1467 // if (content_name_a != content_name_b) { 1468 // // If content_name_a != content_name_b, then b's content description 1469 // // should not have changed since the description-info message only 1470 // // contained an update for content_name_a. 1471 // EXPECT_EQ(old_content_desc_b, new_content_desc_b); 1472 // } 1473 1474 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1475 initiator->ExpectSentStanza( 1476 IqAck("6", kInitiator, kResponder)); 1477 EXPECT_EQ(0U, initiator->sent_stanza_count()); 1478 } else { 1479 responder->SkipUnsentStanza(); 1480 } 1481 1482 initiator->session->Terminate(); 1483 initiator->ExpectSentStanza( 1484 IqSet("7", kInitiator, kResponder, 1485 TerminateXml(resulting_protocol, 1486 cricket::STR_TERMINATE_SUCCESS))); 1487 1488 responder->DeliverStanza(initiator->stanza()); 1489 responder->ExpectSentStanza( 1490 IqAck("7", kResponder, kInitiator)); 1491 EXPECT_EQ(cricket::BaseSession::STATE_SENTTERMINATE, 1492 initiator->session_state()); 1493 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE, 1494 responder->session_state()); 1495 } 1496 1497 // Test an initiate with other content, called "main". 1498 void TestOtherContent(SignalingProtocol initiator_protocol, 1499 SignalingProtocol responder_protocol, 1500 SignalingProtocol resulting_protocol) { 1501 std::string content_name = "main"; 1502 std::string content_type = "http://oink.splat/session"; 1503 std::string content_name_a = content_name; 1504 std::string channel_name_a = "rtp"; 1505 std::string content_name_b = content_name; 1506 std::string channel_name_b = "rtcp"; 1507 std::string initiate_xml = InitiateXml( 1508 initiator_protocol, 1509 content_name_a, content_type); 1510 std::string transport_info_a_xml = TransportInfo4Xml( 1511 initiator_protocol, content_name, 1512 channel_name_a, 0, 1, 1513 channel_name_b, 2, 3); 1514 std::string transport_info_b_xml = ""; 1515 std::string transport_info_reply_a_xml = TransportInfo4Xml( 1516 resulting_protocol, content_name, 1517 channel_name_a, 4, 5, 1518 channel_name_b, 6, 7); 1519 std::string transport_info_reply_b_xml = ""; 1520 std::string accept_xml = AcceptXml( 1521 resulting_protocol, 1522 content_name_a, content_type); 1523 1524 1525 TestSession(initiator_protocol, responder_protocol, resulting_protocol, 1526 content_type, 1527 content_type, 1528 content_name_a, channel_name_a, 1529 content_name_b, channel_name_b, 1530 initiate_xml, 1531 transport_info_a_xml, transport_info_b_xml, 1532 transport_info_reply_a_xml, transport_info_reply_b_xml, 1533 accept_xml); 1534 } 1535 1536 // Test an initiate with audio content. 1537 void TestAudioContent(SignalingProtocol initiator_protocol, 1538 SignalingProtocol responder_protocol, 1539 SignalingProtocol resulting_protocol) { 1540 std::string gingle_content_type = cricket::NS_GINGLE_AUDIO; 1541 std::string content_name = cricket::CN_AUDIO; 1542 std::string content_type = cricket::NS_JINGLE_RTP; 1543 std::string channel_name_a = "rtp"; 1544 std::string channel_name_b = "rtcp"; 1545 std::string initiate_xml = InitiateXml( 1546 initiator_protocol, 1547 gingle_content_type, 1548 content_name, content_type, 1549 "", ""); 1550 std::string transport_info_a_xml = TransportInfo4Xml( 1551 initiator_protocol, content_name, 1552 channel_name_a, 0, 1, 1553 channel_name_b, 2, 3); 1554 std::string transport_info_b_xml = ""; 1555 std::string transport_info_reply_a_xml = TransportInfo4Xml( 1556 resulting_protocol, content_name, 1557 channel_name_a, 4, 5, 1558 channel_name_b, 6, 7); 1559 std::string transport_info_reply_b_xml = ""; 1560 std::string accept_xml = AcceptXml( 1561 resulting_protocol, 1562 gingle_content_type, 1563 content_name, content_type, 1564 "", ""); 1565 1566 1567 TestSession(initiator_protocol, responder_protocol, resulting_protocol, 1568 gingle_content_type, 1569 content_type, 1570 content_name, channel_name_a, 1571 content_name, channel_name_b, 1572 initiate_xml, 1573 transport_info_a_xml, transport_info_b_xml, 1574 transport_info_reply_a_xml, transport_info_reply_b_xml, 1575 accept_xml); 1576 } 1577 1578 // Since media content is "split" into two contents (audio and 1579 // video), we need to treat it special. 1580 void TestVideoContents(SignalingProtocol initiator_protocol, 1581 SignalingProtocol responder_protocol, 1582 SignalingProtocol resulting_protocol) { 1583 std::string content_type = cricket::NS_JINGLE_RTP; 1584 std::string gingle_content_type = cricket::NS_GINGLE_VIDEO; 1585 std::string content_name_a = cricket::CN_AUDIO; 1586 std::string channel_name_a = "rtp"; 1587 std::string content_name_b = cricket::CN_VIDEO; 1588 std::string channel_name_b = "video_rtp"; 1589 1590 std::string initiate_xml = InitiateXml( 1591 initiator_protocol, 1592 gingle_content_type, 1593 content_name_a, content_type, 1594 content_name_b, content_type); 1595 std::string transport_info_a_xml = TransportInfo2Xml( 1596 initiator_protocol, content_name_a, 1597 channel_name_a, 0, 1); 1598 std::string transport_info_b_xml = TransportInfo2Xml( 1599 initiator_protocol, content_name_b, 1600 channel_name_b, 2, 3); 1601 std::string transport_info_reply_a_xml = TransportInfo2Xml( 1602 resulting_protocol, content_name_a, 1603 channel_name_a, 4, 5); 1604 std::string transport_info_reply_b_xml = TransportInfo2Xml( 1605 resulting_protocol, content_name_b, 1606 channel_name_b, 6, 7); 1607 std::string accept_xml = AcceptXml( 1608 resulting_protocol, 1609 gingle_content_type, 1610 content_name_a, content_type, 1611 content_name_b, content_type); 1612 1613 TestSession(initiator_protocol, responder_protocol, resulting_protocol, 1614 gingle_content_type, 1615 content_type, 1616 content_name_a, channel_name_a, 1617 content_name_b, channel_name_b, 1618 initiate_xml, 1619 transport_info_a_xml, transport_info_b_xml, 1620 transport_info_reply_a_xml, transport_info_reply_b_xml, 1621 accept_xml); 1622 } 1623 1624 void TestBadRedirect(SignalingProtocol protocol) { 1625 std::string content_name = "main"; 1626 std::string content_type = "http://oink.splat/session"; 1627 std::string channel_name_a = "chana"; 1628 std::string channel_name_b = "chanb"; 1629 std::string initiate_xml = InitiateXml( 1630 protocol, content_name, content_type); 1631 std::string transport_info_xml = TransportInfo4Xml( 1632 protocol, content_name, 1633 channel_name_a, 0, 1, 1634 channel_name_b, 2, 3); 1635 std::string transport_info_reply_xml = TransportInfo4Xml( 1636 protocol, content_name, 1637 channel_name_a, 4, 5, 1638 channel_name_b, 6, 7); 1639 std::string accept_xml = AcceptXml( 1640 protocol, content_name, content_type); 1641 std::string responder_full = kResponder + "/full"; 1642 1643 talk_base::scoped_ptr<cricket::PortAllocator> allocator( 1644 new TestPortAllocator()); 1645 int next_message_id = 0; 1646 1647 talk_base::scoped_ptr<TestClient> initiator( 1648 new TestClient(allocator.get(), &next_message_id, 1649 kInitiator, protocol, 1650 content_type, 1651 content_name, channel_name_a, 1652 content_name, channel_name_b)); 1653 1654 talk_base::scoped_ptr<TestClient> responder( 1655 new TestClient(allocator.get(), &next_message_id, 1656 responder_full, protocol, 1657 content_type, 1658 content_name, channel_name_a, 1659 content_name, channel_name_b)); 1660 1661 // Create Session and check channels and state. 1662 initiator->CreateSession(); 1663 EXPECT_EQ(1U, initiator->session_created_count); 1664 EXPECT_EQ(kSessionId, initiator->session->id()); 1665 EXPECT_EQ(initiator->session->local_name(), kInitiator); 1666 EXPECT_EQ(cricket::BaseSession::STATE_INIT, 1667 initiator->session_state()); 1668 1669 EXPECT_TRUE(initiator->HasChannel(content_name, 1)); 1670 EXPECT_TRUE(initiator->HasChannel(content_name, 2)); 1671 1672 // Initiate and expect initiate message sent. 1673 cricket::SessionDescription* offer = NewTestSessionDescription( 1674 content_name, content_type); 1675 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); 1676 EXPECT_EQ(initiator->session->remote_name(), kResponder); 1677 EXPECT_EQ(initiator->session->local_description(), offer); 1678 1679 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1680 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, 1681 initiator->session_state()); 1682 initiator->ExpectSentStanza( 1683 IqSet("0", kInitiator, kResponder, initiate_xml)); 1684 1685 // Expect transport-info message from initiator. 1686 initiator->DeliverAckToLastStanza(); 1687 initiator->PrepareCandidates(); 1688 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1689 initiator->ExpectSentStanza( 1690 IqSet("1", kInitiator, kResponder, transport_info_xml)); 1691 1692 // Send an unauthorized redirect to the initiator and expect it be ignored. 1693 initiator->blow_up_on_error = false; 1694 const buzz::XmlElement* initiate_stanza = initiator->stanza(); 1695 talk_base::scoped_ptr<buzz::XmlElement> redirect_stanza( 1696 buzz::XmlElement::ForStr( 1697 IqError("ER", kResponder, kInitiator, 1698 RedirectXml(protocol, initiate_xml, "not (at) allowed.com")))); 1699 initiator->session_manager->OnFailedSend( 1700 initiate_stanza, redirect_stanza.get()); 1701 EXPECT_EQ(initiator->session->remote_name(), kResponder); 1702 initiator->blow_up_on_error = true; 1703 EXPECT_EQ(initiator->error_count, 1); 1704 } 1705 1706 void TestGoodRedirect(SignalingProtocol protocol) { 1707 std::string content_name = "main"; 1708 std::string content_type = "http://oink.splat/session"; 1709 std::string channel_name_a = "chana"; 1710 std::string channel_name_b = "chanb"; 1711 std::string initiate_xml = InitiateXml( 1712 protocol, content_name, content_type); 1713 std::string transport_info_xml = TransportInfo4Xml( 1714 protocol, content_name, 1715 channel_name_a, 0, 1, 1716 channel_name_b, 2, 3); 1717 std::string transport_info_reply_xml = TransportInfo4Xml( 1718 protocol, content_name, 1719 channel_name_a, 4, 5, 1720 channel_name_b, 6, 7); 1721 std::string accept_xml = AcceptXml( 1722 protocol, content_name, content_type); 1723 std::string responder_full = kResponder + "/full"; 1724 1725 talk_base::scoped_ptr<cricket::PortAllocator> allocator( 1726 new TestPortAllocator()); 1727 int next_message_id = 0; 1728 1729 talk_base::scoped_ptr<TestClient> initiator( 1730 new TestClient(allocator.get(), &next_message_id, 1731 kInitiator, protocol, 1732 content_type, 1733 content_name, channel_name_a, 1734 content_name, channel_name_b)); 1735 1736 talk_base::scoped_ptr<TestClient> responder( 1737 new TestClient(allocator.get(), &next_message_id, 1738 responder_full, protocol, 1739 content_type, 1740 content_name, channel_name_a, 1741 content_name, channel_name_b)); 1742 1743 // Create Session and check channels and state. 1744 initiator->CreateSession(); 1745 EXPECT_EQ(1U, initiator->session_created_count); 1746 EXPECT_EQ(kSessionId, initiator->session->id()); 1747 EXPECT_EQ(initiator->session->local_name(), kInitiator); 1748 EXPECT_EQ(cricket::BaseSession::STATE_INIT, 1749 initiator->session_state()); 1750 1751 EXPECT_TRUE(initiator->HasChannel(content_name, 1)); 1752 EXPECT_TRUE(initiator->HasChannel(content_name, 2)); 1753 1754 // Initiate and expect initiate message sent. 1755 cricket::SessionDescription* offer = NewTestSessionDescription( 1756 content_name, content_type); 1757 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); 1758 EXPECT_EQ(initiator->session->remote_name(), kResponder); 1759 EXPECT_EQ(initiator->session->local_description(), offer); 1760 1761 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1762 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, 1763 initiator->session_state()); 1764 initiator->ExpectSentStanza( 1765 IqSet("0", kInitiator, kResponder, initiate_xml)); 1766 1767 // Expect transport-info message from initiator. 1768 initiator->DeliverAckToLastStanza(); 1769 initiator->PrepareCandidates(); 1770 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1771 initiator->ExpectSentStanza( 1772 IqSet("1", kInitiator, kResponder, transport_info_xml)); 1773 1774 // Send a redirect to the initiator and expect all of the message 1775 // to be resent. 1776 const buzz::XmlElement* initiate_stanza = initiator->stanza(); 1777 talk_base::scoped_ptr<buzz::XmlElement> redirect_stanza( 1778 buzz::XmlElement::ForStr( 1779 IqError("ER2", kResponder, kInitiator, 1780 RedirectXml(protocol, initiate_xml, responder_full)))); 1781 initiator->session_manager->OnFailedSend( 1782 initiate_stanza, redirect_stanza.get()); 1783 EXPECT_EQ(initiator->session->remote_name(), responder_full); 1784 1785 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1786 initiator->ExpectSentStanza( 1787 IqSet("2", kInitiator, responder_full, initiate_xml)); 1788 initiator->ExpectSentStanza( 1789 IqSet("3", kInitiator, responder_full, transport_info_xml)); 1790 1791 // Deliver the initiate. Expect ack and session created with 1792 // transports. 1793 responder->DeliverStanza( 1794 IqSet("2", kInitiator, responder_full, initiate_xml)); 1795 responder->ExpectSentStanza( 1796 IqAck("2", responder_full, kInitiator)); 1797 EXPECT_EQ(0U, responder->sent_stanza_count()); 1798 1799 EXPECT_EQ(1U, responder->session_created_count); 1800 EXPECT_EQ(kSessionId, responder->session->id()); 1801 EXPECT_EQ(responder->session->local_name(), responder_full); 1802 EXPECT_EQ(responder->session->remote_name(), kInitiator); 1803 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, 1804 responder->session_state()); 1805 1806 EXPECT_TRUE(responder->HasChannel(content_name, 1)); 1807 EXPECT_TRUE(responder->HasChannel(content_name, 2)); 1808 1809 // Deliver transport-info and expect ack. 1810 responder->DeliverStanza( 1811 IqSet("3", kInitiator, responder_full, transport_info_xml)); 1812 responder->ExpectSentStanza( 1813 IqAck("3", responder_full, kInitiator)); 1814 1815 // Expect reply transport-infos sent to new remote JID 1816 responder->PrepareCandidates(); 1817 EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); 1818 responder->ExpectSentStanza( 1819 IqSet("4", responder_full, kInitiator, transport_info_reply_xml)); 1820 1821 initiator->DeliverStanza(responder->stanza()); 1822 initiator->ExpectSentStanza( 1823 IqAck("4", kInitiator, responder_full)); 1824 1825 // The channels should be able to become writable at this point. This 1826 // requires pinging, so it may take a little while. 1827 EXPECT_TRUE_WAIT(initiator->chan_a->writable() && 1828 initiator->chan_a->readable(), kEventTimeout); 1829 EXPECT_TRUE_WAIT(initiator->chan_b->writable() && 1830 initiator->chan_b->readable(), kEventTimeout); 1831 EXPECT_TRUE_WAIT(responder->chan_a->writable() && 1832 responder->chan_a->readable(), kEventTimeout); 1833 EXPECT_TRUE_WAIT(responder->chan_b->writable() && 1834 responder->chan_b->readable(), kEventTimeout); 1835 1836 // Accept the session and expect accept stanza. 1837 cricket::SessionDescription* answer = NewTestSessionDescription( 1838 content_name, content_type); 1839 EXPECT_TRUE(responder->session->Accept(answer)); 1840 EXPECT_EQ(responder->session->local_description(), answer); 1841 1842 responder->ExpectSentStanza( 1843 IqSet("5", responder_full, kInitiator, accept_xml)); 1844 EXPECT_EQ(0U, responder->sent_stanza_count()); 1845 1846 // Deliver the accept message and expect an ack. 1847 initiator->DeliverStanza(responder->stanza()); 1848 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1849 initiator->ExpectSentStanza( 1850 IqAck("5", kInitiator, responder_full)); 1851 EXPECT_EQ(0U, initiator->sent_stanza_count()); 1852 1853 // Both sessions should be in progress and have functioning 1854 // channels. 1855 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, 1856 initiator->session_state(), kEventTimeout); 1857 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, 1858 responder->session_state(), kEventTimeout); 1859 TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(), 1860 responder->chan_a.get(), responder->chan_b.get()); 1861 } 1862 1863 void TestCandidatesInInitiateAndAccept(const std::string& test_name) { 1864 std::string content_name = "main"; 1865 std::string content_type = "http://oink.splat/session"; 1866 std::string channel_name_a = "rtp"; 1867 std::string channel_name_b = "rtcp"; 1868 cricket::SignalingProtocol protocol = PROTOCOL_JINGLE; 1869 1870 talk_base::scoped_ptr<cricket::PortAllocator> allocator( 1871 new TestPortAllocator()); 1872 int next_message_id = 0; 1873 1874 talk_base::scoped_ptr<TestClient> initiator( 1875 new TestClient(allocator.get(), &next_message_id, 1876 kInitiator, protocol, 1877 content_type, 1878 content_name, channel_name_a, 1879 content_name, channel_name_b)); 1880 1881 talk_base::scoped_ptr<TestClient> responder( 1882 new TestClient(allocator.get(), &next_message_id, 1883 kResponder, protocol, 1884 content_type, 1885 content_name, channel_name_a, 1886 content_name, channel_name_b)); 1887 1888 // Create Session and check channels and state. 1889 initiator->CreateSession(); 1890 EXPECT_TRUE(initiator->HasTransport(content_name)); 1891 EXPECT_TRUE(initiator->HasChannel(content_name, 1)); 1892 EXPECT_TRUE(initiator->HasTransport(content_name)); 1893 EXPECT_TRUE(initiator->HasChannel(content_name, 2)); 1894 1895 // Initiate and expect initiate message sent. 1896 cricket::SessionDescription* offer = NewTestSessionDescription( 1897 content_name, content_type); 1898 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); 1899 1900 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1901 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, 1902 initiator->session_state()); 1903 initiator->ExpectSentStanza( 1904 IqSet("0", kInitiator, kResponder, 1905 InitiateXml(protocol, content_name, content_type))); 1906 1907 // Fake the delivery the initiate and candidates together. 1908 responder->DeliverStanza( 1909 IqSet("A", kInitiator, kResponder, 1910 JingleInitiateActionXml( 1911 JingleContentXml( 1912 content_name, content_type, kTransportType, 1913 P2pCandidateXml(channel_name_a, 0) + 1914 P2pCandidateXml(channel_name_a, 1) + 1915 P2pCandidateXml(channel_name_b, 2) + 1916 P2pCandidateXml(channel_name_b, 3))))); 1917 responder->ExpectSentStanza( 1918 IqAck("A", kResponder, kInitiator)); 1919 EXPECT_EQ(0U, responder->sent_stanza_count()); 1920 1921 EXPECT_EQ(1U, responder->session_created_count); 1922 EXPECT_EQ(kSessionId, responder->session->id()); 1923 EXPECT_EQ(responder->session->local_name(), kResponder); 1924 EXPECT_EQ(responder->session->remote_name(), kInitiator); 1925 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, 1926 responder->session_state()); 1927 1928 EXPECT_TRUE(responder->HasTransport(content_name)); 1929 EXPECT_TRUE(responder->HasChannel(content_name, 1)); 1930 EXPECT_TRUE(responder->HasTransport(content_name)); 1931 EXPECT_TRUE(responder->HasChannel(content_name, 2)); 1932 1933 // Expect transport-info message from initiator. 1934 // But don't send candidates until initiate ack is received. 1935 initiator->DeliverAckToLastStanza(); 1936 initiator->PrepareCandidates(); 1937 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1938 initiator->ExpectSentStanza( 1939 IqSet("1", kInitiator, kResponder, 1940 TransportInfo4Xml(protocol, content_name, 1941 channel_name_a, 0, 1, 1942 channel_name_b, 2, 3))); 1943 1944 responder->PrepareCandidates(); 1945 EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); 1946 responder->ExpectSentStanza( 1947 IqSet("2", kResponder, kInitiator, 1948 TransportInfo4Xml(protocol, content_name, 1949 channel_name_a, 4, 5, 1950 channel_name_b, 6, 7))); 1951 1952 // Accept the session and expect accept stanza. 1953 cricket::SessionDescription* answer = NewTestSessionDescription( 1954 content_name, content_type); 1955 EXPECT_TRUE(responder->session->Accept(answer)); 1956 1957 responder->ExpectSentStanza( 1958 IqSet("3", kResponder, kInitiator, 1959 AcceptXml(protocol, content_name, content_type))); 1960 EXPECT_EQ(0U, responder->sent_stanza_count()); 1961 1962 // Fake the delivery the accept and candidates together. 1963 initiator->DeliverStanza( 1964 IqSet("B", kResponder, kInitiator, 1965 JingleActionXml("session-accept", 1966 JingleContentXml( 1967 content_name, content_type, kTransportType, 1968 P2pCandidateXml(channel_name_a, 4) + 1969 P2pCandidateXml(channel_name_a, 5) + 1970 P2pCandidateXml(channel_name_b, 6) + 1971 P2pCandidateXml(channel_name_b, 7))))); 1972 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); 1973 initiator->ExpectSentStanza( 1974 IqAck("B", kInitiator, kResponder)); 1975 EXPECT_EQ(0U, initiator->sent_stanza_count()); 1976 1977 // The channels should be able to become writable at this point. This 1978 // requires pinging, so it may take a little while. 1979 EXPECT_TRUE_WAIT(initiator->chan_a->writable() && 1980 initiator->chan_a->readable(), kEventTimeout); 1981 EXPECT_TRUE_WAIT(initiator->chan_b->writable() && 1982 initiator->chan_b->readable(), kEventTimeout); 1983 EXPECT_TRUE_WAIT(responder->chan_a->writable() && 1984 responder->chan_a->readable(), kEventTimeout); 1985 EXPECT_TRUE_WAIT(responder->chan_b->writable() && 1986 responder->chan_b->readable(), kEventTimeout); 1987 1988 1989 // Both sessions should be in progress and have functioning 1990 // channels. 1991 EXPECT_EQ(protocol, initiator->session->current_protocol()); 1992 EXPECT_EQ(protocol, responder->session->current_protocol()); 1993 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, 1994 initiator->session_state(), kEventTimeout); 1995 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, 1996 responder->session_state(), kEventTimeout); 1997 TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(), 1998 responder->chan_a.get(), responder->chan_b.get()); 1999 } 2000 2001 // Tests that when an initiator terminates right after initiate, 2002 // everything behaves correctly. 2003 void TestEarlyTerminationFromInitiator(SignalingProtocol protocol) { 2004 std::string content_name = "main"; 2005 std::string content_type = "http://oink.splat/session"; 2006 2007 talk_base::scoped_ptr<cricket::PortAllocator> allocator( 2008 new TestPortAllocator()); 2009 int next_message_id = 0; 2010 2011 talk_base::scoped_ptr<TestClient> initiator( 2012 new TestClient(allocator.get(), &next_message_id, 2013 kInitiator, protocol, 2014 content_type, 2015 content_name, "a", 2016 content_name, "b")); 2017 2018 talk_base::scoped_ptr<TestClient> responder( 2019 new TestClient(allocator.get(), &next_message_id, 2020 kResponder, protocol, 2021 content_type, 2022 content_name, "a", 2023 content_name, "b")); 2024 2025 // Send initiate 2026 initiator->CreateSession(); 2027 EXPECT_TRUE(initiator->session->Initiate( 2028 kResponder, NewTestSessionDescription(content_name, content_type))); 2029 initiator->ExpectSentStanza( 2030 IqSet("0", kInitiator, kResponder, 2031 InitiateXml(protocol, content_name, content_type))); 2032 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, 2033 initiator->session_state()); 2034 2035 responder->DeliverStanza(initiator->stanza()); 2036 responder->ExpectSentStanza( 2037 IqAck("0", kResponder, kInitiator)); 2038 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, 2039 responder->session_state()); 2040 2041 initiator->session->TerminateWithReason(cricket::STR_TERMINATE_ERROR); 2042 initiator->ExpectSentStanza( 2043 IqSet("1", kInitiator, kResponder, 2044 TerminateXml(protocol, cricket::STR_TERMINATE_ERROR))); 2045 EXPECT_EQ(cricket::BaseSession::STATE_SENTTERMINATE, 2046 initiator->session_state()); 2047 2048 responder->DeliverStanza(initiator->stanza()); 2049 responder->ExpectSentStanza( 2050 IqAck("1", kResponder, kInitiator)); 2051 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE, 2052 responder->session_state()); 2053 } 2054 2055 // Tests that when the responder rejects, everything behaves 2056 // correctly. 2057 void TestRejection(SignalingProtocol protocol) { 2058 std::string content_name = "main"; 2059 std::string content_type = "http://oink.splat/session"; 2060 2061 talk_base::scoped_ptr<cricket::PortAllocator> allocator( 2062 new TestPortAllocator()); 2063 int next_message_id = 0; 2064 2065 talk_base::scoped_ptr<TestClient> initiator( 2066 new TestClient(allocator.get(), &next_message_id, 2067 kInitiator, protocol, 2068 content_type, 2069 content_name, "a", 2070 content_name, "b")); 2071 2072 // Send initiate 2073 initiator->CreateSession(); 2074 EXPECT_TRUE(initiator->session->Initiate( 2075 kResponder, NewTestSessionDescription(content_name, content_type))); 2076 initiator->ExpectSentStanza( 2077 IqSet("0", kInitiator, kResponder, 2078 InitiateXml(protocol, content_name, content_type))); 2079 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, 2080 initiator->session_state()); 2081 2082 initiator->DeliverStanza( 2083 IqSet("1", kResponder, kInitiator, 2084 RejectXml(protocol, cricket::STR_TERMINATE_ERROR))); 2085 initiator->ExpectSentStanza( 2086 IqAck("1", kInitiator, kResponder)); 2087 if (protocol == PROTOCOL_JINGLE) { 2088 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE, 2089 initiator->session_state()); 2090 } else { 2091 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDREJECT, 2092 initiator->session_state()); 2093 } 2094 } 2095 2096 void TestTransportMux() { 2097 SignalingProtocol initiator_protocol = PROTOCOL_JINGLE; 2098 SignalingProtocol responder_protocol = PROTOCOL_JINGLE; 2099 SignalingProtocol resulting_protocol = PROTOCOL_JINGLE; 2100 std::string content_type = cricket::NS_JINGLE_RTP; 2101 std::string gingle_content_type = cricket::NS_GINGLE_VIDEO; 2102 std::string content_name_a = cricket::CN_AUDIO; 2103 std::string channel_name_a = "rtp"; 2104 std::string content_name_b = cricket::CN_VIDEO; 2105 std::string channel_name_b = "video_rtp"; 2106 2107 std::string initiate_xml = InitiateXml( 2108 initiator_protocol, 2109 gingle_content_type, 2110 content_name_a, content_type, 2111 content_name_b, content_type, true); 2112 std::string transport_info_a_xml = TransportInfo2Xml( 2113 initiator_protocol, content_name_a, 2114 channel_name_a, 0, 1); 2115 std::string transport_info_b_xml = TransportInfo2Xml( 2116 initiator_protocol, content_name_b, 2117 channel_name_b, 2, 3); 2118 std::string transport_info_reply_a_xml = TransportInfo2Xml( 2119 resulting_protocol, content_name_a, 2120 channel_name_a, 4, 5); 2121 std::string transport_info_reply_b_xml = TransportInfo2Xml( 2122 resulting_protocol, content_name_b, 2123 channel_name_b, 6, 7); 2124 std::string accept_xml = AcceptXml( 2125 resulting_protocol, 2126 gingle_content_type, 2127 content_name_a, content_type, 2128 content_name_b, content_type, true); 2129 2130 TestSession(initiator_protocol, responder_protocol, resulting_protocol, 2131 gingle_content_type, 2132 content_type, 2133 content_name_a, channel_name_a, 2134 content_name_b, channel_name_b, 2135 initiate_xml, 2136 transport_info_a_xml, transport_info_b_xml, 2137 transport_info_reply_a_xml, transport_info_reply_b_xml, 2138 accept_xml, 2139 true); 2140 } 2141 2142 void TestSendDescriptionInfo() { 2143 talk_base::scoped_ptr<cricket::PortAllocator> allocator( 2144 new TestPortAllocator()); 2145 int next_message_id = 0; 2146 2147 std::string content_name = "content-name"; 2148 std::string content_type = "content-type"; 2149 talk_base::scoped_ptr<TestClient> initiator( 2150 new TestClient(allocator.get(), &next_message_id, 2151 kInitiator, PROTOCOL_JINGLE, 2152 content_type, 2153 content_name, "", 2154 "", "")); 2155 2156 initiator->CreateSession(); 2157 cricket::SessionDescription* offer = NewTestSessionDescription( 2158 content_name, content_type); 2159 std::string initiate_xml = InitiateXml( 2160 PROTOCOL_JINGLE, content_name, content_type); 2161 2162 cricket::ContentInfos contents; 2163 TestContentDescription content(content_type, content_type); 2164 contents.push_back( 2165 cricket::ContentInfo(content_name, content_type, &content)); 2166 std::string description_info_xml = JingleDescriptionInfoXml( 2167 content_name, content_type); 2168 2169 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); 2170 initiator->ExpectSentStanza( 2171 IqSet("0", kInitiator, kResponder, initiate_xml)); 2172 2173 EXPECT_TRUE(initiator->session->SendDescriptionInfoMessage(contents)); 2174 initiator->ExpectSentStanza( 2175 IqSet("1", kInitiator, kResponder, description_info_xml)); 2176 } 2177 2178 void DoTestSignalNewDescription( 2179 TestClient* client, 2180 cricket::BaseSession::State state, 2181 cricket::ContentAction expected_content_action, 2182 cricket::ContentSource expected_content_source) { 2183 // Clean up before the new test. 2184 client->new_local_description = false; 2185 client->new_remote_description = false; 2186 2187 client->SetSessionState(state); 2188 EXPECT_EQ((expected_content_source == cricket::CS_LOCAL), 2189 client->new_local_description); 2190 EXPECT_EQ((expected_content_source == cricket::CS_REMOTE), 2191 client->new_remote_description); 2192 EXPECT_EQ(expected_content_action, client->last_content_action); 2193 EXPECT_EQ(expected_content_source, client->last_content_source); 2194 } 2195 2196 void TestCallerSignalNewDescription() { 2197 talk_base::scoped_ptr<cricket::PortAllocator> allocator( 2198 new TestPortAllocator()); 2199 int next_message_id = 0; 2200 2201 std::string content_name = "content-name"; 2202 std::string content_type = "content-type"; 2203 talk_base::scoped_ptr<TestClient> initiator( 2204 new TestClient(allocator.get(), &next_message_id, 2205 kInitiator, PROTOCOL_JINGLE, 2206 content_type, 2207 content_name, "", 2208 "", "")); 2209 2210 initiator->CreateSession(); 2211 2212 // send offer -> send update offer -> 2213 // receive pr answer -> receive update pr answer -> 2214 // receive answer 2215 DoTestSignalNewDescription( 2216 initiator.get(), cricket::BaseSession::STATE_SENTINITIATE, 2217 cricket::CA_OFFER, cricket::CS_LOCAL); 2218 2219 DoTestSignalNewDescription( 2220 initiator.get(), cricket::BaseSession::STATE_SENTINITIATE, 2221 cricket::CA_OFFER, cricket::CS_LOCAL); 2222 2223 DoTestSignalNewDescription( 2224 initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT, 2225 cricket::CA_PRANSWER, cricket::CS_REMOTE); 2226 2227 DoTestSignalNewDescription( 2228 initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT, 2229 cricket::CA_PRANSWER, cricket::CS_REMOTE); 2230 2231 DoTestSignalNewDescription( 2232 initiator.get(), cricket::BaseSession::STATE_RECEIVEDACCEPT, 2233 cricket::CA_ANSWER, cricket::CS_REMOTE); 2234 } 2235 2236 void TestCalleeSignalNewDescription() { 2237 talk_base::scoped_ptr<cricket::PortAllocator> allocator( 2238 new TestPortAllocator()); 2239 int next_message_id = 0; 2240 2241 std::string content_name = "content-name"; 2242 std::string content_type = "content-type"; 2243 talk_base::scoped_ptr<TestClient> initiator( 2244 new TestClient(allocator.get(), &next_message_id, 2245 kInitiator, PROTOCOL_JINGLE, 2246 content_type, 2247 content_name, "", 2248 "", "")); 2249 2250 initiator->CreateSession(); 2251 2252 // receive offer -> receive update offer -> 2253 // send pr answer -> send update pr answer -> 2254 // send answer 2255 DoTestSignalNewDescription( 2256 initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE, 2257 cricket::CA_OFFER, cricket::CS_REMOTE); 2258 2259 DoTestSignalNewDescription( 2260 initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE, 2261 cricket::CA_OFFER, cricket::CS_REMOTE); 2262 2263 DoTestSignalNewDescription( 2264 initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT, 2265 cricket::CA_PRANSWER, cricket::CS_LOCAL); 2266 2267 DoTestSignalNewDescription( 2268 initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT, 2269 cricket::CA_PRANSWER, cricket::CS_LOCAL); 2270 2271 DoTestSignalNewDescription( 2272 initiator.get(), cricket::BaseSession::STATE_SENTACCEPT, 2273 cricket::CA_ANSWER, cricket::CS_LOCAL); 2274 } 2275 2276 void TestGetTransportStats() { 2277 talk_base::scoped_ptr<cricket::PortAllocator> allocator( 2278 new TestPortAllocator()); 2279 int next_message_id = 0; 2280 2281 std::string content_name = "content-name"; 2282 std::string content_type = "content-type"; 2283 talk_base::scoped_ptr<TestClient> initiator( 2284 new TestClient(allocator.get(), &next_message_id, 2285 kInitiator, PROTOCOL_JINGLE, 2286 content_type, 2287 content_name, "", 2288 "", "")); 2289 initiator->CreateSession(); 2290 2291 cricket::SessionStats stats; 2292 EXPECT_TRUE(initiator->session->GetStats(&stats)); 2293 // At initiation, there are 2 transports. 2294 EXPECT_EQ(2ul, stats.proxy_to_transport.size()); 2295 EXPECT_EQ(2ul, stats.transport_stats.size()); 2296 } 2297 }; 2298 2299 // For each of these, "X => Y = Z" means "if a client with protocol X 2300 // initiates to a client with protocol Y, they end up speaking protocol Z. 2301 2302 // Gingle => Gingle = Gingle (with other content) 2303 TEST_F(SessionTest, GingleToGingleOtherContent) { 2304 TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE); 2305 } 2306 2307 // Gingle => Gingle = Gingle (with audio content) 2308 TEST_F(SessionTest, GingleToGingleAudioContent) { 2309 TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE); 2310 } 2311 2312 // Gingle => Gingle = Gingle (with video contents) 2313 TEST_F(SessionTest, GingleToGingleVideoContents) { 2314 TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE); 2315 } 2316 2317 // Jingle => Jingle = Jingle (with other content) 2318 TEST_F(SessionTest, JingleToJingleOtherContent) { 2319 TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE); 2320 } 2321 2322 // Jingle => Jingle = Jingle (with audio content) 2323 TEST_F(SessionTest, JingleToJingleAudioContent) { 2324 TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE); 2325 } 2326 2327 // Jingle => Jingle = Jingle (with video contents) 2328 TEST_F(SessionTest, JingleToJingleVideoContents) { 2329 TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE); 2330 } 2331 2332 // Hybrid => Hybrid = Jingle (with other content) 2333 TEST_F(SessionTest, HybridToHybridOtherContent) { 2334 TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE); 2335 } 2336 2337 // Hybrid => Hybrid = Jingle (with audio content) 2338 TEST_F(SessionTest, HybridToHybridAudioContent) { 2339 TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE); 2340 } 2341 2342 // Hybrid => Hybrid = Jingle (with video contents) 2343 TEST_F(SessionTest, HybridToHybridVideoContents) { 2344 TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE); 2345 } 2346 2347 // Gingle => Hybrid = Gingle (with other content) 2348 TEST_F(SessionTest, GingleToHybridOtherContent) { 2349 TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE); 2350 } 2351 2352 // Gingle => Hybrid = Gingle (with audio content) 2353 TEST_F(SessionTest, GingleToHybridAudioContent) { 2354 TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE); 2355 } 2356 2357 // Gingle => Hybrid = Gingle (with video contents) 2358 TEST_F(SessionTest, GingleToHybridVideoContents) { 2359 TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE); 2360 } 2361 2362 // Jingle => Hybrid = Jingle (with other content) 2363 TEST_F(SessionTest, JingleToHybridOtherContent) { 2364 TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE); 2365 } 2366 2367 // Jingle => Hybrid = Jingle (with audio content) 2368 TEST_F(SessionTest, JingleToHybridAudioContent) { 2369 TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE); 2370 } 2371 2372 // Jingle => Hybrid = Jingle (with video contents) 2373 TEST_F(SessionTest, JingleToHybridVideoContents) { 2374 TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE); 2375 } 2376 2377 // Hybrid => Gingle = Gingle (with other content) 2378 TEST_F(SessionTest, HybridToGingleOtherContent) { 2379 TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE); 2380 } 2381 2382 // Hybrid => Gingle = Gingle (with audio content) 2383 TEST_F(SessionTest, HybridToGingleAudioContent) { 2384 TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE); 2385 } 2386 2387 // Hybrid => Gingle = Gingle (with video contents) 2388 TEST_F(SessionTest, HybridToGingleVideoContents) { 2389 TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE); 2390 } 2391 2392 // Hybrid => Jingle = Jingle (with other content) 2393 TEST_F(SessionTest, HybridToJingleOtherContent) { 2394 TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE); 2395 } 2396 2397 // Hybrid => Jingle = Jingle (with audio content) 2398 TEST_F(SessionTest, HybridToJingleAudioContent) { 2399 TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE); 2400 } 2401 2402 // Hybrid => Jingle = Jingle (with video contents) 2403 TEST_F(SessionTest, HybridToJingleVideoContents) { 2404 TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE); 2405 } 2406 2407 TEST_F(SessionTest, GingleEarlyTerminationFromInitiator) { 2408 TestEarlyTerminationFromInitiator(PROTOCOL_GINGLE); 2409 } 2410 2411 TEST_F(SessionTest, JingleEarlyTerminationFromInitiator) { 2412 TestEarlyTerminationFromInitiator(PROTOCOL_JINGLE); 2413 } 2414 2415 TEST_F(SessionTest, HybridEarlyTerminationFromInitiator) { 2416 TestEarlyTerminationFromInitiator(PROTOCOL_HYBRID); 2417 } 2418 2419 TEST_F(SessionTest, GingleRejection) { 2420 TestRejection(PROTOCOL_GINGLE); 2421 } 2422 2423 TEST_F(SessionTest, JingleRejection) { 2424 TestRejection(PROTOCOL_JINGLE); 2425 } 2426 2427 TEST_F(SessionTest, GingleGoodRedirect) { 2428 TestGoodRedirect(PROTOCOL_GINGLE); 2429 } 2430 2431 TEST_F(SessionTest, JingleGoodRedirect) { 2432 TestGoodRedirect(PROTOCOL_JINGLE); 2433 } 2434 2435 TEST_F(SessionTest, GingleBadRedirect) { 2436 TestBadRedirect(PROTOCOL_GINGLE); 2437 } 2438 2439 TEST_F(SessionTest, JingleBadRedirect) { 2440 TestBadRedirect(PROTOCOL_JINGLE); 2441 } 2442 2443 TEST_F(SessionTest, TestCandidatesInInitiateAndAccept) { 2444 TestCandidatesInInitiateAndAccept("Candidates in initiate/accept"); 2445 } 2446 2447 TEST_F(SessionTest, TestTransportMux) { 2448 TestTransportMux(); 2449 } 2450 2451 TEST_F(SessionTest, TestSendDescriptionInfo) { 2452 TestSendDescriptionInfo(); 2453 } 2454 2455 TEST_F(SessionTest, TestCallerSignalNewDescription) { 2456 TestCallerSignalNewDescription(); 2457 } 2458 2459 TEST_F(SessionTest, TestCalleeSignalNewDescription) { 2460 TestCalleeSignalNewDescription(); 2461 } 2462 2463 TEST_F(SessionTest, TestGetTransportStats) { 2464 TestGetTransportStats(); 2465 } 2466