| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license | |
| 5 * that can be found in the LICENSE file in the root of the source | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 | |
| 11 #include "webrtc/libjingle/session/p2ptransportparser.h" | |
| 12 | |
| 13 #include <vector> | |
| 14 | |
| 15 #include "webrtc/p2p/base/constants.h" | |
| 16 #include "webrtc/libjingle/session/constants.h" | |
| 17 #include "webrtc/libjingle/session/parsing.h" | |
| 18 #include "webrtc/libjingle/session/sessionmanager.h" | |
| 19 #include "webrtc/libjingle/session/sessionmessages.h" | |
| 20 #include "webrtc/libjingle/xmllite/qname.h" | |
| 21 #include "webrtc/libjingle/xmllite/xmlelement.h" | |
| 22 #include "webrtc/libjingle/xmpp/constants.h" | |
| 23 #include "webrtc/base/base64.h" | |
| 24 #include "webrtc/base/common.h" | |
| 25 #include "webrtc/base/stringencode.h" | |
| 26 #include "webrtc/base/stringutils.h" | |
| 27 | |
| 28 namespace cricket { | |
| 29 | |
| 30 static buzz::XmlElement* NewTransportElement(const std::string& name) { | |
| 31 return new buzz::XmlElement(buzz::QName(name, LN_TRANSPORT), true); | |
| 32 } | |
| 33 | |
| 34 bool P2PTransportParser::ParseTransportDescription( | |
| 35 const buzz::XmlElement* elem, | |
| 36 const CandidateTranslator* translator, | |
| 37 TransportDescription* desc, | |
| 38 ParseError* error) { | |
| 39 ASSERT(elem->Name().LocalPart() == LN_TRANSPORT); | |
| 40 desc->transport_type = elem->Name().Namespace(); | |
| 41 if (desc->transport_type != NS_GINGLE_P2P) | |
| 42 return BadParse("Unsupported transport type", error); | |
| 43 | |
| 44 for (const buzz::XmlElement* candidate_elem = elem->FirstElement(); | |
| 45 candidate_elem != NULL; | |
| 46 candidate_elem = candidate_elem->NextElement()) { | |
| 47 // Only look at local part because the namespace might (eventually) | |
| 48 // be NS_GINGLE_P2P or NS_JINGLE_ICE_UDP. | |
| 49 if (candidate_elem->Name().LocalPart() == LN_CANDIDATE) { | |
| 50 Candidate candidate; | |
| 51 if (!ParseCandidate(ICEPROTO_GOOGLE, candidate_elem, translator, | |
| 52 &candidate, error)) { | |
| 53 return false; | |
| 54 } | |
| 55 | |
| 56 desc->candidates.push_back(candidate); | |
| 57 } | |
| 58 } | |
| 59 return true; | |
| 60 } | |
| 61 | |
| 62 bool P2PTransportParser::WriteTransportDescription( | |
| 63 const TransportDescription& desc, | |
| 64 const CandidateTranslator* translator, | |
| 65 buzz::XmlElement** out_elem, | |
| 66 WriteError* error) { | |
| 67 TransportProtocol proto = TransportProtocolFromDescription(&desc); | |
| 68 rtc::scoped_ptr<buzz::XmlElement> trans_elem( | |
| 69 NewTransportElement(desc.transport_type)); | |
| 70 | |
| 71 // Fail if we get HYBRID or ICE right now. | |
| 72 // TODO(juberti): Add ICE and HYBRID serialization. | |
| 73 if (proto != ICEPROTO_GOOGLE) { | |
| 74 LOG(LS_ERROR) << "Failed to serialize non-GICE TransportDescription"; | |
| 75 return false; | |
| 76 } | |
| 77 | |
| 78 for (std::vector<Candidate>::const_iterator iter = desc.candidates.begin(); | |
| 79 iter != desc.candidates.end(); ++iter) { | |
| 80 rtc::scoped_ptr<buzz::XmlElement> cand_elem( | |
| 81 new buzz::XmlElement(QN_GINGLE_P2P_CANDIDATE)); | |
| 82 if (!WriteCandidate(proto, *iter, translator, cand_elem.get(), error)) { | |
| 83 return false; | |
| 84 } | |
| 85 trans_elem->AddElement(cand_elem.release()); | |
| 86 } | |
| 87 | |
| 88 *out_elem = trans_elem.release(); | |
| 89 return true; | |
| 90 } | |
| 91 | |
| 92 bool P2PTransportParser::ParseGingleCandidate( | |
| 93 const buzz::XmlElement* elem, | |
| 94 const CandidateTranslator* translator, | |
| 95 Candidate* candidate, | |
| 96 ParseError* error) { | |
| 97 return ParseCandidate(ICEPROTO_GOOGLE, elem, translator, candidate, error); | |
| 98 } | |
| 99 | |
| 100 bool P2PTransportParser::WriteGingleCandidate( | |
| 101 const Candidate& candidate, | |
| 102 const CandidateTranslator* translator, | |
| 103 buzz::XmlElement** out_elem, | |
| 104 WriteError* error) { | |
| 105 rtc::scoped_ptr<buzz::XmlElement> elem( | |
| 106 new buzz::XmlElement(QN_GINGLE_CANDIDATE)); | |
| 107 bool ret = WriteCandidate(ICEPROTO_GOOGLE, candidate, translator, elem.get(), | |
| 108 error); | |
| 109 if (ret) { | |
| 110 *out_elem = elem.release(); | |
| 111 } | |
| 112 return ret; | |
| 113 } | |
| 114 | |
| 115 bool P2PTransportParser::VerifyUsernameFormat(TransportProtocol proto, | |
| 116 const std::string& username, | |
| 117 ParseError* error) { | |
| 118 if (proto == ICEPROTO_GOOGLE || proto == ICEPROTO_HYBRID) { | |
| 119 if (username.size() > GICE_UFRAG_MAX_LENGTH) | |
| 120 return BadParse("candidate username is too long", error); | |
| 121 if (!rtc::Base64::IsBase64Encoded(username)) | |
| 122 return BadParse("candidate username has non-base64 encoded characters", | |
| 123 error); | |
| 124 } else if (proto == ICEPROTO_RFC5245) { | |
| 125 if (username.size() > ICE_UFRAG_MAX_LENGTH) | |
| 126 return BadParse("candidate username is too long", error); | |
| 127 } | |
| 128 return true; | |
| 129 } | |
| 130 | |
| 131 bool P2PTransportParser::ParseCandidate(TransportProtocol proto, | |
| 132 const buzz::XmlElement* elem, | |
| 133 const CandidateTranslator* translator, | |
| 134 Candidate* candidate, | |
| 135 ParseError* error) { | |
| 136 ASSERT(proto == ICEPROTO_GOOGLE); | |
| 137 ASSERT(translator != NULL); | |
| 138 | |
| 139 if (!elem->HasAttr(buzz::QN_NAME) || | |
| 140 !elem->HasAttr(QN_ADDRESS) || | |
| 141 !elem->HasAttr(QN_PORT) || | |
| 142 !elem->HasAttr(QN_USERNAME) || | |
| 143 !elem->HasAttr(QN_PROTOCOL) || | |
| 144 !elem->HasAttr(QN_GENERATION)) { | |
| 145 return BadParse("candidate missing required attribute", error); | |
| 146 } | |
| 147 | |
| 148 rtc::SocketAddress address; | |
| 149 if (!ParseAddress(elem, QN_ADDRESS, QN_PORT, &address, error)) | |
| 150 return false; | |
| 151 | |
| 152 std::string channel_name = elem->Attr(buzz::QN_NAME); | |
| 153 int component = 0; | |
| 154 if (!translator || | |
| 155 !translator->GetComponentFromChannelName(channel_name, &component)) { | |
| 156 return BadParse("candidate has unknown channel name " + channel_name, | |
| 157 error); | |
| 158 } | |
| 159 | |
| 160 float preference = 0.0; | |
| 161 if (!GetXmlAttr(elem, QN_PREFERENCE, 0.0f, &preference)) { | |
| 162 return BadParse("candidate has unknown preference", error); | |
| 163 } | |
| 164 | |
| 165 candidate->set_component(component); | |
| 166 candidate->set_address(address); | |
| 167 candidate->set_username(elem->Attr(QN_USERNAME)); | |
| 168 candidate->set_preference(preference); | |
| 169 candidate->set_protocol(elem->Attr(QN_PROTOCOL)); | |
| 170 candidate->set_generation_str(elem->Attr(QN_GENERATION)); | |
| 171 if (elem->HasAttr(QN_PASSWORD)) | |
| 172 candidate->set_password(elem->Attr(QN_PASSWORD)); | |
| 173 if (elem->HasAttr(buzz::QN_TYPE)) | |
| 174 candidate->set_type(elem->Attr(buzz::QN_TYPE)); | |
| 175 if (elem->HasAttr(QN_NETWORK)) | |
| 176 candidate->set_network_name(elem->Attr(QN_NETWORK)); | |
| 177 | |
| 178 if (!VerifyUsernameFormat(proto, candidate->username(), error)) | |
| 179 return false; | |
| 180 | |
| 181 return true; | |
| 182 } | |
| 183 | |
| 184 bool P2PTransportParser::WriteCandidate(TransportProtocol proto, | |
| 185 const Candidate& candidate, | |
| 186 const CandidateTranslator* translator, | |
| 187 buzz::XmlElement* elem, | |
| 188 WriteError* error) { | |
| 189 ASSERT(proto == ICEPROTO_GOOGLE); | |
| 190 ASSERT(translator != NULL); | |
| 191 | |
| 192 std::string channel_name; | |
| 193 if (!translator || | |
| 194 !translator->GetChannelNameFromComponent( | |
| 195 candidate.component(), &channel_name)) { | |
| 196 return BadWrite("Cannot write candidate because of unknown component.", | |
| 197 error); | |
| 198 } | |
| 199 | |
| 200 elem->SetAttr(buzz::QN_NAME, channel_name); | |
| 201 elem->SetAttr(QN_ADDRESS, candidate.address().ipaddr().ToString()); | |
| 202 elem->SetAttr(QN_PORT, candidate.address().PortAsString()); | |
| 203 AddXmlAttr(elem, QN_PREFERENCE, candidate.preference()); | |
| 204 elem->SetAttr(QN_USERNAME, candidate.username()); | |
| 205 elem->SetAttr(QN_PROTOCOL, candidate.protocol()); | |
| 206 elem->SetAttr(QN_GENERATION, candidate.generation_str()); | |
| 207 if (!candidate.password().empty()) | |
| 208 elem->SetAttr(QN_PASSWORD, candidate.password()); | |
| 209 elem->SetAttr(buzz::QN_TYPE, candidate.type()); | |
| 210 if (!candidate.network_name().empty()) | |
| 211 elem->SetAttr(QN_NETWORK, candidate.network_name()); | |
| 212 | |
| 213 return true; | |
| 214 } | |
| 215 | |
| 216 } // namespace cricket | |
| OLD | NEW |