Loading...
Searching...
No Matches
XrdClPlugInManager.cc
Go to the documentation of this file.
//------------------------------------------------------------------------------
// Copyright (c) 2014 by European Organization for Nuclear Research (CERN)
// Author: Lukasz Janyst <ljanyst@cern.ch>
//------------------------------------------------------------------------------
// This file is part of the XRootD software suite.
//
// XRootD 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.
//
// XRootD 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 Lesser General Public License
// along with XRootD. If not, see <http://www.gnu.org/licenses/>.
//
// In applying this licence, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
//------------------------------------------------------------------------------
#include "XrdCl/XrdClPlugInManager.hh"
#include "XrdCl/XrdClDefaultEnv.hh"
#include "XrdCl/XrdClLog.hh"
#include "XrdCl/XrdClConstants.hh"
#include "XrdCl/XrdClUtils.hh"
#include "XrdCl/XrdClURL.hh"
#include "XrdSys/XrdSysPwd.hh"
#include "XrdVersion.hh"
#ifdef WITH_XRDEC
#include "XrdCl/XrdClEcHandler.hh"
#endif
#include <unistd.h>
#include <sys/types.h>
#include <vector>
#include <string>
#include <algorithm>
XrdVERSIONINFOREF( XrdCl );
namespace XrdCl
{
//----------------------------------------------------------------------------
// Constructor
//----------------------------------------------------------------------------
PlugInManager::PlugInManager():
pDefaultFactory(0)
{
}
//----------------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------------
PlugInManager:: ~PlugInManager()
{
std::map<std::string, FactoryHelper*>::iterator it;
for( it = pFactoryMap.begin(); it != pFactoryMap.end(); ++it )
{
it->second->counter--;
if( it->second->counter == 0 )
delete it->second;
}
delete pDefaultFactory;
}
//----------------------------------------------------------------------------
// Register a plug-in favtory for the given url
//----------------------------------------------------------------------------
bool PlugInManager::RegisterFactory( const std::string &url,
PlugInFactory *factory )
{
Log *log = DefaultEnv::GetLog();
XrdSysMutexHelper scopedLock( pMutex );
std::string normUrl = NormalizeURL( url );
if( normUrl == "" )
return false;
std::map<std::string, FactoryHelper*>::iterator it;
it = pFactoryMap.find( normUrl );
if( it != pFactoryMap.end() )
{
if( it->second->isEnv )
return false;
// we don't need to check the counter because it's valid only
// for environment plugins which cannot be replaced via
// this method
delete it->second;
}
if( !factory )
{
log->Debug( PlugInMgrMsg, "Removing the factory for %s",
normUrl.c_str() );
pFactoryMap.erase( it );
return true;
}
log->Debug( PlugInMgrMsg, "Registering a factory for %s",
normUrl.c_str() );
FactoryHelper *h = new FactoryHelper();
h->factory = factory;
h->counter = 1;
pFactoryMap[normUrl] = h;
return true;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
bool PlugInManager::RegisterDefaultFactory( PlugInFactory *factory )
{
Log *log = DefaultEnv::GetLog();
XrdSysMutexHelper scopedLock( pMutex );
if( pDefaultFactory && pDefaultFactory->isEnv )
return false;
delete pDefaultFactory;
pDefaultFactory = 0;
if( factory )
{
log->Debug( PlugInMgrMsg, "Registering a default factory" );
pDefaultFactory = new FactoryHelper;
pDefaultFactory->factory = factory;
}
else
log->Debug( PlugInMgrMsg, "Removing the default factory" );
return true;
}
//----------------------------------------------------------------------------
// Retrieve the plug-in factory for the given URL
//----------------------------------------------------------------------------
PlugInFactory *PlugInManager::GetFactory( const std::string url )
{
XrdSysMutexHelper scopedLock( pMutex );
if( pDefaultFactory && pDefaultFactory->isEnv )
return pDefaultFactory->factory;
std::string normUrl = NormalizeURL( url );
if( normUrl.empty() )
{
if( pDefaultFactory )
return pDefaultFactory->factory;
return 0;
}
std::map<std::string, FactoryHelper*>::iterator it;
it = pFactoryMap.find( normUrl );
if( it != pFactoryMap.end() && it->second->isEnv )
return it->second->factory;
std::string protocol = URL( url ).GetProtocol();
std::map<std::string, FactoryHelper*>::iterator itProt;
itProt = pFactoryMap.find( protocol );
if( itProt != pFactoryMap.end() && itProt->second->isEnv )
return itProt->second->factory;
if( pDefaultFactory )
return pDefaultFactory->factory;
if( it != pFactoryMap.end() )
return it->second->factory;
if( itProt != pFactoryMap.end() )
return itProt->second->factory;
return 0;
}
//----------------------------------------------------------------------------
// Process user environment to load plug-in settings.
//----------------------------------------------------------------------------
void PlugInManager::ProcessEnvironmentSettings()
{
XrdSysMutexHelper scopedLock( pMutex );
Log *log = DefaultEnv::GetLog();
Env *env = DefaultEnv::GetEnv();
log->Debug( PlugInMgrMsg, "Initializing plug-in manager..." );
//--------------------------------------------------------------------------
// Check if a default plug-in has been specified in the environment
//--------------------------------------------------------------------------
bool loadConfigs = true;
std::string defaultPlugIn = DefaultPlugIn;
env->GetString( "PlugIn", defaultPlugIn );
if( !defaultPlugIn.empty() )
{
loadConfigs = false;
log->Debug( PlugInMgrMsg, "Loading default plug-in from %s...",
defaultPlugIn.c_str());
std::pair<XrdOucPinLoader*, PlugInFactory *> pg = LoadFactory(
defaultPlugIn, std::map<std::string, std::string>() );
if( !pg.first )
{
log->Debug( PlugInMgrMsg, "Failed to load default plug-in from %s",
defaultPlugIn.c_str());
loadConfigs = false;
}
pDefaultFactory = new FactoryHelper();
pDefaultFactory->factory = pg.second;
pDefaultFactory->plugin = pg.first;
pDefaultFactory->isEnv = true;
}
//--------------------------------------------------------------------------
// If there is no default plug-in or it is invalid then load plug-in config
// files
//--------------------------------------------------------------------------
if( loadConfigs )
{
log->Debug( PlugInMgrMsg,
"No default plug-in, loading plug-in configs..." );
ProcessConfigDir( "/etc/xrootd/client.plugins.d" );
XrdSysPwd pwdHandler;
passwd *pwd = pwdHandler.Get( getuid() );
if( pwd )
{
std::string userPlugIns = pwd->pw_dir;
userPlugIns += "/.xrootd/client.plugins.d";
ProcessConfigDir( userPlugIns );
}
std::string customPlugIns = DefaultPlugInConfDir;
env->GetString( "PlugInConfDir", customPlugIns );
if( !customPlugIns.empty() )
ProcessConfigDir( customPlugIns );
}
}
//----------------------------------------------------------------------------
// Process the configuration directory and load plug in definitions
//----------------------------------------------------------------------------
void PlugInManager::ProcessConfigDir( const std::string &dir )
{
Log *log = DefaultEnv::GetLog();
log->Debug( PlugInMgrMsg, "Processing plug-in definitions in %s...",
dir.c_str());
std::vector<std::string> entries;
std::vector<std::string>::iterator it;
Status st = Utils::GetDirectoryEntries( entries, dir );
if( !st.IsOK() )
{
log->Debug( PlugInMgrMsg, "Unable to process directory %s: %s",
dir.c_str(), st.ToString().c_str() );
return;
}
std::sort( entries.begin(), entries.end() );
for( it = entries.begin(); it != entries.end(); ++it )
{
std::string confFile = dir + "/" + *it;
std::string suffix = ".conf";
if( confFile.length() <= suffix.length() )
continue;
if( !std::equal( suffix.rbegin(), suffix.rend(), confFile.rbegin() ) )
continue;
ProcessPlugInConfig( confFile );
}
}
//----------------------------------------------------------------------------
// Process a plug-in config file and load the plug-in if possible
//----------------------------------------------------------------------------
void PlugInManager::ProcessPlugInConfig( const std::string &confFile )
{
Log *log = DefaultEnv::GetLog();
log->Dump( PlugInMgrMsg, "Processing: %s", confFile.c_str() );
//--------------------------------------------------------------------------
// Read the config
//--------------------------------------------------------------------------
std::map<std::string, std::string> config;
Status st = Utils::ProcessConfig( config, confFile );
if( !st.IsOK() )
{
log->Debug( PlugInMgrMsg, "Unable process config %s: %s",
confFile.c_str(), st.ToString().c_str() );
return;
}
const char *keys[] = { "url", "lib", "enable", 0 };
for( int i = 0; keys[i]; ++i )
{
if( config.find( keys[i] ) == config.end() )
{
log->Debug( PlugInMgrMsg, "Unable to find '%s' key in the config file "
"%s, ignoring this config", keys[i], confFile.c_str() );
return;
}
}
//--------------------------------------------------------------------------
// Attempt to load the plug in and place it in the map
//--------------------------------------------------------------------------
std::string url = config["url"];
std::string lib = config["lib"];
std::string enable = config["enable"];
log->Dump( PlugInMgrMsg, "Settings from '%s': url='%s', lib='%s', "
"enable='%s'", confFile.c_str(), url.c_str(), lib.c_str(),
enable.c_str() );
std::pair<XrdOucPinLoader*, PlugInFactory *> pg;
pg.first = 0; pg.second = 0;
if( enable == "true" )
{
log->Debug( PlugInMgrMsg, "Trying to load a plug-in for '%s' from '%s'",
url.c_str(), lib.c_str() );
pg = LoadFactory( lib, config );
if( !pg.second )
return;
}
else
log->Debug( PlugInMgrMsg, "Trying to disable plug-in for '%s'",
url.c_str() );
if( !RegisterFactory( url, lib, pg.second, pg.first ) )
{
delete pg.first;
delete pg.second;
}
}
//----------------------------------------------------------------------------
// Load the plug-in and create the factory
//----------------------------------------------------------------------------
std::pair<XrdOucPinLoader*,PlugInFactory*> PlugInManager::LoadFactory(
const std::string &lib, const std::map<std::string, std::string> &config )
{
Log *log = DefaultEnv::GetLog();
#ifdef WITH_XRDEC
if( lib == "XrdEcDefault" )
{
auto itr = config.find( "nbdta" );
if( itr == config.end() )
return std::make_pair<XrdOucPinLoader*, PlugInFactory*>( nullptr, nullptr );
uint8_t nbdta = std::stoul( itr->second );
itr = config.find( "nbprt" );
if( itr == config.end() )
return std::make_pair<XrdOucPinLoader*, PlugInFactory*>( nullptr, nullptr );
uint8_t nbprt = std::stoul( itr->second );
itr = config.find( "chsz" );
if( itr == config.end() )
return std::make_pair<XrdOucPinLoader*, PlugInFactory*>( nullptr, nullptr );
uint64_t chsz = std::stoul( itr->second );
std::vector<std::string> plgr;
itr = config.find( "plgr" );
if( itr != config.end() )
Utils::splitString( plgr, itr->second, "," );
std::string xrdclECenv = std::to_string(nbdta) + "," +
std::to_string(nbprt) + "," +
std::to_string(chsz);
setenv("XRDCL_EC", xrdclECenv.c_str(), 1);
EcPlugInFactory *ecHandler = new EcPlugInFactory( nbdta, nbprt, chsz, std::move( plgr ) );
return std::make_pair<XrdOucPinLoader*, PlugInFactory*>( nullptr, ecHandler );
}
#endif
char errorBuff[1024];
XrdOucPinLoader *pgHandler = new XrdOucPinLoader( errorBuff, 1024,
&XrdVERSIONINFOVAR( XrdCl ),
"client", lib.c_str() );
PlugInFunc_t pgFunc = (PlugInFunc_t)pgHandler->Resolve("XrdClGetPlugIn", -1);
if( !pgFunc )
{
log->Debug( PlugInMgrMsg, "Error while loading %s: %s", lib.c_str(),
errorBuff );
pgHandler->Unload();
delete pgHandler;
return std::make_pair<XrdOucPinLoader*, PlugInFactory*>( 0, 0 );
}
PlugInFactory *f = (PlugInFactory*)pgFunc( &config );
if( !f )
{
delete pgHandler;
return std::make_pair<XrdOucPinLoader*, PlugInFactory*>( 0, 0 );
}
return std::make_pair( pgHandler, f );
}
//----------------------------------------------------------------------------
// Handle factory - register it or free all the memory
//----------------------------------------------------------------------------
bool PlugInManager::RegisterFactory( const std::string &urlString,
const std::string &lib,
PlugInFactory *factory,
XrdOucPinLoader *plugin )
{
//--------------------------------------------------------------------------
// Process and normalize the URLs
//--------------------------------------------------------------------------
Log *log = DefaultEnv::GetLog();
std::vector<std::string> urls;
std::vector<std::string> normalizedURLs;
std::vector<std::string>::iterator it;
if (urlString == "*") {
if (pDefaultFactory) {
if (pDefaultFactory->isEnv) {
log->Debug(PlugInMgrMsg, "There is already an env default plugin "
"loaded, skipping %s", lib.c_str());
return false;
} else {
log->Debug(PlugInMgrMsg, "There can be only one default plugin "
"loaded, skipping %s", lib.c_str());
return false;
}
} else {
pDefaultFactory = new FactoryHelper();
pDefaultFactory->factory = factory;
pDefaultFactory->plugin = plugin;
pDefaultFactory->isEnv = false;
return true;
}
}
Utils::splitString( urls, urlString, ";" );
for( it = urls.begin(); it != urls.end(); ++it )
{
std::string normURL = NormalizeURL( *it );
if( normURL == "" )
{
log->Debug( PlugInMgrMsg, "Url cannot be normalized: '%s', ignoring",
it->c_str() );
continue;
}
normalizedURLs.push_back( normURL );
}
std::sort( normalizedURLs.begin(), normalizedURLs.end() );
auto last = std::unique( normalizedURLs.begin(), normalizedURLs.end() );
normalizedURLs.erase( last, normalizedURLs.end() );
if( normalizedURLs.empty() )
return false;
//--------------------------------------------------------------------------
// Insert or remove from the map
//--------------------------------------------------------------------------
FactoryHelper *h = 0;
if( factory )
{
h = new FactoryHelper();
h->isEnv = true;
h->counter = normalizedURLs.size();
h->plugin = plugin;
h->factory = factory;
}
std::map<std::string, FactoryHelper*>::iterator mapIt;
for( it = normalizedURLs.begin(); it != normalizedURLs.end(); ++it )
{
mapIt = pFactoryMap.find( *it );
if( mapIt != pFactoryMap.end() )
{
mapIt->second->counter--;
if( mapIt->second->counter == 0 )
delete mapIt->second;
}
if( h )
{
log->Debug( PlugInMgrMsg, "Registering a factory for %s from %s",
it->c_str(), lib.c_str() );
pFactoryMap[*it] = h;
}
else
{
if( mapIt != pFactoryMap.end() )
{
log->Debug( PlugInMgrMsg, "Removing the factory for %s",
it->c_str() );
pFactoryMap.erase( mapIt );
}
}
}
return true;
}
//----------------------------------------------------------------------------
// Normalize a URL
//----------------------------------------------------------------------------
std::string PlugInManager::NormalizeURL( const std::string url )
{
URL urlObj = url;
if( !urlObj.IsValid() )
return "";
std::string protocol = urlObj.GetProtocol();
std::string hostname = urlObj.GetHostName();
if( hostname == "*" )
return protocol;
std::ostringstream o;
o << protocol << "://" << hostname << ":";
o << urlObj.GetPort();
return o.str();
}
};
XrdClConstants.hh
XrdClDefaultEnv.hh
XrdClEcHandler.hh
XrdClLog.hh
XrdVERSIONINFOREF
XrdVERSIONINFOREF(XrdCl)
XrdClPlugInManager.hh
XrdClURL.hh
XrdClUtils.hh
XrdSysPwd.hh
XrdCl::DefaultEnv::GetLog
static Log * GetLog()
Get default log.
Definition XrdClDefaultEnv.cc:493
XrdCl::DefaultEnv::GetEnv
static Env * GetEnv()
Get default client environment.
Definition XrdClDefaultEnv.cc:445
XrdCl::Env
Definition XrdClEnv.hh:38
XrdCl::Env::GetString
bool GetString(const std::string &key, std::string &value)
Definition XrdClEnv.cc:31
XrdCl::Log
Handle diagnostics.
Definition XrdClLog.hh:101
XrdCl::Log::Debug
void Debug(uint64_t topic, const char *format,...)
Print a debug message.
Definition XrdClLog.cc:282
XrdCl::PlugInFactory
Plugin factory.
Definition XrdClPlugInInterface.hh:549
XrdCl::PlugInManager::ProcessEnvironmentSettings
void ProcessEnvironmentSettings()
Definition XrdClPlugInManager.cc:186
XrdCl::PlugInManager::RegisterFactory
bool RegisterFactory(const std::string &url, PlugInFactory *factory)
Definition XrdClPlugInManager.cc:75
XrdCl::PlugInManager::PlugInManager
PlugInManager()
Constructor.
Definition XrdClPlugInManager.cc:51
XrdCl::PlugInManager::RegisterDefaultFactory
bool RegisterDefaultFactory(PlugInFactory *factory)
Register a plug-in factory applying to all URLs.
Definition XrdClPlugInManager.cc:119
XrdCl::PlugInManager::~PlugInManager
~PlugInManager()
Destructor.
Definition XrdClPlugInManager.cc:59
XrdCl::PlugInManager::GetFactory
PlugInFactory * GetFactory(const std::string url)
Definition XrdClPlugInManager.cc:145
XrdCl::URL
URL representation.
Definition XrdClURL.hh:31
XrdCl::URL::GetProtocol
const std::string & GetProtocol() const
Get the protocol.
Definition XrdClURL.hh:118
XrdCl::Utils::ProcessConfig
static Status ProcessConfig(std::map< std::string, std::string > &config, const std::string &file)
Process a config file and return key-value pairs.
Definition XrdClUtils.cc:534
XrdCl::Utils::splitString
static void splitString(Container &result, const std::string &input, const std::string &delimiter)
Split a string.
Definition XrdClUtils.hh:56
XrdCl::Utils::GetDirectoryEntries
static Status GetDirectoryEntries(std::vector< std::string > &entries, const std::string &path)
Get directory entries.
Definition XrdClUtils.cc:506
XrdOucPinLoader::Resolve
void * Resolve(const char *symbl, int mcnt=1)
Definition XrdOucPinLoader.cc:267
XrdOucPinLoader::Unload
void Unload(bool dodel=false)
Definition XrdOucPinLoader.cc:305
XrdSysMutexHelper
Definition XrdSysPthread.hh:263
XrdSysPwd
Definition XrdSysPwd.hh:37
XrdSysPwd::Get
struct passwd * Get(const char *Usr)
Definition XrdSysPwd.hh:42
XrdCl
Definition XrdClAction.hh:34
XrdCl::DefaultPlugIn
const char *const DefaultPlugIn
Definition XrdClConstants.hh:105
XrdCl::DefaultPlugInConfDir
const char *const DefaultPlugInConfDir
Definition XrdClConstants.hh:104
XrdCl::PlugInMgrMsg
const uint64_t PlugInMgrMsg
Definition XrdClConstants.hh:43
XrdGlobal::Log
XrdSysError Log
Definition XrdConfig.cc:113
XrdCl::Status
Procedure execution status.
Definition XrdClStatus.hh:115
XrdCl::Status::IsOK
bool IsOK() const
We're fine.
Definition XrdClStatus.hh:124
XrdCl::Status::ToString
std::string ToString() const
Create a string representation.
Definition XrdClStatus.cc:97