OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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 #include <stdio.h> | 5 #include <stdio.h> |
6 #include <string.h> | 6 #include <string.h> |
7 | 7 |
8 #include <string> | 8 #include <string> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/at_exit.h" | 11 #include "base/at_exit.h" |
12 #include "base/base_paths.h" | |
13 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
14 #include "base/bind.h" | |
15 #include "base/file_path.h" | |
16 #include "base/logging.h" | 13 #include "base/logging.h" |
17 #include "base/message_loop.h" | |
18 #include "base/path_service.h" | |
19 #include "base/rand_util.h" | |
20 #include "base/stringize_macros.h" | 14 #include "base/stringize_macros.h" |
21 #include "base/task.h" | 15 #include "remoting/host/host_plugin_utils.h" |
22 #include "base/threading/platform_thread.h" | 16 #include "remoting/host/host_script_object.h" |
23 #include "base/threading/thread.h" | |
24 #include "base/synchronization/cancellation_flag.h" | |
25 #include "remoting/base/auth_token_util.h" | |
26 #include "remoting/host/chromoting_host.h" | |
27 #include "remoting/host/chromoting_host_context.h" | |
28 #include "remoting/host/host_config.h" | |
29 #include "remoting/host/host_key_pair.h" | |
30 #include "remoting/host/host_status_observer.h" | |
31 #include "remoting/host/in_memory_host_config.h" | |
32 #include "remoting/host/register_support_host_request.h" | |
33 #include "remoting/host/support_access_verifier.h" | |
34 #include "third_party/npapi/bindings/npapi.h" | 17 #include "third_party/npapi/bindings/npapi.h" |
35 #include "third_party/npapi/bindings/npfunctions.h" | 18 #include "third_party/npapi/bindings/npfunctions.h" |
36 #include "third_party/npapi/bindings/npruntime.h" | 19 #include "third_party/npapi/bindings/npruntime.h" |
37 | 20 |
38 // Symbol export is handled with a separate def file on Windows. | 21 // Symbol export is handled with a separate def file on Windows. |
39 #if defined (__GNUC__) && __GNUC__ >= 4 | 22 #if defined (__GNUC__) && __GNUC__ >= 4 |
40 #define EXPORT __attribute__((visibility("default"))) | 23 #define EXPORT __attribute__((visibility("default"))) |
41 #else | 24 #else |
42 #define EXPORT | 25 #define EXPORT |
43 #endif | 26 #endif |
44 | 27 |
45 #if defined(OS_WIN) | 28 #if defined(OS_WIN) |
46 // TODO(wez): libvpx expects these 64-bit division functions to be provided | 29 // TODO(wez): libvpx expects these 64-bit division functions to be provided |
47 // by libgcc.a, which we aren't linked against. These implementations can | 30 // by libgcc.a, which we aren't linked against. These implementations can |
48 // be removed once we have native MSVC libvpx builds for Windows. | 31 // be removed once we have native MSVC libvpx builds for Windows. |
49 extern "C" { | 32 extern "C" { |
50 | 33 |
51 int64_t __cdecl __divdi3(int64_t a, int64_t b) { | 34 int64_t __cdecl __divdi3(int64_t a, int64_t b) { |
52 return a / b; | 35 return a / b; |
53 } | 36 } |
54 uint64_t __cdecl __udivdi3(uint64_t a, uint64_t b) { | 37 uint64_t __cdecl __udivdi3(uint64_t a, uint64_t b) { |
55 return a / b; | 38 return a / b; |
56 } | 39 } |
57 | 40 |
58 } | 41 } |
59 #endif | 42 #endif |
60 | 43 |
61 // Supported Javascript interface: | 44 using remoting::g_npnetscape_funcs; |
62 // readonly attribute string accessCode; | 45 using remoting::HostNPScriptObject; |
63 // readonly attribute int state; | 46 using remoting::StringFromNPIdentifier; |
64 // | |
65 // state: { | |
66 // DISCONNECTED, | |
67 // REQUESTED_ACCESS_CODE, | |
68 // RECEIVED_ACCESS_CODE, | |
69 // CONNECTED, | |
70 // AFFIRMING_CONNECTION, | |
71 // ERROR, | |
72 // } | |
73 // | |
74 // attribute Function void logDebugInfo(string); | |
75 // attribute Function void onStateChanged(); | |
76 // | |
77 // // The |auth_service_with_token| parameter should be in the format | |
78 // // "auth_service:auth_token". An example would be "oauth2:1/2a3912vd". | |
79 // void connect(string uid, string auth_service_with_token); | |
80 // void disconnect(); | |
81 | |
82 | 47 |
83 namespace { | 48 namespace { |
84 | 49 |
85 const char* kAttrNameAccessCode = "accessCode"; | |
86 const char* kAttrNameState = "state"; | |
87 const char* kAttrNameLogDebugInfo = "logDebugInfo"; | |
88 const char* kAttrNameOnStateChanged = "onStateChanged"; | |
89 const char* kFuncNameConnect = "connect"; | |
90 const char* kFuncNameDisconnect = "disconnect"; | |
91 | |
92 // States. | |
93 const char* kAttrNameDisconnected = "DISCONNECTED"; | |
94 const char* kAttrNameRequestedAccessCode = "REQUESTED_ACCESS_CODE"; | |
95 const char* kAttrNameReceivedAccessCode = "RECEIVED_ACCESS_CODE"; | |
96 const char* kAttrNameConnected = "CONNECTED"; | |
97 const char* kAttrNameAffirmingConnection = "AFFIRMING_CONNECTION"; | |
98 const char* kAttrNameError = "ERROR"; | |
99 | |
100 const int kMaxLoginAttempts = 5; | |
101 | |
102 // Global netscape functions initialized in NP_Initialize. | |
103 NPNetscapeFuncs* g_npnetscape_funcs = NULL; | |
104 | |
105 // Global AtExitManager, created in NP_Initialize and destroyed in NP_Shutdown. | |
106 base::AtExitManager* g_at_exit_manager = NULL; | 50 base::AtExitManager* g_at_exit_manager = NULL; |
107 | 51 |
108 // The name and description are returned by GetValue, but are also | 52 // The name and description are returned by GetValue, but are also |
109 // combined with the MIME type to satisfy GetMIMEDescription, so we | 53 // combined with the MIME type to satisfy GetMIMEDescription, so we |
110 // use macros here to allow that to happen at compile-time. | 54 // use macros here to allow that to happen at compile-time. |
111 #define HOST_PLUGIN_NAME "Remoting Host Plugin" | 55 #define HOST_PLUGIN_NAME "Remoting Host Plugin" |
112 #define HOST_PLUGIN_DESCRIPTION "Remoting Host Plugin" | 56 #define HOST_PLUGIN_DESCRIPTION "Remoting Host Plugin" |
113 | 57 |
114 // Convert an NPIdentifier into a std::string. | |
115 std::string StringFromNPIdentifier(NPIdentifier identifier) { | |
116 if (!g_npnetscape_funcs->identifierisstring(identifier)) | |
117 return std::string(); | |
118 NPUTF8* np_string = g_npnetscape_funcs->utf8fromidentifier(identifier); | |
119 std::string string(np_string); | |
120 g_npnetscape_funcs->memfree(np_string); | |
121 return string; | |
122 } | |
123 | |
124 // Convert an NPVariant into a std::string. | |
125 std::string StringFromNPVariant(const NPVariant& variant) { | |
126 if (!NPVARIANT_IS_STRING(variant)) | |
127 return std::string(); | |
128 const NPString& np_string = NPVARIANT_TO_STRING(variant); | |
129 return std::string(np_string.UTF8Characters, np_string.UTF8Length); | |
130 } | |
131 | |
132 // Convert a std::string into an NPVariant. | |
133 // Caller is responsible for making sure that NPN_ReleaseVariantValue is | |
134 // called on returned value. | |
135 NPVariant NPVariantFromString(const std::string& val) { | |
136 size_t len = val.length(); | |
137 NPUTF8* chars = | |
138 reinterpret_cast<NPUTF8*>(g_npnetscape_funcs->memalloc(len + 1)); | |
139 strcpy(chars, val.c_str()); | |
140 NPVariant variant; | |
141 STRINGN_TO_NPVARIANT(chars, len, variant); | |
142 return variant; | |
143 } | |
144 | |
145 // Convert an NPVariant into an NSPObject. | |
146 NPObject* ObjectFromNPVariant(const NPVariant& variant) { | |
147 if (!NPVARIANT_IS_OBJECT(variant)) | |
148 return NULL; | |
149 return NPVARIANT_TO_OBJECT(variant); | |
150 } | |
151 | |
152 // NPAPI plugin implementation for remoting host script object. | |
153 // HostNPScriptObject creates threads that are required to run | |
154 // ChromotingHost and starts/stops the host on those threads. When | |
155 // destroyed it sychronously shuts down the host and all threads. | |
156 class HostNPScriptObject : public remoting::HostStatusObserver { | |
157 public: | |
158 HostNPScriptObject(NPP plugin, NPObject* parent) | |
159 : plugin_(plugin), | |
160 parent_(parent), | |
161 state_(kDisconnected), | |
162 log_debug_info_func_(NULL), | |
163 on_state_changed_func_(NULL), | |
164 np_thread_id_(base::PlatformThread::CurrentId()), | |
165 failed_login_attempts_(0), | |
166 disconnected_event_(true, false) { | |
167 VLOG(2) << "HostNPScriptObject"; | |
168 host_context_.SetUITaskPostFunction(base::Bind( | |
169 &HostNPScriptObject::PostTaskToNPThread, base::Unretained(this))); | |
170 } | |
171 | |
172 ~HostNPScriptObject() { | |
173 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | |
174 | |
175 // Disconnect synchronously. We cannot disconnect asynchronously | |
176 // here because |host_context_| needs to be stopped on the plugin | |
177 // thread, but the plugin thread may not exist after the instance | |
178 // is destroyed. | |
179 destructing_.Set(); | |
180 disconnected_event_.Reset(); | |
181 DisconnectInternal(); | |
182 disconnected_event_.Wait(); | |
183 | |
184 host_context_.Stop(); | |
185 if (log_debug_info_func_) { | |
186 g_npnetscape_funcs->releaseobject(log_debug_info_func_); | |
187 } | |
188 if (on_state_changed_func_) { | |
189 g_npnetscape_funcs->releaseobject(on_state_changed_func_); | |
190 } | |
191 } | |
192 | |
193 bool Init() { | |
194 VLOG(2) << "Init"; | |
195 // TODO(wez): This starts a bunch of threads, which might fail. | |
196 host_context_.Start(); | |
197 return true; | |
198 } | |
199 | |
200 bool HasMethod(const std::string& method_name) { | |
201 VLOG(2) << "HasMethod " << method_name; | |
202 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | |
203 return (method_name == kFuncNameConnect || | |
204 method_name == kFuncNameDisconnect); | |
205 } | |
206 | |
207 bool InvokeDefault(const NPVariant* args, | |
208 uint32_t argCount, | |
209 NPVariant* result) { | |
210 VLOG(2) << "InvokeDefault"; | |
211 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | |
212 SetException("exception during default invocation"); | |
213 return false; | |
214 } | |
215 | |
216 bool Invoke(const std::string& method_name, | |
217 const NPVariant* args, | |
218 uint32_t argCount, | |
219 NPVariant* result) { | |
220 VLOG(2) << "Invoke " << method_name; | |
221 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | |
222 if (method_name == kFuncNameConnect) { | |
223 return Connect(args, argCount, result); | |
224 } else if (method_name == kFuncNameDisconnect) { | |
225 return Disconnect(args, argCount, result); | |
226 } else { | |
227 SetException("Invoke: unknown method " + method_name); | |
228 return false; | |
229 } | |
230 } | |
231 | |
232 bool HasProperty(const std::string& property_name) { | |
233 VLOG(2) << "HasProperty " << property_name; | |
234 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | |
235 return (property_name == kAttrNameAccessCode || | |
236 property_name == kAttrNameState || | |
237 property_name == kAttrNameLogDebugInfo || | |
238 property_name == kAttrNameOnStateChanged || | |
239 property_name == kAttrNameDisconnected || | |
240 property_name == kAttrNameRequestedAccessCode || | |
241 property_name == kAttrNameReceivedAccessCode || | |
242 property_name == kAttrNameConnected || | |
243 property_name == kAttrNameAffirmingConnection || | |
244 property_name == kAttrNameError); | |
245 } | |
246 | |
247 bool GetProperty(const std::string& property_name, NPVariant* result) { | |
248 VLOG(2) << "GetProperty " << property_name; | |
249 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | |
250 if (!result) { | |
251 SetException("GetProperty: NULL result"); | |
252 return false; | |
253 } | |
254 | |
255 if (property_name == kAttrNameOnStateChanged) { | |
256 OBJECT_TO_NPVARIANT(on_state_changed_func_, *result); | |
257 return true; | |
258 } else if (property_name == kAttrNameLogDebugInfo) { | |
259 OBJECT_TO_NPVARIANT(log_debug_info_func_, *result); | |
260 return true; | |
261 } else if (property_name == kAttrNameState) { | |
262 INT32_TO_NPVARIANT(state_, *result); | |
263 return true; | |
264 } else if (property_name == kAttrNameAccessCode) { | |
265 *result = NPVariantFromString(access_code_); | |
266 return true; | |
267 } else if (property_name == kAttrNameDisconnected) { | |
268 INT32_TO_NPVARIANT(kDisconnected, *result); | |
269 return true; | |
270 } else if (property_name == kAttrNameRequestedAccessCode) { | |
271 INT32_TO_NPVARIANT(kRequestedAccessCode, *result); | |
272 return true; | |
273 } else if (property_name == kAttrNameReceivedAccessCode) { | |
274 INT32_TO_NPVARIANT(kReceivedAccessCode, *result); | |
275 return true; | |
276 } else if (property_name == kAttrNameConnected) { | |
277 INT32_TO_NPVARIANT(kConnected, *result); | |
278 return true; | |
279 } else if (property_name == kAttrNameAffirmingConnection) { | |
280 INT32_TO_NPVARIANT(kAffirmingConnection, *result); | |
281 return true; | |
282 } else if (property_name == kAttrNameError) { | |
283 INT32_TO_NPVARIANT(kError, *result); | |
284 return true; | |
285 } else { | |
286 SetException("GetProperty: unsupported property " + property_name); | |
287 return false; | |
288 } | |
289 } | |
290 | |
291 bool SetProperty(const std::string& property_name, const NPVariant* value) { | |
292 VLOG(2) << "SetProperty " << property_name; | |
293 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | |
294 | |
295 if (property_name == kAttrNameOnStateChanged) { | |
296 if (NPVARIANT_IS_OBJECT(*value)) { | |
297 if (on_state_changed_func_) { | |
298 g_npnetscape_funcs->releaseobject(on_state_changed_func_); | |
299 } | |
300 on_state_changed_func_ = NPVARIANT_TO_OBJECT(*value); | |
301 if (on_state_changed_func_) { | |
302 g_npnetscape_funcs->retainobject(on_state_changed_func_); | |
303 } | |
304 return true; | |
305 } else { | |
306 SetException("SetProperty: unexpected type for property " + | |
307 property_name); | |
308 } | |
309 return false; | |
310 } | |
311 | |
312 if (property_name == kAttrNameLogDebugInfo) { | |
313 if (NPVARIANT_IS_OBJECT(*value)) { | |
314 if (log_debug_info_func_) { | |
315 g_npnetscape_funcs->releaseobject(log_debug_info_func_); | |
316 } | |
317 log_debug_info_func_ = NPVARIANT_TO_OBJECT(*value); | |
318 if (log_debug_info_func_) { | |
319 g_npnetscape_funcs->retainobject(log_debug_info_func_); | |
320 } | |
321 return true; | |
322 } else { | |
323 SetException("SetProperty: unexpected type for property " + | |
324 property_name); | |
325 } | |
326 return false; | |
327 } | |
328 | |
329 return false; | |
330 } | |
331 | |
332 bool RemoveProperty(const std::string& property_name) { | |
333 VLOG(2) << "RemoveProperty " << property_name; | |
334 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | |
335 return false; | |
336 } | |
337 | |
338 bool Enumerate(std::vector<std::string>* values) { | |
339 VLOG(2) << "Enumerate"; | |
340 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | |
341 const char* entries[] = { | |
342 kAttrNameAccessCode, | |
343 kAttrNameState, | |
344 kAttrNameLogDebugInfo, | |
345 kAttrNameOnStateChanged, | |
346 kFuncNameConnect, | |
347 kFuncNameDisconnect, | |
348 kAttrNameDisconnected, | |
349 kAttrNameRequestedAccessCode, | |
350 kAttrNameReceivedAccessCode, | |
351 kAttrNameConnected, | |
352 kAttrNameAffirmingConnection, | |
353 kAttrNameError | |
354 }; | |
355 for (size_t i = 0; i < arraysize(entries); ++i) { | |
356 values->push_back(entries[i]); | |
357 } | |
358 return true; | |
359 } | |
360 | |
361 // remoting::HostStatusObserver implementation. | |
362 virtual void OnSignallingConnected(remoting::SignalStrategy* signal_strategy, | |
363 const std::string& full_jid) OVERRIDE { | |
364 OnStateChanged(kConnected); | |
365 } | |
366 | |
367 virtual void OnSignallingDisconnected() OVERRIDE { | |
368 } | |
369 | |
370 virtual void OnAccessDenied() OVERRIDE { | |
371 DCHECK_EQ(MessageLoop::current(), host_context_.network_message_loop()); | |
372 | |
373 ++failed_login_attempts_; | |
374 if (failed_login_attempts_ == kMaxLoginAttempts) | |
375 DisconnectInternal(); | |
376 } | |
377 | |
378 virtual void OnShutdown() OVERRIDE { | |
379 DCHECK_EQ(MessageLoop::current(), host_context_.main_message_loop()); | |
380 | |
381 OnStateChanged(kDisconnected); | |
382 } | |
383 | |
384 private: | |
385 enum State { | |
386 kDisconnected, | |
387 kRequestedAccessCode, | |
388 kReceivedAccessCode, | |
389 kConnected, | |
390 kAffirmingConnection, | |
391 kError | |
392 }; | |
393 | |
394 // Start connection. args are: | |
395 // string uid, string auth_token | |
396 // No result. | |
397 bool Connect(const NPVariant* args, uint32_t argCount, NPVariant* result); | |
398 | |
399 // Disconnect. No arguments or result. | |
400 bool Disconnect(const NPVariant* args, uint32_t argCount, NPVariant* result); | |
401 | |
402 // Call LogDebugInfo handler if there is one. | |
403 void LogDebugInfo(const std::string& message); | |
404 | |
405 // Call OnStateChanged handler if there is one. | |
406 void OnStateChanged(State state); | |
407 | |
408 // Callbacks invoked during session setup. | |
409 void OnReceivedSupportID(remoting::SupportAccessVerifier* access_verifier, | |
410 bool success, | |
411 const std::string& support_id); | |
412 | |
413 // Helper functions that run on main thread. Can be called on any | |
414 // other thread. | |
415 void ConnectInternal(const std::string& uid, | |
416 const std::string& auth_token, | |
417 const std::string& auth_service); | |
418 void DisconnectInternal(); | |
419 | |
420 // Callback for ChromotingHost::Shutdown(). | |
421 void OnShutdownFinished(); | |
422 | |
423 // Call a JavaScript function wrapped as an NPObject. | |
424 // If result is non-null, the result of the call will be stored in it. | |
425 // Caller is responsible for releasing result if they ask for it. | |
426 static bool CallJSFunction(NPObject* func, | |
427 const NPVariant* args, | |
428 uint32_t argCount, | |
429 NPVariant* result); | |
430 | |
431 // Posts a task on the main NP thread. | |
432 void PostTaskToNPThread(const tracked_objects::Location& from_here, | |
433 Task* task); | |
434 | |
435 // Utility function for PostTaskToNPThread. | |
436 static void NPTaskSpringboard(void* task); | |
437 | |
438 // Set an exception for the current call. | |
439 void SetException(const std::string& exception_string); | |
440 | |
441 NPP plugin_; | |
442 NPObject* parent_; | |
443 int state_; | |
444 std::string access_code_; | |
445 NPObject* log_debug_info_func_; | |
446 NPObject* on_state_changed_func_; | |
447 base::PlatformThreadId np_thread_id_; | |
448 | |
449 scoped_ptr<remoting::RegisterSupportHostRequest> register_request_; | |
450 scoped_refptr<remoting::ChromotingHost> host_; | |
451 scoped_refptr<remoting::MutableHostConfig> host_config_; | |
452 remoting::ChromotingHostContext host_context_; | |
453 int failed_login_attempts_; | |
454 | |
455 base::WaitableEvent disconnected_event_; | |
456 base::CancellationFlag destructing_; | |
457 }; | |
458 | |
459 // string uid, string auth_token | |
460 bool HostNPScriptObject::Connect(const NPVariant* args, | |
461 uint32_t arg_count, | |
462 NPVariant* result) { | |
463 LogDebugInfo("Connecting..."); | |
464 | |
465 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | |
466 if (arg_count != 2) { | |
467 SetException("connect: bad number of arguments"); | |
468 return false; | |
469 } | |
470 | |
471 std::string uid = StringFromNPVariant(args[0]); | |
472 if (uid.empty()) { | |
473 SetException("connect: bad uid argument"); | |
474 return false; | |
475 } | |
476 | |
477 std::string auth_service_with_token = StringFromNPVariant(args[1]); | |
478 std::string auth_token; | |
479 std::string auth_service; | |
480 remoting::ParseAuthTokenWithService(auth_service_with_token, &auth_token, | |
481 &auth_service); | |
482 if (auth_token.empty()) { | |
483 SetException("connect: auth_service_with_token argument has empty token"); | |
484 return false; | |
485 } | |
486 | |
487 ConnectInternal(uid, auth_token, auth_service); | |
488 | |
489 return true; | |
490 } | |
491 | |
492 void HostNPScriptObject::ConnectInternal( | |
493 const std::string& uid, | |
494 const std::string& auth_token, | |
495 const std::string& auth_service) { | |
496 if (MessageLoop::current() != host_context_.main_message_loop()) { | |
497 host_context_.main_message_loop()->PostTask( | |
498 FROM_HERE, | |
499 NewRunnableMethod(this, &HostNPScriptObject::ConnectInternal, | |
500 uid, auth_token, auth_service)); | |
501 return; | |
502 } | |
503 // Store the supplied user ID and token to the Host configuration. | |
504 scoped_refptr<remoting::MutableHostConfig> host_config = | |
505 new remoting::InMemoryHostConfig; | |
506 host_config->SetString(remoting::kXmppLoginConfigPath, uid); | |
507 host_config->SetString(remoting::kXmppAuthTokenConfigPath, auth_token); | |
508 host_config->SetString(remoting::kXmppAuthServiceConfigPath, auth_service); | |
509 | |
510 // Create an access verifier and fetch the host secret. | |
511 scoped_ptr<remoting::SupportAccessVerifier> access_verifier; | |
512 access_verifier.reset(new remoting::SupportAccessVerifier); | |
513 | |
514 // Generate a key pair for the Host to use. | |
515 // TODO(wez): Move this to the worker thread. | |
516 remoting::HostKeyPair host_key_pair; | |
517 host_key_pair.Generate(); | |
518 host_key_pair.Save(host_config); | |
519 | |
520 // Request registration of the host for support. | |
521 scoped_ptr<remoting::RegisterSupportHostRequest> register_request( | |
522 new remoting::RegisterSupportHostRequest()); | |
523 if (!register_request->Init( | |
524 host_config.get(), | |
525 base::Bind(&HostNPScriptObject::OnReceivedSupportID, | |
526 base::Unretained(this), | |
527 access_verifier.get()))) { | |
528 OnStateChanged(kDisconnected); | |
529 return; | |
530 } | |
531 | |
532 // Create the Host. | |
533 scoped_refptr<remoting::ChromotingHost> host = | |
534 remoting::ChromotingHost::Create(&host_context_, host_config, | |
535 access_verifier.release()); | |
536 host->AddStatusObserver(this); | |
537 host->AddStatusObserver(register_request.get()); | |
538 host->set_it2me(true); | |
539 | |
540 // Nothing went wrong, so lets save the host, config and request. | |
541 host_ = host; | |
542 host_config_ = host_config; | |
543 register_request_.reset(register_request.release()); | |
544 | |
545 // Start the Host. | |
546 host_->Start(); | |
547 | |
548 OnStateChanged(kRequestedAccessCode); | |
549 return; | |
550 } | |
551 | |
552 bool HostNPScriptObject::Disconnect(const NPVariant* args, | |
553 uint32_t arg_count, | |
554 NPVariant* result) { | |
555 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | |
556 if (arg_count != 0) { | |
557 SetException("disconnect: bad number of arguments"); | |
558 return false; | |
559 } | |
560 | |
561 DisconnectInternal(); | |
562 | |
563 return true; | |
564 } | |
565 | |
566 void HostNPScriptObject::DisconnectInternal() { | |
567 if (MessageLoop::current() != host_context_.main_message_loop()) { | |
568 host_context_.main_message_loop()->PostTask( | |
569 FROM_HERE, | |
570 NewRunnableMethod(this, &HostNPScriptObject::DisconnectInternal)); | |
571 return; | |
572 } | |
573 | |
574 if (!host_) { | |
575 disconnected_event_.Signal(); | |
576 return; | |
577 } | |
578 | |
579 host_->Shutdown( | |
580 NewRunnableMethod(this, &HostNPScriptObject::OnShutdownFinished)); | |
581 } | |
582 | |
583 void HostNPScriptObject::OnShutdownFinished() { | |
584 DCHECK_EQ(MessageLoop::current(), host_context_.main_message_loop()); | |
585 | |
586 host_ = NULL; | |
587 register_request_.reset(); | |
588 host_config_ = NULL; | |
589 disconnected_event_.Signal(); | |
590 } | |
591 | |
592 void HostNPScriptObject::OnReceivedSupportID( | |
593 remoting::SupportAccessVerifier* access_verifier, | |
594 bool success, | |
595 const std::string& support_id) { | |
596 CHECK_NE(base::PlatformThread::CurrentId(), np_thread_id_); | |
597 | |
598 if (!success) { | |
599 // TODO(wez): Replace the success/fail flag with full error reporting. | |
600 DisconnectInternal(); | |
601 return; | |
602 } | |
603 | |
604 // Inform the AccessVerifier of our Support-Id, for authentication. | |
605 access_verifier->OnIT2MeHostRegistered(success, support_id); | |
606 | |
607 // Combine the Support Id with the Host Id to make the Access Code. | |
608 // TODO(wez): Locking, anyone? | |
609 access_code_ = support_id + "-" + access_verifier->host_secret(); | |
610 | |
611 // Let the caller know that life is good. | |
612 OnStateChanged(kReceivedAccessCode); | |
613 } | |
614 | |
615 void HostNPScriptObject::OnStateChanged(State state) { | |
616 if (destructing_.IsSet()) { | |
617 return; | |
618 } | |
619 | |
620 if (!host_context_.IsUIThread()) { | |
621 host_context_.PostToUIThread( | |
622 FROM_HERE, | |
623 NewRunnableMethod(this, &HostNPScriptObject::OnStateChanged, state)); | |
624 return; | |
625 } | |
626 state_ = state; | |
627 if (on_state_changed_func_) { | |
628 VLOG(2) << "Calling state changed " << state; | |
629 bool is_good = CallJSFunction(on_state_changed_func_, NULL, 0, NULL); | |
630 LOG_IF(ERROR, !is_good) << "OnStateChangedNP failed"; | |
631 } | |
632 } | |
633 | |
634 void HostNPScriptObject::LogDebugInfo(const std::string& message) { | |
635 if (!host_context_.IsUIThread()) { | |
636 host_context_.PostToUIThread( | |
637 FROM_HERE, | |
638 NewRunnableMethod(this, &HostNPScriptObject::LogDebugInfo, message)); | |
639 return; | |
640 } | |
641 if (log_debug_info_func_) { | |
642 NPVariant* arg = new NPVariant(); | |
643 LOG(INFO) << "Logging: " << message; | |
644 STRINGZ_TO_NPVARIANT(message.c_str(), *arg); | |
645 bool is_good = CallJSFunction(log_debug_info_func_, arg, 1, NULL); | |
646 LOG_IF(ERROR, !is_good) << "LogDebugInfo failed"; | |
647 } | |
648 } | |
649 | |
650 void HostNPScriptObject::SetException(const std::string& exception_string) { | |
651 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | |
652 g_npnetscape_funcs->setexception(parent_, exception_string.c_str()); | |
653 LogDebugInfo(exception_string); | |
654 } | |
655 | |
656 bool HostNPScriptObject::CallJSFunction(NPObject* func, | |
657 const NPVariant* args, | |
658 uint32_t argCount, | |
659 NPVariant* result) { | |
660 NPVariant np_result; | |
661 bool is_good = func->_class->invokeDefault(func, args, argCount, &np_result); | |
662 if (is_good) { | |
663 if (result) { | |
664 *result = np_result; | |
665 } else { | |
666 g_npnetscape_funcs->releasevariantvalue(&np_result); | |
667 } | |
668 } | |
669 return is_good; | |
670 } | |
671 | |
672 void HostNPScriptObject::PostTaskToNPThread( | |
673 const tracked_objects::Location& from_here, Task* task) { | |
674 // The NPAPI functions cannot make use of |from_here|, but this method is | |
675 // passed as a callback to ChromotingHostContext, so it needs to have the | |
676 // appropriate signature. | |
677 | |
678 // Can be called from any thread. | |
679 g_npnetscape_funcs->pluginthreadasynccall(plugin_, | |
680 &NPTaskSpringboard, | |
681 task); | |
682 } | |
683 | |
684 void HostNPScriptObject::NPTaskSpringboard(void* task) { | |
685 Task* real_task = reinterpret_cast<Task*>(task); | |
686 real_task->Run(); | |
687 delete real_task; | |
688 } | |
689 | |
690 // NPAPI plugin implementation for remoting host. | 58 // NPAPI plugin implementation for remoting host. |
691 // Documentation for most of the calls in this class can be found here: | 59 // Documentation for most of the calls in this class can be found here: |
692 // https://developer.mozilla.org/en/Gecko_Plugin_API_Reference/Scripting_plugins | 60 // https://developer.mozilla.org/en/Gecko_Plugin_API_Reference/Scripting_plugins |
693 class HostNPPlugin { | 61 class HostNPPlugin { |
694 public: | 62 public: |
695 // |mode| is the display mode of plug-in. Values: | 63 // |mode| is the display mode of plug-in. Values: |
696 // NP_EMBED: (1) Instance was created by an EMBED tag and shares the browser | 64 // NP_EMBED: (1) Instance was created by an EMBED tag and shares the browser |
697 // window with other content. | 65 // window with other content. |
698 // NP_FULL: (2) Instance was created by a separate file and is the primary | 66 // NP_FULL: (2) Instance was created by a separate file and is the primary |
699 // content in the window. | 67 // content in the window. |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
997 return NPERR_NO_ERROR; | 365 return NPERR_NO_ERROR; |
998 } | 366 } |
999 | 367 |
1000 NPError SetWindow(NPP instance, NPWindow* pNPWindow) { | 368 NPError SetWindow(NPP instance, NPWindow* pNPWindow) { |
1001 VLOG(2) << "SetWindow"; | 369 VLOG(2) << "SetWindow"; |
1002 return NPERR_NO_ERROR; | 370 return NPERR_NO_ERROR; |
1003 } | 371 } |
1004 | 372 |
1005 } // namespace | 373 } // namespace |
1006 | 374 |
1007 DISABLE_RUNNABLE_METHOD_REFCOUNT(HostNPScriptObject); | |
1008 | |
1009 #if defined(OS_WIN) | 375 #if defined(OS_WIN) |
1010 HMODULE g_hModule = NULL; | 376 HMODULE g_hModule = NULL; |
1011 | 377 |
1012 BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) { | 378 BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) { |
1013 switch (dwReason) { | 379 switch (dwReason) { |
1014 case DLL_PROCESS_ATTACH: | 380 case DLL_PROCESS_ATTACH: |
1015 g_hModule = hModule; | 381 g_hModule = hModule; |
1016 DisableThreadLibraryCalls(hModule); | 382 DisableThreadLibraryCalls(hModule); |
1017 break; | 383 break; |
1018 case DLL_PROCESS_DETACH: | 384 case DLL_PROCESS_DETACH: |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1079 } | 445 } |
1080 | 446 |
1081 EXPORT NPError API_CALL NP_GetValue(void* npp, | 447 EXPORT NPError API_CALL NP_GetValue(void* npp, |
1082 NPPVariable variable, | 448 NPPVariable variable, |
1083 void* value) { | 449 void* value) { |
1084 return GetValue((NPP)npp, variable, value); | 450 return GetValue((NPP)npp, variable, value); |
1085 } | 451 } |
1086 #endif | 452 #endif |
1087 | 453 |
1088 } // extern "C" | 454 } // extern "C" |
OLD | NEW |