c++ - boost::asio read on socket to server blocks all incoming connection on client socket to be accepted -


i'm quite new boost::asio, writing http proxy (at moment testing on windows 7, boost 1.52.0 ). faced behavior don't understand please me it.

i'm using synchronios functions in current implementation. here server class:

#include "server.h"  namespace proxy {  sync_accept_server::sync_accept_server(const std::string& address, int port)     : _io_service(),      _acceptor(_io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port )),      _connection_id(0),      _new_connection() {     _acceptor.set_option(boost::asio::ip::tcp::no_delay(true)); }  void  sync_accept_server::start_accept() {      boost::system::error_code error;      // wait incoming connections     (;;) {         // create new connection         //_new_connection.reset(new connection(_p_io_service_pool->get_io_service(), ++_connection_id));         _new_connection.reset(new sync_connection(++_connection_id));          std::cout << "start waiting incoming connection" << std::endl;         _acceptor.accept(_new_connection->get_socket(), error);          if ( !error ) {             // create new thread             boost::thread new_thread(boost::bind(&sync_connection::start, _new_connection));             new_thread.detach();              //_new_connection->start();             std::cout << " new connection started, id: " << _connection_id << std::endl;         }         else {             std::cout << "error during incoming connection acceptance: " << error.message();         }      } }  } // namespace proxy 

here connection class reads headers browser, setting connection server, sends data server host, reads response , write data browser

#include <boost/assert.hpp> #include <boost/lexical_cast.hpp>  #include "sync_connection.h"  namespace {  std::string streambuf_to_string(boost::asio::streambuf &buf) {     std::ostringstream string_stream;      string_stream << &buf;      return std::string(string_stream.str()); }  } // anonym namespace  namespace proxy {  sync_connection::sync_connection(int id)     : _io_service(),     _server_io_service(),      _bsocket(_io_service),      _bbuffer(),      _ssocket(_server_io_service),      _sbuffer(),      _resolver(_server_io_service),      _streambuf(),      _headers(),      _content_length(-1),      _was_read(0),      _id(id),      _new_url(),      end_sign("\r\n\r\n") {     std::cout << "connection created, id: " << _id << std::endl; }  void sync_connection::start() {     boost::system::error_code error;      // read headers browser socket     // note functoin read more data return number of bytes , including end_sign     std::size_t len = boost::asio::read_until(_bsocket, _streambuf, end_sign, error);      boost_assert(!error);      // conver sream buf string - parse     _headers = streambuf_to_string(_streambuf);      // parse headers     _request.feed(_headers.c_str(), len);      // start connect server     start_connect(); }  void sync_connection::start_connect() {     // parse url     http::url url(_request.url());     std::string port = url.port().empty() ? "80" : url.port();     std::string server = url.host();      // build new url     _new_url = url.path();     std::string query = url.query();     if ( !query.empty() ) {         _new_url += ( "?" + query );     }      // host has '/' sign @ begining of string might cos     // connection troubles     server = server.substr(1, server.npos);      boost_assert(!server.empty());     if ( server.empty() ) {         return;     }      std::cout << _id << " server: " << server << std::endl;      boost::system::error_code error;      // create query able resolve hostname ip , port     boost::asio::ip::tcp::resolver::query resolver_query(server, port);     // resolve list of enpoints     boost::asio::ip::tcp::resolver::iterator endpoint_iterator = _resolver.resolve(resolver_query, error);      boost_assert(!error);      // till not connected ot out of enpoints     bool is_connected = false;     while ( endpoint_iterator != boost::asio::ip::tcp::resolver::iterator() && !is_connected ) {         // let's try connect here         _ssocket.connect(*endpoint_iterator, error);          //( error ) ? ( ++endpoint_iterator ) : ( is_connected = true );         if ( error ) {             std::cout << _id << " error occurs: " << error.message() << " try new endpoint" << std::endl;             ++endpoint_iterator;         } else {             is_connected = true;         }     }      // raise exception in case did not manage connect server     if ( !is_connected ) {         std::cout << _id << " did not manage connect server, error: " << error.message() << std::endl;         boost_assert(false);     }      else {         std::cout << _id << " connected now!" << std::endl;         _ssocket.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));         start_write_to_server();     }  }  void sync_connection::start_write_to_server() {     // prepare request send server     std::string _proxy_request = _request.method_name();     _proxy_request += " ";     _proxy_request += _new_url;     _proxy_request += " http/";     _proxy_request += "1.1"; // todo - have protocol version requiest     _proxy_request += "\r\n";     // end of request line     // other headers should same in browser request     _proxy_request += _headers;      boost::system::error_code error;     // can send data     boost::asio::write(_ssocket, boost::asio::buffer(_proxy_request), error);      boost_assert_msg(!error, error.message().c_str());      _headers.clear();      // read response     start_read_from_server(); }  void sync_connection::start_read_from_server() {     // lets read headers @ begining     // clean streambuf since contain end_sign     _streambuf.consume(_streambuf.size());      boost::system::error_code error;     std::size_t len = boost::asio::read_until(_ssocket, _streambuf, end_sign, error);      boost_assert_msg(!error, error.message().c_str());      // headers     _headers = streambuf_to_string(_streambuf);      boost_assert_msg(!_headers.empty(), "empty response server, went wrong");      // parse response server     _response.feed(_headers.c_str(), len);      std::cout << "headers:\n" << _headers << std::endl;      // check content-length header     if ( _response.has_header("content-length") ) {         std::cout << _id << " content-length present" << std::endl;         _content_length = boost::lexical_cast<int>(_response.header("content-length"));     }      std::cout << _id << " content length " << _response.has_header("content-length") << std::endl;      // since read_until read more data till end_sign     // need calculate how many bytes of body read      // if there bunch of data after end_sign     if ( len < _headers.size() ) {         _was_read = _headers.size() - len;     }      start_write_to_browser(); }  void sync_connection::start_write_to_browser() {     // write response browser     boost::system::error_code error_server;     boost::system::error_code error_browser;     boost::asio::write(_bsocket, boost::asio::buffer(_headers), error_browser);      boost_assert_msg(!error_browser, error_browser.message().c_str());      // need read server body ?     std::cout << _id << " content-lenght: " << _content_length << std::endl;     std::size_t len = 0;     if ( _content_length == -1 || _was_read < _content_length ) {          bool done = false;         {             std::cout << _id << " start reading" << std::endl;             len = _ssocket.read_some(boost::asio::buffer(_sbuffer), error_server);             _was_read += len;             std::cout << _id << " bytes read: " << _was_read << std::endl;              boost::asio::write(_bsocket, boost::asio::buffer(_sbuffer, len), error_browser);              boost_assert_msg( !error_browser, error_browser.message().c_str() );             if ( error_server ) {                 std::cout << _id << "error, stop reading: " << error_server.message() << std::endl;                 break;             }              std::cout << _id << " data written browser" << std::endl;         } while ( _content_length == -1 || _was_read < _content_length );      }      std::cout << _id << " done connection, close sockets" << std::endl;     shutdown(); }  void sync_connection::shutdown() {     _ssocket.close();     _bsocket.close(); }  } // namespace proxy 

the problem when content-length not present in server response ( chunked transfer encoding ) - in case don't know how many data should read browser, , call read_some method when there no more data on socket. call hangs ~10-15 sec till connection closed server (eof). in general i'm fine behavior.

but problem last read_some call on server socket blocks new incoming connection browser accepted acceptor. new connections not accepted till read_some on server socket return eof.

i've done lot of experements already, , interesting thing same blocking call on browser socket not block other incoming connections accepted. if call

_bsocket.read_some(...)

and there no data read , server keeping connection - new incoming connections accepted fine.

i can't understand why work in way, don't have relations between server , browser socket in implementation, initialized different io_service objects.

is there wrong in implementation? i'm facing same issue async functions. tips helpful.


Comments

Popular posts from this blog

SPSS keyboard combination alters encoding -

Add new record to the table by click on the button in Microsoft Access -

javascript - jQuery .height() return 0 when visible but non-0 when hidden -