/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2023 Osimis S.A., Belgium
* Copyright (C) 2024-2025 Orthanc Team SRL, Belgium
* Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
*
* This program 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, either version 3 of
* the License, or (at your option) any later version.
*
* This program 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program. If not, see
* .
**/
#include "PrecompiledHeaders.h"
#include "SharedLibrary.h"
#include "Logging.h"
#include "OrthancException.h"
#include
#if defined(_WIN32)
#include
#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include
#else
#error Support your platform here
#endif
namespace Orthanc
{
SharedLibrary::SharedLibrary(const std::string& path) :
path_(path),
handle_(NULL)
{
#if defined(_WIN32)
handle_ = ::LoadLibraryA(path_.c_str());
if (handle_ == NULL)
{
LOG(ERROR) << "LoadLibrary(" << path_ << ") failed: Error " << ::GetLastError();
if (::GetLastError() == ERROR_BAD_EXE_FORMAT &&
sizeof(void*) == 4)
{
throw OrthancException(ErrorCode_SharedLibrary,
"You are most probably trying to load a 64bit plugin into a 32bit version of Orthanc");
}
else if (::GetLastError() == ERROR_BAD_EXE_FORMAT &&
sizeof(void*) == 8)
{
throw OrthancException(ErrorCode_SharedLibrary,
"You are most probably trying to load a 32bit plugin into a 64bit version of Orthanc");
}
else
{
throw OrthancException(ErrorCode_SharedLibrary);
}
}
#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__)
/**
* "RTLD_LOCAL" is the default, and is only present to be
* explicit. "RTLD_DEEPBIND" was added in Orthanc 1.6.0, in order
* to avoid crashes while loading plugins from the LSB binaries of
* the Orthanc core.
*
* BUT this had no effect, and this results in a crash if loading
* the Python 2.7 plugin => We disabled it again in Orthanc 1.6.1.
**/
#if 0 // && defined(RTLD_DEEPBIND) // This is a GNU extension
// Disabled in Orthanc 1.6.1
handle_ = ::dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
#else
handle_ = ::dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL);
#endif
if (handle_ == NULL)
{
std::string explanation;
const char *tmp = ::dlerror();
if (tmp)
{
explanation = ": Error " + std::string(tmp);
}
LOG(ERROR) << "dlopen(" << path_ << ") failed" << explanation;
throw OrthancException(ErrorCode_SharedLibrary);
}
#else
#error Support your platform here
#endif
}
SharedLibrary::~SharedLibrary()
{
if (handle_)
{
#if defined(_WIN32)
::FreeLibrary((HMODULE)handle_);
#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__)
::dlclose(handle_);
#else
#error Support your platform here
#endif
}
}
const std::string &SharedLibrary::GetPath() const
{
return path_;
}
SharedLibrary::FunctionPointer SharedLibrary::GetFunctionInternal(const std::string& name)
{
if (!handle_)
{
throw OrthancException(ErrorCode_InternalError);
}
#if defined(_WIN32)
return ::GetProcAddress((HMODULE)handle_, name.c_str());
#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__)
return ::dlsym(handle_, name.c_str());
#else
#error Support your platform here
#endif
}
SharedLibrary::FunctionPointer SharedLibrary::GetFunction(const std::string& name)
{
SharedLibrary::FunctionPointer result = GetFunctionInternal(name);
if (result == NULL)
{
throw OrthancException(
ErrorCode_SharedLibrary,
"Shared library does not expose function \"" + name + "\"");
}
else
{
return result;
}
}
bool SharedLibrary::HasFunction(const std::string& name)
{
return GetFunctionInternal(name) != NULL;
}
}