| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/protocol/jingle_messages.h" | 5 #include "remoting/protocol/jingle_messages.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
| 9 #include "remoting/base/constants.h" | 9 #include "remoting/base/constants.h" |
| 10 #include "remoting/base/name_value_map.h" | 10 #include "remoting/base/name_value_map.h" |
| 11 #include "remoting/base/remoting_bot.h" | 11 #include "remoting/base/remoting_bot.h" |
| 12 #include "remoting/protocol/content_description.h" | 12 #include "remoting/protocol/content_description.h" |
| 13 #include "remoting/protocol/session_plugin.h" | 13 #include "remoting/protocol/session_plugin.h" |
| 14 #include "remoting/signaling/jid_util.h" | |
| 15 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h" | 14 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h" |
| 16 | 15 |
| 17 using buzz::QName; | 16 using buzz::QName; |
| 18 using buzz::XmlElement; | 17 using buzz::XmlElement; |
| 19 | 18 |
| 20 namespace remoting { | 19 namespace remoting { |
| 21 namespace protocol { | 20 namespace protocol { |
| 22 | 21 |
| 23 namespace { | 22 namespace { |
| 24 | 23 |
| 25 const char kJabberNamespace[] = "jabber:client"; | 24 const char kJabberNamespace[] = "jabber:client"; |
| 26 const char kJingleNamespace[] = "urn:xmpp:jingle:1"; | 25 const char kJingleNamespace[] = "urn:xmpp:jingle:1"; |
| 27 | 26 |
| 28 // Namespace for transport messages when using standard ICE. | 27 // Namespace for transport messages when using standard ICE. |
| 29 const char kIceTransportNamespace[] = "google:remoting:ice"; | 28 const char kIceTransportNamespace[] = "google:remoting:ice"; |
| 30 | 29 |
| 31 const char kWebrtcTransportNamespace[] = "google:remoting:webrtc"; | 30 const char kWebrtcTransportNamespace[] = "google:remoting:webrtc"; |
| 32 | 31 |
| 33 const char kEmptyNamespace[] = ""; | 32 const char kEmptyNamespace[] = ""; |
| 34 const char kXmlNamespace[] = "http://www.w3.org/XML/1998/namespace"; | 33 const char kXmlNamespace[] = "http://www.w3.org/XML/1998/namespace"; |
| 35 | 34 |
| 36 const int kPortMin = 1000; | 35 const int kPortMin = 1000; |
| 37 const int kPortMax = 65535; | 36 const int kPortMax = 65535; |
| 38 | 37 |
| 39 const NameMapElement<SignalingAddress::Channel> kChannelTypes[] = { | |
| 40 {SignalingAddress::Channel::LCS, "lcs"}, | |
| 41 {SignalingAddress::Channel::XMPP, "xmpp"}, | |
| 42 }; | |
| 43 | |
| 44 const NameMapElement<JingleMessage::ActionType> kActionTypes[] = { | 38 const NameMapElement<JingleMessage::ActionType> kActionTypes[] = { |
| 45 { JingleMessage::SESSION_INITIATE, "session-initiate" }, | 39 { JingleMessage::SESSION_INITIATE, "session-initiate" }, |
| 46 { JingleMessage::SESSION_ACCEPT, "session-accept" }, | 40 { JingleMessage::SESSION_ACCEPT, "session-accept" }, |
| 47 { JingleMessage::SESSION_TERMINATE, "session-terminate" }, | 41 { JingleMessage::SESSION_TERMINATE, "session-terminate" }, |
| 48 { JingleMessage::SESSION_INFO, "session-info" }, | 42 { JingleMessage::SESSION_INFO, "session-info" }, |
| 49 { JingleMessage::TRANSPORT_INFO, "transport-info" }, | 43 { JingleMessage::TRANSPORT_INFO, "transport-info" }, |
| 50 }; | 44 }; |
| 51 | 45 |
| 52 const NameMapElement<JingleMessage::Reason> kReasons[] = { | 46 const NameMapElement<JingleMessage::Reason> kReasons[] = { |
| 53 { JingleMessage::SUCCESS, "success" }, | 47 { JingleMessage::SUCCESS, "success" }, |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 result->SetAttr(QName(kEmptyNamespace, "type"), candidate.candidate.type()); | 138 result->SetAttr(QName(kEmptyNamespace, "type"), candidate.candidate.type()); |
| 145 result->SetAttr(QName(kEmptyNamespace, "protocol"), | 139 result->SetAttr(QName(kEmptyNamespace, "protocol"), |
| 146 candidate.candidate.protocol()); | 140 candidate.candidate.protocol()); |
| 147 result->SetAttr(QName(kEmptyNamespace, "priority"), | 141 result->SetAttr(QName(kEmptyNamespace, "priority"), |
| 148 base::UintToString(candidate.candidate.priority())); | 142 base::UintToString(candidate.candidate.priority())); |
| 149 result->SetAttr(QName(kEmptyNamespace, "generation"), | 143 result->SetAttr(QName(kEmptyNamespace, "generation"), |
| 150 base::UintToString(candidate.candidate.generation())); | 144 base::UintToString(candidate.candidate.generation())); |
| 151 return result; | 145 return result; |
| 152 } | 146 } |
| 153 | 147 |
| 154 // Represents the XML attrbute names for the various address fields in the | |
| 155 // iq stanza. | |
| 156 enum class Field { JID, CHANNEL, ENDPOINT_ID }; | |
| 157 | |
| 158 buzz::QName GetQNameByField(Field attr, bool from) { | |
| 159 std::string attribute_name; | |
| 160 switch (attr) { | |
| 161 case Field::JID: | |
| 162 attribute_name = (from) ? "from" : "to"; | |
| 163 break; | |
| 164 case Field::ENDPOINT_ID: | |
| 165 attribute_name = (from) ? "from-endpoint-id" : "to-endpoint-id"; | |
| 166 break; | |
| 167 case Field::CHANNEL: | |
| 168 attribute_name = (from) ? "from-channel" : "to-channel"; | |
| 169 break; | |
| 170 default: | |
| 171 NOTREACHED(); | |
| 172 } | |
| 173 return QName(kEmptyNamespace, attribute_name); | |
| 174 } | |
| 175 | |
| 176 SignalingAddress ParseAddress( | |
| 177 const buzz::XmlElement* iq, bool from, std::string* error) { | |
| 178 std::string jid(iq->Attr(GetQNameByField(Field::JID, from))); | |
| 179 if (jid.empty()) { | |
| 180 return SignalingAddress(); | |
| 181 } | |
| 182 | |
| 183 const XmlElement* jingle = iq->FirstNamed(QName(kJingleNamespace, "jingle")); | |
| 184 | |
| 185 if (!jingle) { | |
| 186 return SignalingAddress(jid); | |
| 187 } | |
| 188 | |
| 189 std::string type(iq->Attr(QName(std::string(), "type"))); | |
| 190 // For error IQs, flips the |from| flag as the jingle node represents the | |
| 191 // original request. | |
| 192 if (type == "error") { | |
| 193 from = !from; | |
| 194 } | |
| 195 | |
| 196 std::string endpoint_id( | |
| 197 jingle->Attr(GetQNameByField(Field::ENDPOINT_ID, from))); | |
| 198 std::string channel_str(jingle->Attr(GetQNameByField(Field::CHANNEL, from))); | |
| 199 SignalingAddress::Channel channel; | |
| 200 | |
| 201 if (channel_str.empty()) { | |
| 202 channel = SignalingAddress::Channel::XMPP; | |
| 203 } else if (!NameToValue(kChannelTypes, channel_str, &channel)) { | |
| 204 *error = "Unknown channel: " + channel_str; | |
| 205 return SignalingAddress(); | |
| 206 } | |
| 207 | |
| 208 bool is_lcs = (channel == SignalingAddress::Channel::LCS); | |
| 209 | |
| 210 if (is_lcs == endpoint_id.empty()) { | |
| 211 *error = (is_lcs ? "Missing |endpoint-id| for LCS channel" | |
| 212 : "|endpoint_id| should be empty for XMPP channel"); | |
| 213 return SignalingAddress(); | |
| 214 } | |
| 215 | |
| 216 if (from && is_lcs && !IsValidBotJid(jid)) { | |
| 217 *error = "Reject LCS message from untrusted sender: " + jid; | |
| 218 return SignalingAddress(); | |
| 219 } | |
| 220 | |
| 221 return SignalingAddress(jid, endpoint_id, channel); | |
| 222 } | |
| 223 | |
| 224 void SetAddress(buzz::XmlElement* iq, | |
| 225 buzz::XmlElement* jingle, | |
| 226 const SignalingAddress& address, | |
| 227 bool from) { | |
| 228 if (address.empty()) { | |
| 229 return; | |
| 230 } | |
| 231 | |
| 232 // Always set the JID. | |
| 233 iq->SetAttr(GetQNameByField(Field::JID, from), address.jid()); | |
| 234 | |
| 235 // Do not tamper the routing-info in the jingle tag for error IQ's, as | |
| 236 // it corresponds to the original message. | |
| 237 std::string type(iq->Attr(QName(std::string(), "type"))); | |
| 238 if (type == "error") { | |
| 239 return; | |
| 240 } | |
| 241 | |
| 242 // Start from a fresh slate regardless of the previous address format. | |
| 243 jingle->ClearAttr(GetQNameByField(Field::CHANNEL, from)); | |
| 244 jingle->ClearAttr(GetQNameByField(Field::ENDPOINT_ID, from)); | |
| 245 | |
| 246 // Only set the channel and endpoint_id in the LCS channel. | |
| 247 if (address.channel() == SignalingAddress::Channel::LCS) { | |
| 248 jingle->AddAttr(GetQNameByField(Field::ENDPOINT_ID, from), | |
| 249 address.endpoint_id()); | |
| 250 jingle->AddAttr(GetQNameByField(Field::CHANNEL, from), | |
| 251 ValueToName(kChannelTypes, address.channel())); | |
| 252 } | |
| 253 } | |
| 254 | |
| 255 } // namespace | 148 } // namespace |
| 256 | 149 |
| 257 SignalingAddress::SignalingAddress() | |
| 258 : channel_(SignalingAddress::Channel::XMPP) {} | |
| 259 | |
| 260 SignalingAddress::SignalingAddress(const std::string& jid) | |
| 261 : jid_(NormalizeJid(jid)), channel_(SignalingAddress::Channel::XMPP) { | |
| 262 DCHECK(!jid.empty()); | |
| 263 } | |
| 264 | |
| 265 SignalingAddress::SignalingAddress(const std::string& jid, | |
| 266 const std::string& endpoint_id, | |
| 267 Channel channel) | |
| 268 : jid_(NormalizeJid(jid)), | |
| 269 endpoint_id_(NormalizeJid(endpoint_id)), | |
| 270 channel_(channel) { | |
| 271 DCHECK(!jid.empty()); | |
| 272 } | |
| 273 | |
| 274 bool SignalingAddress::operator==(const SignalingAddress& other) const { | |
| 275 return (other.jid_ == jid_) && (other.endpoint_id_ == endpoint_id_) && | |
| 276 (other.channel_ == channel_); | |
| 277 } | |
| 278 | |
| 279 bool SignalingAddress::operator!=(const SignalingAddress& other) const { | |
| 280 return !(*this == other); | |
| 281 } | |
| 282 | |
| 283 // static | 150 // static |
| 284 bool JingleMessage::IsJingleMessage(const buzz::XmlElement* stanza) { | 151 bool JingleMessage::IsJingleMessage(const buzz::XmlElement* stanza) { |
| 285 return stanza->Name() == QName(kJabberNamespace, "iq") && | 152 return stanza->Name() == QName(kJabberNamespace, "iq") && |
| 286 stanza->Attr(QName(std::string(), "type")) == "set" && | 153 stanza->Attr(QName(std::string(), "type")) == "set" && |
| 287 stanza->FirstNamed(QName(kJingleNamespace, "jingle")) != nullptr; | 154 stanza->FirstNamed(QName(kJingleNamespace, "jingle")) != nullptr; |
| 288 } | 155 } |
| 289 | 156 |
| 290 // static | 157 // static |
| 291 std::string JingleMessage::GetActionName(ActionType action) { | 158 std::string JingleMessage::GetActionName(ActionType action) { |
| 292 return ValueToName(kActionTypes, action); | 159 return ValueToName(kActionTypes, action); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 308 return false; | 175 return false; |
| 309 } | 176 } |
| 310 | 177 |
| 311 const XmlElement* jingle_tag = | 178 const XmlElement* jingle_tag = |
| 312 stanza->FirstNamed(QName(kJingleNamespace, "jingle")); | 179 stanza->FirstNamed(QName(kJingleNamespace, "jingle")); |
| 313 if (!jingle_tag) { | 180 if (!jingle_tag) { |
| 314 *error = "Not a jingle message"; | 181 *error = "Not a jingle message"; |
| 315 return false; | 182 return false; |
| 316 } | 183 } |
| 317 | 184 |
| 318 from = ParseAddress(stanza, true, error); | 185 from = SignalingAddress::Parse(stanza, SignalingAddress::FROM, error); |
| 319 if (!error->empty()) { | 186 to = SignalingAddress::Parse(stanza, SignalingAddress::TO, error); |
| 187 if (from.empty() || to.empty()) { |
| 320 return false; | 188 return false; |
| 321 } | 189 } |
| 322 | 190 |
| 323 to = ParseAddress(stanza, false, error); | |
| 324 if (!error->empty()) { | |
| 325 return false; | |
| 326 } | |
| 327 | |
| 328 initiator = jingle_tag->Attr(QName(kEmptyNamespace, "initiator")); | 191 initiator = jingle_tag->Attr(QName(kEmptyNamespace, "initiator")); |
| 329 | 192 |
| 330 std::string action_str = jingle_tag->Attr(QName(kEmptyNamespace, "action")); | 193 std::string action_str = jingle_tag->Attr(QName(kEmptyNamespace, "action")); |
| 331 if (action_str.empty()) { | 194 if (action_str.empty()) { |
| 332 *error = "action attribute is missing"; | 195 *error = "action attribute is missing"; |
| 333 return false; | 196 return false; |
| 334 } | 197 } |
| 335 if (!NameToValue(kActionTypes, action_str, &action)) { | 198 if (!NameToValue(kActionTypes, action_str, &action)) { |
| 336 *error = "Unknown action " + action_str; | 199 *error = "Unknown action " + action_str; |
| 337 return false; | 200 return false; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 443 std::unique_ptr<XmlElement> root( | 306 std::unique_ptr<XmlElement> root( |
| 444 new XmlElement(QName("jabber:client", "iq"), true)); | 307 new XmlElement(QName("jabber:client", "iq"), true)); |
| 445 | 308 |
| 446 DCHECK(!to.empty()); | 309 DCHECK(!to.empty()); |
| 447 root->SetAttr(QName(kEmptyNamespace, "type"), "set"); | 310 root->SetAttr(QName(kEmptyNamespace, "type"), "set"); |
| 448 | 311 |
| 449 XmlElement* jingle_tag = | 312 XmlElement* jingle_tag = |
| 450 new XmlElement(QName(kJingleNamespace, "jingle"), true); | 313 new XmlElement(QName(kJingleNamespace, "jingle"), true); |
| 451 root->AddElement(jingle_tag); | 314 root->AddElement(jingle_tag); |
| 452 jingle_tag->AddAttr(QName(kEmptyNamespace, "sid"), sid); | 315 jingle_tag->AddAttr(QName(kEmptyNamespace, "sid"), sid); |
| 453 SetAddress(root.get(), jingle_tag, to, false); | 316 |
| 454 SetAddress(root.get(), jingle_tag, from, true); | 317 to.SetInMessage(root.get(), SignalingAddress::TO); |
| 318 if (!from.empty()) |
| 319 from.SetInMessage(root.get(), SignalingAddress::FROM); |
| 455 | 320 |
| 456 const char* action_attr = ValueToName(kActionTypes, action); | 321 const char* action_attr = ValueToName(kActionTypes, action); |
| 457 if (!action_attr) { | 322 if (!action_attr) { |
| 458 LOG(FATAL) << "Invalid action value " << action; | 323 LOG(FATAL) << "Invalid action value " << action; |
| 459 } | 324 } |
| 460 jingle_tag->AddAttr(QName(kEmptyNamespace, "action"), action_attr); | 325 jingle_tag->AddAttr(QName(kEmptyNamespace, "action"), action_attr); |
| 461 | 326 |
| 462 if (attachments) { | 327 if (attachments) { |
| 463 jingle_tag->AddElement(new XmlElement(*attachments)); | 328 jingle_tag->AddElement(new XmlElement(*attachments)); |
| 464 } | 329 } |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 std::unique_ptr<buzz::XmlElement> JingleMessageReply::ToXml( | 408 std::unique_ptr<buzz::XmlElement> JingleMessageReply::ToXml( |
| 544 const buzz::XmlElement* request_stanza) const { | 409 const buzz::XmlElement* request_stanza) const { |
| 545 std::unique_ptr<XmlElement> iq( | 410 std::unique_ptr<XmlElement> iq( |
| 546 new XmlElement(QName(kJabberNamespace, "iq"), true)); | 411 new XmlElement(QName(kJabberNamespace, "iq"), true)); |
| 547 | 412 |
| 548 iq->SetAttr(QName(kEmptyNamespace, "id"), | 413 iq->SetAttr(QName(kEmptyNamespace, "id"), |
| 549 request_stanza->Attr(QName(kEmptyNamespace, "id"))); | 414 request_stanza->Attr(QName(kEmptyNamespace, "id"))); |
| 550 | 415 |
| 551 SignalingAddress original_from; | 416 SignalingAddress original_from; |
| 552 std::string error_message; | 417 std::string error_message; |
| 553 original_from = ParseAddress(request_stanza, true, &error_message); | 418 original_from = SignalingAddress::Parse( |
| 554 DCHECK(error_message.empty()); | 419 request_stanza, SignalingAddress::FROM, &error_message); |
| 420 DCHECK(!original_from.empty()); |
| 555 | 421 |
| 556 if (type == REPLY_RESULT) { | 422 if (type == REPLY_RESULT) { |
| 557 iq->SetAttr(QName(kEmptyNamespace, "type"), "result"); | 423 iq->SetAttr(QName(kEmptyNamespace, "type"), "result"); |
| 558 XmlElement* jingle = | 424 XmlElement* jingle = |
| 559 new XmlElement(QName(kJingleNamespace, "jingle"), true); | 425 new XmlElement(QName(kJingleNamespace, "jingle"), true); |
| 560 iq->AddElement(jingle); | 426 iq->AddElement(jingle); |
| 561 SetAddress(iq.get(), jingle, original_from, false); | 427 original_from.SetInMessage(iq.get(), SignalingAddress::TO); |
| 562 return iq; | 428 return iq; |
| 563 } | 429 } |
| 564 | 430 |
| 565 DCHECK_EQ(type, REPLY_ERROR); | 431 DCHECK_EQ(type, REPLY_ERROR); |
| 566 | 432 |
| 567 iq->SetAttr(QName(kEmptyNamespace, "type"), "error"); | 433 iq->SetAttr(QName(kEmptyNamespace, "type"), "error"); |
| 568 SetAddress(iq.get(), nullptr, original_from, false); | 434 original_from.SetInMessage(iq.get(), SignalingAddress::TO); |
| 569 | 435 |
| 570 for (const buzz::XmlElement* child = request_stanza->FirstElement(); | 436 for (const buzz::XmlElement* child = request_stanza->FirstElement(); |
| 571 child != nullptr; child = child->NextElement()) { | 437 child != nullptr; child = child->NextElement()) { |
| 572 iq->AddElement(new buzz::XmlElement(*child)); | 438 iq->AddElement(new buzz::XmlElement(*child)); |
| 573 } | 439 } |
| 574 | 440 |
| 575 buzz::XmlElement* error = | 441 buzz::XmlElement* error = |
| 576 new buzz::XmlElement(QName(kJabberNamespace, "error")); | 442 new buzz::XmlElement(QName(kJabberNamespace, "error")); |
| 577 iq->AddElement(error); | 443 iq->AddElement(error); |
| 578 | 444 |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 685 result->AddElement(FormatIceCredentials(credentials)); | 551 result->AddElement(FormatIceCredentials(credentials)); |
| 686 } | 552 } |
| 687 for (const NamedCandidate& candidate : candidates) { | 553 for (const NamedCandidate& candidate : candidates) { |
| 688 result->AddElement(FormatIceCandidate(candidate)); | 554 result->AddElement(FormatIceCandidate(candidate)); |
| 689 } | 555 } |
| 690 return result; | 556 return result; |
| 691 } | 557 } |
| 692 | 558 |
| 693 } // namespace protocol | 559 } // namespace protocol |
| 694 } // namespace remoting | 560 } // namespace remoting |
| OLD | NEW |