Skip to content

Commit 2c3d714

Browse files
author
Peter Thorson
committed
[improvement] Improve error handling options for get_connection and start_accept. Update docs. fixes #896
1 parent a04fb34 commit 2c3d714

File tree

14 files changed

+520
-28
lines changed

14 files changed

+520
-28
lines changed

changelog.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,20 @@ HEAD
1717
compliant URIs when IPv6 literals are involved. Thank you Jeff Davie,
1818
thorsten-klein, mstaz, and barsnick for reporting, example patches, and
1919
testing. #601 #879
20+
- Improvement: The error handling system for the server role's async start
21+
accept loop and connection generation has been significantly improved.
22+
`endpoint::get_connection` now takes an output parameter ec that gives
23+
a detailed error code if connection creation fails. `endpoint::start_accept`
24+
now accepts a handler function as a parameter instead of an error code.
25+
This handler function allows the client program to be alerted when the
26+
async accept loop stops (for any reason, including explicit cancellation)
27+
at any time. Previously, it was only possible to tell if the initial loop
28+
start had failed, making it difficult to tell when/if the async accept loop
29+
needed to be restarted. The loop handler returns two error codes, a higher
30+
level library code and a second more specific transport level code. The
31+
old `endpoint::get_connection` and `endpoint::start_accept` functions
32+
remain for backwards compatibility but are deprecated. Thank you Oleh
33+
Derevenko for reporting. #896
2034
- Improvement: Cancel ping timer before calling blocking pong handler.
2135
This should reduce any unnecessary expiration logic done to a timer
2236
that is going to be cancelled regardless. Thank you Oleh Derevenko

docs/handlers.dox

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,27 @@ that fail will never have a close handler called.
105105
Close will be called exactly once for every connection that open was called for.
106106
Close is not called for failed connections.
107107

108+
Endpoint Handlers
109+
-----------------
110+
111+
## Acceptance Loop End Handler
112+
113+
| Event | Signature | Availability |
114+
| ------------------------------------- | --------------------------------------------------------------------- | ---------------------------- |
115+
| Async Accept Loop end (after opening) | `accept_loop(void(lib::error_code const &, lib::error_code const &))` | 0.9.0 Core, Server role only |
116+
117+
This handler is passed to the `endpoint::start_accept()` function, which initiates an
118+
asyncronous loop that accepts new connections, and is invoked when that loop ends. The
119+
handler will be called exactly once for each call of `start_accept` no matter when or
120+
how it exits (it might exit immediately).
121+
122+
The handler may be called inside the call to `start_accept` if that function has enough
123+
information to determine that accepting connections will be impossible. Otherwise, it
124+
may be invoked at a later time from a different asyncronous handler.
125+
126+
The handler returns two error codes. The first from the core library and the second a
127+
more detailed code passed through from the underlying transport.
128+
108129
Message Handlers
109130
----------------
110131

examples/simple_broadcast_server/simple_broadcast_server.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ using websocketpp::connection_hdl;
88
using websocketpp::lib::placeholders::_1;
99
using websocketpp::lib::placeholders::_2;
1010
using websocketpp::lib::bind;
11+
using websocketpp::lib::error_code;
1112

