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