From 6bf0faed36d48665d4e8ba4058682fb2bd8de093 Mon Sep 17 00:00:00 2001 From: Reinhard Pfau Date: Mon, 25 Aug 2008 13:12:09 +0000 Subject: [PATCH] libsimpleio: (reinhard) added t2n glue as additional lib (/sub package) --- Makefile.am | 2 +- configure.in | 6 +- glue_t2n/Makefile.am | 13 + glue_t2n/glue_t2n.cpp | 909 +++++++++++++++++++++++++++++++++++++ glue_t2n/glue_t2n.hpp | 200 ++++++++ glue_t2n/libsimpleio_t2n.pc.in | 11 + libsimpleio.spec | 41 ++- unittest/test_simpleio_basics.cpp | 4 +- 8 files changed, 1177 insertions(+), 9 deletions(-) create mode 100644 glue_t2n/Makefile.am create mode 100644 glue_t2n/glue_t2n.cpp create mode 100644 glue_t2n/glue_t2n.hpp create mode 100644 glue_t2n/libsimpleio_t2n.pc.in diff --git a/Makefile.am b/Makefile.am index 1f2d4d0..9093663 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,3 @@ AUTOMAKE_OPTIONS = foreign -SUBDIRS = doc simpleio unittest +SUBDIRS = doc simpleio glue_t2n unittest diff --git a/configure.in b/configure.in index 3399270..bc81b53 100644 --- a/configure.in +++ b/configure.in @@ -34,6 +34,7 @@ PKG_CHECK_MODULES(LIBI2NCOMMON, libi2ncommon) AC_SUBST(LIBI2NCOMMON_CFLAGS) AC_SUBST(LIBI2NCOMMON_LIBS) +LIBT2N_CHECK(libt2n) AM_PATH_CPPUNIT(1.8.0) @@ -48,6 +49,7 @@ dnl dnl spit out the result files: -AC_OUTPUT(Makefile doc/Makefile simpleio/Makefile unittest/Makefile - simpleio/libsimpleio.pc +AC_OUTPUT(Makefile doc/Makefile glue_t2n/Makefile simpleio/Makefile \ + unittest/Makefile \ + simpleio/libsimpleio.pc glue_t2n/libsimpleio_t2n.pc ) diff --git a/glue_t2n/Makefile.am b/glue_t2n/Makefile.am new file mode 100644 index 0000000..d7acfc6 --- /dev/null +++ b/glue_t2n/Makefile.am @@ -0,0 +1,13 @@ +INCLUDES = -I$(top_srcdir)/simpleio @LIBT2N_CFLAGS@ @BOOST_CPPFLAGS@ \ + @LIBI2NCOMMON_CFLAGS@ +METASOURCES = AUTO +lib_LTLIBRARIES = libsimpleio_t2n.la +libsimpleio_t2n_la_SOURCES = glue_t2n.cpp +include_HEADERS = glue_t2n.hpp +libsimpleio_t2n_la_LIBADD = $(top_builddir)/simpleio/libsimpleio.la \ + @LIBT2N_LIBS@ @BOOST_LDFLAGS@ @BOOST_SIGNALS_LIB@ @LIBI2NCOMMON_LIBS@ + +libsimpleio_t2n_la_LDFLAGS = -version-info @LIBSIMPLEIO_LIB_VERSION@ + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA= libsimpleio_t2n.pc diff --git a/glue_t2n/glue_t2n.cpp b/glue_t2n/glue_t2n.cpp new file mode 100644 index 0000000..21a946e --- /dev/null +++ b/glue_t2n/glue_t2n.cpp @@ -0,0 +1,909 @@ +/** + * @file + * + * @author Reinhard Pfau \ + * + * @copyright © Copyright 2008 by Intra2net AG + * @license commercial + * @contact info@intra2net.com + */ + +#include "glue_t2n.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + + + +namespace I2n +{ + +using namespace SimpleIo; + + +namespace +{ + + +Logger::PartLogger& module_logger() +{ + static Logger::PartLogger _module_logger(HERE); + return _module_logger; +} // eo module_logger(); + + + +/** + * @brief a class with some methods we like to have on our io classes. + * + * This class is to be used as second base in a wrapper class and needs it's methods to + * be redefined for "the real thing". + */ +class IOExportWrapperBase +{ + public: + + IOExportWrapperBase() + { + } + + virtual ~IOExportWrapperBase() + { + } + + virtual void sendData(const std::string& data) + { + } + + + virtual std::string receiveData() + { + return std::string(); + } + + virtual boost::signals::connection connectEof( const boost::function< void() >& func ) + { + return boost::signals::connection(); + } + + virtual boost::signals::connection connectRead( const boost::function< void() >& func ) + { + return boost::signals::connection(); + } + +}; // eo class IOExportWrapperBase + + +typedef boost::shared_ptr< IOExportWrapperBase > IOExportWrapperBasePtr; + + +/** + * @brief IO wrapper template. + * @tparam IOClass a type based on SimpleIo::IOImplementation + * + * The type is used as a public base for the resulting class; the second public base is our + * helper with the additional methods we need internally and which we (finally) define here. + */ +template< + class IOClass +> +class IOExportWrapper +: public IOClass +, public IOExportWrapperBase +{ + BOOST_STATIC_ASSERT(( boost::is_base_of< IOImplementation,IOClass >::value )); + + public: + IOExportWrapper() + { + } + + template< + typename Arg1 + > + IOExportWrapper(Arg1 arg1) + : IOClass(arg1) + {} + + + template< + typename Arg1, typename Arg2 + > + IOExportWrapper(Arg1 arg1, Arg2 arg2) + : IOClass(arg1,arg2) + {} + + + template< + typename Arg1, typename Arg2, typename Arg3 + > + IOExportWrapper(Arg1 arg1, Arg2 arg2, Arg3 arg3) + : IOClass(arg1,arg2,arg3) + {} + + + template< + typename Arg1, typename Arg2, typename Arg3, typename Arg4 + > + IOExportWrapper(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) + : IOClass(arg1,arg2,arg3,arg4) + {} + + + template< + typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5 + > + IOExportWrapper(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) + : IOClass(arg1,arg2,arg3,arg4,arg5) + {} + + + /** + * @brief exposed funtion for sending data. + * @param data the chunk to be send. + */ + virtual void sendData(const std::string& data) + { + IOClass::lowSend(data); + } + + /** + * @brief returns the new received data. + * @return the receievd data. + * + * Clears the receive buffer. + */ + virtual std::string receiveData() + { + std::string result; + result.swap(IOClass::m_input_buffer); + return result; + } + + /** + * @brief exposed connect to EOF signal. + * @param func the function which should be connected to the eof signal. + * @return signal connection handle. + */ + virtual boost::signals::connection connectEof( const boost::function< void() >& func ) + { + return IOClass::m_signal_eof.connect(func); + } + + /** + * @brief exposed connect to "read" signal. + * @param func the function which should be connected to the "read" signal. + * @return signal connection handle. + */ + virtual boost::signals::connection connectRead( const boost::function< void() >& func ) + { + return IOClass::m_signal_read.connect(func); + } + + protected: + +}; // eo class IOExportWrapper + + +/* +** specialized versions of io classes: +*/ + +/** + * @brief enhanced unix domain socket class with reconnect feature. + * + * Used for t2n client connections. + */ +class T2nUnixIOSocket +: public SimpleIo::UnixIOSocket +{ + typedef SimpleIo::UnixIOSocket inherited; + public: + T2nUnixIOSocket( const std::string& path ); + + virtual void close(SimpleIo::Direction direction = SimpleIo::Direction::both); + + bool reopen(bool force= false); + + protected: + + virtual void doRead(); + + + protected: + + bool m_in_do_read; + bool m_may_reconnect; + +}; // T2nUnixIOSocket + + +T2nUnixIOSocket::T2nUnixIOSocket(const std::string& path) +: inherited(path) +, m_in_do_read(false) +, m_may_reconnect(false) +{ +} // eo T2nUnixIOSocket::T2nUnixIOSocket(const std::string&) + + +void T2nUnixIOSocket::close(SimpleIo::Direction direction) +{ + bool was_open= opened(); + inherited::close(direction); + if (m_in_do_read and not opened()) + { + m_may_reconnect= was_open; + } +} // eo T2nUnixIOSocket::close(SimpleIo::Direction) + + +bool T2nUnixIOSocket::reopen(bool force) +{ + if (m_path.empty()) + { + return false; + } + if (m_may_reconnect || force) + { + return inherited::open( m_path ); + } + return false; +} // eo T2nUnixIOSocket::reopen() + + +void T2nUnixIOSocket::doRead() +{ + m_in_do_read= true; + try + { + inherited::doRead(); + } + catch (...) + { + m_in_do_read= false; + throw; + } + m_in_do_read= false; +} // eo T2nUnixIOSocket::doRead() + + +/** + * @brief server class for libt2n using unix domain sockets. + * + * well, it's enough to provide an appropriate constructor. + * (did i mention that templates are really cool stuff? :-) ) + */ +class T2NUnixServer +: public T2NServerBase +{ + public: + + T2NUnixServer(const std::string& path, int mode=0600) + : T2NServerBase( ServerSocketBaseImplementationPtr( + new UnixServerSocket< + IOExportWrapper< UnixIOSocket > + >(path, mode) + ) ) + { + } // eo T2NServerBase + +}; // eo T2NUnixServer + + + +class RealT2NClientConnection +: public T2NClientConnection +{ + public: + RealT2NClientConnection( SimpleIo::IOImplementationPtr connection ) + : T2NClientConnection(connection) + { + } +}; // eo class T2NClient + +} // eo namespace + + + +/* +** implementation of T2NClientConnection +*/ + + +T2NClientConnection::T2NClientConnection( + IOImplementationPtr connection +) +: libt2n::client_connection() +, m_real_connection(connection) +, m_got_new_data(false) +{ + SCOPETRACKER(); + IOExportWrapperBasePtr ptr = boost::dynamic_pointer_cast< IOExportWrapperBase >(connection); + if (!ptr) + { + module_logger().error(HERE) << "illegal pointer passed"; + close(); + return; + } + if (!connection->opened()) + { + module_logger().warning(HERE) << "connection not open, either failed or already closed"; + close(); + return; + } + + ptr->connectRead( boost::bind(&T2NClientConnection::newDataSlot, this) ); + ptr->connectEof( boost::bind(&T2NClientConnection::eofSlot, this) ); + +} // eo T2NClientConnection::T2NClientConnection(IOImplementationPtr) + + +T2NClientConnection::~T2NClientConnection() +{ + SCOPETRACKER(); +} // eo T2NClientConnection::~T2NClientConnection + + +/** + * @brief returns if the connection is open. + * @return @a true if the connection is open. + */ +bool T2NClientConnection::isOpen() +{ + return m_real_connection and m_real_connection->opened(); +} // eo T2NClientConnection::isOpen() + + +/** + * @brief try to reopen a connection. + * @return @a true if the connection was reopened. + */ +bool T2NClientConnection::reopen(bool force) +{ + if (not m_real_connection) + { + return false; + } + boost::shared_ptr< T2nUnixIOSocket > t2n_socket= + boost::shared_dynamic_cast< T2nUnixIOSocket >(m_real_connection); + if (t2n_socket) + { + return t2n_socket->reopen(force); + } + return false; +} // eo T2NClientConnection::reopen() + + +/** + * @brief closes the connection. + * + * This closes the underlying IO connection and calls libt2n::server_connection::close() to + * mark the connection as closed for libt2n. + */ +void T2NClientConnection::close() +{ + SCOPETRACKER(); + if (m_real_connection) + { + m_real_connection->close(); + m_real_connection.reset(); + } + libt2n::client_connection::close(); +} // eo T2NClientConnection::close() + + +/** + * @brief sends a raw data chunk on the connection. + * + * @param data the /raw) data chunk which should be sended. + */ +void T2NClientConnection::real_write(const std::string& data) +{ + SCOPETRACKER(); + if (is_closed()) + { + module_logger().warning(HERE) << "attempt to write data on closed connection"; + return; + } + IOExportWrapperBasePtr ptr = boost::dynamic_pointer_cast< IOExportWrapperBase >(m_real_connection); + if (!ptr) + { + // should never happen... + module_logger().error(HERE)<< "illegal io pointer"; + close(); + //TODO: throw an error?! + NOT_REACHED(); + return; + } + ptr->sendData(data); +} // eo T2NClientConnection::real_write(const std::string) + + +/** + * @brief called to fill the connection buffer. + * + * Since this class uses the asnychronous SimpleIo framework, new data may already be read when + * this method is called. + * + * @param usec_timeout + * @param usec_timeout_remaining + * @return @a true if new data is available. + */ +bool T2NClientConnection::fill_buffer(long long usec_timeout,long long* usec_timeout_remaining) +{ + SCOPETRACKER(); + if (is_closed()) + { + module_logger().debug(HERE) << "fill_buffer() called on closed connection"; + return false; + } + SimpleIo::MilliTime t0,t1; + SimpleIo::get_current_monotonic_time(t0); + if (!m_got_new_data) + { + IOExportWrapperBasePtr ptr = boost::dynamic_pointer_cast< IOExportWrapperBase >(m_real_connection); + if (!ptr) + { + module_logger().error(HERE) << "illegal io pointer"; + close(); + return false; + } + // try to fetch data (call the backend) + int timeout= 0; + + if (usec_timeout<0) + { + timeout= -1; + } + else if (usec_timeout > 0) + { + long long msec_timeout= (usec_timeout + 500)/1000; + + if (msec_timeout >= INT_MAX) + { + timeout= INT_MAX; + } + else + { + timeout= (int)msec_timeout; + } + } + Backend::getBackend()->doOneStep( timeout ); + } + SimpleIo::get_current_monotonic_time(t1); + if (usec_timeout_remaining) + { + long long delta= ((long long)(t1 - t0).get_milliseconds())* 1000L; + *usec_timeout_remaining= (usec_timeout > delta ) ? (usec_timeout - delta) : 0L; + module_logger().debug() << "timeout: " << usec_timeout << " -> " << *usec_timeout_remaining; + } + if (m_got_new_data) + { + m_got_new_data= false; + return true; + } + return false; +} // eo T2NClientConnection::fill_buffer(long long,long long*) + + +/** + * @brief called when new data arrived on this connection. + * + * reads the new data from the underlying IO object and stores it in the connection buffer. + * Also remembers (in the bool member var @a m_got_new_data) that new data was received. + */ +void T2NClientConnection::newDataSlot() +{ + SCOPETRACKER(); + IOExportWrapperBasePtr ptr = boost::dynamic_pointer_cast< IOExportWrapperBase >(m_real_connection); + if (!ptr) + { + //TODO: throw an error?! + NOT_REACHED(); + return; + } + std::string new_data= ptr->receiveData(); + module_logger().debug() << "got " << new_data.size() << " bytes of new data"; + buffer+= new_data; + m_got_new_data= true; +} // eo T2NClientConnection::newDataSlot() + + +/** + * @brief called when an EOF was detected by the underlying IO object (i.e. the connection + * was closed by the peer side). + * + * Calls close(). + */ +void T2NClientConnection::eofSlot() +{ + SCOPETRACKER(); + close(); +} // eo T2NClientConnection::eofSlot() + + +/* +** implementation of T2NServerConnection +*/ + + +T2NServerConnection::T2NServerConnection( + T2NServerBasePtr server, + IOImplementationPtr connection, + int timeout +) +: libt2n::server_connection(timeout) +, m_real_connection(connection) +, m_server_weak_ptr(server) +, m_got_new_data(false) +{ + SCOPETRACKER(); + IOExportWrapperBasePtr ptr = boost::dynamic_pointer_cast< IOExportWrapperBase >(connection); + if (!ptr) + { + module_logger().error(HERE) << "illegal pointer passed"; + close(); + return; + } + if (!connection->opened()) + { + module_logger().warning(HERE) << "connection not open, either failed or already closed"; + close(); + return; + } + + ptr->connectRead( boost::bind(&T2NServerConnection::newDataSlot, this) ); + ptr->connectEof( boost::bind(&T2NServerConnection::eofSlot, this) ); + +} // eo T2NServerConnection::T2NServerConnection(IOImplementationPtr) + + +T2NServerConnection::~T2NServerConnection() +{ + SCOPETRACKER(); +} // eo T2NServerConnection::~T2NServerConnection + + +/** + * @brief closes the connection. + * + * This closes the underlying IO connection and calls libt2n::server_connection::close() to + * mark the connection as closed for libt2n. + */ +void T2NServerConnection::close() +{ + SCOPETRACKER(); + if (m_real_connection) + { + m_real_connection->close(); + m_real_connection.reset(); + } + libt2n::server_connection::close(); +} // eo T2NServerConnection::close() + + +/** + * @brief sends a raw data chunk on the connection. + * + * @param data the (raw) data chunk which should be sended. + */ +void T2NServerConnection::real_write(const std::string& data) +{ + SCOPETRACKER(); + if (is_closed()) + { + module_logger().warning(HERE) << "attempt to write data on closed connection"; + return; + } + IOExportWrapperBasePtr ptr = boost::dynamic_pointer_cast< IOExportWrapperBase >(m_real_connection); + if (!ptr) + { + // should never happen... + module_logger().error(HERE)<< "illegal io pointer"; + close(); + //TODO: throw an error?! + NOT_REACHED(); + return; + } + ptr->sendData(data); +} // eo T2NServerConnection::real_write(const std::string) + + +/** + * @brief called to fill the connection buffer. + * + * Since this class uses the asnychronous SimpleIo framework, new data may already be read when + * this method is called. + * + * @param usec_timeout + * @param usec_timeout_remaining + * @return @a true if new data is available. + */ +bool T2NServerConnection::fill_buffer(long long usec_timeout,long long* usec_timeout_remaining) +{ + SCOPETRACKER(); + if (is_closed()) + { + module_logger().debug(HERE) << "fill_buffer() called on closed connection"; + return false; + } + SimpleIo::MilliTime t0,t1; + SimpleIo::get_current_monotonic_time(t0); + if (!m_got_new_data) + { + IOExportWrapperBasePtr ptr = boost::dynamic_pointer_cast< IOExportWrapperBase >(m_real_connection); + if (!ptr) + { + module_logger().error(HERE) << "illegal io pointer"; + close(); + return false; + } + // try to fetch data (call the backend) + int timeout= 0; + + if (usec_timeout<0) + { + timeout= -1; + } + else if (usec_timeout > 0) + { + long long msec_timeout= (usec_timeout + 500)/1000; + + if (msec_timeout >= INT_MAX) + { + timeout= INT_MAX; + } + else + { + timeout= (int)msec_timeout; + } + } + Backend::getBackend()->doOneStep( timeout ); + } + SimpleIo::get_current_monotonic_time(t1); + if (usec_timeout_remaining) + { + long long delta= ((long long)(t1 - t0).get_milliseconds())* 1000L; + *usec_timeout_remaining= (usec_timeout > delta ) ? (usec_timeout - delta) : 0L; + } + if (m_got_new_data) + { + m_got_new_data= false; + return true; + } + return false; +} // eo T2NServerConnection::fill_buffer(long long,long long*) + + +/** + * @brief called when new data arrived on this connection. + * + * reads the new data from the underlying IO object and stores it in the connection buffer. + * Also remembers (in the bool member var @a m_got_new_data that new data was received. + */ +void T2NServerConnection::newDataSlot() +{ + SCOPETRACKER(); + IOExportWrapperBasePtr ptr = boost::dynamic_pointer_cast< IOExportWrapperBase >(m_real_connection); + if (!ptr) + { + //TODO:throw an error?! + NOT_REACHED(); + return; + } + buffer+= ptr->receiveData(); + m_got_new_data= true; + reset_timeout(); + + T2NServerBasePtr server =m_server_weak_ptr.lock(); + if (server) + { + server->m_signal_client_got_new_data(); + } +} // eo T2NServerConnection::newDataSlot() + + +/** + * @brief called when an EOF was detected by the underlying IO object (i.e. the connection + * was closed by the peer side). + * + * Calls close(). + */ +void T2NServerConnection::eofSlot() +{ + SCOPETRACKER(); + close(); +} // eo T2NServerConnection::eofSlot() + + + +/* +** implementation of T2NServerBase +*/ + + +/** + * @brief constructs a libt2n server object. + * + * @param server_port shared pointer to a (SimpleIo) port server object which + * is used as underlying port handler. + */ +T2NServerBase::T2NServerBase( ServerSocketBaseImplementationPtr server_port) +: m_server_port(server_port) +{ + SCOPETRACKER(); + // register our callback for new incoming conncetions. + server_port->setNewConnectionBaseCallback( + boost::bind(&T2NServerBase::newConnectionSlot, this, _1) + ); +} // eo T2NServerBase::T2NServerBase(ServerSocketBaseImplementationPtr) + + +/** + * @brief destructor. + * + */ +T2NServerBase::~T2NServerBase() +{ + SCOPETRACKER(); +} // eo T2NServerBase::~T2NServerBase() + + +/** + * @brief returns wether the server port is opened. + * + * @return @a true iff the server port is open. + */ +bool T2NServerBase::isOpen() +{ + return (m_server_port && m_server_port->opened()); +} // eo T2NServerBase + + + +/** + * @brief callback for the port server object when a new connection is established. + * + * @param io_ptr the (shared) pointer to the new connection. + */ +void T2NServerBase::newConnectionSlot(IOImplementationPtr io_ptr) +{ + SCOPETRACKER(); + add_connection( new T2NServerConnection( get_ptr_as< T2NServerBase >(), io_ptr, get_default_timeout() ) ); +} // eo T2NServerBase::newConnectionSlot(IOImplementationPtr) + + +/** + * @brief try to fill the buffers of the managed connections. + * + * will be called by T2NServerBase::fill_buffer(). + * + * @return @a true if at least one connection buffer has new data. + */ +bool T2NServerBase::fill_connection_buffers() +{ + SCOPETRACKER(); + Backend::getBackend()->doOneStep(0); + bool result= false; + for(std::map::iterator it=connections.begin(); + it != connections.end(); + ++it) + { + T2NServerConnection *conn = dynamic_cast(it->second); + if (!conn) + { + if (it->second) + { + // react somehow if (it->second) is not NULL... + module_logger().error(HERE) << "illegal connection pointer"; + it->second->close(); + } + continue; + } + result= result or conn->fill_buffer(0); + } + return result; +} // eo T2NServerBase::fill_connection_buffers() + + +/** + * @brief fills the connection buffers. + * + * Uses the SimpleIo Backend to wait for new data. + * + * @param usec_timeout the maximum time period to wait for new data (in microseconds). + * 0 returns immediately, -1 waits until some event occurred. + * @param timeout_remaining ignored! + * @return @a true if new data for at least one connection arrived. + * + * @note since this method uses the SimpleIo backend, the timeout will have only milli second + * resolution. + */ +bool T2NServerBase::fill_buffer(long long usec_timeout, long long* timeout_remaining) +{ + SCOPETRACKER(); + int timeout= 0; + + if (usec_timeout<0) + { + timeout= -1; + } + else if (usec_timeout > 0) + { + long long msec_timeout= (usec_timeout + 500)/1000; + + if (msec_timeout >= INT_MAX) + { + timeout= INT_MAX; + } + else + { + timeout= (int)msec_timeout; + } + } + // not really.. but it shouldn't be used either... + if (timeout_remaining) *timeout_remaining= 0L; + + if (! fill_connection_buffers() && timeout>0) + { + bool had_activity= Backend::getBackend()->doOneStep( timeout ); + return fill_connection_buffers(); + } + return true; +} // to T2NServerBase::fill_buffer(long long,long long*) + + + +/* +** creator functions: +*/ + + +/** + * @brief creates a server object with unix domain server socket. + * @param path path of the unix domain socket. + * @param mode mode for the socket. + * @return shared pointer with the new server object; empty if none could be created.. + */ +T2NServerBasePtr createT2NUnixServerPort(const std::string& path, int mode) +{ + SCOPETRACKER(); + boost::shared_ptr< T2NUnixServer > result( new T2NUnixServer(path,mode) ); + if (!result->isOpen()) + { + module_logger().error(HERE) + << "failed to open unix domain server socket on \"" << path << "\""; + } + return result; +} // eo createT2NUnixServerPort(const std::string&,int) + + +/** + * @brief creates a client object connected to a server via unix daomain socket. + * @param path path of cthe unix domain socket. + * @return shared pointer with the new client object; empty if none could be created.. + */ +T2NClientConnectionPtr createT2NUnixClientConnection(const std::string& path) +{ + typedef IOExportWrapper< SimpleIo::UnixIOSocket > MyIo; + typedef boost::shared_ptr< MyIo > MyIoPtr; + SCOPETRACKER(); + MyIoPtr connection( new MyIo(path) ); + boost::shared_ptr< RealT2NClientConnection > result( new RealT2NClientConnection( connection ) ); + if (not result->isOpen()) + { + module_logger().error(HERE) + << "failed to open unix domain client socket on \"" << path << "\""; + return T2NClientConnectionPtr(); + } + return result; +} // eo createT2NUnixClientConnection(const std::string&) + + +} // eo namespace I2n diff --git a/glue_t2n/glue_t2n.hpp b/glue_t2n/glue_t2n.hpp new file mode 100644 index 0000000..24b3594 --- /dev/null +++ b/glue_t2n/glue_t2n.hpp @@ -0,0 +1,200 @@ +/** + * @file + * @brief the "glue" between libt2n and SimpleIo framework. + * + * contains our own server and cleint class which should fit into the asnychronous way of "SimpleIo". + * We use our own classes since the libt2n socket classes are made for synchronous operation + * which can lead to problems even if we import the connection fd's into "SimpleIo"... + * + * @author Reinhard Pfau \ + * + * @copyright © Copyright 2008 by Intra2net AG + * @license commercial + * @contact info@intra2net.com + * + * @todo support for TCP/IP connections. + */ + +#ifndef __CONND_GLUE_T2N_HPP__ +#define __CONND_GLUE_T2N_HPP__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace I2n +{ + + + +/** + * @brief specialized version of the libt2n client connection which fits into the SimpleIo framework. + * + */ +class T2NClientConnection +: public libt2n::client_connection +{ + public: + + T2NClientConnection(); + virtual ~T2NClientConnection(); + + bool isOpen(); + + bool reopen(bool force= false); + + + /* + ** overloaded methods from libt2n classes: + */ + + virtual void close(); + + protected: + + T2NClientConnection( SimpleIo::IOImplementationPtr connection ); + + void newDataSlot(); + + void eofSlot(); + + /* + ** overloaded methods from t2n classes: + */ + + virtual void real_write(const std::string& data); + + virtual bool fill_buffer(long long usec_timeout=-1,long long* usec_timeout_remaining=NULL); + + protected: + + SimpleIo::IOImplementationPtr m_real_connection; + + bool m_got_new_data; + +}; // eo class T2NClientConnection + + +typedef boost::shared_ptr< T2NClientConnection > T2NClientConnectionPtr; + + +class T2NServerBase; + +typedef boost::shared_ptr< T2NServerBase > T2NServerBasePtr; +typedef boost::weak_ptr< T2NServerBase > T2NServerBaseWeakPtr; + +/** + * @brief specialized version of the libt2n server connection which fits into the SimpleIo framework. + * + */ +class T2NServerConnection +: public libt2n::server_connection +{ + friend class T2NServerBase; + public: + + T2NServerConnection(); + virtual ~T2NServerConnection(); + + + /* + ** overloaded methods from libt2n classes: + */ + + virtual void close(); + + protected: + + T2NServerConnection( + T2NServerBasePtr server, + SimpleIo::IOImplementationPtr connection, + int timeout); + + void newDataSlot(); + + void eofSlot(); + + /* + ** overloaded methods from t2n classes: + */ + + virtual void real_write(const std::string& data); + + virtual bool fill_buffer(long long usec_timeout=-1,long long* usec_timeout_remaining=NULL); + + protected: + + SimpleIo::IOImplementationPtr m_real_connection; + T2NServerBaseWeakPtr m_server_weak_ptr; + + bool m_got_new_data; + +}; // eo class T2NServerConnection + + + +/** + * @brief base server class for handling server ports for libt2n. + * + * Needs to be derived for the real type of connection (unix, IPv4, etc.). + * + * Does all necessary connection handling and realizes the abstract methods from + * the libt2n::server class. + */ +class T2NServerBase +: public libt2n::server +, virtual public SharedBase +{ + public: + virtual ~T2NServerBase(); + + bool isOpen(); + + /* + ** overloaded methods from t2n classes: + */ + + virtual bool fill_buffer(long long usec_timeout=-1, long long* timeout_remaining=NULL); + + public: + + boost::signal< void() > m_signal_client_got_new_data; + + protected: + + T2NServerBase( SimpleIo::ServerSocketBaseImplementationPtr server_port); + + void newConnectionSlot(SimpleIo::IOImplementationPtr io_ptr); + + /* + ** overloaded methods from t2n classes: + */ + + virtual bool fill_connection_buffers(void); + + + protected: + + SimpleIo::ServerSocketBaseImplementationPtr m_server_port; + +}; // eo T2NServerBase + + +typedef boost::shared_ptr< T2NServerBase > T2NServerBasePtr; + + +T2NServerBasePtr createT2NUnixServerPort(const std::string& path, int mode= 0600); + +T2NClientConnectionPtr createT2NUnixClientConnection(const std::string& path); + + +} // eo namespace I2n + +#endif diff --git a/glue_t2n/libsimpleio_t2n.pc.in b/glue_t2n/libsimpleio_t2n.pc.in new file mode 100644 index 0000000..44ac70b --- /dev/null +++ b/glue_t2n/libsimpleio_t2n.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libsimpleio_t2n +Description: t2n glue for libsimpleio +Version: @VERSION@ +Requires: libsimpleio libt2n +Libs: -L${libdir} -lsimpleio_t2n +Cflags: -I${includedir} diff --git a/libsimpleio.spec b/libsimpleio.spec index 699bf3e..4c83b29 100644 --- a/libsimpleio.spec +++ b/libsimpleio.spec @@ -12,6 +12,7 @@ Requires: libi2ncommon >= 1.0 Requires: boost >= 1.32.0 BuildPrereq: libtool BuildRequires: boost-devel >= 1.32.0 +BuildRequires: libt2n-devel >= 0.4 %description @@ -26,7 +27,27 @@ Requires: boost-devel >= 1.32.0 %description devel -library with asynchronous io functionality for Intra2net programs +development files for library with asynchronous io functionality for Intra2net programs + + +%package t2n +Summary: glue library for using t2n with libsimpleio +Group: Intranator +Requires: libt2n >= 0.4 + +%description t2n +glue lib for using t2n with simpleio. + + +%package t2n-devel +Summary: glue library for using t2n with libsimpleio +Group: Intranator/Development +Requires: libt2n-devel >= 0.4 + +%description t2n-devel +development files for glue lib for using t2n with simpleio. + + %prep %setup -q @@ -55,6 +76,18 @@ rm -fr $RPM_BUILD_ROOT %files devel %defattr(-,root,root) -%{prefix}/lib/*.*a* -%{prefix}/lib/pkgconfig/*.pc -%{prefix}/include/ +%{prefix}/lib/libsimpleio.*a* +%{prefix}/lib/pkgconfig/libsimpleio.pc +%{prefix}/include/simpleio*.hpp + +%files t2n +%defattr(-,root,root) +%doc LICENSE +%{prefix}/lib/libsimpleio_t2n.so* + +%files t2n-devel +%defattr(-,root,root) +%{prefix}/lib/libsimpleio_t2n.*a* +%{prefix}/lib/pkgconfig/libsimpleio_t2n.pc +%{prefix}/include/glue_t2n*.hpp + diff --git a/unittest/test_simpleio_basics.cpp b/unittest/test_simpleio_basics.cpp index 1adff2f..66c03bb 100644 --- a/unittest/test_simpleio_basics.cpp +++ b/unittest/test_simpleio_basics.cpp @@ -689,7 +689,7 @@ class TestSimpleioBasics : public TestFixture for(int i=20; i-->0 && proc.processState() != ProcessState::stopped;) { - backend->doOneStep(10); + backend->doOneStep(15); } CPPUNIT_ASSERT_EQUAL( ProcessState(ProcessState::stopped), proc.processState() ); @@ -715,7 +715,7 @@ class TestSimpleioBasics : public TestFixture CPPUNIT_ASSERT_EQUAL(true, res); for(int i=20; i-->0 && proc.processState() != ProcessState::stopped;) { - backend->doOneStep(10); + backend->doOneStep(15); } CPPUNIT_ASSERT_EQUAL( ProcessState(ProcessState::stopped), proc.processState() ); -- 1.7.1