53583e5735
SenseApiDesc: * Use a number count for num exported implexor APIs instead of NULL-terminated list. * Add sanity checker functions for structs. SenseApiLib: * Invoke the new sanity checkers on new Lib objects. * SenseApiDesc is now a member object instead of being pointed to. SenseApiManager: * loadSenseApiLib now calls the SenseApiDesc getter function. * loadSenseApiLib now fills out the SenseApiLib class object. New Sense API Mgmt Sub-API: This sub-api (metalanguage, some might call it) is used to initialize the lib's connection to the provider. After this call, the lib should be ready to attach new devices to its provider on behalf of Hk.
156 lines
4.2 KiB
C++
156 lines
4.2 KiB
C++
#include <iostream>
|
|
#include <stdexcept>
|
|
#include <optional>
|
|
#include <filesystem>
|
|
#include <senseApis/senseApiManager.h>
|
|
#include <senseApis/senseApiLib.h>
|
|
#include <opts.h>
|
|
#include <user/senseApiDesc.h>
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
namespace hk {
|
|
namespace sense_api {
|
|
|
|
struct DlCloser {
|
|
void operator()(void* handle) const {
|
|
if (handle) {
|
|
dlclose(handle);
|
|
}
|
|
}
|
|
};
|
|
|
|
static std::optional<std::string> findLibraryPath(
|
|
const std::string& libraryPath)
|
|
{
|
|
std::vector<std::string> searchPaths = {
|
|
fs::current_path().string(),
|
|
fs::path("/proc/self/exe").parent_path().string()
|
|
};
|
|
|
|
if (!OptionParser::getOptions().senseApiLibPath.empty())
|
|
{
|
|
searchPaths.insert(
|
|
searchPaths.begin(), OptionParser::getOptions().senseApiLibPath);
|
|
}
|
|
|
|
for (const auto& path : searchPaths)
|
|
{
|
|
fs::path fullPath = fs::path(path) / libraryPath;
|
|
if (fs::exists(fullPath))
|
|
{
|
|
return fullPath.string();
|
|
}
|
|
}
|
|
|
|
std::cerr << std::string(__func__) + ": library '"
|
|
+ libraryPath + "' isn't in search bespoke search paths: ";
|
|
for (const auto& path : searchPaths)
|
|
{
|
|
std::cerr << path << " ";
|
|
}
|
|
std::cerr << std::endl;
|
|
std::cerr << "Trying to load " + libraryPath + " from system default search "
|
|
"paths\n";
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
SenseApiLib& SenseApiManager::loadSenseApiLib(const std::string& libraryPath)
|
|
{
|
|
const CSenseApiDesc *libApiDesc;
|
|
std::optional<std::string> fullPath = findLibraryPath(libraryPath);
|
|
std::string resolvedPath = fullPath.value_or(libraryPath);
|
|
|
|
// Clear any existing error
|
|
dlerror();
|
|
auto dlopen_handle = std::unique_ptr<void, DlCloser>(
|
|
dlopen(resolvedPath.c_str(), RTLD_LAZY));
|
|
if (!dlopen_handle && fullPath.has_value())
|
|
{
|
|
// Fallback to using the supplied libraryPath
|
|
dlerror();
|
|
dlopen_handle.reset(dlopen(libraryPath.c_str(), RTLD_LAZY));
|
|
}
|
|
|
|
if (!dlopen_handle)
|
|
{
|
|
const char *dlerr = dlerror();
|
|
|
|
std::string error = (dlerr
|
|
? dlerr
|
|
: "Unknown error while opening shlib");
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": Cannot load library '"
|
|
+ libraryPath + "': "
|
|
+ error);
|
|
}
|
|
|
|
// Initialize getSenseApiDescriptor
|
|
auto func = reinterpret_cast<getSenseApiDescFn *>(
|
|
dlsym(dlopen_handle.get(), HK_GET_SENSE_API_DESC_FN_NAME_STR));
|
|
if (!func)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": dlsym('"
|
|
HK_GET_SENSE_API_DESC_FN_NAME_STR "') failed for library '"
|
|
+ libraryPath + "'");
|
|
}
|
|
|
|
libApiDesc = func();
|
|
if (!libApiDesc)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": getSenseApiDesc() returned NULL for "
|
|
"library '" + libraryPath + "'");
|
|
}
|
|
|
|
auto lib = std::make_unique<SenseApiLib>(
|
|
libraryPath, dlopen_handle.release(), func);
|
|
lib->setSenseApiDesc(libApiDesc);
|
|
senseApiLibs.push_back(std::move(lib));
|
|
return *senseApiLibs.back();
|
|
}
|
|
|
|
std::optional<std::reference_wrapper<SenseApiLib>>
|
|
SenseApiManager::getSenseApiLib(const std::string& libraryPath)
|
|
{
|
|
auto it = std::find_if(senseApiLibs.begin(), senseApiLibs.end(),
|
|
[&libPath = libraryPath](const std::unique_ptr<SenseApiLib>& lib) {
|
|
return lib->libraryPath == libPath;
|
|
}
|
|
);
|
|
|
|
if (it != senseApiLibs.end()) { return **it; }
|
|
return std::nullopt;
|
|
}
|
|
|
|
void SenseApiManager::unloadSenseApiLib(const std::string& libraryPath)
|
|
{
|
|
auto it = std::find_if(senseApiLibs.begin(), senseApiLibs.end(),
|
|
[&lpath = libraryPath](const std::unique_ptr<SenseApiLib>& lib) {
|
|
return lib->libraryPath == lpath;
|
|
}
|
|
);
|
|
|
|
if (it != senseApiLibs.end())
|
|
{
|
|
senseApiLibs.erase(it);
|
|
return;
|
|
}
|
|
|
|
std::cerr << std::string(__func__) + ": Library not found: "
|
|
<< libraryPath << '\n';
|
|
}
|
|
|
|
void SenseApiManager::loadAllSenseApiLibsFromOptions()
|
|
{
|
|
const auto& options = OptionParser::getOptions();
|
|
for (const auto& libPath : options.senseApiLibs) {
|
|
loadSenseApiLib(libPath);
|
|
}
|
|
}
|
|
|
|
} // namespace sense_api
|
|
} // namespace hk
|