6#include <boost/url.hpp>
7#include <boost/algorithm/string.hpp>
8#include <boost/asio.hpp>
9#include <boost/chrono.hpp>
10#include <boost/thread.hpp>
11#include <boost/log/trivial.hpp>
12#include <boost/log/common.hpp>
13#include <boost/log/sinks.hpp>
14#include <boost/log/sources/logger.hpp>
15#include <boost/log/expressions.hpp>
16#include <boost/log/attributes.hpp>
17#include <boost/log/support/date_time.hpp>
18#include <boost/core/null_deleter.hpp>
19#include <boost/shared_ptr.hpp>
21#include "grpc/loadbalancer.grpc.pb.h"
23#include "e2sarError.hpp"
25using namespace boost::asio;
26using namespace std::string_literals;
27using namespace boost::log;
29#define BOOST_LOG_FLUSH() sink->flush()
30#define BOOST_MLL_START(PREF) { std::ostringstream PREF_ostr;
31#define BOOST_MLL_LOG(PREF) PREF_ostr
32#define BOOST_MLL_STOP(PREF) BOOST_LOG_SEV(lg, trivial::info) << PREF_ostr.str(); } BOOST_LOG_FLUSH();
34#define BOOST_LOG_INFO() BOOST_LOG_SEV(lg, trivial::info)
35#define BOOST_LOG_WARN() BOOST_LOG_SEV(lg, trivial::warning)
36#define BOOST_LOG_ERR() BOOST_LOG_SEV(lg, trivial::error)
43 typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink;
44 extern boost::shared_ptr<text_sink> sink;
45 extern sources::severity_logger_mt<trivial::severity_level> lg;
47 const u_int16_t DATAPLANE_PORT = 19522;
48 const u_int16_t DATAPLANE_PORT_MIN = 16384;
49 const u_int16_t DATAPLANE_PORT_MAX = 32767;
61 enum class TokenType: u_int16_t {
63 all=0, admin=1, load_balancer=admin, instance=2, reservation=instance, session=3, END
65 inline static constexpr size_t ttAsIdx(TokenType tt)
67 return static_cast<size_t>(tt);
69 inline static const std::string toString(TokenType tt)
72 case TokenType::all:
return "ALL"s;
73 case TokenType::admin:
return "LOAD_BALANCER"s;
74 case TokenType::instance:
return "RESERVATION"s;
75 case TokenType::session:
return "SESSION"s;
76 default:
return "UNKNOWN"s;
79 static const size_t tokenTypeCardinality =
static_cast<size_t>(TokenType::END);
82 enum class TokenPermission: u_int16_t {
84 _read_only_, _register_, _reserve_, _update_, END
86 inline static const std::string toString(TokenPermission tt)
89 case TokenPermission::_read_only_:
return "READ"s;
90 case TokenPermission::_register_:
return "REGISTER"s;
91 case TokenPermission::_reserve_:
return "RESERVE"s;
92 case TokenPermission::_update_:
return "UPDATE"s;
93 default:
return "UNKNOWN"s;
96 static const size_t tokenPermissionCardinality =
static_cast<size_t>(TokenPermission::END);
112 u_int16_t syncPortv4;
113 u_int16_t syncPortv6;
117 u_int16_t dataMinPort;
118 u_int16_t dataMaxPort;
125 std::array<std::string, tokenTypeCardinality> tokensByType;
127 std::string sessionId;
130 ip::address dataAddrv4;
131 ip::address dataAddrv6;
133 ip::address syncAddrv4;
134 ip::address syncAddrv6;
146 EjfatURI(
const std::string &uri, TokenType tt=TokenType::admin,
bool preferV6=
false);
165 inline void set_Token(
const std::string &t, TokenType tt)
167 tokensByType[ttAsIdx(tt)] = t;
173 tokensByType[ttAsIdx(TokenType::instance)] = t;
179 tokensByType[ttAsIdx(TokenType::session)] = t;
185 auto idx = ttAsIdx(TokenType::instance);
186 if (!tokensByType[idx].empty())
187 return tokensByType[idx];
189 return E2SARErrorInfo{E2SARErrorc::ParameterNotAvailable,
"Instance token not available"s};
195 auto idx = ttAsIdx(TokenType::session);
196 if (!tokensByType[idx].empty())
197 return tokensByType[idx];
199 return E2SARErrorInfo{E2SARErrorc::ParameterNotAvailable,
"Session token not available"s};
205 auto idx = ttAsIdx(TokenType::admin);
206 if (!tokensByType[idx].empty())
207 return tokensByType[idx];
209 return E2SARErrorInfo{E2SARErrorc::ParameterNotAvailable,
"Admin token not available"s};
235 if (a.first.is_v4()) {
236 syncAddrv4 = a.first;
237 syncPortv4 = a.second;
240 syncAddrv6 = a.first;
241 syncPortv6 = a.second;
250 inline void set_dataAddr(
const std::pair<ip::address, std::pair<u_int16_t, u_int16_t>> &a)
252 if (a.first.is_v4()) {
253 dataAddrv4 = a.first;
257 dataAddrv6 = a.first;
260 dataMinPort = a.second.first;
261 dataMaxPort = a.second.second;
269 dataMinPort = minPort;
270 dataMaxPort = maxPort;
292 inline const result<std::pair<ip::address, u_int16_t>>
get_cpAddr()
const
294 return std::pair<ip::address, u_int16_t>(cpAddr, cpPort);
298 inline const result<std::pair<std::string, u_int16_t>>
get_cpHost()
const
301 return std::pair<std::string, u_int16_t>(cpHost, cpPort);
303 return E2SARErrorInfo{E2SARErrorc::ParameterNotAvailable,
"Control plane hostname not available"s};
321 return haveDatav4 || haveDatav6;
327 return haveSyncv4 || haveSyncv6;
343 inline const result<std::pair<ip::address, std::pair<u_int16_t, u_int16_t>>>
get_dataAddrv4() const noexcept
346 return std::make_pair(dataAddrv4, std::make_pair(dataMinPort, dataMaxPort));
347 return E2SARErrorInfo{E2SARErrorc::ParameterNotAvailable,
"Data plane address not available"s};
351 inline const result<std::pair<ip::address, std::pair<u_int16_t, u_int16_t>>>
get_dataAddrv6() const noexcept
354 return std::make_pair(dataAddrv6, std::make_pair(dataMinPort, dataMaxPort));
355 return E2SARErrorInfo{E2SARErrorc::ParameterNotAvailable,
"Data plane address not available"s};
361 if (haveDatav4 || haveDatav6)
362 return std::pair<u_int16_t, u_int16_t>(dataMinPort, dataMaxPort);
363 return E2SARErrorInfo{E2SARErrorc::ParameterNotAvailable,
"Data plane address not available"s};
367 inline const result<std::pair<ip::address, u_int16_t>>
get_syncAddrv4() const noexcept
370 return std::pair<ip::address, u_int16_t>(syncAddrv4, syncPortv4);
371 return E2SARErrorInfo{E2SARErrorc::ParameterNotAvailable,
"Sync v4 address not available"s};
375 inline const result<std::pair<ip::address, u_int16_t>>
get_syncAddrv6() const noexcept
378 return std::pair<ip::address, u_int16_t>(syncAddrv6, syncPortv6);
379 return E2SARErrorInfo{E2SARErrorc::ParameterNotAvailable,
"Sync v6 address not available"s};
383 inline const result<std::pair<ip::address, u_int16_t>>
get_syncAddr() const noexcept
385 if (preferV6 && haveSyncv6)
386 return std::pair<ip::address, u_int16_t>(syncAddrv6, syncPortv6);
388 return std::pair<ip::address, u_int16_t>(syncAddrv4, syncPortv4);
390 return std::pair<ip::address, u_int16_t>(syncAddrv6, syncPortv6);
391 return E2SARErrorInfo{E2SARErrorc::ParameterNotAvailable,
"Sync address not available"s};
397 operator std::string()
const;
399 const std::string to_string(TokenType tt = TokenType::admin)
const;
406 static inline result<EjfatURI>
getFromEnv(
const std::string &envVar =
"EJFAT_URI"s,
407 TokenType tt=TokenType::admin,
bool preferV6=
false) noexcept
409 const char *envStr = std::getenv(envVar.c_str());
410 if (envStr !=
nullptr)
414 return EjfatURI(envStr, tt, preferV6);
418 return E2SARErrorInfo{E2SARErrorc::CaughtException,
"Unable to parse EJFAT_URI from environment variable: "s +
static_cast<std::string
>(e)};
421 return E2SARErrorInfo{E2SARErrorc::Undefined,
"Environment variable "s + envVar +
" not defined."s};
430 TokenType tt=TokenType::admin,
bool preferV6=
false) noexcept
434 return EjfatURI(uriStr, tt, preferV6);
438 return E2SARErrorInfo{E2SARErrorc::CaughtException,
"Unable to parse URI from string: "s +
static_cast<std::string
>(e)};
447 static inline result<EjfatURI>
getFromFile(
const std::string &fileName =
"/tmp/ejfat_uri"s,
448 TokenType tt=TokenType::admin,
bool preferV6=
false) noexcept
450 if (!fileName.empty())
452 std::ifstream file(fileName);
456 if (std::getline(file, uriLine))
461 return EjfatURI(uriLine, tt, preferV6);
465 return E2SARErrorInfo{E2SARErrorc::CaughtException,
"Unable to parse URI: "s +
static_cast<std::string
>(e)};
469 return E2SARErrorInfo{E2SARErrorc::Undefined,
"Unable to parse URI."s};
472 return E2SARErrorInfo{E2SARErrorc::NotFound,
"Unable to find file "s + fileName};
486 static inline const result<ip::address> string_to_ip(const std::
string &addr) noexcept
495 ip::make_address(addr.substr(1, addr.length() - 2));
501 return ip::make_address(addr.substr(1, addr.length() - 2));
504 return ip::make_address(addr);
506 catch (boost::system::system_error &e)
508 return E2SARErrorInfo{E2SARErrorc::ParameterError,
"Unable to convert IP address from "s + addr};
515 static inline const result<u_int16_t> string_to_port(
const std::string &port_string)
noexcept
519 u_int16_t port = std::stoi(port_string);
520 if (port < 1024 || port > 65535)
523 return E2SARErrorInfo{E2SARErrorc::OutOfRange,
"Port value "s + port_string +
" is out of range"s};
527 catch (
const std::exception &e)
529 return E2SARErrorInfo{E2SARErrorc::ParameterError,
"Unable to convert "s + port_string +
" to integer"s};
536 static inline const result<std::pair<ip::address, u_int16_t>> string_tuple_to_ip_and_port(
const std::string &t)
noexcept
539 auto const pos = t.find_last_of(
"]:");
542 if ((pos == std::string::npos) || (t[pos] ==
']'))
544 auto r1 = string_to_ip(t);
546 return std::pair<ip::address, u_int16_t>(r1.value(), 0);
548 return E2SARErrorInfo{E2SARErrorc::ParameterError,
"Unable to convert "s + t +
" to ip address and port"s};
552 auto r1 = string_to_ip(t.substr(0, pos));
553 auto r2 = string_to_port(t.substr(pos + 1));
555 return std::pair<ip::address, int>(r1.value(), r2.value());
556 return E2SARErrorInfo{E2SARErrorc::ParameterError,
"Unable to convert "s + t +
" to ip address and port"s};
566 static inline const result<std::tuple<ip::address, u_int16_t, u_int16_t>> string_tuple_to_ip_and_port_range(
const std::string &t)
noexcept
568 auto const pos = t.find_last_of(
"]:");
571 if ((pos == std::string::npos) || (t[pos] ==
']'))
573 auto r1 = string_to_ip(t);
575 return std::tuple<ip::address, u_int16_t, u_int16_t>(r1.value(), 0, 0);
577 return E2SARErrorInfo{E2SARErrorc::ParameterError,
"Unable to convert "s + t +
" to ip address and port range"s};
580 auto r1 = string_to_ip(t.substr(0, pos));
582 return E2SARErrorInfo{E2SARErrorc::ParameterError,
"Unable to convert "s + t +
" to ip address and port range"s};
584 std::string portStr = t.substr(pos + 1);
585 auto dashPos = portStr.find(
'-');
586 if (dashPos != std::string::npos)
589 auto r2 = string_to_port(portStr.substr(0, dashPos));
590 auto r3 = string_to_port(portStr.substr(dashPos + 1));
593 if (r2.value() > r3.value())
594 return E2SARErrorInfo{E2SARErrorc::ParameterError,
"Invalid port range: min > max in "s + t};
595 return std::tuple<ip::address, u_int16_t, u_int16_t>(r1.value(), r2.value(), r3.value());
597 return E2SARErrorInfo{E2SARErrorc::ParameterError,
"Unable to convert "s + t +
" to ip address and port range"s};
602 auto r2 = string_to_port(portStr);
604 return std::tuple<ip::address, u_int16_t, u_int16_t>(r1.value(), r2.value(), r2.value());
605 return E2SARErrorInfo{E2SARErrorc::ParameterError,
"Unable to convert "s + t +
" to ip address and port range"s};
615 static inline result<std::vector<ip::address>> resolveHost(
const std::string &host_name)
noexcept
618 std::vector<ip::address> addresses;
619 boost::asio::io_context io_context;
623 ip::udp::resolver resolver(io_context);
624 ip::udp::resolver::results_type results = resolver.resolve(host_name,
"443");
626 for(
auto i = results.begin(); i != results.end(); ++i)
628 ip::udp::endpoint endpoint = *i;
629 addresses.push_back(endpoint.address());
636 return E2SARErrorInfo{E2SARErrorc::NotFound,
"Unable to convert "s + host_name +
" to ip address"s};
642 std::size_t operator()(
const std::pair<u_int64_t, u_int16_t>& p)
const {
643 u_int64_t hash1 = p.first;
644 u_int64_t tmp = p.second;
645 u_int64_t hash2 = tmp | tmp << 16 | tmp << 32 | tmp << 48;
646 return hash1 ^ hash2;
651 bool operator()(
const std::pair<u_int64_t, u_int16_t>& lhs,
const std::pair<u_int64_t, u_int16_t>& rhs)
const {
652 return lhs.first == rhs.first && lhs.second == rhs.second;
664 static inline float clockEntropyTest(
int totalTests = 1000,
int sleepMs = 1)
666 std::vector<int_least64_t> points;
667 std::vector<int> bins(256, 0);
669 for (
int i = 0; i < totalTests; i++)
671 auto now = boost::chrono::system_clock::now();
672 auto nowUsec = boost::chrono::duration_cast<boost::chrono::microseconds>(now.time_since_epoch()).count();
673 bins[nowUsec & 0xff]++;
674 auto until = now + boost::chrono::milliseconds(sleepMs);
675 boost::this_thread::sleep_until(until);
680 for (
size_t i = 0; i < bins.size(); i++)
682 float prob =
static_cast<float>(bins[i])/(totalTests*1.0);
683 entropy += prob * std::log(prob);
687 entropy *= -1.0/std::log(2);
691 template<
typename Container>
692 std::string concatWithSeparator(
const Container& c,
const std::string& sep=
","s)
694 typename Container::const_iterator it = c.begin();
706 inline void busyWaitUsecs(
const boost::chrono::steady_clock::time_point &tp, int64_t usecs)
711 if (boost::chrono::duration_cast<boost::chrono::microseconds>(boost::chrono::high_resolution_clock::now()
712 - tp).count() > usecs)
717 using OptimizationsWord = u_int16_t;
735 inline static OptimizationsWord toWord(Code o)
737 return 1 <<
static_cast<int>(o);
739 inline static std::string toString(Code o)
743 case Code::none:
return "none"s;
744 case Code::sendmmsg:
return "sendmmsg";
745 case Code::liburing_recv:
return "liburing_recv";
746 case Code::liburing_send:
return "liburing_send";
747 case Code::recvmmsg:
return "recvmmsg";
752 inline static Code fromString(
const std::string& opt)
756 else if (opt ==
"sendmmsg"s)
757 return Code::sendmmsg;
758 else if (opt ==
"liburing_recv"s)
759 return Code::liburing_recv;
760 else if (opt ==
"liburing_send"s)
761 return Code::liburing_send;
762 else if (opt ==
"recvmmsg"s)
763 return Code::recvmmsg;
764 return Code::unknown;
769 const static std::vector<std::string> availableAsStrings()
noexcept;
774 const static OptimizationsWord availableAsWord()
noexcept;
780 static result<int> select(std::vector<std::string>& opt)
noexcept;
786 static result <int> select(std::vector<Code> &opt)
noexcept;
791 const static std::vector<std::string> selectedAsStrings()
noexcept;
796 const static OptimizationsWord selectedAsWord()
noexcept;
801 const static std::vector<Code> selectedAsList()
noexcept;
806 const static bool isSelected(Code o)
noexcept;
809 static const std::vector<Optimizations::Code> available;
812 OptimizationsWord selected_optimizations;
Definition e2sarError.hpp:62
Definition e2sarUtil.hpp:59
EjfatURI(const std::string &uri, TokenType tt=TokenType::admin, bool preferV6=false)
Definition e2sarUtil.cpp:191
const result< std::pair< ip::address, u_int16_t > > get_syncAddr() const noexcept
Definition e2sarUtil.hpp:383
const result< std::string > get_SessionToken() const
Definition e2sarUtil.hpp:193
void set_lbName(const std::string &n)
Definition e2sarUtil.hpp:213
~EjfatURI()
Definition e2sarUtil.hpp:149
bool get_useTls() const
Definition e2sarUtil.hpp:159
const bool has_syncAddrv4() const
Definition e2sarUtil.hpp:331
const bool has_dataAddrv4() const
Definition e2sarUtil.hpp:307
void set_InstanceToken(const std::string &t)
Definition e2sarUtil.hpp:171
const std::string get_lbId() const
Definition e2sarUtil.hpp:280
const result< std::pair< std::string, u_int16_t > > get_cpHost() const
Definition e2sarUtil.hpp:298
static result< EjfatURI > getFromEnv(const std::string &envVar="EJFAT_URI"s, TokenType tt=TokenType::admin, bool preferV6=false) noexcept
Definition e2sarUtil.hpp:406
const result< std::pair< ip::address, u_int16_t > > get_syncAddrv6() const noexcept
Definition e2sarUtil.hpp:375
const bool has_syncAddr() const
Definition e2sarUtil.hpp:325
const bool has_syncAddrv6() const
Definition e2sarUtil.hpp:337
void set_dataPortRange(u_int16_t minPort, u_int16_t maxPort)
Definition e2sarUtil.hpp:267
void set_sessionId(const std::string &i)
Definition e2sarUtil.hpp:225
const result< std::string > get_AdminToken() const
Definition e2sarUtil.hpp:203
void set_dataAddr(const std::pair< ip::address, std::pair< u_int16_t, u_int16_t > > &a)
Definition e2sarUtil.hpp:250
void set_Token(const std::string &t, TokenType tt)
Definition e2sarUtil.hpp:165
const result< std::pair< ip::address, u_int16_t > > get_cpAddr() const
Definition e2sarUtil.hpp:292
const std::string get_sessionId() const
Definition e2sarUtil.hpp:286
const result< std::string > get_InstanceToken() const
Definition e2sarUtil.hpp:183
static result< EjfatURI > getFromFile(const std::string &fileName="/tmp/ejfat_uri"s, TokenType tt=TokenType::admin, bool preferV6=false) noexcept
Definition e2sarUtil.hpp:447
const result< std::pair< ip::address, std::pair< u_int16_t, u_int16_t > > > get_dataAddrv4() const noexcept
Definition e2sarUtil.hpp:343
void set_SessionToken(const std::string &t)
Definition e2sarUtil.hpp:177
const bool has_dataAddrv6() const
Definition e2sarUtil.hpp:313
const result< std::pair< ip::address, std::pair< u_int16_t, u_int16_t > > > get_dataAddrv6() const noexcept
Definition e2sarUtil.hpp:351
static result< EjfatURI > getFromString(const std::string &uriStr, TokenType tt=TokenType::admin, bool preferV6=false) noexcept
Definition e2sarUtil.hpp:429
result< std::vector< ip::address > > getDataplaneLocalAddresses(bool v6=false) noexcept
Definition e2sarUtil.cpp:451
const bool has_dataAddr() const
Definition e2sarUtil.hpp:319
const result< std::pair< u_int16_t, u_int16_t > > get_dataPortRange() const noexcept
Definition e2sarUtil.hpp:359
const result< std::pair< ip::address, u_int16_t > > get_syncAddrv4() const noexcept
Definition e2sarUtil.hpp:367
void set_syncAddr(const std::pair< ip::address, u_int16_t > &a)
Definition e2sarUtil.hpp:233
const std::string get_lbName() const
Definition e2sarUtil.hpp:274
void set_lbId(const std::string &i)
Definition e2sarUtil.hpp:219
Definition e2sarUtil.hpp:722
std::string expandTilde(const std::string &path)
Definition e2sarUtil.cpp:493
void defineClogLogger()
Definition e2sarUtil.cpp:515
Definition e2sarError.hpp:42
Definition e2sarUtil.hpp:650
Definition e2sarUtil.hpp:641