IPV4网络帧协议分片/组包处理代码实现

152 篇文章 1 订阅
61 篇文章 3 订阅
#pragma once

#include "gw.h"
#include "ethernet.h"
#include "./packet/IPFrame.h"

namespace vgw {
    void ipv4_init();
    void ipv4_input(struct ip_hdr* ip, int len);
    bool ipv4_output(struct ip_hdr* ip, int len);
    bool ipv4_output_(const vgw::packet::IPFrame* packet);
}
#include "gw.h"
#include "ipv4.h"
#include "checksum.h"
#include "etharp.h"
#include "ethernet.h"
#include "udp.h"
#include "icmp.h"
#include "./io/MemoryStream.h"
#include "./packet/IPEndPoint.h"
#include "./packet/IPFrame.h"
#include "./packet/UdpFrame.h"
#include "./packet/IcmpFrame.h"

using vgw::io::MemoryStream;
using vgw::packet::IPEndPoint;
using vgw::packet::IPFrame;
using vgw::packet::IPFlags;
using vgw::packet::UdpFrame;
using vgw::packet::IcmpFrame;
using vgw::packet::BufferSegment;

namespace vgw {
    struct Subpackage {
    public:
        typedef std::shared_ptr<IPFrame>                            IPFramePtr;
        typedef std::shared_ptr<Subpackage>                         Ptr;

    public:
        inline Subpackage() : FinalizeTime(GetTickCount64() + Subpackage::MaxFinalizeTime) {}

    public:
        UInt64                                                      FinalizeTime;
        std::vector<IPFramePtr>                                     Frames;

    public:
        static const int                                            MaxFinalizeTime = 1000;
    };
    typedef std::unordered_map<std::string, Subpackage::Ptr>        SubpackageTable;

    extern uint32_t                                                 ETHERNET_IP;
    extern uint32_t                                                 ETHERNET_MASK;
    extern eth_addr                                                 ETHERNET_MAC;
    extern boost::asio::io_context                                  ETHERNET_CONTEXT_;
    static std::shared_ptr<boost::asio::deadline_timer>             ETHERNET_IPV4_TICKTMR_;

    std::atomic<unsigned short>                                     _ipaid = { (unsigned short)GetTickCount64() }; // ATOMIC_FLAG_INIT
    const int ip_hdr::IP_HLEN                                       = sizeof(struct ip_hdr);
    static SubpackageTable                                          _subpackages;

    inline static void                                              ipv4_input(const std::shared_ptr<IPFrame>& packet);
    inline static bool                                              ipv4_fragment(const std::shared_ptr<IPFrame>& packet);
    inline static bool                                              ipv4_update(uint64_t now);

    unsigned short ip_hdr::NewId() {
        unsigned short r = 0;
        do {
            r = ++_ipaid;
        } while (r == 0);
        return r;
    }

    struct ip_hdr* ip_hdr::Parse(const void* packet, int len) {
        struct ip_hdr* iphdr = (struct ip_hdr*)packet;
        if (NULL == iphdr) {
            return NULL;
        }

        int iphdr_ver = IPH_V(iphdr);
        if (iphdr_ver != ip_hdr::IP_VER) {
            return NULL;
        }

        int iphdr_hlen = IPH_HL(iphdr) << 2;
        if (iphdr_hlen >= len) {
            return NULL;
        }

        if (iphdr_hlen < IP_HLEN) {
            return NULL;
        }

        int ttl = IPH_TTL(iphdr);
        if (ttl <= 0) {
            return NULL;
        }

        if (len != __ntohs(iphdr->len)) {
            return NULL;
        }

        /* all ones (broadcast) or all zeroes (old skool broadcast) */
        if ((~iphdr->dest == IP_ADDR_ANY_VALUE) || (iphdr->dest == IP_ADDR_ANY_VALUE)) {
            return NULL;
        }

        if ((~iphdr->src == IP_ADDR_ANY_VALUE) || (iphdr->src == IP_ADDR_ANY_VALUE)) {
            return NULL;
        }

