Boost.Asio:SSL服务器和客户端。服务器SIGSEGV和客户端短读错误

时间:2015-08-17 00:18:30

标签: c++ ssl boost boost-asio

我已经成功构建了Boost的SSL样本,并且我已经运行它们没有明显的问题。我使用HTTP服务器和SSL示例作为参考编写了自己的代码。当我运行我的代码时,我从客户端收到了这个错误:

Handshake failed. Error: short read

这来自我的服务器:

debug: ConnectionManager::ConnectionManager()
debug: Server::Server(boost::asio::io_service&, short unsigned int)
debug: std::__cxx11::string Server::HPasswordHandler() const
debug: void Server::StartAccept()
debug: Connection::Connection(boost::asio::io_service&, boost::asio::ssl::context&, ConnectionManager&)
debug: boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >::lowest_layer_type& Connection::Socket()
debug: void Server::HAccept(const boost::system::error_code&)
debug: void Connection::Start()
debug: void Server::StartAccept()
debug: Connection::Connection(boost::asio::io_service&, boost::asio::ssl::context&, ConnectionManager&)
debug: boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >::lowest_layer_type& Connection::Socket()
Segmentation fault

debug:是我尝试进行一些调试。当我连接到服务器时发生分段错误。

那你的想法是什么?

我的服务器代码:

#include <iostream>
#include <sstream>
#include <locale>
#include <string>
#include <set>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/thread.hpp>

inline void debug_msg(const std::string &instr) {
    std::string res = "debug: ";
    res += instr;
    res += "\n";
    std::cout << res;
    std::cout.flush(); // since I don't use std::endl
}

#if defined(DEBUG) && !defined(NDEBUG)
#define _func_debug_    debug_msg(__PRETTY_FUNCTION__);
#else
#define _func_debug_
#endif

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

class ConnectionManager;

class Connection :
    public boost::enable_shared_from_this<Connection> {
public:
    Connection(const Connection&) = delete;
    Connection &operator=(const Connection&) = delete;
    explicit Connection(
        boost::asio::io_service &io_service,
        boost::asio::ssl::context &context,
        ConnectionManager &connectionManager) :
        socket_(io_service, context),
        connectionManager_(connectionManager) {
        _func_debug_
    }
    ssl_socket_t::lowest_layer_type &Socket() {
        _func_debug_
        return socket_.lowest_layer();
    }
    void Start() {
        _func_debug_
        socket_.async_handshake(
                boost::asio::ssl::stream_base::server,
                boost::bind(&Connection::HHandshake,
                    this,
                    boost::asio::placeholders::error));
    }
    void Stop() {
        _func_debug_
        socket_.lowest_layer().cancel();
        socket_.shutdown();
        socket_.lowest_layer().close();
    }
protected:
    ssl_socket_t socket_;
    ConnectionManager &connectionManager_;
    boost::asio::streambuf readBuffer_;
    std::string message_;
    void HHandshake(const boost::system::error_code &error) {
        _func_debug_
        if (!error) {
            boost::asio::async_read_until(socket_, readBuffer_, '\0',
                boost::bind(&Connection::HReadUntil, this,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred));
        }
        else if (error != boost::asio::error::operation_aborted) {
            NotifyConnectionManagerToStop();
        }
    }
    void HReadUntil(
        const boost::system::error_code &error,
        size_t bytes_transferred) {
        _func_debug_
        if (!error) {
            std::string s;
            std::istream is(&readBuffer_);
            std::getline(is, s, '\0');
            std::cout << "Message: " << s << std::endl;
            message_ = "Server received your message!";
            message_ += std::string("", 1);
            boost::asio::async_write(socket_,
                boost::asio::buffer(message_, message_.size()),
                boost::bind(&Connection::HWrite, this,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred));
        }
        else if (error != boost::asio::error::operation_aborted) {
            // if operation is aborted, connection manager
            // already knows about it, since sockets
            // can be stopped only by connection manager
            NotifyConnectionManagerToStop();
        }
    }
    void HWrite(
        const boost::system::error_code &error,
        size_t bytes_transferred) {
        _func_debug_
        if (!error) {
            // nothing else to do.
        }
        else if (error != boost::asio::error::operation_aborted) {
            NotifyConnectionManagerToStop();
        }
    }
    void NotifyConnectionManagerToStop();
};

typedef boost::shared_ptr<Connection> Connection_ptr;

class ConnectionManager {
public:
    ConnectionManager(const ConnectionManager&) = delete;
    ConnectionManager &operator=(const ConnectionManager&) = delete;
    ConnectionManager() {
        _func_debug_
    }
    void Start(Connection_ptr connection) {
        _func_debug_
        connections_.insert(connection);
        connection->Start();
    }
    void Stop(Connection_ptr connection) {
        _func_debug_
        connections_.erase(connection);
        connection->Stop();
    }
    void StopAll() {
        _func_debug_
        for (auto connection : connections_)
            connection->Stop();
        connections_.clear();
    }
protected:
    std::set<Connection_ptr> connections_;
};

void Connection::NotifyConnectionManagerToStop() {
    _func_debug_
    connectionManager_.Stop(shared_from_this());
}

