diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..06f69b0 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,82 @@ +################ +# project config +################ + +# C++ project +language: cpp + +dist: trusty +sudo: required +group: edge + + +################ +# build matrix +################ + +matrix: + include: + + ################ + # Linux / GCC + ################ + + - os: linux + compiler: gcc + env: COMPILER=g++-5 + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-5', 'ninja-build'] + + - os: linux + compiler: gcc + env: COMPILER=g++-6 + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-6', 'ninja-build'] + + - os: linux + compiler: gcc + env: COMPILER=g++-7 + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-7', 'ninja-build'] + + ################ + # Linux / Clang + ################ + + - os: linux + compiler: clang + env: COMPILER=clang++-4.0 + addons: + apt: + sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-4.0'] + packages: ['clang-4.0', 'ninja-build'] + + - os: linux + compiler: clang + env: COMPILER=clang++-5.0 + addons: + apt: + sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0'] + packages: ['clang-5.0', 'ninja-build'] + +################ +# build / test +################ + +script: + + # show OS/compiler version + - uname -a + - $CXX --version + + # compile and execute unit tests + - mkdir -p build.release && cd build.release + - cmake .. ${CMAKE_OPTIONS} -GNinja && cmake --build . --config Release + - cd .. + diff --git a/README.md b/README.md index 632e9c0..8fc0303 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ sure that your compiler is up-to-date and supports C++11. **Note for the reader:** This readme file has a peculiar structure. We start explaining the pure and hard core low level interface in which you have to take care of opening socket connections yourself. In reality, you probably want -to use the simpler TCP interface that is being described later on. +to use the simpler TCP interface that is being described [later on](#tcp-connections). ABOUT diff --git a/include/amqpcpp/libboostasio.h b/include/amqpcpp/libboostasio.h index 3a49f03..3f80b89 100644 --- a/include/amqpcpp/libboostasio.h +++ b/include/amqpcpp/libboostasio.h @@ -26,35 +26,12 @@ #include #include - -/////////////////////////////////////////////////////////////////// -#define STRAND_SOCKET_HANDLER(_fn) \ -[fn = _fn, strand = _strand](const boost::system::error_code &ec, \ - const std::size_t bytes_transferred) \ -{ \ - const std::shared_ptr apStrand = strand.lock(); \ - if (!apStrand) \ - { \ - fn(boost::system::errc::make_error_code(boost::system::errc::operation_canceled),std::size_t{0}); \ - return; \ - } \ - \ - apStrand->dispatch(boost::bind(fn,ec,bytes_transferred)); \ -} - -/////////////////////////////////////////////////////////////////// -#define STRAND_TIMER_HANDLER(_fn) \ -[fn = _fn, strand = _strand](const boost::system::error_code &ec) \ -{ \ - const std::shared_ptr apStrand = strand.lock(); \ - if (!apStrand) \ - { \ - fn(boost::system::errc::make_error_code(boost::system::errc::operation_canceled)); \ - return; \ - } \ - \ - apStrand->dispatch(boost::bind(fn,ec)); \ -} +// C++17 has 'weak_from_this()' support. +#if __cplusplus >= 201701L +#define PTR_FROM_THIS weak_from_this +#else +#define PTR_FROM_THIS shared_from_this +#endif /** * Set up namespace @@ -120,6 +97,64 @@ private: */ bool _write_pending{false}; + using handler_cb = boost::function; + using io_handler = boost::function; + + /** + * Builds a io handler callback that executes the io callback in a strand. + * @param io_handler The handler callback to dispatch + * @return handler_cb A function wrapping the execution of the handler function in a io_service::strand. + */ + handler_cb get_dispatch_wrapper(io_handler fn) + { + return [fn, strand = _strand](const boost::system::error_code &ec, const std::size_t bytes_transferred) + { + const std::shared_ptr apStrand = strand.lock(); + if (!apStrand) + { + fn(boost::system::errc::make_error_code(boost::system::errc::operation_canceled), std::size_t{0}); + return; + } + apStrand->dispatch(boost::bind(fn, ec, bytes_transferred)); + }; + } + + /** + * Binds and returns a read handler for the io operation. + * @param connection The connection being watched. + * @param fd The file descripter being watched. + * @return handler callback + */ + handler_cb get_read_handler(TcpConnection *const connection, const int fd) + { + auto fn = boost::bind(&Watcher::read_handler, + this, + _1, + _2, + PTR_FROM_THIS(), + connection, + fd); + return get_dispatch_wrapper(fn); + } + + /** + * Binds and returns a read handler for the io operation. + * @param connection The connection being watched. + * @param fd The file descripter being watched. + * @return handler callback + */ + handler_cb get_write_handler(TcpConnection *const connection, const int fd) + { + auto fn = boost::bind(&Watcher::write_handler, + this, + _1, + _2, + PTR_FROM_THIS(), + connection, + fd); + return get_dispatch_wrapper(fn); + } + /** * Handler method that is called by boost's io_service when the socket pumps a read event. * @param ec The status of the callback. @@ -147,21 +182,10 @@ private: connection->process(fd, AMQP::readable); _read_pending = true; - - _socket.async_read_some(boost::asio::null_buffers(), - STRAND_SOCKET_HANDLER( - boost::bind(&Watcher::read_handler, - this, - boost::placeholders::_1, - boost::placeholders::_2, -// C++17 has 'weak_from_this()' support. -#if __cplusplus >= 201701L - weak_from_this(), -#else - shared_from_this(), -#endif - connection, - fd))); + + _socket.async_read_some( + boost::asio::null_buffers(), + get_read_handler(connection, fd)); } } @@ -193,20 +217,9 @@ private: _write_pending = true; - _socket.async_write_some(boost::asio::null_buffers(), - STRAND_SOCKET_HANDLER( - boost::bind(&Watcher::write_handler, - this, - boost::placeholders::_1, - boost::placeholders::_2, -// C++17 has 'weak_from_this()' support. -#if __cplusplus >= 201701L - weak_from_this(), -#else - shared_from_this(), -#endif - connection, - fd))); + _socket.async_write_some( + boost::asio::null_buffers(), + get_write_handler(connection, fd)); } } @@ -262,20 +275,9 @@ private: { _read_pending = true; - _socket.async_read_some(boost::asio::null_buffers(), - STRAND_SOCKET_HANDLER( - boost::bind(&Watcher::read_handler, - this, - boost::placeholders::_1, - boost::placeholders::_2, -// C++17 has 'weak_from_this()' support. -#if __cplusplus >= 201701L - weak_from_this(), -#else - shared_from_this(), -#endif - connection, - fd))); + _socket.async_read_some( + boost::asio::null_buffers(), + get_read_handler(connection, fd)); } // 2. Handle writes? @@ -286,20 +288,9 @@ private: { _write_pending = true; - _socket.async_write_some(boost::asio::null_buffers(), - STRAND_SOCKET_HANDLER( - boost::bind(&Watcher::write_handler, - this, - boost::placeholders::_1, - boost::placeholders::_2, -// C++17 has 'weak_from_this()' support. -#if __cplusplus >= 201701L - weak_from_this(), -#else - shared_from_this(), -#endif - connection, - fd))); + _socket.async_write_some( + boost::asio::null_buffers(), + get_write_handler(connection, fd)); } } }; @@ -329,11 +320,39 @@ private: */ boost::asio::deadline_timer _timer; + using handler_fn = boost::function; + /** + * Binds and returns a lamba function handler for the io operation. + * @param connection The connection being watched. + * @param timeout The file descripter being watched. + * @return handler callback + */ + handler_fn get_handler(TcpConnection *const connection, const uint16_t timeout) + { + auto fn = boost::bind(&Timer::timeout, + this, + _1, + PTR_FROM_THIS(), + connection, + timeout); + return [fn, strand = _strand](const boost::system::error_code &ec) + { + const std::shared_ptr apStrand = strand.lock(); + if (!apStrand) + { + fn(boost::system::errc::make_error_code(boost::system::errc::operation_canceled)); + return; + } + apStrand->dispatch(boost::bind(fn, ec)); + }; + } + /** * Callback method that is called by libev when the timer expires + * @param ec error code returned from loop * @param loop The loop in which the event was triggered - * @param timer Internal timer object - * @param revents The events that triggered this call + * @param connection + * @param timeout */ void timeout(const boost::system::error_code &ec, std::weak_ptr awpThis, @@ -357,18 +376,7 @@ private: _timer.expires_at(_timer.expires_at() + boost::posix_time::seconds(timeout)); // Posts the timer event - _timer.async_wait(STRAND_TIMER_HANDLER( - boost::bind(&Timer::timeout, - this, - boost::placeholders::_1, -// C++17 has 'weak_from_this()' support. -#if __cplusplus >= 201701L - weak_from_this(), -#else - shared_from_this(), -#endif - connection, - timeout))); + _timer.async_wait(get_handler(connection, timeout)); } } @@ -423,19 +431,11 @@ private: // stop timer in case it was already set stop(); + // Reschedule the timer for the future: _timer.expires_from_now(boost::posix_time::seconds(timeout)); - _timer.async_wait(STRAND_TIMER_HANDLER( - boost::bind(&Timer::timeout, - this, - boost::placeholders::_1, -// C++17 has 'weak_from_this()' support. -#if __cplusplus >= 201701L - weak_from_this(), -#else - shared_from_this(), -#endif - connection, - timeout))); + + // Posts the timer event + _timer.async_wait(get_handler(connection, timeout)); } }; diff --git a/src/connectionstartframe.h b/src/connectionstartframe.h index f11c69b..272384e 100644 --- a/src/connectionstartframe.h +++ b/src/connectionstartframe.h @@ -196,8 +196,8 @@ public: properties["product"] = "Copernica AMQP library"; properties["version"] = "Unknown"; properties["platform"] = "Unknown"; - properties["copyright"] = "Copyright 2015 Copernica BV"; - properties["information"] = "http://www.copernica.com"; + properties["copyright"] = "Copyright 2015 - 2018 Copernica BV"; + properties["information"] = "https://www.copernica.com"; properties["capabilities"] = capabilities; // move connection to handshake mode diff --git a/tests/Makefile b/tests/Makefile index b5bf2f3..ee7f59c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ -CPP = g++ +CPP = g++ CPPFLAGS = -Wall -c -I. -O2 -flto -std=c++11 -g -LD = g++ +LD = g++ LDFLAGS = -lamqpcpp -lcopernica_event -lcopernica_network -lev RESULT = a.out SOURCES = $(wildcard *.cpp) diff --git a/tests/libboostasio.cpp b/tests/libboostasio.cpp index ee9555c..c71c9e3 100644 --- a/tests/libboostasio.cpp +++ b/tests/libboostasio.cpp @@ -5,7 +5,7 @@ * * @author Gavin Smith * - * Compile with g++ libboostasio.cpp -o boost_test -lpthread -lboost_system -lamqpcpp + * Compile with g++ -std=c++14 libboostasio.cpp -o boost_test -lpthread -lboost_system -lamqpcpp */ /**