|
Boost : |
Subject: [boost] [asio] send blocks with MSG_DONTWAIT (linux)
From: Stefan Pledl (stefan.pledl_at_[hidden])
Date: 2009-04-27 05:24:57
If i pass the flag MSG_DONTWAIT to basic_stream_socket::send(buffers, flags)
the call blocks in the following situation.
-> Connection is established (boost::asio::socket_base::send_buffer_size
option(2048) is set)
-> sending data form local endpoint to remote endpoint
-> remote endpoint does not read the data due to software bug/crash etc.
-> sendqueue (see netstat) on local endpoint runs full
-> send on local endpoint blocks at this point
I think the flag MSG_DONTWAIT should avoid this blocking call.
If i do the same using C-function send(fd, buf*, len, flag) the call does not
block.
I have analyzed the code and i think the problem is in send function in
asio/detail/reactive_socket_service.hpp
socket_ops::send returns but socket_ops::poll_write blocks.
I have added the following changes (see comments __SP__) and all works ok for
me. Is the blocking desired or where is my mistake?
modified code form asio/detail/reactive_socket_service.hpp
----------------------------------------------------------
// Send the given data to the peer.
template <typename ConstBufferSequence>
size_t send(implementation_type& impl, const ConstBufferSequence& buffers,
socket_base::message_flags flags, boost::system::error_code& ec)
{
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
return 0;
}
// Copy buffers into array.
socket_ops::buf bufs[max_buffers];
typename ConstBufferSequence::const_iterator iter = buffers.begin();
typename ConstBufferSequence::const_iterator end = buffers.end();
size_t i = 0;
size_t total_buffer_size = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
boost::asio::const_buffer buffer(*iter);
socket_ops::init_buf(bufs[i],
boost::asio::buffer_cast<const void*>(buffer),
boost::asio::buffer_size(buffer));
total_buffer_size += boost::asio::buffer_size(buffer);
}
// A request to receive 0 bytes on a stream socket is a no-op.
if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
{
ec = boost::system::error_code();
return 0;
}
// Send the data.
for (;;)
{
// Try to complete the operation without blocking.
int bytes_sent = socket_ops::send(impl.socket_, bufs, i, flags, ec);
// Check if operation succeeded.
if (bytes_sent >= 0)
return bytes_sent;
// Operation failed.
if ((impl.flags_ & implementation_type::user_set_non_blocking)
|| (ec != boost::asio::error::would_block
&& ec != boost::asio::error::try_again))
return 0;
// __SP__
// do not poll if flag MSG_DONTWAIT is set
if (flags & MSG_DONTWAIT)
return 0;
// __SP__
// Wait for socket to become ready.
if (socket_ops::poll_write(impl.socket_, ec) < 0)
return 0;
}
}
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk