// Copyright (c) 2010 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_client.h" #include "base/logging.h" #include "base/message_loop.h" #include "jingle/notifier/communicator/gaia_token_pre_xmpp_auth.h" #include "remoting/jingle_glue/iq_request.h" #include "remoting/jingle_glue/jingle_thread.h" #include "remoting/jingle_glue/relay_port_allocator.h" #include "remoting/jingle_glue/xmpp_socket_adapter.h" #include "third_party/libjingle/source/talk/base/asyncsocket.h" #include "third_party/libjingle/source/talk/base/ssladapter.h" #include "third_party/libjingle/source/talk/p2p/base/sessionmanager.h" #include "third_party/libjingle/source/talk/p2p/base/transport.h" #include "third_party/libjingle/source/talk/p2p/client/sessionmanagertask.h" #include "third_party/libjingle/source/talk/session/tunnel/tunnelsessionclient.h" #include "third_party/libjingle/source/talk/xmpp/prexmppauth.h" #include "third_party/libjingle/source/talk/xmpp/saslcookiemechanism.h" namespace remoting { JingleClient::JingleClient(JingleThread* thread) : thread_(thread), callback_(NULL), client_(NULL), state_(START), initialized_(false), closed_(false) { } JingleClient::~JingleClient() { base::AutoLock auto_lock(state_lock_); DCHECK(!initialized_ || closed_); } void JingleClient::Init( const std::string& username, const std::string& auth_token, const std::string& auth_token_service, Callback* callback) { DCHECK_NE(username, ""); { base::AutoLock auto_lock(state_lock_); DCHECK(!initialized_ && !closed_); initialized_ = true; DCHECK(callback != NULL); callback_ = callback; } message_loop()->PostTask( FROM_HERE, NewRunnableMethod(this, &JingleClient::DoInitialize, username, auth_token, auth_token_service)); } void JingleClient::DoInitialize(const std::string& username, const std::string& auth_token, const std::string& auth_token_service) { DCHECK_EQ(message_loop(), MessageLoop::current()); buzz::Jid login_jid(username); buzz::XmppClientSettings settings; settings.set_user(login_jid.node()); settings.set_host(login_jid.domain()); settings.set_resource("chromoting"); settings.set_use_tls(true); settings.set_token_service(auth_token_service); settings.set_auth_cookie(auth_token); settings.set_server(talk_base::SocketAddress("talk.google.com", 5222)); client_ = new buzz::XmppClient(thread_->task_pump()); client_->SignalStateChange.connect( this, &JingleClient::OnConnectionStateChanged); buzz::AsyncSocket* socket = new XmppSocketAdapter(settings, false); client_->Connect(settings, "", socket, CreatePreXmppAuth(settings)); client_->Start(); network_manager_.reset(new talk_base::NetworkManager()); RelayPortAllocator* port_allocator = new RelayPortAllocator(network_manager_.get(), "transp2"); port_allocator_.reset(port_allocator); port_allocator->SetJingleInfo(client_); session_manager_.reset(new cricket::SessionManager(port_allocator_.get())); cricket::SessionManagerTask* receiver = new cricket::SessionManagerTask(client_, session_manager_.get()); receiver->EnableOutgoingMessages(); receiver->Start(); } void JingleClient::Close() { Close(NULL); } void JingleClient::Close(Task* closed_task) { { base::AutoLock auto_lock(state_lock_); // If the client is already closed then don't close again. if (closed_) { if (closed_task) thread_->message_loop()->PostTask(FROM_HERE, closed_task); return; } closed_task_.reset(closed_task); closed_ = true; } message_loop()->PostTask( FROM_HERE, NewRunnableMethod(this, &JingleClient::DoClose)); } void JingleClient::DoClose() { DCHECK_EQ(message_loop(), MessageLoop::current()); DCHECK(closed_); session_manager_.reset(); port_allocator_.reset(); network_manager_.reset(); if (client_) { client_->Disconnect(); // Client is deleted by TaskRunner. client_ = NULL; } if (closed_task_.get()) { closed_task_->Run(); closed_task_.reset(); } } std::string JingleClient::GetFullJid() { base::AutoLock auto_lock(full_jid_lock_); return full_jid_; } IqRequest* JingleClient::CreateIqRequest() { return new IqRequest(this); } MessageLoop* JingleClient::message_loop() { return thread_->message_loop(); } cricket::SessionManager* JingleClient::session_manager() { DCHECK_EQ(message_loop(), MessageLoop::current()); return session_manager_.get(); } void JingleClient::OnConnectionStateChanged(buzz::XmppEngine::State state) { switch (state) { case buzz::XmppEngine::STATE_START: UpdateState(START); break; case buzz::XmppEngine::STATE_OPENING: UpdateState(CONNECTING); break; case buzz::XmppEngine::STATE_OPEN: SetFullJid(client_->jid().Str()); UpdateState(CONNECTED); break; case buzz::XmppEngine::STATE_CLOSED: UpdateState(CLOSED); // Client is destroyed by the TaskRunner after the client is // closed. Reset the pointer so we don't try to use it later. client_ = NULL; break; default: NOTREACHED(); break; } } void JingleClient::SetFullJid(const std::string& full_jid) { base::AutoLock auto_lock(full_jid_lock_); full_jid_ = full_jid; } void JingleClient::UpdateState(State new_state) { if (new_state != state_) { state_ = new_state; { // We have to have the lock held, otherwise we cannot be sure that // the client hasn't been closed when we call the callback. base::AutoLock auto_lock(state_lock_); if (!closed_) callback_->OnStateChange(this, new_state); } } } buzz::PreXmppAuth* JingleClient::CreatePreXmppAuth( const buzz::XmppClientSettings& settings) { buzz::Jid jid(settings.user(), settings.host(), buzz::STR_EMPTY); return new notifier::GaiaTokenPreXmppAuth(jid.Str(), settings.auth_cookie(), settings.token_service()); } } // namespace remoting