Gibberish procedente del código del servidor SSL ASIO después del primer mensaje

I'm trying to write a SSL-based async server using Boost ASIO example code from aquí.

I get the first message and its response correctly at the client side. Then, I send a second message which is received fine at the server, however when the response is sent to client. It comes as some gibberish.

I have uploaded the server code to pastebin. Also, find it below:

// file  -  Server.h
  class Server
  {
  public:
    explicit Server(const std::string &address,
               int port,
               std::size_t threadPoolSize);

    // run the io_service loop
    void run();

    // stop the server
    void stop();

  private:
    //handle async accept operation
    void handleAccept(const boost::system::error_code &e);

    // number of threads in thread pool
    std::size_t _threadPoolSize;

    // the io_service
    boost::asio::io_service _ioService;

    // acceptor to listen for incoming connections
    boost::asio::ip::tcp::acceptor _acceptor;

    std::string get_password()
    {
      return "password";
    }

    // ssl context
    boost::asio::ssl::context _context;    
    ConnectionPtr _connection;

  };

//////////////////////////////////////////////////////////////////////////
// file  -  Server.cpp
//////////////////////////////////////////////////////////////////////////
  Server::Server(const std::string& address,
               int port,
               std::size_t threadPoolSize)
    : _threadPoolSize(threadPoolSize),
      _acceptor(_ioService),
      _context(_ioService, boost::asio::ssl::context::sslv23),
      _connection()
  {
    try {
      DEBUG_2("Starting server on port: ", port);
      boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);
      _acceptor.open(endpoint.protocol());
      _acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
      _acceptor.bind(endpoint);
      _acceptor.listen();
      _context.set_options(
        boost::asio::ssl::context::default_workarounds
        | boost::asio::ssl::context::no_sslv2
        | boost::asio::ssl::context::single_dh_use);
      _context.set_password_callback(boost::bind(&Server::get_password, this));
      _context.use_certificate_chain_file("./demoCA/cacert.pem");
      _context.use_private_key_file("./demoCA/private/cakey.pem", 
                                    boost::asio::ssl::context::pem);
      // _context.use_tmp_dh_file("dh512.pem");
      _connection.reset(new CclConnection(_ioService, _context));
      _acceptor.async_accept(_connection->socket(),
                             boost::bind(&Server::handleAccept, 
                                         this,
                                         boost::asio::placeholders::error));
    }
    catch(std::exception& e)
    {
      STD_EXCEPTION_MESSAGE;
      throw;
    }

  }

  void Server::run()
  {
    // Create a pool of threads to run all of the io_services.
    std::vector<boost::shared_ptr<boost::thread> > threads;
    for (std::size_t i = 0; i < _threadPoolSize; ++i)
    {
      boost::shared_ptr<boost::thread> 
    thread(new boost::thread(
         boost::bind(&boost::asio::io_service::run, 
                 &_ioService)
         )
      );
      threads.push_back(thread);
    }

    // Wait for all threads in the pool to exit.
    for (std::size_t i = 0; i < threads.size(); ++i)
      threads[i]->join();
  }

  void Server::stop()
  {
    _ioService.stop();
  }

  void Server::handleAccept(const boost::system::error_code& e)
  {
    if (!e)
    {
      _connection->handshake();
      _connection.reset(new CclConnection(_ioService, _context));
      _acceptor.async_accept(_connection->socket(),
                 boost::bind(&Server::handleAccept, 
                     this,
                     boost::asio::placeholders::error));
    }
  }

////////////////////////////////////////////////////////////
// file  -  Connection.h
////////////////////////////////////////////////////////////

#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

  typedef boost::asio::ssl::stream< boost::asio::ip::tcp::socket >
    ssl_socket;

  class Connection 
    : public boost::enable_shared_from_this<Connection>
  {
  public:
    explicit Connection(boost::asio::io_service& io_service,
                           boost::asio::ssl::context& context);

    //get socket from the connection
    ssl_socket::lowest_layer_type& socket();

    // do an SSL handshake
    void handshake();

    //get socket from the connection
    boost::asio::io_service::strand& strand();

    // start first async operation
    void start();

    void sendResponse(const Response& response);

    void close();

    // get remote IP address for this connection
    std::string getIPAddress();

  private:
    void handleRead(const boost::system::error_code& e,
            std::size_t bytesTransferred);

    void handleWrite(const boost::system::error_code& e);

    boost::asio::io_service::strand _strand;

    ssl_socket _socket;

    void handleHandshake(const boost::system::error_code& e);

    boost::array<char, 8192> _buffer;
  };

  typedef boost::shared_ptr<Connection> ConnectionPtr;

///////////////////////////////////////////////////////////////
// File - Connection.cpp
///////////////////////////////////////////////////////////////


  Connection::Connection(boost::asio::io_service& io_service,
                               boost::asio::ssl::context& context)
    : _strand(io_service),
      _socket(io_service, context)
  {
  }

  ssl_socket::lowest_layer_type& Connection::socket()
  {
    return _socket.lowest_layer();
  }

  boost::asio::io_service::strand& Connection::strand()
  {
    return _strand;
  }

  void Connection::start()
  {
    _socket.async_read_some(boost::asio::buffer(_buffer),
                _strand.wrap(
                  boost::bind(
                &Connection::handleRead,
                shared_from_this(),
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred
                )
                  )
      );
  }

  void Connection::handshake()
  {
    std::cout << "doing ssl handshake" << std::endl;
    _socket.async_handshake(boost::asio::ssl::stream_base::server,
                            _strand.wrap(
                              boost::bind(
                                &Connection::handleHandshake,
                                shared_from_this(),
                                boost::asio::placeholders::error
                                )
                              )
      );
  }

  void Connection::handleHandshake(const boost::system::error_code& error)
  {
    if (!error)
    {
      _socket.async_read_some(boost::asio::buffer(_buffer),
                              _strand.wrap(
                                boost::bind(
                                  &Connection::handleRead,
                                  shared_from_this(),
                                  boost::asio::placeholders::error,
                                  boost::asio::placeholders::bytes_transferred
                                  )
                                )
        );
    }
    else
    {
      std::cout << "error occured: " << error.message();
      this->close();
    }
  }

  void Connection::handleRead(const boost::system::error_code& e,
                 std::size_t bytesTransferred)
  {
    if (!e) {

      // handle read data
      this->start();
    }
    else {
      this->close();
    }
  }

  void Connection::handleWrite(const boost::system::error_code& e)
  {
    if (!e) {
       this->start();
    }
    else {
      this->close();
    }
  }

  void Connection::sendResponse(const Response& response)
  {
    boost::asio::async_write(_socket,
                             boost::asio::buffer(convertToString(response)),
                             _strand.wrap(
                               boost::bind(
                                 &Connection::handleWrite,
                                 shared_from_this(),
                                 boost::asio::placeholders::error
                                 )
                               )
      );

  }

  void Connection::close()
  {
    boost::system::error_code ignoredCode;
    socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both,
                     ignoredCode);
  }

  std::string Connection::getIPAddress()
  {
    return socket().remote_endpoint().address().to_string();
  }

Can someone point me out as to what is being done wrongly here?

Noticias: The issue is resolved as noted by me in the comment. The issue was exactly similar to another vieja pregunta en stackoverflow.

preguntado el 10 de marzo de 12 a las 12:03

Have you checked (for example with Wireshark), that the message comes out of the server garbled and it is not a client fault? -

No, I have not tried. But, assuming that the that SSL is involved, I guess I will not be able to read the packets. Also, the code works fine if I remove the SSL completely. -

I haven't used Wireshark for SSL, but this might be useful: wiki.wireshark.org/SSL -

please post your code in the question, not on an external website such as pastebin. -

yup, got the same issue ;-) However since I have asked this question on stack overflow, I had to revamp my implementation to not interleave async_writes... My advice to you it to pass through message queue. -

1 Respuestas

Your code doesn't recognize, that boost::asio::buffer es solo el wrapper for objects from which it was constructed. Here (in Connection::sendResponse):

boost::asio::buffer(convertToString(response))

You created buffer out of a (probably) temporary object, which was destroyed before it was used by boost::asio::async_write.

Boost.Asio documentation specifically tells you about that en el párrafo "Buffer invalidation"

For the boost::asio::buffer overloads that accept an argument of type std::string, the buffer objects returned are invalidated according to the rules defined for invalidation of references, pointers and iterators referring to elements of the sequence (C++ Std, 21.3).

respondido 10 mar '12, 13:03

The code works fine if I remove the SSL stuff (context/ssl stream sockets etc) from the server. I do not think this is a problem here. - Lazylabs

This is an undefined behaviour. It can work sometimes. One of the messages garbled and one which is not, suggest, that your problem is indeed, some kind of UB. - Rafael Rawicki

Thanks for the pointer, I'll surely try changing this. Can you see any problem with the handshake here or anything like that? - Lazylabs

Hay un relacionado pregunta on stackoverflow. The issue was exactly the same. The writes were getting interleaved. The problem is now solved by implementing the reference counted buffer example as noted in the comment there by user @Hasturkun. - Lazylabs

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.