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_;
}