Completed buffered recv implementation.

This commit is contained in:
chris 2003-10-23 06:27:00 +00:00
parent 2143785a37
commit d5d7fa984a

View File

@ -23,6 +23,9 @@
#include <boost/type_traits.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/null_completion_context.hpp"
#include "asio/detail/bind_handler.hpp"
namespace asio {
/// The buffered_recv_stream class template can be used to add buffering to the
@ -102,8 +105,6 @@ public:
/// 0 if the stream was closed cleanly. Throws an exception on failure.
size_t recv(void* data, size_t max_length)
{
using namespace std; // For memcpy.
if (read_pos_ == bytes_in_buffer_)
{
bytes_in_buffer_ = next_layer_.recv(buffer_, Buffer_Size);
@ -112,19 +113,80 @@ public:
return 0;
}
size_t bytes_avail = bytes_in_buffer_ - read_pos_;
size_t length = (max_length < bytes_avail) ? max_length : bytes_avail;
memcpy(data, buffer_ + read_pos_, length);
read_pos_ += length;
return length;
return copy(data, max_length);
}
template <typename Handler, typename Completion_Context>
class recv_handler
{
public:
recv_handler(demuxer_type& demuxer, char* buffer,
size_t& bytes_in_buffer, size_t& read_pos, void* data,
size_t max_length, Handler handler, Completion_Context& context)
: demuxer_(demuxer),
buffer_(buffer),
bytes_in_buffer_(bytes_in_buffer),
read_pos_(read_pos),
data_(data),
max_length_(max_length),
handler_(handler),
context_(context)
{
}
template <typename Error>
void operator()(const Error& e, size_t bytes_recvd)
{
bytes_in_buffer_ = bytes_recvd;
read_pos_ = 0;
if (bytes_in_buffer_ == 0)
{
demuxer_.operation_immediate(detail::bind_handler(handler_, e, 0),
context_);
}
else
{
using namespace std; // For memcpy.
size_t bytes_avail = bytes_in_buffer_ - read_pos_;
size_t length = (max_length_ < bytes_avail)
? max_length_ : bytes_avail;
memcpy(data_, buffer_ + read_pos_, length);
read_pos_ += length;
demuxer_.operation_immediate(
detail::bind_handler(handler_, e, length), context_);
}
}
private:
demuxer_type& demuxer_;
char* buffer_;
size_t& bytes_in_buffer_;
size_t& read_pos_;
void* data_;
size_t max_length_;
Handler handler_;
Completion_Context& context_;
};
/// Start an asynchronous receive. The buffer for the data being received
/// must be valid for the lifetime of the asynchronous operation.
template <typename Handler>
void async_recv(void* data, size_t max_length, Handler handler)
{
next_layer_.async_recv(data, max_length, handler);
if (read_pos_ == bytes_in_buffer_)
{
next_layer_.async_recv(buffer_, Buffer_Size,
recv_handler<Handler, null_completion_context>(demuxer(), buffer_,
bytes_in_buffer_, read_pos_, data, max_length, handler,
null_completion_context::instance()));
}
else
{
size_t length = copy(data, max_length);
next_layer_.demuxer().operation_immediate(
detail::bind_handler(handler, 0, length));
}
}
/// Start an asynchronous receive. The buffer for the data being received
@ -133,10 +195,35 @@ public:
void async_recv(void* data, size_t max_length, Handler handler,
Completion_Context& context)
{
next_layer_.async_recv(data, max_length, handler, context);
if (read_pos_ == bytes_in_buffer_)
{
next_layer_.async_recv(buffer_, Buffer_Size,
recv_handler<Handler, Completion_Context>(demuxer(), buffer_,
bytes_in_buffer_, read_pos_, data, max_length, handler, context));
}
else
{
size_t length = copy(data, max_length);
next_layer_.demuxer().operation_immediate(
detail::bind_handler(handler, 0, length), context);
}
}
private:
/// Copy data out of the internal buffer to the specified target buffer.
/// Returns the number of bytes copied.
size_t copy(void* data, size_t max_length)
{
using namespace std; // For memcpy.
size_t bytes_avail = bytes_in_buffer_ - read_pos_;
size_t length = (max_length < bytes_avail) ? max_length : bytes_avail;
memcpy(data, buffer_ + read_pos_, length);
read_pos_ += length;
return length;
}
/// The next layer.
Next_Layer next_layer_;