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
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,
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.
*
// 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, "<unknown>"));
}
};
}
}
+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