Eumcoz
Eumcoz

Reputation: 2458

asio write succeeding but no information sent

I am having a problem while creating a client program that sends requests. The request are using keep alive TCP HTTP connections. When a connection is closed(due to timeout or max being hit), I try and start a new connection if none are available, and resend the request. The connect works fine however, when I try and send the write, nothing is sent(according to Wireshark), but my error code for the write was a success. The receiving server does not receive any information either. Here is the main parts of my code:

void request_handler::send_1(std::vector<std::string> *bid_vector, std::string request_path, boost::mutex *bids_mutex)
{
    try
    {
        boost::asio::streambuf request;
        std::ostream request_stream(&request);
        std::string reply_information;
        request_stream << "GET /tests HTTP/1.1\r\n";
        request_stream << "Host: 10.1.10.160\r\n";
        request_stream << "Accept: */*\r\n";
        request_stream << "Connection: keep-alive\r\n\r\n";

        server1_mutex_.lock();
        if(server1_available_map_.size() == 0)
        {
            server1_mutex_.unlock();

            persistent_connection *new_connection = new persistent_connection("10.1.10.160","80");
            if(new_connection->send(request, reply_information))
            {
                server1_mutex_.lock();
                    server1_available_map_[new_connection->get_id()] = new_connection;
                server1_mutex_.unlock();
            }
        }
        else
        {
                persistent_connection *current_connection = (*(server1_available_map_.begin())).second;
                server1_available_map_.erase(current_connection->get_id());
            server1_mutex_.unlock();

            int retry_counter = 20;
            while(!current_connection->query_rtb(request, reply_information) && --retry_counter != 0)
            {
                delete current_connection;

                server1_mutex_.lock();
                if(server1_available_map_.size() == 0)
                {
                    server1_mutex_.unlock();
                    current_connection = new persistent_connection("10.1.10.160","80");
                }
                else
                {
                        current_connection = (*(server1_available_map_.begin())).second;
                        server1_available_map_.erase(current_connection->get_id());
                    server1_mutex_.unlock();
                }
            }
            //Could not connect to 20 connections
            if(retry_counter == 0)
            {
                Log::fatal("Could not connect in 20 tries");
                delete current_connection;
                return;
            }

            server1_mutex_.lock();
                server1_available_map_[current_connection->get_id()] = current_connection;
            server1_mutex_.unlock();
        }    
        bids_mutex->lock();
            bid_vector->push_back(reply_information);
        bids_mutex->unlock();    
    }
    catch(boost::thread_interrupted& e)
    {
        std::cout << "before cancel 1" << std::endl;
        return;
    }
    catch(...)
    {
        std::cout << "blah blah blah" << std::endl;
    }
}

And my persistent_connection class

persistent_connection::persistent_connection(std::string ip, std::string port):
    io_service_(), socket_(io_service_), host_ip_(ip)
{
    boost::uuids::uuid uuid = boost::uuids::random_generator()();
    id_ = boost::lexical_cast<std::string>(uuid);

    boost::asio::ip::tcp::resolver resolver(io_service_);
    boost::asio::ip::tcp::resolver::query query(host_ip_,port);
    boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
    boost::asio::ip::tcp::endpoint endpoint = *iterator;
    socket_.async_connect(endpoint, boost::bind(&persistent_connection::handler_connect, this, boost::asio::placeholders::error, iterator));
    io_service_.run();
}

void persistent_connection::handler_connect(const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
{
    if(ec)
    {
        std::cout << "Couldn't connect" << ec << std::endl;
        return;
    }
    else
    {
        boost::asio::socket_base::keep_alive keep_option(true);
        socket_.set_option(keep_option);
        std::cout << "Connect handler" << std::endl;
    }
}


bool persistent_connection::send(boost::asio::streambuf &request_information, std::string &reply_information)
{

    std::cout << "DOING QUERY in " << id_ << std::endl;
    boost::system::error_code write_ec, read_ec;
    try
    {
        std::cout << "Before write" << std::endl;
        boost::asio::write(socket_, request_information, write_ec);
        std::cout << write_ec.message() << std::endl;
    }catch(std::exception& e)
    {
        std::cout << "Write exception: " << e.what() << std::endl;
    }
    if(write_ec)
    {
        std::cout <<"Write error: " << write_ec.message() << std::endl;
        return false;
    }
    boost::array<char,8192> buf;
    buf.assign(0);
    try
    {
        std::cout << "Before read" << std::endl;
        boost::asio::read(socket_, boost::asio::buffer(buf), boost::asio::transfer_at_least(1), read_ec);
        std::cout << read_ec.message() << std::endl;
    }catch(std::exception& e)
    {
        std::cout << "Read exception: " << e.what() << std::endl;
    }
    if(read_ec)
    {
        std::cout << "Read error: " << read_ec.message() << std::endl;
        return false;
    }
    reply_information = buf.data();
    return true;
}

std::string persistent_connection::get_id()
{
    return id_;
}

The path for this to happen is if server1_available_map_.size() > 0, and if the while executes, and fails. And then if the size == 0 on the second server1_available_map_.size();

The output for the call is:

DOING QUERY in 69a8f0ab-2a06-45b4-be26-37aea6d93ff2
Before write
Success
Before read
End of file
Read error: End of file
Connect handler
DOING QUERY in 4eacaa96-1040-4878-8bf5-c29b87fa1232
Before write
Success
Before read

Which shows that the first connection gets an end of file(connection closed by server on other end). The second connection connects fine(Connect handler message), and the query is executed in the second connection(different id), and the write is apparently successful, and the program hangs on the read(because there is nothing to read).

Does anyone have any idea why this would be happening? Is there something I seem to be doing wrong?

Thank you

Upvotes: 0

Views: 233

Answers (1)

Dan
Dan

Reputation: 3635

It looks like you are passing the same boost::asio::streambuf to multiple write calls.

boost::asio::write(socket_, request_information, write_ec);

The contents of the buffer are consumed by the first call to boost::asio::write. This effectively empties the buffer so that there is nothing left to send. Pass a const string if you want to use the same buffer for multiple writes.

Upvotes: 1

Related Questions