SWC-DB  v0.5.12 C++ documentations
SWC-DB© (Super Wide Column Database) - High Performance Scalable Database (https://github.com/kashirin-alex/swc-db)
Resolver.cc
Go to the documentation of this file.
1 /*
2  * SWC-DB© Copyright since 2019 Alex Kashirin <kashirin.alex@gmail.com>
3  * License details at <https://github.com/kashirin-alex/swc-db/#license>
4  */
5 
6 
9 
10 
11 #if defined(__MINGW64__) || defined(_WIN32)
12  #define EAI_SYSTEM EAI_FAIL
13 #endif
14 
15 
16 namespace SWC {
17 
18 
19 namespace Serialization {
20 
21 
22 void encode(uint8_t** bufp, const Comm::EndPoint& endpoint) {
23  Serialization::encode_bool(bufp, endpoint.address().is_v4());
24  Serialization::encode_i16(bufp, endpoint.port());
25  if(endpoint.address().is_v4()) {
26  auto v4_bytes = endpoint.address().to_v4().to_bytes();
27  Serialization::encode_bytes_fixed(bufp, v4_bytes.data(), v4_bytes.size());
28 
29  } else {
30  auto v6_bytes = endpoint.address().to_v6().to_bytes();
31  Serialization::encode_bytes_fixed(bufp, v6_bytes.data(), v6_bytes.size());
32  }
33 }
34 
35 Comm::EndPoint decode(const uint8_t** bufp, size_t* remainp) {
36  bool is_v4 = Serialization::decode_bool(bufp, remainp);
37  uint16_t port = Serialization::decode_i16(bufp, remainp);
38  if(is_v4) {
39  asio::ip::address_v4::bytes_type v4_bytes;
40  const uint8_t* bytes = Serialization::decode_bytes_fixed(
41  bufp, remainp, v4_bytes.size());
42  std::memcpy(v4_bytes.data(), bytes, v4_bytes.size());
43  return Comm::EndPoint(asio::ip::make_address_v4(v4_bytes), port);
44  }
45 
46  asio::ip::address_v6::bytes_type v6_bytes;
47  const uint8_t* bytes = Serialization::decode_bytes_fixed(
48  bufp, remainp, v6_bytes.size());
49  std::memcpy(v6_bytes.data(), bytes, v6_bytes.size());
50  return Comm::EndPoint(asio::ip::address_v6(v6_bytes), port);
51 }
52 
53 
54 uint32_t encoded_length(const Comm::EndPoints& endpoints) noexcept {
55  uint32_t len = Serialization::encoded_length_vi32(endpoints.size());
56  for(auto& endpoint : endpoints)
57  len += Serialization::encoded_length(endpoint);
58  return len;
59 }
60 
61 void encode(uint8_t** bufp, const Comm::EndPoints& endpoints) {
62  Serialization::encode_vi32(bufp, endpoints.size());
63  for(auto& endpoint : endpoints)
64  Serialization::encode(bufp, endpoint);
65 }
66 
67 void decode(const uint8_t** bufp, size_t* remainp,
68  Comm::EndPoints& endpoints) {
69  endpoints.clear();
70  endpoints.shrink_to_fit();
71  if(uint32_t sz = Serialization::decode_vi32(bufp, remainp)) {
72  endpoints.reserve(sz);
73  for(uint32_t i=0; i<sz; ++i)
74  endpoints.emplace_back(Serialization::decode(bufp, remainp));
75  }
76 }
77 
78 } // namespace Serialization
79 
80 
81 
82 namespace Comm {
83 
84 
85 void print(std::ostream& out, const EndPoints& endpoints) {
86  out << "endpoints=[";
87  for(auto& endpoint : endpoints)
88  out << endpoint << ',';
89  out << ']';
90 }
91 
92 
93 bool has_endpoint(const EndPoint& e1,
94  const EndPoints& endpoints_in) noexcept {
95  return std::find(endpoints_in.cbegin(), endpoints_in.cend(), e1)
96  != endpoints_in.cend();
97 }
98 
99 bool has_endpoint(const EndPoints& endpoints,
100  const EndPoints& endpoints_in) noexcept {
101  for(auto& endpoint : endpoints) {
102  if(has_endpoint(endpoint, endpoints_in))
103  return true;
104  }
105  return false;
106 }
107 
108 bool equal_endpoints(const EndPoints& endpoints1,
109  const EndPoints& endpoints2) noexcept {
110  if(endpoints1.size() != endpoints2.size())
111  return false;
112  auto it = endpoints2.cbegin();
113  for(; it != endpoints2.cend(); ++it) {
114  if(!has_endpoint(*it, endpoints1))
115  return false;
116  }
117  return it == endpoints2.cend();
118 }
119 
120 size_t endpoints_hash(const EndPoints& endpoints) {
121  std::string s;
122  s.reserve(23 * endpoints.size());
123  for(auto& endpoint : endpoints) {
124  s.append(endpoint.address().to_string());
125  s.append(":");
126  s.append(std::to_string(endpoint.port()));
127  s.append("_");
128  }
129  std::hash<std::string> hasher;
130  return hasher(s);
131 }
132 
133 size_t endpoint_hash(const EndPoint& endpoint) noexcept {
134  return std::hash<EndPoint>()(endpoint);
135 }
136 
137 
138 
139 
141 bool Resolver::is_ipv4_address(const std::string& str) noexcept {
142  struct sockaddr_in sa;
143  return inet_pton(AF_INET, str.c_str(), &(sa.sin_addr));
144 }
145 
147 bool Resolver::is_ipv6_address(const std::string& str) noexcept {
148  struct sockaddr_in6 sa;
149  return inet_pton(AF_INET6, str.c_str(), &(sa.sin6_addr));
150 }
151 
152 EndPoints Resolver::get_endpoints(uint16_t defaul_port,
153  const Config::Strings& addrs,
154  const std::string& host,
155  const Networks& nets,
156  bool srv) {
157  EndPoints endpoints;
158  std::string ip;
159  uint16_t port;
160  if(!addrs.empty()) {
161  for(auto& addr : addrs) {
162  auto at = addr.find_first_of("-");
163  if(at != std::string::npos) {
164  ip = addr.substr(0, at);
165  Config::Property::from_string(addr.c_str() + at + 1, &port);
166  } else {
167  ip = addr;
168  port = defaul_port;
169  }
170  endpoints.emplace_back(asio::ip::make_address(ip.c_str()), port );
171  }
172 
173  } else if(!host.empty()) {
174  std::string hostname;
175  auto hostname_cfg = host;
176  auto at = host.find_first_of(":");
177  if(at != std::string::npos) {
178  hostname = host.substr(0, at);
179  Config::Property::from_string(host.c_str() + at + 1, &port);
180  } else {
181  port = defaul_port;
182  hostname = host;
183  }
184  addrinfo hints, *result, *rp;
185  memset(&hints, 0, sizeof(struct addrinfo));
186 
187  hints.ai_family = AF_UNSPEC;
188  hints.ai_socktype = SOCK_STREAM;
189  hints.ai_protocol = 0;
190  hints.ai_flags = 0; //AI_CANONNAME | AI_ALL | AI_ADDRCONFIG;
191 
192  errno = 0;
193  int err = getaddrinfo(hostname.c_str(), nullptr, &hints, &result);
194  if(err) {
195  err = err == EAI_SYSTEM ? errno : (SWC_ERRNO_EAI_BEGIN + (-err));
196  SWC_THROWF(err, "Bad addr-info for host: %s", hostname.c_str());
197  }
198 
199  for (rp = result; rp != nullptr; rp = rp->ai_next) {
200  char c_addr[INET6_ADDRSTRLEN];
201  const char * s = nullptr;
202  switch(rp->ai_family) {
203  case AF_INET: {
204  s = inet_ntop(AF_INET,
205  &reinterpret_cast<struct sockaddr_in*>(rp->ai_addr)->sin_addr,
206  c_addr, INET_ADDRSTRLEN);
207  break;
208  }
209  case AF_INET6:{
210  s = inet_ntop(AF_INET6,
211  &reinterpret_cast<struct sockaddr_in6*>(rp->ai_addr)->sin6_addr,
212  c_addr, INET6_ADDRSTRLEN);
213  break;
214  }
215  default:
216  break;
217  }
218  if(!s) {
219  err = SWC_ERRNO_EAI_BEGIN + (-EAFNOSUPPORT);
220  break;
221  }
222 
223  endpoints.emplace_back(asio::ip::make_address(c_addr), port);
224  }
225  freeaddrinfo(result);
226  if(err)
227  SWC_THROWF(err, "Bad IP for host: %s", hostname.c_str());
228  }
229 
230  if(srv && endpoints.empty()) {
231  endpoints.emplace_back(asio::ip::make_address("::"), defaul_port);
232  return endpoints;
233  }
234 
235  if(nets.empty())
236  return endpoints;
237 
238  EndPoints sorted;
239  sort(nets, endpoints, sorted);
240  return sorted;
241 }
242 
243 void Resolver::sort(const Networks& nets, const EndPoints& endpoints,
244  EndPoints& sorted) {
245  // sort endpoints by Network Priority Access
246  asio::error_code ec;
247 
248  for(auto& net : nets) {
249  for(auto& endpoint : endpoints) {
250  if((net.is_v4 && endpoint.address().is_v4() &&
251  is_network(endpoint, net.v4)) ||
252  (!net.is_v4 && endpoint.address().is_v6() &&
253  is_network(endpoint, net.v6)))
254  sorted.push_back(endpoint);
255  }
256  }
257 
258  for(auto& endpoint : endpoints) { // add rest
259  if(!has_endpoint(endpoint, sorted))
260  sorted.push_back(endpoint);
261  }
262 }
263 
265  Networks& nets, asio::error_code& ec) {
266  nets.reserve(networks.size());
267  for(auto& net : networks) {
268  if(net.find_first_of(":") == std::string::npos)
269  nets.emplace_back(asio::ip::make_network_v4(net, ec));
270  else
271  nets.emplace_back(asio::ip::make_network_v6(net, ec));
272  }
273 }
274 
276  Networks_v4& nets_v4,
277  Networks_v6& nets_v6,
278  asio::error_code& ec) {
279  for(auto& net : networks) {
280  if(net.find_first_of(":") == std::string::npos)
281  nets_v4.push_back(asio::ip::make_network_v4(net, ec));
282  else
283  nets_v6.push_back(asio::ip::make_network_v6(net, ec));
284  }
285 }
286 
288  Networks_v4& nets_v4,
289  Networks_v6& nets_v6) {
290  char hostname[256];
291  if(gethostname(hostname, sizeof(hostname)) == -1) {
292  err = errno;
293  return;
294  }
295 
296  addrinfo hints, *result, *rp;
297  memset(&hints, 0, sizeof(struct addrinfo));
298  hints.ai_family = AF_UNSPEC;
299  hints.ai_socktype = SOCK_STREAM;
300  hints.ai_protocol = 0;
301  hints.ai_flags = 0;
302 
303  errno = 0;
304  if((err = getaddrinfo(hostname, nullptr, &hints, &result))) {
305  err = err == EAI_SYSTEM ? errno : (SWC_ERRNO_EAI_BEGIN + (-err));
306  return;
307  }
308 
309  asio::error_code ec;
310  for (rp = result; rp != nullptr; rp = rp->ai_next) {
311  char c_addr[INET6_ADDRSTRLEN];
312  const char * s = nullptr;
313  errno = 0;
314  switch(rp->ai_family) {
315  case AF_INET: {
316  s = inet_ntop(AF_INET,
317  &reinterpret_cast<struct sockaddr_in*>(rp->ai_addr)->sin_addr,
318  c_addr, INET_ADDRSTRLEN);
319  if(s)
320  nets_v4.push_back(
321  asio::ip::make_network_v4(
322  asio::ip::make_address_v4(c_addr, ec), 32));
323  break;
324  }
325  case AF_INET6: {
326  s = inet_ntop(AF_INET6,
327  &reinterpret_cast<struct sockaddr_in6*>(rp->ai_addr)->sin6_addr,
328  c_addr, INET6_ADDRSTRLEN);
329  if(s)
330  nets_v6.push_back(
331  asio::ip::make_network_v6(
332  asio::ip::make_address_v6(c_addr, ec), 128));
333  break;
334  }
335  default:
336  break;
337  }
338  if(!s) {
339  err = SWC_ERRNO_EAI_BEGIN + (-EAFNOSUPPORT);
340  break;
341  }
342  if(ec) {
343  err = ec.value();
344  break;
345  }
346  if(errno) {
347  err = errno;
348  break;
349  }
350  }
351  freeaddrinfo(result);
352 }
353 
354 bool Resolver::is_network(const EndPoint& endpoint,
355  const Networks_v4& nets_v4,
356  const Networks_v6& nets_v6) noexcept {
357  if(endpoint.address().is_v4()) {
358  for(auto& net : nets_v4)
359  if(is_network(endpoint, net))
360  return true;
361  return false;
362  }
363  if(endpoint.address().is_v6()) {
364  for(auto& net : nets_v6) {
365  if(is_network(endpoint, net))
366  return true;
367  }
368  return false;
369  }
370  return false;
371 }
372 
373 bool Resolver::is_network(const EndPoint& endpoint,
374  const asio::ip::network_v4& net) noexcept {
375  return endpoint.address().to_v4() == net.address() ||
376  asio::ip::make_network_v4(endpoint.address().to_v4(), 32)
377  .is_subnet_of(net);
378 }
379 
380 bool Resolver::is_network(const EndPoint& endpoint,
381  const asio::ip::network_v6& net) noexcept {
382  return endpoint.address().to_v6() == net.address() ||
383  asio::ip::make_network_v6(endpoint.address().to_v6(), 128)
384  .is_subnet_of(net);
385 }
386 
387 }} // namespace SWC::Comm
SWC::Comm::Resolver::is_network
bool is_network(const EndPoint &endpoint, const Networks_v4 &nets_v4, const Networks_v6 &nets_v6) noexcept
Definition: Resolver.cc:354
SWC::Comm::Resolver::get_networks
void get_networks(const Config::Strings &networks, Networks &nets, asio::error_code &ec)
Definition: Resolver.cc:264
SWC::Comm::Resolver::get_local_networks
void get_local_networks(int &err, Networks_v4 &nets_v4, Networks_v6 &nets_v6)
Definition: Resolver.cc:287
SWC::Core::Vector::clear
SWC_CAN_INLINE void clear() noexcept(_NoExceptDestructor)
Definition: Vector.h:120
SWC::Serialization::encoded_length_vi32
constexpr SWC_CAN_INLINE uint8_t encoded_length_vi32(uint32_t val) noexcept
Definition: Serialization.h:234
SWC::Comm::EndPoint
asio::ip::tcp::endpoint EndPoint
Definition: Resolver.h:19
SWC_ERRNO_EAI_BEGIN
#define SWC_ERRNO_EAI_BEGIN
Definition: Error.h:31
SWC::Serialization::encode_i16
SWC_CAN_INLINE void encode_i16(uint8_t **bufp, uint16_t val) noexcept
Definition: Serialization.h:112
SWC::Comm::has_endpoint
bool SWC_PURE_FUNC has_endpoint(const EndPoint &e1, const EndPoints &endpoints_in) noexcept
Definition: Resolver.cc:93
SWC::Comm::endpoints_hash
size_t endpoints_hash(const EndPoints &endpoints)
Definition: Resolver.cc:120
SWC::Serialization::encoded_length
SWC_CAN_INLINE uint8_t encoded_length(const Comm::EndPoint &endpoint) noexcept
Definition: Resolver.h:63
SWC::Comm::print
void print(std::ostream &out, const EndPoints &endpoints)
Definition: Resolver.cc:85
SWC::Serialization::encode
void encode(uint8_t **bufp, const Comm::EndPoint &endpoint)
Definition: Resolver.cc:22
SWC::Serialization::encode_bool
constexpr SWC_CAN_INLINE void encode_bool(uint8_t **bufp, bool bval) noexcept
Definition: Serialization.h:102
Resolver.h
SWC::Core::Vector::empty
constexpr SWC_CAN_INLINE bool empty() const noexcept
Definition: Vector.h:168
SWC::Serialization::encode_bytes_fixed
SWC_CAN_INLINE void encode_bytes_fixed(uint8_t **bufp, const void *data, uint32_t len) noexcept
Definition: Serialization.h:568
SWC::Serialization::decode_i16
SWC_CAN_INLINE uint16_t decode_i16(const uint8_t **bufp, size_t *remainp)
Definition: Serialization.h:117
SWC
The SWC-DB C++ namespace 'SWC'.
Definition: main.cc:12
SWC::Serialization::decode_bool
constexpr SWC_CAN_INLINE bool decode_bool(const uint8_t **bufp, size_t *remainp)
Definition: Serialization.h:107
Serialization.h
SWC_THROWF
#define SWC_THROWF(_code_, _fmt_,...)
Definition: Exception.h:136
SWC::Config::str
Property::Value_string::Ptr str(std::string &&v)
Definition: PropertiesParser.cc:45
SWC::Config::Property::from_string
void from_string(const char *s, double *value)
Definition: Property.cc:109
SWC_SHOULD_INLINE
#define SWC_SHOULD_INLINE
Definition: Compat.h:63
SWC::Comm::Resolver::sort
void sort(const Networks &nets, const EndPoints &endpoints, EndPoints &sorted)
Definition: Resolver.cc:243
SWC::Core::Vector::shrink_to_fit
SWC_CAN_INLINE void shrink_to_fit(size_type sz=0)
Definition: Vector.h:276
SWC::Core::Vector< EndPoint >
SWC::Comm::Resolver::is_ipv4_address
bool is_ipv4_address(const std::string &str) noexcept
Definition: Resolver.cc:141
SWC::Serialization::decode
Comm::EndPoint decode(const uint8_t **bufp, size_t *remainp)
Definition: Resolver.cc:35
SWC::Serialization::encode_vi32
constexpr SWC_CAN_INLINE void encode_vi32(uint8_t **bufp, uint32_t val)
Definition: Serialization.h:243
SWC::Serialization::decode_bytes_fixed
constexpr SWC_CAN_INLINE const uint8_t * decode_bytes_fixed(const uint8_t **bufp, size_t *remainp, uint32_t len)
Definition: Serialization.h:574
SWC::Comm::endpoint_hash
size_t SWC_PURE_FUNC endpoint_hash(const EndPoint &endpoint) noexcept
Definition: Resolver.cc:133
SWC::Comm::Resolver::is_ipv6_address
bool is_ipv6_address(const std::string &str) noexcept
Definition: Resolver.cc:147
SWC::Comm::Resolver::get_endpoints
EndPoints get_endpoints(uint16_t defaul_port, const Config::Strings &addrs, const std::string &host, const Networks &nets, bool srv=false)
Definition: Resolver.cc:152
SWC::Core::Vector::push_back
SWC_CAN_INLINE void push_back(ArgsT &&... args)
Definition: Vector.h:331
SWC::Core::to_string
SWC_CAN_INLINE std::string to_string(const BitFieldInt< T, SZ > &v)
Definition: BitFieldInt.h:263
SWC::Core::Vector::size
constexpr SWC_CAN_INLINE size_type size() const noexcept
Definition: Vector.h:189
SWC::Core::Vector::emplace_back
SWC_CAN_INLINE reference emplace_back(ArgsT &&... args)
Definition: Vector.h:349
SWC::Core::Vector::reserve
SWC_CAN_INLINE void reserve(size_type cap)
Definition: Vector.h:288
SWC::Comm::equal_endpoints
bool SWC_PURE_FUNC equal_endpoints(const EndPoints &endpoints1, const EndPoints &endpoints2) noexcept
Definition: Resolver.cc:108
SWC::Serialization::decode_vi32
constexpr SWC_CAN_INLINE uint32_t decode_vi32(const uint8_t **bufp, size_t *remainp)
Definition: Serialization.h:254