| 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 |