1213
class broadcast_server {
1314
public:
@@ -27,6 +28,11 @@ class broadcast_server {
2728
m_connections.erase(hdl);
2829
}
2930

31+
void on_end_accept(error_code lib_ec, error_code trans_ec) {
32+
std::cout << "Accept loop ended "
33+
<< lib_ec.message() << "/" << trans_ec.message() << std::endl;
34+
}
35+
3036
void on_message(connection_hdl hdl, server::message_ptr msg) {
3137
for (auto it : m_connections) {
3238
m_server.send(it,msg);
@@ -35,7 +41,7 @@ class broadcast_server {
3541

3642
void run(uint16_t port) {
3743
m_server.listen(port);
38-
m_server.start_accept();
44+
m_server.start_accept(bind(&broadcast_server::on_end_accept,this,::_1,::_2));
3945
m_server.run();
4046
}
4147
private:

examples/subprotocol_server/subprotocol_server.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ int main() {
3939

4040
s.init_asio();
4141
s.listen(9005);
42-
s.start_accept();
42+
s.start_accept(NULL); // omit error handling to keep example consise
4343

4444
s.run();
4545
} catch (websocketpp::exception const & e) {

examples/telemetry_server/telemetry_server.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
#include <streambuf>
99
#include <string>
1010

11+
using websocketpp::lib::placeholders::_1;
12+
using websocketpp::lib::placeholders::_2;
13+
using websocketpp::lib::bind;
14+
using websocketpp::lib::error_code;
15+
1116
/**
1217
* The telemetry server accepts connections and sends a message every second to
1318
* each client containing an integer count. This example can be used as the
@@ -43,8 +48,6 @@ class telemetry_server {
4348
m_endpoint.init_asio();
4449

4550
// Bind the handlers we are using
46-
using websocketpp::lib::placeholders::_1;
47-
using websocketpp::lib::bind;
4851
m_endpoint.set_open_handler(bind(&telemetry_server::on_open,this,_1));
4952
m_endpoint.set_close_handler(bind(&telemetry_server::on_close,this,_1));
5053
m_endpoint.set_http_handler(bind(&telemetry_server::on_http,this,_1));
@@ -61,7 +64,7 @@ class telemetry_server {
6164
m_endpoint.listen(port);
6265

6366
// Start the server accept loop
64-
m_endpoint.start_accept();
67+
m_endpoint.start_accept(bind(&telemetry_server::on_end_accept,this,_1,_2));
6568

6669
// Set the initial timer to start telemetry
6770
set_timer();
@@ -85,7 +88,7 @@ class telemetry_server {
8588
);
8689
}
8790

88-
void on_timer(websocketpp::lib::error_code const & ec) {
91+
void on_timer(error_code const & ec) {
8992
if (ec) {
9093
// there was an error, stop telemetry
9194
m_endpoint.get_alog().write(websocketpp::log::alevel::app,
@@ -149,7 +152,7 @@ class telemetry_server {
149152
response.assign((std::istreambuf_iterator<char>(file)),
150153
std::istreambuf_iterator<char>());
151154

152-
con->set_body(response);
155+
con->set_body(std::move(response));
153156
con->set_status(websocketpp::http::status_code::ok);
154157
}
155158

@@ -160,6 +163,11 @@ class telemetry_server {
160163
void on_close(connection_hdl hdl) {
161164
m_connections.erase(hdl);
162165
}
166+
167+
void on_end_accept(error_code lib_ec, error_code trans_ec) {
168+
std::cout << "Accept loop ended "
169+
<< lib_ec.message() << "/" << trans_ec.message() << std::endl;
170+
}
163171
private:
164172
typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;
165173

examples/testee_server/testee_server.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ typedef websocketpp::server<testee_config> server;
7878
using websocketpp::lib::placeholders::_1;
7979
using websocketpp::lib::placeholders::_2;
8080
using websocketpp::lib::bind;
81+
using websocketpp::lib::error_code;
8182

8283
// pull out the type of messages sent by our config
8384
typedef server::message_ptr message_ptr;
@@ -92,6 +93,12 @@ void on_socket_init(websocketpp::connection_hdl, boost::asio::ip::tcp::socket &
9293
s.set_option(option);
9394
}
9495

96+
// Define a callback to handle failures accepting connections
97+
void on_end_accept(error_code lib_ec, error_code trans_ec) {
98+
std::cout << "Accept loop ended "
99+
<< lib_ec.message() << "/" << trans_ec.message() << std::endl;
100+
}
101+
95102
int main(int argc, char * argv[]) {
96103
// Create a server endpoint
97104
server testee_server;
@@ -122,7 +129,7 @@ int main(int argc, char * argv[]) {
122129
testee_server.listen(port);
123130

124131
// Start the server accept loop
125-
testee_server.start_accept();
132+
testee_server.start_accept(&on_end_accept);
126133

127134
// Start the ASIO io_service run loop
128135
if (num_threads == 1) {

0 commit comments

Comments
 (0)