/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Synergy Si Ltd.
* Copyright (C) 2012 Nick Bolton
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "arch/unix/ArchPluginUnix.h"
#include "arch/unix/XArchUnix.h"
#include "common/PluginVersion.h"
#include "base/IEventQueue.h"
#include "base/Event.h"
#include "base/Log.h"
#include
#include
#include
#include
typedef void (*initFunc)(void*, void*);
typedef int (*initEventFunc)(void (*sendEvent)(const char*, void*));
typedef void* (*invokeFunc)(const char*, void*);
typedef void (*cleanupFunc)();
void* g_eventTarget = NULL;
IEventQueue* g_events = NULL;
static const char kPre174Plugin[] = "Pre-1.7.4";
ArchPluginUnix::ArchPluginUnix()
{
}
ArchPluginUnix::~ArchPluginUnix()
{
}
void
ArchPluginUnix::load()
{
String pluginsDir = getPluginsDir();
LOG((CLOG_DEBUG "plugins dir: %s", pluginsDir.c_str()));
struct dirent* de = NULL;
DIR* dir = NULL;
dir = opendir(pluginsDir.c_str());
if (dir == NULL) {
LOG((CLOG_DEBUG "can't open plugins dir: %s",
pluginsDir.c_str()));
return;
}
std::vector plugins;
while ((de = readdir(dir)) != NULL) {
// ignore hidden files and diretories like .. and .
if (de->d_name[0] != '.') {
plugins.push_back(de->d_name);
}
}
closedir(dir);
std::vector::iterator it;
for (it = plugins.begin(); it != plugins.end(); ++it) {
LOG((CLOG_DEBUG "loading plugin: %s", (*it).c_str()));
String path = String(getPluginsDir()).append("/").append(*it);
void* library = dlopen(path.c_str(), RTLD_LAZY);
if (library == NULL) {
LOG((CLOG_ERR "failed to load plugin '%s', error: %s", (*it).c_str(), dlerror()));
continue;
}
String filename = synergy::string::removeFileExt(*it);
m_pluginTable.insert(std::make_pair(filename, library));
size_t pos = filename.find("lib");
String pluginName = filename.substr(pos + 3);
char* version = (char*)invoke(filename.c_str(), "version", NULL);
String expectedVersion(pluginVersion(pluginName.c_str()));
if (version != NULL && expectedVersion.compare(version) == 0) {
LOG((CLOG_DEBUG "loaded plugin: %s (%s)", (*it).c_str(), version));
}
else {
LOG((CLOG_WARN "plugin version doesn't match"));
LOG((CLOG_DEBUG "expected plugin version: %s actual plugin version: %s",
expectedVersion.c_str(), version));
LOG((CLOG_WARN "skip plugin: %s", (*it).c_str()));
m_pluginTable.erase(filename);
dlclose(library);
}
}
}
void
ArchPluginUnix::unload()
{
PluginTable::iterator it;
for (it = m_pluginTable.begin(); it != m_pluginTable.end(); it++) {
cleanupFunc cleanup = (cleanupFunc)dlsym(it->second, "cleanup");
if (cleanup != NULL) {
cleanup();
}
else {
LOG((CLOG_DEBUG "no cleanup function in %s", it->first.c_str()));
}
LOG((CLOG_DEBUG "unloading plugin: %s", it->first.c_str()));
dlclose(it->second);
}
}
void
ArchPluginUnix::init(void* log, void* arch)
{
PluginTable::iterator it;
for (it = m_pluginTable.begin(); it != m_pluginTable.end(); it++) {
initFunc initPlugin = (initFunc)dlsym(it->second, "init");
if (initPlugin != NULL) {
initPlugin(log, arch);
}
else {
LOG((CLOG_DEBUG "no init function in %s", it->first.c_str()));
}
}
}
void
ArchPluginUnix::initEvent(void* eventTarget, IEventQueue* events)
{
g_eventTarget = eventTarget;
g_events = events;
PluginTable::iterator it;
for (it = m_pluginTable.begin(); it != m_pluginTable.end(); it++) {
initEventFunc initEventPlugin = (initEventFunc)dlsym(it->second, "initEvent");
if (initEventPlugin != NULL) {
initEventPlugin(&sendEvent);
}
else {
LOG((CLOG_DEBUG "no init event function in %s", it->first.c_str()));
}
}
}
bool
ArchPluginUnix::exists(const char* name)
{
PluginTable::iterator it;
it = m_pluginTable.find(name);
return it != m_pluginTable.end() ? true : false;
}
void*
ArchPluginUnix::invoke(
const char* plugin,
const char* command,
void** args)
{
PluginTable::iterator it;
it = m_pluginTable.find(plugin);
if (it != m_pluginTable.end()) {
invokeFunc invokePlugin = (invokeFunc)dlsym(it->second, "invoke");
void* result = NULL;
if (invokePlugin != NULL) {
result = invokePlugin(command, args);
}
else {
LOG((CLOG_DEBUG "no invoke function in %s", it->first.c_str()));
}
return result;
}
else {
LOG((CLOG_DEBUG "invoke command failed, plugin: %s command: %s",
plugin, command));
return NULL;
}
}
String
ArchPluginUnix::getPluginsDir()
{
return ARCH->getPluginDirectory();
}
void
sendEvent(const char* eventName, void* data)
{
LOG((CLOG_DEBUG5 "plugin sending event"));
Event::Type type = g_events->getRegisteredType(eventName);
g_events->addEvent(Event(type, g_eventTarget, data));
}
void
log(const char* text)
{
LOG((CLOG_DEBUG "plugin: %s", text));
}