llplugininstance.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /**
  2. * @file llplugininstance.cpp
  3. * @brief LLPluginInstance handles loading the dynamic library of a plugin and setting up its entry points for message passing.
  4. *
  5. * $LicenseInfo:firstyear=2008&license=viewergpl$
  6. *
  7. * Copyright (c) 2008-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "linden_common.h"
  33. #include "llplugininstance.h"
  34. #include "llapr.h"
  35. #if LL_WINDOWS
  36. # include "direct.h" // Needed for _chdir()
  37. #endif
  38. const char* LLPluginInstance::PLUGIN_INIT_FUNCTION_NAME = "LLPluginInitEntryPoint";
  39. LLPluginInstance::LLPluginInstance(LLPluginInstanceMessageListener* ownerp)
  40. : mOwner(ownerp),
  41. mDSOHandle(NULL),
  42. mPluginUserData(NULL),
  43. mPluginSendMessageFunction(NULL)
  44. {
  45. }
  46. LLPluginInstance::~LLPluginInstance()
  47. {
  48. if (mDSOHandle)
  49. {
  50. apr_dso_unload(mDSOHandle);
  51. mDSOHandle = NULL;
  52. }
  53. }
  54. // Dynamically loads the plugin and runs the plugin's init function.
  55. // plugin_file is the file name of plugin dll/dylib/so.
  56. // Returns 0 if successful, APR error code or error code from the plugin init
  57. // function on failure.
  58. int LLPluginInstance::load(const std::string& plugin_dir,
  59. const std::string& plugin_file)
  60. {
  61. pluginInitFunction init_function = NULL;
  62. if (plugin_dir.length())
  63. {
  64. #if LL_WINDOWS
  65. // VWR-21275:
  66. // *SOME* Windows systems fail to load the Qt plugins if the current
  67. // working directory is not the same as the directory with the Qt DLLs
  68. // in. This should not cause any run time issues since we are changing
  69. // the cwd for the plugin shell process and not the viewer.
  70. // Changing back to the previous directory is not necessary since the
  71. // plugin shell quits once the plugin exits.
  72. _chdir(plugin_dir.c_str());
  73. #endif
  74. }
  75. int result = apr_dso_load(&mDSOHandle, plugin_file.c_str(), gAPRPoolp);
  76. if (result != APR_SUCCESS)
  77. {
  78. char buf[1024];
  79. apr_dso_error(mDSOHandle, buf, sizeof(buf));
  80. llwarns << "apr_dso_load() of " << plugin_file << " failed with error "
  81. << result << " , additional info string: " << buf << llendl;
  82. }
  83. if (result == APR_SUCCESS)
  84. {
  85. result = apr_dso_sym((apr_dso_handle_sym_t*)&init_function,
  86. mDSOHandle,
  87. PLUGIN_INIT_FUNCTION_NAME);
  88. if (result != APR_SUCCESS)
  89. {
  90. llwarns << "apr_dso_sym() failed with error " << result << llendl;
  91. }
  92. }
  93. if (result == APR_SUCCESS)
  94. {
  95. result = init_function(staticReceiveMessage, (void*)this,
  96. &mPluginSendMessageFunction, &mPluginUserData);
  97. if (result == APR_SUCCESS)
  98. {
  99. llinfos << "Loaded " << plugin_file << " successfully." << llendl;
  100. }
  101. else
  102. {
  103. llwarns << "Call to init function failed with error " << result
  104. << llendl;
  105. }
  106. }
  107. return result;
  108. }
  109. // Sends a message to the plugin.
  110. void LLPluginInstance::sendMessage(const std::string& message)
  111. {
  112. if (mPluginSendMessageFunction)
  113. {
  114. LL_DEBUGS("PluginMessages") << "sending message to plugin: \""
  115. << message << "\"" << LL_ENDL;
  116. mPluginSendMessageFunction(message.c_str(), &mPluginUserData);
  117. }
  118. else
  119. {
  120. llwarns << "Dropping message: \"" << message << "\"" << llendl;
  121. }
  122. }
  123. //static
  124. void LLPluginInstance::staticReceiveMessage(const char* message_string,
  125. void** user_data)
  126. {
  127. // *TODO: validate that the user_data argument is still a valid
  128. // LLPluginInstance pointer. We could also use a key that is looked up in a
  129. // map (instead of a direct pointer) for safety, but that is probably
  130. // overkill.
  131. LLPluginInstance* self = (LLPluginInstance*)*user_data;
  132. if (self)
  133. {
  134. self->receiveMessage(message_string);
  135. }
  136. }
  137. // Plugin receives message from plugin loader shell.
  138. void LLPluginInstance::receiveMessage(const char* message_string)
  139. {
  140. if (!mOwner)
  141. {
  142. llwarns_once << "No owner: cannot process messages !" << llendl;
  143. return;
  144. }
  145. LL_DEBUGS("PluginMessages") << "processing incoming message: \""
  146. << message_string << "\"" << LL_ENDL;
  147. mOwner->receivePluginMessage(message_string);
  148. }