Home > database >  Sending a large text via Boost ASIO
Sending a large text via Boost ASIO

Time:04-02

I am trying to send a very large string to one of my clients. I am mostly following code in HTTP server example: https://www.boost.org/doc/libs/1_78_0/doc/html/boost_asio/examples/cpp11_examples.html

Write callbacks return with error code 14, that probably means EFAULT, "bad address" according to this link:

https://mariadb.com/kb/en/operating-system-error-codes/

Note that I could not use message() member function of error_code to read error message, that was causing segmentation fault. (I am using Boost 1.53, and the error might be due to this: https://github.com/boostorg/system/issues/50)

When I try to send small strings, let's say of size 10 for example, write callback does not return with an error.

Here is how I am using async_write:

void Connection::do_write(const std::string& write_buffer)
{
  auto self(shared_from_this());
  boost::asio::async_write(socket_, boost::asio::buffer(write_buffer, write_buffer.size()),
      [this, self, write_buffer](boost::system::error_code ec, std::size_t transfer_size)
      {
        if (!ec)
        {

        } else {
          // code enters here **when** I am sending a large text.
          // transfer_size always prints 65535
        }
      });
}

Here is how I am using async_read_some:

void Connection::do_read()
{
  auto self(shared_from_this());
  socket_.async_read_some(boost::asio::buffer(buffer_),
      [this, self](boost::system::error_code ec, std::size_t bytes_transferred)
      {
        if (!ec)
        {
           do_write(VERY_LARGE_STRING);
           do_read();
        } else if (ec != boost::asio::error::operation_aborted) {
          connection_manager_.stop(shared_from_this());
        }
      });
}

What could be causing write callback to return with error with large string?

CodePudding user response:

The segfault indicates likely Undefined Behaviour to me.

Of course there's to little code to tell, but one strong smell is from you using a reference to a non-member as the buffer:

boost::asio::buffer(write_buffer, write_buffer.size())

Besides that could simply be spelled boost::asio::buffer(writer_buffer), there's not much hope that write_buffer stays around for the duration of the asynchronous operation that depends on it.

As the documentation states:

Although the buffers object may be copied as necessary, ownership of the underlying memory blocks is retained by the caller, which must guarantee that they remain valid until the handler is called.

I would check that you're doing that correctly.

Another potential cause for UB is when you cause overlapping writes on the same socket/stream object:

This operation is implemented in terms of zero or more calls to the stream's async_write_some function, and is known as a composed operation. The program must ensure that the stream performs no other write operations (such as async_write, the stream's async_write_some function, or any other composed operations that perform writes) until this operation completes.

If you checked both these causes of concern and find that something must be wrong, please post a new question including a fully selfcontained example (SSCCE or MCVE)

  • Related