Add websocket::stream pong and async_pong

This commit is contained in:
Vinnie Falco
2016-11-03 17:53:32 -04:00
parent f56d4fe74b
commit f904759877
8 changed files with 156 additions and 16 deletions

View File

@ -11,6 +11,7 @@ WebSocket
* Write buffer option does not change capacity
* Close connection during async_read on close frame
* Add pong, async pong to stream
Core

View File

@ -329,7 +329,7 @@ Ping and pong messages are control frames which may be sent at any time
by either peer on an established WebSocket connection. They are sent
using the functions
[link beast.ref.websocket__stream.ping `ping`] and
[link beast.ref.websocket__stream.ping `pong`].
[link beast.ref.websocket__stream.pong `pong`].
To receive pong control frames, callers may register a "pong callback" using
[link beast.ref.websocket__stream.set_option `set_option`]. The object provided

View File

@ -226,7 +226,7 @@ struct message_headers
The Reason-Phrase is obsolete as of rfc7230.
@note This field is present only if `isRequest == false`.
@note This field is present only if `isRequest == false`.
*/
std::string reason;

View File

@ -104,7 +104,6 @@ protected:
// The write buffer.
// The buffer is allocated or reallocated at the beginning of
// sending a message.
//
std::unique_ptr<std::uint8_t[]> buf;
void

View File

@ -38,7 +38,7 @@ class stream<NextLayer>::ping_op
template<class DeducedHandler>
data(DeducedHandler&& h_, stream<NextLayer>& ws_,
ping_data const& payload)
opcode op_, ping_data const& payload)
: ws(ws_)
, h(std::forward<DeducedHandler>(h_))
, cont(boost_asio_handler_cont_helpers::
@ -46,8 +46,8 @@ class stream<NextLayer>::ping_op
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
ws.template write_ping<static_streambuf>(
fb, opcode::ping, payload);
ws.template write_ping<
static_streambuf>(fb, op_, payload);
}
};
@ -191,19 +191,38 @@ upcall:
}
template<class NextLayer>
template<class PingHandler>
template<class WriteHandler>
typename async_completion<
PingHandler, void(error_code)>::result_type
WriteHandler, void(error_code)>::result_type
stream<NextLayer>::
async_ping(ping_data const& payload, PingHandler&& handler)
async_ping(ping_data const& payload, WriteHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
beast::async_completion<
PingHandler, void(error_code)
WriteHandler, void(error_code)
> completion(handler);
ping_op<decltype(completion.handler)>{
completion.handler, *this, payload};
completion.handler, *this,
opcode::ping, payload};
return completion.result.get();
}
template<class NextLayer>
template<class WriteHandler>
typename async_completion<
WriteHandler, void(error_code)>::result_type
stream<NextLayer>::
async_pong(ping_data const& payload, WriteHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
beast::async_completion<
WriteHandler, void(error_code)
> completion(handler);
ping_op<decltype(completion.handler)>{
completion.handler, *this,
opcode::pong, payload};
return completion.result.get();
}
@ -229,6 +248,28 @@ ping(ping_data const& payload, error_code& ec)
boost::asio::write(stream_, db.data(), ec);
}
template<class NextLayer>
void
stream<NextLayer>::
pong(ping_data const& payload)
{
error_code ec;
pong(payload, ec);
if(ec)
throw system_error{ec};
}
template<class NextLayer>
void
stream<NextLayer>::
pong(ping_data const& payload, error_code& ec)
{
detail::frame_streambuf db;
write_ping<static_streambuf>(
db, opcode::pong, payload);
boost::asio::write(stream_, db.data(), ec);
}
//------------------------------------------------------------------------------
} // websocket

View File

@ -40,7 +40,7 @@ namespace websocket {
system call, by concatenating the frame header and the payload.
In the client role, this will send a single frame in one system
calls, using the write buffer to calculate masked data.
call, using the write buffer to calculate masked data.
2. autofragment: true
compression: false
@ -215,7 +215,7 @@ public:
template<class NextLayer>
template<class Buffers, class Handler>
void
void
stream<NextLayer>::
write_frame_op<Buffers, Handler>::
operator()(error_code ec, std::size_t)

View File

@ -987,14 +987,107 @@ public:
this function. Invocation of the handler will be performed in a
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class PingHandler>
template<class WriteHandler>
#if GENERATING_DOCS
void_or_deduced
#else
typename async_completion<
PingHandler, void(error_code)>::result_type
WriteHandler, void(error_code)>::result_type
#endif
async_ping(ping_data const& payload, PingHandler&& handler);
async_ping(ping_data const& payload, WriteHandler&& handler);
/** Send a WebSocket pong frame.
This function is used to synchronously send a pong frame on
the stream. The call blocks until one of the following is true:
@li The pong frame finishes sending.
@li An error occurs on the stream.
This function is implemented in terms of one or more calls to the
next layer's `write_some` functions.
The WebSocket protocol allows pong frames to be sent from either
end at any time. It is not necessary to first receive a ping in
order to send a pong. The remote peer may use the receipt of a
pong frame as an indication that the connection is not dead.
@param payload The payload of the pong message, which may be empty.
@throws system_error Thrown on failure.
*/
void
pong(ping_data const& payload);
/** Send a WebSocket pong frame.
This function is used to synchronously send a pong frame on
the stream. The call blocks until one of the following is true:
@li The pong frame finishes sending.
@li An error occurs on the stream.
This function is implemented in terms of one or more calls to the
next layer's `write_some` functions.
The WebSocket protocol allows pong frames to be sent from either
end at any time. It is not necessary to first receive a ping in
order to send a pong. The remote peer may use the receipt of a
pong frame as an indication that the connection is not dead.
@param payload The payload of the pong message, which may be empty.
@param ec Set to indicate what error occurred, if any.
*/
void
pong(ping_data const& payload, error_code& ec);
/** Start an asynchronous operation to send a WebSocket pong frame.
This function is used to asynchronously send a pong frame to
the stream. The function call always returns immediately. The
asynchronous operation will continue until one of the following
is true:
@li The entire pong frame is sent.
@li An error occurs on the stream.
This operation is implemented in terms of one or more calls to the
next layer's `async_write_some` functions, and is known as a
<em>composed operation</em>. The program must ensure that the
stream performs no other writes until this operation completes.
The WebSocket protocol allows pong frames to be sent from either
end at any time. It is not necessary to first receive a ping in
order to send a pong. The remote peer may use the receipt of a
pong frame as an indication that the connection is not dead.
@param payload The payload of the pong message, which may be empty.
@param handler The handler to be called when the read operation
completes. Copies will be made of the handler as required. The
function signature of the handler must be:
@code
void handler(
error_code const& error // Result of operation
);
@endcode
Regardless of whether the asynchronous operation completes
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class WriteHandler>
#if GENERATING_DOCS
void_or_deduced
#else
typename async_completion<
WriteHandler, void(error_code)>::result_type
#endif
async_pong(ping_data const& payload, WriteHandler&& handler);
/** Read a message from the stream.

View File

@ -910,6 +910,9 @@ public:
}
ws.set_option(pong_callback{});
// send pong
ws.pong("");
// send auto fragmented message
ws.set_option(auto_fragment{true});
ws.set_option(write_buffer_size{8});
@ -1172,6 +1175,9 @@ public:
ws.set_option(pong_callback{});
}
// send pong
ws.async_pong("", do_yield[ec]);
// send auto fragmented message
ws.set_option(auto_fragment{true});
ws.set_option(write_buffer_size{8});