        // if ((IPH_OFFSET(iphdr) & __ntohs((UInt16)(ip_hdr::IP_OFFMASK | ip_hdr::IP_MF)))) {
        //     return NULL;
        // }

        #ifdef VGW_CHECKSUM
        if (iphdr->chksum != 0) {
            int cksum = inet_chksum(iphdr, iphdr_hlen);
            if (cksum != 0) {
                return NULL;
            }
        }
        #endif

        int ip_proto = IPH_PROTO(iphdr);
        if (ip_proto == IP_PROTO_UDP ||
            ip_proto == IP_PROTO_TCP ||
            ip_proto == IP_PROTO_ICMP) {
            return iphdr;
        }
        return NULL;
    }

    inline static void ipv4_loopback() {
        std::shared_ptr<boost::asio::deadline_timer> ticktmr_ = ETHERNET_IPV4_TICKTMR_;
        if (!ticktmr_) {
            ticktmr_ = make_shared_object<boost::asio::deadline_timer>(ETHERNET_CONTEXT_);
            ETHERNET_IPV4_TICKTMR_ = ticktmr_;
        }

        auto callbackf = [ticktmr_](const boost::system::error_code& ec) {
            if (!ec) {
                uint64_t now = GetTickCount64();
                ipv4_update(now);
                ipv4_loopback();
            }
        };
        ticktmr_->expires_from_now(boost::posix_time::seconds(1));
        ticktmr_->async_wait(callbackf);
    }

    void ipv4_init() {
        udp_init();
        ipv4_loopback();
    }

    bool ipv4_output(struct ip_hdr* ip, int len) {
        if (!ip || len < 1) {
            return false;
        }

        struct eth_addr dst;
        if (!etharp_get(ip->dest, dst)) {
            return false;
        }

        int sz = sizeof(struct eth_hdr) + len;
        struct eth_hdr* pkg = (struct eth_hdr*)malloc(sz);
        pkg->src = ETHERNET_MAC;
        pkg->dst = dst;
        pkg->proto = htons(ETHTYPE_IP);
        memcpy(pkg + 1, ip, len);

        int err = ethernet_output(pkg, sz);
        free(pkg);
        return err == 0;
    }

    bool ipv4_output_(const IPFrame* packet) {
        typedef IPFrame::IPFramePtr              IPFramePtr;
        typedef std::shared_ptr<BufferSegment>   Buffer;

        if (!packet) {
            return false;
        }

        while (0 == packet->Id) {
            const_cast<IPFrame*>(packet)->Id = IPFrame::NewId();
        }

        std::vector<IPFramePtr> subpackages;
        int subpacketl = IPFrame::Subpackages(subpackages,
            std::shared_ptr<IPFrame>(const_cast<IPFrame*>(packet), [](const IPFrame*) {}));
        if (subpacketl <= 0) {
            return false;
        }

        for (int i = 0; i < subpacketl; i++) {
            IPFramePtr frame_ = subpackages[i];
            if (NULL == frame_) {
                return false;
            }

            Buffer message_ = frame_->ToArray();
            if (NULL == message_ || message_->Length <= 0) {
                return false;
            }

            bool written = ipv4_output((struct ip_hdr*)message_->Buffer.get(), message_->Length);
            if (!written) {
                return false;
            }
        }
        return true;
    }

    void ipv4_input(struct ip_hdr* ip, int len) {
        int proto = ip_hdr::IPH_PROTO(ip);
        switch (proto) {
        case ip_hdr::IP_PROTO_UDP:
            break;
        case ip_hdr::IP_PROTO_ICMP:
            break;
        default:
            return;
        };
        std::shared_ptr<IPFrame> packet = IPFrame::Parse(ip, len, false);
        if (packet) {
            ipv4_input(packet);
        }
    }

    inline static void ipv4_input(const std::shared_ptr<IPFrame>& packet) {
        if (packet->ProtocolType == ip_hdr::IP_PROTO_UDP) {
            if (!ipv4_fragment(packet)) {
                std::shared_ptr<UdpFrame> frame = UdpFrame::Parse(packet.get());
                if (NULL != frame) {
                    udp_input(packet, frame);
                }
            }
        }
        else if (packet->ProtocolType == ip_hdr::IP_PROTO_ICMP) {
            if (!ipv4_fragment(packet)) {
                std::shared_ptr<IcmpFrame> frame = IcmpFrame::Parse(packet.get());
                if (NULL != frame) {
                    icmp_input(packet, frame);
                }
            }
        }
    }

