Index: remoting/protocol/jingle_messages.cc |
diff --git a/remoting/protocol/jingle_messages.cc b/remoting/protocol/jingle_messages.cc |
index c2c9b8016e0b7c7fdab9c5deb25e7f4c5ad24c8e..7e4c21ee3bb537264b29c9070701b5217abad643 100644 |
--- a/remoting/protocol/jingle_messages.cc |
+++ b/remoting/protocol/jingle_messages.cc |
@@ -17,11 +17,16 @@ using buzz::XmlElement; |
namespace remoting { |
namespace protocol { |
+namespace { |
+ |
const char kJabberNamespace[] = "jabber:client"; |
const char kJingleNamespace[] = "urn:xmpp:jingle:1"; |
-const char kP2PTransportNamespace[] = "http://www.google.com/transport/p2p"; |
-namespace { |
+// Namespace for transport messages for legacy GICE. |
+const char kGiceTransportNamespace[] = "http://www.google.com/transport/p2p"; |
+ |
+// Namespace for transport messages when using standard ICE. |
+const char kIceTransportNamespace[] = "google:remoting:ice"; |
const char kEmptyNamespace[] = ""; |
const char kXmlNamespace[] = "http://www.w3.org/XML/1998/namespace"; |
@@ -45,9 +50,101 @@ const NameMapElement<JingleMessage::Reason> kReasons[] = { |
{ JingleMessage::INCOMPATIBLE_PARAMETERS, "incompatible-parameters" }, |
}; |
-bool ParseCandidate(const buzz::XmlElement* element, |
- JingleMessage::NamedCandidate* candidate) { |
- DCHECK(element->Name() == QName(kP2PTransportNamespace, "candidate")); |
+bool ParseIceCredentials(const buzz::XmlElement* element, |
+ JingleMessage::IceCredentials* credentials) { |
+ DCHECK(element->Name() == QName(kIceTransportNamespace, "credentials")); |
+ |
+ const std::string& channel = element->Attr(QName(kEmptyNamespace, "channel")); |
+ const std::string& ufrag = |
+ element->Attr(QName(kEmptyNamespace, "ufrag")); |
+ const std::string& password = |
+ element->Attr(QName(kEmptyNamespace, "password")); |
+ |
+ if (channel.empty() || ufrag.empty() || password.empty()) { |
+ return false; |
+ } |
+ |
+ credentials->channel = channel; |
+ credentials->ufrag = ufrag; |
+ credentials->password = password; |
+ |
+ return true; |
+} |
+ |
+bool ParseIceCandidate(const buzz::XmlElement* element, |
+ JingleMessage::NamedCandidate* candidate) { |
+ DCHECK(element->Name() == QName(kIceTransportNamespace, "candidate")); |
+ |
+ const std::string& name = element->Attr(QName(kEmptyNamespace, "name")); |
+ const std::string& foundation = |
+ element->Attr(QName(kEmptyNamespace, "foundation")); |
+ const std::string& address = element->Attr(QName(kEmptyNamespace, "address")); |
+ const std::string& port_str = element->Attr(QName(kEmptyNamespace, "port")); |
+ const std::string& type = element->Attr(QName(kEmptyNamespace, "type")); |
+ const std::string& protocol = |
+ element->Attr(QName(kEmptyNamespace, "protocol")); |
+ const std::string& priority_str = |
+ element->Attr(QName(kEmptyNamespace, "priority")); |
+ const std::string& generation_str = |
+ element->Attr(QName(kEmptyNamespace, "generation")); |
+ |
+ int port; |
+ unsigned priority; |
+ int generation; |
+ if (name.empty() || foundation.empty() || address.empty() || |
+ !base::StringToInt(port_str, &port) || port < kPortMin || |
+ port > kPortMax || type.empty() || protocol.empty() || |
+ !base::StringToUint(priority_str, &priority) || |
+ !base::StringToInt(generation_str, &generation)) { |
+ return false; |
+ } |
+ |
+ candidate->name = name; |
+ |
+ candidate->candidate.set_foundation(foundation); |
+ candidate->candidate.set_address(rtc::SocketAddress(address, port)); |
+ candidate->candidate.set_type(type); |
+ candidate->candidate.set_protocol(protocol); |
+ candidate->candidate.set_priority(priority); |
+ candidate->candidate.set_generation(generation); |
+ |
+ return true; |
+} |
+ |
+bool ParseIceTransportInfo( |
+ const buzz::XmlElement* element, |
+ std::list<JingleMessage::IceCredentials>* ice_credentials, |
+ std::list<JingleMessage::NamedCandidate>* candidates) { |
+ DCHECK(element->Name() == QName(kIceTransportNamespace, "transport")); |
+ |
+ ice_credentials->clear(); |
+ candidates->clear(); |
+ |
+ QName qn_credentials(kIceTransportNamespace, "credentials"); |
+ for (const XmlElement* credentials_tag = element->FirstNamed(qn_credentials); |
+ credentials_tag; |
+ credentials_tag = credentials_tag->NextNamed(qn_credentials)) { |
+ JingleMessage::IceCredentials credentials; |
+ if (!ParseIceCredentials(credentials_tag, &credentials)) |
+ return false; |
+ ice_credentials->push_back(credentials); |
+ } |
+ |
+ QName qn_candidate(kIceTransportNamespace, "candidate"); |
+ for (const XmlElement* candidate_tag = element->FirstNamed(qn_candidate); |
+ candidate_tag; candidate_tag = candidate_tag->NextNamed(qn_candidate)) { |
+ JingleMessage::NamedCandidate candidate; |
+ if (!ParseIceCandidate(candidate_tag, &candidate)) |
+ return false; |
+ candidates->push_back(candidate); |
+ } |
+ |
+ return true; |
+} |
+ |
+bool ParseGiceCandidate(const buzz::XmlElement* element, |
+ JingleMessage::NamedCandidate* candidate) { |
+ DCHECK(element->Name() == QName(kGiceTransportNamespace, "candidate")); |
const std::string& name = element->Attr(QName(kEmptyNamespace, "name")); |
const std::string& address = element->Attr(QName(kEmptyNamespace, "address")); |
@@ -88,9 +185,59 @@ bool ParseCandidate(const buzz::XmlElement* element, |
return true; |
} |
-XmlElement* FormatCandidate(const JingleMessage::NamedCandidate& candidate) { |
+bool ParseGiceTransportInfo( |
+ const buzz::XmlElement* element, |
+ std::list<JingleMessage::NamedCandidate>* candidates) { |
+ DCHECK(element->Name() == QName(kGiceTransportNamespace, "transport")); |
+ |
+ candidates->clear(); |
+ |
+ QName qn_candidate(kGiceTransportNamespace, "candidate"); |
+ for (const XmlElement* candidate_tag = element->FirstNamed(qn_candidate); |
+ candidate_tag; candidate_tag = candidate_tag->NextNamed(qn_candidate)) { |
+ JingleMessage::NamedCandidate candidate; |
+ if (!ParseGiceCandidate(candidate_tag, &candidate)) |
+ return false; |
+ candidates->push_back(candidate); |
+ } |
+ |
+ return true; |
+} |
+ |
+XmlElement* FormatIceCredentials( |
+ const JingleMessage::IceCredentials& credentials) { |
+ XmlElement* result = |
+ new XmlElement(QName(kIceTransportNamespace, "credentials")); |
+ result->SetAttr(QName(kEmptyNamespace, "channel"), credentials.channel); |
+ result->SetAttr(QName(kEmptyNamespace, "ufrag"), credentials.ufrag); |
+ result->SetAttr(QName(kEmptyNamespace, "password"), credentials.password); |
+ return result; |
+} |
+ |
+XmlElement* FormatIceCandidate(const JingleMessage::NamedCandidate& candidate) { |
+ XmlElement* result = |
+ new XmlElement(QName(kIceTransportNamespace, "candidate")); |
+ result->SetAttr(QName(kEmptyNamespace, "name"), candidate.name); |
+ result->SetAttr(QName(kEmptyNamespace, "foundation"), |
+ candidate.candidate.foundation()); |
+ result->SetAttr(QName(kEmptyNamespace, "address"), |
+ candidate.candidate.address().ipaddr().ToString()); |
+ result->SetAttr(QName(kEmptyNamespace, "port"), |
+ base::IntToString(candidate.candidate.address().port())); |
+ result->SetAttr(QName(kEmptyNamespace, "type"), candidate.candidate.type()); |
+ result->SetAttr(QName(kEmptyNamespace, "protocol"), |
+ candidate.candidate.protocol()); |
+ result->SetAttr(QName(kEmptyNamespace, "priority"), |
+ base::DoubleToString(candidate.candidate.priority())); |
+ result->SetAttr(QName(kEmptyNamespace, "generation"), |
+ base::IntToString(candidate.candidate.generation())); |
+ return result; |
+} |
+ |
+XmlElement* FormatGiceCandidate( |
+ const JingleMessage::NamedCandidate& candidate) { |
XmlElement* result = |
- new XmlElement(QName(kP2PTransportNamespace, "candidate")); |
+ new XmlElement(QName(kGiceTransportNamespace, "candidate")); |
result->SetAttr(QName(kEmptyNamespace, "name"), candidate.name); |
result->SetAttr(QName(kEmptyNamespace, "address"), |
candidate.candidate.address().ipaddr().ToString()); |
@@ -112,9 +259,6 @@ XmlElement* FormatCandidate(const JingleMessage::NamedCandidate& candidate) { |
} // namespace |
-JingleMessage::NamedCandidate::NamedCandidate() { |
-} |
- |
JingleMessage::NamedCandidate::NamedCandidate( |
const std::string& name, |
const cricket::Candidate& candidate) |
@@ -122,6 +266,12 @@ JingleMessage::NamedCandidate::NamedCandidate( |
candidate(candidate) { |
} |
+JingleMessage::IceCredentials::IceCredentials(std::string channel, |
+ std::string ufrag, |
+ std::string password) |
+ : channel(channel), ufrag(ufrag), password(password) { |
+} |
+ |
// static |
bool JingleMessage::IsJingleMessage(const buzz::XmlElement* stanza) { |
return stanza->Name() == QName(kJabberNamespace, "iq") && |
@@ -134,19 +284,13 @@ std::string JingleMessage::GetActionName(ActionType action) { |
return ValueToName(kActionTypes, action); |
} |
-JingleMessage::JingleMessage() |
- : action(UNKNOWN_ACTION), |
- reason(UNKNOWN_REASON) { |
+JingleMessage::JingleMessage() { |
} |
-JingleMessage::JingleMessage( |
- const std::string& to_value, |
- ActionType action_value, |
- const std::string& sid_value) |
- : to(to_value), |
- action(action_value), |
- sid(sid_value), |
- reason(UNKNOWN_REASON) { |
+JingleMessage::JingleMessage(const std::string& to, |
+ ActionType action, |
+ const std::string& sid) |
+ : to(to), action(action), sid(sid) { |
} |
JingleMessage::~JingleMessage() { |
@@ -240,21 +384,26 @@ bool JingleMessage::ParseXml(const buzz::XmlElement* stanza, |
} |
} |
- candidates.clear(); |
- const XmlElement* transport_tag = content_tag->FirstNamed( |
- QName(kP2PTransportNamespace, "transport")); |
- if (transport_tag) { |
- QName qn_candidate(kP2PTransportNamespace, "candidate"); |
- for (const XmlElement* candidate_tag = |
- transport_tag->FirstNamed(qn_candidate); |
- candidate_tag != nullptr; |
- candidate_tag = candidate_tag->NextNamed(qn_candidate)) { |
- NamedCandidate candidate; |
- if (!ParseCandidate(candidate_tag, &candidate)) { |
- *error = "Failed to parse candidates"; |
- return false; |
- } |
- candidates.push_back(candidate); |
+ const XmlElement* ice_transport_tag = content_tag->FirstNamed( |
+ QName(kIceTransportNamespace, "transport")); |
+ const XmlElement* gice_transport_tag = content_tag->FirstNamed( |
+ QName(kGiceTransportNamespace, "transport")); |
+ if (ice_transport_tag && gice_transport_tag) { |
+ *error = "ICE and GICE transport information is found in the same message"; |
+ return false; |
+ } else if (ice_transport_tag) { |
+ standard_ice = true; |
+ if (!ParseIceTransportInfo(ice_transport_tag, &ice_credentials, |
+ &candidates)) { |
+ *error = "Failed to parse transport info"; |
+ return false; |
+ } |
+ } else if (gice_transport_tag) { |
+ standard_ice = false; |
+ ice_credentials.clear(); |
+ if (!ParseGiceTransportInfo(gice_transport_tag, &candidates)) { |
+ *error = "Failed to parse transport info"; |
+ return false; |
} |
} |
@@ -313,12 +462,27 @@ scoped_ptr<buzz::XmlElement> JingleMessage::ToXml() const { |
if (description.get()) |
content_tag->AddElement(description->ToXml()); |
- XmlElement* transport_tag = |
- new XmlElement(QName(kP2PTransportNamespace, "transport"), true); |
- content_tag->AddElement(transport_tag); |
- for (std::list<NamedCandidate>::const_iterator it = candidates.begin(); |
- it != candidates.end(); ++it) { |
- transport_tag->AddElement(FormatCandidate(*it)); |
+ if (standard_ice) { |
+ XmlElement* transport_tag = |
+ new XmlElement(QName(kIceTransportNamespace, "transport"), true); |
+ content_tag->AddElement(transport_tag); |
+ for (std::list<IceCredentials>::const_iterator it = |
+ ice_credentials.begin(); |
+ it != ice_credentials.end(); ++it) { |
+ transport_tag->AddElement(FormatIceCredentials(*it)); |
+ } |
+ for (std::list<NamedCandidate>::const_iterator it = candidates.begin(); |
+ it != candidates.end(); ++it) { |
+ transport_tag->AddElement(FormatIceCandidate(*it)); |
+ } |
+ } else { |
+ XmlElement* transport_tag = |
+ new XmlElement(QName(kGiceTransportNamespace, "transport"), true); |
+ content_tag->AddElement(transport_tag); |
+ for (std::list<NamedCandidate>::const_iterator it = candidates.begin(); |
+ it != candidates.end(); ++it) { |
+ transport_tag->AddElement(FormatGiceCandidate(*it)); |
+ } |
} |
} |