| 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 |