// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "remoting/jingle_glue/jingle_signaling_connector.h" #include "base/logging.h" #include "base/stl_util.h" #include "third_party/libjingle/source/talk/p2p/base/sessionmanager.h" #include "third_party/libjingle/source/talk/xmpp/constants.h" #include "third_party/libjingle/source/talk/xmpp/xmppclient.h" namespace remoting { namespace { // GTalk sometimes generates service-unavailable error messages with // incorrect namespace. This method fixes such messages. // TODO(sergeyu): Fix this on the server side. void FixErrorStanza(buzz::XmlElement* stanza) { if (!stanza->FirstNamed(buzz::QN_ERROR)) { buzz::XmlElement* error = stanza->FirstNamed(buzz::QName("", "error")); error->SetName(buzz::QN_ERROR); } } } // namespace JingleSignalingConnector::JingleSignalingConnector( SignalStrategy* signal_strategy, cricket::SessionManager* session_manager) : signal_strategy_(signal_strategy), session_manager_(session_manager) { session_manager_->SignalOutgoingMessage.connect( this, &JingleSignalingConnector::OnOutgoingMessage); signal_strategy_->AddListener(this); // Assume that signaling is ready from the beginning. session_manager_->SignalRequestSignaling.connect( session_manager_, &cricket::SessionManager::OnSignalingReady); } JingleSignalingConnector::~JingleSignalingConnector() { signal_strategy_->RemoveListener(this); STLDeleteContainerPairSecondPointers(pending_requests_.begin(), pending_requests_.end()); } void JingleSignalingConnector::OnSignalStrategyStateChange( SignalStrategy::State state) { } bool JingleSignalingConnector::OnSignalStrategyIncomingStanza( const buzz::XmlElement* stanza) { if (session_manager_->IsSessionMessage(stanza)) { session_manager_->OnIncomingMessage(stanza); return true; } if (stanza->Name() == buzz::QN_IQ) { std::string type = stanza->Attr(buzz::QN_TYPE); std::string id = stanza->Attr(buzz::QN_ID); if ((type == "error" || type == "result") && !id.empty()) { IqRequestsMap::iterator it = pending_requests_.find(id); if (it != pending_requests_.end()) { if (type == "result") { session_manager_->OnIncomingResponse(it->second, stanza); } else { scoped_ptr stanza_copy( new buzz::XmlElement(*stanza)); FixErrorStanza(stanza_copy.get()); session_manager_->OnFailedSend(it->second, stanza_copy.get()); } delete it->second; pending_requests_.erase(it); return true; } } } return false; } void JingleSignalingConnector::OnOutgoingMessage( cricket::SessionManager* session_manager, const buzz::XmlElement* stanza) { DCHECK_EQ(session_manager, session_manager_); scoped_ptr stanza_copy(new buzz::XmlElement(*stanza)); if (stanza_copy->Name() == buzz::QN_IQ) { std::string type = stanza_copy->Attr(buzz::QN_TYPE); if (type == "set" || type == "get") { std::string id = stanza_copy->Attr(buzz::QN_ID); // Add ID attribute for set and get stanzas if it is not there. if (id.empty()) { id = signal_strategy_->GetNextId(); stanza_copy->SetAttr(buzz::QN_ID, id); } // Save the outgoing request for OnIncomingResponse(). pending_requests_[id] = new buzz::XmlElement(*stanza); } } signal_strategy_->SendStanza(stanza_copy.release()); } } // namespace remoting