class Server {
public:
    Server(const Server &) = delete;
    Server &operator=(const Server &) = delete;

    Server(
        boost::asio::io_service &io_service,
        unsigned short port) :
        io_service_(io_service),
        acceptor_(io_service,
            boost::asio::ip::tcp::endpoint(
                boost::asio::ip::tcp::v4(), port)),
        context_(boost::asio::ssl::context::sslv23)
    {
        _func_debug_
        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::HPasswordHandler,
            this));
        context_.use_certificate_chain_file("server.crt");
        context_.use_private_key_file("server.key",
            boost::asio::ssl::context::pem);
        context_.use_tmp_dh_file("dh1024.pem");
        StartAccept();
    }
protected:
    boost::asio::io_service &io_service_;
    boost::asio::ip::tcp::acceptor acceptor_;
    boost::asio::ssl::context context_;
    ConnectionManager connection_manager_;
    Connection_ptr new_connection_;
    std::string HPasswordHandler() const {
        _func_debug_
        return "somehow return password";
    }
    void HAccept(const boost::system::error_code &error) {
        _func_debug_
        if (!error) {
            new_connection_->Start();
            StartAccept();
        }
        else {
            new_connection_.reset();
        }
    }
    void StartAccept() {
        _func_debug_
        new_connection_.reset(new Connection(io_service_,
            context_, connection_manager_));
        acceptor_.async_accept(new_connection_->Socket(),
            boost::bind(&Server::HAccept, this,
                boost::asio::placeholders::error));
    }
};

int main(int argc, char **argv) {
    try {
        if (argc != 2) {
            std::cerr << "Usage: PROGRAM <port>" << std::endl;
            return 1;
        }
        boost::asio::io_service io_service;
        Server server(io_service, std::atoi(argv[1]));
        boost::thread t(boost::bind(&boost::asio::io_service::run,
            &io_service));
        std::cin.get();
        io_service.stop();
        t.join();
        return 0;
    }
    catch (std::exception &e) {
        std::cerr << "Exception: " << e.what() << std::endl;
        return 2;
    }
}

我的客户代码:

#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>

class Client {
protected:
    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
    std::string message_;
    boost::asio::streambuf readBuffer_;
    bool HVerifyCertificate(bool preverified,
        boost::asio::ssl::verify_context &ctx) {
        return preverified;
    }
    void HConnect(const boost::system::error_code &error) {
        if (!error) {
            socket_.async_handshake(boost::asio::ssl::stream_base::client,
                boost::bind(&Client::HHandshake, this,
                    boost::asio::placeholders::error));
        }
        else {
            std::cout << "Connect failed. Error: " <<
                error.message() << std::endl;
        }
    }
    void HReadUntil(const boost::system::error_code &error,
            size_t bytes_transferred) {
        if (!error) {
            std::string s;
            std::istream is(&readBuffer_);
            std::getline(is, s, '\0');
            std::cout << s << std::endl;
        }
        else {
            std::cout << "Read failed. Error: " <<
                error.message() << std::endl;
        }
    }
    void HWrite(const boost::system::error_code &error,
        size_t bytes_transferred) {
        if (!error) {
            boost::asio::async_read_until(socket_, readBuffer_, '\0',
                boost::bind(&Client::HReadUntil, this,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred));
        }
        else {
            std::cout << "Write failed. Error: " <<
                error.message() << std::endl;
        }
    }
    void HHandshake(const boost::system::error_code &error) {
        if (!error) {
            std::cout << "To send a message type something: ";
            std::getline(std::cin, message_);
            message_ += std::string("", 1); // append null character
            boost::asio::async_write(socket_,
                boost::asio::buffer(message_, message_.size()),
                boost::bind(&Client::HWrite, this,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred));
        }
        else {
            std::cout << "Handshake failed. Error: " <<
                error.message() << std::endl;
        }
    }
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) {
        socket_.set_verify_mode(boost::asio::ssl::verify_peer);
        socket_.set_verify_callback(boost::bind(&Client::HVerifyCertificate,
            this, _1, _2));
        boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
            boost::bind(&Client::HConnect, this,
                boost::asio::placeholders::error));
    }
};

int main(int argc, char **argv) {
    try {
        if (argc != 3) {
            std::cerr << "Usage: PROGRAM <host> <port>" << std::endl;
            return 1;
        }
        boost::asio::io_service io_service;
        boost::asio::ip::tcp::resolver resolver(io_service);
        boost::asio::ip::tcp::resolver::query query(argv[1], argv[2]);
        boost::asio::ip::tcp::resolver::iterator iterator =
            resolver.resolve(query);
        boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
        ctx.load_verify_file("server.crt");
        Client client(io_service, ctx, iterator);
        io_service.run();
        return 0;
    }
    catch (std::exception &e) {
        std::cerr << "Exception: " << e.what() << std::endl;
        return 1;
    }
}

我使用了the description here to generate ssl related files

1 个答案:

答案 0 :(得分:0)

嗯,这是一个简单的错误。我忘了通过连接管理器启动新连接,因此我的连接对象被删除,并且我收到了分段错误。问题解决了。 :d