simplified code, split up long methods in separate methods
This commit is contained in:
parent
21a431d8a8
commit
bca39d8f29
|
|
@ -1,108 +0,0 @@
|
||||||
/**
|
|
||||||
* Address2Str.h
|
|
||||||
*
|
|
||||||
* Helper class to get a stringed version of an address obtained from get_addrinfo
|
|
||||||
*
|
|
||||||
* @author Aljar Meesters <aljar.meesters@copernica.com
|
|
||||||
* @copyright 2020 Copernica BV
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Include guard
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dependencies
|
|
||||||
*/
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opening namespace
|
|
||||||
*/
|
|
||||||
namespace AMQP {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* class implemenation
|
|
||||||
*/
|
|
||||||
class Address2str
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* The address as string
|
|
||||||
*/
|
|
||||||
char *_buffer = nullptr;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
* @param struct addrinfo *
|
|
||||||
*/
|
|
||||||
Address2str(struct addrinfo *info)
|
|
||||||
{
|
|
||||||
// Switch on family
|
|
||||||
switch(info->ai_family)
|
|
||||||
{
|
|
||||||
// If we are ip4
|
|
||||||
case AF_INET:
|
|
||||||
{
|
|
||||||
// ugly cast
|
|
||||||
struct sockaddr_in *addr_in = (struct sockaddr_in *)(info->ai_addr);
|
|
||||||
|
|
||||||
// create the buffer
|
|
||||||
_buffer = new char[INET_ADDRSTRLEN];
|
|
||||||
|
|
||||||
// get the info in our buffer
|
|
||||||
inet_ntop(AF_INET, &(addr_in->sin_addr), _buffer, INET_ADDRSTRLEN);
|
|
||||||
|
|
||||||
// done
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we are ipv6
|
|
||||||
case AF_INET6:
|
|
||||||
{
|
|
||||||
// ugly cast
|
|
||||||
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)(info->ai_addr);
|
|
||||||
|
|
||||||
// crate buffer
|
|
||||||
_buffer = new char[INET6_ADDRSTRLEN];
|
|
||||||
|
|
||||||
// get the info in our buffer
|
|
||||||
inet_ntop(AF_INET6, &(addr_in6->sin6_addr), _buffer, INET6_ADDRSTRLEN);
|
|
||||||
|
|
||||||
// done
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// If it is not ipv4 or ipv6 we don't set it.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destruction
|
|
||||||
*/
|
|
||||||
virtual ~Address2str()
|
|
||||||
{
|
|
||||||
// if we have a buffer, we should free it.
|
|
||||||
if (_buffer) delete[](_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the char
|
|
||||||
* @return char*
|
|
||||||
*/
|
|
||||||
const char *toChar() const
|
|
||||||
{
|
|
||||||
// expose the buffer.
|
|
||||||
return _buffer;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ending of namespace
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
*/
|
*/
|
||||||
#include <random>
|
#include <random>
|
||||||
#include "connectionorder.h"
|
#include "connectionorder.h"
|
||||||
#include "address2str.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Include guard
|
* Include guard
|
||||||
|
|
@ -39,93 +38,22 @@ private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to order the vector of addrinfo based on the ordering received
|
* Helper function to order the vector of addrinfo based on the ordering received
|
||||||
|
* This may be useful since getaddrinfo is sorting the addresses on proximity
|
||||||
|
* (e.g. https://lists.debian.org/debian-glibc/2007/09/msg00347.html),
|
||||||
* @param order
|
* @param order
|
||||||
*/
|
*/
|
||||||
void reorder(ConnectionOrder::Order order)
|
void reorder(const ConnectionOrder &order)
|
||||||
{
|
{
|
||||||
// witch on order
|
// witch on order
|
||||||
switch (order)
|
switch (order.order()) {
|
||||||
{
|
case ConnectionOrder::Order::random: shuffle(); break;
|
||||||
// Do we want to have a random order of the addresses?
|
case ConnectionOrder::Order::ascending: sort(); break;
|
||||||
// This may be useful since getaddrinfo is sorting the addresses on proximity
|
case ConnectionOrder::Order::descending: sort(); reverse(); break;
|
||||||
// (e.g. https://lists.debian.org/debian-glibc/2007/09/msg00347.html),
|
case ConnectionOrder::Order::reverse: reverse(); break;
|
||||||
// which may break loadbalancing..
|
default: break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
|
@ -133,7 +61,7 @@ public:
|
||||||
* @param port
|
* @param port
|
||||||
* @param order
|
* @param order
|
||||||
*/
|
*/
|
||||||
AddressInfo(const char *hostname, uint16_t port = 5672, ConnectionOrder::Order order = ConnectionOrder::Order::standard)
|
AddressInfo(const char *hostname, uint16_t port, const ConnectionOrder &order)
|
||||||
{
|
{
|
||||||
// store portnumber in buffer
|
// store portnumber in buffer
|
||||||
auto portnumber = std::to_string(port);
|
auto portnumber = std::to_string(port);
|
||||||
|
|
@ -174,6 +102,65 @@ public:
|
||||||
freeaddrinfo(_info);
|
freeaddrinfo(_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shuffle the addresses
|
||||||
|
*/
|
||||||
|
void shuffle()
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Order the addresses based on IP
|
||||||
|
*/
|
||||||
|
void sort()
|
||||||
|
{
|
||||||
|
// sort the addresses
|
||||||
|
std::sort(_v.begin(), _v.end(), [](const struct addrinfo *v1, const struct addrinfo *v2) -> bool {
|
||||||
|
|
||||||
|
// check the IP versions (they must be identical to be comparable)
|
||||||
|
if (v1->ai_family != v2->ai_family) return v1->ai_family < v2->ai_family;
|
||||||
|
|
||||||
|
// should we compare ipv4 or ipv6?
|
||||||
|
switch (v1->ai_family) {
|
||||||
|
case AF_INET: {
|
||||||
|
// ugly cast
|
||||||
|
auto *a1 = (struct sockaddr_in *)(v1->ai_addr);
|
||||||
|
auto *a2 = (struct sockaddr_in *)(v2->ai_addr);
|
||||||
|
|
||||||
|
// do the comparison for the addresses
|
||||||
|
return a1->sin_addr.s_addr < a2->sin_addr.s_addr;
|
||||||
|
}
|
||||||
|
case AF_INET6: {
|
||||||
|
// ugly cast
|
||||||
|
auto *a1 = (struct sockaddr_in6 *)(v1->ai_addr);
|
||||||
|
auto *a2 = (struct sockaddr_in6 *)(v2->ai_addr);
|
||||||
|
|
||||||
|
// do the comparison
|
||||||
|
return memcmp(&a1->sin6_addr, &a2->sin6_addr, sizeof(in6_addr)) < 0;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the order
|
||||||
|
*/
|
||||||
|
void reverse()
|
||||||
|
{
|
||||||
|
// reverse the order
|
||||||
|
std::reverse(_v.begin(), _v.end());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of the array
|
* Size of the array
|
||||||
* @return size_t
|
* @return size_t
|
||||||
|
|
|
||||||
|
|
@ -47,21 +47,24 @@ public:
|
||||||
* Constructor
|
* Constructor
|
||||||
* @var order
|
* @var order
|
||||||
*/
|
*/
|
||||||
ConnectionOrder (const char *order) : _order(Order::standard)
|
ConnectionOrder(const char *order) : _order(Order::standard)
|
||||||
{
|
{
|
||||||
// Set the orders based on the string
|
// Set the orders based on the string
|
||||||
if (strcmp(order, "random") == 0) _order = Order::random;
|
if (strcmp(order, "random") == 0) _order = Order::random;
|
||||||
else if (strcmp(order, "ascending") == 0 || strcmp(order, "asc") == 0) _order = Order::ascending;
|
else if (strcmp(order, "ascending") == 0 || strcmp(order, "asc") == 0) _order = Order::ascending;
|
||||||
else if (strcmp(order, "descending") == 0 || strcmp(order, "desc") == 0 ) _order = Order::descending;
|
else if (strcmp(order, "descending") == 0 || strcmp(order, "desc") == 0 ) _order = Order::descending;
|
||||||
|
|
||||||
// If we don't ave a match we fall back to standard, which was set as default
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
|
virtual ~ConnectionOrder() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the order
|
* Get the order
|
||||||
* @return Order
|
* @return Order
|
||||||
*/
|
*/
|
||||||
Order order()
|
const Order &order() const
|
||||||
{
|
{
|
||||||
return _order;
|
return _order;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ namespace AMQP {
|
||||||
*/
|
*/
|
||||||
TcpConnection::TcpConnection(TcpHandler *handler, const Address &address) :
|
TcpConnection::TcpConnection(TcpHandler *handler, const Address &address) :
|
||||||
_handler(handler),
|
_handler(handler),
|
||||||
_state(new TcpResolver(this, address.hostname(), address.port(), address.secure(), address.option("connectTimeout", 5), ConnectionOrder(address.option("connectionOrder")).order())),
|
_state(new TcpResolver(this, address.hostname(), address.port(), address.secure(), address.option("connectTimeout", 5), ConnectionOrder(address.option("connectionOrder")))),
|
||||||
_connection(this, address.login(), address.vhost())
|
_connection(this, address.login(), address.vhost())
|
||||||
{
|
{
|
||||||
// tell the handler
|
// tell the handler
|
||||||
|
|
|
||||||
|
|
@ -87,9 +87,9 @@ private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How should the addresses be ordered when we want to connect
|
* How should the addresses be ordered when we want to connect
|
||||||
* @var bool
|
* @var ConnectionOrdre
|
||||||
*/
|
*/
|
||||||
ConnectionOrder::Order _order;
|
ConnectionOrder _order;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -196,7 +196,7 @@ public:
|
||||||
* @param timeout timeout per connection attempt
|
* @param timeout timeout per connection attempt
|
||||||
* @param order How should we oreder the addresses of the host to connect to
|
* @param order How should we oreder the addresses of the host to connect to
|
||||||
*/
|
*/
|
||||||
TcpResolver(TcpParent *parent, std::string hostname, uint16_t port, bool secure, int timeout, ConnectionOrder::Order order) :
|
TcpResolver(TcpParent *parent, std::string hostname, uint16_t port, bool secure, int timeout, const ConnectionOrder &order) :
|
||||||
TcpExtState(parent),
|
TcpExtState(parent),
|
||||||
_hostname(std::move(hostname)),
|
_hostname(std::move(hostname)),
|
||||||
_secure(secure),
|
_secure(secure),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue