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

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

Issue 7210025: Split host plugin into multiple files. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge gary's changes 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/host_status_observer.h » ('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::OnShutdown() {
287 DCHECK_EQ(MessageLoop::current(), host_context_.main_message_loop());
288
289 OnStateChanged(kDisconnected);
290 }
291
292 // string uid, string auth_token
293 bool HostNPScriptObject::Connect(const NPVariant* args,
294 uint32_t arg_count,
295 NPVariant* result) {
296 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
297
298 LogDebugInfo("Connecting...");
299
300 if (arg_count != 2) {
301 SetException("connect: bad number of arguments");
302 return false;
303 }
304
305 std::string uid = StringFromNPVariant(args[0]);
306 if (uid.empty()) {
307 SetException("connect: bad uid argument");
308 return false;
309 }
310
311 std::string auth_service_with_token = StringFromNPVariant(args[1]);
312 std::string auth_token;
313 std::string auth_service;
314 ParseAuthTokenWithService(auth_service_with_token, &auth_token,
315 &auth_service);
316 if (auth_token.empty()) {
317 SetException("connect: auth_service_with_token argument has empty token");
318 return false;
319 }
320
321 ConnectInternal(uid, auth_token, auth_service);
322
323 return true;
324 }
325
326 void HostNPScriptObject::ConnectInternal(
327 const std::string& uid,
328 const std::string& auth_token,
329 const std::string& auth_service) {
330 if (MessageLoop::current() != host_context_.main_message_loop()) {
331 host_context_.main_message_loop()->PostTask(
332 FROM_HERE,
333 NewRunnableMethod(this, &HostNPScriptObject::ConnectInternal,
334 uid, auth_token, auth_service));
335 return;
336 }
337 // Store the supplied user ID and token to the Host configuration.
338 scoped_refptr<MutableHostConfig> host_config = new InMemoryHostConfig();
339 host_config->SetString(kXmppLoginConfigPath, uid);
340 host_config->SetString(kXmppAuthTokenConfigPath, auth_token);
341 host_config->SetString(kXmppAuthServiceConfigPath, auth_service);
342
343 // Create an access verifier and fetch the host secret.
344 scoped_ptr<SupportAccessVerifier> access_verifier;
345 access_verifier.reset(new SupportAccessVerifier());
346
347 // Generate a key pair for the Host to use.
348 // TODO(wez): Move this to the worker thread.
349 HostKeyPair host_key_pair;
350 host_key_pair.Generate();
351 host_key_pair.Save(host_config);
352
353 // Request registration of the host for support.
354 scoped_ptr<RegisterSupportHostRequest> register_request(
355 new RegisterSupportHostRequest());
356 if (!register_request->Init(
357 host_config.get(),
358 base::Bind(&HostNPScriptObject::OnReceivedSupportID,
359 base::Unretained(this),
360 access_verifier.get()))) {
361 OnStateChanged(kDisconnected);
362 return;
363 }
364
365 // Create the Host.
366 scoped_refptr<ChromotingHost> host =
367 ChromotingHost::Create(&host_context_, host_config,
368 access_verifier.release());
369 host->AddStatusObserver(this);
370 host->AddStatusObserver(register_request.get());
371 host->set_it2me(true);
372
373 // Nothing went wrong, so lets save the host, config and request.
374 host_ = host;
375 host_config_ = host_config;
376 register_request_.reset(register_request.release());
377
378 // Start the Host.
379 host_->Start();
380
381 OnStateChanged(kRequestedAccessCode);
382 return;
383 }
384
385 bool HostNPScriptObject::Disconnect(const NPVariant* args,
386 uint32_t arg_count,
387 NPVariant* result) {
388 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
389 if (arg_count != 0) {
390 SetException("disconnect: bad number of arguments");
391 return false;
392 }
393
394 DisconnectInternal();
395
396 return true;
397 }
398
399 void HostNPScriptObject::DisconnectInternal() {
400 if (MessageLoop::current() != host_context_.main_message_loop()) {
401 host_context_.main_message_loop()->PostTask(
402 FROM_HERE,
403 NewRunnableMethod(this, &HostNPScriptObject::DisconnectInternal));
404 return;
405 }
406
407 if (!host_) {
408 disconnected_event_.Signal();
409 return;
410 }
411
412 host_->Shutdown(
413 NewRunnableMethod(this, &HostNPScriptObject::OnShutdownFinished));
414 }
415
416 void HostNPScriptObject::OnShutdownFinished() {
417 DCHECK_EQ(MessageLoop::current(), host_context_.main_message_loop());
418
419 host_ = NULL;
420 register_request_.reset();
421 host_config_ = NULL;
422 disconnected_event_.Signal();
423 }
424
425 void HostNPScriptObject::OnReceivedSupportID(
426 SupportAccessVerifier* access_verifier,
427 bool success,
428 const std::string& support_id) {
429 CHECK_NE(base::PlatformThread::CurrentId(), np_thread_id_);
430
431 if (!success) {
432 // TODO(wez): Replace the success/fail flag with full error reporting.
433 DisconnectInternal();
434 return;
435 }
436
437 // Inform the AccessVerifier of our Support-Id, for authentication.
438 access_verifier->OnIT2MeHostRegistered(success, support_id);
439
440 // Combine the Support Id with the Host Id to make the Access Code.
441 // TODO(wez): Locking, anyone?
442 access_code_ = support_id + "-" + access_verifier->host_secret();
443
444 // Let the caller know that life is good.
445 OnStateChanged(kReceivedAccessCode);
446 }
447
448 void HostNPScriptObject::OnStateChanged(State state) {
449 if (destructing_.IsSet()) {
450 return;
451 }
452
453 if (!host_context_.IsUIThread()) {
454 host_context_.PostToUIThread(
455 FROM_HERE,
456 NewRunnableMethod(this, &HostNPScriptObject::OnStateChanged, state));
457 return;
458 }
459 state_ = state;
460 if (on_state_changed_func_) {
461 VLOG(2) << "Calling state changed " << state;
462 bool is_good = CallJSFunction(on_state_changed_func_, NULL, 0, NULL);
463 LOG_IF(ERROR, !is_good) << "OnStateChanged failed";
464 }
465 }
466
467 void HostNPScriptObject::LogDebugInfo(const std::string& message) {
468 if (!host_context_.IsUIThread()) {
469 host_context_.PostToUIThread(
470 FROM_HERE,
471 NewRunnableMethod(this, &HostNPScriptObject::LogDebugInfo, message));
472 return;
473 }
474 if (log_debug_info_func_) {
475 NPVariant* arg = new NPVariant();
476 LOG(INFO) << "Logging: " << message;
477 STRINGZ_TO_NPVARIANT(message.c_str(), *arg);
478 bool is_good = CallJSFunction(log_debug_info_func_, arg, 1, NULL);
479 LOG_IF(ERROR, !is_good) << "LogDebugInfo failed";
480 }
481 }
482
483 void HostNPScriptObject::SetException(const std::string& exception_string) {
484 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_);
485 g_npnetscape_funcs->setexception(parent_, exception_string.c_str());
486 LogDebugInfo(exception_string);
487 }
488
489 bool HostNPScriptObject::CallJSFunction(NPObject* func,
490 const NPVariant* args,
491 uint32_t argCount,
492 NPVariant* result) {
493 NPVariant np_result;
494 bool is_good = func->_class->invokeDefault(func, args, argCount, &np_result);
495 if (is_good) {
496 if (result) {
497 *result = np_result;
498 } else {
499 g_npnetscape_funcs->releasevariantvalue(&np_result);
500 }
501 }
502 return is_good;
503 }
504
505 void HostNPScriptObject::PostTaskToNPThread(
506 const tracked_objects::Location& from_here, Task* task) {
507 // The NPAPI functions cannot make use of |from_here|, but this method is
508 // passed as a callback to ChromotingHostContext, so it needs to have the
509 // appropriate signature.
510
511 // Can be called from any thread.
512 g_npnetscape_funcs->pluginthreadasynccall(plugin_,
513 &NPTaskSpringboard,
514 task);
515 }
516
517 void HostNPScriptObject::NPTaskSpringboard(void* task) {
518 Task* real_task = reinterpret_cast<Task*>(task);
519 real_task->Run();
520 delete real_task;
521 }
522
523 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/host_script_object.h ('k') | remoting/host/host_status_observer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698