OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "remoting/jingle_glue/jingle_client.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "base/waitable_event.h" |
| 9 #include "base/message_loop.h" |
| 10 #include "chrome/common/net/notifier/communicator/xmpp_socket_adapter.h" |
| 11 #include "remoting/jingle_glue/jingle_thread.h" |
| 12 #include "remoting/jingle_glue/relay_port_allocator.h" |
| 13 #include "talk/base/asyncsocket.h" |
| 14 #include "talk/base/ssladapter.h" |
| 15 #include "talk/p2p/base/sessionmanager.h" |
| 16 #include "talk/p2p/client/sessionmanagertask.h" |
| 17 #ifdef USE_SSL_TUNNEL |
| 18 #include "talk/session/tunnel/securetunnelsessionclient.h" |
| 19 #endif |
| 20 #include "talk/session/tunnel/tunnelsessionclient.h" |
| 21 |
| 22 namespace remoting { |
| 23 |
| 24 JingleClient::JingleClient() |
| 25 : callback_(NULL), |
| 26 state_(START) { } |
| 27 |
| 28 JingleClient::~JingleClient() { |
| 29 // JingleClient can be destroyed only after it's closed. |
| 30 DCHECK(state_ == CLOSED); |
| 31 } |
| 32 |
| 33 void JingleClient::Init(const std::string& username, |
| 34 const std::string& password, |
| 35 Callback* callback) { |
| 36 DCHECK(username != ""); |
| 37 DCHECK(callback != NULL); |
| 38 DCHECK(thread_ == NULL); // Init() can be called only once. |
| 39 |
| 40 callback_ = callback; |
| 41 |
| 42 username_ = username; |
| 43 password_ = password; |
| 44 |
| 45 thread_.reset(new JingleThread()); |
| 46 thread_->Start(); |
| 47 thread_->message_loop()->PostTask( |
| 48 FROM_HERE, NewRunnableMethod(this, &JingleClient::DoInitialize)); |
| 49 } |
| 50 |
| 51 class JingleClient::ConnectRequest { |
| 52 public: |
| 53 ConnectRequest() |
| 54 : completed_event_(true, false) { } |
| 55 |
| 56 JingleChannel* Wait() { |
| 57 completed_event_.Wait(); |
| 58 return channel_; |
| 59 }; |
| 60 |
| 61 void Done(JingleChannel* channel) { |
| 62 channel_ = channel; |
| 63 completed_event_.Signal(); |
| 64 }; |
| 65 |
| 66 private: |
| 67 base::WaitableEvent completed_event_; |
| 68 JingleChannel* channel_; |
| 69 }; |
| 70 |
| 71 JingleChannel* JingleClient::Connect(const std::string& host_jid, |
| 72 JingleChannel::Callback* callback) { |
| 73 ConnectRequest request; |
| 74 thread_->message_loop()->PostTask( |
| 75 FROM_HERE, NewRunnableMethod(this, &JingleClient::DoConnect, |
| 76 &request, host_jid, callback)); |
| 77 return request.Wait(); |
| 78 } |
| 79 |
| 80 void JingleClient::DoConnect(ConnectRequest* request, |
| 81 const std::string& host_jid, |
| 82 JingleChannel::Callback* callback) { |
| 83 talk_base::StreamInterface* stream = |
| 84 tunnel_session_client_->CreateTunnel(buzz::Jid(host_jid), ""); |
| 85 DCHECK(stream != NULL); |
| 86 |
| 87 JingleChannel* channel = new JingleChannel(callback); |
| 88 channel->Init(thread_.get(), stream, host_jid); |
| 89 request->Done(channel); |
| 90 } |
| 91 |
| 92 void JingleClient::Close() { |
| 93 DCHECK(thread_ != NULL); // Close() be called only after Init(). |
| 94 message_loop()->PostTask( |
| 95 FROM_HERE, NewRunnableMethod(this, &JingleClient::DoClose)); |
| 96 thread_->Stop(); |
| 97 thread_.reset(NULL); |
| 98 } |
| 99 |
| 100 void JingleClient::DoClose() { |
| 101 client_->Disconnect(); |
| 102 // Client is deleted by TaskRunner. |
| 103 client_ = NULL; |
| 104 tunnel_session_client_.reset(); |
| 105 port_allocator_.reset(); |
| 106 session_manager_.reset(); |
| 107 network_manager_.reset(); |
| 108 UpdateState(CLOSED); |
| 109 } |
| 110 |
| 111 void JingleClient::DoInitialize() { |
| 112 buzz::Jid login_jid(username_); |
| 113 talk_base::InsecureCryptStringImpl password; |
| 114 password.password() = password_; |
| 115 |
| 116 buzz::XmppClientSettings xcs; |
| 117 xcs.set_user(login_jid.node()); |
| 118 xcs.set_host(login_jid.domain()); |
| 119 xcs.set_resource("chromoting"); |
| 120 xcs.set_use_tls(true); |
| 121 xcs.set_pass(talk_base::CryptString(password)); |
| 122 xcs.set_server(talk_base::SocketAddress("talk.google.com", 5222)); |
| 123 |
| 124 client_ = new buzz::XmppClient(thread_->task_pump()); |
| 125 client_->SignalStateChange.connect( |
| 126 this, &JingleClient::OnConnectionStateChanged); |
| 127 |
| 128 buzz::AsyncSocket* socket = |
| 129 new notifier::XmppSocketAdapter(xcs, false); |
| 130 |
| 131 client_->Connect(xcs, "", socket, NULL); |
| 132 client_->Start(); |
| 133 |
| 134 network_manager_.reset(new talk_base::NetworkManager()); |
| 135 |
| 136 RelayPortAllocator* port_allocator = |
| 137 new RelayPortAllocator(network_manager_.get(), "transp2"); |
| 138 port_allocator_.reset(port_allocator); |
| 139 port_allocator->SetJingleInfo(client_); |
| 140 |
| 141 session_manager_.reset(new cricket::SessionManager(port_allocator_.get())); |
| 142 #ifdef USE_SSL_TUNNEL |
| 143 cricket::SecureTunnelSessionClient* session_client = |
| 144 new cricket::SecureTunnelSessionClient(client_->jid(), |
| 145 session_manager_.get()); |
| 146 if (!session_client->GenerateIdentity()) |
| 147 return false; |
| 148 tunnel_session_client_.reset(session_client); |
| 149 #else // !USE_SSL_TUNNEL |
| 150 tunnel_session_client_.reset( |
| 151 new cricket::TunnelSessionClient(client_->jid(), |
| 152 session_manager_.get())); |
| 153 #endif // USE_SSL_TUNNEL |
| 154 |
| 155 receiver_ = new cricket::SessionManagerTask(client_, session_manager_.get()); |
| 156 receiver_->EnableOutgoingMessages(); |
| 157 receiver_->Start(); |
| 158 |
| 159 tunnel_session_client_->SignalIncomingTunnel.connect( |
| 160 this, &JingleClient::OnIncomingTunnel); |
| 161 } |
| 162 |
| 163 std::string JingleClient::GetFullJid() { |
| 164 AutoLock auto_lock(full_jid_lock_); |
| 165 return full_jid_; |
| 166 } |
| 167 |
| 168 MessageLoop* JingleClient::message_loop() { |
| 169 if (thread_ == NULL) { |
| 170 return NULL; |
| 171 } |
| 172 return thread_->message_loop(); |
| 173 } |
| 174 |
| 175 void JingleClient::OnConnectionStateChanged(buzz::XmppEngine::State state) { |
| 176 switch (state) { |
| 177 case buzz::XmppEngine::STATE_START: |
| 178 UpdateState(START); |
| 179 break; |
| 180 case buzz::XmppEngine::STATE_OPENING: |
| 181 UpdateState(CONNECTING); |
| 182 break; |
| 183 case buzz::XmppEngine::STATE_OPEN: |
| 184 { |
| 185 AutoLock auto_lock(full_jid_lock_); |
| 186 full_jid_ = client_->jid().Str(); |
| 187 } |
| 188 UpdateState(CONNECTED); |
| 189 break; |
| 190 case buzz::XmppEngine::STATE_CLOSED: |
| 191 UpdateState(CLOSED); |
| 192 break; |
| 193 } |
| 194 } |
| 195 |
| 196 void JingleClient::OnIncomingTunnel( |
| 197 cricket::TunnelSessionClient* client, buzz::Jid jid, |
| 198 std::string description, cricket::Session* session) { |
| 199 // Decline connection if we don't have callback. |
| 200 if (!callback_) { |
| 201 client->DeclineTunnel(session); |
| 202 return; |
| 203 } |
| 204 |
| 205 JingleChannel::Callback* channel_callback; |
| 206 if (callback_->OnAcceptConnection(this, jid.Str(), &channel_callback)) { |
| 207 DCHECK(channel_callback != NULL); |
| 208 talk_base::StreamInterface* stream = |
| 209 client->AcceptTunnel(session); |
| 210 scoped_refptr<JingleChannel> channel(new JingleChannel(channel_callback)); |
| 211 channel->Init(thread_.get(), stream, jid.Str()); |
| 212 callback_->OnNewConnection(this, channel); |
| 213 } else { |
| 214 client->DeclineTunnel(session); |
| 215 return; |
| 216 } |
| 217 } |
| 218 |
| 219 void JingleClient::UpdateState(State new_state) { |
| 220 if (new_state != state_) { |
| 221 state_ = new_state; |
| 222 if (callback_) |
| 223 callback_->OnStateChange(this, new_state); |
| 224 } |
| 225 } |
| 226 |
| 227 } // namespace remoting |
OLD | NEW |