Index: remoting/jingle_glue/jingle_client.cc |
diff --git a/remoting/jingle_glue/jingle_client.cc b/remoting/jingle_glue/jingle_client.cc |
index 938664eed1ecbbe4fa880c74720f2aba8a96e018..01e607bb30fa407a8fab587dc65c148c4b4c1742 100644 |
--- a/remoting/jingle_glue/jingle_client.cc |
+++ b/remoting/jingle_glue/jingle_client.cc |
@@ -2,9 +2,6 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-// TODO(ajwong): We assign and read from a few of the member variables on |
-// two threads. We need to audit this for thread safety. |
- |
#include "remoting/jingle_glue/jingle_client.h" |
#include "base/logging.h" |
@@ -17,92 +14,64 @@ |
#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" |
-#ifdef USE_SSL_TUNNEL |
-#include "third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.h" |
-#endif |
#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 { |
+namespace { |
+// A TunnelSessionClient that allows local connections. |
+class LocalTunnelSessionClient : public cricket::TunnelSessionClient { |
+ public: |
+ LocalTunnelSessionClient(const buzz::Jid& jid, |
+ cricket::SessionManager* manager) |
+ : TunnelSessionClient(jid, manager) { |
+ } |
+ |
+ protected: |
+ virtual cricket::TunnelSession* MakeTunnelSession( |
+ cricket::Session* session, talk_base::Thread* stream_thread, |
+ cricket::TunnelSessionRole role) { |
+ session->transport()->set_allow_local_ips(true); |
+ return new cricket::TunnelSession(this, session, stream_thread); |
+ } |
+}; |
+} // namespace |
+ |
JingleClient::JingleClient(JingleThread* thread) |
- : client_(NULL), |
- thread_(thread), |
- state_(CREATED), |
- callback_(NULL) { |
+ : thread_(thread), |
+ callback_(NULL), |
+ client_(NULL), |
+ state_(START), |
+ initialized_(false), |
+ closed_(false) { |
} |
JingleClient::~JingleClient() { |
- // JingleClient can be destroyed only after it's closed. |
- DCHECK(state_ == CLOSED || state_ == CREATED); |
+ 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, ""); |
- DCHECK(callback != NULL); |
- DCHECK(state_ == CREATED); |
- |
- callback_ = callback; |
- message_loop()->PostTask( |
- FROM_HERE, NewRunnableMethod(this, &JingleClient::DoInitialize, |
- username, auth_token, auth_token_service)); |
- state_ = INITIALIZED; |
-} |
- |
-JingleChannel* JingleClient::Connect(const std::string& host_jid, |
- JingleChannel::Callback* callback) { |
- // Ownership if channel is given to DoConnect. |
- scoped_refptr<JingleChannel> channel = new JingleChannel(callback); |
- message_loop()->PostTask( |
- FROM_HERE, NewRunnableMethod(this, &JingleClient::DoConnect, |
- channel, host_jid, callback)); |
- return channel; |
-} |
- |
-void JingleClient::DoConnect(scoped_refptr<JingleChannel> channel, |
- const std::string& host_jid, |
- JingleChannel::Callback* callback) { |
- DCHECK_EQ(message_loop(), MessageLoop::current()); |
- |
- talk_base::StreamInterface* stream = |
- tunnel_session_client_->CreateTunnel(buzz::Jid(host_jid), ""); |
- DCHECK(stream != NULL); |
- channel->Init(thread_, stream, host_jid); |
-} |
+ { |
+ AutoLock auto_lock(state_lock_); |
+ DCHECK(!initialized_ && !closed_); |
+ initialized_ = true; |
-void JingleClient::Close() { |
- // Once we are closed we really shouldn't talk to the callback again. In the |
- // case when JingleClient outlives the owner access the callback is not safe. |
- // TODO(hclam): We need to lock to reset callback. |
- callback_ = NULL; |
+ DCHECK(callback != NULL); |
+ callback_ = callback; |
+ } |
message_loop()->PostTask( |
- FROM_HERE, NewRunnableMethod(this, &JingleClient::DoClose)); |
-} |
- |
-void JingleClient::DoClose() { |
- DCHECK_EQ(message_loop(), MessageLoop::current()); |
- |
- // If we have not yet initialized and the client is already closed then |
- // don't close again. |
- if (state_ == CLOSED) |
- return; |
- |
- if (client_) { |
- client_->Disconnect(); |
- // Client is deleted by TaskRunner. |
- client_ = NULL; |
- } |
- tunnel_session_client_.reset(); |
- port_allocator_.reset(); |
- session_manager_.reset(); |
- network_manager_.reset(); |
- UpdateState(CLOSED); |
+ FROM_HERE, NewRunnableMethod(this, &JingleClient::DoInitialize, |
+ username, auth_token, auth_token_service)); |
} |
void JingleClient::DoInitialize(const std::string& username, |
@@ -138,18 +107,10 @@ void JingleClient::DoInitialize(const std::string& username, |
port_allocator->SetJingleInfo(client_); |
session_manager_.reset(new cricket::SessionManager(port_allocator_.get())); |
-#ifdef USE_SSL_TUNNEL |
- cricket::SecureTunnelSessionClient* session_client = |
- new cricket::SecureTunnelSessionClient(client_->jid(), |
- session_manager_.get()); |
- if (!session_client->GenerateIdentity()) |
- return false; |
- tunnel_session_client_.reset(session_client); |
-#else // !USE_SSL_TUNNEL |
+ |
tunnel_session_client_.reset( |
- new cricket::TunnelSessionClient(client_->jid(), |
- session_manager_.get())); |
-#endif // USE_SSL_TUNNEL |
+ new LocalTunnelSessionClient(client_->jid(), |
+ session_manager_.get())); |
cricket::SessionManagerTask* receiver = |
new cricket::SessionManagerTask(client_, session_manager_.get()); |
@@ -160,6 +121,72 @@ void JingleClient::DoInitialize(const std::string& username, |
this, &JingleClient::OnIncomingTunnel); |
} |
+JingleChannel* JingleClient::Connect(const std::string& host_jid, |
+ JingleChannel::Callback* callback) { |
+ DCHECK(initialized_ && !closed_); |
+ |
+ // Ownership if channel is given to DoConnect. |
+ scoped_refptr<JingleChannel> channel = new JingleChannel(callback); |
+ message_loop()->PostTask( |
+ FROM_HERE, NewRunnableMethod(this, &JingleClient::DoConnect, |
+ channel, host_jid, callback)); |
+ return channel; |
+} |
+ |
+void JingleClient::DoConnect(scoped_refptr<JingleChannel> channel, |
+ const std::string& host_jid, |
+ JingleChannel::Callback* callback) { |
+ DCHECK_EQ(message_loop(), MessageLoop::current()); |
+ |
+ talk_base::StreamInterface* stream = |
+ tunnel_session_client_->CreateTunnel(buzz::Jid(host_jid), ""); |
+ DCHECK(stream != NULL); |
+ |
+ channel->Init(thread_, stream, host_jid); |
+} |
+ |
+void JingleClient::Close() { |
+ Close(NULL); |
+} |
+ |
+void JingleClient::Close(Task* closed_task) { |
+ { |
+ 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_); |
+ |
+ tunnel_session_client_.reset(); |
+ 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() { |
AutoLock auto_lock(full_jid_lock_); |
return full_jid_; |
@@ -176,7 +203,7 @@ MessageLoop* JingleClient::message_loop() { |
void JingleClient::OnConnectionStateChanged(buzz::XmppEngine::State state) { |
switch (state) { |
case buzz::XmppEngine::STATE_START: |
- UpdateState(INITIALIZED); |
+ UpdateState(START); |
break; |
case buzz::XmppEngine::STATE_OPENING: |
UpdateState(CONNECTING); |
@@ -200,8 +227,11 @@ void JingleClient::OnConnectionStateChanged(buzz::XmppEngine::State state) { |
void JingleClient::OnIncomingTunnel( |
cricket::TunnelSessionClient* client, buzz::Jid jid, |
std::string description, cricket::Session* session) { |
- // Decline connection if we don't have callback. |
- if (!callback_) { |
+ // Must always lock state and check closed_ when calling callback. |
+ AutoLock auto_lock(state_lock_); |
+ |
+ if (closed_) { |
+ // Always reject connection if we are closed. |
client->DeclineTunnel(session); |
return; |
} |
@@ -221,8 +251,11 @@ void JingleClient::OnIncomingTunnel( |
void JingleClient::UpdateState(State new_state) { |
if (new_state != state_) { |
state_ = new_state; |
- if (callback_) |
- callback_->OnStateChange(this, new_state); |
+ { |
+ AutoLock auto_lock(state_lock_); |
+ if (!closed_) |
+ callback_->OnStateChange(this, new_state); |
+ } |
} |
} |