#pragma once
#include "../env.h"
#include <boost/asio/ip/basic_endpoint.hpp>
namespace vgw {
namespace packet {
enum AddressFamily {
InterNetwork = AF_INET,
InterNetworkV6 = AF_INET6,
};
struct IPEndPoint {
private:
mutable Byte _AddressBytes[sizeof(struct in6_addr)]; // 16
AddressFamily _AddressFamily;
public:
const int Port;
public:
static const int MinPort = 0;
static const int MaxPort = UINT16_MAX;
static const UInt32 NoneAddress = INADDR_NONE;
public:
inline IPEndPoint()
: IPEndPoint(NoneAddress, 0) {
}
inline IPEndPoint(UInt32 address, int port)
: _AddressFamily(AddressFamily::InterNetwork)
, Port(port) {
*(UInt32*)this->_AddressBytes = address;
}
IPEndPoint(const char* address, int port);
IPEndPoint(AddressFamily af, const void* address_bytes, int address_size, int port);
public:
inline bool IsNone() {
if (AddressFamily::InterNetwork != this->_AddressFamily) {
return false;
}
else {
UInt32 dw = this->GetAddress();
return dw == IPEndPoint::NoneAddress;
}
}
inline bool IsAny() {
if (AddressFamily::InterNetwork != this->_AddressFamily) {
return false;
}
else {
UInt32 dw = this->GetAddress();
return dw == 0;
}
}
inline std::string GetAddressBytes() const {
int datalen;
Byte* data = this->GetAddressBytes(datalen);
return std::string((char*)data, datalen);
}
inline Byte* GetAddressBytes(int& len) const {
if (this->_AddressFamily == AddressFamily::InterNetworkV6) {
len = sizeof(this->_AddressBytes);
return this->_AddressBytes;
}
else {
len = sizeof(UInt32);
return this->_AddressBytes;
}
}
inline UInt32 GetAddress() const {
return *(UInt32*)this->_AddressBytes;
}
inline AddressFamily GetAddressFamily() const {
return this->_AddressFamily;
}
inline bool Equals(const IPEndPoint& value) const {
IPEndPoint* right = (IPEndPoint*)&reinterpret_cast<const char&>(value);
if ((IPEndPoint*)this == (IPEndPoint*)right) {
return true;
}
if ((IPEndPoint*)this == (IPEndPoint*)NULL ||
(IPEndPoint*)right == (IPEndPoint*)NULL ||
this->Port != value.Port) {
return false;
}
return *this == value;
}
inline bool operator == (const IPEndPoint& right) const {
if (this->_AddressFamily != right._AddressFamily) {
return false;
}
Byte* x = this->_AddressBytes;
Byte* y = right._AddressBytes;
if (x == y) {
return true;
}
if (this->_AddressFamily == AddressFamily::InterNetworkV6) {
UInt64* qx = (UInt64*)x;
UInt64* qy = (UInt64*)y;
return qx[0] == qy[0] && qx[1] == qy[1];
}
return *(UInt32*)x == *(UInt32*)y;
}
inline bool operator != (const IPEndPoint& right) const {
bool b = (*this) == right;
return !b;
}
inline IPEndPoint& operator = (const IPEndPoint& right) {
this->_AddressFamily = right._AddressFamily;
const_cast<int&>(this->Port) = right.Port;
int address_bytes_size;
Byte* address_bytes = right.GetAddressBytes(address_bytes_size);
memcpy(this->_AddressBytes, address_bytes, address_bytes_size);
return *this;
}
inline std::string ToAddressString() noexcept {
int address_bytes_size;
Byte* address_bytes = GetAddressBytes(address_bytes_size);
return ToAddressString(this->_AddressFamily, address_bytes, address_bytes_size);
}
std::string ToString() noexcept;
public:
static std::string GetHostName() noexcept;
static std::string ToAddressString(AddressFamily af, const Byte* address_bytes, int address_size) noexcept;
inline static std::string ToAddressString(UInt32 address) noexcept {
return ToAddressString(AddressFamily::InterNetwork, (Byte*)&address, sizeof(address));
}
inline static std::string ToAddressString(AddressFamily af, const std::string& address_bytes) noexcept {
return ToAddressString(af, (Byte*)address_bytes.data(), address_bytes.size());
}
inline static UInt32 PrefixToNetmask(int prefix) {
UInt32 mask = prefix ? (~0 << (32 - prefix)) : 0;
return htonl(mask);
}
inline static int NetmaskToPrefix(UInt32 mask) {
unsigned char* bytes = (unsigned char*)&mask;
unsigned int bitLength = 0;
unsigned int idx = 0;
// find beginning 0xFF
for (; idx < sizeof(mask) && bytes[idx] == 0xff; idx++);
bitLength = 8 * idx;
if (idx < sizeof(mask)) {
switch (bytes[idx]) {
case 0xFE: bitLength += 7; break;
case 0xFC: bitLength += 6; break;
case 0xF8: bitLength += 5; break;
case 0xF0: bitLength += 4; break;
case 0xE0: bitLength += 3; break;
case 0xC0: bitLength += 2; break;
case 0x80: bitLength += 1; break;
case 0x00: break;
default: // invalid bitmask
return ~0;
}
// remainder must be 0x00
for (unsigned int j = idx + 1; j < sizeof(mask); j++) {
unsigned char x = bytes[j];
if (x != 0x00) {
return ~0;
}
}
}
return bitLength;
}
inline static bool IsInvalid(const IPEndPoint* p) {
IPEndPoint* __p = (IPEndPoint*)p;
if (NULL == __p) {
return true;
}
if (__p->IsNone()) {
return true;
}
if (__p->IsAny()) {
return true;
}
return false;
}
inline static bool IsInvalid(const IPEndPoint& value) {
return IPEndPoint::IsInvalid(std::addressof(value));
}
public:
template<class TProtocol>
inline static boost::asio::ip::basic_endpoint<TProtocol> ToEndPoint(const IPEndPoint& endpoint) {
AddressFamily af = endpoint.GetAddressFamily();
if (af == AddressFamily::InterNetwork) {
return WrapAddress<TProtocol>(endpoint.GetAddress(), endpoint.Port);
}
else {
int len;
const Byte* address = endpoint.GetAddressBytes(len);
return WrapAddressV6<TProtocol>(address, len, endpoint.Port);
}
}
template<class TProtocol>
inline static IPEndPoint ToEndPoint(const boost::asio::ip::basic_endpoint<TProtocol>& endpoint) {
boost::asio::ip::address address = endpoint.address();
if (address.is_v4()) {
return IPEndPoint(ntohl(address.to_v4().to_ulong()), endpoint.port());
}
else {
boost::asio::ip::address_v6::bytes_type bytes = address.to_v6().to_bytes();
return IPEndPoint(AddressFamily::InterNetworkV6, bytes.data(), bytes.size(), endpoint.port());
}
}
template<class TProtocol>
inline static boost::asio::ip::basic_endpoint<TProtocol> NewAddress(const char* address, int port) {
if (NULL == address || *address == '\x0') {
address = "0.0.0.0";
}
if (port < IPEndPoint::MinPort || port > IPEndPoint::MaxPort) {
port = IPEndPoint::MinPort;
}
boost::system::error_code ec;
boost::asio::ip::address ba = boost::asio::ip::address::from_string(address, ec);
if (ec) {
ba = boost::asio::ip::address_v4(IPEndPoint::NoneAddress);
}
boost::asio::ip::basic_endpoint<TProtocol> defaultEP(ba, port);
return defaultEP;
}
template<class TProtocol>
inline static boost::asio::ip::basic_endpoint<TProtocol> WrapAddress(UInt32 address, int port) {
typedef boost::asio::ip::basic_endpoint<TProtocol> protocol_endpoint;
return protocol_endpoint(boost::asio::ip::address_v4(ntohl(address)), port);
}
template<class TProtocol>
inline static boost::asio::ip::basic_endpoint<TProtocol> WrapAddressV6(const void* address, int size, int port) {
typedef boost::asio::ip::basic_endpoint<TProtocol> protocol_endpoint;
if (size < 0) {
size = 0;
}
boost::asio::ip::address_v6::bytes_type address_bytes;
unsigned char* p = &address_bytes[0];
memcpy(p, address, size);
memset(p, 0, address_bytes.size() - size);
return protocol_endpoint(boost::asio::ip::address_v6(address_bytes), port);
}
template<class TProtocol>
inline static boost::asio::ip::basic_endpoint<TProtocol> AnyAddress(int port) {
return NewAddress<TProtocol>("\x0", port);
}
template<class TProtocol>
inline static boost::asio::ip::basic_endpoint<TProtocol> LocalAddress(boost::asio::ip::basic_resolver<TProtocol>& resolver, int port) {
return GetAddressByHostName<TProtocol>(resolver, GetHostName(), port);
}
template<class TProtocol>
inline static boost::asio::ip::basic_endpoint<TProtocol> GetAddressByHostName(boost::asio::ip::basic_resolver<TProtocol>& resolver, const std::string& hostname, int port) {
typedef boost::asio::ip::basic_resolver<TProtocol> protocol_resolver;
typename protocol_resolver::query q(hostname.c_str(), std::to_string(port).c_str());
#ifndef _WIN32
typename protocol_resolver::iterator i = resolver.resolve(q);
typename protocol_resolver::iterator l;
if (i == l) {
return AnyAddress<TProtocol>(port);
}
#else
typename protocol_resolver::results_type results = resolver.resolve(q);
if (results.empty()) {
return AnyAddress<TProtocol>(port);
}
typename protocol_resolver::iterator i = results.begin();
typename protocol_resolver::iterator l = results.end();
#endif
for (; i != l; ++i) {
boost::asio::ip::basic_endpoint<TProtocol> localEP = *i;
if (!localEP.address().is_v4()) {
continue;
}
return localEP;
}
return AnyAddress<TProtocol>(port);
}
template<class TProtocol>
inline static bool Equals(const boost::asio::ip::basic_endpoint<TProtocol>& x, const boost::asio::ip::basic_endpoint<TProtocol>& y) {
if (x != y) {
return false;
}
if (x.address() != y.address()) {
return false;
}
return x.port() == y.port();
}
};
}
}
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#ifdef _WIN32
#include <WS2tcpip.h>
#else
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#endif
#include <string>
#include <boost/asio.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/ip/tcp.hpp>
#include "Ipep.h"
#include "IPEndPoint.h"
#define IP_END_POINT_USE_BOOST_INET_PTON
namespace vgw {
namespace packet {
IPEndPoint::IPEndPoint(const char* address, int port)
: _AddressFamily(AddressFamily::InterNetwork)
, Port(port) {
if (NULL == address || *address == '\x0') {
*(UInt32*)this->_AddressBytes = IPEndPoint::NoneAddress;
this->_AddressFamily = AddressFamily::InterNetwork;
}
else {
#ifndef IP_END_POINT_USE_BOOST_INET_PTON
struct sockaddr_in6 in6;
int err = inet_pton(AF_INET6, address, &in6);
if (err > 0) {
this->_AddressFamily = AddressFamily::InterNetworkV6;
memcpy(this->_AddressBytes, &in6.sin6_addr, sizeof(this->_AddressBytes));
}
else {
*(UInt32*)this->_AddressBytes = inet_addr(address);
this->_AddressFamily = AddressFamily::InterNetwork;
}
#else
boost::system::error_code ec;
boost::asio::ip::address host;
try {
host = boost::asio::ip::address::from_string(address, ec);
}
catch (std::exception&) {
ec = boost::asio::error::invalid_argument;
}
if (ec) {
this->_AddressFamily = AddressFamily::InterNetwork;
*(UInt32*)this->_AddressBytes = IPEndPoint::NoneAddress;
}
else if (host.is_v6()) {
this->_AddressFamily = AddressFamily::InterNetworkV6;
boost::asio::ip::address_v6::bytes_type buf = host.to_v6().to_bytes();
memcpy(this->_AddressBytes, buf.data(), buf.size());
}
else {
this->_AddressFamily = AddressFamily::InterNetwork;
boost::asio::ip::address_v4::bytes_type buf = host.to_v4().to_bytes();
memcpy(this->_AddressBytes, buf.data(), buf.size());
}
#endif
}
}
IPEndPoint::IPEndPoint(AddressFamily af, const void* address_bytes, int address_size, int port)
: _AddressFamily(af)
, Port(port) {
int limit_size = 0;
if (af == AddressFamily::InterNetworkV6) {
limit_size = sizeof(struct in6_addr);
}
else {
af = AddressFamily::InterNetwork;
limit_size = sizeof(struct in_addr);
}
memset(this->_AddressBytes, 0, limit_size);
if (NULL != address_bytes && address_size > 0) {
memcpy(this->_AddressBytes, address_bytes, std::min<int>(address_size, limit_size));
}
this->_AddressFamily = af;
}
std::string IPEndPoint::GetHostName() noexcept {
char sz[256]; // 域名规定不超过64字节(但是几乎大部分实现为64-1字节)
sz[0x00] = 0;
sz[0xff] = 0;
gethostname(sz, 0xff);
return sz[0] == 0x00 ? "localhost" : sz;
}
std::string IPEndPoint::ToString() noexcept {
return Ipep::ToIpepAddress(this);
}
std::string IPEndPoint::ToAddressString(AddressFamily af, const Byte* address_bytes, int address_size) noexcept {
if (NULL == address_bytes || address_size <= 0) {
return "0.0.0.0";
}
if (af == AddressFamily::InterNetworkV6) {
if (address_size < (int)sizeof(struct in6_addr)) {
return "0.0.0.0";
}
char sz[INET6_ADDRSTRLEN];
if (!inet_ntop(AF_INET6, (struct in6_addr*)address_bytes, sz, sizeof(sz))) {
return "0.0.0.0";
}
return sz;
}
else {
if (address_size < (int)sizeof(struct in_addr)) {
return "0.0.0.0";
}
char sz[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, (struct in_addr*)address_bytes, sz, sizeof(sz))) {
return "0.0.0.0";
}
return sz; // inet_ntoa(*(struct in_addr*)address);
}
}
}
}
#pragma once
#include "../env.h"
#include "IPEndPoint.h"
namespace vgw {
namespace packet {
class Ipep final {
public:
typedef std::function<void(std::vector<IPEndPoint>&)> GetAddressesByHostNameCallback;
typedef std::function<void(IPEndPoint*)> GetAddressByHostNameCallback;
public:
static IPEndPoint GetEndPoint(const std::string& address);
static IPEndPoint GetEndPoint(const std::string& host, int port);
inline static std::string ToIpepAddress(const IPEndPoint& ep) {
return ToIpepAddress(std::addressof(ep));
}
static std::string ToIpepAddress(const IPEndPoint* ep);
static bool SetDnsAddresses(const std::vector<std::string>& addresses);
static bool ToEndPoint(const std::string& addresses, std::vector<std::string>& out);
public:
template<class TProtocol>
inline static void GetAddressByHostName(const std::shared_ptr<boost::asio::ip::basic_resolver<TProtocol> >& resolver, const std::string& hostname, int port, const std::shared_ptr<GetAddressByHostNameCallback>& callback) {
if (NULL == resolver) {
throw std::runtime_error("Argument \"resolver\" is not allowed to be a NULL references.");
}
GetAddressByHostName(*resolver.get(), hostname, port, callback);
}
template<class TProtocol>
inline static void GetAddressByHostName(boost::asio::ip::basic_resolver<TProtocol>& resolver, const std::string& hostname, int port, const std::shared_ptr<GetAddressByHostNameCallback>& callback) {
if (NULL == callback) {
throw std::runtime_error("Argument \"callback\" is not allowed to be a NULL references.");
}
std::shared_ptr<GetAddressByHostNameCallback> callback_ = callback;
GetAddressesByHostName(resolver, hostname, port, make_shared_object<GetAddressesByHostNameCallback>(
[callback_](std::vector<IPEndPoint>& addresses) {
IPEndPoint* address = NULL;
if (NULL == address) {
for (size_t i = 0, l = addresses.size(); i < l; i++) {
const IPEndPoint& r = addresses[i];
if (r.GetAddressFamily() == AddressFamily::InterNetwork) {
address = (IPEndPoint*)&reinterpret_cast<const char&>(r);
break;
}
}
}
if (NULL == address) {
for (size_t i = 0, l = addresses.size(); i < l; i++) {
const IPEndPoint& r = addresses[i];
if (r.GetAddressFamily() == AddressFamily::InterNetworkV6) {
address = (IPEndPoint*)&reinterpret_cast<const char&>(r);
break;
}
}
}
(*callback_)(address);
}));
}
template<class TProtocol>
inline static void GetAddressesByHostName(const std::shared_ptr<boost::asio::ip::basic_resolver<TProtocol> >& resolver, const std::string& hostname, int port, const std::shared_ptr<GetAddressesByHostNameCallback>& callback) {
if (NULL == resolver) {
throw std::runtime_error("Argument \"resolver\" is not allowed to be a NULL references.");
}
GetAddressesByHostName(*resolver.get(), hostname, port, callback);
}
template<class TProtocol>
inline static void GetAddressesByHostName(boost::asio::ip::basic_resolver<TProtocol>& resolver, const std::string& hostname, int port, const std::shared_ptr<GetAddressesByHostNameCallback>& callback) {
typedef boost::asio::ip::basic_resolver<TProtocol> protocol_resolver;
if (NULL == callback) {
throw std::runtime_error("Argument \"callback\" is not allowed to be a NULL references.");
}
IPEndPoint localEP = IPEndPoint(hostname.data(), port);
if (!localEP.IsNone()) {
std::vector<IPEndPoint> addresses;
addresses.push_back(localEP);
(*callback)(addresses);
return;
}
std::shared_ptr<GetAddressesByHostNameCallback> callback_ = callback;
auto completion_resolve = [](
std::vector<IPEndPoint>& addresses,
typename protocol_resolver::iterator& i,
typename protocol_resolver::iterator& l,
const std::shared_ptr<GetAddressesByHostNameCallback>& callback) {
for (; i != l; ++i) {
boost::asio::ip::basic_endpoint<TProtocol> localEP = std::move(*i);
if (!localEP.address().is_v4()) {
continue;
}
addresses.push_back(IPEndPoint::ToEndPoint<TProtocol>(localEP));
}
};
typename protocol_resolver::query q(hostname.c_str(), std::to_string(port).c_str());
#ifndef _WIN32
resolver.async_resolve(q,
[completion_resolve, callback_](const boost::system::error_code& ec, typename protocol_resolver::iterator results) {
std::vector<IPEndPoint> addresses;
if (!ec) {
typename protocol_resolver::iterator i = std::move(results);
typename protocol_resolver::iterator l;
completion_resolve(addresses, i, l, callback_);
}
(*callback_)(addresses);
});
#else
resolver.async_resolve(q,
[completion_resolve, callback_](const boost::system::error_code& ec, typename protocol_resolver::results_type results) {
std::vector<IPEndPoint> addresses;
if (!ec) {
if (!results.empty()) {
typename protocol_resolver::iterator i = results.begin();
typename protocol_resolver::iterator l = results.end();
completion_resolve(addresses, i, l, callback_);
}
}
(*callback_)(addresses);
});
#endif
}
};
}
}
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#ifdef _WIN32
#include <WinSock2.h>
#else
#include <netdb.h>
#endif
#include "Ipep.h"
#include "IPEndPoint.h"
namespace vgw {
namespace packet {
IPEndPoint Ipep::GetEndPoint(const std::string& address) {
if (address.empty()) {
return Ipep::GetEndPoint(address, 0);
}
size_t index = address.rfind(':');
if (index != std::string::npos) {
std::string host = address.substr(0, index);
std::string port = address.substr(index + 1);
return Ipep::GetEndPoint(host, atoi(port.data()));
}
else {
return Ipep::GetEndPoint(address, 0);
}
}
std::string Ipep::ToIpepAddress(const IPEndPoint* ep) {
if (NULL == ep) {
return "0.0.0.0:0";
}
int address_bytes_size;
Byte* address_bytes = ep->GetAddressBytes(address_bytes_size);
std::string address_text = IPEndPoint::ToAddressString(ep->GetAddressFamily(), address_bytes, address_bytes_size);
char sz[0xff];
sprintf(sz, "%s:%u", address_text.data(), ep->Port);
return sz;
}
IPEndPoint Ipep::GetEndPoint(const std::string& host, int port) {
if (port < IPEndPoint::MinPort || port > IPEndPoint::MaxPort) {
port = IPEndPoint::MinPort;
}
IPEndPoint localEP = IPEndPoint(host.data(), port);
if (localEP.IsNone()) {
struct addrinfo req, *hints, *p;
memset(&req, 0, sizeof(req));
req.ai_family = AF_UNSPEC;
req.ai_socktype = SOCK_STREAM;
if (getaddrinfo(host.data(), NULL, &req, &hints)) {
return IPEndPoint(0u, port);
}
for (p = hints; NULL != p; p = p->ai_next) {
if (p->ai_family == AF_INET) {
struct sockaddr_in* ipv4 = (struct sockaddr_in*)p->ai_addr;
return IPEndPoint(AddressFamily::InterNetwork,
(Byte*)&(ipv4->sin_addr), sizeof(ipv4->sin_addr), port);
}
}
for (p = hints; NULL != p; p = p->ai_next) {
if (p->ai_family == AF_INET6) {
struct sockaddr_in6* ipv6 = (struct sockaddr_in6*)p->ai_addr;
return IPEndPoint(AddressFamily::InterNetworkV6,
(Byte*)&(ipv6->sin6_addr), sizeof(ipv6->sin6_addr), port);
}
}
}
return localEP;
}
}
}