    inline static bool ipv4_fragment(const std::shared_ptr<IPFrame>& packet) {
        if ((packet->Flags & IPFlags::IP_MF) != 0 ||
            ((packet->Flags & IPFlags::IP_OFFMASK) != 0 && packet->GetFragmentOffset() > 0)) {
            std::shared_ptr<BufferSegment> payload = packet->Payload;
            if (NULL == payload || payload->Length <= 0) {
                return false;
            }
            Subpackage::IPFramePtr originNew;
            std::string key;
            {
                char sz[255];
                snprintf(sz, sizeof(sz), "%u->%u/%u", packet->Source, packet->Destination, packet->Id);
                key = sz;
            }
            do {
                std::shared_ptr<Subpackage> subpackage;
                {
                    SubpackageTable::iterator tail = _subpackages.find(key);
                    SubpackageTable::iterator endl = _subpackages.end();
                    if (tail != endl) {
                        subpackage = tail->second;
                    }
                    else {
                        subpackage = make_shared_object<Subpackage>();
                        _subpackages.insert(SubpackageTable::value_type(key, subpackage));
                    }
                }
                std::vector<Subpackage::IPFramePtr>& frames = subpackage->Frames;
                size_t index = frames.size();
                if (index <= 0) {
                    frames.push_back(packet);
                }
                else {
                    while (index > 0) {
                        Subpackage::IPFramePtr left = frames[index - 1];
                        if (packet->GetFragmentOffset() >= left->GetFragmentOffset()) {
                            break;
                        }
                        else {
                            index--;
                        }
                    }
                    frames.insert(frames.begin() + index, packet);
                }
                int nextFragementOffset = 0;
                bool fullFragementOffset = true;
                {
                    size_t count = frames.size();
                    for (index = 0; index < count; index++) {
                        Subpackage::IPFramePtr left = frames[index];
                        if (left->GetFragmentOffset() != nextFragementOffset) {
                            fullFragementOffset = false;
                            break;
                        }
                        nextFragementOffset = left->GetFragmentOffset() + left->Payload->Length;
                    }
                    if (fullFragementOffset) {
                        Subpackage::IPFramePtr left = frames[frames.size() - 1];
                        if ((packet->Flags & IPFlags::IP_MF) == 0 &&
                            (packet->Flags & IPFlags::IP_OFFMASK) != 0 && left->GetFragmentOffset() > 0) {
                            left = frames[0];
                            {
                                SubpackageTable::iterator tail = _subpackages.find(key);
                                SubpackageTable::iterator endl = _subpackages.end();
                                if (tail != endl) {
                                    _subpackages.erase(tail);
                                }
                            }
                            std::shared_ptr<Byte> buffer = make_shared_alloc<Byte>(nextFragementOffset);
                            MemoryStream ms(buffer, nextFragementOffset);
                            {
                                for (index = 0, count = frames.size(); index < count; index++) {
                                    std::shared_ptr<BufferSegment> payload = frames[index]->Payload;
                                    ms.Write(payload->Buffer.get(), 0, payload->Length);
                                }
                            }
                            originNew = make_shared_object<IPFrame>();
                            originNew->AddressesFamily = left->AddressesFamily;
                            originNew->ProtocolType = left->ProtocolType;
                            originNew->Source = left->Source;
                            originNew->Destination = left->Destination;
                            originNew->Payload = make_shared_object<BufferSegment>(buffer, nextFragementOffset);
                            originNew->Id = left->Id;
                            originNew->Options = left->Options;
                            originNew->Tos = left->Tos;
                            originNew->Ttl = left->Ttl;
                            originNew->Flags = IPFlags::IP_DF;
                            originNew->SetFragmentOffset(0);
                        }
                    }
                }
            } while (0);
            if (NULL != originNew) {
                ipv4_input(originNew);
            }
            return true;
        }
        else {
            return false;
        }
    }

