diff --git a/src/shrpx.cc b/src/shrpx.cc index fa10ee55..354cf35c 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -151,6 +151,11 @@ namespace { void evlistener_errorcb(evconnlistener *listener, void *ptr) { LOG(ERROR) << "Accepting incoming connection failed"; + + auto listener_handler = static_cast(ptr); + + listener_handler->disable_evlistener_temporary + (&get_config()->listener_disable_timeout); } } // namespace @@ -449,6 +454,8 @@ void graceful_shutdown_signal_cb(evutil_socket_t sig, short events, void *arg) LOG(INFO) << "Graceful shutdown signal received"; } + worker_config->graceful_shutdown = true; + listener_handler->disable_evlistener(); // After disabling accepting new connection, disptach incoming @@ -456,8 +463,6 @@ void graceful_shutdown_signal_cb(evutil_socket_t sig, short events, void *arg) listener_handler->accept_pending_connection(); - worker_config->graceful_shutdown = true; - listener_handler->graceful_shutdown_worker(); } } // namespace @@ -809,6 +814,7 @@ void fill_default_config() mod_config()->argc = 0; mod_config()->argv = nullptr; mod_config()->max_downstream_connections = 100; + mod_config()->listener_disable_timeout = {0, 0}; } } // namespace @@ -977,6 +983,12 @@ Timeout: connection. Default: )" << get_config()->downstream_idle_read_timeout.tv_sec << R"( + --listener-disable-timeout= + After accepting connection failed, connection + listener is disabled for a given time in seconds. + Specifying 0 disables this feature. + Default: )" + << get_config()->listener_disable_timeout.tv_sec << R"( --backend-http-proxy-uri= Specify proxy URI in the form http://[:@]:. If a @@ -1297,6 +1309,7 @@ int main(int argc, char **argv) {"stream-write-timeout", required_argument, &flag, 61}, {"no-location-rewrite", no_argument, &flag, 62}, {"backend-connections-per-frontend", required_argument, &flag, 63}, + {"listener-disable-timeout", required_argument, &flag, 64}, {nullptr, 0, nullptr, 0 } }; @@ -1590,6 +1603,10 @@ int main(int argc, char **argv) cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_CONNECTIONS_PER_FRONTEND, optarg); break; + case 64: + // --listener-disable-timeout + cmdcfgs.emplace_back(SHRPX_OPT_LISTENER_DISABLE_TIMEOUT, optarg); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index d0b29288..b523c4c8 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -131,6 +131,7 @@ const char SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS[] = const char SHRPX_OPT_NO_LOCATION_REWRITE[] = "no-location-rewrite"; const char SHRPX_OPT_BACKEND_CONNECTIONS_PER_FRONTEND[] = "backend-connections-per-frontend"; +const char SHRPX_OPT_LISTENER_DISABLE_TIMEOUT[] = "listener-disable-timeout"; namespace { Config *config = nullptr; @@ -897,6 +898,13 @@ int parse_config(const char *opt, const char *optarg) return 0; } + if(util::strieq(opt, SHRPX_OPT_LISTENER_DISABLE_TIMEOUT)) { + timeval tv = {strtol(optarg, nullptr, 10), 0}; + mod_config()->listener_disable_timeout = tv; + + return 0; + } + if(util::strieq(opt, "conf")) { LOG(WARNING) << "conf is ignored"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index a74597e8..7d1aed20 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -120,6 +120,7 @@ extern const char SHRPX_OPT_ADD_RESPONSE_HEADER[]; extern const char SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS[]; extern const char SHRPX_OPT_NO_LOCATION_REWRITE[]; extern const char SHRPX_OPT_BACKEND_CONNECTIONS_PER_FRONTEND[]; +extern const char SHRPX_OPT_LISTENER_DISABLE_TIMEOUT[]; union sockaddr_union { sockaddr sa; @@ -173,6 +174,7 @@ struct Config { timeval stream_read_timeout; timeval stream_write_timeout; timeval downstream_idle_read_timeout; + timeval listener_disable_timeout; std::unique_ptr host; std::unique_ptr private_key_file; std::unique_ptr private_key_passwd; diff --git a/src/shrpx_listen_handler.cc b/src/shrpx_listen_handler.cc index 70cf3f4c..f3dfb4d6 100644 --- a/src/shrpx_listen_handler.cc +++ b/src/shrpx_listen_handler.cc @@ -45,6 +45,21 @@ using namespace nghttp2; namespace shrpx { +namespace { +void evlistener_disable_cb(evutil_socket_t fd, short events, void *arg) +{ + auto listener_handler = static_cast(arg); + + // If we are in graceful shutdown period, we must not enable + // evlisteners again. + if(worker_config->graceful_shutdown) { + return; + } + + listener_handler->enable_evlistener(); +} +} // namespace + ListenHandler::ListenHandler(event_base *evbase, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx) : evbase_(evbase), @@ -54,6 +69,8 @@ ListenHandler::ListenHandler(event_base *evbase, SSL_CTX *sv_ssl_ctx, (evbase, get_config()->worker_rate_limit_cfg)), evlistener4_(nullptr), evlistener6_(nullptr), + evlistener_disable_timerev_(evtimer_new(evbase, + evlistener_disable_cb, this)), worker_stat_(util::make_unique()), num_worker_shutdown_(0), worker_round_robin_cnt_(0) @@ -295,6 +312,17 @@ evconnlistener* ListenHandler::get_evlistener6() const return evlistener6_; } +void ListenHandler::enable_evlistener() +{ + if(evlistener4_) { + evconnlistener_enable(evlistener4_); + } + + if(evlistener6_) { + evconnlistener_enable(evlistener6_); + } +} + void ListenHandler::disable_evlistener() { if(evlistener4_) { @@ -306,6 +334,24 @@ void ListenHandler::disable_evlistener() } } +void ListenHandler::disable_evlistener_temporary(const timeval *timeout) +{ + int rv; + + if(timeout->tv_sec == 0 || + evtimer_pending(evlistener_disable_timerev_, nullptr)) { + return; + } + + disable_evlistener(); + + rv = evtimer_add(evlistener_disable_timerev_, timeout); + + if(rv < 0) { + LOG(ERROR) << "evtimer_add for evlistener_disable_timerev_ failed"; + } +} + namespace { void perform_accept_pending_connection(ListenHandler *listener_handler, evconnlistener *listener) diff --git a/src/shrpx_listen_handler.h b/src/shrpx_listen_handler.h index aa1b189e..64b77d0f 100644 --- a/src/shrpx_listen_handler.h +++ b/src/shrpx_listen_handler.h @@ -73,7 +73,9 @@ public: evconnlistener* get_evlistener4() const; void set_evlistener6(evconnlistener *evlistener6); evconnlistener* get_evlistener6() const; + void enable_evlistener(); void disable_evlistener(); + void disable_evlistener_temporary(const timeval *timeout); void accept_pending_connection(); void graceful_shutdown_worker(); void join_worker(); @@ -92,6 +94,7 @@ private: bufferevent_rate_limit_group *rate_limit_group_; evconnlistener *evlistener4_; evconnlistener *evlistener6_; + event *evlistener_disable_timerev_; std::unique_ptr worker_stat_; size_t num_worker_shutdown_; unsigned int worker_round_robin_cnt_;