Гибберши от кода сервера ASIO SSL после первого сообщения - PullRequest
0 голосов
/ 10 марта 2012

Я пытаюсь написать асинхронный сервер на основе SSL, используя пример кода Boost ASIO из здесь .

Я получаю первое сообщение и его ответ правильно на стороне клиента. Затем я отправляю второе сообщение, которое нормально принимается на сервере, однако, когда ответ отправляется клиенту. Это похоже на бред.

Я загрузил код сервера в pastebin . Также найдите его ниже:

// 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();
  }

Может кто-нибудь указать мне на то, что здесь делается неправильно?

Обновление : проблема решена, как отмечено мной в комментарии. Эта проблема была точно такой же, как и у другого старого вопроса относительно stackoverflow.

1 Ответ

2 голосов
/ 10 марта 2012

Ваш код не распознает, что boost::asio::buffer является только оболочкой для объектов , из которых он был построен.Здесь (в Connection::sendResponse):

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

Вы создали буфер из (вероятно) временного объекта, который был уничтожен до того, как был использован boost::asio::async_write.

Документация Boost.Asio, в частности, сообщает вам об этом в параграфе "Недействительность буфера"

Для перегрузок boost :: asio :: bufferкоторые принимают аргумент типа std :: string, возвращенные объекты буфера признаются недействительными в соответствии с правилами, определенными для признания недействительными ссылок, указателей и итераторов, ссылающихся на элементы последовательности (C ++ Std, 21.3).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...