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
ToActionType(const std::string & type)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
ToJingleString(ActionType type)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
ToGingleString(ActionType type)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
IsJingleMessage(const buzz::XmlElement * stanza)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
IsGingleMessage(const buzz::XmlElement * stanza)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
IsSessionMessage(const buzz::XmlElement * stanza)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
ParseGingleSessionMessage(const buzz::XmlElement * session,SessionMessage * msg,ParseError * error)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
ParseJingleSessionMessage(const buzz::XmlElement * jingle,SessionMessage * msg,ParseError * error)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
ParseHybridSessionMessage(const buzz::XmlElement * jingle,SessionMessage * msg,ParseError * error)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
ParseSessionMessage(const buzz::XmlElement * stanza,SessionMessage * msg,ParseError * error)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
WriteGingleAction(const SessionMessage & msg,const XmlElements & action_elems)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
WriteJingleAction(const SessionMessage & msg,const XmlElements & action_elems)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
WriteSessionMessage(const SessionMessage & msg,const XmlElements & action_elems,buzz::XmlElement * stanza)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
GetTransportParser(const TransportParserMap & trans_parsers,const std::string & transport_type)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
GetCandidateTranslator(const CandidateTranslatorMap & translators,const std::string & content_name)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
GetParserAndTranslator(const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,const std::string & transport_type,const std::string & content_name,TransportParser ** parser,CandidateTranslator ** translator,ParseError * error)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
GetParserAndTranslator(const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,const std::string & transport_type,const std::string & content_name,TransportParser ** parser,CandidateTranslator ** translator,WriteError * error)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
ParseGingleCandidate(const buzz::XmlElement * candidate_elem,const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,const std::string & content_name,Candidates * candidates,ParseError * error)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
ParseGingleCandidates(const buzz::XmlElement * parent,const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,const std::string & content_name,Candidates * candidates,ParseError * error)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
ParseGingleTransportInfos(const buzz::XmlElement * action_elem,const ContentInfos & contents,const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,TransportInfos * tinfos,ParseError * error)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
ParseJingleTransportInfo(const buzz::XmlElement * trans_elem,const std::string & content_name,const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,TransportInfo * tinfo,ParseError * error)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
ParseJingleTransportInfos(const buzz::XmlElement * jingle,const ContentInfos & contents,const TransportParserMap trans_parsers,const CandidateTranslatorMap & translators,TransportInfos * tinfos,ParseError * error)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
NewTransportElement(const std::string & name)475 buzz::XmlElement* NewTransportElement(const std::string& name) {
476 return new buzz::XmlElement(buzz::QName(name, LN_TRANSPORT), true);
477 }
478
WriteGingleCandidates(const Candidates & candidates,const TransportParserMap & trans_parsers,const std::string & transport_type,const CandidateTranslatorMap & translators,const std::string & content_name,XmlElements * elems,WriteError * error)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
WriteGingleTransportInfos(const TransportInfos & tinfos,const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,XmlElements * elems,WriteError * error)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
WriteJingleTransportInfo(const TransportInfo & tinfo,const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,XmlElements * elems,WriteError * error)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
WriteJingleContent(const std::string name,const XmlElements & child_elems,XmlElements * elems)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
WriteJingleTransportInfos(const TransportInfos & tinfos,const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,XmlElements * elems,WriteError * error)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
GetContentParser(const ContentParserMap & content_parsers,const std::string & type)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
ParseContentInfo(SignalingProtocol protocol,const std::string & name,const std::string & type,const buzz::XmlElement * elem,const ContentParserMap & parsers,ContentInfos * contents,ParseError * error)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
ParseContentType(const buzz::XmlElement * parent_elem,std::string * content_type,const buzz::XmlElement ** content_elem,ParseError * error)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
ParseGingleContentInfos(const buzz::XmlElement * session,const ContentParserMap & content_parsers,ContentInfos * contents,ParseError * error)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
ParseJingleContentInfos(const buzz::XmlElement * jingle,const ContentParserMap & content_parsers,ContentInfos * contents,ParseError * error)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
ParseJingleGroupInfos(const buzz::XmlElement * jingle,ContentGroups * groups,ParseError * error)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
WriteContentInfo(SignalingProtocol protocol,const ContentInfo & content,const ContentParserMap & parsers,WriteError * error)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
IsWritable(SignalingProtocol protocol,const ContentInfo & content,const ContentParserMap & parsers)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
WriteGingleContentInfos(const ContentInfos & contents,const ContentParserMap & parsers,XmlElements * elems,WriteError * error)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
GetTransportInfoByContentName(const TransportInfos & tinfos,const std::string & content_name)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
WriteJingleContents(const ContentInfos & contents,const ContentParserMap & content_parsers,const TransportInfos & tinfos,const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,XmlElements * elems,WriteError * error)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
WriteJingleContentInfos(const ContentInfos & contents,const ContentParserMap & content_parsers,XmlElements * elems,WriteError * error)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
WriteJingleGroupInfo(const ContentInfos & contents,const ContentGroups & groups,XmlElements * elems,WriteError * error)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
ParseContentType(SignalingProtocol protocol,const buzz::XmlElement * action_elem,std::string * content_type,ParseError * error)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
ParseContentMessage(SignalingProtocol protocol,const buzz::XmlElement * action_elem,bool expect_transports,const ContentParserMap & content_parsers,const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,SessionInitiate * init,ParseError * error)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
WriteContentMessage(SignalingProtocol protocol,const ContentInfos & contents,const TransportInfos & tinfos,const ContentParserMap & content_parsers,const TransportParserMap & transport_parsers,const CandidateTranslatorMap & translators,const ContentGroups & groups,XmlElements * elems,WriteError * error)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
ParseSessionInitiate(SignalingProtocol protocol,const buzz::XmlElement * action_elem,const ContentParserMap & content_parsers,const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,SessionInitiate * init,ParseError * error)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
WriteSessionInitiate(SignalingProtocol protocol,const ContentInfos & contents,const TransportInfos & tinfos,const ContentParserMap & content_parsers,const TransportParserMap & transport_parsers,const CandidateTranslatorMap & translators,const ContentGroups & groups,XmlElements * elems,WriteError * error)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
ParseSessionAccept(SignalingProtocol protocol,const buzz::XmlElement * action_elem,const ContentParserMap & content_parsers,const TransportParserMap & transport_parsers,const CandidateTranslatorMap & translators,SessionAccept * accept,ParseError * error)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
WriteSessionAccept(SignalingProtocol protocol,const ContentInfos & contents,const TransportInfos & tinfos,const ContentParserMap & content_parsers,const TransportParserMap & transport_parsers,const CandidateTranslatorMap & translators,const ContentGroups & groups,XmlElements * elems,WriteError * error)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
ParseSessionTerminate(SignalingProtocol protocol,const buzz::XmlElement * action_elem,SessionTerminate * term,ParseError * error)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
WriteSessionTerminate(SignalingProtocol protocol,const SessionTerminate & term,XmlElements * elems)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
ParseDescriptionInfo(SignalingProtocol protocol,const buzz::XmlElement * action_elem,const ContentParserMap & content_parsers,const TransportParserMap & transport_parsers,const CandidateTranslatorMap & translators,DescriptionInfo * description_info,ParseError * error)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
WriteDescriptionInfo(SignalingProtocol protocol,const ContentInfos & contents,const ContentParserMap & content_parsers,XmlElements * elems,WriteError * error)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
ParseTransportInfos(SignalingProtocol protocol,const buzz::XmlElement * action_elem,const ContentInfos & contents,const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,TransportInfos * tinfos,ParseError * error)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
WriteTransportInfos(SignalingProtocol protocol,const TransportInfos & tinfos,const TransportParserMap & trans_parsers,const CandidateTranslatorMap & translators,XmlElements * elems,WriteError * error)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
GetUriTarget(const std::string & prefix,const std::string & str,std::string * after)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
FindSessionRedirect(const buzz::XmlElement * stanza,SessionRedirect * redirect)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