module_dl.cpp

00001 
00002 /***************************************************************************
00003  *  module-dl.cpp - representation of a module (i.e. shared object)
00004  *                  This code is based on gmodule from glib
00005  *
00006  *  Generated: Wed Aug 23 15:58:27 2006
00007  *  Copyright  2006  Tim Niemueller [www.niemueller.de]
00008  *
00009  ****************************************************************************/
00010 
00011 /*  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version. A runtime exception applies to
00015  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00016  *
00017  *  This program is distributed in the hope that it will be useful,
00018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  *  GNU Library General Public License for more details.
00021  *
00022  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00023  */
00024 
00025 /*
00026  * For nice reading and hints about using dynamic module loading with C++ you
00027  * should have a look at
00028  * http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/C++-dlopen-mini-HOWTO.html
00029  */
00030 
00031 #include <utils/system/dynamic_module/module_dl.h>
00032 #include <utils/system/file.h>
00033 
00034 #include <cstring>
00035 #include <dlfcn.h>
00036 
00037 
00038 namespace fawkes {
00039 
00040 /** @class ModuleDL utils/system/dynamic_module/module_dl.h
00041  * A Module implementation for the dl dynamic loader library that comes
00042  * with glibc, applicable for Linux Systems
00043  */
00044 
00045 const char * ModuleDL::FILE_EXTENSION = "so";
00046 
00047 
00048 /** Constructor for ModuleDL
00049  * @param filename Full filename of the module
00050  * @param flags Module flags, @see Module
00051  */
00052 ModuleDL::ModuleDL(std::string filename, Module::ModuleFlags flags)
00053 {
00054   this->filename = filename;
00055   this->flags    = flags;
00056 
00057   handle         = NULL;
00058 
00059   file_found     = false;
00060   is_resident    = false;
00061   ref_count      = 0;
00062 }
00063 
00064 
00065 /** Destructor of ModuleDL */
00066 ModuleDL::~ModuleDL()
00067 {
00068   close();
00069 }
00070 
00071 
00072 /** Open the module
00073  * @return Returns true if the module could be opened, false otherwise
00074  * @exception ModuleOpenException Thrown if there was any problem while loading the
00075  * module
00076  */
00077 void
00078 ModuleDL::open()
00079 {
00080   if ( handle != NULL )  return;
00081 
00082   // Note: We assume Linux-style shared objects
00083   std::string full_filename = "";
00084   full_filename = filename;
00085   if ( full_filename.find(".so", 0) != (full_filename.length() - 3)) {
00086     // filename has no proper ending
00087     full_filename += ".so";
00088   }
00089 
00090   int tflags = 0;
00091   tflags |= ((flags & MODULE_BIND_LAZY)   != 0) ? RTLD_LAZY : RTLD_NOW;
00092   tflags |= ((flags & MODULE_BIND_NOW)    != 0) ? RTLD_NOW : 0;
00093   tflags |= ((flags & MODULE_BIND_LOCAL)  != 0) ? RTLD_LOCAL : 0;
00094   tflags |= ((flags & MODULE_BIND_GLOBAL) != 0) ? RTLD_GLOBAL : 0;
00095 #ifdef linux
00096   tflags |= ((flags & MODULE_BIND_DEEP)   != 0) ? RTLD_DEEPBIND : 0;
00097 #endif
00098 
00099   if ( full_filename == "") {
00100     handle = dlopen (NULL, tflags);
00101 
00102     filename    = "main";
00103     is_resident = true;
00104     ref_count   = 1;
00105   } else {
00106 
00107     // check whether we have a readable file right away
00108     if (File::is_regular(full_filename.c_str())) {
00109       // ok, try loading the module
00110       handle = dlopen(full_filename.c_str(), tflags);
00111 
00112       if ( NULL == handle) {
00113         const char *err = dlerror();
00114         if ( NULL == err ) {
00115           throw ModuleOpenException("dlopen failed with an unknown error");
00116         } else {
00117           ModuleOpenException e("dlopen failed");
00118           e.append("dlerror: %s", err);
00119           throw e;
00120         }
00121       } else {
00122         is_resident = false;
00123         ref_count   = 1;
00124       }
00125     } else {
00126       ModuleOpenException e("Cannot open module");
00127       e.append("File '%s' does not exist", full_filename.c_str());
00128       throw e;
00129     }
00130   }
00131 }
00132 
00133 
00134 /** Close the module
00135  * @return Returns true if the module could be closed, false otherwise
00136  */
00137 bool
00138 ModuleDL::close()
00139 {
00140   if ( handle == NULL )  return true;
00141 
00142   if ( ref_count > 0 )  --ref_count;
00143 
00144   if ( (ref_count == 0) && ! is_resident ) {
00145     if ( dlclose(handle) != 0 ) {
00146       handle = NULL;
00147       return false;
00148     }
00149     handle = NULL;
00150   }
00151 
00152   return true;
00153 }
00154 
00155 
00156 /** Increment the reference count of this module */
00157 void
00158 ModuleDL::ref()
00159 {
00160   ++ref_count;
00161 }
00162 
00163 
00164 /** Decrease the reference count of this module */
00165 void
00166 ModuleDL::unref()
00167 {
00168   if ( ref_count > 0 ) {
00169     --ref_count;
00170   }
00171 }
00172 
00173 
00174 /** Check if there are no reference to this module
00175  * @return Returns true if there are no references to this module,
00176  * false if there is at least one reference
00177  */
00178 bool
00179 ModuleDL::notref()
00180 {
00181   return (ref_count == 0);
00182 }
00183 
00184 
00185 /** Get the reference count of this module
00186  * @return Returns the number of references to this module
00187  */
00188 unsigned int
00189 ModuleDL::get_ref_count()
00190 {
00191   return ref_count;
00192 }
00193 
00194 
00195 /** Compare to another ModuleDL instance
00196  * @param cmod a reference to the other comparison instance
00197  * @return Returns true, if the full file names of both modules are the
00198  * same, false otherwise
00199  */
00200 bool
00201 ModuleDL::operator==(ModuleDL &cmod)
00202 {
00203   return ( filename == cmod.get_filename() );
00204 }
00205 
00206 
00207 /** Check if the module has the given symbol
00208  * @param symbol_name The name of the symbol.
00209  * NOTE: C++ symbols are mangled with type info and thus are not plainly
00210  * available as symbol name. Use extern "C" to avoid this.
00211  * Read
00212  * http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/C++-dlopen-mini-HOWTO.html
00213  * for more information on this topic.
00214  * @return Returns true if the symbol was found, false otherwise
00215  */
00216 bool
00217 ModuleDL::has_symbol(const char *symbol_name)
00218 {
00219   if( symbol_name == NULL ) {
00220     return false;
00221   }
00222   if ( handle == NULL ) {
00223     return false;
00224   }
00225 
00226   return ( dlsym( handle, symbol_name ) != NULL );
00227 }
00228 
00229 
00230 /** Get a symbol from the module
00231  * @param symbol_name The name of the symbol.
00232  * NOTE: C++ symbols are mangled with type info and thus are not plainly
00233  * available as symbol name. Use extern "C" to avoid this.
00234  * Read
00235  * http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/C++-dlopen-mini-HOWTO.html
00236  * for more information on this topic.
00237  * @return Returns a pointer to the symbol or NULL if symbol was not found
00238  */
00239 void *
00240 ModuleDL::get_symbol(const char *symbol_name)
00241 {
00242   if( symbol_name == NULL ) return NULL;
00243   if ( handle == NULL ) return NULL;
00244 
00245   return dlsym( handle, symbol_name );
00246 }
00247 
00248 
00249 /** Get file extension for dl modules
00250  * @return Returns the file extension for dl modules, this is "so"
00251  */
00252 const char *
00253 ModuleDL::get_file_extension()
00254 {
00255   return FILE_EXTENSION;
00256 }
00257 
00258 
00259 /** Get the full file name of the module
00260  * @return Returns a string with the full file name of the module
00261  */
00262 std::string
00263 ModuleDL::get_filename()
00264 {
00265   return filename;
00266 }
00267 
00268 
00269 /** Get the base file name of the module
00270  * @return Returns the base file name of the module. On Unix systems this is
00271  * everything after the last slash
00272  */
00273 std::string
00274 ModuleDL::get_base_filename()
00275 {
00276   if ( filename.find("/", 0) != std::string::npos ) {
00277     std::string rv = filename.substr(filename.rfind("/", filename.length()) + 1, filename.length());
00278     return rv;
00279   } else {
00280     return filename.c_str();
00281   }
00282 }
00283 
00284 
00285 } // end namespace fawkes

Generated on Tue Feb 22 13:32:28 2011 for Fawkes API by  doxygen 1.4.7