XRootD
Loading...
Searching...
No Matches
XrdClPlugInManager.cc
Go to the documentation of this file.
1//------------------------------------------------------------------------------
2// Copyright (c) 2014 by European Organization for Nuclear Research (CERN)
3// Author: Lukasz Janyst <ljanyst@cern.ch>
4//------------------------------------------------------------------------------
5// This file is part of the XRootD software suite.
6//
7// XRootD is free software: you can redistribute it and/or modify
8// it under the terms of the GNU Lesser General Public License as published by
9// the Free Software Foundation, either version 3 of the License, or
10// (at your option) any later version.
11//
12// XRootD is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU Lesser General Public License
18// along with XRootD. If not, see <http://www.gnu.org/licenses/>.
19//
20// In applying this licence, CERN does not waive the privileges and immunities
21// granted to it by virtue of its status as an Intergovernmental Organization
22// or submit itself to any jurisdiction.
23//------------------------------------------------------------------------------
24
27#include "XrdCl/XrdClLog.hh"
29#include "XrdCl/XrdClUtils.hh"
30#include "XrdCl/XrdClURL.hh"
31#include "XrdSys/XrdSysPwd.hh"
32#include "XrdVersion.hh"
33
34#ifdef WITH_XRDEC
36#endif
37
38#include <unistd.h>
39#include <sys/types.h>
40#include <vector>
41#include <string>
42#include <algorithm>
43
45
46namespace XrdCl
47{
48 //----------------------------------------------------------------------------
49 // Constructor
50 //----------------------------------------------------------------------------
52 pDefaultFactory(0)
53 {
54 }
55
56 //----------------------------------------------------------------------------
57 // Destructor
58 //----------------------------------------------------------------------------
60 {
61 std::map<std::string, FactoryHelper*>::iterator it;
62 for( it = pFactoryMap.begin(); it != pFactoryMap.end(); ++it )
63 {
64 it->second->counter--;
65 if( it->second->counter == 0 )
66 delete it->second;
67 }
68
69 delete pDefaultFactory;
70 }
71
72 //----------------------------------------------------------------------------
73 // Register a plug-in favtory for the given url
74 //----------------------------------------------------------------------------
75 bool PlugInManager::RegisterFactory( const std::string &url,
76 PlugInFactory *factory )
77 {
78 Log *log = DefaultEnv::GetLog();
79 XrdSysMutexHelper scopedLock( pMutex );
80
81 std::string normUrl = NormalizeURL( url );
82 if( normUrl == "" )
83 return false;
84
85 std::map<std::string, FactoryHelper*>::iterator it;
86 it = pFactoryMap.find( normUrl );
87 if( it != pFactoryMap.end() )
88 {
89 if( it->second->isEnv )
90 return false;
91
92 // we don't need to check the counter because it's valid only
93 // for environment plugins which cannot be replaced via
94 // this method
95 delete it->second;
96 }
97
98 if( !factory )
99 {
100 log->Debug( PlugInMgrMsg, "Removing the factory for %s",
101 normUrl.c_str() );
102 pFactoryMap.erase( it );
103 return true;
104 }
105
106 log->Debug( PlugInMgrMsg, "Registering a factory for %s",
107 normUrl.c_str() );
108
109 FactoryHelper *h = new FactoryHelper();
110 h->factory = factory;
111 h->counter = 1;
112 pFactoryMap[normUrl] = h;
113 return true;
114 }
115
116 //------------------------------------------------------------------------
118 //------------------------------------------------------------------------
120 {
121 Log *log = DefaultEnv::GetLog();
122 XrdSysMutexHelper scopedLock( pMutex );
123
124 if( pDefaultFactory && pDefaultFactory->isEnv )
125 return false;
126
127 delete pDefaultFactory;
128 pDefaultFactory = 0;
129
130 if( factory )
131 {
132 log->Debug( PlugInMgrMsg, "Registering a default factory" );
133 pDefaultFactory = new FactoryHelper;
134 pDefaultFactory->factory = factory;
135 }
136 else
137 log->Debug( PlugInMgrMsg, "Removing the default factory" );
138
139 return true;
140 }
141
142 //----------------------------------------------------------------------------
143 // Retrieve the plug-in factory for the given URL
144 //----------------------------------------------------------------------------
145 PlugInFactory *PlugInManager::GetFactory( const std::string url )
146 {
147 XrdSysMutexHelper scopedLock( pMutex );
148
149 if( pDefaultFactory && pDefaultFactory->isEnv )
150 return pDefaultFactory->factory;
151
152 std::string normUrl = NormalizeURL( url );
153 if( normUrl.empty() )
154 {
155 if( pDefaultFactory )
156 return pDefaultFactory->factory;
157 return 0;
158 }
159
160 std::map<std::string, FactoryHelper*>::iterator it;
161 it = pFactoryMap.find( normUrl );
162 if( it != pFactoryMap.end() && it->second->isEnv )
163 return it->second->factory;
164
165 std::string protocol = URL( url ).GetProtocol();
166 std::map<std::string, FactoryHelper*>::iterator itProt;
167 itProt = pFactoryMap.find( protocol );
168 if( itProt != pFactoryMap.end() && itProt->second->isEnv )
169 return itProt->second->factory;
170
171 if( pDefaultFactory )
172 return pDefaultFactory->factory;
173
174 if( it != pFactoryMap.end() )
175 return it->second->factory;
176
177 if( itProt != pFactoryMap.end() )
178 return itProt->second->factory;
179
180 return 0;
181 }
182
183 //----------------------------------------------------------------------------
184 // Process user environment to load plug-in settings.
185 //----------------------------------------------------------------------------
187 {
188 XrdSysMutexHelper scopedLock( pMutex );
189 Log *log = DefaultEnv::GetLog();
190 Env *env = DefaultEnv::GetEnv();
191
192 log->Debug( PlugInMgrMsg, "Initializing plug-in manager..." );
193
194 //--------------------------------------------------------------------------
195 // Check if a default plug-in has been specified in the environment
196 //--------------------------------------------------------------------------
197 bool loadConfigs = true;
198 std::string defaultPlugIn = DefaultPlugIn;
199 env->GetString( "PlugIn", defaultPlugIn );
200 if( !defaultPlugIn.empty() )
201 {
202 loadConfigs = false;
203 log->Debug( PlugInMgrMsg, "Loading default plug-in from %s...",
204 defaultPlugIn.c_str());
205
206 std::pair<XrdOucPinLoader*, PlugInFactory *> pg = LoadFactory(
207 defaultPlugIn, std::map<std::string, std::string>() );
208
209 if( !pg.first )
210 {
211 log->Debug( PlugInMgrMsg, "Failed to load default plug-in from %s",
212 defaultPlugIn.c_str());
213 loadConfigs = false;
214 }
215
216 pDefaultFactory = new FactoryHelper();
217 pDefaultFactory->factory = pg.second;
218 pDefaultFactory->plugin = pg.first;
219 pDefaultFactory->isEnv = true;
220 }
221
222 //--------------------------------------------------------------------------
223 // If there is no default plug-in or it is invalid then load plug-in config
224 // files
225 //--------------------------------------------------------------------------
226 if( loadConfigs )
227 {
228 log->Debug( PlugInMgrMsg,
229 "No default plug-in, loading plug-in configs..." );
230
231 ProcessConfigDir( "/etc/xrootd/client.plugins.d" );
232
233 XrdSysPwd pwdHandler;
234 passwd *pwd = pwdHandler.Get( getuid() );
235 if( pwd )
236 {
237 std::string userPlugIns = pwd->pw_dir;
238 userPlugIns += "/.xrootd/client.plugins.d";
239 ProcessConfigDir( userPlugIns );
240 }
241 std::string customPlugIns = DefaultPlugInConfDir;
242 env->GetString( "PlugInConfDir", customPlugIns );
243 if( !customPlugIns.empty() )
244 ProcessConfigDir( customPlugIns );
245 }
246 }
247
248 //----------------------------------------------------------------------------
249 // Process the configuration directory and load plug in definitions
250 //----------------------------------------------------------------------------
251 void PlugInManager::ProcessConfigDir( const std::string &dir )
252 {
253 Log *log = DefaultEnv::GetLog();
254 log->Debug( PlugInMgrMsg, "Processing plug-in definitions in %s...",
255 dir.c_str());
256
257 std::vector<std::string> entries;
258 std::vector<std::string>::iterator it;
259 Status st = Utils::GetDirectoryEntries( entries, dir );
260 if( !st.IsOK() )
261 {
262 log->Debug( PlugInMgrMsg, "Unable to process directory %s: %s",
263 dir.c_str(), st.ToString().c_str() );
264 return;
265 }
266 std::sort( entries.begin(), entries.end() );
267
268 for( it = entries.begin(); it != entries.end(); ++it )
269 {
270 std::string confFile = dir + "/" + *it;
271 std::string suffix = ".conf";
272 if( confFile.length() <= suffix.length() )
273 continue;
274 if( !std::equal( suffix.rbegin(), suffix.rend(), confFile.rbegin() ) )
275 continue;
276
277 ProcessPlugInConfig( confFile );
278 }
279 }
280
281 //----------------------------------------------------------------------------
282 // Process a plug-in config file and load the plug-in if possible
283 //----------------------------------------------------------------------------
284 void PlugInManager::ProcessPlugInConfig( const std::string &confFile )
285 {
286 Log *log = DefaultEnv::GetLog();
287 log->Dump( PlugInMgrMsg, "Processing: %s", confFile.c_str() );
288
289 //--------------------------------------------------------------------------
290 // Read the config
291 //--------------------------------------------------------------------------
292 std::map<std::string, std::string> config;
293 Status st = Utils::ProcessConfig( config, confFile );
294 if( !st.IsOK() )
295 {
296 log->Debug( PlugInMgrMsg, "Unable process config %s: %s",
297 confFile.c_str(), st.ToString().c_str() );
298 return;
299 }
300
301 const char *keys[] = { "url", "lib", "enable", 0 };
302 for( int i = 0; keys[i]; ++i )
303 {
304 if( config.find( keys[i] ) == config.end() )
305 {
306 log->Debug( PlugInMgrMsg, "Unable to find '%s' key in the config file "
307 "%s, ignoring this config", keys[i], confFile.c_str() );
308 return;
309 }
310 }
311
312 //--------------------------------------------------------------------------
313 // Attempt to load the plug in and place it in the map
314 //--------------------------------------------------------------------------
315 std::string url = config["url"];
316 std::string lib = config["lib"];
317 std::string enable = config["enable"];
318
319 log->Dump( PlugInMgrMsg, "Settings from '%s': url='%s', lib='%s', "
320 "enable='%s'", confFile.c_str(), url.c_str(), lib.c_str(),
321 enable.c_str() );
322
323 std::pair<XrdOucPinLoader*, PlugInFactory *> pg;
324 pg.first = 0; pg.second = 0;
325 if( enable == "true" )
326 {
327 log->Debug( PlugInMgrMsg, "Trying to load a plug-in for '%s' from '%s'",
328 url.c_str(), lib.c_str() );
329
330 pg = LoadFactory( lib, config );
331
332 if( !pg.second )
333 return;
334 }
335 else
336 log->Debug( PlugInMgrMsg, "Trying to disable plug-in for '%s'",
337 url.c_str() );
338
339 if( !RegisterFactory( url, lib, pg.second, pg.first ) )
340 {
341 delete pg.first;
342 delete pg.second;
343 }
344 }
345
346 //----------------------------------------------------------------------------
347 // Load the plug-in and create the factory
348 //----------------------------------------------------------------------------
349 std::pair<XrdOucPinLoader*,PlugInFactory*> PlugInManager::LoadFactory(
350 const std::string &lib, const std::map<std::string, std::string> &config )
351 {
352 Log *log = DefaultEnv::GetLog();
353
354#ifdef WITH_XRDEC
355 if( lib == "XrdEcDefault" )
356 {
357 auto itr = config.find( "nbdta" );
358 if( itr == config.end() )
359 return std::make_pair<XrdOucPinLoader*, PlugInFactory*>( nullptr, nullptr );
360 uint8_t nbdta = std::stoul( itr->second );
361 itr = config.find( "nbprt" );
362 if( itr == config.end() )
363 return std::make_pair<XrdOucPinLoader*, PlugInFactory*>( nullptr, nullptr );
364 uint8_t nbprt = std::stoul( itr->second );
365 itr = config.find( "chsz" );
366 if( itr == config.end() )
367 return std::make_pair<XrdOucPinLoader*, PlugInFactory*>( nullptr, nullptr );
368 uint64_t chsz = std::stoul( itr->second );
369 std::vector<std::string> plgr;
370 itr = config.find( "plgr" );
371 if( itr != config.end() )
372 Utils::splitString( plgr, itr->second, "," );
373
374 std::string xrdclECenv = std::to_string(nbdta) + "," +
375 std::to_string(nbprt) + "," +
376 std::to_string(chsz);
377 setenv("XRDCL_EC", xrdclECenv.c_str(), 1);
378
379 EcPlugInFactory *ecHandler = new EcPlugInFactory( nbdta, nbprt, chsz, std::move( plgr ) );
380 return std::make_pair<XrdOucPinLoader*, PlugInFactory*>( nullptr, ecHandler );
381 }
382#endif
383
384 char errorBuff[1024];
385 XrdOucPinLoader *pgHandler = new XrdOucPinLoader( errorBuff, 1024,
386 &XrdVERSIONINFOVAR( XrdCl ),
387 "client", lib.c_str() );
388
389 PlugInFunc_t pgFunc = (PlugInFunc_t)pgHandler->Resolve("XrdClGetPlugIn", -1);
390
391 if( !pgFunc )
392 {
393 log->Debug( PlugInMgrMsg, "Error while loading %s: %s", lib.c_str(),
394 errorBuff );
395 pgHandler->Unload();
396 delete pgHandler;
397 return std::make_pair<XrdOucPinLoader*, PlugInFactory*>( 0, 0 );
398 }
399
400 PlugInFactory *f = (PlugInFactory*)pgFunc( &config );
401
402 if( !f )
403 {
404 delete pgHandler;
405 return std::make_pair<XrdOucPinLoader*, PlugInFactory*>( 0, 0 );
406 }
407
408 return std::make_pair( pgHandler, f );
409 }
410
411 //----------------------------------------------------------------------------
412 // Handle factory - register it or free all the memory
413 //----------------------------------------------------------------------------
414 bool PlugInManager::RegisterFactory( const std::string &urlString,
415 const std::string &lib,
416 PlugInFactory *factory,
417 XrdOucPinLoader *plugin )
418 {
419 //--------------------------------------------------------------------------
420 // Process and normalize the URLs
421 //--------------------------------------------------------------------------
422 Log *log = DefaultEnv::GetLog();
423 std::vector<std::string> urls;
424 std::vector<std::string> normalizedURLs;
425 std::vector<std::string>::iterator it;
426
427 if (urlString == "*") {
428 if (pDefaultFactory) {
429 if (pDefaultFactory->isEnv) {
430 log->Debug(PlugInMgrMsg, "There is already an env default plugin "
431 "loaded, skipping %s", lib.c_str());
432 return false;
433 } else {
434 log->Debug(PlugInMgrMsg, "There can be only one default plugin "
435 "loaded, skipping %s", lib.c_str());
436 return false;
437 }
438 } else {
439 pDefaultFactory = new FactoryHelper();
440 pDefaultFactory->factory = factory;
441 pDefaultFactory->plugin = plugin;
442 pDefaultFactory->isEnv = false;
443 return true;
444 }
445 }
446
447 Utils::splitString( urls, urlString, ";" );
448
449 for( it = urls.begin(); it != urls.end(); ++it )
450 {
451 std::string normURL = NormalizeURL( *it );
452 if( normURL == "" )
453 {
454 log->Debug( PlugInMgrMsg, "Url cannot be normalized: '%s', ignoring",
455 it->c_str() );
456 continue;
457 }
458 normalizedURLs.push_back( normURL );
459 }
460
461 std::sort( normalizedURLs.begin(), normalizedURLs.end() );
462
463 auto last = std::unique( normalizedURLs.begin(), normalizedURLs.end() );
464 normalizedURLs.erase( last, normalizedURLs.end() );
465
466 if( normalizedURLs.empty() )
467 return false;
468
469 //--------------------------------------------------------------------------
470 // Insert or remove from the map
471 //--------------------------------------------------------------------------
472 FactoryHelper *h = 0;
473
474 if( factory )
475 {
476 h = new FactoryHelper();
477 h->isEnv = true;
478 h->counter = normalizedURLs.size();
479 h->plugin = plugin;
480 h->factory = factory;
481 }
482
483 std::map<std::string, FactoryHelper*>::iterator mapIt;
484 for( it = normalizedURLs.begin(); it != normalizedURLs.end(); ++it )
485 {
486 mapIt = pFactoryMap.find( *it );
487 if( mapIt != pFactoryMap.end() )
488 {
489 mapIt->second->counter--;
490 if( mapIt->second->counter == 0 )
491 delete mapIt->second;
492 }
493
494 if( h )
495 {
496 log->Debug( PlugInMgrMsg, "Registering a factory for %s from %s",
497 it->c_str(), lib.c_str() );
498 pFactoryMap[*it] = h;
499 }
500 else
501 {
502 if( mapIt != pFactoryMap.end() )
503 {
504 log->Debug( PlugInMgrMsg, "Removing the factory for %s",
505 it->c_str() );
506 pFactoryMap.erase( mapIt );
507 }
508 }
509 }
510
511 return true;
512 }
513
514 //----------------------------------------------------------------------------
515 // Normalize a URL
516 //----------------------------------------------------------------------------
517 std::string PlugInManager::NormalizeURL( const std::string url )
518 {
519 URL urlObj = url;
520 if( !urlObj.IsValid() )
521 return "";
522
523 std::string protocol = urlObj.GetProtocol();
524 std::string hostname = urlObj.GetHostName();
525
526 if( hostname == "*" )
527 return protocol;
528
529 std::ostringstream o;
530 o << protocol << "://" << hostname << ":";
531 o << urlObj.GetPort();
532 return o.str();
533 }
534};
XrdVERSIONINFOREF(XrdCl)
static Log * GetLog()
Get default log.
static Env * GetEnv()
Get default client environment.
bool GetString(const std::string &key, std::string &value)
Definition XrdClEnv.cc:31
Handle diagnostics.
Definition XrdClLog.hh:101
void Debug(uint64_t topic, const char *format,...)
Print a debug message.
Definition XrdClLog.cc:282
bool RegisterFactory(const std::string &url, PlugInFactory *factory)
bool RegisterDefaultFactory(PlugInFactory *factory)
Register a plug-in factory applying to all URLs.
PlugInFactory * GetFactory(const std::string url)
URL representation.
Definition XrdClURL.hh:31
const std::string & GetProtocol() const
Get the protocol.
Definition XrdClURL.hh:118
static Status ProcessConfig(std::map< std::string, std::string > &config, const std::string &file)
Process a config file and return key-value pairs.
static void splitString(Container &result, const std::string &input, const std::string &delimiter)
Split a string.
Definition XrdClUtils.hh:56
static Status GetDirectoryEntries(std::vector< std::string > &entries, const std::string &path)
Get directory entries.
void * Resolve(const char *symbl, int mcnt=1)
void Unload(bool dodel=false)
struct passwd * Get(const char *Usr)
Definition XrdSysPwd.hh:42
const char *const DefaultPlugIn
const char *const DefaultPlugInConfDir
const uint64_t PlugInMgrMsg
XrdSysError Log
Definition XrdConfig.cc:112
Procedure execution status.
bool IsOK() const
We're fine.
std::string ToString() const
Create a string representation.