C/CXX vgw IPEndPoint code-implement

159 篇文章 1 订阅
66 篇文章 3 订阅
#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;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值