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 {
|
||||
|
||||
// Environment variables to tell new binary the listening socket's
|
||||
// file descriptors. They are not close-on-exec.
|
||||
// Deprecated: Environment variables to tell new binary the listening
|
||||
// socket's file descriptors. They are not close-on-exec.
|
||||
#define ENV_LISTENER4_FD "NGHTTPX_LISTENER4_FD"
|
||||
#define ENV_LISTENER6_FD "NGHTTPX_LISTENER6_FD"
|
||||
|
||||
// Environment variable to tell new binary the port number the current
|
||||
// binary is listening to.
|
||||
// Deprecated: Environment variable to tell new binary the port number
|
||||
// the current binary is listening to.
|
||||
#define ENV_PORT "NGHTTPX_PORT"
|
||||
|
||||
// Environment variable to tell new binary the listening socket's file
|
||||
// descriptor if frontend listens UNIX domain socket.
|
||||
// Deprecated: Environment variable to tell new binary the listening
|
||||
// socket's file descriptor if frontend listens UNIX domain socket.
|
||||
#define ENV_UNIX_FD "NGHTTP2_UNIX_FD"
|
||||
// Environment variable to tell new binary the UNIX domain socket
|
||||
// path.
|
||||
// Deprecated: Environment variable to tell new binary the UNIX domain
|
||||
// socket 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
|
||||
#define _KERNEL_FASTOPEN
|
||||
// conditional define for TCP_FASTOPEN mostly on ubuntu
|
||||
|
@ -122,18 +130,8 @@ namespace shrpx {
|
|||
#endif
|
||||
|
||||
struct SignalServer {
|
||||
SignalServer()
|
||||
: ipc_fd{{-1, -1}},
|
||||
server_fd(-1),
|
||||
server_fd6(-1),
|
||||
worker_process_pid(-1) {}
|
||||
SignalServer() : ipc_fd{{-1, -1}}, worker_process_pid(-1) {}
|
||||
~SignalServer() {
|
||||
if (server_fd6 != -1) {
|
||||
close(server_fd6);
|
||||
}
|
||||
if (server_fd != -1) {
|
||||
close(server_fd);
|
||||
}
|
||||
if (ipc_fd[0] != -1) {
|
||||
close(ipc_fd[0]);
|
||||
}
|
||||
|
@ -144,10 +142,6 @@ struct SignalServer {
|
|||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -295,42 +289,35 @@ void exec_binary(SignalServer *ssv) {
|
|||
size_t envlen = 0;
|
||||
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;
|
||||
|
||||
if (listenerconf.host_unix) {
|
||||
fd = ENV_UNIX_FD "=";
|
||||
fd += util::utos(ssv->server_fd);
|
||||
envp[envidx++] = &fd[0];
|
||||
auto envp = make_unique<char *[]>(envlen + listenerconf.addrs.size() + 1);
|
||||
size_t envidx = 0;
|
||||
|
||||
path = ENV_UNIX_PATH "=";
|
||||
path += listenerconf.host.get();
|
||||
envp[envidx++] = &path[0];
|
||||
} else {
|
||||
if (ssv->server_fd) {
|
||||
fd = ENV_LISTENER4_FD "=";
|
||||
fd += util::utos(ssv->server_fd);
|
||||
envp[envidx++] = &fd[0];
|
||||
std::vector<ImmutableString> fd_envs;
|
||||
for (size_t i = 0; i < listenerconf.addrs.size(); ++i) {
|
||||
auto &addr = listenerconf.addrs[i];
|
||||
std::string s = ENV_ACCEPT_PREFIX;
|
||||
s += util::utos(i + 1);
|
||||
s += '=';
|
||||
if (addr.host_unix) {
|
||||
s += "unix,";
|
||||
s += util::utos(addr.fd);
|
||||
s += ',';
|
||||
s += addr.host;
|
||||
} else {
|
||||
s += "tcp,";
|
||||
s += util::utos(addr.fd);
|
||||
}
|
||||
|
||||
if (ssv->server_fd6) {
|
||||
fd6 = ENV_LISTENER6_FD "=";
|
||||
fd6 += util::utos(ssv->server_fd6);
|
||||
envp[envidx++] = &fd6[0];
|
||||
}
|
||||
|
||||
port = ENV_PORT "=";
|
||||
port += util::utos(listenerconf.port);
|
||||
envp[envidx++] = &port[0];
|
||||
fd_envs.emplace_back(s);
|
||||
envp[envidx++] = const_cast<char *>(fd_envs.back().c_str());
|
||||
}
|
||||
|
||||
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_PORT) ||
|
||||
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
|
||||
|
||||
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 {
|
||||
int create_unix_domain_server_socket() {
|
||||
auto &listenerconf = get_config()->conn.listener;
|
||||
int create_unix_domain_server_socket(FrontendAddr &faddr,
|
||||
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();
|
||||
auto pathlen = strlen(path);
|
||||
{
|
||||
auto envfd = getenv(ENV_UNIX_FD);
|
||||
auto envpath = getenv(ENV_UNIX_PATH);
|
||||
if (envfd && envpath) {
|
||||
auto fd = strtoul(envfd, nullptr, 10);
|
||||
if (found != std::end(iaddrs)) {
|
||||
LOG(NOTICE) << "Listening on UNIX domain socket " << faddr.host;
|
||||
(*found).used = true;
|
||||
faddr.fd = (*found).fd;
|
||||
faddr.hostport = "localhost";
|
||||
|
||||
if (util::streq(envpath, path)) {
|
||||
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);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SOCK_NONBLOCK
|
||||
auto fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||
if (fd == -1) {
|
||||
auto error = errno;
|
||||
LOG(WARN) << "socket() syscall failed: " << strerror(error);
|
||||
return -1;
|
||||
}
|
||||
#else // !SOCK_NONBLOCK
|
||||
auto fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd == -1) {
|
||||
auto error = errno;
|
||||
LOG(WARN) << "socket() syscall failed: " << strerror(error);
|
||||
return -1;
|
||||
}
|
||||
util::make_socket_nonblocking(fd);
|
||||
|
@ -471,115 +465,122 @@ int create_unix_domain_server_socket() {
|
|||
int val = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sockaddr_union addr;
|
||||
addr.un.sun_family = AF_UNIX;
|
||||
if (pathlen + 1 > sizeof(addr.un.sun_path)) {
|
||||
LOG(FATAL) << "UNIX domain socket path " << path << " is too long > "
|
||||
if (faddr.host.size() + 1 > sizeof(addr.un.sun_path)) {
|
||||
LOG(FATAL) << "UNIX domain socket path " << faddr.host << " is too long > "
|
||||
<< sizeof(addr.un.sun_path);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
// 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(path);
|
||||
unlink(faddr.host.c_str());
|
||||
|
||||
if (bind(fd, &addr.sa, sizeof(addr.un)) != 0) {
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto &listenerconf = get_config()->conn.listener;
|
||||
|
||||
if (listen(fd, listenerconf.backlog) != 0) {
|
||||
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);
|
||||
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 {
|
||||
int create_tcp_server_socket(int family) {
|
||||
auto &listenerconf = get_config()->conn.listener;
|
||||
|
||||
{
|
||||
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 create_tcp_server_socket(FrontendAddr &faddr,
|
||||
std::vector<InheritedAddr> &iaddrs) {
|
||||
int fd = -1;
|
||||
int rv;
|
||||
|
||||
auto service = util::utos(listenerconf.port);
|
||||
auto &listenerconf = get_config()->conn.listener;
|
||||
|
||||
auto service = util::utos(faddr.port);
|
||||
addrinfo hints{};
|
||||
hints.ai_family = family;
|
||||
hints.ai_family = faddr.family;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
#ifdef AI_ADDRCONFIG
|
||||
hints.ai_flags |= AI_ADDRCONFIG;
|
||||
#endif // AI_ADDRCONFIG
|
||||
|
||||
auto node = strcmp("*", listenerconf.host.get()) == 0
|
||||
? nullptr
|
||||
: listenerconf.host.get();
|
||||
auto node = faddr.host == "*" ? nullptr : faddr.host.c_str();
|
||||
|
||||
addrinfo *res, *rp;
|
||||
rv = getaddrinfo(node, service.c_str(), &hints, &res);
|
||||
if (rv != 0) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "Unable to get IPv" << (family == AF_INET ? "4" : "6")
|
||||
<< " address for " << listenerconf.host.get() << ": "
|
||||
<< gai_strerror(rv);
|
||||
LOG(INFO) << "Unable to get IPv" << (faddr.family == AF_INET ? "4" : "6")
|
||||
<< " address for " << faddr.host << ", port " << faddr.port
|
||||
<< ": " << gai_strerror(rv);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto res_d = defer(freeaddrinfo, res);
|
||||
|
||||
std::array<char, NI_MAXHOST> host;
|
||||
|
||||
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
|
||||
fd =
|
||||
socket(rp->ai_family, rp->ai_socktype | SOCK_NONBLOCK, rp->ai_protocol);
|
||||
if (fd == -1) {
|
||||
auto error = errno;
|
||||
LOG(WARN) << "socket() syscall failed, error=" << error;
|
||||
LOG(WARN) << "socket() syscall failed: " << strerror(error);
|
||||
continue;
|
||||
}
|
||||
#else // !SOCK_NONBLOCK
|
||||
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if (fd == -1) {
|
||||
auto error = errno;
|
||||
LOG(WARN) << "socket() syscall failed, error=" << error;
|
||||
LOG(WARN) << "socket() syscall failed: " << strerror(error);
|
||||
continue;
|
||||
}
|
||||
util::make_socket_nonblocking(fd);
|
||||
|
@ -588,21 +589,19 @@ int create_tcp_server_socket(int family) {
|
|||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
|
||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||
auto error = errno;
|
||||
LOG(WARN)
|
||||
<< "Failed to set SO_REUSEADDR option to listener socket, error="
|
||||
<< error;
|
||||
LOG(WARN) << "Failed to set SO_REUSEADDR option to listener socket: "
|
||||
<< strerror(error);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (family == AF_INET6) {
|
||||
if (faddr.family == AF_INET6) {
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
|
||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||
auto error = errno;
|
||||
LOG(WARN)
|
||||
<< "Failed to set IPV6_V6ONLY option to listener socket, error="
|
||||
<< error;
|
||||
LOG(WARN) << "Failed to set IPV6_V6ONLY option to listener socket: "
|
||||
<< strerror(error);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
@ -613,7 +612,9 @@ int create_tcp_server_socket(int family) {
|
|||
val = 3;
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val,
|
||||
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
|
||||
|
||||
|
@ -622,7 +623,7 @@ int create_tcp_server_socket(int family) {
|
|||
// ports will fail with permission denied error.
|
||||
if (bind(fd, rp->ai_addr, rp->ai_addrlen) == -1) {
|
||||
auto error = errno;
|
||||
LOG(WARN) << "bind() syscall failed, error=" << error;
|
||||
LOG(WARN) << "bind() syscall failed: " << strerror(error);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
@ -631,13 +632,15 @@ int create_tcp_server_socket(int family) {
|
|||
val = listenerconf.fastopen;
|
||||
if (setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &val,
|
||||
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) {
|
||||
auto error = errno;
|
||||
LOG(WARN) << "listen() syscall failed, error=" << error;
|
||||
LOG(WARN) << "listen() syscall failed: " << strerror(error);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
@ -646,27 +649,200 @@ int create_tcp_server_socket(int family) {
|
|||
}
|
||||
|
||||
if (!rp) {
|
||||
LOG(WARN) << "Listening " << (family == AF_INET ? "IPv4" : "IPv6")
|
||||
LOG(WARN) << "Listening " << (faddr.family == AF_INET ? "IPv4" : "IPv6")
|
||||
<< " socket failed";
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char host[NI_MAXHOST];
|
||||
rv = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), nullptr, 0,
|
||||
NI_NUMERICHOST);
|
||||
faddr.fd = fd;
|
||||
faddr.hostport = util::make_hostport(host.data(), faddr.port);
|
||||
|
||||
if (rv != 0) {
|
||||
LOG(WARN) << gai_strerror(rv);
|
||||
LOG(NOTICE) << "Listening on " << faddr.hostport;
|
||||
|
||||
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
|
||||
|
||||
|
@ -680,19 +856,6 @@ int call_daemon() {
|
|||
}
|
||||
} // 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 {
|
||||
pid_t fork_worker_process(SignalServer *ssv) {
|
||||
int rv;
|
||||
|
@ -722,7 +885,7 @@ pid_t fork_worker_process(SignalServer *ssv) {
|
|||
}
|
||||
|
||||
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);
|
||||
if (rv != 0) {
|
||||
LOG(FATAL) << "Worker process returned error";
|
||||
|
@ -803,40 +966,8 @@ int event_loop() {
|
|||
util::make_socket_closeonexec(fd);
|
||||
}
|
||||
|
||||
auto &listenerconf = get_config()->conn.listener;
|
||||
|
||||
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;
|
||||
if (create_acceptor_socket() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto loop = EV_DEFAULT;
|
||||
|
@ -986,8 +1117,6 @@ void fill_default_config() {
|
|||
{
|
||||
auto &listenerconf = connconf.listener;
|
||||
{
|
||||
listenerconf.host = strcopy("*");
|
||||
listenerconf.port = 3000;
|
||||
// Default accept() backlog
|
||||
listenerconf.backlog = 512;
|
||||
listenerconf.timeout.sleep = 30_s;
|
||||
|
@ -1120,9 +1249,10 @@ Connections:
|
|||
Set frontend host and port. If <HOST> is '*', it
|
||||
assumes all addresses including both IPv4 and IPv6.
|
||||
UNIX domain socket can be specified by prefixing path
|
||||
name with "unix:" (e.g., unix:/var/run/nghttpx.sock)
|
||||
Default: )" << get_config()->conn.listener.host.get() << ","
|
||||
<< get_config()->conn.listener.port << R"(
|
||||
name with "unix:" (e.g., unix:/var/run/nghttpx.sock).
|
||||
This option can be used multiple times to listen to
|
||||
multiple addresses.
|
||||
Default: *,3000
|
||||
--backlog=<N>
|
||||
Set listen backlog size.
|
||||
Default: )" << get_config()->conn.listener.backlog << R"(
|
||||
|
@ -1838,6 +1968,13 @@ void process_options(
|
|||
auto &upstreamconf = mod_config()->conn.upstream;
|
||||
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) {
|
||||
LOG(FATAL) << "--backend-ipv4 and --backend-ipv6 cannot be used at the "
|
||||
<< "same time.";
|
||||
|
@ -1949,8 +2086,7 @@ void process_options(
|
|||
// for AF_UNIX socket, we use "localhost" as host for backend
|
||||
// hostport. This is used as Host header field to backend and
|
||||
// not going to be passed to any syscalls.
|
||||
addr.hostport = ImmutableString(
|
||||
util::make_hostport("localhost", listenerconf.port));
|
||||
addr.hostport = "localhost";
|
||||
|
||||
auto path = addr.host.c_str();
|
||||
auto pathlen = addr.host.size();
|
||||
|
|
|
@ -45,16 +45,16 @@ void acceptcb(struct ev_loop *loop, ev_io *w, int revent) {
|
|||
}
|
||||
} // namespace
|
||||
|
||||
AcceptHandler::AcceptHandler(int fd, ConnectionHandler *h)
|
||||
: conn_hnr_(h), fd_(fd) {
|
||||
ev_io_init(&wev_, acceptcb, fd_, EV_READ);
|
||||
AcceptHandler::AcceptHandler(const FrontendAddr *faddr, ConnectionHandler *h)
|
||||
: conn_hnr_(h), faddr_(faddr) {
|
||||
ev_io_init(&wev_, acceptcb, faddr_->fd, EV_READ);
|
||||
wev_.data = this;
|
||||
ev_io_start(conn_hnr_->get_loop(), &wev_);
|
||||
}
|
||||
|
||||
AcceptHandler::~AcceptHandler() {
|
||||
ev_io_stop(conn_hnr_->get_loop(), &wev_);
|
||||
close(fd_);
|
||||
close(faddr_->fd);
|
||||
}
|
||||
|
||||
void AcceptHandler::accept_connection() {
|
||||
|
@ -63,10 +63,10 @@ void AcceptHandler::accept_connection() {
|
|||
socklen_t addrlen = sizeof(sockaddr);
|
||||
|
||||
#ifdef HAVE_ACCEPT4
|
||||
auto cfd =
|
||||
accept4(fd_, &sockaddr.sa, &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||
#else // !HAVE_ACCEPT4
|
||||
auto cfd = accept(fd_, &sockaddr.sa, &addrlen);
|
||||
auto cfd = accept4(faddr_->fd, &sockaddr.sa, &addrlen,
|
||||
SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||
#else // !HAVE_ACCEPT4
|
||||
auto cfd = accept(faddr_->fd, &sockaddr.sa, &addrlen);
|
||||
#endif // !HAVE_ACCEPT4
|
||||
|
||||
if (cfd == -1) {
|
||||
|
@ -101,7 +101,7 @@ void AcceptHandler::accept_connection() {
|
|||
|
||||
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_); }
|
||||
|
||||
int AcceptHandler::get_fd() const { return fd_; }
|
||||
int AcceptHandler::get_fd() const { return faddr_->fd; }
|
||||
|
||||
} // namespace shrpx
|
||||
|
|
|
@ -32,10 +32,11 @@
|
|||
namespace shrpx {
|
||||
|
||||
class ConnectionHandler;
|
||||
struct FrontendAddr;
|
||||
|
||||
class AcceptHandler {
|
||||
public:
|
||||
AcceptHandler(int fd, ConnectionHandler *h);
|
||||
AcceptHandler(const FrontendAddr *faddr, ConnectionHandler *h);
|
||||
~AcceptHandler();
|
||||
void accept_connection();
|
||||
void enable();
|
||||
|
@ -45,7 +46,7 @@ public:
|
|||
private:
|
||||
ev_io wev_;
|
||||
ConnectionHandler *conn_hnr_;
|
||||
int fd_;
|
||||
const FrontendAddr *faddr_;
|
||||
};
|
||||
|
||||
} // namespace shrpx
|
||||
|
|
|
@ -377,7 +377,8 @@ int ClientHandler::upstream_http1_connhd_read() {
|
|||
}
|
||||
|
||||
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(),
|
||||
get_config()->conn.upstream.timeout.write,
|
||||
get_config()->conn.upstream.timeout.read,
|
||||
|
@ -392,6 +393,7 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
|
|||
: nullptr),
|
||||
ipaddr_(ipaddr),
|
||||
port_(port),
|
||||
faddr_(faddr),
|
||||
worker_(worker),
|
||||
left_connhd_len_(NGHTTP2_CLIENT_MAGIC_LEN),
|
||||
should_close_after_write_(false) {
|
||||
|
@ -851,8 +853,8 @@ void ClientHandler::write_accesslog(Downstream *downstream) {
|
|||
std::chrono::high_resolution_clock::now(), // request_end_time
|
||||
|
||||
req.http_major, req.http_minor, resp.http_status,
|
||||
downstream->response_sent_body_length, StringRef(port_),
|
||||
get_config()->conn.listener.port, get_config()->pid,
|
||||
downstream->response_sent_body_length, StringRef(port_), faddr_->port,
|
||||
get_config()->pid,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -875,7 +877,7 @@ void ClientHandler::write_accesslog(int major, int minor, unsigned int status,
|
|||
highres_now, // request_end_time
|
||||
major, minor, // major, minor
|
||||
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();
|
||||
}
|
||||
|
||||
const std::string &ClientHandler::get_forwarded_by() {
|
||||
StringRef ClientHandler::get_forwarded_by() {
|
||||
auto &fwdconf = get_config()->http.forwarded;
|
||||
|
||||
if (fwdconf.by_node_type == FORWARDED_NODE_OBFUSCATED) {
|
||||
return fwdconf.by_obfuscated;
|
||||
}
|
||||
if (!local_hostport_.empty()) {
|
||||
return local_hostport_;
|
||||
return StringRef(fwdconf.by_obfuscated);
|
||||
}
|
||||
|
||||
auto &listenerconf = get_config()->conn.listener;
|
||||
|
||||
// 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_;
|
||||
return StringRef(faddr_->hostport);
|
||||
}
|
||||
|
||||
const std::string &ClientHandler::get_forwarded_for() const {
|
||||
|
@ -1168,10 +1133,6 @@ const std::string &ClientHandler::get_forwarded_for() const {
|
|||
return forwarded_for_obfuscated_;
|
||||
}
|
||||
|
||||
if (get_config()->conn.listener.host_unix) {
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
|
||||
return ipaddr_;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ struct WorkerStat;
|
|||
class ClientHandler {
|
||||
public:
|
||||
ClientHandler(Worker *worker, int fd, SSL *ssl, const char *ipaddr,
|
||||
const char *port);
|
||||
const char *port, const FrontendAddr *faddr);
|
||||
~ClientHandler();
|
||||
|
||||
int noop();
|
||||
|
@ -136,7 +136,7 @@ public:
|
|||
|
||||
// Returns string suitable for use in "by" parameter of Forwarded
|
||||
// header field.
|
||||
const std::string &get_forwarded_by();
|
||||
StringRef get_forwarded_by();
|
||||
// Returns string suitable for use in "for" parameter of Forwarded
|
||||
// header field.
|
||||
const std::string &get_forwarded_for() const;
|
||||
|
@ -152,13 +152,13 @@ private:
|
|||
std::string port_;
|
||||
// The ALPN identifier negotiated for this connection.
|
||||
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
|
||||
// of Forwarded header field.
|
||||
std::string forwarded_for_obfuscated_;
|
||||
std::function<int(ClientHandler &)> read_, write_;
|
||||
std::function<int(ClientHandler &)> on_read_, on_write_;
|
||||
// Address of frontend listening socket
|
||||
const FrontendAddr *faddr_;
|
||||
Worker *worker_;
|
||||
// The number of bytes of HTTP/2 client connection header to read
|
||||
size_t left_connhd_len_;
|
||||
|
|
|
@ -1428,11 +1428,15 @@ int parse_config(const char *opt, const char *optarg,
|
|||
case SHRPX_OPTID_FRONTEND: {
|
||||
auto &listenerconf = mod_config()->conn.listener;
|
||||
|
||||
FrontendAddr addr{};
|
||||
addr.fd = -1;
|
||||
|
||||
if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) {
|
||||
auto path = optarg + str_size(SHRPX_UNIX_PATH_PREFIX);
|
||||
listenerconf.host = strcopy(path);
|
||||
listenerconf.port = 0;
|
||||
listenerconf.host_unix = true;
|
||||
addr.host = ImmutableString(path);
|
||||
addr.host_unix = true;
|
||||
|
||||
listenerconf.addrs.push_back(std::move(addr));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1442,9 +1446,26 @@ int parse_config(const char *opt, const char *optarg,
|
|||
return -1;
|
||||
}
|
||||
|
||||
listenerconf.host = strcopy(host);
|
||||
listenerconf.port = port;
|
||||
listenerconf.host_unix = false;
|
||||
addr.host = ImmutableString(host);
|
||||
addr.port = port;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -239,6 +239,24 @@ struct AltSvc {
|
|||
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 {
|
||||
DownstreamAddr() : addr{}, port(0), host_unix(false) {}
|
||||
DownstreamAddr(const DownstreamAddr &other);
|
||||
|
@ -464,14 +482,8 @@ struct ConnectionConfig {
|
|||
struct {
|
||||
ev_tstamp sleep;
|
||||
} timeout;
|
||||
// address of frontend connection. This could be a path to UNIX
|
||||
// domain socket. In this case, |host_unix| must be true.
|
||||
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;
|
||||
// address of frontend acceptors
|
||||
std::vector<FrontendAddr> addrs;
|
||||
int backlog;
|
||||
// TCP fastopen. If this is positive, it is passed to
|
||||
// setsockopt() along with TCP_FASTOPEN.
|
||||
|
|
|
@ -297,7 +297,8 @@ void ConnectionHandler::graceful_shutdown_worker() {
|
|||
#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)) {
|
||||
LLOG(INFO, this) << "Accepted connection. fd=" << fd;
|
||||
}
|
||||
|
@ -317,7 +318,7 @@ int ConnectionHandler::handle_connection(int fd, sockaddr *addr, int addrlen) {
|
|||
}
|
||||
|
||||
auto client =
|
||||
ssl::accept_connection(single_worker_.get(), fd, addr, addrlen);
|
||||
ssl::accept_connection(single_worker_.get(), fd, addr, addrlen, faddr);
|
||||
if (!client) {
|
||||
LLOG(ERROR, this) << "ClientHandler creation failed";
|
||||
|
||||
|
@ -338,6 +339,7 @@ int ConnectionHandler::handle_connection(int fd, sockaddr *addr, int addrlen) {
|
|||
wev.client_fd = fd;
|
||||
memcpy(&wev.client_addr, addr, addrlen);
|
||||
wev.client_addrlen = addrlen;
|
||||
wev.faddr = faddr;
|
||||
|
||||
workers_[idx]->send(wev);
|
||||
|
||||
|
@ -352,39 +354,19 @@ Worker *ConnectionHandler::get_single_worker() const {
|
|||
return single_worker_.get();
|
||||
}
|
||||
|
||||
void ConnectionHandler::set_acceptor(std::unique_ptr<AcceptHandler> h) {
|
||||
acceptor_ = 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::add_acceptor(std::unique_ptr<AcceptHandler> h) {
|
||||
acceptors_.push_back(std::move(h));
|
||||
}
|
||||
|
||||
void ConnectionHandler::enable_acceptor() {
|
||||
if (acceptor_) {
|
||||
acceptor_->enable();
|
||||
}
|
||||
|
||||
if (acceptor6_) {
|
||||
acceptor6_->enable();
|
||||
for (auto &a : acceptors_) {
|
||||
a->enable();
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionHandler::disable_acceptor() {
|
||||
if (acceptor_) {
|
||||
acceptor_->disable();
|
||||
}
|
||||
|
||||
if (acceptor6_) {
|
||||
acceptor6_->disable();
|
||||
for (auto &a : acceptors_) {
|
||||
a->disable();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,11 +382,8 @@ void ConnectionHandler::sleep_acceptor(ev_tstamp t) {
|
|||
}
|
||||
|
||||
void ConnectionHandler::accept_pending_connection() {
|
||||
if (acceptor_) {
|
||||
acceptor_->accept_connection();
|
||||
}
|
||||
if (acceptor6_) {
|
||||
acceptor6_->accept_connection();
|
||||
for (auto &a : acceptors_) {
|
||||
a->accept_connection();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ class Worker;
|
|||
struct WorkerStat;
|
||||
struct TicketKeys;
|
||||
class MemcachedDispatcher;
|
||||
struct FrontendAddr;
|
||||
|
||||
struct OCSPUpdateContext {
|
||||
// ocsp response buffer
|
||||
|
@ -79,7 +80,8 @@ class ConnectionHandler {
|
|||
public:
|
||||
ConnectionHandler(struct ev_loop *loop);
|
||||
~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.
|
||||
int create_single_worker();
|
||||
// Creates |num| Worker objects for multi threaded configuration.
|
||||
|
@ -92,10 +94,7 @@ public:
|
|||
const std::shared_ptr<TicketKeys> &get_ticket_keys() const;
|
||||
struct ev_loop *get_loop() const;
|
||||
Worker *get_single_worker() const;
|
||||
void set_acceptor(std::unique_ptr<AcceptHandler> h);
|
||||
AcceptHandler *get_acceptor() const;
|
||||
void set_acceptor6(std::unique_ptr<AcceptHandler> h);
|
||||
AcceptHandler *get_acceptor6() const;
|
||||
void add_acceptor(std::unique_ptr<AcceptHandler> h);
|
||||
void enable_acceptor();
|
||||
void disable_acceptor();
|
||||
void sleep_acceptor(ev_tstamp t);
|
||||
|
@ -154,10 +153,7 @@ private:
|
|||
// Worker object.
|
||||
std::shared_ptr<TicketKeys> ticket_keys_;
|
||||
struct ev_loop *loop_;
|
||||
// acceptor for IPv4 address or UNIX domain socket.
|
||||
std::unique_ptr<AcceptHandler> acceptor_;
|
||||
// acceptor for IPv6 address
|
||||
std::unique_ptr<AcceptHandler> acceptor6_;
|
||||
std::vector<std::unique_ptr<AcceptHandler>> acceptors_;
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
std::unique_ptr<neverbleed_t> nb_;
|
||||
#endif // HAVE_NEVERBLEED
|
||||
|
|
|
@ -46,8 +46,6 @@ std::string create_error_html(unsigned int status_code) {
|
|||
res += "</h1><footer>";
|
||||
const auto &server_name = get_config()->http.server_name;
|
||||
res.append(server_name.c_str(), server_name.size());
|
||||
res += " at port ";
|
||||
res += util::utos(get_config()->conn.listener.port);
|
||||
res += "</footer></body></html>";
|
||||
return res;
|
||||
}
|
||||
|
@ -63,7 +61,7 @@ std::string create_via_header_value(int major, int minor) {
|
|||
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 &host,
|
||||
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
|
||||
// |params| is bitwise-OR of zero or more of shrpx_forwarded_param
|
||||
// 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 &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,
|
||||
int addrlen) {
|
||||
int addrlen, const FrontendAddr *faddr) {
|
||||
char host[NI_MAXHOST];
|
||||
char service[NI_MAXSERV];
|
||||
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,
|
||||
|
|
|
@ -45,6 +45,7 @@ class ClientHandler;
|
|||
class Worker;
|
||||
class DownstreamConnectionPool;
|
||||
struct DownstreamAddr;
|
||||
struct FrontendAddr;
|
||||
|
||||
namespace ssl {
|
||||
|
||||
|
@ -76,7 +77,7 @@ SSL_CTX *create_ssl_client_context(
|
|||
);
|
||||
|
||||
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
|
||||
// Config::downstream_addrs. We only consider first downstream since
|
||||
|
|
|
@ -179,8 +179,9 @@ void Worker::process_events() {
|
|||
break;
|
||||
}
|
||||
|
||||
auto client_handler = ssl::accept_connection(
|
||||
this, wev.client_fd, &wev.client_addr.sa, wev.client_addrlen);
|
||||
auto client_handler =
|
||||
ssl::accept_connection(this, wev.client_fd, &wev.client_addr.sa,
|
||||
wev.client_addrlen, wev.faddr);
|
||||
if (!client_handler) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
WLOG(ERROR, this) << "ClientHandler creation failed";
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace shrpx {
|
|||
class Http2Session;
|
||||
class ConnectBlocker;
|
||||
class MemcachedDispatcher;
|
||||
struct FrontendAddr;
|
||||
|
||||
#ifdef HAVE_MRUBY
|
||||
namespace mruby {
|
||||
|
@ -93,6 +94,7 @@ struct WorkerEvent {
|
|||
sockaddr_union client_addr;
|
||||
size_t client_addrlen;
|
||||
int client_fd;
|
||||
const FrontendAddr *faddr;
|
||||
};
|
||||
std::shared_ptr<TicketKeys> ticket_keys;
|
||||
};
|
||||
|
|
|
@ -389,13 +389,8 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
|
|||
|
||||
ConnectionHandler conn_handler(loop);
|
||||
|
||||
if (wpconf->server_fd6 != -1) {
|
||||
conn_handler.set_acceptor6(
|
||||
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));
|
||||
for (auto &addr : get_config()->conn.listener.addrs) {
|
||||
conn_handler.add_acceptor(make_unique<AcceptHandler>(&addr, &conn_handler));
|
||||
}
|
||||
|
||||
auto &upstreamconf = get_config()->conn.upstream;
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <functional>
|
||||
#include <typeinfo>
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
|
@ -317,6 +318,11 @@ private:
|
|||
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) {
|
||||
return lhs.size() == rhs.size() &&
|
||||
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;
|
||||
}
|
||||
|
||||
inline bool operator!=(const ImmutableString &lhs, const ImmutableString &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
inline bool operator!=(const ImmutableString &lhs, const std::string &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
@ -351,6 +361,15 @@ inline bool operator!=(const char *lhs, const ImmutableString &rhs) {
|
|||
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
|
||||
// it behaves like simple string, but it does not own pointer. When
|
||||
// it is default constructed, it has empty string. You can freely
|
||||
|
@ -374,7 +393,9 @@ public:
|
|||
: base(s.c_str()), len(s.size()) {}
|
||||
StringRef(const char *s) : base(s), len(strlen(s)) {}
|
||||
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]) {
|
||||
return StringRef(s, N - 1);
|
||||
}
|
||||
|
@ -388,6 +409,7 @@ public:
|
|||
const char *c_str() const { return base; }
|
||||
size_type size() const { return len; }
|
||||
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); }
|
||||
|
||||
|
@ -430,6 +452,15 @@ inline bool operator!=(const char *lhs, const StringRef &rhs) {
|
|||
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,
|
||||
char **argv) {
|
||||
try {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
|
@ -101,6 +102,34 @@ void test_template_immutable_string(void) {
|
|||
CU_ASSERT('o' == br_op[1]);
|
||||
CU_ASSERT('t' == br_op[6]);
|
||||
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) {
|
||||
|
@ -145,6 +174,31 @@ void test_template_string_ref(void) {
|
|||
|
||||
CU_ASSERT("delta" == cstrnref);
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue