简体   繁体   中英

Write:Unitialized Error when performing boost::asio::async_write

I have assigned to create a HTTPS server using boost::asio , So i did spent some time in the internet and found one source that explains how we can combine boost HTTP and its SSL features together which wasn't explained in the boost official website.Everything has gone fine and now i am in execution phase, that's where a mind sicking problem rose,in my code after i constructed the request stream i am using boost::asio::async_write to deliver it,During runtime i was receiving an error like the below, I am very certain that it caused by boost::asio::async_write , But I am not certain about what caused it to do so, can anyone shed some light for me,I have been wandering in the darkness:( (please see my code below)

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));


    }  

The asynchronous operations are designed to not throw exceptions and instead pass errors to the completion handlers as their first parameter ( boost::system::error_code ). For example, the following program demonstrates async_write() failing with an uninitialized error:

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

The above program will output uninitialized . If an exception is being thrown from an asynchronous operation, then it strongly suggest that undefined behavior is being invoked.

Based on the posted code, the async_write() operation may violate the requirement where ownership of the underlying buffer memory is retained by the caller, who must guarantee that it remains valid until the handler is called. In this case, if the next iteration of the while loop may invalidate the buffer that had been provided to the prior iteration's async_write() operation.

However, even in the absence of undefined behavior, there will be additional problems, as the program neither attempts to establish the connection nor performs the SSL handshake, both of which must be completed before transmitting or receiving data over an encrypted connection.


When using asynchronous operations, a while-sleep loop that is part of the overall operation flow is often an indication of code smell. Consider removing the sqlite3 and encrypt code, and getting an SSL prototype up and running first. It may also help to compile with the highest warning-level/pedantic flags enabled. The Boost.Asio SSL overview shows a typical synchronous usage pattern:

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 ...

The official SSL example can also serve as a great starting point or reference for using asynchronous operations. Once the SSL prototype is confirmed as working, then add the sqlite3 and encrypt logic back into the program.

Also, in the event multiple threads are being used, be aware that the SSL stream is not thread-safe. All asynchronous operations must be synchronized through an explicit strand . For composed operations, such as async_write() , the initiating function must be invoked within the context of a strand , and the completion handler must be wrapped by the same strand .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM