From cae80f85741d2564d918a0e3285c62e51491a7fc Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Sat, 10 Dec 2005 09:59:10 +0000 Subject: [PATCH] Loadable filter support for FilterFactory using dlopen/dlsym. Only works for Linux and similar systems. Added a test it in test_filter_factory. Also extended test_filter_factory to call the loadable filters (to ensure they are _right_). --- src/Makefile.am | 16 ++++++-- src/filter.hpp | 15 ++++---- src/filter_dl.cpp | 46 ++++++++++++++++++++++ src/filter_factory.cpp | 39 +++++++++++++++++-- src/filter_factory.hpp | 9 ++--- src/test_filter_factory.cpp | 89 +++++++++++++++++++++++++------------------ src/tstdl.cpp | 49 ++++++++++++++++++++++++ 7 files changed, 205 insertions(+), 58 deletions(-) create mode 100644 src/filter_dl.cpp create mode 100644 src/tstdl.cpp diff --git a/src/Makefile.am b/src/Makefile.am index d3924c1..197c06a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -## $Id: Makefile.am,v 1.37 2005-12-02 12:21:07 adam Exp $ +## $Id: Makefile.am,v 1.38 2005-12-10 09:59:10 adam Exp $ MAINTAINERCLEANFILES = Makefile.in config.in config.hpp @@ -9,7 +9,7 @@ EXTRA_DIST=Jamfile.in # Rules for the library.. lib_LTLIBRARIES = libyp2.la -libyp2_la_LDFLAGS = -version-info 0:0:0 +libyp2_la_LDFLAGS = -version-info 0:0:0 -export-dynamic libyp2_la_SOURCES = \ session.cpp session.hpp \ @@ -33,10 +33,19 @@ libyp2_la_SOURCES = \ LDADD= libyp2.la $(YAZPPLALIB) $(XSLT_LIBS) bin_PROGRAMS = -noinst_PROGRAMS = ex_filter_frontend_net ex_router_flexml +noinst_PROGRAMS = ex_filter_frontend_net ex_router_flexml tstdl ex_filter_frontend_net_SOURCES = ex_filter_frontend_net.cpp ex_router_flexml_SOURCES = ex_router_flexml.cpp +tstdl_SOURCES = tstdl.cpp + +# Rules for dl programs +pkglib_LTLIBRARIES = yp2_filter_dl.la + +yp2_filter_dl_la_SOURCES = filter_dl.cpp +yp2_filter_dl_la_LDFLAGS = -rpath $(pkglibdir) -module -avoid-version +yp2_filter_dl_la_LIBADD = libyp2.la + # Rules for test programs.. check_PROGRAMS = \ @@ -67,6 +76,7 @@ test_boost_threads_SOURCES=test_boost_threads.cpp test_boost_time_SOURCES=test_boost_time.cpp test_thread_pool_observer_SOURCES = test_thread_pool_observer.cpp test_filter_factory_SOURCES = test_filter_factory.cpp +test_filter_factory_LDFLAGS = -export-dynamic test_filter_frontend_net_SOURCES = test_filter_frontend_net.cpp test_filter_log_SOURCES = test_filter_log.cpp test_filter_z3950_client_SOURCES = test_filter_z3950_client.cpp diff --git a/src/filter.hpp b/src/filter.hpp index 29f5216..c2855bd 100644 --- a/src/filter.hpp +++ b/src/filter.hpp @@ -1,4 +1,4 @@ -/* $Id: filter.hpp,v 1.9 2005-11-03 14:45:15 adam Exp $ +/* $Id: filter.hpp,v 1.10 2005-12-10 09:59:10 adam Exp $ Copyright (c) 2005, Index Data. %LICENSE% @@ -23,12 +23,7 @@ namespace yp2 { ///sends Package off to next Filter, returns altered Package virtual void process(Package & package) const = 0; - virtual void configure(const xmlNode * ptr = 0) { }; - }; - - struct Creator { - const char* type; - yp2::filter::Base* (*creator)(); + virtual void configure(const xmlNode * ptr) { }; }; class FilterException : public std::runtime_error { @@ -39,9 +34,13 @@ namespace yp2 { }; } - } +struct yp2_filter_struct { + int ver; + yp2::filter::Base* (*creator)(); +}; + #endif /* * Local variables: diff --git a/src/filter_dl.cpp b/src/filter_dl.cpp new file mode 100644 index 0000000..7ce559b --- /dev/null +++ b/src/filter_dl.cpp @@ -0,0 +1,46 @@ +/* $Id: filter_dl.cpp,v 1.1 2005-12-10 09:59:10 adam Exp $ + Copyright (c) 2005, Index Data. + +%LICENSE% + */ + +#include "config.hpp" + +#include "filter.hpp" +#include "router.hpp" +#include "package.hpp" + +namespace yp2 { + namespace filter { + class Filter_dl: public yp2::filter::Base { + public: + void process(yp2::Package & package) const; + }; + } +} + +void yp2::filter::Filter_dl::process(yp2::Package & package) const +{ + package.data() = 42; +} + +static yp2::filter::Base* filter_creator() +{ + return new yp2::filter::Filter_dl; +} + +extern "C" { + struct yp2_filter_struct yp2_filter_dl = { + 0, + filter_creator + }; +} + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * c-file-style: "stroustrup" + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/filter_factory.cpp b/src/filter_factory.cpp index 6cbca63..a5406bd 100644 --- a/src/filter_factory.cpp +++ b/src/filter_factory.cpp @@ -1,11 +1,16 @@ -/* $Id: filter_factory.cpp,v 1.1 2005-11-10 23:10:42 adam Exp $ +/* $Id: filter_factory.cpp,v 1.2 2005-12-10 09:59:10 adam Exp $ Copyright (c) 2005, Index Data. %LICENSE% */ +#include "config.hpp" + #include "filter_factory.hpp" +#if HAVE_DLFCN_H +#include +#endif #include #include #include @@ -13,6 +18,7 @@ namespace yp2 { class FilterFactory::Rep { + typedef std::map CallbackMap; public: friend class FilterFactory; CallbackMap m_fcm; @@ -47,7 +53,7 @@ yp2::FilterFactory::~FilterFactory() bool yp2::FilterFactory::add_creator(std::string fi, CreateFilterCallback cfc) { - return m_p->m_fcm.insert(CallbackMap::value_type(fi, cfc)).second; + return m_p->m_fcm.insert(Rep::CallbackMap::value_type(fi, cfc)).second; } @@ -58,7 +64,7 @@ bool yp2::FilterFactory::drop_creator(std::string fi) yp2::filter::Base* yp2::FilterFactory::create(std::string fi) { - CallbackMap::const_iterator it = m_p->m_fcm.find(fi); + Rep::CallbackMap::const_iterator it = m_p->m_fcm.find(fi); if (it == m_p->m_fcm.end()){ std::string msg = "filter type '" + fi + "' not found"; @@ -68,6 +74,33 @@ yp2::filter::Base* yp2::FilterFactory::create(std::string fi) return (it->second()); } +#if HAVE_DLFCN_H +bool yp2::FilterFactory::add_creator_dyn(const std::string &fi, + const std::string &path) +{ + std::string full_path = path + "/yp2_filter_" + fi + ".so"; + void *dl_handle = dlopen(full_path.c_str(), RTLD_GLOBAL|RTLD_NOW); + if (!dl_handle) + { + const char *dl = dlerror(); + std::cout << "dlopen " << full_path << " failed. dlerror=" << dl << + std::endl; + return false; + } + + std::string full_name = "yp2_filter_" + fi; + + void *dlsym_ptr = dlsym(dl_handle, full_name.c_str()); + if (!dlsym_ptr) + { + std::cout << "dlsym " << full_name << " failed\n"; + return false; + } + struct yp2_filter_struct *s = (struct yp2_filter_struct *) dlsym_ptr; + return add_creator(fi, s->creator); +} +#endif + /* * Local variables: * c-basic-offset: 4 diff --git a/src/filter_factory.hpp b/src/filter_factory.hpp index 320f86f..c8b2251 100644 --- a/src/filter_factory.hpp +++ b/src/filter_factory.hpp @@ -1,4 +1,4 @@ -/* $Id: filter_factory.hpp,v 1.6 2005-11-10 23:10:42 adam Exp $ +/* $Id: filter_factory.hpp,v 1.7 2005-12-10 09:59:10 adam Exp $ Copyright (c) 2005, Index Data. %LICENSE% @@ -28,7 +28,6 @@ namespace yp2 { class FilterFactory : public boost::noncopyable { typedef yp2::filter::Base* (*CreateFilterCallback)(); - typedef std::map CallbackMap; class Rep; public: @@ -38,14 +37,12 @@ namespace yp2 { ~FilterFactory(); bool add_creator(std::string fi, CreateFilterCallback cfc); - /// true if unregistration ok bool drop_creator(std::string fi); - /// factory create method - yp2::filter::Base* create(std::string fi); - + + bool add_creator_dyn(const std::string &fi, const std::string &path); private: boost::scoped_ptr m_p; }; diff --git a/src/test_filter_factory.cpp b/src/test_filter_factory.cpp index 7dfcaae..b9190e3 100644 --- a/src/test_filter_factory.cpp +++ b/src/test_filter_factory.cpp @@ -1,16 +1,16 @@ -/* $Id: test_filter_factory.cpp,v 1.6 2005-12-02 12:21:07 adam Exp $ +/* $Id: test_filter_factory.cpp,v 1.7 2005-12-10 09:59:10 adam Exp $ Copyright (c) 2005, Index Data. %LICENSE% */ - #include #include #include "config.hpp" #include "filter.hpp" +#include "package.hpp" #include "filter_factory.hpp" @@ -19,25 +19,35 @@ using namespace boost::unit_test; +// XFilter class XFilter: public yp2::filter::Base { public: - void process(yp2::Package & package) const {}; + void process(yp2::Package & package) const; }; +void XFilter::process(yp2::Package & package) const +{ + package.data() = 1; +} -yp2::filter::Base* xfilter_creator(){ +static yp2::filter::Base* xfilter_creator(){ return new XFilter; } +// YFilter ... class YFilter: public yp2::filter::Base { public: - void process(yp2::Package & package) const {}; + void process(yp2::Package & package) const; }; -yp2::filter::Base* yfilter_creator(){ - return new YFilter; +void YFilter::process(yp2::Package & package) const +{ + package.data() = 2; } +static yp2::filter::Base* yfilter_creator(){ + return new YFilter; +} BOOST_AUTO_UNIT_TEST( test_filter_factory_1 ) { @@ -51,54 +61,57 @@ BOOST_AUTO_UNIT_TEST( test_filter_factory_1 ) const std::string xfid = "XFilter"; const std::string yfid = "YFilter"; - //std::cout << "Xfilter name: " << xfid << std::endl; - //std::cout << "Yfilter name: " << yfid << std::endl; - - BOOST_CHECK_EQUAL(ffactory.add_creator(xfid, xfilter_creator), - true); - BOOST_CHECK_EQUAL(ffactory.drop_creator(xfid), - true); - BOOST_CHECK_EQUAL(ffactory.add_creator(xfid, xfilter_creator), - true); - BOOST_CHECK_EQUAL(ffactory.add_creator(yfid, yfilter_creator), - true); + BOOST_CHECK(ffactory.add_creator(xfid, xfilter_creator)); + BOOST_CHECK(ffactory.drop_creator(xfid)); + BOOST_CHECK(ffactory.add_creator(xfid, xfilter_creator)); + BOOST_CHECK(ffactory.add_creator(yfid, yfilter_creator)); yp2::filter::Base* xfilter = 0; xfilter = ffactory.create(xfid); yp2::filter::Base* yfilter = 0; yfilter = ffactory.create(yfid); - //BOOST_CHECK_EQUAL(sizeof(xf), sizeof(*xfilter)); - //BOOST_CHECK_EQUAL(sizeof(yf), sizeof(*yfilter)); - BOOST_CHECK(0 != xfilter); BOOST_CHECK(0 != yfilter); + + yp2::Package pack; + xfilter->process(pack); + BOOST_CHECK_EQUAL(pack.data(), 1); + + yfilter->process(pack); + BOOST_CHECK_EQUAL(pack.data(), 2); } catch ( ... ) { throw; BOOST_CHECK (false); } - - std::exit(0); } -// get function - right val in assignment -//std::string name() const { -//return m_name; -// return "Base"; -//} - -// set function - left val in assignment -//std::string & name() { -// return m_name; -//} +#if HAVE_DLFCN_H +BOOST_AUTO_UNIT_TEST( test_filter_factory_2 ) +{ + try { + yp2::FilterFactory ffactory; + + const std::string id = "dl"; + + BOOST_CHECK(ffactory.add_creator_dyn(id, ".libs")); + + yp2::filter::Base* filter = 0; + filter = ffactory.create(id); -// set function - can be chained -//Base & name(const std::string & name){ -// m_name = name; -// return *this; -//} + BOOST_CHECK(0 != filter); + yp2::Package pack; + filter->process(pack); + BOOST_CHECK_EQUAL(pack.data(), 42); // magic from filter_dl .. + } + catch ( ... ) { + throw; + BOOST_CHECK (false); + } +} +#endif /* * Local variables: diff --git a/src/tstdl.cpp b/src/tstdl.cpp new file mode 100644 index 0000000..4f3eb66 --- /dev/null +++ b/src/tstdl.cpp @@ -0,0 +1,49 @@ +/* $Id: tstdl.cpp,v 1.1 2005-12-10 09:59:10 adam Exp $ + Copyright (c) 2005, Index Data. + +%LICENSE% + */ + +#include "config.hpp" + +#include +#include +#if HAVE_DLFCN_H +#include +#endif + +using namespace std; + +int main(int argc, char **argv) +{ +#if HAVE_DLFCN_H + if (argc != 3) + { + cerr << "bad args" << endl << "Usage: tstdl filename symbol" << endl; + exit(1); + } + void *mod = dlopen(argv[1][0] ? argv[1] : 0, RTLD_NOW|RTLD_LOCAL); + if (!mod) + { + cerr << "dlopen failed for file " << argv[1] << + "dlerror=" << dlerror() << endl; + exit(1); + } + void *sym = dlsym(mod, argv[2]); + printf("sym=%p\n", sym); + dlclose(mod); + exit(0); +#else + cerr << "dl lib not enabled or not supported" << endl; + exit(1); +#endif + +} +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * c-file-style: "stroustrup" + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ -- 1.7.10.4