#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;
}
}
}