nghttpx: Support UNIX domain socket in backend connections

This commit is contained in:
Tatsuhiro Tsujikawa 2015-02-22 12:27:51 +09:00
parent 49781da8f0
commit 997f9233bc
5 changed files with 72 additions and 16 deletions

View File

@ -28,6 +28,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h>
#include <netdb.h> #include <netdb.h>
#include <signal.h> #include <signal.h>
#include <netinet/in.h> #include <netinet/in.h>
@ -821,7 +822,9 @@ Connections:
backend addresses are accepted by repeating this option. backend addresses are accepted by repeating this option.
HTTP/2 backend does not support multiple backend HTTP/2 backend does not support multiple backend
addresses and the first occurrence of this option is addresses and the first occurrence of this option is
used. used. UNIX domain socket can be specified by prefixing
path name with "unix:" (e.g.,
-bunix:/var/run/backend.sock)
Default: )" << DEFAULT_DOWNSTREAM_HOST << "," Default: )" << DEFAULT_DOWNSTREAM_HOST << ","
<< DEFAULT_DOWNSTREAM_PORT << R"( << DEFAULT_DOWNSTREAM_PORT << R"(
-f, --frontend=<HOST,PORT> -f, --frontend=<HOST,PORT>
@ -1870,23 +1873,35 @@ int main(int argc, char **argv) {
} }
for (auto &addr : mod_config()->downstream_addrs) { for (auto &addr : mod_config()->downstream_addrs) {
auto ipv6 = util::ipv6_numeric_addr(addr.host.get());
std::string hostport;
if (ipv6) { if (util::istartsWith(addr.host.get(), SHRPX_UNIX_PATH_PREFIX)) {
hostport += "["; // 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 =
strcopy(util::make_hostport("localhost", get_config()->port));
auto path = addr.host.get() + str_size(SHRPX_UNIX_PATH_PREFIX);
auto pathlen = strlen(path);
if (pathlen + 1 > sizeof(addr.addr.un.sun_path)) {
LOG(FATAL) << "path unix domain socket is bound to is too long > "
<< sizeof(addr.addr.un.sun_path);
exit(EXIT_FAILURE);
} }
hostport += addr.host.get(); LOG(INFO) << "Use UNIX domain socket path " << path
<< " for backend connection";
if (ipv6) { addr.addr.un.sun_family = AF_UNIX;
hostport += "]"; // copy path including terminal NULL
std::copy_n(path, pathlen + 1, addr.addr.un.sun_path);
addr.addrlen = sizeof(addr.addr.un);
continue;
} }
hostport += ":"; addr.hostport = strcopy(util::make_hostport(addr.host.get(), addr.port));
hostport += util::utos(addr.port);
addr.hostport = strcopy(hostport);
if (resolve_hostname( if (resolve_hostname(
&addr.addr, &addr.addrlen, addr.host.get(), addr.port, &addr.addr, &addr.addrlen, addr.host.get(), addr.port,

View File

@ -521,6 +521,16 @@ int parse_config(const char *opt, const char *optarg) {
char host[NI_MAXHOST]; char host[NI_MAXHOST];
uint16_t port; uint16_t port;
if (util::strieq(opt, SHRPX_OPT_BACKEND)) { if (util::strieq(opt, SHRPX_OPT_BACKEND)) {
if (util::istartsWith(optarg, SHRPX_UNIX_PATH_PREFIX)) {
DownstreamAddr addr;
addr.host = strcopy(optarg);
addr.port = 0;
mod_config()->downstream_addrs.push_back(std::move(addr));
return 0;
}
if (split_host_port(host, sizeof(host), &port, optarg) == -1) { if (split_host_port(host, sizeof(host), &port, optarg) == -1) {
return -1; return -1;
} }

View File

@ -30,6 +30,7 @@
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <cstdio> #include <cstdio>
@ -52,6 +53,8 @@ class CertLookupTree;
} // namespace ssl } // namespace ssl
#define SHRPX_UNIX_PATH_PREFIX "unix:"
extern const char SHRPX_OPT_PRIVATE_KEY_FILE[]; extern const char SHRPX_OPT_PRIVATE_KEY_FILE[];
extern const char SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE[]; extern const char SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE[];
extern const char SHRPX_OPT_CERTIFICATE_FILE[]; extern const char SHRPX_OPT_CERTIFICATE_FILE[];
@ -139,6 +142,7 @@ union sockaddr_union {
sockaddr sa; sockaddr sa;
sockaddr_in6 in6; sockaddr_in6 in6;
sockaddr_in in; sockaddr_in in;
sockaddr_un un;
}; };
enum shrpx_proto { PROTO_HTTP2, PROTO_HTTP }; enum shrpx_proto { PROTO_HTTP2, PROTO_HTTP };

View File

@ -847,7 +847,9 @@ int create_nonblock_socket(int family) {
make_socket_closeonexec(fd); make_socket_closeonexec(fd);
#endif // !SOCK_NONBLOCK #endif // !SOCK_NONBLOCK
if (family == AF_INET || family == AF_INET6) {
make_socket_nodelay(fd); make_socket_nodelay(fd);
}
return fd; return fd;
} }
@ -1016,6 +1018,26 @@ std::string dtos(double n) {
return utos(static_cast<int64_t>(n)) + "." + (f.size() == 1 ? "0" : "") + f; return utos(static_cast<int64_t>(n)) + "." + (f.size() == 1 ? "0" : "") + f;
} }
std::string make_hostport(const char *host, uint16_t port) {
auto ipv6 = ipv6_numeric_addr(host);
std::string hostport;
if (ipv6) {
hostport += "[";
}
hostport += host;
if (ipv6) {
hostport += "]";
}
hostport += ":";
hostport += utos(port);
return hostport;
}
} // namespace util } // namespace util
} // namespace nghttp2 } // namespace nghttp2

View File

@ -551,6 +551,11 @@ std::string duration_str(double t);
// fractional digits follow. // fractional digits follow.
std::string format_duration(const std::chrono::microseconds &u); std::string format_duration(const std::chrono::microseconds &u);
// Creates "host:port" string using given |host| and |port|. If
// |host| is numeric IPv6 address (e.g., ::1), it is enclosed by "["
// and "]".
std::string make_hostport(const char *host, uint16_t port);
} // namespace util } // namespace util
} // namespace nghttp2 } // namespace nghttp2