/indra/llplugin/llplugininstance.cpp
C++ | 186 lines | 95 code | 22 blank | 69 comment | 15 complexity | c7443ec3099f1d629c4dedfd56c0d514 MD5 | raw file
Possible License(s): LGPL-2.1
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 * @cond 6 * $LicenseInfo:firstyear=2008&license=viewerlgpl$ 7 * Second Life Viewer Source Code 8 * Copyright (C) 2010, Linden Research, Inc. 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; 13 * version 2.1 of the License only. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23 * 24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA 25 * $/LicenseInfo$ 26 * @endcond 27 */ 28 29#include "linden_common.h" 30 31#include "llplugininstance.h" 32 33#include "llapr.h" 34 35#if LL_WINDOWS 36#include "direct.h" // needed for _chdir() 37#endif 38 39/** Virtual destructor. */ 40LLPluginInstanceMessageListener::~LLPluginInstanceMessageListener() 41{ 42} 43 44/** 45 * TODO:DOC describe how it's used 46 */ 47const char *LLPluginInstance::PLUGIN_INIT_FUNCTION_NAME = "LLPluginInitEntryPoint"; 48 49/** 50 * Constructor. 51 * 52 * @param[in] owner Plugin instance. TODO:DOC is this a good description of what "owner" is? 53 */ 54LLPluginInstance::LLPluginInstance(LLPluginInstanceMessageListener *owner) : 55 mDSOHandle(NULL), 56 mPluginUserData(NULL), 57 mPluginSendMessageFunction(NULL) 58{ 59 mOwner = owner; 60} 61 62/** 63 * Destructor. 64 */ 65LLPluginInstance::~LLPluginInstance() 66{ 67 if(mDSOHandle != NULL) 68 { 69 apr_dso_unload(mDSOHandle); 70 mDSOHandle = NULL; 71 } 72} 73 74/** 75 * Dynamically loads the plugin and runs the plugin's init function. 76 * 77 * @param[in] plugin_file Name of plugin dll/dylib/so. TODO:DOC is this correct? see .h 78 * @return 0 if successful, APR error code or error code from the plugin's init function on failure. 79 */ 80int LLPluginInstance::load(const std::string& plugin_dir, std::string &plugin_file) 81{ 82 pluginInitFunction init_function = NULL; 83 84 if ( plugin_dir.length() ) 85 { 86#if LL_WINDOWS 87 // VWR-21275: 88 // *SOME* Windows systems fail to load the Qt plugins if the current working 89 // directory is not the same as the directory with the Qt DLLs in. 90 // This should not cause any run time issues since we are changing the cwd for the 91 // plugin shell process and not the viewer. 92 // Changing back to the previous directory is not necessary since the plugin shell 93 // quits once the plugin exits. 94 _chdir( plugin_dir.c_str() ); 95#endif 96 }; 97 98 int result = apr_dso_load(&mDSOHandle, 99 plugin_file.c_str(), 100 gAPRPoolp); 101 if(result != APR_SUCCESS) 102 { 103 char buf[1024]; 104 apr_dso_error(mDSOHandle, buf, sizeof(buf)); 105 106 LL_WARNS("Plugin") << "apr_dso_load of " << plugin_file << " failed with error " << result << " , additional info string: " << buf << LL_ENDL; 107 108 } 109 110 if(result == APR_SUCCESS) 111 { 112 result = apr_dso_sym((apr_dso_handle_sym_t*)&init_function, 113 mDSOHandle, 114 PLUGIN_INIT_FUNCTION_NAME); 115 116 if(result != APR_SUCCESS) 117 { 118 LL_WARNS("Plugin") << "apr_dso_sym failed with error " << result << LL_ENDL; 119 } 120 } 121 122 if(result == APR_SUCCESS) 123 { 124 result = init_function(staticReceiveMessage, (void*)this, &mPluginSendMessageFunction, &mPluginUserData); 125 126 if(result != APR_SUCCESS) 127 { 128 LL_WARNS("Plugin") << "call to init function failed with error " << result << LL_ENDL; 129 } 130 } 131 132 return (int)result; 133} 134 135/** 136 * Sends a message to the plugin. 137 * 138 * @param[in] message Message 139 */ 140void LLPluginInstance::sendMessage(const std::string &message) 141{ 142 if(mPluginSendMessageFunction) 143 { 144 LL_DEBUGS("Plugin") << "sending message to plugin: \"" << message << "\"" << LL_ENDL; 145 mPluginSendMessageFunction(message.c_str(), &mPluginUserData); 146 } 147 else 148 { 149 LL_WARNS("Plugin") << "dropping message: \"" << message << "\"" << LL_ENDL; 150 } 151} 152 153/** 154 * Idle. TODO:DOC what's the purpose of this? 155 * 156 */ 157void LLPluginInstance::idle(void) 158{ 159} 160 161// static 162void LLPluginInstance::staticReceiveMessage(const char *message_string, void **user_data) 163{ 164 // TODO: validate that the user_data argument is still a valid LLPluginInstance pointer 165 // we could also use a key that's looked up in a map (instead of a direct pointer) for safety, but that's probably overkill 166 LLPluginInstance *self = (LLPluginInstance*)*user_data; 167 self->receiveMessage(message_string); 168} 169 170/** 171 * Plugin receives message from plugin loader shell. 172 * 173 * @param[in] message_string Message 174 */ 175void LLPluginInstance::receiveMessage(const char *message_string) 176{ 177 if(mOwner) 178 { 179 LL_DEBUGS("Plugin") << "processing incoming message: \"" << message_string << "\"" << LL_ENDL; 180 mOwner->receivePluginMessage(message_string); 181 } 182 else 183 { 184 LL_WARNS("Plugin") << "dropping incoming message: \"" << message_string << "\"" << LL_ENDL; 185 } 186}