Opened 5 years ago
#13468 new Bugs
asio receive buffer overwritten before handler called
| Reported by: | Owned by: | chris_kohlhoff | |
|---|---|---|---|
| Milestone: | To Be Determined | Component: | asio |
| Version: | Boost 1.66.0 | Severity: | Problem |
| Keywords: | Cc: |
Description
I am developing on linux CentOS6.8
Whilst using boost::asio::ip::udp::socket::async_receive_from, I have found that if packets arrive too quickly the receive buffer is overwritten before the handler is called, resulting in a loss of data.
In order to resolve this in my implementation I have modified epoll_reactor::descriptor_state::perform_io to only process one entry from the EPOLLIN queue as below marked +++
operation* epoll_reactor::descriptor_state::perform_io(uint32_t events)
{
mutex_.lock();
perform_io_cleanup_on_block_exit io_cleanup(reactor_);
mutex::scoped_lock descriptor_lock(mutex_, mutex::scoped_lock::adopt_lock);
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI };
for (int j = max_ops - 1; j >= 0; --j)
{
if (events & (flag[j] | EPOLLERR | EPOLLHUP))
{
try_speculative_[j] = true;
while (reactor_op* op = op_queue_[j].front())
{
if (reactor_op::status status = op->perform())
{
op_queue_[j].pop();
io_cleanup.ops_.push(op);
if (status == reactor_op::done_and_exhausted)
{
try_speculative_[j] = false;
break;
}
+++ if ((events & EPOLLIN) && (flag[j] == EPOLLIN))
+++ {
+++ // only read one packet at a time
+++ break;
+++ }
}
else
break;
}
}
}
The first operation will be returned for completion now. The others will be posted for later by the io_cleanup object's destructor. io_cleanup.first_op_ = io_cleanup.ops_.front(); io_cleanup.ops_.pop(); return io_cleanup.first_op_;
}
