pass asio socket to another class
I have two classes SslHandshake and SslRequest with according to names functionality. After client and server handshakes are done in the SslHandshake, I pass both sockets to SslRequest and start transferring data from server to client. 1. If I is not waiting for finishing of transferring, instance of SslHandshake will be destroyed automatically (in the ~SslHandshake I will destroy both socket objects and transferring in the SslRequest will be aborted). 2. If I start transferring with waiting, after a few iterations SslRequest::ReadSocketOut will be called successfully, but the readSocketHandle will not be called (so, will be called but with timeout error). So, I need to handshake in one class and transfer data into another class. How to prevent destroying instance of SslHandshake until data transferring will be done into SslRequest or how to fix socket reading without callback calling after a few iterations? void SslHandshake::HandshakeInHandle(const bSystem::error_code &error) { TRY { CHECK_BOOST_ERROR { LOG_MSG_DEBUG_KEYWORD(KEYWORD_INCOMING, << "Handshake done"); // --- Transfer with waiting of mutex //IoServicePtr servicePointer((IoService *)&m_SocketIn->get_io_service()); //boost::thread serviceThread(boost::bind(&IoService::IO_SERVICE_THREAD_VOID, servicePointer)); //SslRequest::SharedPtr sslRequest(new SslRequest(m_SocketIn, m_SocketOut)); //sslRequest->Transfer(); SslRequest::SocketPtr socketIn(m_SocketIn); SslRequest::SocketPtr socketOut(m_SocketOut); // --- Transfer with waiting of thread //IoServicePtr servicePointer((IoService *)&m_SocketIn->get_io_service()); //servicePointer->SessionIndex = IndexThis; //boost::thread serviceThread(boost::bind(&IoService::IO_SERVICE_THREAD_VOID, servicePointer)); //SslRequest::SharedPtr request = SslRequest::CreateInstance(m_SocketIn, m_SocketOut); //request->Transfer(); //serviceThread.join(); // --- Transfer with waiting of IO_SERVICE_THREAD_VOID IoServicePtr servicePointer((IoService *)&m_SocketIn->get_io_service()); servicePointer->SessionIndex = IndexThis; SslRequest::SharedPtr request = SslRequest::CreateInstance(/*m_SocketIn, m_SocketOut*/socketIn, socketOut INDEX_THIS_PASS); request->Transfer(); servicePointer->IO_SERVICE_THREAD_VOID(); } } CATCH_LOG_STD CATCH_LOG_ANY } void SslRequest::ReadSocketOut(TransferringBuffer &buffer, SimpleSocketCallback readSocketHandle) { bAsIO::async_read( *m_SocketOut, bAsIO::buffer(buffer), boost::bind( readSocketHandle, SHARED_FROM_THIS, baPlaceholders::error, baPlaceholders::bytes_transferred)); } -- View this message in context: http://boost.2283326.n4.nabble.com/pass-asio-socket-to-another-class-tp46700... Sent from the Boost - Users mailing list archive at Nabble.com.
On 11/12/2014 02:55, cap wrote:
1. If I is not waiting for finishing of transferring, instance of SslHandshake will be destroyed automatically (in the ~SslHandshake I will destroy both socket objects and transferring in the SslRequest will be aborted). 2. If I start transferring with waiting, after a few iterations SslRequest::ReadSocketOut will be called successfully, but the readSocketHandle will not be called (so, will be called but with timeout error).
So, I need to handshake in one class and transfer data into another class.
How to prevent destroying instance of SslHandshake until data transferring will be done into SslRequest or how to fix socket reading without callback calling after a few iterations?
From the code you posted, it looks like you need to go back to basics and understand how the Asio service threading model works. Have a closer look at the async examples -- the basic idea is that nothing happens without an io_service::run call being in progress on some thread. In many of the examples this is done by queuing up the initial operations to be performed first and then running the io_service on the main thread (which then returns once all the operations are completed), but it's more common in real code to have the io_service on a dedicated worker thread (with some io_service::work in scope to prevent it exiting when there's nothing to do) and queuing up operations as needed (though this way you need to be more careful about cross threaded operations). Either way works (they're both good in different cases), but what you should never do is to spin up a thread specifically for one operation.
Sorry, I've forgot to specify a /Listener/ class: void Listener::Init(void) { for (UINT i = 0; i < 10; ++i) { IoServicePtr service(new IoService()); m_PtrIoServices.push_back(service); m_WorkIoServices.push_back(IoService::work(*service)); m_Threads.create_thread(boost::bind(&IoService::IO_SERVICE_THREAD_VOID, service)); } } void Listener::Run(void) { Listener listenerHttp(httpPort, &HttpRequest::CreateInstance); Listener listenerSsl(sslPort, &SslHandshake::CreateInstance); m_Threads.join_all(); } So, I have the same source code for unsecured HTTP requests, the code works perfectly with /boost::asio::ip::tcp::socket/ but *boost::asio::ssl::streamboost::asio::ip::tcp::socket* sometime hangups. Also I've wrote small example from boost http://www.boost.org/doc/libs/1_56_0/doc/html/boost_asio/example/cpp03/ssl/c... : class client : public boost::enable_shared_from_this<client> { public: client( boost::asio::io_service& io_service, boost::asio::ssl::context& context, boost::asio::ip::tcp::resolver::iterator endpoint_iterator) : socket_(io_service, context), stand_(io_service) { socket_.set_verify_mode(boost::asio::ssl::verify_peer); socket_.set_verify_callback( boost::bind(&client::verify_certificate, this, _1, _2)); boost::asio::async_connect( socket_.lowest_layer(), endpoint_iterator, boost::bind( &client::handle_connect, this, boost::asio::placeholders::error)); } bool verify_certificate( bool preverified, boost::asio::ssl::verify_context& ctx) { return true; //preverified; } void handle_connect( const boost::system::error_code& error) { if (!error) { socket_.async_handshake( boost::asio::ssl::stream_base::client, stand_.wrap( boost::bind( &client::handle_handshake, this, boost::asio::placeholders::error))); } else { std::cout << "Connect failed: " << error.message() << "\n"; } } void handle_handshake( const boost::system::error_code& error) { if (!error) { memset(request_, 0, max_length); strcpy_s(request_, "GET https://www.google.com.ua/ HTTP/1.1"); size_t request_length = strlen(request_); boost::asio::async_write( socket_, boost::asio::buffer(request_, request_length), stand_.wrap( boost::bind( &client::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred))); } else { std::cout << "Handshake failed: " << error.message() << "\n"; } } void handle_write( const boost::system::error_code& error, size_t bytes_transferred) { if (!error) { boost::asio::async_read( socket_, boost::asio::buffer(reply_, bytes_transferred), stand_.wrap( boost::bind( &client::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred))); } else { std::cout << "Write failed: " << error.message() << "\n"; } } void handle_read( const boost::system::error_code& error, size_t bytes_transferred) { if (!error) { std::cout << "Reply: "; std::cout.write(reply_, bytes_transferred); std::cout << "\n"; } else { std::cout << "Read failed: " << error.message() << "\n"; } } private: boost::asio::ssl::streamboost::asio::ip::tcp::socket socket_; boost::asio::strand stand_; char request_[max_length]; char reply_[max_length]; }; void TestClient(void) { try { boost::asio::io_service io_service; boost::asio::ip::tcp::resolver resolver(io_service); boost::asio::ip::tcp::resolver::query query("www.google.com.ua", "443"); boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23); client c(io_service, ctx, iterator); io_service.run(); } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } } /boost::asio::async_read/ calls without errors but /handle_read/ never calls. boost 1.56.0, OpenSSL 1.0.1i, VisualStudio 2012 (v110), Windows 8.1 Example is launched from DLL. -- View this message in context: http://boost.2283326.n4.nabble.com/pass-asio-socket-to-another-class-tp46700... Sent from the Boost - Users mailing list archive at Nabble.com.
On 13/12/2014 05:00, cap wrote:
Sorry, I've forgot to specify a /Listener/ class:
void Listener::Init(void) { for (UINT i = 0; i < 10; ++i) { IoServicePtr service(new IoService()); m_PtrIoServices.push_back(service); m_WorkIoServices.push_back(IoService::work(*service)); m_Threads.create_thread(boost::bind(&IoService::IO_SERVICE_THREAD_VOID, service)); } }
Why are you creating multiple I/O services? Typically you should create a single io_service and 1-N threads calling io_service::run on that service.
void handle_handshake( const boost::system::error_code& error) { if (!error) { memset(request_, 0, max_length); strcpy_s(request_, "GET https://www.google.com.ua/ HTTP/1.1"); size_t request_length = strlen(request_);
After this completes your code immediately goes to read from the connection. HTTP servers will typically not send any reply data until you send a complete request -- which the above is not since it is missing several headers required by HTTP/1.1 and most importantly is missing the CRLFCRLF request terminator.
participants (2)
-
cap
-
Gavin Lambert