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 |