关于C/C++语言上面对于IP地址转换及包装方面的。
IPEndPoint.h
#pragma once
#include <Server/Environment.h>
#include <boost/asio/ip/basic_endpoint.hpp>
namespace Server {
namespace Net {
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 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;
}
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();
}
};
}
}
IPEndPoint.cpp
#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 Server {
namespace Net {
IPEndPoint::IPEndPoint(const char* address, int port)
: _AddressFamily(AddressFamily::InterNetwork)
, Port(port) {
if (NULL == address || *address == '\x0') {
*(UInt32*)this->_AddressBytes = 0;
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(address_size, limit_size));
}
this->_AddressFamily = af;
}
std::string IPEndPoint::GetHostName() noexcept {
char szz[256]; // 域名规定不超过64字节(但是几乎大部分实现为64-1字节)
int err = gethostname(szz, 0xff);
if (err <= 0) {
return "localhost";
}
return szz;
}
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);
}
}
}
}