From 0af9629cc1e1608646a023b99fa8be99ad66b999 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 3 Apr 2016 00:23:44 +0900 Subject: [PATCH] nghttpx: Fix crash with backend failure --- src/shrpx_http2_downstream_connection.cc | 3 --- src/shrpx_http2_session.cc | 33 +++++++++++++++++++----- src/shrpx_http2_session.h | 2 ++ 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/shrpx_http2_downstream_connection.cc b/src/shrpx_http2_downstream_connection.cc index 756180ef..a72422f5 100644 --- a/src/shrpx_http2_downstream_connection.cc +++ b/src/shrpx_http2_downstream_connection.cc @@ -97,9 +97,6 @@ int Http2DownstreamConnection::attach_downstream(Downstream *downstream) { http2session_->add_downstream_connection(this); if (http2session_->get_state() == Http2Session::DISCONNECTED) { http2session_->signal_write(); - if (http2session_->get_state() == Http2Session::DISCONNECTED) { - return -1; - } } downstream_ = downstream; diff --git a/src/shrpx_http2_session.cc b/src/shrpx_http2_session.cc index 38716faa..f18ada48 100644 --- a/src/shrpx_http2_session.cc +++ b/src/shrpx_http2_session.cc @@ -165,6 +165,22 @@ void writecb(struct ev_loop *loop, ev_io *w, int revents) { } } // namespace +namespace { +void initiate_connection_cb(struct ev_loop *loop, ev_timer *w, int revents) { + auto http2session = static_cast(w->data); + ev_timer_stop(loop, w); + if (http2session->initiate_connection() != 0) { + if (LOG_ENABLED(INFO)) { + SSLOG(INFO, http2session) << "Could not initiate backend connection"; + } + http2session->disconnect(true); + assert(http2session->get_num_dconns() == 0); + delete http2session; + return; + } +} +} // namespace + Http2Session::Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx, Worker *worker, DownstreamAddrGroup *group) : dlnext(nullptr), @@ -199,6 +215,9 @@ Http2Session::Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx, ev_timer_init(&settings_timer_, settings_timeout_cb, 0., 10.); settings_timer_.data = this; + + ev_timer_init(&initiate_connection_timer_, initiate_connection_cb, 0., 0.); + initiate_connection_timer_.data = this; } Http2Session::~Http2Session() { @@ -224,6 +243,7 @@ int Http2Session::disconnect(bool hard) { conn_.rlimit.stopw(); conn_.wlimit.stopw(); + ev_timer_stop(conn_.loop, &initiate_connection_timer_); ev_timer_stop(conn_.loop, &settings_timer_); ev_timer_stop(conn_.loop, &connchk_timer_); @@ -1600,14 +1620,15 @@ int Http2Session::downstream_write() { void Http2Session::signal_write() { switch (state_) { case Http2Session::DISCONNECTED: - if (LOG_ENABLED(INFO)) { - LOG(INFO) << "Start connecting to backend server"; - } - if (initiate_connection() != 0) { + if (!ev_is_active(&initiate_connection_timer_)) { if (LOG_ENABLED(INFO)) { - SSLOG(INFO, this) << "Could not initiate backend connection"; + LOG(INFO) << "Start connecting to backend server"; } - disconnect(true); + // Since the timer is set to 0., these will feed 2 events. We + // will stop the timer in the initiate_connection_timer_ to void + // 2nd event. + ev_timer_start(conn_.loop, &initiate_connection_timer_); + ev_feed_event(conn_.loop, &initiate_connection_timer_, 0); } break; case Http2Session::CONNECTED: diff --git a/src/shrpx_http2_session.h b/src/shrpx_http2_session.h index ecea8886..16fbac1d 100644 --- a/src/shrpx_http2_session.h +++ b/src/shrpx_http2_session.h @@ -211,6 +211,8 @@ private: // connection check has started, this timer is started again and // traps PING ACK timeout. ev_timer connchk_timer_; + // timer to initiate connection. usually, this fires immediately. + ev_timer initiate_connection_timer_; DList dconns_; DList streams_; std::function read_, write_;