    inline static bool ipv4_update(uint64_t now) {
        std::vector<std::string> releases;
        SubpackageTable::iterator endl = _subpackages.end();
        SubpackageTable::iterator tail = _subpackages.begin();
        for (; tail != endl; ++tail) {
            const Subpackage::Ptr& subpackage = tail->second;
            if (now >= subpackage->FinalizeTime || // 滴答时间是否发生数值溢出的现象?
                (subpackage->FinalizeTime > Subpackage::MaxFinalizeTime && now <= Subpackage::MaxFinalizeTime)) {
                releases.push_back(tail->first);
            }
        }
        for (size_t i = 0, l = releases.size(); i < l; i++) {
            const std::string& key = releases[i];
            SubpackageTable::iterator tail = _subpackages.find(key);
            if (tail != endl) {
                _subpackages.erase(tail);
            }
        }
        return true;
    }
}
#pragma once

#include <stdint.h>

namespace vgw {
    /** Internet protocol v4 */
    static const uint16_t ETHTYPE_IP = 0x0800U;
    /** Address resolution protocol */
    static const uint16_t ETHTYPE_ARP = 0x0806U;
    /** Wake on lan */
    static const uint16_t ETHTYPE_WOL = 0x0842U;
    /** RARP */
    static const uint16_t ETHTYPE_RARP = 0x8035U;
    /** Virtual local area network */
    static const uint16_t ETHTYPE_VLAN = 0x8100U;
    /** Internet protocol v6 */
    static const uint16_t ETHTYPE_IPV6 = 0x86DDU;
    /** PPP Over Ethernet Discovery Stage */
    static const uint16_t ETHTYPE_PPPOEDISC = 0x8863U;
    /** PPP Over Ethernet Session Stage */
    static const uint16_t ETHTYPE_PPPOE = 0x8864U;
    /** Jumbo Frames */
    static const uint16_t ETHTYPE_JUMBO = 0x8870U;
    /** Process field network */
    static const uint16_t ETHTYPE_PROFINET = 0x8892U;
    /** Ethernet for control automation technology */
    static const uint16_t ETHTYPE_ETHERCAT = 0x88A4U;
    /** Link layer discovery protocol */
    static const uint16_t ETHTYPE_LLDP = 0x88CCU;
    /** Serial real-time communication system */
    static const uint16_t ETHTYPE_SERCOS = 0x88CDU;
    /** Media redundancy protocol */
    static const uint16_t ETHTYPE_MRP = 0x88E3U;
    /** Precision time protocol */
    static const uint16_t ETHTYPE_PTP = 0x88F7U;
    /** Q-in-Q, 802.1ad */
    static const uint16_t ETHTYPE_QINQ = 0x9100U;
    /** Ethernet */
    static const uint16_t ETHARP_IANA_HWTYPE_ETHERNET = 1;

    static const uint16_t ARP_REQUEST = 1;
    static const uint16_t ARP_REPLY = 2;

    #ifndef ETH_HWADDR_LEN
    #ifdef ETHARP_HWADDR_LEN
    #define ETH_HWADDR_LEN    ETHARP_HWADDR_LEN /* compatibility mode */
    #else
    #define ETH_HWADDR_LEN    6
    #endif
    #endif

    #pragma pack(push, 1)
    struct eth_addr {
        union {
            uint8_t                             s_data[ETH_HWADDR_LEN];
            struct {
                uint32_t                        dw;
                uint16_t                        w;
            } s_zero;
        };
    };

    struct eth_hdr {
        struct eth_addr                     dst;
        struct eth_addr                     src;
        uint16_t                            proto;
    };

    /** the ARP message, see RFC 826 ("Packet format") */
    struct etharp_hdr {
        uint16_t                            hwtype;
        uint16_t                            proto;
        uint8_t                             hwlen;
        uint8_t                             protolen;
        uint16_t                            opcode;
        struct eth_addr                     shwaddr;
        uint32_t                            sipaddr;
        struct eth_addr                     dhwaddr;
        uint32_t                            dipaddr;
    };

    struct ip_hdr {
    public:
        enum Flags {
            IP_RF = 0x8000,            /* reserved fragment flag */
            IP_DF = 0x4000,            /* dont fragment flag */
            IP_MF = 0x2000,            /* more fragments flag */
            IP_OFFMASK = 0x1fff,       /* mask for fragmenting bits */
        };

    public:
        /* version / header length / type of service */
        unsigned char                                                v_hl;
        /* type of service */
        unsigned char                                                tos;
        /* total length */
        unsigned short                                               len;
        /* identification */
        unsigned short                                               id;
        /* fragment offset field */
        unsigned short                                               flags;
        /* time to live */
        unsigned char                                                ttl;
        /* protocol */
        unsigned char                                                proto;
        /* checksum */
        unsigned short                                               chksum;
        /* source and destination IP addresses */
        unsigned int                                                 src;
        unsigned int                                                 dest;

    public:
        inline static int                                            IPH_V(struct ip_hdr* hdr) {
            return ((hdr)->v_hl >> 4);
        }
        inline static int                                            IPH_HL(struct ip_hdr* hdr) {
            return ((hdr)->v_hl & 0x0f);
        }
        inline static int                                            IPH_PROTO(struct ip_hdr* hdr) {
            return ((hdr)->proto & 0xff);
        }
        inline static int                                            IPH_OFFSET(struct ip_hdr* hdr) {
            return (hdr)->flags;
        }
        inline static int                                            IPH_TTL(struct ip_hdr* hdr) {
            return ((hdr)->ttl & 0xff);
        }

    public:
        static struct ip_hdr*                                        Parse(const void* packet, int size);
        static unsigned short                                        NewId();

    public:
        static const int                                             MTU = 1500;
        static const int                                             IP_HLEN;
        static const unsigned char                                   IP_VER = 4;
        static const unsigned int                                    IP_ADDR_ANY_VALUE = 0x00000000;
        static const unsigned int                                    IP_ADDR_BROADCAST_VALUE = 0xffffffff;
        static const int                                             TOS_ROUTIN_MODE = 0;
        static const unsigned char                                   IP_DFT_TTL = 64;
        static const unsigned char                                   IP_PROTO_IP = 0;
        static const unsigned char                                   IP_PROTO_ICMP = 1;
        static const unsigned char                                   IP_PROTO_UDP = 17;
        static const unsigned char                                   IP_PROTO_TCP = 6;
    };
    #pragma pack(pop)
}
#pragma once

#include "../env.h"
#include "../gw.h"
#include "IPEndPoint.h"

namespace vgw {
    namespace packet {
        typedef ip_hdr::Flags                                       IPFlags;

        class BufferSegment final {
        public:
            std::shared_ptr<Byte>                                   Buffer;
            int                                                     Length;

        public:
            inline BufferSegment() : Length(0) {}
            inline BufferSegment(const std::shared_ptr<Byte>& buffer, int length)
                : Buffer(buffer)
                , Length(buffer ? std::max<int>(0, length) : 0) {

            }
        };

        class IPFrame final {
        public:
            typedef std::shared_ptr<IPFrame>                        IPFramePtr;

        public:
            AddressFamily                                           AddressesFamily;
            UInt32                                                  Destination;
            UInt32                                                  Source;
            Byte                                                    Ttl;
            UInt16                                                  Id;
            Byte                                                    Tos;
            Byte                                                    ProtocolType;
            IPFlags                                                 Flags;
            std::shared_ptr<BufferSegment>                          Payload;
            std::shared_ptr<BufferSegment>                          Options;

        public:
            inline IPFrame()
                : AddressesFamily(AddressFamily::InterNetwork)
                , Destination(0)
                , Source(IPFrame::DefaultTtl)
                , Ttl(64)
                , Id(0)
                , Tos(0)
                , ProtocolType(0)
                , Flags(IPFlags::IP_DF) {

            }
            inline int                                              GetFragmentOffset() {
                int offset = (UInt16)this->Flags;
                offset = ((UInt16)(offset << 3)) >> 3;
                offset <<= 3;
                return offset;
            }
            inline void                                             SetFragmentOffset(int value) {
                int flags = (int)this->Flags >> 13;
                flags = flags << 13 | value >> 3;
                this->Flags = (IPFlags)flags;
            }

