1 /* 2 * libjingle 3 * Copyright 2010, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "talk/p2p/base/sessionmessages.h" 29 30 #include <stdio.h> 31 #include <string> 32 33 #include "talk/p2p/base/constants.h" 34 #include "talk/p2p/base/p2ptransport.h" 35 #include "talk/p2p/base/parsing.h" 36 #include "talk/p2p/base/sessionclient.h" 37 #include "talk/p2p/base/sessiondescription.h" 38 #include "talk/p2p/base/transport.h" 39 #include "webrtc/libjingle/xmllite/xmlconstants.h" 40 #include "talk/xmpp/constants.h" 41 #include "webrtc/base/logging.h" 42 #include "webrtc/base/scoped_ptr.h" 43 #include "webrtc/base/stringutils.h" 44 45 namespace cricket { 46 47 ActionType ToActionType(const std::string& type) { 48 if (type == GINGLE_ACTION_INITIATE) 49 return ACTION_SESSION_INITIATE; 50 if (type == GINGLE_ACTION_INFO) 51 return ACTION_SESSION_INFO; 52 if (type == GINGLE_ACTION_ACCEPT) 53 return ACTION_SESSION_ACCEPT; 54 if (type == GINGLE_ACTION_REJECT) 55 return ACTION_SESSION_REJECT; 56 if (type == GINGLE_ACTION_TERMINATE) 57 return ACTION_SESSION_TERMINATE; 58 if (type == GINGLE_ACTION_CANDIDATES) 59 return ACTION_TRANSPORT_INFO; 60 if (type == JINGLE_ACTION_SESSION_INITIATE) 61 return ACTION_SESSION_INITIATE; 62 if (type == JINGLE_ACTION_TRANSPORT_INFO) 63 return ACTION_TRANSPORT_INFO; 64 if (type == JINGLE_ACTION_TRANSPORT_ACCEPT) 65 return ACTION_TRANSPORT_ACCEPT; 66 if (type == JINGLE_ACTION_SESSION_INFO) 67 return ACTION_SESSION_INFO; 68 if (type == JINGLE_ACTION_SESSION_ACCEPT) 69 return ACTION_SESSION_ACCEPT; 70 if (type == JINGLE_ACTION_SESSION_TERMINATE) 71 return ACTION_SESSION_TERMINATE; 72 if (type == JINGLE_ACTION_TRANSPORT_INFO) 73 return ACTION_TRANSPORT_INFO; 74 if (type == JINGLE_ACTION_TRANSPORT_ACCEPT) 75 return ACTION_TRANSPORT_ACCEPT; 76 if (type == JINGLE_ACTION_DESCRIPTION_INFO) 77 return ACTION_DESCRIPTION_INFO; 78 if (type == GINGLE_ACTION_UPDATE) 79 return ACTION_DESCRIPTION_INFO; 80 81 return ACTION_UNKNOWN; 82 } 83 84 std::string ToJingleString(ActionType type) { 85 switch (type) { 86 case ACTION_SESSION_INITIATE: 87 return JINGLE_ACTION_SESSION_INITIATE; 88 case ACTION_SESSION_INFO: 89 return JINGLE_ACTION_SESSION_INFO; 90 case ACTION_DESCRIPTION_INFO: 91 return JINGLE_ACTION_DESCRIPTION_INFO; 92 case ACTION_SESSION_ACCEPT: 93 return JINGLE_ACTION_SESSION_ACCEPT; 94 // Notice that reject and terminate both go to 95 // "session-terminate", but there is no "session-reject". 96 case ACTION_SESSION_REJECT: 97 case ACTION_SESSION_TERMINATE: 98 return JINGLE_ACTION_SESSION_TERMINATE; 99 case ACTION_TRANSPORT_INFO: 100 return JINGLE_ACTION_TRANSPORT_INFO; 101 case ACTION_TRANSPORT_ACCEPT: 102 return JINGLE_ACTION_TRANSPORT_ACCEPT; 103 default: 104 return ""; 105 } 106 } 107 108 std::string ToGingleString(ActionType type) { 109 switch (type) { 110 case ACTION_SESSION_INITIATE: 111 return GINGLE_ACTION_INITIATE; 112 case ACTION_SESSION_INFO: 113 return GINGLE_ACTION_INFO; 114 case ACTION_SESSION_ACCEPT: 115 return GINGLE_ACTION_ACCEPT; 116 case ACTION_SESSION_REJECT: 117 return GINGLE_ACTION_REJECT; 118 case ACTION_SESSION_TERMINATE: 119 return GINGLE_ACTION_TERMINATE; 120 case ACTION_TRANSPORT_INFO: 121 return GINGLE_ACTION_CANDIDATES; 122 default: 123 return ""; 124 } 125 } 126 127 128 bool IsJingleMessage(const buzz::XmlElement* stanza) { 129 const buzz::XmlElement* jingle = stanza->FirstNamed(QN_JINGLE); 130 if (jingle == NULL) 131 return false; 132 133 return (jingle->HasAttr(buzz::QN_ACTION) && jingle->HasAttr(QN_SID)); 134 } 135 136 bool IsGingleMessage(const buzz::XmlElement* stanza) { 137 const buzz::XmlElement* session = stanza->FirstNamed(QN_GINGLE_SESSION); 138 if (session == NULL) 139 return false; 140 141 return (session->HasAttr(buzz::QN_TYPE) && 142 session->HasAttr(buzz::QN_ID) && 143 session->HasAttr(QN_INITIATOR)); 144 } 145 146 bool IsSessionMessage(const buzz::XmlElement* stanza) { 147 return (stanza->Name() == buzz::QN_IQ && 148 stanza->Attr(buzz::QN_TYPE) == buzz::STR_SET && 149 (IsJingleMessage(stanza) || 150 IsGingleMessage(stanza))); 151 } 152 153 bool ParseGingleSessionMessage(const buzz::XmlElement* session, 154 SessionMessage* msg, 155 ParseError* error) { 156 msg->protocol = PROTOCOL_GINGLE; 157 std::string type_string = session->Attr(buzz::QN_TYPE); 158 msg->type = ToActionType(type_string); 159 msg->sid = session->Attr(buzz::QN_ID); 160 msg->initiator = session->Attr(QN_INITIATOR); 161 msg->action_elem = session; 162 163 if (msg->type == ACTION_UNKNOWN) 164 return BadParse("unknown action: " + type_string, error); 165 166 return true; 167 } 168 169 bool ParseJingleSessionMessage(const buzz::XmlElement* jingle, 170 SessionMessage* msg, 171 ParseError* error) { 172 msg->protocol = PROTOCOL_JINGLE; 173 std::string type_string = jingle->Attr(buzz::QN_ACTION); 174 msg->type = ToActionType(type_string); 175 msg->sid = jingle->Attr(QN_SID); 176 msg->initiator = GetXmlAttr(jingle, QN_INITIATOR, buzz::STR_EMPTY); 177 msg->action_elem = jingle; 178 179 if (msg->type == ACTION_UNKNOWN) 180 return BadParse("unknown action: " + type_string, error); 181 182 return true; 183 } 184 185 bool ParseHybridSessionMessage(const buzz::XmlElement* jingle, 186 SessionMessage* msg, 187 ParseError* error) { 188 if (!ParseJingleSessionMessage(jingle, msg, error)) 189 return false; 190 msg->protocol = PROTOCOL_HYBRID; 191 192 return true; 193 } 194 195 bool ParseSessionMessage(const buzz::XmlElement* stanza, 196 SessionMessage* msg, 197 ParseError* error) { 198 msg->id = stanza->Attr(buzz::QN_ID); 199 msg->from = stanza->Attr(buzz::QN_FROM); 200 msg->to = stanza->Attr(buzz::QN_TO); 201 msg->stanza = stanza; 202 203 const buzz::XmlElement* jingle = stanza->FirstNamed(QN_JINGLE); 204 const buzz::XmlElement* session = stanza->FirstNamed(QN_GINGLE_SESSION); 205 if (jingle && session) 206 return ParseHybridSessionMessage(jingle, msg, error); 207 if (jingle != NULL) 208 return ParseJingleSessionMessage(jingle, msg, error); 209 if (session != NULL) 210 return ParseGingleSessionMessage(session, msg, error); 211 return false; 212 } 213 214 buzz::XmlElement* WriteGingleAction(const SessionMessage& msg, 215 const XmlElements& action_elems) { 216 buzz::XmlElement* session = new buzz::XmlElement(QN_GINGLE_SESSION, true); 217 session->AddAttr(buzz::QN_TYPE, ToGingleString(msg.type)); 218 session->AddAttr(buzz::QN_ID, msg.sid); 219 session->AddAttr(QN_INITIATOR, msg.initiator); 220 AddXmlChildren(session, action_elems); 221 return session; 222 } 223 224 buzz::XmlElement* WriteJingleAction(const SessionMessage& msg, 225 const XmlElements& action_elems) { 226 buzz::XmlElement* jingle = new buzz::XmlElement(QN_JINGLE, true); 227 jingle->AddAttr(buzz::QN_ACTION, ToJingleString(msg.type)); 228 jingle->AddAttr(QN_SID, msg.sid); 229 if (msg.type == ACTION_SESSION_INITIATE) { 230 jingle->AddAttr(QN_INITIATOR, msg.initiator); 231 } 232 AddXmlChildren(jingle, action_elems); 233 return jingle; 234 } 235 236 void WriteSessionMessage(const SessionMessage& msg, 237 const XmlElements& action_elems, 238 buzz::XmlElement* stanza) { 239 stanza->SetAttr(buzz::QN_TO, msg.to); 240 stanza->SetAttr(buzz::QN_TYPE, buzz::STR_SET); 241 242 if (msg.protocol == PROTOCOL_GINGLE) { 243 stanza->AddElement(WriteGingleAction(msg, action_elems)); 244 } else { 245 stanza->AddElement(WriteJingleAction(msg, action_elems)); 246 } 247 } 248 249 250 TransportParser* GetTransportParser(const TransportParserMap& trans_parsers, 251 const std::string& transport_type) { 252 TransportParserMap::const_iterator map = trans_parsers.find(transport_type); 253 if (map == trans_parsers.end()) { 254 return NULL; 255 } else { 256 return map->second; 257 } 258 } 259 260 CandidateTranslator* GetCandidateTranslator( 261 const CandidateTranslatorMap& translators, 262 const std::string& content_name) { 263 CandidateTranslatorMap::const_iterator map = translators.find(content_name); 264 if (map == translators.end()) { 265 return NULL; 266 } else { 267 return map->second; 268 } 269 } 270 271 bool GetParserAndTranslator(const TransportParserMap& trans_parsers, 272 const CandidateTranslatorMap& translators, 273 const std::string& transport_type, 274 const std::string& content_name, 275 TransportParser** parser, 276 CandidateTranslator** translator, 277 ParseError* error) { 278 *parser = GetTransportParser(trans_parsers, transport_type); 279 if (*parser == NULL) { 280 return BadParse("unknown transport type: " + transport_type, error); 281 } 282 // Not having a translator isn't fatal when parsing. If this is called for an 283 // initiate message, we won't have our proxies set up to do the translation. 284 // Fortunately, for the cases where translation is needed, candidates are 285 // never sent in initiates. 286 *translator = GetCandidateTranslator(translators, content_name); 287 return true; 288 } 289 290 bool GetParserAndTranslator(const TransportParserMap& trans_parsers, 291 const CandidateTranslatorMap& translators, 292 const std::string& transport_type, 293 const std::string& content_name, 294 TransportParser** parser, 295 CandidateTranslator** translator, 296 WriteError* error) { 297 *parser = GetTransportParser(trans_parsers, transport_type); 298 if (*parser == NULL) { 299 return BadWrite("unknown transport type: " + transport_type, error); 300 } 301 *translator = GetCandidateTranslator(translators, content_name); 302 if (*translator == NULL) { 303 return BadWrite("unknown content name: " + content_name, error); 304 } 305 return true; 306 } 307 308 bool ParseGingleCandidate(const buzz::XmlElement* candidate_elem, 309 const TransportParserMap& trans_parsers, 310 const CandidateTranslatorMap& translators, 311 const std::string& content_name, 312 Candidates* candidates, 313 ParseError* error) { 314 TransportParser* trans_parser; 315 CandidateTranslator* translator; 316 if (!GetParserAndTranslator(trans_parsers, translators, 317 NS_GINGLE_P2P, content_name, 318 &trans_parser, &translator, error)) 319 return false; 320 321 Candidate candidate; 322 if (!trans_parser->ParseGingleCandidate( 323 candidate_elem, translator, &candidate, error)) { 324 return false; 325 } 326 327 candidates->push_back(candidate); 328 return true; 329 } 330 331 bool ParseGingleCandidates(const buzz::XmlElement* parent, 332 const TransportParserMap& trans_parsers, 333 const CandidateTranslatorMap& translators, 334 const std::string& content_name, 335 Candidates* candidates, 336 ParseError* error) { 337 for (const buzz::XmlElement* candidate_elem = parent->FirstElement(); 338 candidate_elem != NULL; 339 candidate_elem = candidate_elem->NextElement()) { 340 if (candidate_elem->Name().LocalPart() == LN_CANDIDATE) { 341 if (!ParseGingleCandidate(candidate_elem, trans_parsers, translators, 342 content_name, candidates, error)) { 343 return false; 344 } 345 } 346 } 347 return true; 348 } 349 350 bool ParseGingleTransportInfos(const buzz::XmlElement* action_elem, 351 const ContentInfos& contents, 352 const TransportParserMap& trans_parsers, 353 const CandidateTranslatorMap& translators, 354 TransportInfos* tinfos, 355 ParseError* error) { 356 bool has_audio = FindContentInfoByName(contents, CN_AUDIO) != NULL; 357 bool has_video = FindContentInfoByName(contents, CN_VIDEO) != NULL; 358 359 // If we don't have media, no need to separate the candidates. 360 if (!has_audio && !has_video) { 361 TransportInfo tinfo(CN_OTHER, 362 TransportDescription(NS_GINGLE_P2P, std::string(), std::string())); 363 if (!ParseGingleCandidates(action_elem, trans_parsers, translators, 364 CN_OTHER, &tinfo.description.candidates, 365 error)) { 366 return false; 367 } 368 369 tinfos->push_back(tinfo); 370 return true; 371 } 372 373 // If we have media, separate the candidates. 374 TransportInfo audio_tinfo( 375 CN_AUDIO, 376 TransportDescription(NS_GINGLE_P2P, std::string(), std::string())); 377 TransportInfo video_tinfo( 378 CN_VIDEO, 379 TransportDescription(NS_GINGLE_P2P, std::string(), std::string())); 380 for (const buzz::XmlElement* candidate_elem = action_elem->FirstElement(); 381 candidate_elem != NULL; 382 candidate_elem = candidate_elem->NextElement()) { 383 if (candidate_elem->Name().LocalPart() == LN_CANDIDATE) { 384 const std::string& channel_name = candidate_elem->Attr(buzz::QN_NAME); 385 if (has_audio && 386 (channel_name == GICE_CHANNEL_NAME_RTP || 387 channel_name == GICE_CHANNEL_NAME_RTCP)) { 388 if (!ParseGingleCandidate( 389 candidate_elem, trans_parsers, 390 translators, CN_AUDIO, 391 &audio_tinfo.description.candidates, error)) { 392 return false; 393 } 394 } else if (has_video && 395 (channel_name == GICE_CHANNEL_NAME_VIDEO_RTP || 396 channel_name == GICE_CHANNEL_NAME_VIDEO_RTCP)) { 397 if (!ParseGingleCandidate( 398 candidate_elem, trans_parsers, 399 translators, CN_VIDEO, 400 &video_tinfo.description.candidates, error)) { 401 return false; 402 } 403 } else { 404 return BadParse("Unknown channel name: " + channel_name, error); 405 } 406 } 407 } 408 409 if (has_audio) { 410 tinfos->push_back(audio_tinfo); 411 } 412 if (has_video) { 413 tinfos->push_back(video_tinfo); 414 } 415 return true; 416 } 417 418 bool ParseJingleTransportInfo(const buzz::XmlElement* trans_elem, 419 const std::string& content_name, 420 const TransportParserMap& trans_parsers, 421 const CandidateTranslatorMap& translators, 422 TransportInfo* tinfo, 423 ParseError* error) { 424 TransportParser* trans_parser; 425 CandidateTranslator* translator; 426 if (!GetParserAndTranslator(trans_parsers, translators, 427 trans_elem->Name().Namespace(), content_name, 428 &trans_parser, &translator, error)) 429 return false; 430 431 TransportDescription tdesc; 432 if (!trans_parser->ParseTransportDescription(trans_elem, translator, 433 &tdesc, error)) 434 return false; 435 436 *tinfo = TransportInfo(content_name, tdesc); 437 return true; 438 } 439 440 bool ParseJingleTransportInfos(const buzz::XmlElement* jingle, 441 const ContentInfos& contents, 442 const TransportParserMap trans_parsers, 443 const CandidateTranslatorMap& translators, 444 TransportInfos* tinfos, 445 ParseError* error) { 446 for (const buzz::XmlElement* pair_elem 447 = jingle->FirstNamed(QN_JINGLE_CONTENT); 448 pair_elem != NULL; 449 pair_elem = pair_elem->NextNamed(QN_JINGLE_CONTENT)) { 450 std::string content_name; 451 if (!RequireXmlAttr(pair_elem, QN_JINGLE_CONTENT_NAME, 452 &content_name, error)) 453 return false; 454 455 const ContentInfo* content = FindContentInfoByName(contents, content_name); 456 if (!content) 457 return BadParse("Unknown content name: " + content_name, error); 458 459 const buzz::XmlElement* trans_elem; 460 if (!RequireXmlChild(pair_elem, LN_TRANSPORT, &trans_elem, error)) 461 return false; 462 463 TransportInfo tinfo; 464 if (!ParseJingleTransportInfo(trans_elem, content->name, 465 trans_parsers, translators, 466 &tinfo, error)) 467 return false; 468 469 tinfos->push_back(tinfo); 470 } 471 472 return true; 473 } 474 475 buzz::XmlElement* NewTransportElement(const std::string& name) { 476 return new buzz::XmlElement(buzz::QName(name, LN_TRANSPORT), true); 477 } 478 479 bool WriteGingleCandidates(const Candidates& candidates, 480 const TransportParserMap& trans_parsers, 481 const std::string& transport_type, 482 const CandidateTranslatorMap& translators, 483 const std::string& content_name, 484 XmlElements* elems, 485 WriteError* error) { 486 TransportParser* trans_parser; 487 CandidateTranslator* translator; 488 if (!GetParserAndTranslator(trans_parsers, translators, 489 transport_type, content_name, 490 &trans_parser, &translator, error)) 491 return false; 492 493 for (size_t i = 0; i < candidates.size(); ++i) { 494 rtc::scoped_ptr<buzz::XmlElement> element; 495 if (!trans_parser->WriteGingleCandidate(candidates[i], translator, 496 element.accept(), error)) { 497 return false; 498 } 499 500 elems->push_back(element.release()); 501 } 502 503 return true; 504 } 505 506 bool WriteGingleTransportInfos(const TransportInfos& tinfos, 507 const TransportParserMap& trans_parsers, 508 const CandidateTranslatorMap& translators, 509 XmlElements* elems, 510 WriteError* error) { 511 for (TransportInfos::const_iterator tinfo = tinfos.begin(); 512 tinfo != tinfos.end(); ++tinfo) { 513 if (!WriteGingleCandidates(tinfo->description.candidates, 514 trans_parsers, tinfo->description.transport_type, 515 translators, tinfo->content_name, 516 elems, error)) 517 return false; 518 } 519 520 return true; 521 } 522 523 bool WriteJingleTransportInfo(const TransportInfo& tinfo, 524 const TransportParserMap& trans_parsers, 525 const CandidateTranslatorMap& translators, 526 XmlElements* elems, 527 WriteError* error) { 528 std::string transport_type = tinfo.description.transport_type; 529 TransportParser* trans_parser; 530 CandidateTranslator* translator; 531 if (!GetParserAndTranslator(trans_parsers, translators, 532 transport_type, tinfo.content_name, 533 &trans_parser, &translator, error)) 534 return false; 535 536 buzz::XmlElement* trans_elem; 537 if (!trans_parser->WriteTransportDescription(tinfo.description, translator, 538 &trans_elem, error)) { 539 return false; 540 } 541 542 elems->push_back(trans_elem); 543 return true; 544 } 545 546 void WriteJingleContent(const std::string name, 547 const XmlElements& child_elems, 548 XmlElements* elems) { 549 buzz::XmlElement* content_elem = new buzz::XmlElement(QN_JINGLE_CONTENT); 550 content_elem->SetAttr(QN_JINGLE_CONTENT_NAME, name); 551 content_elem->SetAttr(QN_CREATOR, LN_INITIATOR); 552 AddXmlChildren(content_elem, child_elems); 553 554 elems->push_back(content_elem); 555 } 556 557 bool WriteJingleTransportInfos(const TransportInfos& tinfos, 558 const TransportParserMap& trans_parsers, 559 const CandidateTranslatorMap& translators, 560 XmlElements* elems, 561 WriteError* error) { 562 for (TransportInfos::const_iterator tinfo = tinfos.begin(); 563 tinfo != tinfos.end(); ++tinfo) { 564 XmlElements content_child_elems; 565 if (!WriteJingleTransportInfo(*tinfo, trans_parsers, translators, 566 &content_child_elems, error)) 567 568 return false; 569 570 WriteJingleContent(tinfo->content_name, content_child_elems, elems); 571 } 572 573 return true; 574 } 575 576 ContentParser* GetContentParser(const ContentParserMap& content_parsers, 577 const std::string& type) { 578 ContentParserMap::const_iterator map = content_parsers.find(type); 579 if (map == content_parsers.end()) { 580 return NULL; 581 } else { 582 return map->second; 583 } 584 } 585 586 bool ParseContentInfo(SignalingProtocol protocol, 587 const std::string& name, 588 const std::string& type, 589 const buzz::XmlElement* elem, 590 const ContentParserMap& parsers, 591 ContentInfos* contents, 592 ParseError* error) { 593 ContentParser* parser = GetContentParser(parsers, type); 594 if (parser == NULL) 595 return BadParse("unknown application content: " + type, error); 596 597 ContentDescription* desc; 598 if (!parser->ParseContent(protocol, elem, &desc, error)) 599 return false; 600 601 contents->push_back(ContentInfo(name, type, desc)); 602 return true; 603 } 604 605 bool ParseContentType(const buzz::XmlElement* parent_elem, 606 std::string* content_type, 607 const buzz::XmlElement** content_elem, 608 ParseError* error) { 609 if (!RequireXmlChild(parent_elem, LN_DESCRIPTION, content_elem, error)) 610 return false; 611 612 *content_type = (*content_elem)->Name().Namespace(); 613 return true; 614 } 615 616 bool ParseGingleContentInfos(const buzz::XmlElement* session, 617 const ContentParserMap& content_parsers, 618 ContentInfos* contents, 619 ParseError* error) { 620 std::string content_type; 621 const buzz::XmlElement* content_elem; 622 if (!ParseContentType(session, &content_type, &content_elem, error)) 623 return false; 624 625 if (content_type == NS_GINGLE_VIDEO) { 626 // A parser parsing audio or video content should look at the 627 // namespace and only parse the codecs relevant to that namespace. 628 // We use this to control which codecs get parsed: first audio, 629 // then video. 630 rtc::scoped_ptr<buzz::XmlElement> audio_elem( 631 new buzz::XmlElement(QN_GINGLE_AUDIO_CONTENT)); 632 CopyXmlChildren(content_elem, audio_elem.get()); 633 if (!ParseContentInfo(PROTOCOL_GINGLE, CN_AUDIO, NS_JINGLE_RTP, 634 audio_elem.get(), content_parsers, 635 contents, error)) 636 return false; 637 638 if (!ParseContentInfo(PROTOCOL_GINGLE, CN_VIDEO, NS_JINGLE_RTP, 639 content_elem, content_parsers, 640 contents, error)) 641 return false; 642 } else if (content_type == NS_GINGLE_AUDIO) { 643 if (!ParseContentInfo(PROTOCOL_GINGLE, CN_AUDIO, NS_JINGLE_RTP, 644 content_elem, content_parsers, 645 contents, error)) 646 return false; 647 } else { 648 if (!ParseContentInfo(PROTOCOL_GINGLE, CN_OTHER, content_type, 649 content_elem, content_parsers, 650 contents, error)) 651 return false; 652 } 653 return true; 654 } 655 656 bool ParseJingleContentInfos(const buzz::XmlElement* jingle, 657 const ContentParserMap& content_parsers, 658 ContentInfos* contents, 659 ParseError* error) { 660 for (const buzz::XmlElement* pair_elem 661 = jingle->FirstNamed(QN_JINGLE_CONTENT); 662 pair_elem != NULL; 663 pair_elem = pair_elem->NextNamed(QN_JINGLE_CONTENT)) { 664 std::string content_name; 665 if (!RequireXmlAttr(pair_elem, QN_JINGLE_CONTENT_NAME, 666 &content_name, error)) 667 return false; 668 669 std::string content_type; 670 const buzz::XmlElement* content_elem; 671 if (!ParseContentType(pair_elem, &content_type, &content_elem, error)) 672 return false; 673 674 if (!ParseContentInfo(PROTOCOL_JINGLE, content_name, content_type, 675 content_elem, content_parsers, 676 contents, error)) 677 return false; 678 } 679 return true; 680 } 681 682 bool ParseJingleGroupInfos(const buzz::XmlElement* jingle, 683 ContentGroups* groups, 684 ParseError* error) { 685 for (const buzz::XmlElement* pair_elem 686 = jingle->FirstNamed(QN_JINGLE_DRAFT_GROUP); 687 pair_elem != NULL; 688 pair_elem = pair_elem->NextNamed(QN_JINGLE_DRAFT_GROUP)) { 689 std::string group_name; 690 if (!RequireXmlAttr(pair_elem, QN_JINGLE_DRAFT_GROUP_TYPE, 691 &group_name, error)) 692 return false; 693 694 ContentGroup group(group_name); 695 for (const buzz::XmlElement* child_elem 696 = pair_elem->FirstNamed(QN_JINGLE_CONTENT); 697 child_elem != NULL; 698 child_elem = child_elem->NextNamed(QN_JINGLE_CONTENT)) { 699 std::string content_name; 700 if (!RequireXmlAttr(child_elem, QN_JINGLE_CONTENT_NAME, 701 &content_name, error)) 702 return false; 703 group.AddContentName(content_name); 704 } 705 groups->push_back(group); 706 } 707 return true; 708 } 709 710 buzz::XmlElement* WriteContentInfo(SignalingProtocol protocol, 711 const ContentInfo& content, 712 const ContentParserMap& parsers, 713 WriteError* error) { 714 ContentParser* parser = GetContentParser(parsers, content.type); 715 if (parser == NULL) { 716 BadWrite("unknown content type: " + content.type, error); 717 return NULL; 718 } 719 720 buzz::XmlElement* elem = NULL; 721 if (!parser->WriteContent(protocol, content.description, &elem, error)) 722 return NULL; 723 724 return elem; 725 } 726 727 bool IsWritable(SignalingProtocol protocol, 728 const ContentInfo& content, 729 const ContentParserMap& parsers) { 730 ContentParser* parser = GetContentParser(parsers, content.type); 731 if (parser == NULL) { 732 return false; 733 } 734 735 return parser->IsWritable(protocol, content.description); 736 } 737 738 bool WriteGingleContentInfos(const ContentInfos& contents, 739 const ContentParserMap& parsers, 740 XmlElements* elems, 741 WriteError* error) { 742 if (contents.size() == 1 || 743 (contents.size() == 2 && 744 !IsWritable(PROTOCOL_GINGLE, contents.at(1), parsers))) { 745 if (contents.front().rejected) { 746 return BadWrite("Gingle protocol may not reject individual contents.", 747 error); 748 } 749 buzz::XmlElement* elem = WriteContentInfo( 750 PROTOCOL_GINGLE, contents.front(), parsers, error); 751 if (!elem) 752 return false; 753 754 elems->push_back(elem); 755 } else if (contents.size() >= 2 && 756 contents.at(0).type == NS_JINGLE_RTP && 757 contents.at(1).type == NS_JINGLE_RTP) { 758 // Special-case audio + video contents so that they are "merged" 759 // into one "video" content. 760 if (contents.at(0).rejected || contents.at(1).rejected) { 761 return BadWrite("Gingle protocol may not reject individual contents.", 762 error); 763 } 764 buzz::XmlElement* audio = WriteContentInfo( 765 PROTOCOL_GINGLE, contents.at(0), parsers, error); 766 if (!audio) 767 return false; 768 769 buzz::XmlElement* video = WriteContentInfo( 770 PROTOCOL_GINGLE, contents.at(1), parsers, error); 771 if (!video) { 772 delete audio; 773 return false; 774 } 775 776 CopyXmlChildren(audio, video); 777 elems->push_back(video); 778 delete audio; 779 } else { 780 return BadWrite("Gingle protocol may only have one content.", error); 781 } 782 783 return true; 784 } 785 786 const TransportInfo* GetTransportInfoByContentName( 787 const TransportInfos& tinfos, const std::string& content_name) { 788 for (TransportInfos::const_iterator tinfo = tinfos.begin(); 789 tinfo != tinfos.end(); ++tinfo) { 790 if (content_name == tinfo->content_name) { 791 return &*tinfo; 792 } 793 } 794 return NULL; 795 } 796 797 bool WriteJingleContents(const ContentInfos& contents, 798 const ContentParserMap& content_parsers, 799 const TransportInfos& tinfos, 800 const TransportParserMap& trans_parsers, 801 const CandidateTranslatorMap& translators, 802 XmlElements* elems, 803 WriteError* error) { 804 for (ContentInfos::const_iterator content = contents.begin(); 805 content != contents.end(); ++content) { 806 if (content->rejected) { 807 continue; 808 } 809 const TransportInfo* tinfo = 810 GetTransportInfoByContentName(tinfos, content->name); 811 if (!tinfo) 812 return BadWrite("No transport for content: " + content->name, error); 813 814 XmlElements pair_elems; 815 buzz::XmlElement* elem = WriteContentInfo( 816 PROTOCOL_JINGLE, *content, content_parsers, error); 817 if (!elem) 818 return false; 819 pair_elems.push_back(elem); 820 821 if (!WriteJingleTransportInfo(*tinfo, trans_parsers, translators, 822 &pair_elems, error)) 823 return false; 824 825 WriteJingleContent(content->name, pair_elems, elems); 826 } 827 return true; 828 } 829 830 bool WriteJingleContentInfos(const ContentInfos& contents, 831 const ContentParserMap& content_parsers, 832 XmlElements* elems, 833 WriteError* error) { 834 for (ContentInfos::const_iterator content = contents.begin(); 835 content != contents.end(); ++content) { 836 if (content->rejected) { 837 continue; 838 } 839 XmlElements content_child_elems; 840 buzz::XmlElement* elem = WriteContentInfo( 841 PROTOCOL_JINGLE, *content, content_parsers, error); 842 if (!elem) 843 return false; 844 content_child_elems.push_back(elem); 845 WriteJingleContent(content->name, content_child_elems, elems); 846 } 847 return true; 848 } 849 850 bool WriteJingleGroupInfo(const ContentInfos& contents, 851 const ContentGroups& groups, 852 XmlElements* elems, 853 WriteError* error) { 854 if (!groups.empty()) { 855 buzz::XmlElement* pair_elem = new buzz::XmlElement(QN_JINGLE_DRAFT_GROUP); 856 pair_elem->SetAttr(QN_JINGLE_DRAFT_GROUP_TYPE, GROUP_TYPE_BUNDLE); 857 858 XmlElements pair_elems; 859 for (ContentInfos::const_iterator content = contents.begin(); 860 content != contents.end(); ++content) { 861 buzz::XmlElement* child_elem = 862 new buzz::XmlElement(QN_JINGLE_CONTENT, false); 863 child_elem->SetAttr(QN_JINGLE_CONTENT_NAME, content->name); 864 pair_elems.push_back(child_elem); 865 } 866 AddXmlChildren(pair_elem, pair_elems); 867 elems->push_back(pair_elem); 868 } 869 return true; 870 } 871 872 bool ParseContentType(SignalingProtocol protocol, 873 const buzz::XmlElement* action_elem, 874 std::string* content_type, 875 ParseError* error) { 876 const buzz::XmlElement* content_elem; 877 if (protocol == PROTOCOL_GINGLE) { 878 if (!ParseContentType(action_elem, content_type, &content_elem, error)) 879 return false; 880 881 // Internally, we only use NS_JINGLE_RTP. 882 if (*content_type == NS_GINGLE_AUDIO || 883 *content_type == NS_GINGLE_VIDEO) 884 *content_type = NS_JINGLE_RTP; 885 } else { 886 const buzz::XmlElement* pair_elem 887 = action_elem->FirstNamed(QN_JINGLE_CONTENT); 888 if (pair_elem == NULL) 889 return BadParse("No contents found", error); 890 891 if (!ParseContentType(pair_elem, content_type, &content_elem, error)) 892 return false; 893 } 894 895 return true; 896 } 897 898 static bool ParseContentMessage( 899 SignalingProtocol protocol, 900 const buzz::XmlElement* action_elem, 901 bool expect_transports, 902 const ContentParserMap& content_parsers, 903 const TransportParserMap& trans_parsers, 904 const CandidateTranslatorMap& translators, 905 SessionInitiate* init, 906 ParseError* error) { 907 init->owns_contents = true; 908 if (protocol == PROTOCOL_GINGLE) { 909 if (!ParseGingleContentInfos(action_elem, content_parsers, 910 &init->contents, error)) 911 return false; 912 913 if (expect_transports && 914 !ParseGingleTransportInfos(action_elem, init->contents, 915 trans_parsers, translators, 916 &init->transports, error)) 917 return false; 918 } else { 919 if (!ParseJingleContentInfos(action_elem, content_parsers, 920 &init->contents, error)) 921 return false; 922 if (!ParseJingleGroupInfos(action_elem, &init->groups, error)) 923 return false; 924 925 if (expect_transports && 926 !ParseJingleTransportInfos(action_elem, init->contents, 927 trans_parsers, translators, 928 &init->transports, error)) 929 return false; 930 } 931 932 return true; 933 } 934 935 static bool WriteContentMessage( 936 SignalingProtocol protocol, 937 const ContentInfos& contents, 938 const TransportInfos& tinfos, 939 const ContentParserMap& content_parsers, 940 const TransportParserMap& transport_parsers, 941 const CandidateTranslatorMap& translators, 942 const ContentGroups& groups, 943 XmlElements* elems, 944 WriteError* error) { 945 if (protocol == PROTOCOL_GINGLE) { 946 if (!WriteGingleContentInfos(contents, content_parsers, elems, error)) 947 return false; 948 949 if (!WriteGingleTransportInfos(tinfos, transport_parsers, translators, 950 elems, error)) 951 return false; 952 } else { 953 if (!WriteJingleContents(contents, content_parsers, 954 tinfos, transport_parsers, translators, 955 elems, error)) 956 return false; 957 if (!WriteJingleGroupInfo(contents, groups, elems, error)) 958 return false; 959 } 960 961 return true; 962 } 963 964 bool ParseSessionInitiate(SignalingProtocol protocol, 965 const buzz::XmlElement* action_elem, 966 const ContentParserMap& content_parsers, 967 const TransportParserMap& trans_parsers, 968 const CandidateTranslatorMap& translators, 969 SessionInitiate* init, 970 ParseError* error) { 971 bool expect_transports = true; 972 return ParseContentMessage(protocol, action_elem, expect_transports, 973 content_parsers, trans_parsers, translators, 974 init, error); 975 } 976 977 978 bool WriteSessionInitiate(SignalingProtocol protocol, 979 const ContentInfos& contents, 980 const TransportInfos& tinfos, 981 const ContentParserMap& content_parsers, 982 const TransportParserMap& transport_parsers, 983 const CandidateTranslatorMap& translators, 984 const ContentGroups& groups, 985 XmlElements* elems, 986 WriteError* error) { 987 return WriteContentMessage(protocol, contents, tinfos, 988 content_parsers, transport_parsers, translators, 989 groups, 990 elems, error); 991 } 992 993 bool ParseSessionAccept(SignalingProtocol protocol, 994 const buzz::XmlElement* action_elem, 995 const ContentParserMap& content_parsers, 996 const TransportParserMap& transport_parsers, 997 const CandidateTranslatorMap& translators, 998 SessionAccept* accept, 999 ParseError* error) { 1000 bool expect_transports = true; 1001 return ParseContentMessage(protocol, action_elem, expect_transports, 1002 content_parsers, transport_parsers, translators, 1003 accept, error); 1004 } 1005 1006 bool WriteSessionAccept(SignalingProtocol protocol, 1007 const ContentInfos& contents, 1008 const TransportInfos& tinfos, 1009 const ContentParserMap& content_parsers, 1010 const TransportParserMap& transport_parsers, 1011 const CandidateTranslatorMap& translators, 1012 const ContentGroups& groups, 1013 XmlElements* elems, 1014 WriteError* error) { 1015 return WriteContentMessage(protocol, contents, tinfos, 1016 content_parsers, transport_parsers, translators, 1017 groups, 1018 elems, error); 1019 } 1020 1021 bool ParseSessionTerminate(SignalingProtocol protocol, 1022 const buzz::XmlElement* action_elem, 1023 SessionTerminate* term, 1024 ParseError* error) { 1025 if (protocol == PROTOCOL_GINGLE) { 1026 const buzz::XmlElement* reason_elem = action_elem->FirstElement(); 1027 if (reason_elem != NULL) { 1028 term->reason = reason_elem->Name().LocalPart(); 1029 const buzz::XmlElement *debug_elem = reason_elem->FirstElement(); 1030 if (debug_elem != NULL) { 1031 term->debug_reason = debug_elem->Name().LocalPart(); 1032 } 1033 } 1034 return true; 1035 } else { 1036 const buzz::XmlElement* reason_elem = 1037 action_elem->FirstNamed(QN_JINGLE_REASON); 1038 if (reason_elem) { 1039 reason_elem = reason_elem->FirstElement(); 1040 if (reason_elem) { 1041 term->reason = reason_elem->Name().LocalPart(); 1042 } 1043 } 1044 return true; 1045 } 1046 } 1047 1048 void WriteSessionTerminate(SignalingProtocol protocol, 1049 const SessionTerminate& term, 1050 XmlElements* elems) { 1051 if (protocol == PROTOCOL_GINGLE) { 1052 elems->push_back(new buzz::XmlElement(buzz::QName(NS_GINGLE, term.reason))); 1053 } else { 1054 if (!term.reason.empty()) { 1055 buzz::XmlElement* reason_elem = new buzz::XmlElement(QN_JINGLE_REASON); 1056 reason_elem->AddElement(new buzz::XmlElement( 1057 buzz::QName(NS_JINGLE, term.reason))); 1058 elems->push_back(reason_elem); 1059 } 1060 } 1061 } 1062 1063 bool ParseDescriptionInfo(SignalingProtocol protocol, 1064 const buzz::XmlElement* action_elem, 1065 const ContentParserMap& content_parsers, 1066 const TransportParserMap& transport_parsers, 1067 const CandidateTranslatorMap& translators, 1068 DescriptionInfo* description_info, 1069 ParseError* error) { 1070 bool expect_transports = false; 1071 return ParseContentMessage(protocol, action_elem, expect_transports, 1072 content_parsers, transport_parsers, translators, 1073 description_info, error); 1074 } 1075 1076 bool WriteDescriptionInfo(SignalingProtocol protocol, 1077 const ContentInfos& contents, 1078 const ContentParserMap& content_parsers, 1079 XmlElements* elems, 1080 WriteError* error) { 1081 if (protocol == PROTOCOL_GINGLE) { 1082 return WriteGingleContentInfos(contents, content_parsers, elems, error); 1083 } else { 1084 return WriteJingleContentInfos(contents, content_parsers, elems, error); 1085 } 1086 } 1087 1088 bool ParseTransportInfos(SignalingProtocol protocol, 1089 const buzz::XmlElement* action_elem, 1090 const ContentInfos& contents, 1091 const TransportParserMap& trans_parsers, 1092 const CandidateTranslatorMap& translators, 1093 TransportInfos* tinfos, 1094 ParseError* error) { 1095 if (protocol == PROTOCOL_GINGLE) { 1096 return ParseGingleTransportInfos( 1097 action_elem, contents, trans_parsers, translators, tinfos, error); 1098 } else { 1099 return ParseJingleTransportInfos( 1100 action_elem, contents, trans_parsers, translators, tinfos, error); 1101 } 1102 } 1103 1104 bool WriteTransportInfos(SignalingProtocol protocol, 1105 const TransportInfos& tinfos, 1106 const TransportParserMap& trans_parsers, 1107 const CandidateTranslatorMap& translators, 1108 XmlElements* elems, 1109 WriteError* error) { 1110 if (protocol == PROTOCOL_GINGLE) { 1111 return WriteGingleTransportInfos(tinfos, trans_parsers, translators, 1112 elems, error); 1113 } else { 1114 return WriteJingleTransportInfos(tinfos, trans_parsers, translators, 1115 elems, error); 1116 } 1117 } 1118 1119 bool GetUriTarget(const std::string& prefix, const std::string& str, 1120 std::string* after) { 1121 size_t pos = str.find(prefix); 1122 if (pos == std::string::npos) 1123 return false; 1124 1125 *after = str.substr(pos + prefix.size(), std::string::npos); 1126 return true; 1127 } 1128 1129 bool FindSessionRedirect(const buzz::XmlElement* stanza, 1130 SessionRedirect* redirect) { 1131 const buzz::XmlElement* error_elem = GetXmlChild(stanza, LN_ERROR); 1132 if (error_elem == NULL) 1133 return false; 1134 1135 const buzz::XmlElement* redirect_elem = 1136 error_elem->FirstNamed(QN_GINGLE_REDIRECT); 1137 if (redirect_elem == NULL) 1138 redirect_elem = error_elem->FirstNamed(buzz::QN_STANZA_REDIRECT); 1139 if (redirect_elem == NULL) 1140 return false; 1141 1142 if (!GetUriTarget(STR_REDIRECT_PREFIX, redirect_elem->BodyText(), 1143 &redirect->target)) 1144 return false; 1145 1146 return true; 1147 } 1148 1149 } // namespace cricket 1150