nghttpx: Fix crash with backend failure

This commit is contained in:
Tatsuhiro Tsujikawa 2016-04-03 00:23:44 +09:00
parent 53989dc70c
commit 0af9629cc1
3 changed files with 29 additions and 9 deletions

View File

@ -97,9 +97,6 @@ int Http2DownstreamConnection::attach_downstream(Downstream *downstream) {
http2session_->add_downstream_connection(this); http2session_->add_downstream_connection(this);
if (http2session_->get_state() == Http2Session::DISCONNECTED) { if (http2session_->get_state() == Http2Session::DISCONNECTED) {
http2session_->signal_write(); http2session_->signal_write();
if (http2session_->get_state() == Http2Session::DISCONNECTED) {
return -1;
}
} }
downstream_ = downstream; downstream_ = downstream;

View File

@ -165,6 +165,22 @@ void writecb(struct ev_loop *loop, ev_io *w, int revents) {
} }
} // namespace } // namespace
namespace {
void initiate_connection_cb(struct ev_loop *loop, ev_timer *w, int revents) {
auto http2session = static_cast<Http2Session *>(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, Http2Session::Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx,
Worker *worker, DownstreamAddrGroup *group) Worker *worker, DownstreamAddrGroup *group)
: dlnext(nullptr), : 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.); ev_timer_init(&settings_timer_, settings_timeout_cb, 0., 10.);
settings_timer_.data = this; settings_timer_.data = this;
ev_timer_init(&initiate_connection_timer_, initiate_connection_cb, 0., 0.);
initiate_connection_timer_.data = this;
} }
Http2Session::~Http2Session() { Http2Session::~Http2Session() {
@ -224,6 +243,7 @@ int Http2Session::disconnect(bool hard) {
conn_.rlimit.stopw(); conn_.rlimit.stopw();
conn_.wlimit.stopw(); conn_.wlimit.stopw();
ev_timer_stop(conn_.loop, &initiate_connection_timer_);
ev_timer_stop(conn_.loop, &settings_timer_); ev_timer_stop(conn_.loop, &settings_timer_);
ev_timer_stop(conn_.loop, &connchk_timer_); ev_timer_stop(conn_.loop, &connchk_timer_);
@ -1600,14 +1620,15 @@ int Http2Session::downstream_write() {
void Http2Session::signal_write() { void Http2Session::signal_write() {
switch (state_) { switch (state_) {
case Http2Session::DISCONNECTED: case Http2Session::DISCONNECTED:
if (!ev_is_active(&initiate_connection_timer_)) {
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
LOG(INFO) << "Start connecting to backend server"; LOG(INFO) << "Start connecting to backend server";
} }
if (initiate_connection() != 0) { // Since the timer is set to 0., these will feed 2 events. We
if (LOG_ENABLED(INFO)) { // will stop the timer in the initiate_connection_timer_ to void
SSLOG(INFO, this) << "Could not initiate backend connection"; // 2nd event.
} ev_timer_start(conn_.loop, &initiate_connection_timer_);
disconnect(true); ev_feed_event(conn_.loop, &initiate_connection_timer_, 0);
} }
break; break;
case Http2Session::CONNECTED: case Http2Session::CONNECTED:

View File

@ -211,6 +211,8 @@ private:
// connection check has started, this timer is started again and // connection check has started, this timer is started again and
// traps PING ACK timeout. // traps PING ACK timeout.
ev_timer connchk_timer_; ev_timer connchk_timer_;
// timer to initiate connection. usually, this fires immediately.
ev_timer initiate_connection_timer_;
DList<Http2DownstreamConnection> dconns_; DList<Http2DownstreamConnection> dconns_;
DList<StreamData> streams_; DList<StreamData> streams_;
std::function<int(Http2Session &)> read_, write_; std::function<int(Http2Session &)> read_, write_;