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; }