From: Marcelo Juchem Date: Tue, 3 May 2016 22:35:30 +0000 (-0700) Subject: More useful logging upon failed AsyncServerSocket::bind() X-Git-Tag: 2016.07.26~290 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=0d8402e0320e90b87d312967ff039c19417ca4f1;p=folly.git 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 --- diff --git a/folly/SocketAddress.cpp b/folly/SocketAddress.cpp index 5f63d8e0..dbeff61b 100644 --- a/folly/SocketAddress.cpp +++ b/folly/SocketAddress.cpp @@ -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, diff --git a/folly/SocketAddress.h b/folly/SocketAddress.h index 12d8cae7..1953e213 100644 --- a/folly/SocketAddress.h +++ b/folly/SocketAddress.h @@ -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. * diff --git a/folly/io/async/AsyncServerSocket.cpp b/folly/io/async/AsyncServerSocket.cpp index 49ece5ef..fccf662d 100644 --- a/folly/io/async/AsyncServerSocket.cpp +++ b/folly/io/async/AsyncServerSocket.cpp @@ -397,8 +397,11 @@ void AsyncServerSocket::bind(uint16_t port) { // Bind to the socket if (::bind(s, res->ai_addr, res->ai_addrlen) != 0) { folly::throwSystemError( - errno, - "failed to bind to async server socket for port"); + errno, + "failed to bind to async server socket for port ", + SocketAddress::getPortFrom(res->ai_addr), + " family ", + SocketAddress::getFamilyNameFrom(res->ai_addr, "")); } }; diff --git a/folly/io/async/test/AsyncSocketTest.cpp b/folly/io/async/test/AsyncSocketTest.cpp index c339feff..bd348bd9 100644 --- a/folly/io/async/test/AsyncSocketTest.cpp +++ b/folly/io/async/test/AsyncSocketTest.cpp @@ -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