Commit d9f54518 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

nghttpx: Add SETTINGS ACK timeout to HTTP/2 backend connections

parent f2f8300b
......@@ -59,7 +59,8 @@ SpdySession::SpdySession(event_base *evbase, SSL_CTX *ssl_ctx)
notified_(false),
wrbev_(nullptr),
rdbev_(nullptr),
flow_control_(false)
flow_control_(false),
settings_timerev_(nullptr)
{}
SpdySession::~SpdySession()
......@@ -75,6 +76,11 @@ int SpdySession::disconnect()
nghttp2_session_del(session_);
session_ = nullptr;
if(settings_timerev_) {
event_free(settings_timerev_);
settings_timerev_ = nullptr;
}
if(ssl_) {
SSL_shutdown(ssl_);
}
......@@ -746,6 +752,50 @@ int on_stream_close_callback
}
} // namespace
namespace {
void settings_timeout_cb(evutil_socket_t fd, short what, void *arg)
{
auto spdy = reinterpret_cast<SpdySession*>(arg);
SSLOG(INFO, spdy) << "SETTINGS timeout";
if(spdy->fail_session(NGHTTP2_SETTINGS_TIMEOUT) != 0) {
spdy->disconnect();
return;
}
if(spdy->send() != 0) {
spdy->disconnect();
}
}
} // namespace
int SpdySession::start_settings_timer()
{
int rv;
// We submit SETTINGS only once
if(settings_timerev_) {
return 0;
}
settings_timerev_ = evtimer_new(evbase_, settings_timeout_cb, this);
if(settings_timerev_ == nullptr) {
return -1;
}
// SETTINGS ACK timeout is 10 seconds for now
timeval settings_timeout = { 10, 0 };
rv = evtimer_add(settings_timerev_, &settings_timeout);
if(rv == -1) {
return -1;
}
return 0;
}
void SpdySession::stop_settings_timer()
{
if(settings_timerev_ == nullptr) {
return;
}
event_free(settings_timerev_);
settings_timerev_ = nullptr;
}
namespace {
int on_frame_recv_callback
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
......@@ -898,6 +948,12 @@ int on_frame_recv_callback
}
break;
}
case NGHTTP2_SETTINGS:
if((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
break;
}
spdy->stop_settings_timer();
break;
case NGHTTP2_PUSH_PROMISE:
if(LOG_ENABLED(INFO)) {
SSLOG(INFO, spdy) << "Received downstream PUSH_PROMISE stream_id="
......@@ -969,6 +1025,21 @@ int before_frame_send_callback(nghttp2_session *session,
}
} // namespace
namespace {
int on_frame_send_callback(nghttp2_session* session,
const nghttp2_frame *frame, void *user_data)
{
auto spdy = reinterpret_cast<SpdySession*>(user_data);
if(frame->hd.type == NGHTTP2_SETTINGS &&
(frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
if(spdy->start_settings_timer() != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
}
return 0;
}
} // namespace
namespace {
int on_frame_not_send_callback(nghttp2_session *session,
const nghttp2_frame *frame,
......@@ -1059,6 +1130,7 @@ int SpdySession::on_connect()
callbacks.on_frame_recv_callback = on_frame_recv_callback;
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
callbacks.before_frame_send_callback = before_frame_send_callback;
callbacks.on_frame_send_callback = on_frame_send_callback;
callbacks.on_frame_not_send_callback = on_frame_not_send_callback;
callbacks.on_frame_recv_parse_error_callback =
on_frame_recv_parse_error_callback;
......@@ -1190,4 +1262,14 @@ void SpdySession::set_state(int state)
state_ = state;
}
int SpdySession::fail_session(nghttp2_error_code error_code)
{
int rv;
rv = nghttp2_session_fail_session(session_, error_code);
if(rv != 0) {
return -1;
}
return 0;
}
} // namespace shrpx
......@@ -74,6 +74,8 @@ public:
// |dconn|.
int submit_window_update(SpdyDownstreamConnection *dconn, int32_t amount);
int fail_session(nghttp2_error_code error_code);
int32_t get_initial_window_size() const;
nghttp2_session* get_session() const;
......@@ -99,6 +101,9 @@ public:
int get_state() const;
void set_state(int state);
int start_settings_timer();
void stop_settings_timer();
enum {
// Disconnected
DISCONNECTED,
......@@ -134,6 +139,7 @@ private:
bool flow_control_;
// Used to parse the response from HTTP proxy
std::unique_ptr<http_parser> proxy_htp_;
event *settings_timerev_;
};
} // namespace shrpx
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment