Commit 23027364 authored by Sergey Doroshenko's avatar Sergey Doroshenko Committed by Viswanath Sivakumar

folly: AsyncServerSocket::getAddress: prefer IPv6

Summary:
Can't connect from ipv6-only cluster to ipv4/ipv6 service which uses different ports.

Facebook:
A lot of tests start a service, get its port, and try to connect to 127.0.0.1:port, which breaks
after this diff since the port corresponds to IPv6 address, not IPv4. Fixing this by changing
127.0.0.1 to ::1 in places found by sandcastle.

```
fbconfig servicerouter/aggregator/tests servicerouter/client/cpp/test common/fb303/cpp/test thrift/lib/cpp2/test unicorn/hotswap/test common/client_mgmt thrift/test servicerouter/client/swig/tests unicorn/async/test servicerouter/selection/tests
```

Test Plan:
```
$ ./fastcopy_server --dir . &
$ netstat -atnlp | grep LISTEN | grep fastcopy
tcp        0      0 0.0.0.0:65478               0.0.0.0:*                   LISTEN      9348/./fastcopy_ser
tcp        0      0 :::52793                    :::*                        LISTEN      9348/./fastcopy_ser
```

Reviewed By: philipp@fb.com

Subscribers: trunkagent, vkatich, fbcode-common-diffs@, chaoyc, search-fbcode-diffs@, davejwatson, andrewcox, mcduff, hitesh, unicorn-diffs@, alandau, mshneer, folly-diffs@, bmatheny, ps, soren

FB internal diff: D1760372

Tasks: 5868818, 5886688

Signature: t1:1760372:1419992695:e7d254b2b8f730baefc169effa236b8daa9d846d
parent 9d022380
...@@ -364,13 +364,13 @@ void AsyncServerSocket::bind(uint16_t port) { ...@@ -364,13 +364,13 @@ void AsyncServerSocket::bind(uint16_t port) {
freeaddrinfo(res0); freeaddrinfo(res0);
}); });
for (res = res0; res; res = res->ai_next) { auto setupAddress = [&] (struct addrinfo* res) {
int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
// IPv6/IPv4 may not be supported by the kernel // IPv6/IPv4 may not be supported by the kernel
if (s < 0 && errno == EAFNOSUPPORT) { if (s < 0 && errno == EAFNOSUPPORT) {
continue; return;
} }
CHECK(s); CHECK_GE(s, 0);
try { try {
setupSocket(s); setupSocket(s);
...@@ -397,7 +397,26 @@ void AsyncServerSocket::bind(uint16_t port) { ...@@ -397,7 +397,26 @@ void AsyncServerSocket::bind(uint16_t port) {
errno, errno,
"failed to bind to async server socket for port"); "failed to bind to async server socket for port");
} }
};
// Prefer AF_INET6 addresses. RFC 3484 mandates that getaddrinfo
// should return IPv6 first and then IPv4 addresses, but glibc's
// getaddrinfo(nullptr) with AI_PASSIVE returns:
// - 0.0.0.0 (IPv4-only)
// - :: (IPv6+IPv4) in this order
// See: https://sourceware.org/bugzilla/show_bug.cgi?id=9981
for (res = res0; res; res = res->ai_next) {
if (res->ai_family == AF_INET6) {
setupAddress(res);
}
} }
for (res = res0; res; res = res->ai_next) {
if (res->ai_family != AF_INET6) {
setupAddress(res);
}
}
if (sockets_.size() == 0) { if (sockets_.size() == 0) {
throw std::runtime_error( throw std::runtime_error(
"did not bind any async server socket for port"); "did not bind any async server socket for port");
...@@ -418,10 +437,10 @@ void AsyncServerSocket::listen(int backlog) { ...@@ -418,10 +437,10 @@ void AsyncServerSocket::listen(int backlog) {
void AsyncServerSocket::getAddress(SocketAddress* addressReturn) const { void AsyncServerSocket::getAddress(SocketAddress* addressReturn) const {
CHECK(sockets_.size() >= 1); CHECK(sockets_.size() >= 1);
if (sockets_.size() > 1) { VLOG_IF(2, sockets_.size() > 1)
VLOG(2) << "Warning: getAddress can return multiple addresses, " << << "Warning: getAddress() called and multiple addresses available ("
"but getAddress was called, so only returning the first"; << sockets_.size() << "). Returning only the first one.";
}
addressReturn->setFromLocalAddress(sockets_[0].socket_); addressReturn->setFromLocalAddress(sockets_[0].socket_);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment