Remove recv_decode and friends, in anticipation of a new improved way of
writing message decoders.
This commit is contained in:
parent
e54ba39147
commit
92414c7e63
10
asio/TODO
10
asio/TODO
@ -6,16 +6,6 @@ Add vectored send/recv functions
|
|||||||
Add the sendv and recvv functions to basic_stream_socket and presumably also to
|
Add the sendv and recvv functions to basic_stream_socket and presumably also to
|
||||||
the buffered stream templates.
|
the buffered stream templates.
|
||||||
|
|
||||||
Add encode_send/async_encode_send functions
|
|
||||||
-------------------------------------------
|
|
||||||
Add new free functions encode_send/async_encode_send that mirror the
|
|
||||||
functionality of recv_decode/async_recv_decode.
|
|
||||||
|
|
||||||
Develop a safe version of recv_until
|
|
||||||
------------------------------------
|
|
||||||
The current implementation of recv_until (and async_recv_until) does not set
|
|
||||||
an upper limit on the size of the received data. This is not particularly safe.
|
|
||||||
|
|
||||||
Demuxer functions for event loop integration
|
Demuxer functions for event loop integration
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
Add functions demuxer::work_pending() and demuxer::perform_work() that can be
|
Add functions demuxer::work_pending() and demuxer::perform_work() that can be
|
||||||
|
@ -17,11 +17,6 @@
|
|||||||
|
|
||||||
#include "asio/detail/push_options.hpp"
|
#include "asio/detail/push_options.hpp"
|
||||||
|
|
||||||
#include "asio/detail/push_options.hpp"
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
#include "asio/detail/pop_options.hpp"
|
|
||||||
|
|
||||||
#include "asio/detail/bind_handler.hpp"
|
#include "asio/detail/bind_handler.hpp"
|
||||||
|
|
||||||
namespace asio {
|
namespace asio {
|
||||||
@ -479,402 +474,6 @@ inline void async_recv_at_least_n(Stream& s, void* data, size_t min_length,
|
|||||||
max_length, handler));
|
max_length, handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read some data from a stream and decode it.
|
|
||||||
/**
|
|
||||||
* This function is used to receive data on a stream and decode it in a single
|
|
||||||
* operation. The function call will block until the decoder function object
|
|
||||||
* indicates that it has finished.
|
|
||||||
*
|
|
||||||
* @param s The stream on which the data is to be received.
|
|
||||||
*
|
|
||||||
* @param decoder The decoder function object to be called to decode the
|
|
||||||
* received data. The function object is assumed to be stateful. That is, it
|
|
||||||
* may not be given sufficient data in a single invocation to complete
|
|
||||||
* decoding, and is expected to maintain state so that it may resume decoding
|
|
||||||
* when the next piece of data is supplied. Copies will be made of the decoder
|
|
||||||
* function object as required, however with respect to maintaining state it
|
|
||||||
* can rely on the fact that only an up-to-date copy will be used. The
|
|
||||||
* equivalent function signature of the handler must be:
|
|
||||||
* @code std::pair<bool, const char*> decoder(
|
|
||||||
* const char* begin, // Pointer to the beginning of data to be decoded.
|
|
||||||
* const char* end // Pointer to one-past-the-end of data to be decoded.
|
|
||||||
* ); @endcode
|
|
||||||
* The first element of the return value is true if the decoder has finished.
|
|
||||||
* The second element is a pointer to the beginning of the unused portion of
|
|
||||||
* the data.
|
|
||||||
*
|
|
||||||
* @param total_bytes_recvd An optional output parameter that receives the
|
|
||||||
* total number of bytes actually received.
|
|
||||||
*
|
|
||||||
* @returns The number of bytes received on the last recv, or 0 if end-of-file
|
|
||||||
* was reached or the connection was closed cleanly.
|
|
||||||
*
|
|
||||||
* @note Throws an exception on failure. The type of the exception depends
|
|
||||||
* on the underlying stream's recv operation.
|
|
||||||
*/
|
|
||||||
template <typename Buffered_Stream, typename Decoder>
|
|
||||||
size_t recv_decode(Buffered_Stream& s, Decoder decoder,
|
|
||||||
size_t* total_bytes_recvd = 0)
|
|
||||||
{
|
|
||||||
size_t total_recvd = 0;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
if (s.recv_buffer().empty() && s.fill() == 0)
|
|
||||||
{
|
|
||||||
if (total_bytes_recvd)
|
|
||||||
*total_bytes_recvd = total_recvd;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<bool, const char*> result =
|
|
||||||
decoder(s.recv_buffer().begin(), s.recv_buffer().end());
|
|
||||||
|
|
||||||
size_t bytes_read = result.second - s.recv_buffer().begin();
|
|
||||||
s.recv_buffer().pop(bytes_read);
|
|
||||||
total_recvd += bytes_read;
|
|
||||||
|
|
||||||
if (result.first)
|
|
||||||
{
|
|
||||||
if (total_bytes_recvd)
|
|
||||||
*total_bytes_recvd = total_recvd;
|
|
||||||
return bytes_read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read some data from a stream and decode it.
|
|
||||||
/**
|
|
||||||
* This function is used to receive data on a stream and decode it in a single
|
|
||||||
* operation. The function call will block until the decoder function object
|
|
||||||
* indicates that it has finished.
|
|
||||||
*
|
|
||||||
* @param s The stream on which the data is to be received.
|
|
||||||
*
|
|
||||||
* @param decoder The decoder function object to be called to decode the
|
|
||||||
* received data. The function object is assumed to be stateful. That is, it
|
|
||||||
* may not be given sufficient data in a single invocation to complete
|
|
||||||
* decoding, and is expected to maintain state so that it may resume decoding
|
|
||||||
* when the next piece of data is supplied. Copies will be made of the decoder
|
|
||||||
* function object as required, however with respect to maintaining state it
|
|
||||||
* can rely on the fact that only an up-to-date copy will be used. The
|
|
||||||
* equivalent function signature of the handler must be:
|
|
||||||
* @code std::pair<bool, const char*> decoder(
|
|
||||||
* const char* begin, // Pointer to the beginning of data to be decoded.
|
|
||||||
* const char* end // Pointer to one-past-the-end of data to be decoded.
|
|
||||||
* ); @endcode
|
|
||||||
* The first element of the return value is true if the decoder has finished.
|
|
||||||
* The second element is a pointer to the beginning of the unused portion of
|
|
||||||
* the data.
|
|
||||||
*
|
|
||||||
* @param total_bytes_recvd An optional output parameter that receives the
|
|
||||||
* total number of bytes actually received.
|
|
||||||
*
|
|
||||||
* @param error_handler The handler to be called when an error occurs. Copies
|
|
||||||
* will be made of the handler as required. The equivalent function signature
|
|
||||||
* of the handler must be:
|
|
||||||
* @code template <typename Error>
|
|
||||||
* void error_handler(
|
|
||||||
* const Error& error // Result of operation (the actual type is dependent on
|
|
||||||
* // the underlying stream's recv operation)
|
|
||||||
* ); @endcode
|
|
||||||
*
|
|
||||||
* @returns The number of bytes received on the last recv, or 0 if end-of-file
|
|
||||||
* was reached or the connection was closed cleanly.
|
|
||||||
*/
|
|
||||||
template <typename Buffered_Stream, typename Decoder, typename Error_Handler>
|
|
||||||
size_t recv_decode(Buffered_Stream& s, Decoder decoder,
|
|
||||||
size_t* total_bytes_recvd, Error_Handler error_handler)
|
|
||||||
{
|
|
||||||
size_t total_recvd = 0;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
if (s.recv_buffer().empty() && s.fill(error_handler) == 0)
|
|
||||||
{
|
|
||||||
if (total_bytes_recvd)
|
|
||||||
*total_bytes_recvd = total_recvd;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<bool, const char*> result =
|
|
||||||
decoder(s.recv_buffer().begin(), s.recv_buffer().end());
|
|
||||||
|
|
||||||
size_t bytes_read = result.second - s.recv_buffer().begin();
|
|
||||||
s.recv_buffer().pop(bytes_read);
|
|
||||||
total_recvd += bytes_read;
|
|
||||||
|
|
||||||
if (result.first)
|
|
||||||
{
|
|
||||||
if (total_bytes_recvd)
|
|
||||||
*total_bytes_recvd = total_recvd;
|
|
||||||
return bytes_read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
template <typename Buffered_Stream, typename Decoder, typename Handler>
|
|
||||||
class recv_decode_handler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
recv_decode_handler(Buffered_Stream& stream, Decoder decoder,
|
|
||||||
Handler handler)
|
|
||||||
: stream_(stream),
|
|
||||||
decoder_(decoder),
|
|
||||||
total_recvd_(0),
|
|
||||||
handler_(handler)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Error>
|
|
||||||
void operator()(const Error& e, size_t bytes_recvd)
|
|
||||||
{
|
|
||||||
if (e || bytes_recvd == 0)
|
|
||||||
{
|
|
||||||
stream_.demuxer().dispatch(
|
|
||||||
detail::bind_handler(handler_, e, bytes_recvd, total_recvd_));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while (!stream_.recv_buffer().empty())
|
|
||||||
{
|
|
||||||
std::pair<bool, const char*> result =
|
|
||||||
decoder_(stream_.recv_buffer().begin(),
|
|
||||||
stream_.recv_buffer().end());
|
|
||||||
|
|
||||||
size_t bytes_read = result.second - stream_.recv_buffer().begin();
|
|
||||||
stream_.recv_buffer().pop(bytes_read);
|
|
||||||
total_recvd_ += bytes_read;
|
|
||||||
|
|
||||||
if (result.first)
|
|
||||||
{
|
|
||||||
stream_.demuxer().dispatch(
|
|
||||||
detail::bind_handler(handler_, 0, bytes_read, total_recvd_));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stream_.async_fill(*this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Buffered_Stream& stream_;
|
|
||||||
Decoder decoder_;
|
|
||||||
size_t total_recvd_;
|
|
||||||
Handler handler_;
|
|
||||||
};
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/// Start an asynchronous receive that will not complete until some data has
|
|
||||||
/// been fully decoded.
|
|
||||||
/**
|
|
||||||
* This function is used to receive data on a stream and decode it in a single
|
|
||||||
* asynchronous operation. The function call always returns immediately. The
|
|
||||||
* asynchronous operation will complete only when the decoder indicates that it
|
|
||||||
* has finished.
|
|
||||||
*
|
|
||||||
* @param s The stream on which the data is to be received.
|
|
||||||
*
|
|
||||||
* @param decoder The decoder function object to be called to decode the
|
|
||||||
* received data. The function object is assumed to be stateful. That is, it
|
|
||||||
* may not be given sufficient data in a single invocation to complete
|
|
||||||
* decoding, and is expected to maintain state so that it may resume decoding
|
|
||||||
* when the next piece of data is supplied. Copies will be made of the decoder
|
|
||||||
* function object as required, however with respect to maintaining state it
|
|
||||||
* can rely on the fact that only an up-to-date copy will be used. The
|
|
||||||
* equivalent function signature of the handler must be:
|
|
||||||
* @code std::pair<bool, const char*> decoder(
|
|
||||||
* const char* begin, // Pointer to the beginning of data to be decoded.
|
|
||||||
* const char* end // Pointer to one-past-the-end of data to be decoded.
|
|
||||||
* ); @endcode
|
|
||||||
* The first element of the return value is true if the decoder has finished.
|
|
||||||
* The second element is a pointer to the beginning of the unused portion of
|
|
||||||
* the data.
|
|
||||||
*
|
|
||||||
* @param handler The handler to be called when the receive operation
|
|
||||||
* completes. Copies will be made of the handler as required. The equivalent
|
|
||||||
* function signature of the handler must be:
|
|
||||||
* @code template <typename Error>
|
|
||||||
* void handler(
|
|
||||||
* const Error& error, // Result of operation (the actual type is
|
|
||||||
* // dependent on the underlying stream's recv
|
|
||||||
* // operation)
|
|
||||||
* size_t last_bytes_recvd, // Number of bytes received on last recv
|
|
||||||
* // operation
|
|
||||||
* size_t total_bytes_recvd // Total number of bytes successfully received
|
|
||||||
* ); @endcode
|
|
||||||
*/
|
|
||||||
template <typename Buffered_Stream, typename Decoder, typename Handler>
|
|
||||||
void async_recv_decode(Buffered_Stream& s, Decoder decoder, Handler handler)
|
|
||||||
{
|
|
||||||
while (!s.recv_buffer().empty())
|
|
||||||
{
|
|
||||||
std::pair<bool, const char*> result =
|
|
||||||
decoder(s.recv_buffer().begin(), s.recv_buffer().end());
|
|
||||||
|
|
||||||
size_t bytes_read = result.second - s.recv_buffer().begin();
|
|
||||||
s.recv_buffer().pop(bytes_read);
|
|
||||||
|
|
||||||
if (result.first)
|
|
||||||
{
|
|
||||||
s.demuxer().post(
|
|
||||||
detail::bind_handler(handler, 0, bytes_read, bytes_read));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s.async_fill(detail::recv_decode_handler<Buffered_Stream, Decoder, Handler>(
|
|
||||||
s, decoder, handler));
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
class recv_until_decoder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
recv_until_decoder(std::string& data, const std::string& delimiter)
|
|
||||||
: data_(data),
|
|
||||||
delimiter_(delimiter),
|
|
||||||
delimiter_length_(delimiter.length()),
|
|
||||||
delimiter_pos_(0)
|
|
||||||
{
|
|
||||||
data_ = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<bool, const char*> operator()(const char* begin, const char* end)
|
|
||||||
{
|
|
||||||
const char* p = begin;
|
|
||||||
while (p < end)
|
|
||||||
{
|
|
||||||
char next_char = *p++;
|
|
||||||
if (next_char == delimiter_[delimiter_pos_])
|
|
||||||
{
|
|
||||||
if (++delimiter_pos_ == delimiter_length_)
|
|
||||||
{
|
|
||||||
data_.append(begin, p - begin);
|
|
||||||
return std::make_pair(true, p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delimiter_pos_ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data_.append(begin, end - begin);
|
|
||||||
return std::make_pair(false, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string& data_;
|
|
||||||
std::string delimiter_;
|
|
||||||
size_t delimiter_length_;
|
|
||||||
size_t delimiter_pos_;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read data from the stream until a delimiter is reached.
|
|
||||||
/**
|
|
||||||
* This function is used to receive data from the stream into a std::string
|
|
||||||
* object until a specified delimiter is reached. The function call will block
|
|
||||||
* until the delimiter is found or an error occurs.
|
|
||||||
*
|
|
||||||
* @param s The stream on which the data is to be received.
|
|
||||||
*
|
|
||||||
* @param data The std::string object into which the received data will be
|
|
||||||
* written.
|
|
||||||
*
|
|
||||||
* @param delimiter The pattern marking the end of the data to receive.
|
|
||||||
*
|
|
||||||
* @param total_bytes_recvd An optional output parameter that receives the
|
|
||||||
* total number of bytes actually received.
|
|
||||||
*
|
|
||||||
* @returns The number of bytes received on the last recv, or 0 if end-of-file
|
|
||||||
* was reached or the connection was closed cleanly.
|
|
||||||
*
|
|
||||||
* @note Throws an exception on failure. The type of the exception depends
|
|
||||||
* on the underlying stream's recv operation.
|
|
||||||
*/
|
|
||||||
template <typename Buffered_Stream>
|
|
||||||
inline size_t recv_until(Buffered_Stream& s, std::string& data,
|
|
||||||
const std::string& delimiter, size_t* total_bytes_recvd = 0)
|
|
||||||
{
|
|
||||||
return recv_decode(s, detail::recv_until_decoder(data, delimiter),
|
|
||||||
total_bytes_recvd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read data from the stream until a delimiter is reached.
|
|
||||||
/**
|
|
||||||
* This function is used to receive data from the stream into a std::string
|
|
||||||
* object until a specified delimiter is reached. The function call will block
|
|
||||||
* until the delimiter is found or an error occurs.
|
|
||||||
*
|
|
||||||
* @param s The stream on which the data is to be received.
|
|
||||||
*
|
|
||||||
* @param data The std::string object into which the received data will be
|
|
||||||
* written.
|
|
||||||
*
|
|
||||||
* @param delimiter The pattern marking the end of the data to receive.
|
|
||||||
*
|
|
||||||
* @param total_bytes_recvd An optional output parameter that receives the
|
|
||||||
* total number of bytes actually received.
|
|
||||||
*
|
|
||||||
* @param error_handler The handler to be called when an error occurs. Copies
|
|
||||||
* will be made of the handler as required. The equivalent function signature
|
|
||||||
* of the handler must be:
|
|
||||||
* @code template <typename Error>
|
|
||||||
* void error_handler(
|
|
||||||
* const Error& error // Result of operation (the actual type is dependent on
|
|
||||||
* // the underlying stream's recv operation)
|
|
||||||
* ); @endcode
|
|
||||||
*
|
|
||||||
* @returns The number of bytes received on the last recv, or 0 if end-of-file
|
|
||||||
* was reached or the connection was closed cleanly.
|
|
||||||
*/
|
|
||||||
template <typename Buffered_Stream, typename Error_Handler>
|
|
||||||
inline size_t recv_until(Buffered_Stream& s, std::string& data,
|
|
||||||
const std::string& delimiter, size_t* total_bytes_recvd,
|
|
||||||
Error_Handler error_handler)
|
|
||||||
{
|
|
||||||
return recv_decode(s, detail::recv_until_decoder(data, delimiter),
|
|
||||||
total_bytes_recvd, error_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Start an asynchronous receive that will not complete until the specified
|
|
||||||
/// delimiter is encountered.
|
|
||||||
/**
|
|
||||||
* This function is used to asynchronously receive data from a stream until a
|
|
||||||
* given delimiter is found. The function call always returns immediately.
|
|
||||||
*
|
|
||||||
* @param s The stream on which the data is to be received.
|
|
||||||
*
|
|
||||||
* @param data The std:::string object into which the received data will be
|
|
||||||
* written. Ownership of the object is retained by the caller, which must
|
|
||||||
* guarantee that it is valid until the handler is called.
|
|
||||||
*
|
|
||||||
* @param delimiter The pattern marking the end of the data to receive. Copies
|
|
||||||
* will be made of the string as required.
|
|
||||||
*
|
|
||||||
* @param handler The handler to be called when the receive operation
|
|
||||||
* completes. Copies will be made of the handler as required. The equivalent
|
|
||||||
* function signature of the handler must be:
|
|
||||||
* @code template <typename Error>
|
|
||||||
* void handler(
|
|
||||||
* const Error& error, // Result of operation (the actual type is
|
|
||||||
* // dependent on the underlying stream's recv
|
|
||||||
* // operation)
|
|
||||||
* size_t last_bytes_recvd, // Number of bytes received on last recv
|
|
||||||
* // operation
|
|
||||||
* size_t total_bytes_recvd // Total number of bytes successfully received
|
|
||||||
* ); @endcode
|
|
||||||
*/
|
|
||||||
template <typename Buffered_Stream, typename Handler>
|
|
||||||
inline void async_recv_until(Buffered_Stream& s, std::string& data,
|
|
||||||
const std::string& delimiter, Handler handler)
|
|
||||||
{
|
|
||||||
async_recv_decode(s, detail::recv_until_decoder(data, delimiter), handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace asio
|
} // namespace asio
|
||||||
|
|
||||||
#include "asio/detail/pop_options.hpp"
|
#include "asio/detail/pop_options.hpp"
|
||||||
|
Loading…
Reference in New Issue
Block a user