| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // TODO(ajwong): We assign and read from a few of the member variables on | |
| 6 // two threads. We need to audit this for thread safety. | |
| 7 | |
| 8 #include "remoting/jingle_glue/jingle_client.h" | 5 #include "remoting/jingle_glue/jingle_client.h" |
| 9 | 6 |
| 10 #include "base/logging.h" | 7 #include "base/logging.h" |
| 11 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
| 12 #include "jingle/notifier/communicator/gaia_token_pre_xmpp_auth.h" | 9 #include "jingle/notifier/communicator/gaia_token_pre_xmpp_auth.h" |
| 13 #include "jingle/notifier/communicator/xmpp_socket_adapter.h" | 10 #include "jingle/notifier/communicator/xmpp_socket_adapter.h" |
| 14 #include "remoting/jingle_glue/iq_request.h" | 11 #include "remoting/jingle_glue/iq_request.h" |
| 15 #include "remoting/jingle_glue/jingle_thread.h" | 12 #include "remoting/jingle_glue/jingle_thread.h" |
| 16 #include "remoting/jingle_glue/relay_port_allocator.h" | 13 #include "remoting/jingle_glue/relay_port_allocator.h" |
| 17 #include "third_party/libjingle/source/talk/base/asyncsocket.h" | 14 #include "third_party/libjingle/source/talk/base/asyncsocket.h" |
| 18 #include "third_party/libjingle/source/talk/base/ssladapter.h" | 15 #include "third_party/libjingle/source/talk/base/ssladapter.h" |
| 19 #include "third_party/libjingle/source/talk/p2p/base/sessionmanager.h" | 16 #include "third_party/libjingle/source/talk/p2p/base/sessionmanager.h" |
| 17 #include "third_party/libjingle/source/talk/p2p/base/transport.h" |
| 20 #include "third_party/libjingle/source/talk/p2p/client/sessionmanagertask.h" | 18 #include "third_party/libjingle/source/talk/p2p/client/sessionmanagertask.h" |
| 21 #ifdef USE_SSL_TUNNEL | |
| 22 #include "third_party/libjingle/source/talk/session/tunnel/securetunnelsessioncl
ient.h" | |
| 23 #endif | |
| 24 #include "third_party/libjingle/source/talk/session/tunnel/tunnelsessionclient.h
" | 19 #include "third_party/libjingle/source/talk/session/tunnel/tunnelsessionclient.h
" |
| 25 #include "third_party/libjingle/source/talk/xmpp/prexmppauth.h" | 20 #include "third_party/libjingle/source/talk/xmpp/prexmppauth.h" |
| 26 #include "third_party/libjingle/source/talk/xmpp/saslcookiemechanism.h" | 21 #include "third_party/libjingle/source/talk/xmpp/saslcookiemechanism.h" |
| 27 | 22 |
| 28 namespace remoting { | 23 namespace remoting { |
| 29 | 24 |
| 25 namespace { |
| 26 // A TunnelSessionClient that allows local connections. |
| 27 class LocalTunnelSessionClient : public cricket::TunnelSessionClient { |
| 28 public: |
| 29 LocalTunnelSessionClient(const buzz::Jid& jid, |
| 30 cricket::SessionManager* manager) |
| 31 : TunnelSessionClient(jid, manager) { |
| 32 } |
| 33 |
| 34 protected: |
| 35 virtual cricket::TunnelSession* MakeTunnelSession( |
| 36 cricket::Session* session, talk_base::Thread* stream_thread, |
| 37 cricket::TunnelSessionRole role) { |
| 38 session->transport()->set_allow_local_ips(true); |
| 39 return new cricket::TunnelSession(this, session, stream_thread); |
| 40 } |
| 41 }; |
| 42 } // namespace |
| 43 |
| 30 JingleClient::JingleClient(JingleThread* thread) | 44 JingleClient::JingleClient(JingleThread* thread) |
| 31 : client_(NULL), | 45 : thread_(thread), |
| 32 thread_(thread), | 46 callback_(NULL), |
| 33 state_(CREATED), | 47 client_(NULL), |
| 34 callback_(NULL) { | 48 state_(START), |
| 49 initialized_(false), |
| 50 closed_(false) { |
| 35 } | 51 } |
| 36 | 52 |
| 37 JingleClient::~JingleClient() { | 53 JingleClient::~JingleClient() { |
| 38 // JingleClient can be destroyed only after it's closed. | 54 AutoLock auto_lock(state_lock_); |
| 39 DCHECK(state_ == CLOSED || state_ == CREATED); | 55 DCHECK(!initialized_ || closed_); |
| 40 } | 56 } |
| 41 | 57 |
| 42 void JingleClient::Init( | 58 void JingleClient::Init( |
| 43 const std::string& username, const std::string& auth_token, | 59 const std::string& username, const std::string& auth_token, |
| 44 const std::string& auth_token_service, Callback* callback) { | 60 const std::string& auth_token_service, Callback* callback) { |
| 45 DCHECK_NE(username, ""); | 61 DCHECK_NE(username, ""); |
| 46 DCHECK(callback != NULL); | |
| 47 DCHECK(state_ == CREATED); | |
| 48 | 62 |
| 49 callback_ = callback; | 63 { |
| 64 AutoLock auto_lock(state_lock_); |
| 65 DCHECK(!initialized_ && !closed_); |
| 66 initialized_ = true; |
| 67 |
| 68 DCHECK(callback != NULL); |
| 69 callback_ = callback; |
| 70 } |
| 71 |
| 50 message_loop()->PostTask( | 72 message_loop()->PostTask( |
| 51 FROM_HERE, NewRunnableMethod(this, &JingleClient::DoInitialize, | 73 FROM_HERE, NewRunnableMethod(this, &JingleClient::DoInitialize, |
| 52 username, auth_token, auth_token_service)); | 74 username, auth_token, auth_token_service)); |
| 53 state_ = INITIALIZED; | |
| 54 } | |
| 55 | |
| 56 JingleChannel* JingleClient::Connect(const std::string& host_jid, | |
| 57 JingleChannel::Callback* callback) { | |
| 58 // Ownership if channel is given to DoConnect. | |
| 59 scoped_refptr<JingleChannel> channel = new JingleChannel(callback); | |
| 60 message_loop()->PostTask( | |
| 61 FROM_HERE, NewRunnableMethod(this, &JingleClient::DoConnect, | |
| 62 channel, host_jid, callback)); | |
| 63 return channel; | |
| 64 } | |
| 65 | |
| 66 void JingleClient::DoConnect(scoped_refptr<JingleChannel> channel, | |
| 67 const std::string& host_jid, | |
| 68 JingleChannel::Callback* callback) { | |
| 69 DCHECK_EQ(message_loop(), MessageLoop::current()); | |
| 70 | |
| 71 talk_base::StreamInterface* stream = | |
| 72 tunnel_session_client_->CreateTunnel(buzz::Jid(host_jid), ""); | |
| 73 DCHECK(stream != NULL); | |
| 74 | |
| 75 channel->Init(thread_, stream, host_jid); | |
| 76 } | |
| 77 | |
| 78 void JingleClient::Close() { | |
| 79 // Once we are closed we really shouldn't talk to the callback again. In the | |
| 80 // case when JingleClient outlives the owner access the callback is not safe. | |
| 81 // TODO(hclam): We need to lock to reset callback. | |
| 82 callback_ = NULL; | |
| 83 | |
| 84 message_loop()->PostTask( | |
| 85 FROM_HERE, NewRunnableMethod(this, &JingleClient::DoClose)); | |
| 86 } | |
| 87 | |
| 88 void JingleClient::DoClose() { | |
| 89 DCHECK_EQ(message_loop(), MessageLoop::current()); | |
| 90 | |
| 91 // If we have not yet initialized and the client is already closed then | |
| 92 // don't close again. | |
| 93 if (state_ == CLOSED) | |
| 94 return; | |
| 95 | |
| 96 if (client_) { | |
| 97 client_->Disconnect(); | |
| 98 // Client is deleted by TaskRunner. | |
| 99 client_ = NULL; | |
| 100 } | |
| 101 tunnel_session_client_.reset(); | |
| 102 port_allocator_.reset(); | |
| 103 session_manager_.reset(); | |
| 104 network_manager_.reset(); | |
| 105 UpdateState(CLOSED); | |
| 106 } | 75 } |
| 107 | 76 |
| 108 void JingleClient::DoInitialize(const std::string& username, | 77 void JingleClient::DoInitialize(const std::string& username, |
| 109 const std::string& auth_token, | 78 const std::string& auth_token, |
| 110 const std::string& auth_token_service) { | 79 const std::string& auth_token_service) { |
| 111 DCHECK_EQ(message_loop(), MessageLoop::current()); | 80 DCHECK_EQ(message_loop(), MessageLoop::current()); |
| 112 | 81 |
| 113 buzz::Jid login_jid(username); | 82 buzz::Jid login_jid(username); |
| 114 | 83 |
| 115 buzz::XmppClientSettings settings; | 84 buzz::XmppClientSettings settings; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 131 client_->Start(); | 100 client_->Start(); |
| 132 | 101 |
| 133 network_manager_.reset(new talk_base::NetworkManager()); | 102 network_manager_.reset(new talk_base::NetworkManager()); |
| 134 | 103 |
| 135 RelayPortAllocator* port_allocator = | 104 RelayPortAllocator* port_allocator = |
| 136 new RelayPortAllocator(network_manager_.get(), "transp2"); | 105 new RelayPortAllocator(network_manager_.get(), "transp2"); |
| 137 port_allocator_.reset(port_allocator); | 106 port_allocator_.reset(port_allocator); |
| 138 port_allocator->SetJingleInfo(client_); | 107 port_allocator->SetJingleInfo(client_); |
| 139 | 108 |
| 140 session_manager_.reset(new cricket::SessionManager(port_allocator_.get())); | 109 session_manager_.reset(new cricket::SessionManager(port_allocator_.get())); |
| 141 #ifdef USE_SSL_TUNNEL | 110 |
| 142 cricket::SecureTunnelSessionClient* session_client = | |
| 143 new cricket::SecureTunnelSessionClient(client_->jid(), | |
| 144 session_manager_.get()); | |
| 145 if (!session_client->GenerateIdentity()) | |
| 146 return false; | |
| 147 tunnel_session_client_.reset(session_client); | |
| 148 #else // !USE_SSL_TUNNEL | |
| 149 tunnel_session_client_.reset( | 111 tunnel_session_client_.reset( |
| 150 new cricket::TunnelSessionClient(client_->jid(), | 112 new LocalTunnelSessionClient(client_->jid(), |
| 151 session_manager_.get())); | 113 session_manager_.get())); |
| 152 #endif // USE_SSL_TUNNEL | |
| 153 | 114 |
| 154 cricket::SessionManagerTask* receiver = | 115 cricket::SessionManagerTask* receiver = |
| 155 new cricket::SessionManagerTask(client_, session_manager_.get()); | 116 new cricket::SessionManagerTask(client_, session_manager_.get()); |
| 156 receiver->EnableOutgoingMessages(); | 117 receiver->EnableOutgoingMessages(); |
| 157 receiver->Start(); | 118 receiver->Start(); |
| 158 | 119 |
| 159 tunnel_session_client_->SignalIncomingTunnel.connect( | 120 tunnel_session_client_->SignalIncomingTunnel.connect( |
| 160 this, &JingleClient::OnIncomingTunnel); | 121 this, &JingleClient::OnIncomingTunnel); |
| 161 } | 122 } |
| 162 | 123 |
| 124 JingleChannel* JingleClient::Connect(const std::string& host_jid, |
| 125 JingleChannel::Callback* callback) { |
| 126 DCHECK(initialized_ && !closed_); |
| 127 |
| 128 // Ownership if channel is given to DoConnect. |
| 129 scoped_refptr<JingleChannel> channel = new JingleChannel(callback); |
| 130 message_loop()->PostTask( |
| 131 FROM_HERE, NewRunnableMethod(this, &JingleClient::DoConnect, |
| 132 channel, host_jid, callback)); |
| 133 return channel; |
| 134 } |
| 135 |
| 136 void JingleClient::DoConnect(scoped_refptr<JingleChannel> channel, |
| 137 const std::string& host_jid, |
| 138 JingleChannel::Callback* callback) { |
| 139 DCHECK_EQ(message_loop(), MessageLoop::current()); |
| 140 |
| 141 talk_base::StreamInterface* stream = |
| 142 tunnel_session_client_->CreateTunnel(buzz::Jid(host_jid), ""); |
| 143 DCHECK(stream != NULL); |
| 144 |
| 145 channel->Init(thread_, stream, host_jid); |
| 146 } |
| 147 |
| 148 void JingleClient::Close() { |
| 149 Close(NULL); |
| 150 } |
| 151 |
| 152 void JingleClient::Close(Task* closed_task) { |
| 153 { |
| 154 AutoLock auto_lock(state_lock_); |
| 155 // If the client is already closed then don't close again. |
| 156 if (closed_) { |
| 157 if (closed_task) |
| 158 thread_->message_loop()->PostTask(FROM_HERE, closed_task); |
| 159 return; |
| 160 } |
| 161 closed_task_.reset(closed_task); |
| 162 closed_ = true; |
| 163 } |
| 164 |
| 165 message_loop()->PostTask( |
| 166 FROM_HERE, NewRunnableMethod(this, &JingleClient::DoClose)); |
| 167 } |
| 168 |
| 169 void JingleClient::DoClose() { |
| 170 DCHECK_EQ(message_loop(), MessageLoop::current()); |
| 171 DCHECK(closed_); |
| 172 |
| 173 tunnel_session_client_.reset(); |
| 174 session_manager_.reset(); |
| 175 port_allocator_.reset(); |
| 176 network_manager_.reset(); |
| 177 |
| 178 if (client_) { |
| 179 client_->Disconnect(); |
| 180 // Client is deleted by TaskRunner. |
| 181 client_ = NULL; |
| 182 } |
| 183 |
| 184 if (closed_task_.get()) { |
| 185 closed_task_->Run(); |
| 186 closed_task_.reset(); |
| 187 } |
| 188 } |
| 189 |
| 163 std::string JingleClient::GetFullJid() { | 190 std::string JingleClient::GetFullJid() { |
| 164 AutoLock auto_lock(full_jid_lock_); | 191 AutoLock auto_lock(full_jid_lock_); |
| 165 return full_jid_; | 192 return full_jid_; |
| 166 } | 193 } |
| 167 | 194 |
| 168 IqRequest* JingleClient::CreateIqRequest() { | 195 IqRequest* JingleClient::CreateIqRequest() { |
| 169 return new IqRequest(this); | 196 return new IqRequest(this); |
| 170 } | 197 } |
| 171 | 198 |
| 172 MessageLoop* JingleClient::message_loop() { | 199 MessageLoop* JingleClient::message_loop() { |
| 173 return thread_->message_loop(); | 200 return thread_->message_loop(); |
| 174 } | 201 } |
| 175 | 202 |
| 176 void JingleClient::OnConnectionStateChanged(buzz::XmppEngine::State state) { | 203 void JingleClient::OnConnectionStateChanged(buzz::XmppEngine::State state) { |
| 177 switch (state) { | 204 switch (state) { |
| 178 case buzz::XmppEngine::STATE_START: | 205 case buzz::XmppEngine::STATE_START: |
| 179 UpdateState(INITIALIZED); | 206 UpdateState(START); |
| 180 break; | 207 break; |
| 181 case buzz::XmppEngine::STATE_OPENING: | 208 case buzz::XmppEngine::STATE_OPENING: |
| 182 UpdateState(CONNECTING); | 209 UpdateState(CONNECTING); |
| 183 break; | 210 break; |
| 184 case buzz::XmppEngine::STATE_OPEN: | 211 case buzz::XmppEngine::STATE_OPEN: |
| 185 { | 212 { |
| 186 AutoLock auto_lock(full_jid_lock_); | 213 AutoLock auto_lock(full_jid_lock_); |
| 187 full_jid_ = client_->jid().Str(); | 214 full_jid_ = client_->jid().Str(); |
| 188 } | 215 } |
| 189 UpdateState(CONNECTED); | 216 UpdateState(CONNECTED); |
| 190 break; | 217 break; |
| 191 case buzz::XmppEngine::STATE_CLOSED: | 218 case buzz::XmppEngine::STATE_CLOSED: |
| 192 UpdateState(CLOSED); | 219 UpdateState(CLOSED); |
| 193 break; | 220 break; |
| 194 default: | 221 default: |
| 195 NOTREACHED(); | 222 NOTREACHED(); |
| 196 break; | 223 break; |
| 197 } | 224 } |
| 198 } | 225 } |
| 199 | 226 |
| 200 void JingleClient::OnIncomingTunnel( | 227 void JingleClient::OnIncomingTunnel( |
| 201 cricket::TunnelSessionClient* client, buzz::Jid jid, | 228 cricket::TunnelSessionClient* client, buzz::Jid jid, |
| 202 std::string description, cricket::Session* session) { | 229 std::string description, cricket::Session* session) { |
| 203 // Decline connection if we don't have callback. | 230 // Must always lock state and check closed_ when calling callback. |
| 204 if (!callback_) { | 231 AutoLock auto_lock(state_lock_); |
| 232 |
| 233 if (closed_) { |
| 234 // Always reject connection if we are closed. |
| 205 client->DeclineTunnel(session); | 235 client->DeclineTunnel(session); |
| 206 return; | 236 return; |
| 207 } | 237 } |
| 208 | 238 |
| 209 JingleChannel::Callback* channel_callback; | 239 JingleChannel::Callback* channel_callback; |
| 210 if (callback_->OnAcceptConnection(this, jid.Str(), &channel_callback)) { | 240 if (callback_->OnAcceptConnection(this, jid.Str(), &channel_callback)) { |
| 211 DCHECK(channel_callback != NULL); | 241 DCHECK(channel_callback != NULL); |
| 212 talk_base::StreamInterface* stream = client->AcceptTunnel(session); | 242 talk_base::StreamInterface* stream = client->AcceptTunnel(session); |
| 213 scoped_refptr<JingleChannel> channel(new JingleChannel(channel_callback)); | 243 scoped_refptr<JingleChannel> channel(new JingleChannel(channel_callback)); |
| 214 channel->Init(thread_, stream, jid.Str()); | 244 channel->Init(thread_, stream, jid.Str()); |
| 215 callback_->OnNewConnection(this, channel); | 245 callback_->OnNewConnection(this, channel); |
| 216 } else { | 246 } else { |
| 217 client->DeclineTunnel(session); | 247 client->DeclineTunnel(session); |
| 218 } | 248 } |
| 219 } | 249 } |
| 220 | 250 |
| 221 void JingleClient::UpdateState(State new_state) { | 251 void JingleClient::UpdateState(State new_state) { |
| 222 if (new_state != state_) { | 252 if (new_state != state_) { |
| 223 state_ = new_state; | 253 state_ = new_state; |
| 224 if (callback_) | 254 { |
| 225 callback_->OnStateChange(this, new_state); | 255 AutoLock auto_lock(state_lock_); |
| 256 if (!closed_) |
| 257 callback_->OnStateChange(this, new_state); |
| 258 } |
| 226 } | 259 } |
| 227 } | 260 } |
| 228 | 261 |
| 229 buzz::PreXmppAuth* JingleClient::CreatePreXmppAuth( | 262 buzz::PreXmppAuth* JingleClient::CreatePreXmppAuth( |
| 230 const buzz::XmppClientSettings& settings) { | 263 const buzz::XmppClientSettings& settings) { |
| 231 buzz::Jid jid(settings.user(), settings.host(), buzz::STR_EMPTY); | 264 buzz::Jid jid(settings.user(), settings.host(), buzz::STR_EMPTY); |
| 232 return new notifier::GaiaTokenPreXmppAuth(jid.Str(), settings.auth_cookie(), | 265 return new notifier::GaiaTokenPreXmppAuth(jid.Str(), settings.auth_cookie(), |
| 233 settings.token_service()); | 266 settings.token_service()); |
| 234 } | 267 } |
| 235 | 268 |
| 236 } // namespace remoting | 269 } // namespace remoting |
| OLD | NEW |