        public:
            inline static std::shared_ptr<BufferSegment>            ToArray(const IPFrame* packet) {
                if (NULL == packet) {
                    return NULL;
                }
                return const_cast<IPFrame*>(packet)->ToArray();
            }
            inline static UInt16                                    NewId() {
                return ip_hdr::NewId();
            }
            inline static int                                       SizeOf(const IPFrame* packet) {
                if (NULL == packet) {
                    return ~0;
                }
                return const_cast<IPFrame*>(packet)->SizeOf();
            }
            std::shared_ptr<BufferSegment>                          ToArray();
            int                                                     SizeOf();
            inline static std::shared_ptr<IPFrame>                  Parse(const void* packet, int size) {
                return IPFrame::Parse(packet, size, true);
            }
            static std::shared_ptr<IPFrame>                         Parse(const void* packet, int size, bool checksum);
            static int                                              Subpackages(std::vector<IPFramePtr>& out, const IPFramePtr& packet);

        public:
            static const Byte                                       DefaultTtl = ip_hdr::IP_DFT_TTL;
        };
    }
}
#include "../gw.h"
#include "../checksum.h"
#include "IPFrame.h"

namespace vgw {
    namespace packet {
        int IPFrame::SizeOf() {
            std::shared_ptr<BufferSegment> payload_segment = this->Payload;
            std::shared_ptr<BufferSegment> options_segment = this->Options;
            int options_size = 0;
            if (NULL != options_segment) {
                options_size = options_segment->Length;
            }

            int payload_offset = sizeof(struct ip_hdr) + options_size;
            int payload_size = 0;
            if (NULL != payload_segment) {
                payload_size = payload_segment->Length;
            }

            int message_data_size = payload_offset + payload_size;
            return message_data_size;
        }

        std::shared_ptr<BufferSegment> IPFrame::ToArray() {
            std::shared_ptr<BufferSegment> payload_segment = this->Payload;
            std::shared_ptr<BufferSegment> options_segment = this->Options;
            int options_size = 0;
            if (NULL != options_segment) {
                options_size = options_segment->Length;
            }

            int payload_offset = sizeof(struct ip_hdr) + options_size;
            int payload_size = 0;
            if (NULL != payload_segment) {
                payload_size = payload_segment->Length;
            }

            int message_data_size = payload_offset + payload_size;
            std::shared_ptr<Byte> message_data = make_shared_alloc<Byte>(message_data_size);

            struct ip_hdr* iphdr = (struct ip_hdr*)message_data.get();
            iphdr->dest = this->Destination;
            iphdr->src = this->Source;
            iphdr->ttl = this->Ttl;
            iphdr->proto = this->ProtocolType;
            iphdr->v_hl = 4 << 4 | payload_offset >> 2;
            iphdr->tos = this->Tos; // Routine Mode
            iphdr->len = __htons(message_data_size);
            iphdr->id = __htons(this->Id);
            iphdr->flags = __htons((UInt16)(this->Flags == 0 ? IPFlags::IP_DF : this->Flags));
            iphdr->chksum = 0;

            if (options_size > 0) {
                Byte* destination_options = message_data.get() + sizeof(struct ip_hdr);
                memcpy(destination_options, options_segment->Buffer.get(), options_size);
            }

            if (payload_size > 0) {
                memcpy(message_data.get() + payload_offset, payload_segment->Buffer.get(), payload_size);
            }

            iphdr->chksum = inet_chksum(message_data.get(), payload_offset);
            if (iphdr->chksum == 0) {
                iphdr->chksum = 0xffff;
            }

            return make_shared_object<BufferSegment>(message_data, message_data_size);
        }

