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 |