nghttpx: ConnectBlocker per backend address
This commit is contained in:
parent
61579ad20f
commit
c9a4f293a1
|
@ -389,7 +389,7 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
|
||||||
pinned_http2sessions_(
|
pinned_http2sessions_(
|
||||||
get_config()->conn.downstream.proto == PROTO_HTTP2
|
get_config()->conn.downstream.proto == PROTO_HTTP2
|
||||||
? make_unique<std::vector<ssize_t>>(
|
? make_unique<std::vector<ssize_t>>(
|
||||||
get_config()->conn.downstream.addr_groups.size(), -1)
|
worker->get_downstream_addr_groups().size(), -1)
|
||||||
: nullptr),
|
: nullptr),
|
||||||
ipaddr_(ipaddr),
|
ipaddr_(ipaddr),
|
||||||
port_(port),
|
port_(port),
|
||||||
|
@ -664,8 +664,8 @@ std::unique_ptr<DownstreamConnection>
|
||||||
ClientHandler::get_downstream_connection(Downstream *downstream) {
|
ClientHandler::get_downstream_connection(Downstream *downstream) {
|
||||||
size_t group;
|
size_t group;
|
||||||
auto &downstreamconf = get_config()->conn.downstream;
|
auto &downstreamconf = get_config()->conn.downstream;
|
||||||
auto &groups = downstreamconf.addr_groups;
|
|
||||||
auto catch_all = downstreamconf.addr_group_catch_all;
|
auto catch_all = downstreamconf.addr_group_catch_all;
|
||||||
|
auto &groups = worker_->get_downstream_addr_groups();
|
||||||
|
|
||||||
const auto &req = downstream->request();
|
const auto &req = downstream->request();
|
||||||
|
|
||||||
|
@ -746,10 +746,6 @@ MemchunkPool *ClientHandler::get_mcpool() { return worker_->get_mcpool(); }
|
||||||
|
|
||||||
SSL *ClientHandler::get_ssl() const { return conn_.tls.ssl; }
|
SSL *ClientHandler::get_ssl() const { return conn_.tls.ssl; }
|
||||||
|
|
||||||
ConnectBlocker *ClientHandler::get_connect_blocker() const {
|
|
||||||
return worker_->get_connect_blocker();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientHandler::direct_http2_upgrade() {
|
void ClientHandler::direct_http2_upgrade() {
|
||||||
upstream_ = make_unique<Http2Upstream>(this);
|
upstream_ = make_unique<Http2Upstream>(this);
|
||||||
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
|
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
|
||||||
|
|
|
@ -99,7 +99,6 @@ public:
|
||||||
get_downstream_connection(Downstream *downstream);
|
get_downstream_connection(Downstream *downstream);
|
||||||
MemchunkPool *get_mcpool();
|
MemchunkPool *get_mcpool();
|
||||||
SSL *get_ssl() const;
|
SSL *get_ssl() const;
|
||||||
ConnectBlocker *get_connect_blocker() const;
|
|
||||||
// Call this function when HTTP/2 connection header is received at
|
// Call this function when HTTP/2 connection header is received at
|
||||||
// the start of the connection.
|
// the start of the connection.
|
||||||
void direct_http2_upgrade();
|
void direct_http2_upgrade();
|
||||||
|
|
|
@ -59,6 +59,7 @@ using namespace nghttp2;
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
struct LogFragment;
|
struct LogFragment;
|
||||||
|
class ConnectBlocker;
|
||||||
|
|
||||||
namespace ssl {
|
namespace ssl {
|
||||||
|
|
||||||
|
@ -294,6 +295,7 @@ struct DownstreamAddr {
|
||||||
// socket path.
|
// socket path.
|
||||||
ImmutableString host;
|
ImmutableString host;
|
||||||
ImmutableString hostport;
|
ImmutableString hostport;
|
||||||
|
ConnectBlocker *connect_blocker;
|
||||||
// backend port. 0 if |host_unix| is true.
|
// backend port. 0 if |host_unix| is true.
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
// true if |host| contains UNIX domain socket path.
|
// true if |host| contains UNIX domain socket path.
|
||||||
|
|
|
@ -26,20 +26,16 @@
|
||||||
|
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
namespace {
|
|
||||||
const ev_tstamp INITIAL_SLEEP = 2.;
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void connect_blocker_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
void connect_blocker_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
LOG(INFO) << "unblock downstream connection";
|
LOG(INFO) << "Unblock";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ConnectBlocker::ConnectBlocker(struct ev_loop *loop)
|
ConnectBlocker::ConnectBlocker(std::mt19937 &gen, struct ev_loop *loop)
|
||||||
: loop_(loop), sleep_(INITIAL_SLEEP) {
|
: gen_(gen), loop_(loop), fail_count_(0) {
|
||||||
ev_timer_init(&timer_, connect_blocker_cb, 0., 0.);
|
ev_timer_init(&timer_, connect_blocker_cb, 0., 0.);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,18 +43,27 @@ ConnectBlocker::~ConnectBlocker() { ev_timer_stop(loop_, &timer_); }
|
||||||
|
|
||||||
bool ConnectBlocker::blocked() const { return ev_is_active(&timer_); }
|
bool ConnectBlocker::blocked() const { return ev_is_active(&timer_); }
|
||||||
|
|
||||||
void ConnectBlocker::on_success() { sleep_ = INITIAL_SLEEP; }
|
void ConnectBlocker::on_success() { fail_count_ = 0; }
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr size_t MAX_BACKOFF_EXP = 10;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void ConnectBlocker::on_failure() {
|
void ConnectBlocker::on_failure() {
|
||||||
if (ev_is_active(&timer_)) {
|
if (ev_is_active(&timer_)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep_ = std::min(128., sleep_ * 2);
|
++fail_count_;
|
||||||
|
|
||||||
LOG(WARN) << "connect failure, start sleeping " << sleep_;
|
auto max_backoff = (1 << std::min(MAX_BACKOFF_EXP, fail_count_)) - 1;
|
||||||
|
auto dist = std::uniform_int_distribution<>(0, max_backoff);
|
||||||
|
auto backoff = dist(gen_);
|
||||||
|
|
||||||
ev_timer_set(&timer_, sleep_, 0.);
|
LOG(WARN) << "Could not connect " << fail_count_
|
||||||
|
<< " times in a row; sleep for " << backoff << " seconds";
|
||||||
|
|
||||||
|
ev_timer_set(&timer_, backoff, 0.);
|
||||||
ev_timer_start(loop_, &timer_);
|
ev_timer_start(loop_, &timer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,15 @@
|
||||||
|
|
||||||
#include "shrpx.h"
|
#include "shrpx.h"
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include <ev.h>
|
#include <ev.h>
|
||||||
|
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
class ConnectBlocker {
|
class ConnectBlocker {
|
||||||
public:
|
public:
|
||||||
ConnectBlocker(struct ev_loop *loop);
|
ConnectBlocker(std::mt19937 &gen, struct ev_loop *loop);
|
||||||
~ConnectBlocker();
|
~ConnectBlocker();
|
||||||
|
|
||||||
// Returns true if making connection is not allowed.
|
// Returns true if making connection is not allowed.
|
||||||
|
@ -41,14 +43,18 @@ public:
|
||||||
// Call this function if connect operation succeeded. This will
|
// Call this function if connect operation succeeded. This will
|
||||||
// reset sleep_ to minimum value.
|
// reset sleep_ to minimum value.
|
||||||
void on_success();
|
void on_success();
|
||||||
// Call this function if connect operation failed. This will start
|
// Call this function if connect operations failed. This will start
|
||||||
// timer and blocks connection establishment for sleep_ seconds.
|
// timer and blocks connection establishment with exponential
|
||||||
|
// backoff.
|
||||||
void on_failure();
|
void on_failure();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::mt19937 gen_;
|
||||||
ev_timer timer_;
|
ev_timer timer_;
|
||||||
struct ev_loop *loop_;
|
struct ev_loop *loop_;
|
||||||
ev_tstamp sleep_;
|
// The number of consecutive connection failure. Reset to 0 on
|
||||||
|
// success.
|
||||||
|
size_t fail_count_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -98,6 +98,9 @@ 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;
|
||||||
|
|
|
@ -147,8 +147,7 @@ void writecb(struct ev_loop *loop, ev_io *w, int revents) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Http2Session::Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx,
|
Http2Session::Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx,
|
||||||
ConnectBlocker *connect_blocker, Worker *worker,
|
Worker *worker, size_t group, size_t idx)
|
||||||
size_t group, size_t idx)
|
|
||||||
: conn_(loop, -1, nullptr, worker->get_mcpool(),
|
: conn_(loop, -1, nullptr, worker->get_mcpool(),
|
||||||
get_config()->conn.downstream.timeout.write,
|
get_config()->conn.downstream.timeout.write,
|
||||||
get_config()->conn.downstream.timeout.read, {}, {}, writecb, readcb,
|
get_config()->conn.downstream.timeout.read, {}, {}, writecb, readcb,
|
||||||
|
@ -156,7 +155,6 @@ Http2Session::Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx,
|
||||||
get_config()->tls.dyn_rec.idle_timeout),
|
get_config()->tls.dyn_rec.idle_timeout),
|
||||||
wb_(worker->get_mcpool()),
|
wb_(worker->get_mcpool()),
|
||||||
worker_(worker),
|
worker_(worker),
|
||||||
connect_blocker_(connect_blocker),
|
|
||||||
ssl_ctx_(ssl_ctx),
|
ssl_ctx_(ssl_ctx),
|
||||||
addr_(nullptr),
|
addr_(nullptr),
|
||||||
session_(nullptr),
|
session_(nullptr),
|
||||||
|
@ -254,30 +252,49 @@ int Http2Session::disconnect(bool hard) {
|
||||||
int Http2Session::initiate_connection() {
|
int Http2Session::initiate_connection() {
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
|
|
||||||
auto &addrs = get_config()->conn.downstream.addr_groups[group_].addrs;
|
auto &groups = worker_->get_downstream_addr_groups();
|
||||||
|
auto &addrs = groups[group_].addrs;
|
||||||
|
|
||||||
if (state_ == DISCONNECTED) {
|
if (state_ == DISCONNECTED) {
|
||||||
if (connect_blocker_->blocked()) {
|
auto &next_downstream = worker_->get_dgrp(group_)->next;
|
||||||
if (LOG_ENABLED(INFO)) {
|
auto end = next_downstream;
|
||||||
DCLOG(INFO, this)
|
|
||||||
<< "Downstream connection was blocked by connect_blocker";
|
for (;;) {
|
||||||
|
auto &addr = addrs[next_downstream];
|
||||||
|
|
||||||
|
if (++next_downstream >= addrs.size()) {
|
||||||
|
next_downstream = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &connect_blocker = addr.connect_blocker;
|
||||||
|
|
||||||
|
if (connect_blocker->blocked()) {
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
DCLOG(INFO, this) << "Backend server "
|
||||||
|
<< (addr.host_unix ? addr.host : addr.hostport)
|
||||||
|
<< " was not available temporarily";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end == next_downstream) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &next_downstream = worker_->get_dgrp(group_)->next;
|
continue;
|
||||||
addr_ = &addrs[next_downstream];
|
}
|
||||||
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
SSLOG(INFO, this) << "Using downstream address idx=" << next_downstream
|
SSLOG(INFO, this) << "Using downstream address idx=" << next_downstream
|
||||||
<< " out of " << addrs.size();
|
<< " out of " << addrs.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++next_downstream >= addrs.size()) {
|
addr_ = &addr;
|
||||||
next_downstream = 0;
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &connect_blocker = addr_->connect_blocker;
|
||||||
|
|
||||||
const auto &proxy = get_config()->downstream_http_proxy;
|
const auto &proxy = get_config()->downstream_http_proxy;
|
||||||
if (!proxy.host.empty() && state_ == DISCONNECTED) {
|
if (!proxy.host.empty() && state_ == DISCONNECTED) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
@ -288,7 +305,7 @@ int Http2Session::initiate_connection() {
|
||||||
conn_.fd = util::create_nonblock_socket(proxy.addr.su.storage.ss_family);
|
conn_.fd = util::create_nonblock_socket(proxy.addr.su.storage.ss_family);
|
||||||
|
|
||||||
if (conn_.fd == -1) {
|
if (conn_.fd == -1) {
|
||||||
connect_blocker_->on_failure();
|
connect_blocker->on_failure();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,7 +313,7 @@ int Http2Session::initiate_connection() {
|
||||||
if (rv != 0 && errno != EINPROGRESS) {
|
if (rv != 0 && errno != EINPROGRESS) {
|
||||||
SSLOG(ERROR, this) << "Failed to connect to the proxy " << proxy.host
|
SSLOG(ERROR, this) << "Failed to connect to the proxy " << proxy.host
|
||||||
<< ":" << proxy.port;
|
<< ":" << proxy.port;
|
||||||
connect_blocker_->on_failure();
|
connect_blocker->on_failure();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +373,7 @@ int Http2Session::initiate_connection() {
|
||||||
conn_.fd =
|
conn_.fd =
|
||||||
util::create_nonblock_socket(addr_->addr.su.storage.ss_family);
|
util::create_nonblock_socket(addr_->addr.su.storage.ss_family);
|
||||||
if (conn_.fd == -1) {
|
if (conn_.fd == -1) {
|
||||||
connect_blocker_->on_failure();
|
connect_blocker->on_failure();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,7 +382,7 @@ int Http2Session::initiate_connection() {
|
||||||
const_cast<sockaddr *>(&addr_->addr.su.sa),
|
const_cast<sockaddr *>(&addr_->addr.su.sa),
|
||||||
addr_->addr.len);
|
addr_->addr.len);
|
||||||
if (rv != 0 && errno != EINPROGRESS) {
|
if (rv != 0 && errno != EINPROGRESS) {
|
||||||
connect_blocker_->on_failure();
|
connect_blocker->on_failure();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,14 +400,14 @@ int Http2Session::initiate_connection() {
|
||||||
util::create_nonblock_socket(addr_->addr.su.storage.ss_family);
|
util::create_nonblock_socket(addr_->addr.su.storage.ss_family);
|
||||||
|
|
||||||
if (conn_.fd == -1) {
|
if (conn_.fd == -1) {
|
||||||
connect_blocker_->on_failure();
|
connect_blocker->on_failure();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = connect(conn_.fd, const_cast<sockaddr *>(&addr_->addr.su.sa),
|
rv = connect(conn_.fd, const_cast<sockaddr *>(&addr_->addr.su.sa),
|
||||||
addr_->addr.len);
|
addr_->addr.len);
|
||||||
if (rv != 0 && errno != EINPROGRESS) {
|
if (rv != 0 && errno != EINPROGRESS) {
|
||||||
connect_blocker_->on_failure();
|
connect_blocker->on_failure();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1615,11 +1632,15 @@ int Http2Session::read_noop(const uint8_t *data, size_t datalen) { return 0; }
|
||||||
int Http2Session::write_noop() { return 0; }
|
int Http2Session::write_noop() { return 0; }
|
||||||
|
|
||||||
int Http2Session::connected() {
|
int Http2Session::connected() {
|
||||||
|
auto &connect_blocker = addr_->connect_blocker;
|
||||||
|
|
||||||
if (!util::check_socket_connected(conn_.fd)) {
|
if (!util::check_socket_connected(conn_.fd)) {
|
||||||
|
connect_blocker->on_failure();
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
connect_blocker_->on_success();
|
connect_blocker->on_success();
|
||||||
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
SSLOG(INFO, this) << "Connection established";
|
SSLOG(INFO, this) << "Connection established";
|
||||||
|
|
|
@ -48,7 +48,6 @@ namespace shrpx {
|
||||||
|
|
||||||
class Http2DownstreamConnection;
|
class Http2DownstreamConnection;
|
||||||
class Worker;
|
class Worker;
|
||||||
class ConnectBlocker;
|
|
||||||
|
|
||||||
struct StreamData {
|
struct StreamData {
|
||||||
StreamData *dlnext, *dlprev;
|
StreamData *dlnext, *dlprev;
|
||||||
|
@ -57,9 +56,8 @@ struct StreamData {
|
||||||
|
|
||||||
class Http2Session {
|
class Http2Session {
|
||||||
public:
|
public:
|
||||||
Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx,
|
Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx, Worker *worker,
|
||||||
ConnectBlocker *connect_blocker, Worker *worker, size_t group,
|
size_t group, size_t idx);
|
||||||
size_t idx);
|
|
||||||
~Http2Session();
|
~Http2Session();
|
||||||
|
|
||||||
// If hard is true, all pending requests are abandoned and
|
// If hard is true, all pending requests are abandoned and
|
||||||
|
@ -203,7 +201,6 @@ private:
|
||||||
// Used to parse the response from HTTP proxy
|
// Used to parse the response from HTTP proxy
|
||||||
std::unique_ptr<http_parser> proxy_htp_;
|
std::unique_ptr<http_parser> proxy_htp_;
|
||||||
Worker *worker_;
|
Worker *worker_;
|
||||||
ConnectBlocker *connect_blocker_;
|
|
||||||
// NULL if no TLS is configured
|
// NULL if no TLS is configured
|
||||||
SSL_CTX *ssl_ctx_;
|
SSL_CTX *ssl_ctx_;
|
||||||
// Address of remote endpoint
|
// Address of remote endpoint
|
||||||
|
|
|
@ -147,16 +147,6 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
|
||||||
auto &downstreamconf = get_config()->conn.downstream;
|
auto &downstreamconf = get_config()->conn.downstream;
|
||||||
|
|
||||||
if (conn_.fd == -1) {
|
if (conn_.fd == -1) {
|
||||||
auto connect_blocker = client_handler_->get_connect_blocker();
|
|
||||||
|
|
||||||
if (connect_blocker->blocked()) {
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
|
||||||
DCLOG(INFO, this)
|
|
||||||
<< "Downstream connection was blocked by connect_blocker";
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ssl_ctx_) {
|
if (ssl_ctx_) {
|
||||||
auto ssl = ssl::create_ssl(ssl_ctx_);
|
auto ssl = ssl::create_ssl(ssl_ctx_);
|
||||||
if (!ssl) {
|
if (!ssl) {
|
||||||
|
@ -168,7 +158,8 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
|
||||||
|
|
||||||
auto &next_downstream = worker_->get_dgrp(group_)->next;
|
auto &next_downstream = worker_->get_dgrp(group_)->next;
|
||||||
auto end = next_downstream;
|
auto end = next_downstream;
|
||||||
auto &addrs = downstreamconf.addr_groups[group_].addrs;
|
auto &groups = worker_->get_downstream_addr_groups();
|
||||||
|
auto &addrs = groups[group_].addrs;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto &addr = addrs[next_downstream];
|
auto &addr = addrs[next_downstream];
|
||||||
|
|
||||||
|
@ -176,6 +167,22 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
|
||||||
next_downstream = 0;
|
next_downstream = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &connect_blocker = addr.connect_blocker;
|
||||||
|
|
||||||
|
if (connect_blocker->blocked()) {
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
DCLOG(INFO, this) << "Backend server "
|
||||||
|
<< (addr.host_unix ? addr.host : addr.hostport)
|
||||||
|
<< " was not available temporarily";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end == next_downstream) {
|
||||||
|
return SHRPX_ERR_NETWORK;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
conn_.fd = util::create_nonblock_socket(addr.addr.su.storage.ss_family);
|
conn_.fd = util::create_nonblock_socket(addr.addr.su.storage.ss_family);
|
||||||
|
|
||||||
if (conn_.fd == -1) {
|
if (conn_.fd == -1) {
|
||||||
|
@ -1012,7 +1019,7 @@ int HttpDownstreamConnection::process_input(const uint8_t *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
int HttpDownstreamConnection::connected() {
|
int HttpDownstreamConnection::connected() {
|
||||||
auto connect_blocker = client_handler_->get_connect_blocker();
|
auto connect_blocker = addr_->connect_blocker;
|
||||||
|
|
||||||
if (!util::check_socket_connected(conn_.fd)) {
|
if (!util::check_socket_connected(conn_.fd)) {
|
||||||
conn_.wlimit.stopw();
|
conn_.wlimit.stopw();
|
||||||
|
@ -1021,6 +1028,8 @@ int HttpDownstreamConnection::connected() {
|
||||||
DLOG(INFO, this) << "downstream connect failed";
|
DLOG(INFO, this) << "downstream connect failed";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connect_blocker->on_failure();
|
||||||
|
|
||||||
downstream_->set_request_state(Downstream::CONNECT_FAIL);
|
downstream_->set_request_state(Downstream::CONNECT_FAIL);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -80,7 +80,7 @@ Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
|
||||||
cl_ssl_ctx_(cl_ssl_ctx),
|
cl_ssl_ctx_(cl_ssl_ctx),
|
||||||
cert_tree_(cert_tree),
|
cert_tree_(cert_tree),
|
||||||
ticket_keys_(ticket_keys),
|
ticket_keys_(ticket_keys),
|
||||||
connect_blocker_(make_unique<ConnectBlocker>(loop_)),
|
downstream_addr_groups_(get_config()->conn.downstream.addr_groups),
|
||||||
graceful_shutdown_(false) {
|
graceful_shutdown_(false) {
|
||||||
ev_async_init(&w_, eventcb);
|
ev_async_init(&w_, eventcb);
|
||||||
w_.data = this;
|
w_.data = this;
|
||||||
|
@ -109,17 +109,29 @@ Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
|
||||||
m = downstreamconf.addr_groups[group].addrs.size();
|
m = downstreamconf.addr_groups[group].addrs.size();
|
||||||
}
|
}
|
||||||
for (size_t idx = 0; idx < m; ++idx) {
|
for (size_t idx = 0; idx < m; ++idx) {
|
||||||
dgrp.http2sessions.push_back(make_unique<Http2Session>(
|
dgrp.http2sessions.push_back(
|
||||||
loop_, cl_ssl_ctx, connect_blocker_.get(), this, group, idx));
|
make_unique<Http2Session>(loop_, cl_ssl_ctx, this, group, idx));
|
||||||
}
|
}
|
||||||
++group;
|
++group;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto &group : downstream_addr_groups_) {
|
||||||
|
for (auto &addr : group.addrs) {
|
||||||
|
addr.connect_blocker = new ConnectBlocker(randgen_, loop_);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Worker::~Worker() {
|
Worker::~Worker() {
|
||||||
ev_async_stop(loop_, &w_);
|
ev_async_stop(loop_, &w_);
|
||||||
ev_timer_stop(loop_, &mcpool_clear_timer_);
|
ev_timer_stop(loop_, &mcpool_clear_timer_);
|
||||||
|
|
||||||
|
for (auto &group : downstream_addr_groups_) {
|
||||||
|
for (auto &addr : group.addrs) {
|
||||||
|
delete addr.connect_blocker;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Worker::schedule_clear_mcpool() {
|
void Worker::schedule_clear_mcpool() {
|
||||||
|
@ -259,10 +271,6 @@ Http2Session *Worker::next_http2_session(size_t group) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectBlocker *Worker::get_connect_blocker() const {
|
|
||||||
return connect_blocker_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ev_loop *Worker::get_loop() const {
|
struct ev_loop *Worker::get_loop() const {
|
||||||
return loop_;
|
return loop_;
|
||||||
}
|
}
|
||||||
|
@ -361,4 +369,8 @@ SSL_SESSION *Worker::reuse_client_tls_session(const Address *addr) {
|
||||||
return d2i_SSL_SESSION(nullptr, &p, ent.session_data.size());
|
return d2i_SSL_SESSION(nullptr, &p, ent.session_data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<DownstreamAddrGroup> &Worker::get_downstream_addr_groups() {
|
||||||
|
return downstream_addr_groups_;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -131,7 +131,6 @@ public:
|
||||||
WorkerStat *get_worker_stat();
|
WorkerStat *get_worker_stat();
|
||||||
DownstreamConnectionPool *get_dconn_pool();
|
DownstreamConnectionPool *get_dconn_pool();
|
||||||
Http2Session *next_http2_session(size_t group);
|
Http2Session *next_http2_session(size_t group);
|
||||||
ConnectBlocker *get_connect_blocker() const;
|
|
||||||
struct ev_loop *get_loop() const;
|
struct ev_loop *get_loop() const;
|
||||||
SSL_CTX *get_sv_ssl_ctx() const;
|
SSL_CTX *get_sv_ssl_ctx() const;
|
||||||
SSL_CTX *get_cl_ssl_ctx() const;
|
SSL_CTX *get_cl_ssl_ctx() const;
|
||||||
|
@ -164,6 +163,8 @@ public:
|
||||||
// found associated to |addr|, nullptr will be returned.
|
// found associated to |addr|, nullptr will be returned.
|
||||||
SSL_SESSION *reuse_client_tls_session(const Address *addr);
|
SSL_SESSION *reuse_client_tls_session(const Address *addr);
|
||||||
|
|
||||||
|
std::vector<DownstreamAddrGroup> &get_downstream_addr_groups();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifndef NOTHREADS
|
#ifndef NOTHREADS
|
||||||
std::future<void> fut_;
|
std::future<void> fut_;
|
||||||
|
@ -196,7 +197,7 @@ private:
|
||||||
ssl::CertLookupTree *cert_tree_;
|
ssl::CertLookupTree *cert_tree_;
|
||||||
|
|
||||||
std::shared_ptr<TicketKeys> ticket_keys_;
|
std::shared_ptr<TicketKeys> ticket_keys_;
|
||||||
std::unique_ptr<ConnectBlocker> connect_blocker_;
|
std::vector<DownstreamAddrGroup> downstream_addr_groups_;
|
||||||
|
|
||||||
bool graceful_shutdown_;
|
bool graceful_shutdown_;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue