in util/ServerSocket.cpp [122:212]
ErrorCode ServerSocket::listen() {
if (!listeningFds_.empty()) {
return OK;
}
struct addrinfo sa;
int port = socket_->getPort();
memset(&sa, 0, sizeof(sa));
const WdtOptions &options = threadCtx_.getOptions();
if (options.ipv6) {
sa.ai_family = AF_INET6;
}
if (options.ipv4) {
sa.ai_family = AF_INET;
}
sa.ai_socktype = SOCK_STREAM;
sa.ai_flags = AI_PASSIVE;
// Dynamic port is the default on receiver (and setting the start_port flag
// explictly automatically also sets static_ports to false)
if (!options.static_ports) {
WVLOG(1) << "Not using static_ports, changing port " << port << " to 0";
port = 0;
}
// Lookup
addrInfoList infoList = nullptr;
std::string portStr = folly::to<std::string>(port);
int res = getaddrinfo(nullptr, portStr.c_str(), &sa, &infoList);
if (res) {
// not errno, can't use WPLOG (perror)
WLOG(ERROR) << "Failed getaddrinfo ai_passive on " << port << " : " << res
<< " : " << gai_strerror(res);
return CONN_ERROR;
}
// if the port specified is 0, then a random port is selected for the first
// address. We use that same port for other address types. Another addrinfo
// list is created using the new port. This variable is used to ensure that we
// do not try to bind again to the previous type.
int addressTypeAlreadyBound = AF_UNSPEC;
for (struct addrinfo *info = infoList; info != nullptr;) {
if (info->ai_family == addressTypeAlreadyBound) {
// we are already listening for this address type
WVLOG(2) << "Ignoring address family " << info->ai_family
<< " since we are already listing on it " << port;
info = info->ai_next;
continue;
}
std::string host, portString;
if (WdtSocket::getNameInfo(info->ai_addr, info->ai_addrlen, host,
portString)) {
// even if getnameinfo fail, we can still continue. Error is logged inside
// SocketUtils
WDT_CHECK(port == folly::to<int32_t>(portString));
}
int listeningFd = listenInternal(info, host);
if (listeningFd < 0) {
info = info->ai_next;
continue;
}
int addressFamily = info->ai_family;
if (port == 0) {
addrInfoList newInfoList = nullptr;
int selectedPort =
getSelectedPortAndNewAddress(listeningFd, sa, host, newInfoList);
if (selectedPort < 0) {
::close(listeningFd);
info = info->ai_next;
continue;
}
port = selectedPort;
socket_->setPort(port);
addressTypeAlreadyBound = addressFamily;
freeaddrinfo(infoList);
infoList = newInfoList;
info = infoList;
} else {
info = info->ai_next;
}
WVLOG(1) << "Successful listen on " << listeningFd << " host " << host
<< " port " << port << " ai_family " << addressFamily;
listeningFds_.emplace_back(listeningFd);
}
freeaddrinfo(infoList);
if (listeningFds_.empty()) {
WLOG(ERROR) << "Unable to listen port " << port;
return CONN_ERROR_RETRYABLE;
}
return OK;
}