Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost::asio::buffer: Getting the buffer size and preventing buffer overflow?

I have the two following functions for sending and receiving packets.

void send(std::string protocol)
{
    char *request=new char[protocol.size()+1];
    request[protocol.size()] = 0;
    memcpy(request,protocol.c_str(),protocol.size());

    request_length = std::strlen(request);
    boost::asio::write(s, boost::asio::buffer(request, request_length));
}
void receive()
{
    char reply[max_length];
    size_t reply_length = boost::asio::read(s, boost::asio::buffer(reply, request_length));
    std::cout << "Reply is: ";
    std::cout.write(reply, reply_length);
    std::cout << "\n";
}

The questions pertain to this part boost::asio::buffer(reply, request_length) where the request length is the length of a string which was initially setup when the packet was sent. How do I check the size of the buffer without knowing request_length? Another question is how do I prevent buffer overflow?

like image 234
pandoragami Avatar asked Feb 25 '13 05:02

pandoragami


People also ask

What is boost:: asio:: buffer?

The boost::asio::buffer function is used to create a buffer object to represent raw memory, an array of POD elements, a vector of POD elements, or a std::string.

What should my ASIO buffer size be?

Usually, an ASIO buffer size (in terms of samples) that is a power of two is preferred. In most DAWs sample processing is more efficient if such an “even” number is chosen.


2 Answers

To get the size of a buffer, the boost::asio::buffer_size() function can be used. However, in your example, this will most likely be of little use to you.

As explained in the buffer overview, Boost.Asio use buffer classes to represent buffers. These classes provide an abstraction and protect Boost.Asio operations against buffer overruns. Although the result of boost::asio::buffer() is passed to operations, the meta-data, such as the size of the buffer or its underlying type, is not transmitted. Also, these buffers do not own the memory, so it is the applications responsibility to ensure the underlying memory remains valid throughout the duration of the buffer abstraction's lifetime.

The boost::asio::buffer() function provides a convenient way to create the buffer classes, where the size of the buffer is deduced from the type possible. When Boost.Asio is able to deduce the buffer length, then Boost.Asio operations will not invoke a buffer overflow when using the resulting buffer type. However, if the application code specifies the size of the buffer to boost::asio::buffer(), then it is the applications responsibility to ensure that the size is not larger than the underlying memory.

When reading data, a buffer is required. The fundamental question becomes how does one know how much memory to allocate, if Boost.Asio does not transmit the size. There are a few solutions to this problem:

  • Query the socket for how much data is available via socket::available(), then allocate the buffer accordingly.

    std::vector<char> data(socket_.available());
    boost::asio::read(socket_, boost::asio::buffer(data));
    
  • Use a class that Boost.Asio can grow in memory, such as boost::asio::streambuf. Some operations, such as boost::asio::read() accept streambuf objects as their buffer and will allocate memory as is required for the operation. However, a completion condition should be provided; otherwise, the operation will continue until the buffer is full.

    boost::asio::streambuf data;
    boost::asio::read(socket_, data,
                      boost::asio::transfer_at_least(socket_.available()));
    
  • As Öö Tiib suggests, incorporate length as part of the communication protocol. Check the Boost.Asio examples for examples of communication protocols. Focus on the protocol, not necessarily on the Boost.Asio API.

    • In a fixed size protocol, both the data producer and consumer use the same size message. As the reader knows the size of the message, the reader can allocate a buffer in advance.
    • In a variable length protocol, the messages are often divided into two parts: a header and a body. The header is normally fixed size, and can contain various meta-information, such as the length of the body. This allows a reader to read a header into a fixed size buffer, extract the body length, allocate a buffer for the body, then read the body.

      // Read fixed header.
      std::vector<char> data(fixed_header_size);
      boost::asio::read(socket_, boost::asio::buffer(data));
      
      protocol::header header(data);
      network_to_local(header); // Handle endianess.
      
      // Read body.
      data.resize(header.body_length());
      boost::asio::read(socket_, boost::asio::buffer(data));  
      
      protocol::body body(data);
      network_to_local(body); // Handle endianess.    
      
like image 109
Tanner Sansbury Avatar answered Nov 15 '22 14:11

Tanner Sansbury


Typically a communication protocol either uses fixed length messages or messages that contain header that tells the length of message.

Boost.Asio online documentation contains large set of examples and tutorials so you should perhaps start from there. Wikipedia is good source for explaining data transmission terminology, boost asio documentation does not do it.

like image 38
Öö Tiib Avatar answered Nov 15 '22 13:11

Öö Tiib