Boost logo

Boost :

Subject: Re: [boost] [asio] send blocks with MSG_DONTWAIT (linux)
From: Dmitry Goncharov (dgoncharov_at_[hidden])
Date: 2009-04-27 07:20:31


Stefan Pledl wrote:
> 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;
> }
> }
>
>
>

You can switch your socket in the non-blocking mode with
basic_stream_socket::non_blocking_io().
Though asio should handle MSG_DONTWAIT as well.

BR, Dmitry


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk