写:执行boost :: asio :: async_write时的单位化错误

时间:2015-09-07 15:02:15

标签: c++ boost https openssl boost-asio

我已经分配了使用boost::asio创建HTTPS服务器,所以我确实花了一些时间在互联网上找到了一个解释我们如何将提升HTTP及其SSL功能组合在一起的来源,这些来源并非如此在升级官方网站上解释。一切都很顺利,现在我处于执行阶段,在构建请求流后我的代码中,我正在使用boost::asio::async_write来提交思维s问题。它,在运行期间我收到如下所示的错误,我非常肯定它是由boost::asio::async_write引起的,但我不确定是什么导致它这样做,任何人都能为我照亮,我有在黑暗中徘徊:((请参阅下面的代码)

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >'
  what():  write: uninitialized

 using boost::asio::ip::tcp;
 string my_password_callback(size_t, boost::asio::ssl::context_base::password_purpose);
 void handle_resolve(const boost::system::error_code& ,
                        tcp::resolver::iterator);
 bool verify_certificate();
 void handle_read();
 void handle_write();



    int i,j,rc;
    sqlite3 *db;
    string selectsql;
    sqlite3_stmt *stmt;
    char *zErrMsg = 0;
    stringstream ss;
    boost::asio::io_service io_service1;
    boost::asio::io_service &io_service(io_service1);
    boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
    boost::asio::ssl::context& context_=ctx;
    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_(io_service,context_);
int main()
{
    boost::shared_ptr<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);
    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(my_password_callback);
    context_.use_certificate_chain_file("SSL\\test.crt");
    context_.use_private_key_file("SSL\\test.key", boost::asio::ssl::context::pem);
    tcp::resolver resolver_(io_service);
    tcp::resolver::query query("172.198.72.135:3000", "http");
    resolver_.async_resolve(query,boost::bind(handle_resolve,
                                           boost::asio::placeholders::error,
                                            boost::asio::placeholders::iterator));
    boost::asio::streambuf request;
    string path="https://172.198.72.135:3000/journals/enc_data?";
while(true)
{
    char * EJTEXT;
    int ID;
    if(sqlite3_open("c:\\MinGW\\test.db", &db))
    {
    selectsql="select IEJ,EJ from EJ limit 1";
    sqlite3_prepare_v2(db, selectsql.c_str(), -1, &stmt, NULL);
    if(sqlite3_step(stmt)==SQLITE_ROW){
    ID=sqlite3_column_int(stmt,0);
    EJTEXT=(char *)sqlite3_column_text(stmt,1);
    }
    else{

    }
   sqlite3_finalize(stmt);
   sqlite3_close(db);
    }
    string EJ=EJTEXT;
     E.Encrypt(EJ);
     string data=E.Url_safe(E.cipher);--my logic
     string Iv=E.Url_safe(E.encoded_iv);--my logic

     std::ostream request_stream(&request);
     request_stream << "POST " <<path+"Data="+data+"&"+"iv="+Iv;
     request_stream << "Host: " <<"172.198.72.135"<< "\r\n";
     request_stream << "Accept: */*\r\n";
     request_stream << "Connection: close\r\n\r\n";
    //try{
   boost::asio::async_write(socket_, request,
       boost::asio::transfer_at_least(1),
        boost::bind(handle_write));
temp="";
data="";
Iv="";

    boost::asio::streambuf response; 
    std::istream response_stream(&response);
    std::string http_version;
    response_stream >> http_version;
    unsigned int status_code;
    response_stream >> status_code;
    std::string status_message;
    std::getline(response_stream, status_message);
    if (!response_stream || http_version.substr(0, 5) != "HTTP/")
    {
      l.HTTP_SSLLOG("Invalid response");
    }
    if (status_code== 200)
    {
     string deletesql="delete * from EJ where IEJ="+ID;
     if(sqlite3_open("c:\\MinGW\\test.db", &db))
    {
    rc=sqlite3_exec(db, deletesql.c_str(), 0, 0, &zErrMsg);
    sqlite3_close(db);
    if(rc)
    {
        ss<<ID;
        l.EJ_Log("ERROR DELETING EJ FOR  "+ss.str());
    }
    }
    else{
        l.DB_Log("ERROR OPENING DB");
    }
    }
    else{
    continue;
}
Sleep(6000);
}
 return 0;
}

 string my_password_callback(size_t t, boost::asio::ssl::context_base::password_purpose p)//std::size_t max_length,ssl::context::password_purpose purpose )
   {
    std::string password;
    return "balaji";
   }

   void handle_resolve(const boost::system::error_code& err,
                        tcp::resolver::iterator endpoint_iterator)
    {
        if (!err)
        {
            socket_.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert);
            socket_.set_verify_callback(boost::bind(verify_certificate));
            boost::asio::connect(socket_.lowest_layer(), endpoint_iterator);
        }
        else
        {
            l.HTTP_SSLLOG("Error resolve: "+err.message());
        }
    }

    bool verify_certificate()
    {
    bool preverified =true;
    context_.set_default_verify_paths();
    return preverified;
    }

    void handle_read()
       {

       }
    void handle_write()
    {
     boost::asio::async_read_until(socket_, response, "\r\n",
          boost::bind(handle_read));


    }  