        std::shared_ptr<IPFrame> IPFrame::Parse(const void* packet, int size, bool checksum) {
            struct ip_hdr* iphdr = checksum ? ip_hdr::Parse(packet, size) : (struct ip_hdr*)packet;
            if (NULL == iphdr) {
                return NULL;
            }

            std::shared_ptr<IPFrame> frame = make_shared_object<IPFrame>();
            frame->Destination = iphdr->dest;
            frame->Source = iphdr->src;
            frame->Tos = iphdr->tos;
            frame->Ttl = iphdr->ttl;
            frame->AddressesFamily = AddressFamily::InterNetwork;
            frame->ProtocolType = iphdr->proto;
            frame->Id = ntohl(iphdr->id);
            frame->Flags = (IPFlags)ntohs(iphdr->flags);

            int iphdr_hlen = ip_hdr::IPH_HL(iphdr) << 2;
            int options_size = (iphdr_hlen - sizeof(struct ip_hdr));
            if (options_size > 0) {
                std::shared_ptr<BufferSegment> options_ = make_shared_object<BufferSegment>();
                options_->Length = options_size;
                options_->Buffer = make_shared_alloc<Byte>(options_size);

                frame->Options = options_;
                memcpy(options_->Buffer.get(), (char*)iphdr + sizeof(struct ip_hdr), options_size);
            }

            int message_size_ = size - iphdr_hlen;
            if (message_size_ > 0) {
                std::shared_ptr<BufferSegment> messages_ = make_shared_object<BufferSegment>();
                messages_->Buffer = make_shared_alloc<Byte>(message_size_);
                messages_->Length = message_size_;

                frame->Payload = messages_;
                memcpy(messages_->Buffer.get(), (char*)iphdr + iphdr_hlen, message_size_);
            }
            return frame;
        }

        int IPFrame::Subpackages(std::vector<IPFramePtr>& out, const IPFramePtr& packet) {
            if (NULL == packet) {
                return 0;
            }

            if (packet->Flags & IPFlags::IP_MF) {
                out.push_back(packet);
                return 1;
            }

            std::shared_ptr<BufferSegment> messages = packet->Payload;
            std::shared_ptr<BufferSegment> options = packet->Options;
            if (NULL == messages) {
                out.push_back(packet);
                return 1;
            }

            int max = ip_hdr::MTU - sizeof(struct ip_hdr);
            if (NULL != options) {
                max -= options->Length;
            }

            int szz = messages->Length;
            max = (max >> 3) << 3;
            if (szz <= max) {
                out.push_back(packet);
                return 1;
            }

            std::shared_ptr<Byte> buffer = messages->Buffer;

            int ofs = 0;
            int fragmentl = 0;
            std::shared_ptr<IPFrame> fragment;
            while (szz > max) {
                fragment = make_shared_object<IPFrame>();
                fragment->ProtocolType = packet->ProtocolType;
                fragment->Source = packet->Source;
                fragment->Destination = packet->Destination;
                fragment->Flags = IPFlags::IP_MF;
                fragment->Id = packet->Id;
                fragment->Options = options;
                fragment->Ttl = packet->Ttl;
                fragment->Tos = packet->Tos;
                fragment->Payload = make_shared_object<BufferSegment>(
                    std::shared_ptr<Byte>(buffer.get() + ofs, [buffer](const Byte*) {}), max);
                fragment->SetFragmentOffset(ofs);

                options = NULL;
                ofs += max;
                szz -= max;
                fragmentl++;
                out.push_back(fragment);
            }
            if (szz > 0) {
                fragment = make_shared_object<IPFrame>();
                fragment->ProtocolType = packet->ProtocolType;
                fragment->Source = packet->Source;
                fragment->Destination = packet->Destination;
                fragment->Flags = ofs <= 0 ? packet->Flags : (IPFlags)0;
                fragment->Id = packet->Id;
                fragment->Options = options;
                fragment->Ttl = packet->Ttl;
                fragment->Tos = packet->Tos;
                fragment->Payload = make_shared_object<BufferSegment>(
                    std::shared_ptr<Byte>(buffer.get() + ofs, [buffer](const Byte*) {}), szz);
                fragment->SetFragmentOffset(ofs);
                out.push_back(fragment);
            }
            return ++fragmentl;
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值