1 // Copyright 2015 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.
5 #include "remoting/test/test_chromoting_client.h"
10 #include "base/logging.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "jingle/glue/thread_wrapper.h"
13 #include "net/base/request_priority.h"
14 #include "net/socket/client_socket_factory.h"
15 #include "remoting/base/url_request_context_getter.h"
16 #include "remoting/client/audio_player.h"
17 #include "remoting/client/chromoting_client.h"
18 #include "remoting/client/client_context.h"
19 #include "remoting/client/token_fetcher_proxy.h"
20 #include "remoting/protocol/authentication_method.h"
21 #include "remoting/protocol/chromium_port_allocator.h"
22 #include "remoting/protocol/host_stub.h"
23 #include "remoting/protocol/libjingle_transport_factory.h"
24 #include "remoting/protocol/negotiating_client_authenticator.h"
25 #include "remoting/protocol/network_settings.h"
26 #include "remoting/protocol/session_config.h"
27 #include "remoting/protocol/third_party_client_authenticator.h"
28 #include "remoting/signaling/xmpp_signal_strategy.h"
29 #include "remoting/test/remote_host_info_fetcher.h"
30 #include "remoting/test/test_video_renderer.h"
34 const char kAppRemotingCapabilities
[] =
35 "rateLimitResizeRequests desktopShape sendInitialResolution googleDrive";
37 const char kXmppHostName
[] = "talk.google.com";
38 const int kXmppPortNumber
= 5222;
40 // Used as the TokenFetcherCallback for App Remoting sessions.
41 void FetchThirdPartyToken(
42 const std::string
& authorization_token
,
43 const std::string
& shared_secret
,
44 const GURL
& token_url
,
45 const std::string
& host_public_key
,
46 const std::string
& scope
,
47 base::WeakPtr
<remoting::TokenFetcherProxy
> token_fetcher_proxy
) {
48 DVLOG(1) << "FetchThirdPartyToken("
49 << "token_url: " << token_url
<< ", "
50 << "host_public_key: " << host_public_key
<< ", "
51 << "scope: " << scope
<< ") Called";
53 if (token_fetcher_proxy
) {
54 token_fetcher_proxy
->OnTokenFetched(authorization_token
, shared_secret
);
55 token_fetcher_proxy
.reset();
57 LOG(ERROR
) << "Invalid token fetcher proxy passed in";
61 const char* ConnectionStateToFriendlyString(
62 remoting::protocol::ConnectionToHost::State state
) {
64 case remoting::protocol::ConnectionToHost::INITIALIZING
:
65 return "INITIALIZING";
67 case remoting::protocol::ConnectionToHost::CONNECTING
:
70 case remoting::protocol::ConnectionToHost::AUTHENTICATED
:
71 return "AUTHENTICATED";
73 case remoting::protocol::ConnectionToHost::CONNECTED
:
76 case remoting::protocol::ConnectionToHost::CLOSED
:
79 case remoting::protocol::ConnectionToHost::FAILED
:
83 LOG(ERROR
) << "Unknown connection state: '" << state
<< "'";
88 const char* ProtocolErrorToFriendlyString(
89 remoting::protocol::ErrorCode error_code
) {
91 case remoting::protocol::OK
:
94 case remoting::protocol::PEER_IS_OFFLINE
:
95 return "PEER_IS_OFFLINE";
97 case remoting::protocol::SESSION_REJECTED
:
98 return "SESSION_REJECTED";
100 case remoting::protocol::AUTHENTICATION_FAILED
:
101 return "AUTHENTICATION_FAILED";
103 case remoting::protocol::INCOMPATIBLE_PROTOCOL
:
104 return "INCOMPATIBLE_PROTOCOL";
106 case remoting::protocol::HOST_OVERLOAD
:
107 return "HOST_OVERLOAD";
109 case remoting::protocol::CHANNEL_CONNECTION_ERROR
:
110 return "CHANNEL_CONNECTION_ERROR";
112 case remoting::protocol::SIGNALING_ERROR
:
113 return "SIGNALING_ERROR";
115 case remoting::protocol::SIGNALING_TIMEOUT
:
116 return "SIGNALING_TIMEOUT";
118 case remoting::protocol::UNKNOWN_ERROR
:
119 return "UNKNOWN_ERROR";
122 LOG(ERROR
) << "Unrecognized error code: '" << error_code
<< "'";
123 return "UNKNOWN_ERROR";
132 TestChromotingClient::TestChromotingClient()
133 : connection_to_host_state_(protocol::ConnectionToHost::INITIALIZING
),
134 connection_error_code_(protocol::OK
) {
137 TestChromotingClient::~TestChromotingClient() {
138 // Ensure any connections are closed and the members are destroyed in the
139 // appropriate order.
143 void TestChromotingClient::StartConnection(
144 const std::string
& user_name
,
145 const std::string
& access_token
,
146 const RemoteHostInfo
& remote_host_info
) {
147 DCHECK(!user_name
.empty());
148 DCHECK(!access_token
.empty());
149 DCHECK(remote_host_info
.IsReadyForConnection());
151 // Required to establish a connection to the host.
152 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
154 scoped_refptr
<URLRequestContextGetter
> request_context_getter
;
155 request_context_getter
= new URLRequestContextGetter(
156 base::ThreadTaskRunnerHandle::Get(), // network_runner
157 base::ThreadTaskRunnerHandle::Get()); // file_runner
159 client_context_
.reset(new ClientContext(base::ThreadTaskRunnerHandle::Get()));
161 video_renderer_
.reset(new TestVideoRenderer());
163 chromoting_client_
.reset(new ChromotingClient(client_context_
.get(),
164 this, // client_user_interface.
165 video_renderer_
.get(),
166 nullptr)); // audio_player
168 if (test_connection_to_host_
) {
169 chromoting_client_
->SetConnectionToHostForTests(
170 test_connection_to_host_
.Pass());
173 XmppSignalStrategy::XmppServerConfig xmpp_server_config
;
174 xmpp_server_config
.host
= kXmppHostName
;
175 xmpp_server_config
.port
= kXmppPortNumber
;
176 xmpp_server_config
.use_tls
= true;
177 xmpp_server_config
.username
= user_name
;
178 xmpp_server_config
.auth_token
= access_token
;
180 // Set up the signal strategy. This must outlive the client object.
181 signal_strategy_
.reset(
182 new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
183 request_context_getter
, xmpp_server_config
));
185 protocol::NetworkSettings
network_settings(
186 protocol::NetworkSettings::NAT_TRAVERSAL_FULL
);
188 scoped_ptr
<protocol::ChromiumPortAllocator
> port_allocator(
189 protocol::ChromiumPortAllocator::Create(request_context_getter
,
192 scoped_ptr
<protocol::TransportFactory
> transport_factory(
193 new protocol::LibjingleTransportFactory(
194 signal_strategy_
.get(), port_allocator
.Pass(), network_settings
,
195 protocol::TransportRole::CLIENT
));
197 scoped_ptr
<protocol::ThirdPartyClientAuthenticator::TokenFetcher
>
198 token_fetcher(new TokenFetcherProxy(
199 base::Bind(&FetchThirdPartyToken
, remote_host_info
.authorization_code
,
200 remote_host_info
.shared_secret
),
201 "FAKE_HOST_PUBLIC_KEY"));
203 std::vector
<protocol::AuthenticationMethod
> auth_methods
;
204 auth_methods
.push_back(protocol::AuthenticationMethod::ThirdParty());
206 // FetchSecretCallback is used for PIN based auth which we aren't using so we
207 // can pass a null callback here.
208 protocol::FetchSecretCallback fetch_secret_callback
;
209 scoped_ptr
<protocol::Authenticator
> authenticator(
210 new protocol::NegotiatingClientAuthenticator(
211 std::string(), // client_pairing_id
212 std::string(), // shared_secret
213 std::string(), // authentication_tag
214 fetch_secret_callback
, token_fetcher
.Pass(), auth_methods
));
216 chromoting_client_
->Start(signal_strategy_
.get(), authenticator
.Pass(),
217 transport_factory
.Pass(), remote_host_info
.host_jid
,
218 kAppRemotingCapabilities
);
221 void TestChromotingClient::EndConnection() {
222 // Clearing out the client will close the connection.
223 chromoting_client_
.reset();
225 // The signal strategy object must outlive the client so destroy it next.
226 signal_strategy_
.reset();
228 // The connection state will be updated when the chromoting client was
229 // destroyed if an active connection was established, but not in other cases.
230 // We should be consistent in either case so we will set the state if needed.
231 if (connection_to_host_state_
!= protocol::ConnectionToHost::CLOSED
&&
232 connection_to_host_state_
!= protocol::ConnectionToHost::FAILED
&&
233 connection_error_code_
== protocol::OK
) {
234 OnConnectionState(protocol::ConnectionToHost::CLOSED
, protocol::OK
);
238 void TestChromotingClient::AddRemoteConnectionObserver(
239 RemoteConnectionObserver
* observer
) {
242 connection_observers_
.AddObserver(observer
);
245 void TestChromotingClient::RemoveRemoteConnectionObserver(
246 RemoteConnectionObserver
* observer
) {
249 connection_observers_
.RemoveObserver(observer
);
252 void TestChromotingClient::SetConnectionToHostForTests(
253 scoped_ptr
<protocol::ConnectionToHost
> connection_to_host
) {
254 test_connection_to_host_
= connection_to_host
.Pass();
257 void TestChromotingClient::OnConnectionState(
258 protocol::ConnectionToHost::State state
,
259 protocol::ErrorCode error_code
) {
260 DVLOG(1) << "TestChromotingClient::OnConnectionState("
261 << "state: " << ConnectionStateToFriendlyString(state
) << ", "
262 << "error_code: " << ProtocolErrorToFriendlyString(error_code
)
265 connection_error_code_
= error_code
;
266 connection_to_host_state_
= state
;
268 FOR_EACH_OBSERVER(RemoteConnectionObserver
, connection_observers_
,
269 ConnectionStateChanged(state
, error_code
));
272 void TestChromotingClient::OnConnectionReady(bool ready
) {
273 DVLOG(1) << "TestChromotingClient::OnConnectionReady("
274 << "ready:" << ready
<< ") Called";
276 FOR_EACH_OBSERVER(RemoteConnectionObserver
, connection_observers_
,
277 ConnectionReady(ready
));
280 void TestChromotingClient::OnRouteChanged(
281 const std::string
& channel_name
,
282 const protocol::TransportRoute
& route
) {
283 DVLOG(1) << "TestChromotingClient::OnRouteChanged("
284 << "channel_name:" << channel_name
<< ", "
285 << "route:" << protocol::TransportRoute::GetTypeString(route
.type
)
288 FOR_EACH_OBSERVER(RemoteConnectionObserver
, connection_observers_
,
289 RouteChanged(channel_name
, route
));
292 void TestChromotingClient::SetCapabilities(const std::string
& capabilities
) {
293 DVLOG(1) << "TestChromotingClient::SetCapabilities("
294 << "capabilities: " << capabilities
<< ") Called";
296 FOR_EACH_OBSERVER(RemoteConnectionObserver
, connection_observers_
,
297 CapabilitiesSet(capabilities
));
300 void TestChromotingClient::SetPairingResponse(
301 const protocol::PairingResponse
& pairing_response
) {
302 DVLOG(1) << "TestChromotingClient::SetPairingResponse("
303 << "client_id: " << pairing_response
.client_id() << ", "
304 << "shared_secret: " << pairing_response
.shared_secret()
307 FOR_EACH_OBSERVER(RemoteConnectionObserver
, connection_observers_
,
308 PairingResponseSet(pairing_response
));
311 void TestChromotingClient::DeliverHostMessage(
312 const protocol::ExtensionMessage
& message
) {
313 DVLOG(1) << "TestChromotingClient::DeliverHostMessage("
314 << "type: " << message
.type() << ", "
315 << "data: " << message
.data() << ") Called";
317 FOR_EACH_OBSERVER(RemoteConnectionObserver
, connection_observers_
,
318 HostMessageReceived(message
));
321 protocol::ClipboardStub
* TestChromotingClient::GetClipboardStub() {
322 DVLOG(1) << "TestChromotingClient::GetClipboardStub() Called";
326 protocol::CursorShapeStub
* TestChromotingClient::GetCursorShapeStub() {
327 DVLOG(1) << "TestChromotingClient::GetCursorShapeStub() Called";
331 void TestChromotingClient::InjectClipboardEvent(
332 const protocol::ClipboardEvent
& event
) {
333 DVLOG(1) << "TestChromotingClient::InjectClipboardEvent() Called";
336 void TestChromotingClient::SetCursorShape(
337 const protocol::CursorShapeInfo
& cursor_shape
) {
338 DVLOG(1) << "TestChromotingClient::SetCursorShape() Called";
342 } // namespace remoting