diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6f198f1f..65be5b43 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@ Version 158:
* Tidy up end_of_stream javadoc
* Tidy up websocket docs
* Examples set reuse_address(true)
+* Advanced servers support clean shutdown via SIGINT or SIGTERM
--------------------------------------------------------------------------------
diff --git a/doc/qbk/00_main.qbk b/doc/qbk/00_main.qbk
index d6849f92..3c9e4555 100644
--- a/doc/qbk/00_main.qbk
+++ b/doc/qbk/00_main.qbk
@@ -28,7 +28,7 @@
[template source_file[path] ''''''[path]'''''']
[template include_file[path][^<''''''[path]''''''>]]
-[template issue[n] '''(#'''[n]''')''']
+[template issue[n] '''#'''[n]'''''']
[def __N3747__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3747.pdf [*N3747]]]
[def __NetTS__ [@http://cplusplus.github.io/networking-ts/draft.pdf [*Networking.TS]]]
diff --git a/doc/qbk/02_examples.qbk b/doc/qbk/02_examples.qbk
index 16196f59..22d0fb14 100644
--- a/doc/qbk/02_examples.qbk
+++ b/doc/qbk/02_examples.qbk
@@ -180,7 +180,9 @@ and illustrate the implementation of advanced features.
[HTTP pipelining]
[Asynchronous timeouts]
[Dual protocols: HTTP and WebSocket]
- [WebSocket use idle ping for timeout]]]
+ [WebSocket use idle ping for timeout]
+ [Clean exit via SIGINT (CTRL+C) or SIGTERM (kill)]
+ ]]
[[example_src example/advanced/server/advanced_server.cpp advanced_server.cpp]]
][
[Advanced, flex (plain + SSL)]
@@ -189,7 +191,9 @@ and illustrate the implementation of advanced features.
[Asynchronous timeouts]
[Dual protocols: HTTP and WebSocket]
[WebSocket use idle ping for timeout]
- [Flexible ports: plain and SSL on the same port]]]
+ [Flexible ports: plain and SSL on the same port]
+ [Clean exit via SIGINT (CTRL+C) or SIGTERM (kill)]
+ ]]
[[example_src example/advanced/server-flex/advanced_server_flex.cpp advanced_server_flex.cpp]]
]]
diff --git a/doc/qbk/09_releases.qbk b/doc/qbk/09_releases.qbk
index 5fbf0813..85197fad 100644
--- a/doc/qbk/09_releases.qbk
+++ b/doc/qbk/09_releases.qbk
@@ -20,9 +20,9 @@ to update to the latest Boost release.
* Move-only completion handlers are supported throughout the library
-* [issue 899] Advanced server examples support idle websocket pings and timeouts
+* ([issue 899]) Advanced server examples support idle websocket pings and timeouts
-* [issue 849] WebSocket permessage-deflate support is now a compile-time
+* ([issue 849]) WebSocket permessage-deflate support is now a compile-time
feature. This adds an additional `bool` template parameter to
[link beast.ref.boost__beast__websocket__stream `websocket::stream`]
When `deflateSupported` is `true`, the stream will be capable of
@@ -34,7 +34,7 @@ to update to the latest Boost release.
will be excluded from function instantiations. Programs which set
`deflateSupported` to `false` when instantiating streams will be smaller.
-* [issue 949] WebSocket error codes are revised. New
+* ([issue 949]) WebSocket error codes are revised. New
[link beast.ref.boost__beast__websocket__error error codes]
are added for more fine-grained failure outcomes. Messages for error
codes are more verbose to help pinpoint the problem. Error codes are
@@ -56,11 +56,11 @@ to update to the latest Boost release.
[*Improvements]
-* [issue 857]
+* ([issue 857])
[link beast.ref.boost__beast__http__basic_fields `http::basic_fields`]
uses less storage
-* [issue 894]
+* ([issue 894])
[link beast.ref.boost__beast__http__basic_fields `http::basic_fields`]
exception specifiers are provided
@@ -68,45 +68,47 @@ to update to the latest Boost release.
* Add [include_file boost/beast/websocket/stream_fwd.hpp]
-* [issue 955] The asynchronous SSL detector example uses a stackless coroutine
+* ([issue 955]) The asynchronous SSL detector example uses a stackless coroutine
* [link beast.ref.boost__beast__bind_handler `bind_handler`]
works with boost placeholders
* Examples set `reuse_address(true)`
+* ([issue 1026]) Advanced servers support clean shutdown via SIGINT or SIGTERM
+
[*Fixes]
* Fix "warning: ‘const’ type qualifier on return type has no effect"
-* [issue 916] Tidy up `ssl_stream` special members in
+* ([issue 916]) Tidy up `ssl_stream` special members in
[source_file example/common/ssl_stream.hpp]
-* [issue 918] Calls to `` are protected from macros
+* ([issue 918]) Calls to `` are protected from macros
-* [issue 954] The control callback is invoked on the proper executor
+* ([issue 954]) The control callback is invoked on the proper executor
-* [issue 994] Fix iterator version of
+* ([issue 994]) Fix iterator version of
[link beast.ref.boost__beast__http__basic_fields.erase.overload1 `http::basic_fields::erase`]
-* [issue 992] Fix use-after-move in example request handlers
+* ([issue 992]) Fix use-after-move in example request handlers
-* [issue 988] Type check completion handlers
+* ([issue 988]) Type check completion handlers
-* [issue 985] Tidy up
+* ([issue 985]) Tidy up
[link beast.ref.boost__beast__bind_handler `bind_handler`]
doc
* Fix memory leak in advanced server examples
-* [issue 1000] Fix soft-mutex assert in websocket stream.
+* ([issue 1000]) Fix soft-mutex assert in websocket stream.
This resolves the assert `"ws_.wr_block_ == tok_"`.
-* [issue 1019] Fix fallthrough warnings
+* ([issue 1019]) Fix fallthrough warnings
-* [issue 1024] Fix teardown for TIME_WAIT
+* ([issue 1024]) Fix teardown for TIME_WAIT
-* [issue 1030] Fix big-endian websocket masking
+* ([issue 1030]) Fix big-endian websocket masking
[*API Changes]
@@ -126,19 +128,19 @@ to update to the latest Boost release.
constructor signature for state objects used with `handler_ptr`
to receive a `const` reference to the handler.
-* [issue 896]
+* ([issue 896])
[link beast.ref.boost__beast__http__basic_fields `http::basic_fields`]
does not support fancy pointers
* [link beast.ref.boost__beast__http__parser `http::parser`]
is no longer [*MoveConstructible]
-* [issue 930] `http::serializer::reader_impl` is deprecated and will
+* ([issue 930]) `http::serializer::reader_impl` is deprecated and will
be removed in the next release. Actions required: Call
[link beast.ref.boost__beast__http__serializer.writer_impl `http::serializer::writer_impl`]
instead of `serializer::reader_impl`.
-* [issue 884] The __BodyReader__ and __BodyWriter__ concept constructor
+* ([issue 884]) The __BodyReader__ and __BodyWriter__ concept constructor
requirements have changed. They now require the header and body
elements to be passed as distinct
[link beast.ref.boost__beast__http__header `http::header`]
diff --git a/example/advanced/server-flex/advanced_server_flex.cpp b/example/advanced/server-flex/advanced_server_flex.cpp
index 211b6ca0..4bb04685 100644
--- a/example/advanced/server-flex/advanced_server_flex.cpp
+++ b/example/advanced/server-flex/advanced_server_flex.cpp
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -1272,6 +1273,17 @@ int main(int argc, char* argv[])
tcp::endpoint{address, port},
doc_root)->run();
+ // Capture SIGINT and SIGTERM to perform a clean shutdown
+ boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);
+ signals.async_wait(
+ [&](boost::system::error_code const&, int)
+ {
+ // Stop the `io_context`. This will cause `run()`
+ // to return immediately, eventually destroying the
+ // `io_context` and all of the sockets in it.
+ ioc.stop();
+ });
+
// Run the I/O service on the requested number of threads
std::vector v;
v.reserve(threads - 1);
@@ -1283,5 +1295,11 @@ int main(int argc, char* argv[])
});
ioc.run();
+ // (If we get here, it means we got a SIGINT or SIGTERM)
+
+ // Block until all the threads exit
+ for(auto& t : v)
+ t.join();
+
return EXIT_SUCCESS;
}
diff --git a/example/advanced/server/advanced_server.cpp b/example/advanced/server/advanced_server.cpp
index 8caa72c5..b3d91b3d 100644
--- a/example/advanced/server/advanced_server.cpp
+++ b/example/advanced/server/advanced_server.cpp
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -815,6 +816,17 @@ int main(int argc, char* argv[])
tcp::endpoint{address, port},
doc_root)->run();
+ // Capture SIGINT and SIGTERM to perform a clean shutdown
+ boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);
+ signals.async_wait(
+ [&](boost::system::error_code const&, int)
+ {
+ // Stop the `io_context`. This will cause `run()`
+ // to return immediately, eventually destroying the
+ // `io_context` and all of the sockets in it.
+ ioc.stop();
+ });
+
// Run the I/O service on the requested number of threads
std::vector v;
v.reserve(threads - 1);
@@ -826,5 +838,11 @@ int main(int argc, char* argv[])
});
ioc.run();
+ // (If we get here, it means we got a SIGINT or SIGTERM)
+
+ // Block until all the threads exit
+ for(auto& t : v)
+ t.join();
+
return EXIT_SUCCESS;
}