nghttpx: Support multiple frontend addresses
This commit allows nghttpx to listen to multiple address and port pair by specifying -f option multiple times.
This commit is contained in:
parent
1d99b425ca
commit
aa07fe7fa6
516
src/shrpx.cc
516
src/shrpx.cc
|
@ -92,22 +92,30 @@ using namespace nghttp2;
|
||||||
|
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
// Environment variables to tell new binary the listening socket's
|
// Deprecated: Environment variables to tell new binary the listening
|
||||||
// file descriptors. They are not close-on-exec.
|
// socket's file descriptors. They are not close-on-exec.
|
||||||
#define ENV_LISTENER4_FD "NGHTTPX_LISTENER4_FD"
|
#define ENV_LISTENER4_FD "NGHTTPX_LISTENER4_FD"
|
||||||
#define ENV_LISTENER6_FD "NGHTTPX_LISTENER6_FD"
|
#define ENV_LISTENER6_FD "NGHTTPX_LISTENER6_FD"
|
||||||
|
|
||||||
// Environment variable to tell new binary the port number the current
|
// Deprecated: Environment variable to tell new binary the port number
|
||||||
// binary is listening to.
|
// the current binary is listening to.
|
||||||
#define ENV_PORT "NGHTTPX_PORT"
|
#define ENV_PORT "NGHTTPX_PORT"
|
||||||
|
|
||||||
// Environment variable to tell new binary the listening socket's file
|
// Deprecated: Environment variable to tell new binary the listening
|
||||||
// descriptor if frontend listens UNIX domain socket.
|
// socket's file descriptor if frontend listens UNIX domain socket.
|
||||||
#define ENV_UNIX_FD "NGHTTP2_UNIX_FD"
|
#define ENV_UNIX_FD "NGHTTP2_UNIX_FD"
|
||||||
// Environment variable to tell new binary the UNIX domain socket
|
// Deprecated: Environment variable to tell new binary the UNIX domain
|
||||||
// path.
|
// socket path.
|
||||||
#define ENV_UNIX_PATH "NGHTTP2_UNIX_PATH"
|
#define ENV_UNIX_PATH "NGHTTP2_UNIX_PATH"
|
||||||
|
|
||||||
|
// Prefix of environment variables to tell new binary the listening
|
||||||
|
// socket's file descriptor. They are not close-on-exec. For TCP
|
||||||
|
// socket, the value must be comma separated 2 parameters: tcp,<FD>.
|
||||||
|
// <FD> is file descriptor. For UNIX domain socket, the value must be
|
||||||
|
// comma separated 3 parameters: unix,<FD>,<PATH>. <FD> is file
|
||||||
|
// descriptor. <PATH> is a path to UNIX domain socket.
|
||||||
|
constexpr char ENV_ACCEPT_PREFIX[] = "NGHTTPX_ACCEPT_";
|
||||||
|
|
||||||
#ifndef _KERNEL_FASTOPEN
|
#ifndef _KERNEL_FASTOPEN
|
||||||
#define _KERNEL_FASTOPEN
|
#define _KERNEL_FASTOPEN
|
||||||
// conditional define for TCP_FASTOPEN mostly on ubuntu
|
// conditional define for TCP_FASTOPEN mostly on ubuntu
|
||||||
|
@ -122,18 +130,8 @@ namespace shrpx {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct SignalServer {
|
struct SignalServer {
|
||||||
SignalServer()
|
SignalServer() : ipc_fd{{-1, -1}}, worker_process_pid(-1) {}
|
||||||
: ipc_fd{{-1, -1}},
|
|
||||||
server_fd(-1),
|
|
||||||
server_fd6(-1),
|
|
||||||
worker_process_pid(-1) {}
|
|
||||||
~SignalServer() {
|
~SignalServer() {
|
||||||
if (server_fd6 != -1) {
|
|
||||||
close(server_fd6);
|
|
||||||
}
|
|
||||||
if (server_fd != -1) {
|
|
||||||
close(server_fd);
|
|
||||||
}
|
|
||||||
if (ipc_fd[0] != -1) {
|
if (ipc_fd[0] != -1) {
|
||||||
close(ipc_fd[0]);
|
close(ipc_fd[0]);
|
||||||
}
|
}
|
||||||
|
@ -144,10 +142,6 @@ struct SignalServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<int, 2> ipc_fd;
|
std::array<int, 2> ipc_fd;
|
||||||
// server socket, either IPv4 or UNIX domain
|
|
||||||
int server_fd;
|
|
||||||
// server socket IPv6
|
|
||||||
int server_fd6;
|
|
||||||
pid_t worker_process_pid;
|
pid_t worker_process_pid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -295,42 +289,35 @@ void exec_binary(SignalServer *ssv) {
|
||||||
size_t envlen = 0;
|
size_t envlen = 0;
|
||||||
for (char **p = environ; *p; ++p, ++envlen)
|
for (char **p = environ; *p; ++p, ++envlen)
|
||||||
;
|
;
|
||||||
// 3 for missing (fd4, fd6 and port) or (unix fd and unix path)
|
|
||||||
auto envp = make_unique<char *[]>(envlen + 3 + 1);
|
|
||||||
size_t envidx = 0;
|
|
||||||
|
|
||||||
std::string fd, fd6, path, port;
|
|
||||||
|
|
||||||
auto &listenerconf = get_config()->conn.listener;
|
auto &listenerconf = get_config()->conn.listener;
|
||||||
|
|
||||||
if (listenerconf.host_unix) {
|
auto envp = make_unique<char *[]>(envlen + listenerconf.addrs.size() + 1);
|
||||||
fd = ENV_UNIX_FD "=";
|
size_t envidx = 0;
|
||||||
fd += util::utos(ssv->server_fd);
|
|
||||||
envp[envidx++] = &fd[0];
|
|
||||||
|
|
||||||
path = ENV_UNIX_PATH "=";
|
std::vector<ImmutableString> fd_envs;
|
||||||
path += listenerconf.host.get();
|
for (size_t i = 0; i < listenerconf.addrs.size(); ++i) {
|
||||||
envp[envidx++] = &path[0];
|
auto &addr = listenerconf.addrs[i];
|
||||||
} else {
|
std::string s = ENV_ACCEPT_PREFIX;
|
||||||
if (ssv->server_fd) {
|
s += util::utos(i + 1);
|
||||||
fd = ENV_LISTENER4_FD "=";
|
s += '=';
|
||||||
fd += util::utos(ssv->server_fd);
|
if (addr.host_unix) {
|
||||||
envp[envidx++] = &fd[0];
|
s += "unix,";
|
||||||
|
s += util::utos(addr.fd);
|
||||||
|
s += ',';
|
||||||
|
s += addr.host;
|
||||||
|
} else {
|
||||||
|
s += "tcp,";
|
||||||
|
s += util::utos(addr.fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssv->server_fd6) {
|
fd_envs.emplace_back(s);
|
||||||
fd6 = ENV_LISTENER6_FD "=";
|
envp[envidx++] = const_cast<char *>(fd_envs.back().c_str());
|
||||||
fd6 += util::utos(ssv->server_fd6);
|
|
||||||
envp[envidx++] = &fd6[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
port = ENV_PORT "=";
|
|
||||||
port += util::utos(listenerconf.port);
|
|
||||||
envp[envidx++] = &port[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < envlen; ++i) {
|
for (size_t i = 0; i < envlen; ++i) {
|
||||||
if (util::starts_with(environ[i], ENV_LISTENER4_FD) ||
|
if (util::starts_with(environ[i], ENV_ACCEPT_PREFIX) ||
|
||||||
|
util::starts_with(environ[i], ENV_LISTENER4_FD) ||
|
||||||
util::starts_with(environ[i], ENV_LISTENER6_FD) ||
|
util::starts_with(environ[i], ENV_LISTENER6_FD) ||
|
||||||
util::starts_with(environ[i], ENV_PORT) ||
|
util::starts_with(environ[i], ENV_PORT) ||
|
||||||
util::starts_with(environ[i], ENV_UNIX_FD) ||
|
util::starts_with(environ[i], ENV_UNIX_FD) ||
|
||||||
|
@ -432,38 +419,45 @@ void worker_process_child_cb(struct ev_loop *loop, ev_child *w, int revents) {
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
struct InheritedAddr {
|
||||||
|
// IP address if TCP socket. Otherwise, UNIX domain socket path.
|
||||||
|
ImmutableString host;
|
||||||
|
uint16_t port;
|
||||||
|
// true if UNIX domain socket path
|
||||||
|
bool host_unix;
|
||||||
|
int fd;
|
||||||
|
bool used;
|
||||||
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int create_unix_domain_server_socket() {
|
int create_unix_domain_server_socket(FrontendAddr &faddr,
|
||||||
auto &listenerconf = get_config()->conn.listener;
|
std::vector<InheritedAddr> &iaddrs) {
|
||||||
|
auto found = std::find_if(
|
||||||
|
std::begin(iaddrs), std::end(iaddrs), [&faddr](const InheritedAddr &ia) {
|
||||||
|
return !ia.used && ia.host_unix && ia.host == faddr.host;
|
||||||
|
});
|
||||||
|
|
||||||
auto path = listenerconf.host.get();
|
if (found != std::end(iaddrs)) {
|
||||||
auto pathlen = strlen(path);
|
LOG(NOTICE) << "Listening on UNIX domain socket " << faddr.host;
|
||||||
{
|
(*found).used = true;
|
||||||
auto envfd = getenv(ENV_UNIX_FD);
|
faddr.fd = (*found).fd;
|
||||||
auto envpath = getenv(ENV_UNIX_PATH);
|
faddr.hostport = "localhost";
|
||||||
if (envfd && envpath) {
|
|
||||||
auto fd = strtoul(envfd, nullptr, 10);
|
|
||||||
|
|
||||||
if (util::streq(envpath, path)) {
|
return 0;
|
||||||
LOG(NOTICE) << "Listening on UNIX domain socket " << path;
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(WARN) << "UNIX domain socket path was changed between old binary ("
|
|
||||||
<< envpath << ") and new binary (" << path << ")";
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SOCK_NONBLOCK
|
#ifdef SOCK_NONBLOCK
|
||||||
auto fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
auto fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
|
auto error = errno;
|
||||||
|
LOG(WARN) << "socket() syscall failed: " << strerror(error);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#else // !SOCK_NONBLOCK
|
#else // !SOCK_NONBLOCK
|
||||||
auto fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
auto fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
|
auto error = errno;
|
||||||
|
LOG(WARN) << "socket() syscall failed: " << strerror(error);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
util::make_socket_nonblocking(fd);
|
util::make_socket_nonblocking(fd);
|
||||||
|
@ -471,115 +465,122 @@ int create_unix_domain_server_socket() {
|
||||||
int val = 1;
|
int val = 1;
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
|
||||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||||
|
auto error = errno;
|
||||||
|
LOG(WARN) << "Failed to set SO_REUSEADDR option to listener socket: "
|
||||||
|
<< strerror(error);
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sockaddr_union addr;
|
sockaddr_union addr;
|
||||||
addr.un.sun_family = AF_UNIX;
|
addr.un.sun_family = AF_UNIX;
|
||||||
if (pathlen + 1 > sizeof(addr.un.sun_path)) {
|
if (faddr.host.size() + 1 > sizeof(addr.un.sun_path)) {
|
||||||
LOG(FATAL) << "UNIX domain socket path " << path << " is too long > "
|
LOG(FATAL) << "UNIX domain socket path " << faddr.host << " is too long > "
|
||||||
<< sizeof(addr.un.sun_path);
|
<< sizeof(addr.un.sun_path);
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// copy path including terminal NULL
|
// copy path including terminal NULL
|
||||||
std::copy_n(path, pathlen + 1, addr.un.sun_path);
|
std::copy_n(faddr.host.c_str(), faddr.host.size() + 1, addr.un.sun_path);
|
||||||
|
|
||||||
// unlink (remove) already existing UNIX domain socket path
|
// unlink (remove) already existing UNIX domain socket path
|
||||||
unlink(path);
|
unlink(faddr.host.c_str());
|
||||||
|
|
||||||
if (bind(fd, &addr.sa, sizeof(addr.un)) != 0) {
|
if (bind(fd, &addr.sa, sizeof(addr.un)) != 0) {
|
||||||
auto error = errno;
|
auto error = errno;
|
||||||
LOG(FATAL) << "Failed to bind UNIX domain socket, error=" << error;
|
LOG(FATAL) << "Failed to bind UNIX domain socket: " << strerror(error);
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &listenerconf = get_config()->conn.listener;
|
||||||
|
|
||||||
if (listen(fd, listenerconf.backlog) != 0) {
|
if (listen(fd, listenerconf.backlog) != 0) {
|
||||||
auto error = errno;
|
auto error = errno;
|
||||||
LOG(FATAL) << "Failed to listen to UNIX domain socket, error=" << error;
|
LOG(FATAL) << "Failed to listen to UNIX domain socket: " << strerror(error);
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(NOTICE) << "Listening on UNIX domain socket " << path;
|
LOG(NOTICE) << "Listening on UNIX domain socket " << faddr.host;
|
||||||
|
|
||||||
return fd;
|
faddr.fd = fd;
|
||||||
|
faddr.hostport = "localhost";
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int create_tcp_server_socket(int family) {
|
int create_tcp_server_socket(FrontendAddr &faddr,
|
||||||
auto &listenerconf = get_config()->conn.listener;
|
std::vector<InheritedAddr> &iaddrs) {
|
||||||
|
|
||||||
{
|
|
||||||
auto envfd =
|
|
||||||
getenv(family == AF_INET ? ENV_LISTENER4_FD : ENV_LISTENER6_FD);
|
|
||||||
auto envport = getenv(ENV_PORT);
|
|
||||||
|
|
||||||
if (envfd && envport) {
|
|
||||||
auto fd = strtoul(envfd, nullptr, 10);
|
|
||||||
auto port = strtoul(envport, nullptr, 10);
|
|
||||||
|
|
||||||
// Only do this iff NGHTTPX_PORT == get_config()->port.
|
|
||||||
// Otherwise, close fd, and create server socket as usual.
|
|
||||||
|
|
||||||
if (port == listenerconf.port) {
|
|
||||||
LOG(NOTICE) << "Listening on port " << listenerconf.port;
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(WARN) << "Port was changed between old binary (" << port
|
|
||||||
<< ") and new binary (" << listenerconf.port << ")";
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
auto service = util::utos(listenerconf.port);
|
auto &listenerconf = get_config()->conn.listener;
|
||||||
|
|
||||||
|
auto service = util::utos(faddr.port);
|
||||||
addrinfo hints{};
|
addrinfo hints{};
|
||||||
hints.ai_family = family;
|
hints.ai_family = faddr.family;
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
hints.ai_flags = AI_PASSIVE;
|
hints.ai_flags = AI_PASSIVE;
|
||||||
#ifdef AI_ADDRCONFIG
|
#ifdef AI_ADDRCONFIG
|
||||||
hints.ai_flags |= AI_ADDRCONFIG;
|
hints.ai_flags |= AI_ADDRCONFIG;
|
||||||
#endif // AI_ADDRCONFIG
|
#endif // AI_ADDRCONFIG
|
||||||
|
|
||||||
auto node = strcmp("*", listenerconf.host.get()) == 0
|
auto node = faddr.host == "*" ? nullptr : faddr.host.c_str();
|
||||||
? nullptr
|
|
||||||
: listenerconf.host.get();
|
|
||||||
|
|
||||||
addrinfo *res, *rp;
|
addrinfo *res, *rp;
|
||||||
rv = getaddrinfo(node, service.c_str(), &hints, &res);
|
rv = getaddrinfo(node, service.c_str(), &hints, &res);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
LOG(INFO) << "Unable to get IPv" << (family == AF_INET ? "4" : "6")
|
LOG(INFO) << "Unable to get IPv" << (faddr.family == AF_INET ? "4" : "6")
|
||||||
<< " address for " << listenerconf.host.get() << ": "
|
<< " address for " << faddr.host << ", port " << faddr.port
|
||||||
<< gai_strerror(rv);
|
<< ": " << gai_strerror(rv);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res_d = defer(freeaddrinfo, res);
|
auto res_d = defer(freeaddrinfo, res);
|
||||||
|
|
||||||
|
std::array<char, NI_MAXHOST> host;
|
||||||
|
|
||||||
for (rp = res; rp; rp = rp->ai_next) {
|
for (rp = res; rp; rp = rp->ai_next) {
|
||||||
|
|
||||||
|
rv = getnameinfo(rp->ai_addr, rp->ai_addrlen, host.data(), host.size(),
|
||||||
|
nullptr, 0, NI_NUMERICHOST);
|
||||||
|
|
||||||
|
if (rv != 0) {
|
||||||
|
LOG(WARN) << "getnameinfo() failed: " << gai_strerror(rv);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto found = std::find_if(std::begin(iaddrs), std::end(iaddrs),
|
||||||
|
[&host, &faddr](const InheritedAddr &ia) {
|
||||||
|
return !ia.used && !ia.host_unix &&
|
||||||
|
ia.host == host.data() &&
|
||||||
|
ia.port == faddr.port;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (found != std::end(iaddrs)) {
|
||||||
|
(*found).used = true;
|
||||||
|
fd = (*found).fd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SOCK_NONBLOCK
|
#ifdef SOCK_NONBLOCK
|
||||||
fd =
|
fd =
|
||||||
socket(rp->ai_family, rp->ai_socktype | SOCK_NONBLOCK, rp->ai_protocol);
|
socket(rp->ai_family, rp->ai_socktype | SOCK_NONBLOCK, rp->ai_protocol);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
auto error = errno;
|
auto error = errno;
|
||||||
LOG(WARN) << "socket() syscall failed, error=" << error;
|
LOG(WARN) << "socket() syscall failed: " << strerror(error);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#else // !SOCK_NONBLOCK
|
#else // !SOCK_NONBLOCK
|
||||||
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
auto error = errno;
|
auto error = errno;
|
||||||
LOG(WARN) << "socket() syscall failed, error=" << error;
|
LOG(WARN) << "socket() syscall failed: " << strerror(error);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
util::make_socket_nonblocking(fd);
|
util::make_socket_nonblocking(fd);
|
||||||
|
@ -588,21 +589,19 @@ int create_tcp_server_socket(int family) {
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
|
||||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||||
auto error = errno;
|
auto error = errno;
|
||||||
LOG(WARN)
|
LOG(WARN) << "Failed to set SO_REUSEADDR option to listener socket: "
|
||||||
<< "Failed to set SO_REUSEADDR option to listener socket, error="
|
<< strerror(error);
|
||||||
<< error;
|
|
||||||
close(fd);
|
close(fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef IPV6_V6ONLY
|
#ifdef IPV6_V6ONLY
|
||||||
if (family == AF_INET6) {
|
if (faddr.family == AF_INET6) {
|
||||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
|
||||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||||
auto error = errno;
|
auto error = errno;
|
||||||
LOG(WARN)
|
LOG(WARN) << "Failed to set IPV6_V6ONLY option to listener socket: "
|
||||||
<< "Failed to set IPV6_V6ONLY option to listener socket, error="
|
<< strerror(error);
|
||||||
<< error;
|
|
||||||
close(fd);
|
close(fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -613,7 +612,9 @@ int create_tcp_server_socket(int family) {
|
||||||
val = 3;
|
val = 3;
|
||||||
if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val,
|
if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val,
|
||||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||||
LOG(WARN) << "Failed to set TCP_DEFER_ACCEPT option to listener socket";
|
auto error = errno;
|
||||||
|
LOG(WARN) << "Failed to set TCP_DEFER_ACCEPT option to listener socket: "
|
||||||
|
<< strerror(error);
|
||||||
}
|
}
|
||||||
#endif // TCP_DEFER_ACCEPT
|
#endif // TCP_DEFER_ACCEPT
|
||||||
|
|
||||||
|
@ -622,7 +623,7 @@ int create_tcp_server_socket(int family) {
|
||||||
// ports will fail with permission denied error.
|
// ports will fail with permission denied error.
|
||||||
if (bind(fd, rp->ai_addr, rp->ai_addrlen) == -1) {
|
if (bind(fd, rp->ai_addr, rp->ai_addrlen) == -1) {
|
||||||
auto error = errno;
|
auto error = errno;
|
||||||
LOG(WARN) << "bind() syscall failed, error=" << error;
|
LOG(WARN) << "bind() syscall failed: " << strerror(error);
|
||||||
close(fd);
|
close(fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -631,13 +632,15 @@ int create_tcp_server_socket(int family) {
|
||||||
val = listenerconf.fastopen;
|
val = listenerconf.fastopen;
|
||||||
if (setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &val,
|
if (setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &val,
|
||||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||||
LOG(WARN) << "Failed to set TCP_FASTOPEN option to listener socket";
|
auto error = errno;
|
||||||
|
LOG(WARN) << "Failed to set TCP_FASTOPEN option to listener socket: "
|
||||||
|
<< strerror(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(fd, listenerconf.backlog) == -1) {
|
if (listen(fd, listenerconf.backlog) == -1) {
|
||||||
auto error = errno;
|
auto error = errno;
|
||||||
LOG(WARN) << "listen() syscall failed, error=" << error;
|
LOG(WARN) << "listen() syscall failed: " << strerror(error);
|
||||||
close(fd);
|
close(fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -646,27 +649,200 @@ int create_tcp_server_socket(int family) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rp) {
|
if (!rp) {
|
||||||
LOG(WARN) << "Listening " << (family == AF_INET ? "IPv4" : "IPv6")
|
LOG(WARN) << "Listening " << (faddr.family == AF_INET ? "IPv4" : "IPv6")
|
||||||
<< " socket failed";
|
<< " socket failed";
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char host[NI_MAXHOST];
|
faddr.fd = fd;
|
||||||
rv = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), nullptr, 0,
|
faddr.hostport = util::make_hostport(host.data(), faddr.port);
|
||||||
NI_NUMERICHOST);
|
|
||||||
|
|
||||||
if (rv != 0) {
|
LOG(NOTICE) << "Listening on " << faddr.hostport;
|
||||||
LOG(WARN) << gai_strerror(rv);
|
|
||||||
|
|
||||||
close(fd);
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
return -1;
|
namespace {
|
||||||
|
int create_acceptor_socket() {
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
auto &listenerconf = mod_config()->conn.listener;
|
||||||
|
|
||||||
|
std::vector<InheritedAddr> iaddrs;
|
||||||
|
|
||||||
|
{
|
||||||
|
// Upgrade from 1.7.0 or earlier
|
||||||
|
auto portenv = getenv(ENV_PORT);
|
||||||
|
if (portenv) {
|
||||||
|
size_t i = 1;
|
||||||
|
for (auto env_name : {ENV_LISTENER4_FD, ENV_LISTENER6_FD}) {
|
||||||
|
auto fdenv = getenv(env_name);
|
||||||
|
if (fdenv) {
|
||||||
|
std::string name = ENV_ACCEPT_PREFIX;
|
||||||
|
name += util::utos(i);
|
||||||
|
std::string value = "tcp,";
|
||||||
|
value += fdenv;
|
||||||
|
setenv(name.c_str(), value.c_str(), 0);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto pathenv = getenv(ENV_UNIX_PATH);
|
||||||
|
auto fdenv = getenv(ENV_UNIX_FD);
|
||||||
|
if (pathenv && fdenv) {
|
||||||
|
std::string name = ENV_ACCEPT_PREFIX;
|
||||||
|
name += '1';
|
||||||
|
std::string value = "unix,";
|
||||||
|
value += fdenv;
|
||||||
|
value += ',';
|
||||||
|
value += pathenv;
|
||||||
|
setenv(name.c_str(), value.c_str(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(NOTICE) << "Listening on " << host << ", port " << listenerconf.port;
|
for (size_t i = 1;; ++i) {
|
||||||
|
std::string name = ENV_ACCEPT_PREFIX;
|
||||||
|
name += util::utos(i);
|
||||||
|
auto env = getenv(name.c_str());
|
||||||
|
if (!env) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return fd;
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "Read env " << name << "=" << env;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto end_type = strchr(env, ',');
|
||||||
|
if (!end_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto type = StringRef(env, end_type);
|
||||||
|
auto value = end_type + 1;
|
||||||
|
|
||||||
|
if (type == "unix") {
|
||||||
|
auto endfd = strchr(value, ',');
|
||||||
|
if (!endfd) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto fd = util::parse_uint(reinterpret_cast<const uint8_t *>(value),
|
||||||
|
endfd - value);
|
||||||
|
if (fd == -1) {
|
||||||
|
LOG(WARN) << "Could not parse file descriptor from "
|
||||||
|
<< std::string(value, endfd - value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto path = endfd + 1;
|
||||||
|
if (strlen(path) == 0) {
|
||||||
|
LOG(WARN) << "Empty UNIX domain socket path (fd=" << fd << ")";
|
||||||
|
close(fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "Inherit UNIX domain socket fd=" << fd
|
||||||
|
<< ", path=" << path;
|
||||||
|
}
|
||||||
|
|
||||||
|
InheritedAddr addr{};
|
||||||
|
addr.host = path;
|
||||||
|
addr.host_unix = true;
|
||||||
|
addr.fd = static_cast<int>(fd);
|
||||||
|
iaddrs.push_back(std::move(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == "tcp") {
|
||||||
|
auto fd = util::parse_uint(value);
|
||||||
|
if (fd == -1) {
|
||||||
|
LOG(WARN) << "Could not parse file descriptor from " << value;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_union su;
|
||||||
|
socklen_t salen = sizeof(su);
|
||||||
|
|
||||||
|
if (getsockname(fd, &su.sa, &salen) != 0) {
|
||||||
|
auto error = errno;
|
||||||
|
LOG(WARN) << "getsockname() syscall failed (fd=" << fd
|
||||||
|
<< "): " << strerror(error);
|
||||||
|
close(fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t port;
|
||||||
|
|
||||||
|
switch (su.storage.ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
port = ntohs(su.in.sin_port);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
port = ntohs(su.in6.sin6_port);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
close(fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<char, NI_MAXHOST> host;
|
||||||
|
rv = getnameinfo(&su.sa, salen, host.data(), host.size(), nullptr, 0,
|
||||||
|
NI_NUMERICHOST);
|
||||||
|
if (rv != 0) {
|
||||||
|
LOG(WARN) << "getnameinfo() failed (fd=" << fd
|
||||||
|
<< "): " << gai_strerror(rv);
|
||||||
|
close(fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "Inherit TCP socket fd=" << fd
|
||||||
|
<< ", address=" << host.data() << ", port=" << port;
|
||||||
|
}
|
||||||
|
|
||||||
|
InheritedAddr addr{};
|
||||||
|
addr.host = host.data();
|
||||||
|
addr.port = static_cast<uint16_t>(port);
|
||||||
|
addr.fd = static_cast<int>(fd);
|
||||||
|
iaddrs.push_back(std::move(addr));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &addr : listenerconf.addrs) {
|
||||||
|
if (addr.host_unix) {
|
||||||
|
if (create_unix_domain_server_socket(addr, iaddrs) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_config()->uid != 0) {
|
||||||
|
// fd is not associated to inode, so we cannot use fchown(2)
|
||||||
|
// here. https://lkml.org/lkml/2004/11/1/84
|
||||||
|
if (chown_to_running_user(addr.host.c_str()) == -1) {
|
||||||
|
auto error = errno;
|
||||||
|
LOG(WARN) << "Changing owner of UNIX domain socket " << addr.host
|
||||||
|
<< " failed: " << strerror(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (create_tcp_server_socket(addr, iaddrs) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &ia : iaddrs) {
|
||||||
|
if (ia.used) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(ia.fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -680,19 +856,6 @@ int call_daemon() {
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
|
||||||
void close_env_fd(std::initializer_list<const char *> envnames) {
|
|
||||||
for (auto envname : envnames) {
|
|
||||||
auto envfd = getenv(envname);
|
|
||||||
if (!envfd) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto fd = strtol(envfd, nullptr, 10);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
pid_t fork_worker_process(SignalServer *ssv) {
|
pid_t fork_worker_process(SignalServer *ssv) {
|
||||||
int rv;
|
int rv;
|
||||||
|
@ -722,7 +885,7 @@ pid_t fork_worker_process(SignalServer *ssv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
close(ssv->ipc_fd[1]);
|
close(ssv->ipc_fd[1]);
|
||||||
WorkerProcessConfig wpconf{ssv->ipc_fd[0], ssv->server_fd, ssv->server_fd6};
|
WorkerProcessConfig wpconf{ssv->ipc_fd[0]};
|
||||||
rv = worker_process_event_loop(&wpconf);
|
rv = worker_process_event_loop(&wpconf);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
LOG(FATAL) << "Worker process returned error";
|
LOG(FATAL) << "Worker process returned error";
|
||||||
|
@ -803,40 +966,8 @@ int event_loop() {
|
||||||
util::make_socket_closeonexec(fd);
|
util::make_socket_closeonexec(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &listenerconf = get_config()->conn.listener;
|
if (create_acceptor_socket() != 0) {
|
||||||
|
return -1;
|
||||||
if (listenerconf.host_unix) {
|
|
||||||
close_env_fd({ENV_LISTENER4_FD, ENV_LISTENER6_FD});
|
|
||||||
auto fd = create_unix_domain_server_socket();
|
|
||||||
if (fd == -1) {
|
|
||||||
LOG(FATAL) << "Failed to listen on UNIX domain socket "
|
|
||||||
<< listenerconf.host.get();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssv.server_fd = fd;
|
|
||||||
|
|
||||||
if (get_config()->uid != 0) {
|
|
||||||
// fd is not associated to inode, so we cannot use fchown(2)
|
|
||||||
// here. https://lkml.org/lkml/2004/11/1/84
|
|
||||||
if (chown_to_running_user(listenerconf.host.get()) == -1) {
|
|
||||||
auto error = errno;
|
|
||||||
LOG(WARN) << "Changing owner of UNIX domain socket "
|
|
||||||
<< listenerconf.host.get() << " failed: " << strerror(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
close_env_fd({ENV_UNIX_FD});
|
|
||||||
auto fd6 = create_tcp_server_socket(AF_INET6);
|
|
||||||
auto fd4 = create_tcp_server_socket(AF_INET);
|
|
||||||
if (fd6 == -1 && fd4 == -1) {
|
|
||||||
LOG(FATAL) << "Failed to listen on address " << listenerconf.host.get()
|
|
||||||
<< ", port " << listenerconf.port;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssv.server_fd = fd4;
|
|
||||||
ssv.server_fd6 = fd6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto loop = EV_DEFAULT;
|
auto loop = EV_DEFAULT;
|
||||||
|
@ -986,8 +1117,6 @@ void fill_default_config() {
|
||||||
{
|
{
|
||||||
auto &listenerconf = connconf.listener;
|
auto &listenerconf = connconf.listener;
|
||||||
{
|
{
|
||||||
listenerconf.host = strcopy("*");
|
|
||||||
listenerconf.port = 3000;
|
|
||||||
// Default accept() backlog
|
// Default accept() backlog
|
||||||
listenerconf.backlog = 512;
|
listenerconf.backlog = 512;
|
||||||
listenerconf.timeout.sleep = 30_s;
|
listenerconf.timeout.sleep = 30_s;
|
||||||
|
@ -1120,9 +1249,10 @@ Connections:
|
||||||
Set frontend host and port. If <HOST> is '*', it
|
Set frontend host and port. If <HOST> is '*', it
|
||||||
assumes all addresses including both IPv4 and IPv6.
|
assumes all addresses including both IPv4 and IPv6.
|
||||||
UNIX domain socket can be specified by prefixing path
|
UNIX domain socket can be specified by prefixing path
|
||||||
name with "unix:" (e.g., unix:/var/run/nghttpx.sock)
|
name with "unix:" (e.g., unix:/var/run/nghttpx.sock).
|
||||||
Default: )" << get_config()->conn.listener.host.get() << ","
|
This option can be used multiple times to listen to
|
||||||
<< get_config()->conn.listener.port << R"(
|
multiple addresses.
|
||||||
|
Default: *,3000
|
||||||
--backlog=<N>
|
--backlog=<N>
|
||||||
Set listen backlog size.
|
Set listen backlog size.
|
||||||
Default: )" << get_config()->conn.listener.backlog << R"(
|
Default: )" << get_config()->conn.listener.backlog << R"(
|
||||||
|
@ -1838,6 +1968,13 @@ void process_options(
|
||||||
auto &upstreamconf = mod_config()->conn.upstream;
|
auto &upstreamconf = mod_config()->conn.upstream;
|
||||||
auto &downstreamconf = mod_config()->conn.downstream;
|
auto &downstreamconf = mod_config()->conn.downstream;
|
||||||
|
|
||||||
|
if (listenerconf.addrs.empty()) {
|
||||||
|
FrontendAddr addr;
|
||||||
|
addr.host = "*";
|
||||||
|
addr.port = 3000;
|
||||||
|
listenerconf.addrs.push_back(std::move(addr));
|
||||||
|
}
|
||||||
|
|
||||||
if (downstreamconf.ipv4 && downstreamconf.ipv6) {
|
if (downstreamconf.ipv4 && downstreamconf.ipv6) {
|
||||||
LOG(FATAL) << "--backend-ipv4 and --backend-ipv6 cannot be used at the "
|
LOG(FATAL) << "--backend-ipv4 and --backend-ipv6 cannot be used at the "
|
||||||
<< "same time.";
|
<< "same time.";
|
||||||
|
@ -1949,8 +2086,7 @@ void process_options(
|
||||||
// for AF_UNIX socket, we use "localhost" as host for backend
|
// for AF_UNIX socket, we use "localhost" as host for backend
|
||||||
// hostport. This is used as Host header field to backend and
|
// hostport. This is used as Host header field to backend and
|
||||||
// not going to be passed to any syscalls.
|
// not going to be passed to any syscalls.
|
||||||
addr.hostport = ImmutableString(
|
addr.hostport = "localhost";
|
||||||
util::make_hostport("localhost", listenerconf.port));
|
|
||||||
|
|
||||||
auto path = addr.host.c_str();
|
auto path = addr.host.c_str();
|
||||||
auto pathlen = addr.host.size();
|
auto pathlen = addr.host.size();
|
||||||
|
|
|
@ -45,16 +45,16 @@ void acceptcb(struct ev_loop *loop, ev_io *w, int revent) {
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
AcceptHandler::AcceptHandler(int fd, ConnectionHandler *h)
|
AcceptHandler::AcceptHandler(const FrontendAddr *faddr, ConnectionHandler *h)
|
||||||
: conn_hnr_(h), fd_(fd) {
|
: conn_hnr_(h), faddr_(faddr) {
|
||||||
ev_io_init(&wev_, acceptcb, fd_, EV_READ);
|
ev_io_init(&wev_, acceptcb, faddr_->fd, EV_READ);
|
||||||
wev_.data = this;
|
wev_.data = this;
|
||||||
ev_io_start(conn_hnr_->get_loop(), &wev_);
|
ev_io_start(conn_hnr_->get_loop(), &wev_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AcceptHandler::~AcceptHandler() {
|
AcceptHandler::~AcceptHandler() {
|
||||||
ev_io_stop(conn_hnr_->get_loop(), &wev_);
|
ev_io_stop(conn_hnr_->get_loop(), &wev_);
|
||||||
close(fd_);
|
close(faddr_->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AcceptHandler::accept_connection() {
|
void AcceptHandler::accept_connection() {
|
||||||
|
@ -63,10 +63,10 @@ void AcceptHandler::accept_connection() {
|
||||||
socklen_t addrlen = sizeof(sockaddr);
|
socklen_t addrlen = sizeof(sockaddr);
|
||||||
|
|
||||||
#ifdef HAVE_ACCEPT4
|
#ifdef HAVE_ACCEPT4
|
||||||
auto cfd =
|
auto cfd = accept4(faddr_->fd, &sockaddr.sa, &addrlen,
|
||||||
accept4(fd_, &sockaddr.sa, &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||||
#else // !HAVE_ACCEPT4
|
#else // !HAVE_ACCEPT4
|
||||||
auto cfd = accept(fd_, &sockaddr.sa, &addrlen);
|
auto cfd = accept(faddr_->fd, &sockaddr.sa, &addrlen);
|
||||||
#endif // !HAVE_ACCEPT4
|
#endif // !HAVE_ACCEPT4
|
||||||
|
|
||||||
if (cfd == -1) {
|
if (cfd == -1) {
|
||||||
|
@ -101,7 +101,7 @@ void AcceptHandler::accept_connection() {
|
||||||
|
|
||||||
util::make_socket_nodelay(cfd);
|
util::make_socket_nodelay(cfd);
|
||||||
|
|
||||||
conn_hnr_->handle_connection(cfd, &sockaddr.sa, addrlen);
|
conn_hnr_->handle_connection(cfd, &sockaddr.sa, addrlen, faddr_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +109,6 @@ void AcceptHandler::enable() { ev_io_start(conn_hnr_->get_loop(), &wev_); }
|
||||||
|
|
||||||
void AcceptHandler::disable() { ev_io_stop(conn_hnr_->get_loop(), &wev_); }
|
void AcceptHandler::disable() { ev_io_stop(conn_hnr_->get_loop(), &wev_); }
|
||||||
|
|
||||||
int AcceptHandler::get_fd() const { return fd_; }
|
int AcceptHandler::get_fd() const { return faddr_->fd; }
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -32,10 +32,11 @@
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
class ConnectionHandler;
|
class ConnectionHandler;
|
||||||
|
struct FrontendAddr;
|
||||||
|
|
||||||
class AcceptHandler {
|
class AcceptHandler {
|
||||||
public:
|
public:
|
||||||
AcceptHandler(int fd, ConnectionHandler *h);
|
AcceptHandler(const FrontendAddr *faddr, ConnectionHandler *h);
|
||||||
~AcceptHandler();
|
~AcceptHandler();
|
||||||
void accept_connection();
|
void accept_connection();
|
||||||
void enable();
|
void enable();
|
||||||
|
@ -45,7 +46,7 @@ public:
|
||||||
private:
|
private:
|
||||||
ev_io wev_;
|
ev_io wev_;
|
||||||
ConnectionHandler *conn_hnr_;
|
ConnectionHandler *conn_hnr_;
|
||||||
int fd_;
|
const FrontendAddr *faddr_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -377,7 +377,8 @@ int ClientHandler::upstream_http1_connhd_read() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
|
ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
|
||||||
const char *ipaddr, const char *port)
|
const char *ipaddr, const char *port,
|
||||||
|
const FrontendAddr *faddr)
|
||||||
: conn_(worker->get_loop(), fd, ssl, worker->get_mcpool(),
|
: conn_(worker->get_loop(), fd, ssl, worker->get_mcpool(),
|
||||||
get_config()->conn.upstream.timeout.write,
|
get_config()->conn.upstream.timeout.write,
|
||||||
get_config()->conn.upstream.timeout.read,
|
get_config()->conn.upstream.timeout.read,
|
||||||
|
@ -392,6 +393,7 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
|
||||||
: nullptr),
|
: nullptr),
|
||||||
ipaddr_(ipaddr),
|
ipaddr_(ipaddr),
|
||||||
port_(port),
|
port_(port),
|
||||||
|
faddr_(faddr),
|
||||||
worker_(worker),
|
worker_(worker),
|
||||||
left_connhd_len_(NGHTTP2_CLIENT_MAGIC_LEN),
|
left_connhd_len_(NGHTTP2_CLIENT_MAGIC_LEN),
|
||||||
should_close_after_write_(false) {
|
should_close_after_write_(false) {
|
||||||
|
@ -851,8 +853,8 @@ void ClientHandler::write_accesslog(Downstream *downstream) {
|
||||||
std::chrono::high_resolution_clock::now(), // request_end_time
|
std::chrono::high_resolution_clock::now(), // request_end_time
|
||||||
|
|
||||||
req.http_major, req.http_minor, resp.http_status,
|
req.http_major, req.http_minor, resp.http_status,
|
||||||
downstream->response_sent_body_length, StringRef(port_),
|
downstream->response_sent_body_length, StringRef(port_), faddr_->port,
|
||||||
get_config()->conn.listener.port, get_config()->pid,
|
get_config()->pid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -875,7 +877,7 @@ void ClientHandler::write_accesslog(int major, int minor, unsigned int status,
|
||||||
highres_now, // request_end_time
|
highres_now, // request_end_time
|
||||||
major, minor, // major, minor
|
major, minor, // major, minor
|
||||||
status, body_bytes_sent, StringRef(port_),
|
status, body_bytes_sent, StringRef(port_),
|
||||||
get_config()->conn.listener.port, get_config()->pid,
|
faddr_->port, get_config()->pid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1116,51 +1118,14 @@ int ClientHandler::proxy_protocol_read() {
|
||||||
return on_proxy_protocol_finish();
|
return on_proxy_protocol_finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &ClientHandler::get_forwarded_by() {
|
StringRef ClientHandler::get_forwarded_by() {
|
||||||
auto &fwdconf = get_config()->http.forwarded;
|
auto &fwdconf = get_config()->http.forwarded;
|
||||||
|
|
||||||
if (fwdconf.by_node_type == FORWARDED_NODE_OBFUSCATED) {
|
if (fwdconf.by_node_type == FORWARDED_NODE_OBFUSCATED) {
|
||||||
return fwdconf.by_obfuscated;
|
return StringRef(fwdconf.by_obfuscated);
|
||||||
}
|
|
||||||
if (!local_hostport_.empty()) {
|
|
||||||
return local_hostport_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &listenerconf = get_config()->conn.listener;
|
return StringRef(faddr_->hostport);
|
||||||
|
|
||||||
// For UNIX domain socket listener, just return empty string.
|
|
||||||
if (listenerconf.host_unix) {
|
|
||||||
return local_hostport_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rv;
|
|
||||||
sockaddr_union su;
|
|
||||||
socklen_t addrlen = sizeof(su);
|
|
||||||
|
|
||||||
rv = getsockname(conn_.fd, &su.sa, &addrlen);
|
|
||||||
if (rv != 0) {
|
|
||||||
return local_hostport_;
|
|
||||||
}
|
|
||||||
|
|
||||||
char host[NI_MAXHOST];
|
|
||||||
rv = getnameinfo(&su.sa, addrlen, host, sizeof(host), nullptr, 0,
|
|
||||||
NI_NUMERICHOST);
|
|
||||||
if (rv != 0) {
|
|
||||||
return local_hostport_;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (su.storage.ss_family == AF_INET6) {
|
|
||||||
local_hostport_ = "[";
|
|
||||||
local_hostport_ += host;
|
|
||||||
local_hostport_ += "]:";
|
|
||||||
} else {
|
|
||||||
local_hostport_ = host;
|
|
||||||
local_hostport_ += ':';
|
|
||||||
}
|
|
||||||
|
|
||||||
local_hostport_ += util::utos(listenerconf.port);
|
|
||||||
|
|
||||||
return local_hostport_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &ClientHandler::get_forwarded_for() const {
|
const std::string &ClientHandler::get_forwarded_for() const {
|
||||||
|
@ -1168,10 +1133,6 @@ const std::string &ClientHandler::get_forwarded_for() const {
|
||||||
return forwarded_for_obfuscated_;
|
return forwarded_for_obfuscated_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_config()->conn.listener.host_unix) {
|
|
||||||
return EMPTY_STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ipaddr_;
|
return ipaddr_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ struct WorkerStat;
|
||||||
class ClientHandler {
|
class ClientHandler {
|
||||||
public:
|
public:
|
||||||
ClientHandler(Worker *worker, int fd, SSL *ssl, const char *ipaddr,
|
ClientHandler(Worker *worker, int fd, SSL *ssl, const char *ipaddr,
|
||||||
const char *port);
|
const char *port, const FrontendAddr *faddr);
|
||||||
~ClientHandler();
|
~ClientHandler();
|
||||||
|
|
||||||
int noop();
|
int noop();
|
||||||
|
@ -136,7 +136,7 @@ public:
|
||||||
|
|
||||||
// Returns string suitable for use in "by" parameter of Forwarded
|
// Returns string suitable for use in "by" parameter of Forwarded
|
||||||
// header field.
|
// header field.
|
||||||
const std::string &get_forwarded_by();
|
StringRef get_forwarded_by();
|
||||||
// Returns string suitable for use in "for" parameter of Forwarded
|
// Returns string suitable for use in "for" parameter of Forwarded
|
||||||
// header field.
|
// header field.
|
||||||
const std::string &get_forwarded_for() const;
|
const std::string &get_forwarded_for() const;
|
||||||
|
@ -152,13 +152,13 @@ private:
|
||||||
std::string port_;
|
std::string port_;
|
||||||
// The ALPN identifier negotiated for this connection.
|
// The ALPN identifier negotiated for this connection.
|
||||||
std::string alpn_;
|
std::string alpn_;
|
||||||
// Host and port of this socket (e.g., "[::1]:8443")
|
|
||||||
std::string local_hostport_;
|
|
||||||
// The obfuscated version of client address used in "for" parameter
|
// The obfuscated version of client address used in "for" parameter
|
||||||
// of Forwarded header field.
|
// of Forwarded header field.
|
||||||
std::string forwarded_for_obfuscated_;
|
std::string forwarded_for_obfuscated_;
|
||||||
std::function<int(ClientHandler &)> read_, write_;
|
std::function<int(ClientHandler &)> read_, write_;
|
||||||
std::function<int(ClientHandler &)> on_read_, on_write_;
|
std::function<int(ClientHandler &)> on_read_, on_write_;
|
||||||
|
// Address of frontend listening socket
|
||||||
|
const FrontendAddr *faddr_;
|
||||||
Worker *worker_;
|
Worker *worker_;
|
||||||
// The number of bytes of HTTP/2 client connection header to read
|
// The number of bytes of HTTP/2 client connection header to read
|
||||||
size_t left_connhd_len_;
|
size_t left_connhd_len_;
|
||||||
|
|
|
@ -1428,11 +1428,15 @@ int parse_config(const char *opt, const char *optarg,
|
||||||
case SHRPX_OPTID_FRONTEND: {
|
case SHRPX_OPTID_FRONTEND: {
|
||||||
auto &listenerconf = mod_config()->conn.listener;
|
auto &listenerconf = mod_config()->conn.listener;
|
||||||
|
|
||||||
|
FrontendAddr addr{};
|
||||||
|
addr.fd = -1;
|
||||||
|
|
||||||
if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) {
|
if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) {
|
||||||
auto path = optarg + str_size(SHRPX_UNIX_PATH_PREFIX);
|
auto path = optarg + str_size(SHRPX_UNIX_PATH_PREFIX);
|
||||||
listenerconf.host = strcopy(path);
|
addr.host = ImmutableString(path);
|
||||||
listenerconf.port = 0;
|
addr.host_unix = true;
|
||||||
listenerconf.host_unix = true;
|
|
||||||
|
listenerconf.addrs.push_back(std::move(addr));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1442,9 +1446,26 @@ int parse_config(const char *opt, const char *optarg,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
listenerconf.host = strcopy(host);
|
addr.host = ImmutableString(host);
|
||||||
listenerconf.port = port;
|
addr.port = port;
|
||||||
listenerconf.host_unix = false;
|
|
||||||
|
if (util::numeric_host(host, AF_INET)) {
|
||||||
|
addr.family = AF_INET;
|
||||||
|
listenerconf.addrs.push_back(std::move(addr));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (util::numeric_host(host, AF_INET6)) {
|
||||||
|
addr.family = AF_INET6;
|
||||||
|
listenerconf.addrs.push_back(std::move(addr));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr.family = AF_INET;
|
||||||
|
listenerconf.addrs.push_back(addr);
|
||||||
|
|
||||||
|
addr.family = AF_INET6;
|
||||||
|
listenerconf.addrs.push_back(std::move(addr));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,6 +239,24 @@ struct AltSvc {
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FrontendAddr {
|
||||||
|
// The frontend address (e.g., FQDN, hostname, IP address). If
|
||||||
|
// |host_unix| is true, this is UNIX domain socket path.
|
||||||
|
ImmutableString host;
|
||||||
|
// For TCP socket, this is <IP address>:<PORT>. For IPv6 address,
|
||||||
|
// address is surrounded by square brackets. If socket is UNIX
|
||||||
|
// domain socket, this is "localhost".
|
||||||
|
ImmutableString hostport;
|
||||||
|
// frontend port. 0 if |host_unix| is true.
|
||||||
|
uint16_t port;
|
||||||
|
// For TCP socket, this is either AF_INET or AF_INET6. For UNIX
|
||||||
|
// domain socket, this is 0.
|
||||||
|
int family;
|
||||||
|
// true if |host| contains UNIX domain socket path.
|
||||||
|
bool host_unix;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
struct DownstreamAddr {
|
struct DownstreamAddr {
|
||||||
DownstreamAddr() : addr{}, port(0), host_unix(false) {}
|
DownstreamAddr() : addr{}, port(0), host_unix(false) {}
|
||||||
DownstreamAddr(const DownstreamAddr &other);
|
DownstreamAddr(const DownstreamAddr &other);
|
||||||
|
@ -464,14 +482,8 @@ struct ConnectionConfig {
|
||||||
struct {
|
struct {
|
||||||
ev_tstamp sleep;
|
ev_tstamp sleep;
|
||||||
} timeout;
|
} timeout;
|
||||||
// address of frontend connection. This could be a path to UNIX
|
// address of frontend acceptors
|
||||||
// domain socket. In this case, |host_unix| must be true.
|
std::vector<FrontendAddr> addrs;
|
||||||
std::unique_ptr<char[]> host;
|
|
||||||
// frontend listening port. 0 if frontend listens on UNIX domain
|
|
||||||
// socket, in this case |host_unix| must be true.
|
|
||||||
uint16_t port;
|
|
||||||
// true if host contains UNIX domain socket path
|
|
||||||
bool host_unix;
|
|
||||||
int backlog;
|
int backlog;
|
||||||
// TCP fastopen. If this is positive, it is passed to
|
// TCP fastopen. If this is positive, it is passed to
|
||||||
// setsockopt() along with TCP_FASTOPEN.
|
// setsockopt() along with TCP_FASTOPEN.
|
||||||
|
|
|
@ -297,7 +297,8 @@ void ConnectionHandler::graceful_shutdown_worker() {
|
||||||
#endif // NOTHREADS
|
#endif // NOTHREADS
|
||||||
}
|
}
|
||||||
|
|
||||||
int ConnectionHandler::handle_connection(int fd, sockaddr *addr, int addrlen) {
|
int ConnectionHandler::handle_connection(int fd, sockaddr *addr, int addrlen,
|
||||||
|
const FrontendAddr *faddr) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
LLOG(INFO, this) << "Accepted connection. fd=" << fd;
|
LLOG(INFO, this) << "Accepted connection. fd=" << fd;
|
||||||
}
|
}
|
||||||
|
@ -317,7 +318,7 @@ int ConnectionHandler::handle_connection(int fd, sockaddr *addr, int addrlen) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto client =
|
auto client =
|
||||||
ssl::accept_connection(single_worker_.get(), fd, addr, addrlen);
|
ssl::accept_connection(single_worker_.get(), fd, addr, addrlen, faddr);
|
||||||
if (!client) {
|
if (!client) {
|
||||||
LLOG(ERROR, this) << "ClientHandler creation failed";
|
LLOG(ERROR, this) << "ClientHandler creation failed";
|
||||||
|
|
||||||
|
@ -338,6 +339,7 @@ int ConnectionHandler::handle_connection(int fd, sockaddr *addr, int addrlen) {
|
||||||
wev.client_fd = fd;
|
wev.client_fd = fd;
|
||||||
memcpy(&wev.client_addr, addr, addrlen);
|
memcpy(&wev.client_addr, addr, addrlen);
|
||||||
wev.client_addrlen = addrlen;
|
wev.client_addrlen = addrlen;
|
||||||
|
wev.faddr = faddr;
|
||||||
|
|
||||||
workers_[idx]->send(wev);
|
workers_[idx]->send(wev);
|
||||||
|
|
||||||
|
@ -352,39 +354,19 @@ Worker *ConnectionHandler::get_single_worker() const {
|
||||||
return single_worker_.get();
|
return single_worker_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionHandler::set_acceptor(std::unique_ptr<AcceptHandler> h) {
|
void ConnectionHandler::add_acceptor(std::unique_ptr<AcceptHandler> h) {
|
||||||
acceptor_ = std::move(h);
|
acceptors_.push_back(std::move(h));
|
||||||
}
|
|
||||||
|
|
||||||
AcceptHandler *ConnectionHandler::get_acceptor() const {
|
|
||||||
return acceptor_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConnectionHandler::set_acceptor6(std::unique_ptr<AcceptHandler> h) {
|
|
||||||
acceptor6_ = std::move(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
AcceptHandler *ConnectionHandler::get_acceptor6() const {
|
|
||||||
return acceptor6_.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionHandler::enable_acceptor() {
|
void ConnectionHandler::enable_acceptor() {
|
||||||
if (acceptor_) {
|
for (auto &a : acceptors_) {
|
||||||
acceptor_->enable();
|
a->enable();
|
||||||
}
|
|
||||||
|
|
||||||
if (acceptor6_) {
|
|
||||||
acceptor6_->enable();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionHandler::disable_acceptor() {
|
void ConnectionHandler::disable_acceptor() {
|
||||||
if (acceptor_) {
|
for (auto &a : acceptors_) {
|
||||||
acceptor_->disable();
|
a->disable();
|
||||||
}
|
|
||||||
|
|
||||||
if (acceptor6_) {
|
|
||||||
acceptor6_->disable();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,11 +382,8 @@ void ConnectionHandler::sleep_acceptor(ev_tstamp t) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionHandler::accept_pending_connection() {
|
void ConnectionHandler::accept_pending_connection() {
|
||||||
if (acceptor_) {
|
for (auto &a : acceptors_) {
|
||||||
acceptor_->accept_connection();
|
a->accept_connection();
|
||||||
}
|
|
||||||
if (acceptor6_) {
|
|
||||||
acceptor6_->accept_connection();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ class Worker;
|
||||||
struct WorkerStat;
|
struct WorkerStat;
|
||||||
struct TicketKeys;
|
struct TicketKeys;
|
||||||
class MemcachedDispatcher;
|
class MemcachedDispatcher;
|
||||||
|
struct FrontendAddr;
|
||||||
|
|
||||||
struct OCSPUpdateContext {
|
struct OCSPUpdateContext {
|
||||||
// ocsp response buffer
|
// ocsp response buffer
|
||||||
|
@ -79,7 +80,8 @@ class ConnectionHandler {
|
||||||
public:
|
public:
|
||||||
ConnectionHandler(struct ev_loop *loop);
|
ConnectionHandler(struct ev_loop *loop);
|
||||||
~ConnectionHandler();
|
~ConnectionHandler();
|
||||||
int handle_connection(int fd, sockaddr *addr, int addrlen);
|
int handle_connection(int fd, sockaddr *addr, int addrlen,
|
||||||
|
const FrontendAddr *faddr);
|
||||||
// Creates Worker object for single threaded configuration.
|
// Creates Worker object for single threaded configuration.
|
||||||
int create_single_worker();
|
int create_single_worker();
|
||||||
// Creates |num| Worker objects for multi threaded configuration.
|
// Creates |num| Worker objects for multi threaded configuration.
|
||||||
|
@ -92,10 +94,7 @@ public:
|
||||||
const std::shared_ptr<TicketKeys> &get_ticket_keys() const;
|
const std::shared_ptr<TicketKeys> &get_ticket_keys() const;
|
||||||
struct ev_loop *get_loop() const;
|
struct ev_loop *get_loop() const;
|
||||||
Worker *get_single_worker() const;
|
Worker *get_single_worker() const;
|
||||||
void set_acceptor(std::unique_ptr<AcceptHandler> h);
|
void add_acceptor(std::unique_ptr<AcceptHandler> h);
|
||||||
AcceptHandler *get_acceptor() const;
|
|
||||||
void set_acceptor6(std::unique_ptr<AcceptHandler> h);
|
|
||||||
AcceptHandler *get_acceptor6() const;
|
|
||||||
void enable_acceptor();
|
void enable_acceptor();
|
||||||
void disable_acceptor();
|
void disable_acceptor();
|
||||||
void sleep_acceptor(ev_tstamp t);
|
void sleep_acceptor(ev_tstamp t);
|
||||||
|
@ -154,10 +153,7 @@ private:
|
||||||
// Worker object.
|
// Worker object.
|
||||||
std::shared_ptr<TicketKeys> ticket_keys_;
|
std::shared_ptr<TicketKeys> ticket_keys_;
|
||||||
struct ev_loop *loop_;
|
struct ev_loop *loop_;
|
||||||
// acceptor for IPv4 address or UNIX domain socket.
|
std::vector<std::unique_ptr<AcceptHandler>> acceptors_;
|
||||||
std::unique_ptr<AcceptHandler> acceptor_;
|
|
||||||
// acceptor for IPv6 address
|
|
||||||
std::unique_ptr<AcceptHandler> acceptor6_;
|
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
std::unique_ptr<neverbleed_t> nb_;
|
std::unique_ptr<neverbleed_t> nb_;
|
||||||
#endif // HAVE_NEVERBLEED
|
#endif // HAVE_NEVERBLEED
|
||||||
|
|
|
@ -46,8 +46,6 @@ std::string create_error_html(unsigned int status_code) {
|
||||||
res += "</h1><footer>";
|
res += "</h1><footer>";
|
||||||
const auto &server_name = get_config()->http.server_name;
|
const auto &server_name = get_config()->http.server_name;
|
||||||
res.append(server_name.c_str(), server_name.size());
|
res.append(server_name.c_str(), server_name.size());
|
||||||
res += " at port ";
|
|
||||||
res += util::utos(get_config()->conn.listener.port);
|
|
||||||
res += "</footer></body></html>";
|
res += "</footer></body></html>";
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +61,7 @@ std::string create_via_header_value(int major, int minor) {
|
||||||
return hdrs;
|
return hdrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string create_forwarded(int params, const std::string &node_by,
|
std::string create_forwarded(int params, const StringRef &node_by,
|
||||||
const std::string &node_for,
|
const std::string &node_for,
|
||||||
const std::string &host,
|
const std::string &host,
|
||||||
const std::string &proto) {
|
const std::string &proto) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ std::string create_via_header_value(int major, int minor);
|
||||||
// Returns generated RFC 7239 Forwarded header field value. The
|
// Returns generated RFC 7239 Forwarded header field value. The
|
||||||
// |params| is bitwise-OR of zero or more of shrpx_forwarded_param
|
// |params| is bitwise-OR of zero or more of shrpx_forwarded_param
|
||||||
// defined in shrpx_config.h.
|
// defined in shrpx_config.h.
|
||||||
std::string create_forwarded(int params, const std::string &node_by,
|
std::string create_forwarded(int params, const StringRef &node_by,
|
||||||
const std::string &node_for,
|
const std::string &node_for,
|
||||||
const std::string &host, const std::string &proto);
|
const std::string &host, const std::string &proto);
|
||||||
|
|
||||||
|
|
|
@ -747,7 +747,7 @@ SSL *create_ssl(SSL_CTX *ssl_ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
|
ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
|
||||||
int addrlen) {
|
int addrlen, const FrontendAddr *faddr) {
|
||||||
char host[NI_MAXHOST];
|
char host[NI_MAXHOST];
|
||||||
char service[NI_MAXSERV];
|
char service[NI_MAXSERV];
|
||||||
int rv;
|
int rv;
|
||||||
|
@ -783,7 +783,7 @@ ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ClientHandler(worker, fd, ssl, host, service);
|
return new ClientHandler(worker, fd, ssl, host, service, faddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tls_hostname_match(const char *pattern, size_t plen, const char *hostname,
|
bool tls_hostname_match(const char *pattern, size_t plen, const char *hostname,
|
||||||
|
|
|
@ -45,6 +45,7 @@ class ClientHandler;
|
||||||
class Worker;
|
class Worker;
|
||||||
class DownstreamConnectionPool;
|
class DownstreamConnectionPool;
|
||||||
struct DownstreamAddr;
|
struct DownstreamAddr;
|
||||||
|
struct FrontendAddr;
|
||||||
|
|
||||||
namespace ssl {
|
namespace ssl {
|
||||||
|
|
||||||
|
@ -76,7 +77,7 @@ SSL_CTX *create_ssl_client_context(
|
||||||
);
|
);
|
||||||
|
|
||||||
ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
|
ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
|
||||||
int addrlen);
|
int addrlen, const FrontendAddr *faddr);
|
||||||
|
|
||||||
// Check peer's certificate against first downstream address in
|
// Check peer's certificate against first downstream address in
|
||||||
// Config::downstream_addrs. We only consider first downstream since
|
// Config::downstream_addrs. We only consider first downstream since
|
||||||
|
|
|
@ -179,8 +179,9 @@ void Worker::process_events() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto client_handler = ssl::accept_connection(
|
auto client_handler =
|
||||||
this, wev.client_fd, &wev.client_addr.sa, wev.client_addrlen);
|
ssl::accept_connection(this, wev.client_fd, &wev.client_addr.sa,
|
||||||
|
wev.client_addrlen, wev.faddr);
|
||||||
if (!client_handler) {
|
if (!client_handler) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
WLOG(ERROR, this) << "ClientHandler creation failed";
|
WLOG(ERROR, this) << "ClientHandler creation failed";
|
||||||
|
|
|
@ -51,6 +51,7 @@ namespace shrpx {
|
||||||
class Http2Session;
|
class Http2Session;
|
||||||
class ConnectBlocker;
|
class ConnectBlocker;
|
||||||
class MemcachedDispatcher;
|
class MemcachedDispatcher;
|
||||||
|
struct FrontendAddr;
|
||||||
|
|
||||||
#ifdef HAVE_MRUBY
|
#ifdef HAVE_MRUBY
|
||||||
namespace mruby {
|
namespace mruby {
|
||||||
|
@ -93,6 +94,7 @@ struct WorkerEvent {
|
||||||
sockaddr_union client_addr;
|
sockaddr_union client_addr;
|
||||||
size_t client_addrlen;
|
size_t client_addrlen;
|
||||||
int client_fd;
|
int client_fd;
|
||||||
|
const FrontendAddr *faddr;
|
||||||
};
|
};
|
||||||
std::shared_ptr<TicketKeys> ticket_keys;
|
std::shared_ptr<TicketKeys> ticket_keys;
|
||||||
};
|
};
|
||||||
|
|
|
@ -389,13 +389,8 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
|
||||||
|
|
||||||
ConnectionHandler conn_handler(loop);
|
ConnectionHandler conn_handler(loop);
|
||||||
|
|
||||||
if (wpconf->server_fd6 != -1) {
|
for (auto &addr : get_config()->conn.listener.addrs) {
|
||||||
conn_handler.set_acceptor6(
|
conn_handler.add_acceptor(make_unique<AcceptHandler>(&addr, &conn_handler));
|
||||||
make_unique<AcceptHandler>(wpconf->server_fd6, &conn_handler));
|
|
||||||
}
|
|
||||||
if (wpconf->server_fd != -1) {
|
|
||||||
conn_handler.set_acceptor(
|
|
||||||
make_unique<AcceptHandler>(wpconf->server_fd, &conn_handler));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &upstreamconf = get_config()->conn.upstream;
|
auto &upstreamconf = get_config()->conn.upstream;
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
namespace nghttp2 {
|
namespace nghttp2 {
|
||||||
|
|
||||||
|
@ -317,6 +318,11 @@ private:
|
||||||
const char *base;
|
const char *base;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline bool operator==(const ImmutableString &lhs, const ImmutableString &rhs) {
|
||||||
|
return lhs.size() == rhs.size() &&
|
||||||
|
std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
inline bool operator==(const ImmutableString &lhs, const std::string &rhs) {
|
inline bool operator==(const ImmutableString &lhs, const std::string &rhs) {
|
||||||
return lhs.size() == rhs.size() &&
|
return lhs.size() == rhs.size() &&
|
||||||
std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
|
std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
|
||||||
|
@ -335,6 +341,10 @@ inline bool operator==(const char *lhs, const ImmutableString &rhs) {
|
||||||
return rhs == lhs;
|
return rhs == lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(const ImmutableString &lhs, const ImmutableString &rhs) {
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
inline bool operator!=(const ImmutableString &lhs, const std::string &rhs) {
|
inline bool operator!=(const ImmutableString &lhs, const std::string &rhs) {
|
||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
@ -351,6 +361,15 @@ inline bool operator!=(const char *lhs, const ImmutableString &rhs) {
|
||||||
return !(rhs == lhs);
|
return !(rhs == lhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::ostream &operator<<(std::ostream &o, const ImmutableString &s) {
|
||||||
|
return o.write(s.c_str(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string &operator+=(std::string &lhs, const ImmutableString &rhs) {
|
||||||
|
lhs.append(rhs.c_str(), rhs.size());
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
// StringRef is a reference to a string owned by something else. So
|
// StringRef is a reference to a string owned by something else. So
|
||||||
// it behaves like simple string, but it does not own pointer. When
|
// it behaves like simple string, but it does not own pointer. When
|
||||||
// it is default constructed, it has empty string. You can freely
|
// it is default constructed, it has empty string. You can freely
|
||||||
|
@ -374,7 +393,9 @@ public:
|
||||||
: base(s.c_str()), len(s.size()) {}
|
: base(s.c_str()), len(s.size()) {}
|
||||||
StringRef(const char *s) : base(s), len(strlen(s)) {}
|
StringRef(const char *s) : base(s), len(strlen(s)) {}
|
||||||
StringRef(const char *s, size_t n) : base(s), len(n) {}
|
StringRef(const char *s, size_t n) : base(s), len(n) {}
|
||||||
|
template <typename InputIt>
|
||||||
|
StringRef(InputIt first, InputIt last)
|
||||||
|
: base(first), len(std::distance(first, last)) {}
|
||||||
template <size_t N> static StringRef from_lit(const char(&s)[N]) {
|
template <size_t N> static StringRef from_lit(const char(&s)[N]) {
|
||||||
return StringRef(s, N - 1);
|
return StringRef(s, N - 1);
|
||||||
}
|
}
|
||||||
|
@ -388,6 +409,7 @@ public:
|
||||||
const char *c_str() const { return base; }
|
const char *c_str() const { return base; }
|
||||||
size_type size() const { return len; }
|
size_type size() const { return len; }
|
||||||
bool empty() const { return len == 0; }
|
bool empty() const { return len == 0; }
|
||||||
|
const_reference operator[](size_type pos) const { return *(base + pos); }
|
||||||
|
|
||||||
std::string str() const { return std::string(base, len); }
|
std::string str() const { return std::string(base, len); }
|
||||||
|
|
||||||
|
@ -430,6 +452,15 @@ inline bool operator!=(const char *lhs, const StringRef &rhs) {
|
||||||
return !(rhs == lhs);
|
return !(rhs == lhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::ostream &operator<<(std::ostream &o, const StringRef &s) {
|
||||||
|
return o.write(s.c_str(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string &operator+=(std::string &lhs, const StringRef &rhs) {
|
||||||
|
lhs.append(rhs.c_str(), rhs.size());
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
inline int run_app(std::function<int(int, char **)> app, int argc,
|
inline int run_app(std::function<int(int, char **)> app, int argc,
|
||||||
char **argv) {
|
char **argv) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include <CUnit/CUnit.h>
|
#include <CUnit/CUnit.h>
|
||||||
|
|
||||||
|
@ -101,6 +102,34 @@ void test_template_immutable_string(void) {
|
||||||
CU_ASSERT('o' == br_op[1]);
|
CU_ASSERT('o' == br_op[1]);
|
||||||
CU_ASSERT('t' == br_op[6]);
|
CU_ASSERT('t' == br_op[6]);
|
||||||
CU_ASSERT('\0' == br_op[7]);
|
CU_ASSERT('\0' == br_op[7]);
|
||||||
|
|
||||||
|
// operator==(const ImmutableString &, const ImmutableString &)
|
||||||
|
{
|
||||||
|
ImmutableString a("foo");
|
||||||
|
ImmutableString b("foo");
|
||||||
|
ImmutableString c("fo");
|
||||||
|
|
||||||
|
CU_ASSERT(a == b);
|
||||||
|
CU_ASSERT(a != c);
|
||||||
|
CU_ASSERT(c != b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// operator<<
|
||||||
|
{
|
||||||
|
ImmutableString a("foo");
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << a;
|
||||||
|
|
||||||
|
CU_ASSERT("foo" == ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// operator +=(std::string &, const ImmutableString &)
|
||||||
|
{
|
||||||
|
std::string a = "alpha";
|
||||||
|
a += ImmutableString("bravo");
|
||||||
|
|
||||||
|
CU_ASSERT("alphabravo" == a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_template_string_ref(void) {
|
void test_template_string_ref(void) {
|
||||||
|
@ -145,6 +174,31 @@ void test_template_string_ref(void) {
|
||||||
|
|
||||||
CU_ASSERT("delta" == cstrnref);
|
CU_ASSERT("delta" == cstrnref);
|
||||||
CU_ASSERT(5 == cstrnref.size());
|
CU_ASSERT(5 == cstrnref.size());
|
||||||
|
|
||||||
|
// operator[]
|
||||||
|
StringRef br_op("foxtrot");
|
||||||
|
|
||||||
|
CU_ASSERT('f' == br_op[0]);
|
||||||
|
CU_ASSERT('o' == br_op[1]);
|
||||||
|
CU_ASSERT('t' == br_op[6]);
|
||||||
|
CU_ASSERT('\0' == br_op[7]);
|
||||||
|
|
||||||
|
// operator<<
|
||||||
|
{
|
||||||
|
StringRef a("foo");
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << a;
|
||||||
|
|
||||||
|
CU_ASSERT("foo" == ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// operator +=(std::string &, const StringRef &)
|
||||||
|
{
|
||||||
|
std::string a = "alpha";
|
||||||
|
a += StringRef("bravo");
|
||||||
|
|
||||||
|
CU_ASSERT("alphabravo" == a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace nghttp2
|
} // namespace nghttp2
|
||||||
|
|
Loading…
Reference in New Issue