Commit 0d8402e0 authored by Marcelo Juchem's avatar Marcelo Juchem Committed by Facebook Github Bot 8

More useful logging upon failed AsyncServerSocket::bind()

Summary: `AsyncServerSocket::bind()` would not give information like port or family name when failing to bind a socket. This diff addresses that by including this information in the exception. Two additional helper methods were added to `SocketAddress` to retrieve both the port and the family name from a `sockaddr` structure.

Reviewed By: ckwalsh, yfeldblum

Differential Revision: D3249778

fb-gh-sync-id: 4edb28af5c211b7bf8d525b40844a5b0b6261e07
fbshipit-source-id: 4edb28af5c211b7bf8d525b40844a5b0b6261e07
parent 32623e8e
......@@ -179,6 +179,39 @@ void SocketAddress::setFromHostPort(const char* hostAndPort) {
setFromAddrInfo(results.info);
}
int SocketAddress::getPortFrom(const struct sockaddr* address) {
switch (address->sa_family) {
case AF_INET:
return ntohs(((sockaddr_in*)address)->sin_port);
case AF_INET6:
return ntohs(((sockaddr_in6*)address)->sin6_port);
default:
return -1;
}
}
const char* SocketAddress::getFamilyNameFrom(
const struct sockaddr* address,
const char* defaultResult) {
#define GETFAMILYNAMEFROM_IMPL(Family) \
case Family: \
return #Family
switch (address->sa_family) {
GETFAMILYNAMEFROM_IMPL(AF_INET);
GETFAMILYNAMEFROM_IMPL(AF_INET6);
GETFAMILYNAMEFROM_IMPL(AF_UNIX);
GETFAMILYNAMEFROM_IMPL(AF_UNSPEC);
default:
return defaultResult;
}
#undef GETFAMILYNAMEFROM_IMPL
}
void SocketAddress::setFromPath(StringPiece path) {
// Before we touch storage_, check to see if the length is too big.
// Note that "storage_.un.addr->sun_path" may not be safe to evaluate here,
......
......@@ -274,6 +274,25 @@ class SocketAddress {
return setFromHostPort(hostAndPort.c_str());
}
/**
* Returns the port number from the given socketaddr structure.
*
* Currently only IPv4 and IPv6 are supported.
*
* Returns -1 for unsupported socket families.
*/
static int getPortFrom(const struct sockaddr* address);
/**
* Returns the family name from the given socketaddr structure (e.g.: AF_INET6
* for IPv6).
*
* Returns `defaultResult` for unsupported socket families.
*/
static const char* getFamilyNameFrom(
const struct sockaddr* address,
const char* defaultResult = nullptr);
/**
* Initialize this SocketAddress from a local unix path.
*
......
......@@ -398,7 +398,10 @@ void AsyncServerSocket::bind(uint16_t port) {
if (::bind(s, res->ai_addr, res->ai_addrlen) != 0) {
folly::throwSystemError(
errno,
"failed to bind to async server socket for port");
"failed to bind to async server socket for port ",
SocketAddress::getPortFrom(res->ai_addr),
" family ",
SocketAddress::getFamilyNameFrom(res->ai_addr, "<unknown>"));
}
};
......
......@@ -76,4 +76,17 @@ TEST(AsyncSocketTest, v4v6samePort) {
}
}
TEST(AsyncSocketTest, duplicateBind) {
EventBase base;
auto server1 = AsyncServerSocket::newSocket(&base);
server1->bind(0);
server1->listen(10);
SocketAddress address;
server1->getAddress(std::addressof(address));
auto server2 = AsyncServerSocket::newSocket(&base);
EXPECT_THROW(server2->bind(address.getPort()), std::exception);
}
} // namespace
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