2015-11-01 01:26:04 +08:00
|
|
|
/**
|
|
|
|
|
* AddressInfo.h
|
|
|
|
|
*
|
2020-11-14 00:10:30 +08:00
|
|
|
* Utility wrapper around "getAddressInfo()"
|
2015-11-01 01:26:04 +08:00
|
|
|
*
|
|
|
|
|
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
|
|
|
|
|
* @copyright 2015 Copernica BV
|
|
|
|
|
*/
|
|
|
|
|
|
2020-11-14 00:10:30 +08:00
|
|
|
/**
|
|
|
|
|
* Dependencies
|
|
|
|
|
*/
|
2020-11-14 00:49:14 +08:00
|
|
|
#include <random>
|
2020-11-16 23:30:29 +08:00
|
|
|
#include "connectionorder.h"
|
|
|
|
|
#include "address2str.h"
|
2020-11-14 00:10:30 +08:00
|
|
|
|
2015-11-01 01:26:04 +08:00
|
|
|
/**
|
|
|
|
|
* Include guard
|
|
|
|
|
*/
|
|
|
|
|
namespace AMQP {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Class definition
|
|
|
|
|
*/
|
|
|
|
|
class AddressInfo
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* The addresses
|
|
|
|
|
* @var struct AddressInfo
|
|
|
|
|
*/
|
|
|
|
|
struct addrinfo *_info = nullptr;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Vector of addrinfo pointers
|
|
|
|
|
* @var std::vector<struct addrinfo *>
|
|
|
|
|
*/
|
|
|
|
|
std::vector<struct addrinfo *> _v;
|
|
|
|
|
|
2020-11-16 23:30:29 +08:00
|
|
|
/**
|
|
|
|
|
* Helper function to order the vector of addrinfo based on the ordering received
|
|
|
|
|
* @param order
|
|
|
|
|
*/
|
|
|
|
|
void reorder(ConnectionOrder::Order order)
|
|
|
|
|
{
|
|
|
|
|
// witch on order
|
|
|
|
|
switch (order)
|
|
|
|
|
{
|
|
|
|
|
// Do we want to have a random order of the addresses?
|
|
|
|
|
// This may be useful since getaddrinfo is sorting the addresses on proximity
|
|
|
|
|
// (e.g. https://lists.debian.org/debian-glibc/2007/09/msg00347.html),
|
|
|
|
|
// which may break loadbalancing..
|
|
|
|
|
case ConnectionOrder::Order::random:
|
|
|
|
|
{
|
|
|
|
|
// create a random device for the seed of the random number generator
|
|
|
|
|
std::random_device rd;
|
|
|
|
|
|
|
|
|
|
// Create the generator
|
|
|
|
|
std::mt19937 gen(rd());
|
|
|
|
|
|
|
|
|
|
// shuffle the vector.
|
|
|
|
|
std::shuffle(_v.begin(), _v.end(), gen);
|
|
|
|
|
|
|
|
|
|
// done
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// do we want to sort in ascending order
|
|
|
|
|
case ConnectionOrder::Order::ascending:
|
|
|
|
|
{
|
|
|
|
|
std::sort(_v.begin(), _v.end(), []
|
|
|
|
|
(struct addrinfo * v1, struct addrinfo * v2) -> bool
|
|
|
|
|
{
|
|
|
|
|
// get the addresses
|
|
|
|
|
Address2str addr1(v1);
|
|
|
|
|
Address2str addr2(v2);
|
|
|
|
|
|
|
|
|
|
// if addr1 doesn't have a proper address it should go to the
|
|
|
|
|
// back. Same holds for addr2
|
|
|
|
|
if (addr1.toChar() == nullptr) return false;
|
|
|
|
|
if (addr2.toChar() == nullptr) return true;
|
|
|
|
|
|
|
|
|
|
// make the comparison based on string comparison
|
|
|
|
|
return strcmp(addr1.toChar(), addr2.toChar()) < 0;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// done
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// do we want to sort in descending order
|
|
|
|
|
case ConnectionOrder::Order::descending:
|
|
|
|
|
{
|
|
|
|
|
std::sort(_v.begin(), _v.end(), []
|
|
|
|
|
(struct addrinfo * v1, struct addrinfo * v2) -> bool
|
|
|
|
|
{
|
|
|
|
|
// get the addresses
|
|
|
|
|
Address2str addr1(v1);
|
|
|
|
|
Address2str addr2(v2);
|
|
|
|
|
|
|
|
|
|
// if addr1 doesn't have a proper address it should go to the
|
|
|
|
|
// back. Same holds for addr2
|
|
|
|
|
if (addr1.toChar() == nullptr) return false;
|
|
|
|
|
if (addr2.toChar() == nullptr) return true;
|
|
|
|
|
|
|
|
|
|
// make the comparison based on string comparison
|
|
|
|
|
return strcmp(addr1.toChar(), addr2.toChar()) > 0;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// done
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// de we want to have reverse ordering of proximity
|
|
|
|
|
case ConnectionOrder::Order::reverse:
|
|
|
|
|
{
|
|
|
|
|
std::reverse(_v.begin(), _v.end());
|
|
|
|
|
|
|
|
|
|
// done
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
// nothing to do, just default behaviour
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-11-01 01:26:04 +08:00
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* Constructor
|
|
|
|
|
* @param hostname
|
|
|
|
|
* @param port
|
2020-11-16 23:30:29 +08:00
|
|
|
* @param order
|
2015-11-01 01:26:04 +08:00
|
|
|
*/
|
2020-11-16 23:30:29 +08:00
|
|
|
AddressInfo(const char *hostname, uint16_t port = 5672, ConnectionOrder::Order order = ConnectionOrder::Order::standard)
|
2015-11-01 01:26:04 +08:00
|
|
|
{
|
|
|
|
|
// store portnumber in buffer
|
|
|
|
|
auto portnumber = std::to_string(port);
|
|
|
|
|
|
|
|
|
|
// info about the lookup
|
|
|
|
|
struct addrinfo hints;
|
|
|
|
|
|
|
|
|
|
// set everything to zero
|
2015-11-28 18:38:15 +08:00
|
|
|
memset(&hints, 0, sizeof(struct addrinfo));
|
2015-11-01 01:26:04 +08:00
|
|
|
|
|
|
|
|
// set hints
|
|
|
|
|
hints.ai_family = AF_UNSPEC; // allow IPv4 or IPv6
|
|
|
|
|
hints.ai_socktype = SOCK_STREAM; // datagram socket/
|
|
|
|
|
|
|
|
|
|
// get address of the server
|
|
|
|
|
auto code = getaddrinfo(hostname, portnumber.data(), &hints, &_info);
|
|
|
|
|
|
|
|
|
|
// was there an error
|
|
|
|
|
if (code != 0) throw std::runtime_error(gai_strerror(code));
|
|
|
|
|
|
|
|
|
|
// keep looping
|
|
|
|
|
for (auto *current = _info; current; current = current->ai_next)
|
|
|
|
|
{
|
|
|
|
|
// store in vector
|
|
|
|
|
_v.push_back(current);
|
|
|
|
|
}
|
2020-11-14 00:10:30 +08:00
|
|
|
|
2020-11-16 23:30:29 +08:00
|
|
|
// Order the vector based on the provided ordering
|
|
|
|
|
reorder(order);
|
2015-11-01 01:26:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Destructor
|
|
|
|
|
*/
|
|
|
|
|
virtual ~AddressInfo()
|
|
|
|
|
{
|
|
|
|
|
// free address info
|
|
|
|
|
freeaddrinfo(_info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Size of the array
|
|
|
|
|
* @return size_t
|
|
|
|
|
*/
|
|
|
|
|
size_t size() const
|
|
|
|
|
{
|
|
|
|
|
return _v.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get reference to struct
|
|
|
|
|
* @param index
|
|
|
|
|
* @return struct addrinfo*
|
|
|
|
|
*/
|
|
|
|
|
const struct addrinfo *operator[](int index) const
|
|
|
|
|
{
|
|
|
|
|
// expose vector
|
|
|
|
|
return _v[index];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* End of namespace
|
|
|
|
|
*/
|
|
|
|
|
}
|