Completed buffered recv implementation.
This commit is contained in:
parent
2143785a37
commit
d5d7fa984a
@ -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_;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user