55
66#include < netinet/in.h>
77
8- #include < csignal>
98#include < cstdint>
109#include < cstdlib>
1110#include < cstring>
1211#include < deque>
1312#include < exception>
1413#include < filesystem>
1514#include < fstream>
15+ #include < functional>
1616#include < ios>
1717#include < iterator>
1818#include < limits>
2727
2828#include " boost/asio/io_context.hpp"
2929#include " boost/asio/ip/tcp.hpp"
30- #include " boost/asio/signal_set.hpp"
3130#include " boost/asio/strand.hpp"
3231#include " boost/beast/core.hpp"
3332#include " boost/beast/http.hpp"
@@ -191,6 +190,8 @@ static WebSocketRequest parse_web_socket_request(const std::string& msg)
191190 } else if (type_str == " list_dir" ) {
192191 req.type = WebSocketRequest::kListDir ;
193192 req.dir_path = extract_string (msg, " path" );
193+ } else if (type_str == " server_exit" ) {
194+ req.type = WebSocketRequest::kServerExit ;
194195 } else {
195196 req.type = WebSocketRequest::kUnknown ;
196197 }
@@ -347,13 +348,16 @@ class WebSocketSession : public std::enable_shared_from_this<WebSocketSession>
347348 std::shared_ptr<TileGenerator> generator_;
348349 std::thread init_thread_;
349350
351+ std::function<void ()> shutdown_cb_;
352+
350353 public:
351354 WebSocketSession (Tcp::socket&& socket,
352355 std::shared_ptr<TileGenerator> generator,
353356 std::shared_ptr<TclEvaluator> tcl_eval,
354357 std::shared_ptr<TimingReport> timing_report,
355358 std::shared_ptr<ClockTreeReport> clock_report,
356- utl::Logger* logger);
359+ utl::Logger* logger,
360+ std::function<void ()> shutdown_cb);
357361 ~WebSocketSession ();
358362
359363 void run (http::request<http::string_body>&& req);
@@ -374,7 +378,8 @@ WebSocketSession::WebSocketSession(
374378 // NOLINTEND(performance-unnecessary-value-param)
375379 std::shared_ptr<TimingReport> timing_report,
376380 std::shared_ptr<ClockTreeReport> clock_report,
377- utl::Logger* logger)
381+ utl::Logger* logger,
382+ std::function<void ()> shutdown_cb)
378383 : websocket_(std::move(socket)),
379384 logger_ (logger),
380385 select_handler_(generator, tcl_eval),
@@ -384,7 +389,8 @@ WebSocketSession::WebSocketSession(
384389 tile_handler_(generator),
385390 drc_handler_(generator),
386391 strand_(net::make_strand(websocket_.get_executor())),
387- generator_(std::move(generator))
392+ generator_(std::move(generator)),
393+ shutdown_cb_(std::move(shutdown_cb))
388394{
389395 if (generator_->getBlock ()) {
390396 tile_handler_.initializeHeatMaps (state_);
@@ -698,6 +704,11 @@ void WebSocketSession::on_read(beast::error_code ec)
698704 self->drc_handler_ .handleDRCHighlight (req, self->state_ ));
699705 });
700706 break ;
707+ case WebSocketRequest::kServerExit :
708+ if (shutdown_cb_) {
709+ shutdown_cb_ ();
710+ }
711+ return ;
701712 default :
702713 net::post (websocket_.get_executor (),
703714 [self = std::move (self), req = std::move (req)]() {
@@ -881,6 +892,7 @@ class DetectSession : public std::enable_shared_from_this<DetectSession>
881892 http::request<http::string_body> req_;
882893 std::string doc_root_;
883894 utl::Logger* logger_;
895+ std::function<void ()> shutdown_cb_;
884896
885897 public:
886898 DetectSession (Tcp::socket&& socket,
@@ -889,7 +901,8 @@ class DetectSession : public std::enable_shared_from_this<DetectSession>
889901 std::shared_ptr<TimingReport> timing_report,
890902 std::shared_ptr<ClockTreeReport> clock_report,
891903 std::string doc_root,
892- utl::Logger* logger);
904+ utl::Logger* logger,
905+ std::function<void ()> shutdown_cb);
893906
894907 void run ();
895908
@@ -903,14 +916,16 @@ DetectSession::DetectSession(Tcp::socket&& socket,
903916 std::shared_ptr<TimingReport> timing_report,
904917 std::shared_ptr<ClockTreeReport> clock_report,
905918 std::string doc_root,
906- utl::Logger* logger)
919+ utl::Logger* logger,
920+ std::function<void ()> shutdown_cb)
907921 : stream_(std::move(socket)),
908922 generator_(std::move(generator)),
909923 tcl_eval_(std::move(tcl_eval)),
910924 timing_report_(std::move(timing_report)),
911925 clock_report_(std::move(clock_report)),
912926 doc_root_(std::move(doc_root)),
913- logger_(logger)
927+ logger_(logger),
928+ shutdown_cb_(std::move(shutdown_cb))
914929{
915930}
916931
@@ -941,7 +956,8 @@ void DetectSession::on_read(beast::error_code ec)
941956 tcl_eval_,
942957 timing_report_,
943958 clock_report_,
944- logger_);
959+ logger_,
960+ shutdown_cb_);
945961 websocket_session->run (std::move (req_));
946962 } else {
947963 // Regular HTTP - hand off to session with already-read request
@@ -965,6 +981,7 @@ class Listener : public std::enable_shared_from_this<Listener>
965981 std::shared_ptr<ClockTreeReport> clock_report_;
966982 std::string doc_root_;
967983 utl::Logger* logger_;
984+ std::function<void ()> shutdown_cb_;
968985
969986 public:
970987 Listener (net::io_context& ioc,
@@ -974,7 +991,8 @@ class Listener : public std::enable_shared_from_this<Listener>
974991 std::shared_ptr<TimingReport> timing_report,
975992 std::shared_ptr<ClockTreeReport> clock_report,
976993 std::string doc_root,
977- utl::Logger* logger);
994+ utl::Logger* logger,
995+ std::function<void ()> shutdown_cb);
978996
979997 void run () { do_accept (); }
980998
@@ -990,15 +1008,17 @@ Listener::Listener(net::io_context& ioc,
9901008 std::shared_ptr<TimingReport> timing_report,
9911009 std::shared_ptr<ClockTreeReport> clock_report,
9921010 std::string doc_root,
993- utl::Logger* logger)
1011+ utl::Logger* logger,
1012+ std::function<void ()> shutdown_cb)
9941013 : ioc_(ioc),
9951014 acceptor_(ioc),
9961015 generator_(std::move(generator)),
9971016 tcl_eval_(std::move(tcl_eval)),
9981017 timing_report_(std::move(timing_report)),
9991018 clock_report_(std::move(clock_report)),
10001019 doc_root_(std::move(doc_root)),
1001- logger_(logger)
1020+ logger_(logger),
1021+ shutdown_cb_(std::move(shutdown_cb))
10021022{
10031023 beast::error_code ec;
10041024
@@ -1049,7 +1069,8 @@ void Listener::on_accept(beast::error_code ec, Tcp::socket socket)
10491069 timing_report_,
10501070 clock_report_,
10511071 doc_root_,
1052- logger_)
1072+ logger_,
1073+ shutdown_cb_)
10531074 ->run ();
10541075 }
10551076 do_accept ();
@@ -1389,22 +1410,22 @@ void WebServer::serve(int port, const std::string& doc_root)
13891410
13901411 net::io_context ioc{num_threads};
13911412
1413+ auto shutdown_cb = [this , &ioc]() {
1414+ logger_->info (utl::WEB , 3 , " Shutting down..." );
1415+ ioc.stop ();
1416+ };
1417+
13921418 std::make_shared<Listener>(ioc,
13931419 Tcp::endpoint{address, u_port},
13941420 generator_,
13951421 tcl_eval,
13961422 timing_report,
13971423 clock_report,
13981424 doc_root,
1399- logger_)
1425+ logger_,
1426+ shutdown_cb)
14001427 ->run ();
14011428
1402- net::signal_set signals (ioc, SIGINT , SIGTERM );
1403- signals.async_wait ([&](auto , auto ) {
1404- logger_->info (utl::WEB , 3 , " Shutting down..." );
1405- ioc.stop ();
1406- });
1407-
14081429 std::vector<std::thread> threads;
14091430 threads.reserve (num_threads - 1 );
14101431 for (int i = 0 ; i < num_threads - 1 ; ++i) {
@@ -1417,6 +1438,7 @@ void WebServer::serve(int port, const std::string& doc_root)
14171438 t.join ();
14181439 }
14191440
1441+ Tcl_ResetResult (interp_);
14201442 logger_->info (utl::WEB , 5 , " Server stopped." );
14211443 } catch (std::exception const & e) {
14221444 logger_->error (utl::WEB , 2 , " Server error : {}" , e.what ());
0 commit comments