/** * *this SocketAddress was created from the numeric IP address of a * connecting host. * The lo and hi addresses are the limit checks from the ACL file. * Return true if this address is in range of any of the address pairs * in the limit check range. * * This check is executed on every incoming connection. */ bool SocketAddress::inRange(const SocketAddress& lo, const SocketAddress& hi) const { (*this).firstAddress(); lo.firstAddress(); hi.firstAddress(); const ::addrinfo& thisInfo = getAddrInfo(*this); const ::addrinfo& loInfo = getAddrInfo(lo); const ::addrinfo& hiInfo = getAddrInfo(hi); if (inRange(thisInfo, loInfo, hiInfo)) { return true; } while (lo.nextAddress()) { if (!hi.nextAddress()) { assert (false); throw(Exception(QPID_MSG("Comparison iteration fails: " + lo.asString() + hi.asString()))); } const ::addrinfo& loInfo = getAddrInfo(lo); const ::addrinfo& hiInfo = getAddrInfo(hi); if (inRange(thisInfo, loInfo, hiInfo)) { return true; } } return false; }
int Socket::listen(const SocketAddress& addr, int backlog) const { createSocket(addr); const SOCKET& socket = impl->fd; BOOL yes=1; QPID_WINSOCK_CHECK(setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes))); if (::bind(socket, getAddrInfo(addr).ai_addr, getAddrInfo(addr).ai_addrlen) == SOCKET_ERROR) throw Exception(QPID_MSG("Can't bind to " << addr.asString() << ": " << strError(WSAGetLastError()))); if (::listen(socket, backlog) == SOCKET_ERROR) throw Exception(QPID_MSG("Can't listen on " <<addr.asString() << ": " << strError(WSAGetLastError()))); return getLocalPort(socket); }
void AsynchConnector::connComplete(DispatchHandle& h) { int errCode = socket.getError(); if (errCode == 0) { h.stopWatch(); try { socket.finishConnect(sa); } catch (const std::exception& e) { failCallback(socket, 0, e.what()); DispatchHandle::doDelete(); return; } connCallback(socket); } else { // Retry while we cause an immediate exception // (asynch failure will be handled by re-entering here at the top) while (sa.nextAddress()) { try { // Try next address without deleting ourselves QPID_LOG(debug, "Ignored socket connect error: " << strError(errCode)); QPID_LOG(info, "Retrying connect: " << sa.asString()); socket.connect(sa); return; } catch (const std::exception& e) { QPID_LOG(debug, "Ignored socket connect exception: " << e.what()); } errCode = socket.getError(); } h.stopWatch(); failCallback(socket, errCode, strError(errCode)); } DispatchHandle::doDelete(); }
void Socket::connect(const SocketAddress& addr) const { peername = addr.asString(false); createSocket(addr); const SOCKET& socket = impl->fd; int err; WSASetLastError(0); if ((::connect(socket, getAddrInfo(addr).ai_addr, getAddrInfo(addr).ai_addrlen) != 0) && ((err = ::WSAGetLastError()) != WSAEWOULDBLOCK)) throw qpid::Exception(QPID_MSG(strError(err) << ": " << peername)); }
/** * this represents the low address of an ACL address range. * Given rangeHi that represents the high address, * return a string showing the numeric comparisons that the * inRange checks will do for address pair. */ std::string SocketAddress::comparisonDetails(const SocketAddress& rangeHi) const { std::ostringstream os; SocketAddress thisSa(*this); SocketAddress rangeHiSa(rangeHi); (void) getAddrInfo(thisSa); (void) getAddrInfo(rangeHiSa); os << "(" << thisSa.asString(true, true, false) << "," << rangeHiSa.asString(true, true, false) << ")"; while (thisSa.nextAddress()) { if (!rangeHiSa.nextAddress()) { throw(Exception(QPID_MSG("Comparison iteration fails: " + (*this).asString() + rangeHi.asString()))); } os << ",(" << thisSa.asString(true, true, false) << "," << rangeHiSa.asString(true, true, false) << ")"; } if (rangeHiSa.nextAddress()) { throw(Exception(QPID_MSG("Comparison iteration fails: " + (*this).asString() + rangeHi.asString()))); } std::string result = os.str(); return result; }
/** * For ACL address matching make sure that the two addresses, *this * which is the low address and hiPeer which is the high address, are * both numeric ip addresses of the same family and that hi > *this. * * Note that if the addresses resolve to more than one struct addrinfo * then this and the hiPeer must be equal. This avoids having to do * difficult range checks where the this and hiPeer both resolve to * multiple IPv4 or IPv6 addresses. * * This check is run at acl file load time and not at run tme. */ bool SocketAddress::isComparable(const SocketAddress& hiPeer) const { try { // May only compare if this socket is IPv4 or IPv6 SocketAddress lo(*this); const ::addrinfo& peerLoInfo = getAddrInfo(lo); if (!(peerLoInfo.ai_family == AF_INET || peerLoInfo.ai_family == AF_INET6)) { return false; } try { // May only compare if peer socket is same family SocketAddress hi(hiPeer); const ::addrinfo& peerHiInfo = getAddrInfo(hi); if (peerLoInfo.ai_family != peerHiInfo.ai_family) { return false; } // Host names that resolve to lists are allowed if they are equal. // For example: localhost, or fjord.lab.example.com if ((*this).asString() == hiPeer.asString()) { return true; } // May only compare if this and peer resolve to single address. if (lo.nextAddress() || hi.nextAddress()) { return false; } // Make sure that the lo/hi relationship is ok int res; if (!compareAddresses(peerLoInfo, peerHiInfo, res) || res < 0) { return false; } return true; } catch (Exception) { // failed to resolve hi return false; } } catch (Exception) { // failed to resolve lo return false; } }