1 个答案:

答案 0 :(得分:4)

异步操作旨在不抛出异常,而是将错误作为第一个参数(var=passwordID)传递给完成处理程序。例如,以下程序demonstrates boost::system::error_code因未初始化错误而失败:

async_write()

上述程序将输出#include <iostream> #include <boost/asio.hpp> #include <boost/asio/ssl.hpp> int main() { boost::asio::io_service io_service; boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23); boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket(io_service, ctx); boost::asio::async_write(socket, boost::asio::buffer("demo"), [](const boost::system::error_code& error, std::size_t bytes_transferred) { std::cout << error.message() << std::endl; }); io_service.run(); } 。如果从异步操作抛出异常,则强烈建议调用未定义的行为。

根据发布的代码,async_write()操作可能违反了调用者保留底层缓冲区内存所有权的要求,调用者必须保证在调用处理程序之前它仍然有效。在这种情况下,如果while循环的下一次迭代可能使已经提供给先前迭代的uninitialized操作的缓冲区无效。

然而,即使没有未定义的行为,也会有其他问题,因为程序既不会尝试建立连接也不会执行SSL握手,这两者都必须在通过加密连接发送或接收数据之前完成。

当使用异步操作时,作为整个操作流程一部分的while-sleep循环通常表示代码异味。考虑删除sqlite3并加密代码,并首先启动并运行SSL原型。它还可以帮助编译启用最高警告级别/迂腐标志。 Boost.Asio SSL overview显示了典型的同步使用模式:

async_write()

official SSL example也可以作为使用异步操作的一个很好的起点或参考。确认SSL原型工作后,再将sqlite3和加密逻辑添加回程序中。

此外,如果正在使用多个线程,请注意SSL流不是线程安全的。必须通过显式strand同步所有异步操作。对于组合操作,例如using boost::asio::ip::tcp; namespace ssl = boost::asio::ssl; typedef ssl::stream<tcp::socket> ssl_socket; // Create a context that uses the default paths for // finding CA certificates. ssl::context ctx(ssl::context::sslv23); ctx.set_default_verify_paths(); // Open a socket and connect it to the remote host. boost::asio::io_service io_service; ssl_socket sock(io_service, ctx); tcp::resolver resolver(io_service); tcp::resolver::query query("host.name", "https"); boost::asio::connect(sock.lowest_layer(), resolver.resolve(query)); sock.lowest_layer().set_option(tcp::no_delay(true)); // Perform SSL handshake and verify the remote host's // certificate. sock.set_verify_mode(ssl::verify_peer); sock.set_verify_callback(ssl::rfc2818_verification("host.name")); sock.handshake(ssl_socket::client); // ... read and write as normal ... ,必须在async_write()的上下文中调用启动函数,并且完成处理程序必须由相同的strand包装。