C/C++ implement IPEndPoint

关于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);
            }
        }
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值