MXM Loader

July 24th, 2010

This module and its classes provides functionalities to load MxM modules, dependencies and configuration files in a customizable way: the basic implementation provides basic, standard loading features, while extension could perform any kind of desired action (for example file measures introductory to a following remote attestation).

The library is simply organized: it provides three different kind of loaders for:

1. text files
2. dynamic libraries
3. MxM engines (an extension of the library loader)

A factory will give the user an interface to obtain fresh loaders of the desired kind: requested parameters for customized implementations should be passed to the factory constructor.
Basic interface

All loaders variant share a common base class that defines the basic interface a generic loader should have, together with its common properties:

//! this class is the basic interface for any kind of loader
class GenericLoader
: public Loggable
{
public:
//! build a generic loader specifying the full path of the file to handle
GenericLoader( const string & fname );

//! releases any resource
virtual ~GenericLoader();

//! loads the file - various implementations will perform requested operations
virtual void load() throw( MXMException ) = 0;

//! tells if the file has been successfully loaded
virtual bool isLoaded() const throw() = 0;

//! returns file name
const string & getFileName() const throw();

//! returns last error
const string & getLastError() const throw();
protected:
//! file load logic - various implementation will implement different checks during this phase
virtual void open() throw() = 0;

//! implementation specific fill-up of _err
virtual void loadLastError() throw() = 0;

//! the full path of the file to load
string _fileName;
//! string representation of the error of the last performed action
string _err;
};

Subtypes of this class will implement the pure virtual methods and possibly add new ones when requested or desired.
The load method should always be explicitlty called, no action is performed during the object construction, in no class of this library.
The text file loader

The TextLoader class is quite simple: its constructor takes the file name as input parameter and tries to open it; a couple of methods will return a reference to the hidden std::ifstream or the file content as a whole:

class TextLoader
: public GenericLoader
{
public:
//! loads the file calling ‘open’ and checks the result
virtual void load() throw( MXMException );

//! tells if the stream is good
virtual bool isLoaded() const throw();

//! returns file content if loading was good
string getFileContent() throw( MXMException );

//! returns reference to input stream
ifstream & getFileStream() throw( MXMException );
protected:
//! file load logic - open text file and guess size
virtual void open() throw( );

//! set common error string
virtual void loadLastError() throw();

//! text file handle
ifstream _file;

//! text file size
int _fileSize;
};

The opening of the file is performed in the open method, where the actual file size is cached to support successive calls to getFileContent; the load method calls open and throws an exception if something gone bad.

A subclass of this one should override the open method to add the custom steps, relying on the basic implementation to perform standard actions, preparatory to have getFileStream and getFileContent fully functional:

class MyLoader
: public TextLoader
{
protected:
virtual void open() throw()
{
TextLoader::open();
if ( TextLoader::isLoaded() )
{
// perform actions on the opened file
}
}
};

The dynamic library loader

The LibraryLoader is a bit more complicated: we broke down the code once more to isolate as most as possible OS-dependent code, support customization and code reuse for the EngineLoader:

class LibraryLoader
: public GenericLoader
{
public:
//! loads the library calling the ‘open’ method then checks the result
virtual void load() throw( MXMException );

//! tells if the library has been successfully loaded
virtual bool isLoaded() const throw();

//! returns a pointer to a symbol
void * getSymbol( const string & ) throw( MXMException );

protected:
//! this method simply calls ‘loadModule’
virtual void open() throw();

//! platform-dependent fill-up of _handle
virtual void loadModule() throw();

//! platform-dependent fill-up of _err
virtual void loadLastError() throw();

//! platform-dependend release of _handle
void unloadModule() throw();

//! platform-dependent symbol load
void * loadSymbol( const string & ) throw();

#ifdef WIN32
//! o.s. handle of the library
HINSTANCE _handle;
#else
//! o.s. handle of the library
void *_handle;
#endif
};

A set of new method is added to support library-specific operations:

1. loadModule performs the library binding calling dlopen on *X platforms or LoadLibrary on Windows
2. unloadModule release the loaded handle using platform-specific APIs
3. loadSymbol performs symbol lookup using platform-specific APIs, returning 0 if something gone bad
4. getSymbol is a secure shell the calls loadSymbol only if the library is loaded, and throws exceptions if the symbol was not found

