blob: ea095c36d55b9c96f6571557f271532c1c2fb381 [file] [log] [blame]
// 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/protocol/pepper_session_manager.h"
#include "base/bind.h"
#include "remoting/jingle_glue/iq_sender.h"
#include "remoting/jingle_glue/jingle_info_request.h"
#include "remoting/jingle_glue/signal_strategy.h"
#include "remoting/protocol/jingle_messages.h"
#include "remoting/protocol/pepper_session.h"
#include "third_party/libjingle/source/talk/base/socketaddress.h"
#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
using buzz::QName;
namespace remoting {
namespace protocol {
PepperSessionManager::PepperSessionManager(pp::Instance* pp_instance)
: pp_instance_(pp_instance),
signal_strategy_(NULL),
listener_(NULL),
allow_nat_traversal_(false) {
}
PepperSessionManager::~PepperSessionManager() {
Close();
}
void PepperSessionManager::Init(
const std::string& local_jid,
SignalStrategy* signal_strategy,
SessionManager::Listener* listener,
crypto::RSAPrivateKey* private_key,
const std::string& certificate,
bool allow_nat_traversal) {
listener_ = listener;
local_jid_ = local_jid;
signal_strategy_ = signal_strategy;
iq_sender_.reset(new IqSender(signal_strategy_));
private_key_.reset(private_key);
certificate_ = certificate;
allow_nat_traversal_ = allow_nat_traversal;
signal_strategy_->AddListener(this);
// If NAT traversal is enabled then we need to request STUN/Relay info.
if (allow_nat_traversal) {
jingle_info_request_.reset(new JingleInfoRequest(signal_strategy_));
jingle_info_request_->Send(base::Bind(&PepperSessionManager::OnJingleInfo,
base::Unretained(this)));
} else {
listener_->OnSessionManagerInitialized();
}
}
void PepperSessionManager::OnJingleInfo(
const std::string& relay_token,
const std::vector<std::string>& relay_hosts,
const std::vector<talk_base::SocketAddress>& stun_hosts) {
DCHECK(CalledOnValidThread());
// TODO(sergeyu): Add support for multiple STUN/relay servers when
// it's implemented in libjingle and P2P Transport API.
transport_config_.stun_server = stun_hosts[0].ToString();
transport_config_.relay_server = relay_hosts[0];
transport_config_.relay_token = relay_token;
VLOG(1) << "STUN server: " << transport_config_.stun_server
<< " Relay server: " << transport_config_.relay_server
<< " Relay token: " << transport_config_.relay_token;
listener_->OnSessionManagerInitialized();
}
Session* PepperSessionManager::Connect(
const std::string& host_jid,
const std::string& host_public_key,
const std::string& client_token,
CandidateSessionConfig* config,
const Session::StateChangeCallback& state_change_callback) {
PepperSession* session = new PepperSession(this);
session->StartConnection(host_jid, host_public_key, client_token,
config, state_change_callback);
sessions_[session->session_id_] = session;
return session;
}
void PepperSessionManager::Close() {
DCHECK(CalledOnValidThread());
// Close() can be called only after all sessions are destroyed.
DCHECK(sessions_.empty());
listener_ = NULL;
jingle_info_request_.reset();
signal_strategy_->RemoveListener(this);
}
bool PepperSessionManager::OnIncomingStanza(const buzz::XmlElement* stanza) {
if (!JingleMessage::IsJingleMessage(stanza))
return false;
JingleMessage message;
std::string error;
if (!message.ParseXml(stanza, &error)) {
SendReply(stanza, JingleMessageReply(JingleMessageReply::BAD_REQUEST));
return true;
}
if (message.action == JingleMessage::SESSION_INITIATE) {
SendReply(stanza, JingleMessageReply(
JingleMessageReply::NOT_IMPLEMENTED,
"Can't accept sessions on the client"));
return true;
}
SessionsMap::iterator it = sessions_.find(message.sid);
if (it == sessions_.end()) {
SendReply(stanza, JingleMessageReply(JingleMessageReply::INVALID_SID));
return true;
}
JingleMessageReply reply;
it->second->OnIncomingMessage(message, &reply);
SendReply(stanza, reply);
return true;
}
void PepperSessionManager::SendReply(const buzz::XmlElement* original_stanza,
const JingleMessageReply& reply) {
buzz::XmlElement* stanza = reply.ToXml(original_stanza);
signal_strategy_->SendStanza(stanza);
}
void PepperSessionManager::SessionDestroyed(PepperSession* session) {
sessions_.erase(session->session_id_);
}
} // namespace protocol
} // namespace remoting