You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
proxysql/lib/ProxySQL_PluginManager.cpp

146 lines
3.2 KiB

#include "ProxySQL_PluginManager.h"
#include <cstring>
#include <dlfcn.h>
namespace {
std::string format_dl_error(const char *prefix) {
const char *dl_err = dlerror();
if (dl_err == nullptr) {
return prefix;
}
return std::string(prefix) + dl_err;
}
std::string plugin_name(const ProxySQL_PluginDescriptor *descriptor) {
if (descriptor == nullptr || descriptor->name == nullptr) {
return "unknown";
}
return descriptor->name;
}
} // namespace
ProxySQL_PluginManager::ProxySQL_PluginManager() {
std::memset(&services_, 0, sizeof(services_));
}
ProxySQL_PluginManager::~ProxySQL_PluginManager() {
stop_all();
for (auto it = plugins_.rbegin(); it != plugins_.rend(); ++it) {
if (it->handle != nullptr) {
dlclose(it->handle);
it->handle = nullptr;
}
}
}
bool ProxySQL_PluginManager::load(const std::string &path, std::string &err) {
err.clear();
void *handle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
if (handle == nullptr) {
err = format_dl_error("dlopen failed: ");
return false;
}
dlerror();
auto descriptor_fn = reinterpret_cast<proxysql_plugin_descriptor_v1_t>(
dlsym(handle, "proxysql_plugin_descriptor_v1"));
const char *dlsym_err = dlerror();
if (dlsym_err != nullptr || descriptor_fn == nullptr) {
err = dlsym_err != nullptr ? dlsym_err : "missing proxysql_plugin_descriptor_v1";
dlclose(handle);
return false;
}
const ProxySQL_PluginDescriptor *descriptor = descriptor_fn();
if (descriptor == nullptr) {
err = "proxysql_plugin_descriptor_v1 returned null";
dlclose(handle);
return false;
}
if (descriptor->abi_version != 1) {
err = "unsupported plugin ABI version";
dlclose(handle);
return false;
}
plugin_handle_t plugin;
plugin.handle = handle;
plugin.descriptor = descriptor;
plugins_.push_back(plugin);
return true;
}
bool ProxySQL_PluginManager::init_all(std::string &err) {
err.clear();
for (auto &plugin : plugins_) {
if (plugin.initialized || plugin.stopped) {
continue;
}
if (plugin.descriptor == nullptr || plugin.descriptor->init == nullptr) {
plugin.initialized = true;
continue;
}
if (!plugin.descriptor->init(&services_)) {
err = "plugin init failed: " + plugin_name(plugin.descriptor);
return false;
}
plugin.initialized = true;
}
return true;
}
bool ProxySQL_PluginManager::start_all(std::string &err) {
err.clear();
for (auto &plugin : plugins_) {
if (plugin.started || plugin.stopped) {
continue;
}
if (!plugin.initialized) {
err = "plugin not initialized: " + plugin_name(plugin.descriptor);
return false;
}
if (plugin.descriptor == nullptr || plugin.descriptor->start == nullptr) {
plugin.started = true;
continue;
}
if (!plugin.descriptor->start()) {
err = "plugin start failed: " + plugin_name(plugin.descriptor);
return false;
}
plugin.started = true;
}
return true;
}
bool ProxySQL_PluginManager::stop_all() {
bool ok = true;
for (auto it = plugins_.rbegin(); it != plugins_.rend(); ++it) {
if (!it->initialized && !it->started) {
continue;
}
if (it->stopped) {
continue;
}
if (it->descriptor != nullptr && it->descriptor->stop != nullptr) {
ok = it->descriptor->stop() && ok;
}
it->stopped = true;
}
return ok;
}
size_t ProxySQL_PluginManager::size() const {
return plugins_.size();
}