The load method here acts exactly like the one from TextLoader class, as getSymbol it’s a shell to safely perform open.
The open method itself just calls loadModule in this basic implementation: this code fragmentation should give the coder many entry points to customize the behaviour of the class reusing at most existing lines: for instance, one can override the loadModule to use different APIs, or open to use the standard OS API and perform custom actions after the binding.
The MxM Engine loader

As stated above, the EngineLoader is an extension of the LibraryLoader: a MxM engine library is a dynamic library with a standard symbol defined in it, factory0, that returns an instance of a factory (exposed through an interface) that will give us an instance of the engine - see MxM basics.

We start defining its interface:

//! engine loader interface
class EngineLoader
{
public:
virtual ~EngineLoader() {}
virtual void load() throw( MXMException ) = 0;
virtual bool isLoaded() const throw() = 0;
virtual const string & getFileName() const throw() = 0;
virtual AbstractEngineFactory& getEngineFactory() throw( MXMException ) = 0;
};

To get the engine factory, we must load the factory0 symbol before, so we break the process in two parts and two classes, whose code will be very similar, and comparable to the code of the first loaders introduced.
But before going on, we should think about the future: since these loaders just performs a symbol lookup and a function call after the loading of a dynamic module, we imagine that customization will be done in the library loader, not in the engine one; so we can choose a common “pointer to implemetation” pattern, passing to the constructor an instance of the library loader; or we can follow the template way to fasten the base class at compile time. We chose the latter solution.

So, an intermediate class sprout, commissioned to load the factory0 symbol:

//! this is the type of the factory0 function, the one defined in every engine library that returns an instance of the engine factory class
typedef void * (*EngineFactoryFunc)() ;

template< class Loader >
class EngineFactoryBaseLoader
: public Loader
{
protected:
//! build the library loader with the specified file name
EngineFactoryBaseLoader(const string& fname);
//! dtor
virtual ~EngineFactoryBaseLoader();
public:
//! loads library and factory0 symbol
virtual void load() throw( MXMException );

//! tells if library and factory0 have been successfully loaded
virtual bool isLoaded() const throw();

//! returns pointer to factory0 symbol in library
EngineFactoryFunc getFactoryFunc() const throw( MXMException );

protected:
//! address of the factory0 function
EngineFactoryFunc _factoryFunc;
};

This template extends the desired LibraryLoader implementation: its load version calls the base implementation, then looks up the symbol, storing its address in the protected member:

template< class Loader >
void EngineFactoryBaseLoader< Loader >::load() throw( MXMException )
{
Loader::load();
this->_factoryFunc = reinterpret_cast< EngineFactoryFunc >( this->getSymbol( “factory0″ ) );
}

The kind of the template parameter Loader determines the implementation of the library loading process; everything else is built over it.

Next step is to call the loaded function and obtain an instance of the engine factory; this will be the actual implementation of the interface exposed above:

template< class Loader >
class EngineFactoryLoader
: public EngineLoader
, public EngineFactoryBaseLoader< Loader >
{
public:
//! loads library, factory0 symbol and engine factory
virtual void load() throw( MXMException );

//! tells if library, factory0 and engine factory have been successfully loaded
virtual bool isLoaded() const throw();

//! returns library name
virtual const string & getFileName() const throw();

//! returns a reference to the loaded engine factory
virtual AbstractEngineFactory& getEngineFactory() throw( MXMException );
protected:
//! pointer to the loaded instance of the abstract engine factory
ptr::Scoped< AbstractEngineFactory > _engineFactory;
};

It extends the intermediate class adding function invocation during the load process:

template< class Loader >
void EngineFactoryLoader< Loader >::load() throw( MXMException )
{
EngineFactoryBaseLoader< Loader >::load();
this->_engineFactory = reinterpret_cast< AbstractEngineFactory * > ( this->_factoryFunc() );
}

The factory of loaders

Now we have everything we need to declare a factory interface and a basic implementation for it:

class AbstractLoaderFactory
{
public:
AbstractLoaderFactory() {}
virtual ~AbstractLoaderFactory() {}
virtual LibraryLoader * getLibraryLoader( const string & fname ) const throw() = 0;
virtual TextLoader * getTextLoader( const string & fname ) const throw() = 0;
virtual EngineLoader * getEngineLoader( const string & fname ) const throw() = 0;
};

A LibraryLoader and a TextLoader are instantiatable, and as EngineLoader we can simply return an instance of EngineFactoryLoader< LibraryLoader > - and engine loading process based on the simplest library loader.

-->