From 41f7effe26189d829c05d9ccce7ced21e32ac113 Mon Sep 17 00:00:00 2001 From: gulliver Date: Mon, 14 Oct 2024 15:35:02 +0200 Subject: [PATCH 1/2] added wait timeout to server start --- include/crow/app.h | 27 ++++++++++++++++++++------- include/crow/http_server.h | 11 +++++++---- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/include/crow/app.h b/include/crow/app.h index 25592da69..82d099205 100644 --- a/include/crow/app.h +++ b/include/crow/app.h @@ -703,19 +703,32 @@ namespace crow } /// \brief Wait until the server has properly started - void wait_for_server_start() + std::cv_status wait_for_server_start(std::chrono::milliseconds wait_timeout = std::chrono::milliseconds(3000)) { + std::cv_status status = std::cv_status::no_timeout; + auto wait_until = std::chrono::steady_clock::now() + wait_timeout; { std::unique_lock lock(start_mutex_); - while (!server_started_) - cv_started_.wait(lock); + while (!server_started_ && (status == std::cv_status::no_timeout)) + { + status = cv_started_.wait_until(lock, wait_until); + } } - if (server_) - server_->wait_for_start(); + + if (status == std::cv_status::no_timeout) + { + if (server_) + { + status = server_->wait_for_start(wait_until); + } #ifdef CROW_ENABLE_SSL - else if (ssl_server_) - ssl_server_->wait_for_start(); + else if (ssl_server_) + { + status = ssl_server_->wait_for_start(wait_until); + } #endif + } + return status; } private: diff --git a/include/crow/http_server.h b/include/crow/http_server.h index 6834a2637..90c95364d 100644 --- a/include/crow/http_server.h +++ b/include/crow/http_server.h @@ -196,12 +196,15 @@ namespace crow // NOTE: Already documented in "crow/app.h" return acceptor_.local_endpoint().port(); } - /// Wait until the server has properly started - void wait_for_start() + /// Wait until the server has properly started or until timeout + std::cv_status wait_for_start(std::chrono::steady_clock::time_point wait_until) { std::unique_lock lock(start_mutex_); - while (!server_started_) - cv_started_.wait(lock); + + std::cv_status status = std::cv_status::no_timeout; + while (!server_started_ && ( status==std::cv_status::no_timeout )) + status = cv_started_.wait_until(lock,wait_until); + return status; } void signal_clear() From 8d6a100e0c3149f8cf6147c5a189dbe21afd35d1 Mon Sep 17 00:00:00 2001 From: Gulliver Date: Mon, 25 Nov 2024 21:28:19 +0100 Subject: [PATCH 2/2] tcp endpoint created before server creation, invalid address error is logged now, server runs into timeout in that case added testcase for invalid address --- include/crow/app.h | 13 ++++++++++--- include/crow/http_server.h | 17 +++++++---------- tests/unittest.cpp | 23 ++++++++++++++++++++--- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/include/crow/app.h b/include/crow/app.h index 82d099205..4b25bc733 100644 --- a/include/crow/app.h +++ b/include/crow/app.h @@ -373,7 +373,7 @@ namespace crow } /// \brief Get the number of threads that server is using - std::uint16_t concurrency() + std::uint16_t concurrency() const { return concurrency_; } @@ -514,11 +514,18 @@ namespace crow #endif validate(); + error_code ec; + asio::ip::address addr = asio::ip::make_address(bindaddr_,ec); + if (ec){ + CROW_LOG_ERROR << ec.message() << " - Can not create valid ip address from string: \"" << bindaddr_ << "\""; + return; + } + tcp::endpoint endpoint(addr, port_); #ifdef CROW_ENABLE_SSL if (ssl_used_) { router_.using_ssl = true; - ssl_server_ = std::move(std::unique_ptr(new ssl_server_t(this, bindaddr_, port_, server_name_, &middlewares_, concurrency_, timeout_, &ssl_context_))); + ssl_server_ = std::move(std::unique_ptr(new ssl_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, &ssl_context_))); ssl_server_->set_tick_function(tick_interval_, tick_function_); ssl_server_->signal_clear(); for (auto snum : signals_) @@ -531,7 +538,7 @@ namespace crow else #endif { - server_ = std::move(std::unique_ptr(new server_t(this, bindaddr_, port_, server_name_, &middlewares_, concurrency_, timeout_, nullptr))); + server_ = std::move(std::unique_ptr(new server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr))); server_->set_tick_function(tick_interval_, tick_function_); for (auto snum : signals_) { diff --git a/include/crow/http_server.h b/include/crow/http_server.h index 90c95364d..e0205d911 100644 --- a/include/crow/http_server.h +++ b/include/crow/http_server.h @@ -42,16 +42,14 @@ namespace crow // NOTE: Already documented in "crow/app.h" class Server { public: - Server(Handler* handler, std::string bindaddr, uint16_t port, std::string server_name = std::string("Crow/") + VERSION, std::tuple* middlewares = nullptr, uint16_t concurrency = 1, uint8_t timeout = 5, typename Adaptor::context* adaptor_ctx = nullptr): - acceptor_(io_service_, tcp::endpoint(asio::ip::address::from_string(bindaddr), port)), + Server(Handler* handler, const tcp::endpoint& endpoint, std::string server_name = std::string("Crow/") + VERSION, std::tuple* middlewares = nullptr, uint16_t concurrency = 1, uint8_t timeout = 5, typename Adaptor::context* adaptor_ctx = nullptr): + acceptor_(io_service_, endpoint), signals_(io_service_), tick_timer_(io_service_), handler_(handler), concurrency_(concurrency), timeout_(timeout), server_name_(server_name), - port_(port), - bindaddr_(bindaddr), task_queue_length_pool_(concurrency_ - 1), middlewares_(middlewares), adaptor_ctx_(adaptor_ctx) @@ -150,11 +148,12 @@ namespace crow // NOTE: Already documented in "crow/app.h" }); } - port_ = acceptor_.local_endpoint().port(); - handler_->port(port_); + handler_->port(acceptor_.local_endpoint().port()); - CROW_LOG_INFO << server_name_ << " server is running at " << (handler_->ssl_used() ? "https://" : "http://") << bindaddr_ << ":" << acceptor_.local_endpoint().port() << " using " << concurrency_ << " threads"; + CROW_LOG_INFO << server_name_ + << " server is running at " << (handler_->ssl_used() ? "https://" : "http://") + << acceptor_.local_endpoint().address() << ":" << acceptor_.local_endpoint().port() << " using " << concurrency_ << " threads"; CROW_LOG_INFO << "Call `app.loglevel(crow::LogLevel::Warning)` to hide Info level logs."; signals_.async_wait( @@ -192,7 +191,7 @@ namespace crow // NOTE: Already documented in "crow/app.h" io_service_.stop(); // Close main io_service } - uint16_t port(){ + uint16_t port() const { return acceptor_.local_endpoint().port(); } @@ -293,8 +292,6 @@ namespace crow // NOTE: Already documented in "crow/app.h" uint16_t concurrency_{2}; std::uint8_t timeout_; std::string server_name_; - uint16_t port_; - std::string bindaddr_; std::vector> task_queue_length_pool_; std::chrono::milliseconds tick_interval_; diff --git a/tests/unittest.cpp b/tests/unittest.cpp index a029c514f..1e1ce67d1 100644 --- a/tests/unittest.cpp +++ b/tests/unittest.cpp @@ -643,7 +643,22 @@ TEST_CASE("server_handling_error_request") app.stop(); } // server_handling_error_request -TEST_CASE("server_dynamic_port_allication") +TEST_CASE("server_invalid_ip_address") +{ + SimpleApp app; + CROW_ROUTE(app, "/") + ([] { + return "A"; + }); + auto _ = app.bindaddr("192.").port(45451).run_async(); + auto state = app.wait_for_server_start(); + + // we should run into a timeout as the server will not started + CHECK(state==cv_status::timeout); +} // server_invalid_ip_address + + +TEST_CASE("server_dynamic_port_allocation") { SimpleApp app; CROW_ROUTE(app, "/") @@ -659,7 +674,7 @@ TEST_CASE("server_dynamic_port_allication") asio::ip::address::from_string(LOCALHOST_ADDRESS), app.port())); } app.stop(); -} // server_dynamic_port_allication +} // server_dynamic_port_allocation TEST_CASE("server_handling_error_request_http_version") { @@ -1520,7 +1535,9 @@ struct NullSimpleMiddleware TEST_CASE("middleware_simple") { App app; - decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451); + asio::ip::address adr = asio::ip::make_address(LOCALHOST_ADDRESS); + tcp::endpoint ep(adr,45451); + decltype(app)::server_t server(&app, ep); CROW_ROUTE(app, "/") ([&](const crow::request& req) { app.get_context(req);