Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(245)

Side by Side Diff: remoting/host/host_script_object.cc

Issue 7216018: Move the Remoting Host plugin into its own sub-directory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix missed path in remoting.gyp. Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/host/host_script_object.h ('k') | remoting/host/plugin/host_plugin.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/host/host_script_object.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop.h"
9 #include "base/task.h"
10 #include "base/threading/platform_thread.h"
11 #include "remoting/base/auth_token_util.h"
12 #include "remoting/host/chromoting_host.h"
13 #include "remoting/host/chromoting_host_context.h"
14 #include "remoting/host/host_config.h"
15 #include "remoting/host/host_key_pair.h"
16 #include "remoting/host/host_plugin_utils.h"
17 #include "remoting/host/in_memory_host_config.h"
18 #include "remoting/host/register_support_host_request.h"
19 #include "remoting/host/support_access_verifier.h"
20
21 namespace remoting {
22
23 // Supported Javascript interface:
24 // readonly attribute string accessCode;
25 // readonly attribute int state;
26 //
27 // state: {
28 // DISCONNECTED,
29 // REQUESTED_ACCESS_CODE,
30 // RECEIVED_ACCESS_CODE,
31 // CONNECTED,
32 // AFFIRMING_CONNECTION,
33 // ERROR,
34 // }
35 //
36 // attribute Function void logDebugInfo(string);
37 // attribute Function void onStateChanged();
38 //
39 // // The |auth_service_with_token| parameter should be in the format
40 // // "auth_service:auth_token". An example would be "oauth2:1/2a3912vd".
41 // void connect(string uid, string auth_service_with_token);
42 // void disconnect();
43
44 namespace {
45
46 const char* kAttrNameAccessCode = "accessCode";
47 const char* kAttrNameState = "state";
48 const char* kAttrNameLogDebugInfo = "logDebugInfo";
49 const char* kAttrNameOnStateChanged = "onStateChanged";
50 const char* kFuncNameConnect = "connect";
51 const char* kFuncNameDisconnect = "disconnect";
52
53 // States.
54 const char* kAttrNameDisconnected = "DISCONNECTED";
55 const char* kAttrNameRequestedAccessCode = "REQUESTED_ACCESS_CODE";
56 const char* kAttrNameReceivedAccessCode = "RECEIVED_ACCESS_CODE";
57 const char* kAttrNameConnected = "CONNECTED";
58 const char* kAttrNameAffirmingConnection = "AFFIRMING_CONNECTION";
59 const char* kAttrNameError = "ERROR";
60
61 const int kMaxLoginAttempts = 5;
62
63 } // namespace
64
65 HostNPScriptObject::HostNPScriptObject(NPP plugin, NPObject* parent)
66 : plugin_(plugin),
67 parent_(parent),
68 state_(kDisconnected),
69 log_debug_info_func_(NULL),
70 on_state_changed_func_(NULL),
71 np_thread_id_(base::PlatformThread::CurrentId()),
72 failed_login_attempts_(0),
73 disconnected_event_(true, false) {
74 VLOG(2) << "HostNPScriptObject";
75 host_context_.SetUITaskPostFunction(base::Bind(
76 &HostNPScriptObject::PostTaskToNPThread, base::Unretained(this)));
77 }
78
79 HostNPScriptObject::~HostNPScriptObject() {
80 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
81
82 // Disconnect synchronously. We cannot disconnect asynchronously
83 // here because |host_context_| needs to be stopped on the plugin
84 // thread, but the plugin thread may not exist after the instance
85 // is destroyed.
86 destructing_.Set();
87 disconnected_event_.Reset();
88 DisconnectInternal();
89 disconnected_event_.Wait();
90
91 host_context_.Stop();
92 if (log_debug_info_func_) {
93 g_npnetscape_funcs->releaseobject(log_debug_info_func_);
94 }
95 if (on_state_changed_func_) {
96 g_npnetscape_funcs->releaseobject(on_state_changed_func_);
97 }
98 }
99
100 bool HostNPScriptObject::Init() {
101 VLOG(2) << "Init";
102 // TODO(wez): This starts a bunch of threads, which might fail.
103 host_context_.Start();
104 return true;
105 }
106
107 bool HostNPScriptObject::HasMethod(const std::string& method_name) {
108 VLOG(2) << "HasMethod " << method_name;
109 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
110 return (method_name == kFuncNameConnect ||
111 method_name == kFuncNameDisconnect);
112 }
113
114 bool HostNPScriptObject::InvokeDefault(const NPVariant* args,
115 uint32_t argCount,
116 NPVariant* result) {
117 VLOG(2) << "InvokeDefault";
118 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
119 SetException("exception during default invocation");
120 return false;
121 }
122
123 bool HostNPScriptObject::Invoke(const std::string& method_name,
124 const NPVariant* args,
125 uint32_t argCount,
126 NPVariant* result) {
127 VLOG(2) << "Invoke " << method_name;
128 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
129 if (method_name == kFuncNameConnect) {
130 return Connect(args, argCount, result);
131 } else if (method_name == kFuncNameDisconnect) {
132 return Disconnect(args, argCount, result);
133 } else {
134 SetException("Invoke: unknown method " + method_name);
135 return false;
136 }
137 }
138
139 bool HostNPScriptObject::HasProperty(const std::string& property_name) {
140 VLOG(2) << "HasProperty " << property_name;
141 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
142 return (property_name == kAttrNameAccessCode ||
143 property_name == kAttrNameState ||
144 property_name == kAttrNameLogDebugInfo ||
145 property_name == kAttrNameOnStateChanged ||
146 property_name == kAttrNameDisconnected ||
147 property_name == kAttrNameRequestedAccessCode ||
148 property_name == kAttrNameReceivedAccessCode ||
149 property_name == kAttrNameConnected ||
150 property_name == kAttrNameAffirmingConnection ||
151 property_name == kAttrNameError);
152 }
153
154 bool HostNPScriptObject::GetProperty(const std::string& property_name,
155 NPVariant* result) {
156 VLOG(2) << "GetProperty " << property_name;
157 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
158 if (!result) {
159 SetException("GetProperty: NULL result");
160 return false;
161 }
162
163 if (property_name == kAttrNameOnStateChanged) {
164 OBJECT_TO_NPVARIANT(on_state_changed_func_, *result);
165 return true;
166 } else if (property_name == kAttrNameLogDebugInfo) {
167 OBJECT_TO_NPVARIANT(log_debug_info_func_, *result);
168 return true;
169 } else if (property_name == kAttrNameState) {
170 INT32_TO_NPVARIANT(state_, *result);
171 return true;
172 } else if (property_name == kAttrNameAccessCode) {
173 *result = NPVariantFromString(access_code_);
174 return true;
175 } else if (property_name == kAttrNameDisconnected) {
176 INT32_TO_NPVARIANT(kDisconnected, *result);
177 return true;
178 } else if (property_name == kAttrNameRequestedAccessCode) {
179 INT32_TO_NPVARIANT(kRequestedAccessCode, *result);
180 return true;
181 } else if (property_name == kAttrNameReceivedAccessCode) {
182 INT32_TO_NPVARIANT(kReceivedAccessCode, *result);
183 return true;
184 } else if (property_name == kAttrNameConnected) {
185 INT32_TO_NPVARIANT(kConnected, *result);
186 return true;
187 } else if (property_name == kAttrNameAffirmingConnection) {
188 INT32_TO_NPVARIANT(kAffirmingConnection, *result);
189 return true;
190 } else if (property_name == kAttrNameError) {
191 INT32_TO_NPVARIANT(kError, *result);
192 return true;
193 } else {
194 SetException("GetProperty: unsupported property " + property_name);
195 return false;
196 }
197 }
198
199 bool HostNPScriptObject::SetProperty(const std::string& property_name,
200 const NPVariant* value) {
201 VLOG(2) << "SetProperty " << property_name;
202 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
203
204 if (property_name == kAttrNameOnStateChanged) {
205 if (NPVARIANT_IS_OBJECT(*value)) {
206 if (on_state_changed_func_) {
207 g_npnetscape_funcs->releaseobject(on_state_changed_func_);
208 }
209 on_state_changed_func_ = NPVARIANT_TO_OBJECT(*value);
210 if (on_state_changed_func_) {
211 g_npnetscape_funcs->retainobject(on_state_changed_func_);
212 }
213 return true;
214 } else {
215 SetException("SetProperty: unexpected type for property " +
216 property_name);
217 }
218 return false;
219 }
220
221 if (property_name == kAttrNameLogDebugInfo) {
222 if (NPVARIANT_IS_OBJECT(*value)) {
223 if (log_debug_info_func_) {
224 g_npnetscape_funcs->releaseobject(log_debug_info_func_);
225 }
226 log_debug_info_func_ = NPVARIANT_TO_OBJECT(*value);
227 if (log_debug_info_func_) {
228 g_npnetscape_funcs->retainobject(log_debug_info_func_);
229 }
230 return true;
231 } else {
232 SetException("SetProperty: unexpected type for property " +
233 property_name);
234 }
235 return false;
236 }
237
238 return false;
239 }
240
241 bool HostNPScriptObject::RemoveProperty(const std::string& property_name) {
242 VLOG(2) << "RemoveProperty " << property_name;
243 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
244 return false;
245 }
246
247 bool HostNPScriptObject::Enumerate(std::vector<std::string>* values) {
248 VLOG(2) << "Enumerate";
249 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
250 const char* entries[] = {
251 kAttrNameAccessCode,
252 kAttrNameState,
253 kAttrNameLogDebugInfo,
254 kAttrNameOnStateChanged,
255 kFuncNameConnect,
256 kFuncNameDisconnect,
257 kAttrNameDisconnected,
258 kAttrNameRequestedAccessCode,
259 kAttrNameReceivedAccessCode,
260 kAttrNameConnected,
261 kAttrNameAffirmingConnection,
262 kAttrNameError
263 };
264 for (size_t i = 0; i < arraysize(entries); ++i) {
265 values->push_back(entries[i]);
266 }
267 return true;
268 }
269
270 void HostNPScriptObject::OnSignallingConnected(SignalStrategy* signal_strategy,
271 const std::string& full_jid) {
272 OnStateChanged(kConnected);
273 }
274
275 void HostNPScriptObject::OnSignallingDisconnected() {
276 }
277
278 void HostNPScriptObject::OnAccessDenied() {
279 DCHECK_EQ(MessageLoop::current(), host_context_.network_message_loop());
280
281 ++failed_login_attempts_;
282 if (failed_login_attempts_ == kMaxLoginAttempts)
283 DisconnectInternal();
284 }
285
286 void HostNPScriptObject::OnAuthenticatedClientsChanged(int clients_connected) {
287 DCHECK_NE(base::PlatformThread::CurrentId(), np_thread_id_);
288 OnStateChanged(clients_connected ? kConnected : kDisconnected);
289 }
290
291 void HostNPScriptObject::OnShutdown() {
292 DCHECK_EQ(MessageLoop::current(), host_context_.main_message_loop());
293
294 OnStateChanged(kDisconnected);
295 }
296
297 // string uid, string auth_token
298 bool HostNPScriptObject::Connect(const NPVariant* args,
299 uint32_t arg_count,
300 NPVariant* result) {
301 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
302
303 LogDebugInfo("Connecting...");
304
305 if (arg_count != 2) {
306 SetException("connect: bad number of arguments");
307 return false;
308 }
309
310 std::string uid = StringFromNPVariant(args[0]);
311 if (uid.empty()) {
312 SetException("connect: bad uid argument");
313 return false;
314 }
315
316 std::string auth_service_with_token = StringFromNPVariant(args[1]);
317 std::string auth_token;
318 std::string auth_service;
319 ParseAuthTokenWithService(auth_service_with_token, &auth_token,
320 &auth_service);
321 if (auth_token.empty()) {
322 SetException("connect: auth_service_with_token argument has empty token");
323 return false;
324 }
325
326 ConnectInternal(uid, auth_token, auth_service);
327
328 return true;
329 }
330
331 void HostNPScriptObject::ConnectInternal(
332 const std::string& uid,
333 const std::string& auth_token,
334 const std::string& auth_service) {
335 if (MessageLoop::current() != host_context_.main_message_loop()) {
336 host_context_.main_message_loop()->PostTask(
337 FROM_HERE,
338 NewRunnableMethod(this, &HostNPScriptObject::ConnectInternal,
339 uid, auth_token, auth_service));
340 return;
341 }
342 // Store the supplied user ID and token to the Host configuration.
343 scoped_refptr<MutableHostConfig> host_config = new InMemoryHostConfig();
344 host_config->SetString(kXmppLoginConfigPath, uid);
345 host_config->SetString(kXmppAuthTokenConfigPath, auth_token);
346 host_config->SetString(kXmppAuthServiceConfigPath, auth_service);
347
348 // Create an access verifier and fetch the host secret.
349 scoped_ptr<SupportAccessVerifier> access_verifier;
350 access_verifier.reset(new SupportAccessVerifier());
351
352 // Generate a key pair for the Host to use.
353 // TODO(wez): Move this to the worker thread.
354 HostKeyPair host_key_pair;
355 host_key_pair.Generate();
356 host_key_pair.Save(host_config);
357
358 // Request registration of the host for support.
359 scoped_ptr<RegisterSupportHostRequest> register_request(
360 new RegisterSupportHostRequest());
361 if (!register_request->Init(
362 host_config.get(),
363 base::Bind(&HostNPScriptObject::OnReceivedSupportID,
364 base::Unretained(this),
365 access_verifier.get()))) {
366 OnStateChanged(kDisconnected);
367 return;
368 }
369
370 // Create the Host.
371 scoped_refptr<ChromotingHost> host =
372 ChromotingHost::Create(&host_context_, host_config,
373 access_verifier.release());
374 host->AddStatusObserver(this);
375 host->AddStatusObserver(register_request.get());
376 host->set_it2me(true);
377
378 // Nothing went wrong, so lets save the host, config and request.
379 host_ = host;
380 host_config_ = host_config;
381 register_request_.reset(register_request.release());
382
383 // Start the Host.
384 host_->Start();
385
386 OnStateChanged(kRequestedAccessCode);
387 return;
388 }
389
390 bool HostNPScriptObject::Disconnect(const NPVariant* args,
391 uint32_t arg_count,
392 NPVariant* result) {
393 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
394 if (arg_count != 0) {
395 SetException("disconnect: bad number of arguments");
396 return false;
397 }
398
399 DisconnectInternal();
400
401 return true;
402 }
403
404 void HostNPScriptObject::DisconnectInternal() {
405 if (MessageLoop::current() != host_context_.main_message_loop()) {
406 host_context_.main_message_loop()->PostTask(
407 FROM_HERE,
408 NewRunnableMethod(this, &HostNPScriptObject::DisconnectInternal));
409 return;
410 }
411
412 if (!host_) {
413 disconnected_event_.Signal();
414 return;
415 }
416
417 host_->Shutdown(
418 NewRunnableMethod(this, &HostNPScriptObject::OnShutdownFinished));
419 }
420
421 void HostNPScriptObject::OnShutdownFinished() {
422 DCHECK_EQ(MessageLoop::current(), host_context_.main_message_loop());
423
424 host_ = NULL;
425 register_request_.reset();
426 host_config_ = NULL;
427 disconnected_event_.Signal();
428 }
429
430 void HostNPScriptObject::OnReceivedSupportID(
431 SupportAccessVerifier* access_verifier,
432 bool success,
433 const std::string& support_id) {
434 CHECK_NE(base::PlatformThread::CurrentId(), np_thread_id_);
435
436 if (!success) {
437 // TODO(wez): Replace the success/fail flag with full error reporting.
438 DisconnectInternal();
439 return;
440 }
441
442 // Inform the AccessVerifier of our Support-Id, for authentication.
443 access_verifier->OnIT2MeHostRegistered(success, support_id);
444
445 // Combine the Support Id with the Host Id to make the Access Code.
446 // TODO(wez): Locking, anyone?
447 access_code_ = support_id + "-" + access_verifier->host_secret();
448
449 // Let the caller know that life is good.
450 OnStateChanged(kReceivedAccessCode);
451 }
452
453 void HostNPScriptObject::OnStateChanged(State state) {
454 if (destructing_.IsSet()) {
455 return;
456 }
457
458 if (!host_context_.IsUIThread()) {
459 host_context_.PostToUIThread(
460 FROM_HERE,
461 NewRunnableMethod(this, &HostNPScriptObject::OnStateChanged, state));
462 return;
463 }
464 state_ = state;
465 if (on_state_changed_func_) {
466 VLOG(2) << "Calling state changed " << state;
467 bool is_good = CallJSFunction(on_state_changed_func_, NULL, 0, NULL);
468 LOG_IF(ERROR, !is_good) << "OnStateChanged failed";
469 }
470 }
471
472 void HostNPScriptObject::LogDebugInfo(const std::string& message) {
473 if (!host_context_.IsUIThread()) {
474 host_context_.PostToUIThread(
475 FROM_HERE,
476 NewRunnableMethod(this, &HostNPScriptObject::LogDebugInfo, message));
477 return;
478 }
479 if (log_debug_info_func_) {
480 NPVariant* arg = new NPVariant();
481 LOG(INFO) << "Logging: " << message;
482 STRINGZ_TO_NPVARIANT(message.c_str(), *arg);
483 bool is_good = CallJSFunction(log_debug_info_func_, arg, 1, NULL);
484 LOG_IF(ERROR, !is_good) << "LogDebugInfo failed";
485 }
486 }
487
488 void HostNPScriptObject::SetException(const std::string& exception_string) {
489 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
490 g_npnetscape_funcs->setexception(parent_, exception_string.c_str());
491 LogDebugInfo(exception_string);
492 }
493
494 bool HostNPScriptObject::CallJSFunction(NPObject* func,
495 const NPVariant* args,
496 uint32_t argCount,
497 NPVariant* result) {
498 NPVariant np_result;
499 bool is_good = func->_class->invokeDefault(func, args, argCount, &np_result);
500 if (is_good) {
501 if (result) {
502 *result = np_result;
503 } else {
504 g_npnetscape_funcs->releasevariantvalue(&np_result);
505 }
506 }
507 return is_good;
508 }
509
510 void HostNPScriptObject::PostTaskToNPThread(
511 const tracked_objects::Location& from_here, Task* task) {
512 // The NPAPI functions cannot make use of |from_here|, but this method is
513 // passed as a callback to ChromotingHostContext, so it needs to have the
514 // appropriate signature.
515
516 // Can be called from any thread.
517 g_npnetscape_funcs->pluginthreadasynccall(plugin_,
518 &NPTaskSpringboard,
519 task);
520 }
521
522 void HostNPScriptObject::NPTaskSpringboard(void* task) {
523 Task* real_task = reinterpret_cast<Task*>(task);
524 real_task->Run();
525 delete real_task;
526 }
527
528 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/host_script_object.h ('k') | remoting/host/plugin/host_plugin.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698