Completed buffered recv implementation.
This commit is contained in:
parent
2143785a37
commit
d5d7fa984a
@ -23,6 +23,9 @@
|
|||||||
#include <boost/type_traits.hpp>
|
#include <boost/type_traits.hpp>
|
||||||
#include "asio/detail/pop_options.hpp"
|
#include "asio/detail/pop_options.hpp"
|
||||||
|
|
||||||
|
#include "asio/null_completion_context.hpp"
|
||||||
|
#include "asio/detail/bind_handler.hpp"
|
||||||
|
|
||||||
namespace asio {
|
namespace asio {
|
||||||
|
|
||||||
/// The buffered_recv_stream class template can be used to add buffering to the
|
/// 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.
|
/// 0 if the stream was closed cleanly. Throws an exception on failure.
|
||||||
size_t recv(void* data, size_t max_length)
|
size_t recv(void* data, size_t max_length)
|
||||||
{
|
{
|
||||||
using namespace std; // For memcpy.
|
|
||||||
|
|
||||||
if (read_pos_ == bytes_in_buffer_)
|
if (read_pos_ == bytes_in_buffer_)
|
||||||
{
|
{
|
||||||
bytes_in_buffer_ = next_layer_.recv(buffer_, Buffer_Size);
|
bytes_in_buffer_ = next_layer_.recv(buffer_, Buffer_Size);
|
||||||
@ -112,19 +113,80 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t bytes_avail = bytes_in_buffer_ - read_pos_;
|
return copy(data, max_length);
|
||||||
size_t length = (max_length < bytes_avail) ? max_length : bytes_avail;
|
|
||||||
memcpy(data, buffer_ + read_pos_, length);
|
|
||||||
read_pos_ += length;
|
|
||||||
return 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
|
/// Start an asynchronous receive. The buffer for the data being received
|
||||||
/// must be valid for the lifetime of the asynchronous operation.
|
/// must be valid for the lifetime of the asynchronous operation.
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
void async_recv(void* data, size_t max_length, Handler 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
|
/// 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,
|
void async_recv(void* data, size_t max_length, Handler handler,
|
||||||
Completion_Context& context)
|
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:
|
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.
|
/// The next layer.
|
||||||
Next_Layer next_layer_;
|
Next_Layer next_layer_;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user