00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "CeylanPlugin.h"
00028
00029
00030 #include "CeylanFile.h"
00031 #include "CeylanDirectory.h"
00032 #include "CeylanOperators.h"
00033 #include "CeylanLogPlug.h"
00034
00035
00036
00037 #ifdef CEYLAN_USES_CONFIG_H
00038 #include "CeylanConfig.h"
00039 #endif // CEYLAN_USES_CONFIG_H
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 extern "C"
00054 {
00055
00056 #ifdef CEYLAN_USES_LTDL_H
00057 #include "ltdl.h"
00058 #endif // CEYLAN_USES_LTDL_H
00059
00060 #ifdef CEYLAN_USES_STRING_H
00061 #include <string.h>
00062 #endif // CEYLAN_USES_STRING_H
00063
00064 }
00065
00066
00067 #include <list>
00068 using std::list ;
00069
00070 using std::string ;
00071
00072 using namespace Ceylan ;
00073 using namespace Ceylan::Log ;
00074
00075
00076
00077 #ifdef CEYLAN_USES_LTDL_H
00078
00079
00080 struct Plugin::SystemSpecificPluginHandle
00081 {
00082 lt_dlhandle _handle ;
00083 } ;
00084
00085 #endif // CEYLAN_USES_PTHREAD_H
00086
00087
00088
00089
00090 PluginException::PluginException( const std::string & message ) :
00091 Ceylan::ModuleException( message )
00092 {
00093
00094 }
00095
00096
00097 PluginException::~PluginException() throw()
00098 {
00099
00100 }
00101
00102
00103
00104
00105 Ceylan::System::FileLocator Plugin::PluginLocator ;
00106
00107 const std::string Plugin::SymbolMarker= CEYLAN_SYMBOL_MARKER ;
00108
00109 Ceylan::Uint16 Plugin::PluginSystemInitialized = 0 ;
00110
00111
00112
00113 Plugin::Plugin( const string & filename, bool autoPrefix ) :
00114 Module(),
00115 _pluginHandle( 0 ),
00116 _filename( filename ),
00117 _autoPrefix( autoPrefix )
00118 {
00119
00120
00121 #if CEYLAN_USES_PLUGINS
00122
00123 _pluginHandle = new SystemSpecificPluginHandle ;
00124 _pluginHandle->_handle = 0 ;
00125
00126
00127 if ( PluginSystemInitialized == 0 )
00128 {
00129
00130
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147 if ( ::lt_dlinit() != 0 )
00148 throw PluginException( "Plugin constructor: initialization of "
00149 " ltdl failed: " + string( ::lt_dlerror() ) ) ;
00150
00151
00152 const list<string> & paths = PluginLocator.getPaths() ;
00153
00154 for ( list<string>::const_iterator it = paths.begin() ;
00155 it != paths.end(); it++ )
00156 {
00157 if ( ::lt_dladdsearchdir( (*it).c_str() ) != 0 )
00158 throw PluginException( "Plugin constructor: "
00159 "error while specifying plugin search directory '"
00160 + (*it) + "': " + string( ::lt_dlerror() ) ) ;
00161
00162 }
00163
00164 }
00165
00166
00167 PluginSystemInitialized++ ;
00168
00169
00170
00171
00172
00173
00174
00175
00176 _pluginHandle->_handle =::lt_dlopenext( filename.c_str() ) ;
00177
00178 if ( _pluginHandle->_handle == 0 )
00179 throw PluginException( "Plugin constructor: "
00180 "error while loading library '" + filename + "': "
00181 + string( ::lt_dlerror() ) + "." ) ;
00182
00183 retrieveMetadata() ;
00184
00185 #else // CEYLAN_USES_PLUGINS
00186
00187 throw PluginException( "Plugin constructor: "
00188 "plugin feature not available" ) ;
00189
00190 #endif // CEYLAN_USES_PLUGINS
00191
00192 }
00193
00194
00195
00196 Plugin::~Plugin() throw()
00197 {
00198
00199
00200 #if CEYLAN_USES_PLUGINS
00201
00202
00203 close() ;
00204
00205 PluginSystemInitialized-- ;
00206
00207 if ( PluginSystemInitialized == 0 )
00208 {
00209
00210 if ( ::lt_dlexit() != 0 )
00211 LogPlug::error( "Plugin destructor: lt_dlexit failed: "
00212 + string( ::lt_dlerror() ) ) ;
00213
00214 }
00215
00216 #endif // CEYLAN_USES_PLUGINS
00217
00218
00219 }
00220
00221
00222
00223 string Plugin::getEmbeddedName()
00224 {
00225
00226 #if CEYLAN_USES_PLUGINS
00227
00228
00229 if ( _pluginHandle->_handle != 0 )
00230 {
00231
00232 const lt_dlinfo * info =::lt_dlgetinfo( _pluginHandle->_handle ) ;
00233
00234 if ( info == 0 )
00235 throw PluginException( "Plugin::getEmbeddedName failed: "
00236 + string( ::lt_dlerror() ) ) ;
00237
00238 return info->name ;
00239
00240 }
00241 else
00242 {
00243 throw ModuleException( "Plugin::getEmbeddedName failed: "
00244 "no handle available." ) ;
00245 }
00246
00247
00248 #else // CEYLAN_USES_PLUGINS
00249
00250 throw PluginException( "Plugin::getEmbeddedName: "
00251 "plugin feature not available" ) ;
00252
00253 #endif // CEYLAN_USES_PLUGINS
00254
00255 }
00256
00257
00258
00259 string Plugin::getFilename() const
00260 {
00261
00262 #if CEYLAN_USES_PLUGINS
00263
00264 if ( _pluginHandle->_handle != 0 )
00265 {
00266
00267 const lt_dlinfo * info =::lt_dlgetinfo( _pluginHandle->_handle ) ;
00268
00269 if ( info == 0 )
00270 throw PluginException( "Plugin::getFilename failed: "
00271 + string( ::lt_dlerror() ) ) ;
00272
00273 return info->filename ;
00274
00275 }
00276 else
00277 throw ModuleException( "Plugin::getFilename failed: "
00278 "no handle available." ) ;
00279
00280 #else // CEYLAN_USES_PLUGINS
00281
00282 throw PluginException( "Plugin::getFilename: "
00283 "plugin feature not available" ) ;
00284
00285 #endif // CEYLAN_USES_PLUGINS
00286
00287 }
00288
00289
00290
00291 Plugin::ReferenceCount Plugin::getReferenceCount() const
00292 {
00293
00294 #if CEYLAN_USES_PLUGINS
00295
00296 if ( _pluginHandle->_handle != 0 )
00297 {
00298
00299 const lt_dlinfo * info =::lt_dlgetinfo( _pluginHandle->_handle ) ;
00300
00301 if ( info == 0 )
00302 throw PluginException( "Plugin::getReferenceCount failed: "
00303 + string( ::lt_dlerror() ) ) ;
00304
00305 return info->ref_count ;
00306
00307 }
00308 else
00309 throw ModuleException( "Plugin::getReferenceCount failed: "
00310 "no handle available." ) ;
00311
00312 #else // CEYLAN_USES_PLUGINS
00313
00314 throw PluginException( "Plugin::getReferenceCount: "
00315 "plugin feature not available" ) ;
00316
00317 #endif // CEYLAN_USES_PLUGINS
00318
00319 }
00320
00321
00322
00323 bool Plugin::isOpen() const
00324 {
00325
00326 #if CEYLAN_USES_PLUGINS
00327
00328 return ( ( _pluginHandle != 0 ) && ( _pluginHandle->_handle != 0 ) ) ;
00329
00330 #else // CEYLAN_USES_PLUGINS
00331
00332 return false ;
00333
00334 #endif // CEYLAN_USES_PLUGINS
00335
00336 }
00337
00338
00339
00340 void * Plugin::getDataSymbol( const string & dataName ) const
00341 {
00342
00343 #if CEYLAN_USES_PLUGINS
00344
00345 if ( ! isOpen() )
00346 throw PluginException( "Plugin::getDataSymbol: "
00347 "loading symbol '" + dataName
00348 + "' requested whereas plugin not opened." ) ;
00349
00350
00351
00352 lt_ptr f =::lt_dlsym( _pluginHandle->_handle, dataName.c_str() ) ;
00353
00354 if ( f == 0 )
00355 throw PluginException( "Plugin::getDataSymbol: "
00356 "symbol '" + dataName + "' not found in '"
00357 + _filename + "'." ) ;
00358
00359 return f ;
00360
00361
00362 #else // CEYLAN_USES_PLUGINS
00363
00364 throw PluginException( "Plugin::getDataSymbol: "
00365 "plugin feature not available" ) ;
00366
00367 #endif // CEYLAN_USES_PLUGINS
00368
00369 }
00370
00371
00372
00373 Plugin::BasicFunctionPointer Plugin::getFunctionSymbol(
00374 const string & functionName ) const
00375 {
00376
00377 #if CEYLAN_USES_PLUGINS
00378
00379 if ( ! isOpen() )
00380 throw PluginException( "Plugin::getFunctionSymbol: "
00381 "loading symbol '" + functionName
00382 + "' requested whereas plugin not opened." ) ;
00383
00384
00385
00386 lt_ptr f =::lt_dlsym( _pluginHandle->_handle, functionName.c_str() ) ;
00387
00388 if ( f == 0 )
00389 throw PluginException( "Plugin::getFunctionSymbol: "
00390 "symbol '" + functionName + "' not found in '"
00391 + _filename + "'." ) ;
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401 BasicFunctionPointer returned ;
00402
00403
00404 if ( sizeof(BasicFunctionPointer) != sizeof(lt_ptr) )
00405 throw PluginException( "Plugin::getFunctionSymbol: "
00406 "unable to convert from pointer to function (size is "
00407 + Ceylan::toString( sizeof(BasicFunctionPointer) )
00408 + ") to pointer to object lt_ptr (size is "
00409 + Ceylan::toString( sizeof(lt_ptr) ) + "." ) ;
00410
00411 ::memcpy( &returned, &f, sizeof(BasicFunctionPointer) ) ;
00412
00413 return returned ;
00414
00415
00416 #else // CEYLAN_USES_PLUGINS
00417
00418 throw PluginException( "Plugin::getFunctionSymbol: "
00419 "plugin feature not available" ) ;
00420
00421 #endif // CEYLAN_USES_PLUGINS
00422
00423 }
00424
00425
00426
00427 void Plugin::close()
00428 {
00429
00430 #if CEYLAN_USES_PLUGINS
00431
00432 if ( _pluginHandle !=0 )
00433 {
00434 if ( _pluginHandle->_handle != 0 )
00435 {
00436 if ( ::lt_dlclose( _pluginHandle->_handle ) == 0 )
00437 {
00438 _pluginHandle->_handle = 0 ;
00439 }
00440 else
00441 {
00442 throw PluginException( "Plugin::close: "
00443 + string( ::lt_dlerror() ) ) ;
00444 }
00445 }
00446 delete _pluginHandle ;
00447 _pluginHandle = 0 ;
00448
00449 }
00450
00451 #else // CEYLAN_USES_PLUGINS
00452
00453 throw PluginException( "Plugin::close: "
00454 "plugin feature not available" ) ;
00455
00456 #endif // CEYLAN_USES_PLUGINS
00457
00458 }
00459
00460
00461
00462 void Plugin::makeResident()
00463 {
00464
00465 #if CEYLAN_USES_PLUGINS
00466
00467 if ( ::lt_dlmakeresident(_pluginHandle->_handle ) == -1 )
00468 throw PluginException( "Plugin::makeResident failed: "
00469 + string( ::lt_dlerror() ) ) ;
00470
00471 #else // CEYLAN_USES_PLUGINS
00472
00473 throw PluginException( "Plugin::makeResident: "
00474 "plugin feature not available" ) ;
00475
00476 #endif // CEYLAN_USES_PLUGINS
00477
00478 }
00479
00480
00481
00482 bool Plugin::isResident() const
00483 {
00484
00485 #if CEYLAN_USES_PLUGINS
00486
00487 int res =::lt_dlisresident(_pluginHandle->_handle ) ;
00488
00489 if ( res == -1 )
00490 throw PluginException( "Plugin::isResident failed: "
00491 + string( ::lt_dlerror() ) ) ;
00492
00493 return ( res == 1 ) ;
00494
00495 #else // CEYLAN_USES_PLUGINS
00496
00497 throw PluginException( "Plugin::isResident: "
00498 "plugin feature not available" ) ;
00499
00500 #endif // CEYLAN_USES_PLUGINS
00501
00502 }
00503
00504
00505
00506 const string Plugin::toString( VerbosityLevels level ) const
00507 {
00508
00509 string res ;
00510
00511 res = "Plugin named '" + getName() + "', corresponding to the library '"
00512 + getFilename() + "' (user specified: '" + _filename + "'), which " ;
00513
00514 if ( isOpen() )
00515 res += "has been already opened" ;
00516 else
00517 res += "has not been opened yet" ;
00518
00519
00520 if ( level == low )
00521 return res ;
00522
00523 res += ". " ;
00524
00525
00526 if ( _autoPrefix )
00527 res += "The plugin loader expects symbols to be prefixed "
00528 "according to module conventions" ;
00529 else
00530 res += "The plugin loader does not expect prefixed symbols" ;
00531
00532 if ( level == medium )
00533 return res ;
00534
00535 return res + ". " + Module::toString( level ) ;
00536
00537 }
00538
00539
00540
00541 void Plugin::retrieveMetadata()
00542 {
00543
00544 setName( getEmbeddedName() ) ;
00545
00546 setDescription( * static_cast<const std::string *>(
00547 getDataSymbol( "Description" ) ) ) ;
00548
00549 setHomePage( * static_cast<const std::string *>(
00550 getDataSymbol( "Url" ) ) ) ;
00551
00552 setAuthor( * static_cast<const std::string *>(
00553 getDataSymbol( "Author" ) ) ) ;
00554
00555 setAuthorMail( * static_cast<const std::string *>(
00556 getDataSymbol( "AuthorMail" ) ) ) ;
00557
00558 try
00559 {
00560
00561 Version versionFromPlugin( * static_cast<const std::string *>(
00562 getDataSymbol( "Version" ) ) ) ;
00563
00564 setVersion( versionFromPlugin ) ;
00565
00566 }
00567 catch( const Ceylan::VersionException & e )
00568 {
00569 throw PluginException( "Plugin::retrieveMetadata: "
00570 "getting version failed: " + e.toString() ) ;
00571 }
00572
00573 setLicence( * static_cast<const std::string *>(
00574 getDataSymbol( "Licence" ) ) ) ;
00575
00576 }
00577