#define _WIN32_WINNT 0x0501 #include #include #include #include #include #include #include #include #include #include #include #include namespace Asio = boost::asio; ////////////////////////////// // Test for timer cancel ////////////////////////////// void handleTimer( boost::system::error_code error ) { if( error ) { std::cout << "handleTimer: error: " << error.message() << std::endl; } else { std::cout << "handleTimer: ok" << std::endl; } } void testErrorCancelTimer( Asio::io_service& ioService, boost::scoped_ptr< Asio::steady_timer >& timer ) { std::cout << "testErrorCancelTimer: start" << std::endl; timer->expires_from_now( boost::chrono::seconds( 6 ) ); // Async wait to be canceled due to a simulated error below. timer->async_wait( boost::bind( &handleTimer, _1 ) ); try { // Simulate error. throw std::runtime_error( "test-error "); } catch( std::exception& e ) { std::cout << "testErrorCancelTimer: error: " << e.what() << std::endl; // How to cancel timer in a no-throw (guaranteed) way? #if 1 // Cancel may throw or give an error. boost::system::error_code cancelError; timer->cancel( cancelError ); #elif 0 // Is deleting the timer safe? // If it does the same thing as cancel - why isn't cancel no-throw? timer.reset(); #endif } } ////////////////////////////// // Test for socket read cancel ////////////////////////////// void handleRead( boost::scoped_ptr< Asio::ip::tcp::socket >& readSocket, boost::shared_ptr< char > /* buffer */, boost::system::error_code error, std::size_t bytesTransferred ) { if( error ) { std::cout << "handleRead: error: " << error.message() << std::endl; } else { std::cout << "handleRead: ok. socket: " << readSocket << std::endl; } } void testErrorCancelRead( Asio::io_service& ioService, boost::scoped_ptr< Asio::ip::tcp::socket >& readSocket ) { std::cout << "testErrorCancelRead: start" << std::endl; // Blocking connect. readSocket->open( Asio::ip::tcp::v4() ); readSocket->connect( Asio::ip::tcp::endpoint( Asio::ip::address::from_string( "127.0.0.1" ), 12345 ) ); // Async read to be canceled due to a simulated error below. boost::shared_ptr< char > buffer( new char ); readSocket->async_receive( Asio::buffer( &*buffer, 1 ), boost::bind( &handleRead, boost::ref( readSocket), buffer, _1, _2 ) ); try { // Simulate error. throw std::runtime_error( "test-error "); } catch( std::exception& e ) { std::cout << "testErrorCancelRead: error: " << e.what() << std::endl; // How to cancel socket receive in a no-throw (guaranteed) way? #if 1 // Cancel may throw or give an error. boost::system::error_code cancelError; readSocket->cancel( cancelError ); #elif 0 // Close socket - again may give an error. boost::system::error_code closeError; readSocket->shutdown( Asio::ip::tcp::socket::shutdown_both, closeError ); readSocket->close( closeError ); #elif 0 // Is deleting the socket safe? // If it does the same thing as cancel - why isn't cancel no-throw? readSocket.reset(); #endif } } ////////////////////////////// // Test for socket write cancel ////////////////////////////// void handleWrite( boost::scoped_ptr< Asio::ip::tcp::socket >& writeSocket, boost::shared_ptr< std::vector< char > > /* buffer */, boost::system::error_code error ) { if( error ) { std::cout << "handleWrite: error: " << error.message() << std::endl; } else { std::cout << "handleWrite: ok. socket: " << writeSocket << std::endl; } } void testErrorCancelWrite( Asio::io_service& ioService, boost::scoped_ptr< Asio::ip::tcp::socket >& writeSocket ) { std::cout << "testErrorCancelWrite: start" << std::endl; // Blocking connect. writeSocket->open( Asio::ip::tcp::v4() ); writeSocket->connect( Asio::ip::tcp::endpoint( Asio::ip::address::from_string( "127.0.0.1" ), 12345 ) ); // Async write to be canceled due to a simulated error below.. boost::shared_ptr< std::vector< char > > buffer( new std::vector< char >( 1000000 ) ); Asio::async_write( *writeSocket, Asio::buffer( &( *buffer )[ 0 ], buffer->size() ), boost::bind( &handleWrite, boost::ref( writeSocket), buffer, _1 ) ); try { // Simulate error. throw std::runtime_error( "test-error "); } catch( std::exception& e ) { std::cout << "testErrorCancelWrite: error: " << e.what() << std::endl; // How to cancel socket async_write in a no-throw way? #if 0 // Cancel may throw or give an error. // Plus it doesn't cancel an async_write boost::system::error_code cancelError; writeSocket->cancel( cancelError ); #elif 1 // Close socket - again may give an error. boost::system::error_code closeError; writeSocket->shutdown( Asio::ip::tcp::socket::shutdown_both, closeError ); writeSocket->close( closeError ); #elif 0 // Is deleting the socket safe? // In this case (when used with a large async_write it leads to crash. writeSocket.reset(); #endif } } int main(void) { Asio::io_service ioService; boost::scoped_ptr< Asio::steady_timer > timer( new Asio::steady_timer( ioService ) ); Asio::ip::tcp::acceptor acceptor( ioService ); acceptor.open( Asio::ip::tcp::v4() ); acceptor.set_option( Asio::ip::tcp::acceptor::reuse_address( true ) ); acceptor.bind( Asio::ip::tcp::endpoint( Asio::ip::tcp::v4(), 12345 ) ); acceptor.listen( Asio::ip::tcp::acceptor::max_connections ); boost::scoped_ptr< Asio::ip::tcp::socket > readSocket( new Asio::ip::tcp::socket( ioService ) ); boost::scoped_ptr< Asio::ip::tcp::socket > writeSocket( new Asio::ip::tcp::socket( ioService ) ); // post the actual test-code to run within io_service::run() ioService.post( boost::bind( &testErrorCancelTimer, boost::ref( ioService ), boost::ref( timer ) ) ); ioService.post( boost::bind( &testErrorCancelRead, boost::ref( ioService ), boost::ref( readSocket ) ) ); ioService.post( boost::bind( &testErrorCancelWrite, boost::ref( ioService ), boost::ref( writeSocket ) ) ); bool run = true; while (run) { try { ioService.run(); run = false; } catch (std::exception& e) { std::cerr << "Run Error: " << e.what() << std::endl; } } return 0; }