Newer
Older
Andrey Lihatskiy
committed
/**
* @file llplugininstance.cpp
* @brief LLPluginInstance handles loading the dynamic library of a plugin and setting up its entry points for message passing.
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Copyright (C) 2010, Linden Research, Inc.
Andrey Lihatskiy
committed
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
Andrey Lihatskiy
committed
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
Andrey Lihatskiy
committed
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Andrey Lihatskiy
committed
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
*/
#include "linden_common.h"
#include "llplugininstance.h"
#include "llapr.h"
callum
committed
#if LL_WINDOWS
Andrey Lihatskiy
committed
#include "direct.h" // needed for _chdir()
callum
committed
#endif
Andrey Lihatskiy
committed
/**
* TODO:DOC describe how it's used
const char *LLPluginInstance::PLUGIN_INIT_FUNCTION_NAME = "ALPluginInitEntryPoint";
Andrey Lihatskiy
committed
/**
* @param[in] owner Plugin instance. TODO:DOC is this a good description of what "owner" is?
LLPluginInstance::LLPluginInstance(LLPluginInstanceMessageListener *owner) :
Andrey Lihatskiy
committed
mDSOHandle(NULL),
mPluginUserData(NULL),
mPluginSendMessageFunction(NULL)
Andrey Lihatskiy
committed
mOwner = owner;
Andrey Lihatskiy
committed
/**
LLPluginInstance::~LLPluginInstance()
{
Andrey Lihatskiy
committed
if(mDSOHandle != NULL)
{
apr_dso_unload(mDSOHandle);
mDSOHandle = NULL;
}
Andrey Lihatskiy
committed
/**
* Dynamically loads the plugin and runs the plugin's init function.
*
* @param[in] plugin_file Name of plugin dll/dylib/so. TODO:DOC is this correct? see .h
* @return 0 if successful, APR error code or error code from the plugin's init function on failure.
*/
callum
committed
int LLPluginInstance::load(const std::string& plugin_dir, std::string &plugin_file)
Andrey Lihatskiy
committed
pluginInitFunction init_function = NULL;
if ( plugin_dir.length() )
{
callum
committed
#if LL_WINDOWS
Andrey Lihatskiy
committed
// VWR-21275:
// *SOME* Windows systems fail to load the Qt plugins if the current working
// directory is not the same as the directory with the Qt DLLs in.
// This should not cause any run time issues since we are changing the cwd for the
// plugin shell process and not the viewer.
// Changing back to the previous directory is not necessary since the plugin shell
// quits once the plugin exits.
_chdir( plugin_dir.c_str() );
callum
committed
#endif
Andrey Lihatskiy
committed
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
};
int result = apr_dso_load(&mDSOHandle,
plugin_file.c_str(),
gAPRPoolp);
if(result != APR_SUCCESS)
{
char buf[1024];
apr_dso_error(mDSOHandle, buf, sizeof(buf));
LL_WARNS("Plugin") << "apr_dso_load of " << plugin_file << " failed with error " << result << " , additional info string: " << buf << LL_ENDL;
}
if(result == APR_SUCCESS)
{
result = apr_dso_sym((apr_dso_handle_sym_t*)&init_function,
mDSOHandle,
PLUGIN_INIT_FUNCTION_NAME);
if(result != APR_SUCCESS)
{
LL_WARNS("Plugin") << "apr_dso_sym failed with error " << result << LL_ENDL;
}
}
if(result == APR_SUCCESS)
{
result = init_function(staticReceiveMessage, (void*)this, &mPluginSendMessageFunction, &mPluginUserData);
if(result != APR_SUCCESS)
{
LL_WARNS("Plugin") << "call to init function failed with error " << result << LL_ENDL;
}
}
return (int)result;
Andrey Lihatskiy
committed
/**
* Sends a message to the plugin.
*
* @param[in] message Message
*/
void LLPluginInstance::sendMessage(const std::string &message)
{
Andrey Lihatskiy
committed
if(mPluginSendMessageFunction)
{
Andrey Lihatskiy
committed
LL_DEBUGS("Plugin") << "sending message to plugin: \"" << message << "\"" << LL_ENDL;
Andrey Lihatskiy
committed
mPluginSendMessageFunction(message.c_str(), &mPluginUserData);
}
else
{
LL_WARNS("Plugin") << "dropping message: \"" << message << "\"" << LL_ENDL;
}
/**
* Idle. TODO:DOC what's the purpose of this?
*
*/
void LLPluginInstance::idle(void)
{
}
// static
void LLPluginInstance::staticReceiveMessage(const char *message_string, void **user_data)
{
Andrey Lihatskiy
committed
// TODO: validate that the user_data argument is still a valid LLPluginInstance pointer
// 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
LLPluginInstance *self = (LLPluginInstance*)*user_data;
self->receiveMessage(message_string);
/**
* Plugin receives message from plugin loader shell.
*
* @param[in] message_string Message
*/
void LLPluginInstance::receiveMessage(const char *message_string)
{
Andrey Lihatskiy
committed
if(mOwner)
{
Andrey Lihatskiy
committed
LL_DEBUGS("Plugin") << "processing incoming message: \"" << message_string << "\"" << LL_ENDL;
Andrey Lihatskiy
committed
mOwner->receivePluginMessage(message_string);
}
else
{
LL_WARNS("Plugin") << "dropping incoming message: \"" << message_string << "\"" << LL_ENDL;
}