1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/protocol/jingle_messages.h"
7 #include "base/logging.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "remoting/base/constants.h"
10 #include "remoting/protocol/content_description.h"
11 #include "remoting/protocol/name_value_map.h"
12 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
15 using buzz::XmlElement
;
22 const char kJabberNamespace
[] = "jabber:client";
23 const char kJingleNamespace
[] = "urn:xmpp:jingle:1";
25 // Namespace for transport messages for legacy GICE.
26 const char kGiceTransportNamespace
[] = "http://www.google.com/transport/p2p";
28 // Namespace for transport messages when using standard ICE.
29 const char kIceTransportNamespace
[] = "google:remoting:ice";
31 const char kEmptyNamespace
[] = "";
32 const char kXmlNamespace
[] = "http://www.w3.org/XML/1998/namespace";
34 const int kPortMin
= 1000;
35 const int kPortMax
= 65535;
37 const NameMapElement
<JingleMessage::ActionType
> kActionTypes
[] = {
38 { JingleMessage::SESSION_INITIATE
, "session-initiate" },
39 { JingleMessage::SESSION_ACCEPT
, "session-accept" },
40 { JingleMessage::SESSION_TERMINATE
, "session-terminate" },
41 { JingleMessage::SESSION_INFO
, "session-info" },
42 { JingleMessage::TRANSPORT_INFO
, "transport-info" },
45 const NameMapElement
<JingleMessage::Reason
> kReasons
[] = {
46 { JingleMessage::SUCCESS
, "success" },
47 { JingleMessage::DECLINE
, "decline" },
48 { JingleMessage::CANCEL
, "cancel" },
49 { JingleMessage::GENERAL_ERROR
, "general-error" },
50 { JingleMessage::INCOMPATIBLE_PARAMETERS
, "incompatible-parameters" },
53 bool ParseIceCredentials(const buzz::XmlElement
* element
,
54 JingleMessage::IceCredentials
* credentials
) {
55 DCHECK(element
->Name() == QName(kIceTransportNamespace
, "credentials"));
57 const std::string
& channel
= element
->Attr(QName(kEmptyNamespace
, "channel"));
58 const std::string
& ufrag
=
59 element
->Attr(QName(kEmptyNamespace
, "ufrag"));
60 const std::string
& password
=
61 element
->Attr(QName(kEmptyNamespace
, "password"));
63 if (channel
.empty() || ufrag
.empty() || password
.empty()) {
67 credentials
->channel
= channel
;
68 credentials
->ufrag
= ufrag
;
69 credentials
->password
= password
;
74 bool ParseIceCandidate(const buzz::XmlElement
* element
,
75 JingleMessage::NamedCandidate
* candidate
) {
76 DCHECK(element
->Name() == QName(kIceTransportNamespace
, "candidate"));
78 const std::string
& name
= element
->Attr(QName(kEmptyNamespace
, "name"));
79 const std::string
& foundation
=
80 element
->Attr(QName(kEmptyNamespace
, "foundation"));
81 const std::string
& address
= element
->Attr(QName(kEmptyNamespace
, "address"));
82 const std::string
& port_str
= element
->Attr(QName(kEmptyNamespace
, "port"));
83 const std::string
& type
= element
->Attr(QName(kEmptyNamespace
, "type"));
84 const std::string
& protocol
=
85 element
->Attr(QName(kEmptyNamespace
, "protocol"));
86 const std::string
& priority_str
=
87 element
->Attr(QName(kEmptyNamespace
, "priority"));
88 const std::string
& generation_str
=
89 element
->Attr(QName(kEmptyNamespace
, "generation"));
94 if (name
.empty() || foundation
.empty() || address
.empty() ||
95 !base::StringToInt(port_str
, &port
) || port
< kPortMin
||
96 port
> kPortMax
|| type
.empty() || protocol
.empty() ||
97 !base::StringToUint(priority_str
, &priority
) ||
98 !base::StringToInt(generation_str
, &generation
)) {
102 candidate
->name
= name
;
104 candidate
->candidate
.set_foundation(foundation
);
105 candidate
->candidate
.set_address(rtc::SocketAddress(address
, port
));
106 candidate
->candidate
.set_type(type
);
107 candidate
->candidate
.set_protocol(protocol
);
108 candidate
->candidate
.set_priority(priority
);
109 candidate
->candidate
.set_generation(generation
);
114 bool ParseIceTransportInfo(
115 const buzz::XmlElement
* element
,
116 std::list
<JingleMessage::IceCredentials
>* ice_credentials
,
117 std::list
<JingleMessage::NamedCandidate
>* candidates
) {
118 DCHECK(element
->Name() == QName(kIceTransportNamespace
, "transport"));
120 ice_credentials
->clear();
123 QName
qn_credentials(kIceTransportNamespace
, "credentials");
124 for (const XmlElement
* credentials_tag
= element
->FirstNamed(qn_credentials
);
126 credentials_tag
= credentials_tag
->NextNamed(qn_credentials
)) {
127 JingleMessage::IceCredentials credentials
;
128 if (!ParseIceCredentials(credentials_tag
, &credentials
))
130 ice_credentials
->push_back(credentials
);
133 QName
qn_candidate(kIceTransportNamespace
, "candidate");
134 for (const XmlElement
* candidate_tag
= element
->FirstNamed(qn_candidate
);
135 candidate_tag
; candidate_tag
= candidate_tag
->NextNamed(qn_candidate
)) {
136 JingleMessage::NamedCandidate candidate
;
137 if (!ParseIceCandidate(candidate_tag
, &candidate
))
139 candidates
->push_back(candidate
);
145 bool ParseGiceCandidate(const buzz::XmlElement
* element
,
146 JingleMessage::NamedCandidate
* candidate
) {
147 DCHECK(element
->Name() == QName(kGiceTransportNamespace
, "candidate"));
149 const std::string
& name
= element
->Attr(QName(kEmptyNamespace
, "name"));
150 const std::string
& address
= element
->Attr(QName(kEmptyNamespace
, "address"));
151 const std::string
& port_str
= element
->Attr(QName(kEmptyNamespace
, "port"));
152 const std::string
& type
= element
->Attr(QName(kEmptyNamespace
, "type"));
153 const std::string
& protocol
=
154 element
->Attr(QName(kEmptyNamespace
, "protocol"));
155 const std::string
& username
=
156 element
->Attr(QName(kEmptyNamespace
, "username"));
157 const std::string
& password
=
158 element
->Attr(QName(kEmptyNamespace
, "password"));
159 const std::string
& preference_str
=
160 element
->Attr(QName(kEmptyNamespace
, "preference"));
161 const std::string
& generation_str
=
162 element
->Attr(QName(kEmptyNamespace
, "generation"));
167 if (name
.empty() || address
.empty() || !base::StringToInt(port_str
, &port
) ||
168 port
< kPortMin
|| port
> kPortMax
|| type
.empty() || protocol
.empty() ||
169 username
.empty() || password
.empty() ||
170 !base::StringToDouble(preference_str
, &preference
) ||
171 !base::StringToInt(generation_str
, &generation
)) {
175 candidate
->name
= name
;
177 candidate
->candidate
.set_address(rtc::SocketAddress(address
, port
));
178 candidate
->candidate
.set_type(type
);
179 candidate
->candidate
.set_protocol(protocol
);
180 candidate
->candidate
.set_username(username
);
181 candidate
->candidate
.set_password(password
);
182 candidate
->candidate
.set_preference(static_cast<float>(preference
));
183 candidate
->candidate
.set_generation(generation
);
188 bool ParseGiceTransportInfo(
189 const buzz::XmlElement
* element
,
190 std::list
<JingleMessage::NamedCandidate
>* candidates
) {
191 DCHECK(element
->Name() == QName(kGiceTransportNamespace
, "transport"));
195 QName
qn_candidate(kGiceTransportNamespace
, "candidate");
196 for (const XmlElement
* candidate_tag
= element
->FirstNamed(qn_candidate
);
197 candidate_tag
; candidate_tag
= candidate_tag
->NextNamed(qn_candidate
)) {
198 JingleMessage::NamedCandidate candidate
;
199 if (!ParseGiceCandidate(candidate_tag
, &candidate
))
201 candidates
->push_back(candidate
);
207 XmlElement
* FormatIceCredentials(
208 const JingleMessage::IceCredentials
& credentials
) {
210 new XmlElement(QName(kIceTransportNamespace
, "credentials"));
211 result
->SetAttr(QName(kEmptyNamespace
, "channel"), credentials
.channel
);
212 result
->SetAttr(QName(kEmptyNamespace
, "ufrag"), credentials
.ufrag
);
213 result
->SetAttr(QName(kEmptyNamespace
, "password"), credentials
.password
);
217 XmlElement
* FormatIceCandidate(const JingleMessage::NamedCandidate
& candidate
) {
219 new XmlElement(QName(kIceTransportNamespace
, "candidate"));
220 result
->SetAttr(QName(kEmptyNamespace
, "name"), candidate
.name
);
221 result
->SetAttr(QName(kEmptyNamespace
, "foundation"),
222 candidate
.candidate
.foundation());
223 result
->SetAttr(QName(kEmptyNamespace
, "address"),
224 candidate
.candidate
.address().ipaddr().ToString());
225 result
->SetAttr(QName(kEmptyNamespace
, "port"),
226 base::IntToString(candidate
.candidate
.address().port()));
227 result
->SetAttr(QName(kEmptyNamespace
, "type"), candidate
.candidate
.type());
228 result
->SetAttr(QName(kEmptyNamespace
, "protocol"),
229 candidate
.candidate
.protocol());
230 result
->SetAttr(QName(kEmptyNamespace
, "priority"),
231 base::DoubleToString(candidate
.candidate
.priority()));
232 result
->SetAttr(QName(kEmptyNamespace
, "generation"),
233 base::IntToString(candidate
.candidate
.generation()));
237 XmlElement
* FormatGiceCandidate(
238 const JingleMessage::NamedCandidate
& candidate
) {
240 new XmlElement(QName(kGiceTransportNamespace
, "candidate"));
241 result
->SetAttr(QName(kEmptyNamespace
, "name"), candidate
.name
);
242 result
->SetAttr(QName(kEmptyNamespace
, "address"),
243 candidate
.candidate
.address().ipaddr().ToString());
244 result
->SetAttr(QName(kEmptyNamespace
, "port"),
245 base::IntToString(candidate
.candidate
.address().port()));
246 result
->SetAttr(QName(kEmptyNamespace
, "type"), candidate
.candidate
.type());
247 result
->SetAttr(QName(kEmptyNamespace
, "protocol"),
248 candidate
.candidate
.protocol());
249 result
->SetAttr(QName(kEmptyNamespace
, "username"),
250 candidate
.candidate
.username());
251 result
->SetAttr(QName(kEmptyNamespace
, "password"),
252 candidate
.candidate
.password());
253 result
->SetAttr(QName(kEmptyNamespace
, "preference"),
254 base::DoubleToString(candidate
.candidate
.preference()));
255 result
->SetAttr(QName(kEmptyNamespace
, "generation"),
256 base::IntToString(candidate
.candidate
.generation()));
262 JingleMessage::NamedCandidate::NamedCandidate(
263 const std::string
& name
,
264 const cricket::Candidate
& candidate
)
266 candidate(candidate
) {
269 JingleMessage::IceCredentials::IceCredentials(std::string channel
,
271 std::string password
)
272 : channel(channel
), ufrag(ufrag
), password(password
) {
276 bool JingleMessage::IsJingleMessage(const buzz::XmlElement
* stanza
) {
277 return stanza
->Name() == QName(kJabberNamespace
, "iq") &&
278 stanza
->Attr(QName(std::string(), "type")) == "set" &&
279 stanza
->FirstNamed(QName(kJingleNamespace
, "jingle")) != nullptr;
283 std::string
JingleMessage::GetActionName(ActionType action
) {
284 return ValueToName(kActionTypes
, action
);
287 JingleMessage::JingleMessage() {
290 JingleMessage::JingleMessage(const std::string
& to
,
292 const std::string
& sid
)
293 : to(to
), action(action
), sid(sid
) {
296 JingleMessage::~JingleMessage() {
299 bool JingleMessage::ParseXml(const buzz::XmlElement
* stanza
,
300 std::string
* error
) {
301 if (!IsJingleMessage(stanza
)) {
302 *error
= "Not a jingle message";
306 const XmlElement
* jingle_tag
=
307 stanza
->FirstNamed(QName(kJingleNamespace
, "jingle"));
309 *error
= "Not a jingle message";
313 from
= stanza
->Attr(QName(kEmptyNamespace
, "from"));
314 to
= stanza
->Attr(QName(kEmptyNamespace
, "to"));
315 initiator
= jingle_tag
->Attr(QName(kEmptyNamespace
, "initiator"));
317 std::string action_str
= jingle_tag
->Attr(QName(kEmptyNamespace
, "action"));
318 if (action_str
.empty()) {
319 *error
= "action attribute is missing";
322 if (!NameToValue(kActionTypes
, action_str
, &action
)) {
323 *error
= "Unknown action " + action_str
;
327 sid
= jingle_tag
->Attr(QName(kEmptyNamespace
, "sid"));
329 *error
= "sid attribute is missing";
333 if (action
== SESSION_INFO
) {
334 // session-info messages may contain arbitrary information not
335 // defined by the Jingle protocol. We don't need to parse it.
336 const XmlElement
* child
= jingle_tag
->FirstElement();
338 // session-info is allowed to be empty.
339 info
.reset(new XmlElement(*child
));
346 const XmlElement
* reason_tag
=
347 jingle_tag
->FirstNamed(QName(kJingleNamespace
, "reason"));
348 if (reason_tag
&& reason_tag
->FirstElement()) {
349 if (!NameToValue(kReasons
, reason_tag
->FirstElement()->Name().LocalPart(),
351 reason
= UNKNOWN_REASON
;
355 if (action
== SESSION_TERMINATE
)
358 const XmlElement
* content_tag
=
359 jingle_tag
->FirstNamed(QName(kJingleNamespace
, "content"));
361 *error
= "content tag is missing";
365 std::string content_name
= content_tag
->Attr(QName(kEmptyNamespace
, "name"));
366 if (content_name
!= ContentDescription::kChromotingContentName
) {
367 *error
= "Unexpected content name: " + content_name
;
371 description
.reset(nullptr);
372 if (action
== SESSION_INITIATE
|| action
== SESSION_ACCEPT
) {
373 const XmlElement
* description_tag
= content_tag
->FirstNamed(
374 QName(kChromotingXmlNamespace
, "description"));
375 if (!description_tag
) {
376 *error
= "Missing chromoting content description";
380 description
= ContentDescription::ParseXml(description_tag
);
381 if (!description
.get()) {
382 *error
= "Failed to parse content description";
387 const XmlElement
* ice_transport_tag
= content_tag
->FirstNamed(
388 QName(kIceTransportNamespace
, "transport"));
389 const XmlElement
* gice_transport_tag
= content_tag
->FirstNamed(
390 QName(kGiceTransportNamespace
, "transport"));
391 if (ice_transport_tag
&& gice_transport_tag
) {
392 *error
= "ICE and GICE transport information is found in the same message";
394 } else if (ice_transport_tag
) {
396 if (!ParseIceTransportInfo(ice_transport_tag
, &ice_credentials
,
398 *error
= "Failed to parse transport info";
401 } else if (gice_transport_tag
) {
402 standard_ice
= false;
403 ice_credentials
.clear();
404 if (!ParseGiceTransportInfo(gice_transport_tag
, &candidates
)) {
405 *error
= "Failed to parse transport info";
413 scoped_ptr
<buzz::XmlElement
> JingleMessage::ToXml() const {
414 scoped_ptr
<XmlElement
> root(
415 new XmlElement(QName("jabber:client", "iq"), true));
418 root
->AddAttr(QName(kEmptyNamespace
, "to"), to
);
420 root
->AddAttr(QName(kEmptyNamespace
, "from"), from
);
421 root
->SetAttr(QName(kEmptyNamespace
, "type"), "set");
423 XmlElement
* jingle_tag
=
424 new XmlElement(QName(kJingleNamespace
, "jingle"), true);
425 root
->AddElement(jingle_tag
);
426 jingle_tag
->AddAttr(QName(kEmptyNamespace
, "sid"), sid
);
428 const char* action_attr
= ValueToName(kActionTypes
, action
);
430 LOG(FATAL
) << "Invalid action value " << action
;
431 jingle_tag
->AddAttr(QName(kEmptyNamespace
, "action"), action_attr
);
433 if (action
== SESSION_INFO
) {
435 jingle_tag
->AddElement(new XmlElement(*info
.get()));
439 if (action
== SESSION_INITIATE
)
440 jingle_tag
->AddAttr(QName(kEmptyNamespace
, "initiator"), initiator
);
442 if (reason
!= UNKNOWN_REASON
) {
443 XmlElement
* reason_tag
= new XmlElement(QName(kJingleNamespace
, "reason"));
444 jingle_tag
->AddElement(reason_tag
);
445 const char* reason_string
=
446 ValueToName(kReasons
, reason
);
448 LOG(FATAL
) << "Invalid reason: " << reason
;
449 reason_tag
->AddElement(new XmlElement(
450 QName(kJingleNamespace
, reason_string
)));
453 if (action
!= SESSION_TERMINATE
) {
454 XmlElement
* content_tag
=
455 new XmlElement(QName(kJingleNamespace
, "content"));
456 jingle_tag
->AddElement(content_tag
);
458 content_tag
->AddAttr(QName(kEmptyNamespace
, "name"),
459 ContentDescription::kChromotingContentName
);
460 content_tag
->AddAttr(QName(kEmptyNamespace
, "creator"), "initiator");
462 if (description
.get())
463 content_tag
->AddElement(description
->ToXml());
466 XmlElement
* transport_tag
=
467 new XmlElement(QName(kIceTransportNamespace
, "transport"), true);
468 content_tag
->AddElement(transport_tag
);
469 for (std::list
<IceCredentials
>::const_iterator it
=
470 ice_credentials
.begin();
471 it
!= ice_credentials
.end(); ++it
) {
472 transport_tag
->AddElement(FormatIceCredentials(*it
));
474 for (std::list
<NamedCandidate
>::const_iterator it
= candidates
.begin();
475 it
!= candidates
.end(); ++it
) {
476 transport_tag
->AddElement(FormatIceCandidate(*it
));
479 XmlElement
* transport_tag
=
480 new XmlElement(QName(kGiceTransportNamespace
, "transport"), true);
481 content_tag
->AddElement(transport_tag
);
482 for (std::list
<NamedCandidate
>::const_iterator it
= candidates
.begin();
483 it
!= candidates
.end(); ++it
) {
484 transport_tag
->AddElement(FormatGiceCandidate(*it
));
492 JingleMessageReply::JingleMessageReply()
493 : type(REPLY_RESULT
),
497 JingleMessageReply::JingleMessageReply(ErrorType error
)
498 : type(error
!= NONE
? REPLY_ERROR
: REPLY_RESULT
),
502 JingleMessageReply::JingleMessageReply(ErrorType error
,
503 const std::string
& text_value
)
509 JingleMessageReply::~JingleMessageReply() { }
511 scoped_ptr
<buzz::XmlElement
> JingleMessageReply::ToXml(
512 const buzz::XmlElement
* request_stanza
) const {
513 scoped_ptr
<XmlElement
> iq(
514 new XmlElement(QName(kJabberNamespace
, "iq"), true));
515 iq
->SetAttr(QName(kEmptyNamespace
, "to"),
516 request_stanza
->Attr(QName(kEmptyNamespace
, "from")));
517 iq
->SetAttr(QName(kEmptyNamespace
, "id"),
518 request_stanza
->Attr(QName(kEmptyNamespace
, "id")));
520 if (type
== REPLY_RESULT
) {
521 iq
->SetAttr(QName(kEmptyNamespace
, "type"), "result");
525 DCHECK_EQ(type
, REPLY_ERROR
);
527 iq
->SetAttr(QName(kEmptyNamespace
, "type"), "error");
529 for (const buzz::XmlElement
* child
= request_stanza
->FirstElement();
530 child
!= nullptr; child
= child
->NextElement()) {
531 iq
->AddElement(new buzz::XmlElement(*child
));
534 buzz::XmlElement
* error
=
535 new buzz::XmlElement(QName(kJabberNamespace
, "error"));
536 iq
->AddElement(error
);
539 std::string error_text
;
541 switch (error_type
) {
544 name
= QName(kJabberNamespace
, "bad-request");
546 case NOT_IMPLEMENTED
:
548 name
= QName(kJabberNamespace
, "feature-bad-request");
552 name
= QName(kJabberNamespace
, "item-not-found");
553 error_text
= "Invalid SID";
555 case UNEXPECTED_REQUEST
:
557 name
= QName(kJabberNamespace
, "unexpected-request");
559 case UNSUPPORTED_INFO
:
561 name
= QName(kJabberNamespace
, "feature-not-implemented");
570 error
->SetAttr(QName(kEmptyNamespace
, "type"), type
);
572 // If the error name is not in the standard namespace, we have
573 // to first add some error from that namespace.
574 if (name
.Namespace() != kJabberNamespace
) {
576 new buzz::XmlElement(QName(kJabberNamespace
, "undefined-condition")));
578 error
->AddElement(new buzz::XmlElement(name
));
580 if (!error_text
.empty()) {
581 // It's okay to always use English here. This text is for
582 // debugging purposes only.
583 buzz::XmlElement
* text_elem
=
584 new buzz::XmlElement(QName(kJabberNamespace
, "text"));
585 text_elem
->SetAttr(QName(kXmlNamespace
, "lang"), "en");
586 text_elem
->SetBodyText(error_text
);
587 error
->AddElement(text_elem
);
593 } // namespace protocol
594 } // namespace remoting