libflute
Classes | Public Member Functions | List of all members
LibFlute::File Class Reference

Represents a file being transmitted or received. More...

#include <File.h>

Public Member Functions

 File (LibFlute::FileDeliveryTable::FileEntry entry)
 Create a file from an FDT entry (used for reception) More...
 
 File (const std::shared_ptr< Transmitter::FileDescription > &file_description)
 Create a file from a Transmitter::FileDescription (used for transmission) More...
 
 File (uint32_t toi, FecOti fec_oti, std::string content_location, std::string content_type, uint64_t expires, char *data, size_t length, bool copy_data=false)
 Create a file from the given parameters (used for transmission) More...
 
virtual ~File ()
 Default destructor. More...
 
void put_symbol (const EncodingSymbol &symbol)
 Write the data from an encoding symbol into the appropriate place in the buffer. More...
 
bool complete () const
 Check if the file is complete. More...
 
char * buffer () const
 Get the data buffer. More...
 
size_t length () const
 Get the data buffer length. More...
 
void encode ()
 Encode the buffer using the Content-Encoding. More...
 
void decode ()
 Decode the buffer using the Content-Encoding. More...
 
bool is_encoded () const
 Check if the buffer is content encoded. More...
 
const FecOtifec_oti () const
 Get the FEC OTI values. More...
 
const LibFlute::FileDeliveryTable::FileEntrymeta () const
 Get the file metadata from its FDT entry. More...
 
unsigned long received_at () const
 Timestamp of file reception. More...
 
void log_access ()
 Log access to the file by incrementing a counter. More...
 
unsigned access_count () const
 Get the access counter value. More...
 
std::vector< EncodingSymbolget_next_symbols (size_t max_size)
 Get the next encoding symbols that fit in max_size bytes. More...
 
void mark_completed (const std::vector< EncodingSymbol > &symbols, bool success)
 Mark encoding symbols as completed. More...
 
void set_fdt_instance_id (uint16_t id)
 Set the FDT instance ID. More...
 
uint16_t fdt_instance_id ()
 Get the FDT instance ID. More...
 

Detailed Description

Represents a file being transmitted or received.

Definition at line 30 of file File.h.

Constructor & Destructor Documentation

◆ File() [1/3]

LibFlute::File::File ( LibFlute::FileDeliveryTable::FileEntry  entry)

Create a file from an FDT entry (used for reception)

Parameters
entryFDT entry

Definition at line 36 of file File.cpp.

37  : _meta( std::move(entry) )
38  , _received_at( time(nullptr) )
39  , _file_description()
40 {
41  spdlog::debug("Creating File from FileEntry");
42  // Allocate a data buffer
43  spdlog::debug("Allocating buffer");
44  _buffer = (char*)malloc(_meta.fec_oti.transfer_length);
45  if (_buffer == nullptr)
46  {
47  throw "Failed to allocate file buffer";
48  }
49  _own_buffer = true;
50 
51  this->calculate_partitioning();
52  this->create_blocks();
53 }
uint64_t transfer_length
Definition: flute_types.h:54

◆ File() [2/3]

LibFlute::File::File ( const std::shared_ptr< Transmitter::FileDescription > &  file_description)

Create a file from a Transmitter::FileDescription (used for transmission)

Parameters
file_descriptionTransmitter File Description

Definition at line 55 of file File.cpp.

56  : _meta()
57  , _file_description(file_description)
58 {
59  spdlog::debug("Creating File from FileDescription");
60 
61  auto length = _file_description->data_length();
62  _buffer = (char*)malloc(length);
63  if (_buffer == nullptr)
64  {
65  throw "No data allocated";
66  }
67  _own_buffer = true;
68  memcpy(_buffer, _file_description->data(), length);
69  _meta = _file_description->file_entry();
70 
71  // for no-code
74  } else {
75  throw "Unsupported FEC scheme";
76  }
77 
78  encode();
79 
80  calculate_partitioning();
81  create_blocks();
82 }
size_t length() const
Get the data buffer length.
Definition: File.h:90
void encode()
Encode the buffer using the Content-Encoding.
Definition: File.cpp:274
FecScheme encoding_id
Definition: flute_types.h:52

◆ File() [3/3]

LibFlute::File::File ( uint32_t  toi,
FecOti  fec_oti,
std::string  content_location,
std::string  content_type,
uint64_t  expires,
char *  data,
size_t  length,
bool  copy_data = false 
)

Create a file from the given parameters (used for transmission)

Parameters
toiTOI of the file
content_locationContent location URI to use
content_typeMIME type
expiresExpiry value (in seconds since the NTP epoch)
dataPointer to the data buffer
lengthLength of the buffer
copy_dataCopy the buffer. If false (the default), the caller must ensure the buffer remains valid while the file is being transmitted.

Definition at line 84 of file File.cpp.

92  : _own_buffer(false)
93  , _meta()
94  , _file_description()
95 {
96  spdlog::debug("Creating File from data");
97  if (copy_data) {
98  spdlog::debug("Allocating buffer");
99  _buffer = (char*)malloc(length);
100  if (_buffer == nullptr)
101  {
102  throw "Failed to allocate file buffer";
103  }
104  memcpy(_buffer, data, length);
105  _own_buffer = true;
106  } else {
107  _buffer = data;
108  }
109 
110  unsigned char md5[MD5_DIGEST_LENGTH];
111  MD5((const unsigned char*)data, length, md5);
112 
113  _meta.toi = toi;
114  _meta.content_location = std::move(content_location);
115  _meta.content_type = std::move(content_type);
116  _meta.content_length = length;
117  _meta.content_md5 = base64_encode(md5, MD5_DIGEST_LENGTH);
118  _meta.expires = expires;
119  _meta.fec_oti = fec_oti;
120 
121  // for no-code
124  } else {
125  throw "Unsupported FEC scheme";
126  }
127 
128  this->calculate_partitioning();
129  this->create_blocks();
130 }
const FecOti & fec_oti() const
Get the FEC OTI values.
Definition: File.h:112

◆ ~File()

LibFlute::File::~File ( )
virtual

Default destructor.

Definition at line 132 of file File.cpp.

133 {
134  spdlog::debug("Destroying File");
135  if (_own_buffer && _buffer != nullptr)
136  {
137  spdlog::debug("Freeing buffer");
138  free(_buffer);
139  }
140 }

Member Function Documentation

◆ access_count()

unsigned LibFlute::File::access_count ( ) const
inline

Get the access counter value.

Definition at line 132 of file File.h.

132 { return _access_count; };

◆ buffer()

char* LibFlute::File::buffer ( ) const
inline

Get the data buffer.

Definition at line 85 of file File.h.

85 { return _buffer; };

◆ complete()

bool LibFlute::File::complete ( ) const
inline

Check if the file is complete.

Definition at line 80 of file File.h.

80 { return _complete; };

◆ decode()

auto LibFlute::File::decode ( )

Decode the buffer using the Content-Encoding.

Will check the MD5 sum after decoding, if present.

Definition at line 329 of file File.cpp.

330 {
331  if (!_been_decoded && !_meta.content_encoding.empty()) {
332  if (_meta.content_encoding == "gzip" || _meta.content_encoding=="deflate") {
333  auto comp_buffer = _buffer;
334  bool own_comp = _own_buffer;
335  std::shared_ptr<unsigned char> decomp_buffer(new unsigned char[16384]);
336  z_stream zs = {
337  .next_in = reinterpret_cast<unsigned char*>(comp_buffer),
338  .avail_in = static_cast<uint32_t>(_meta.fec_oti.transfer_length),
339  .next_out = decomp_buffer.get(),
340  .avail_out = 16384
341  };
342  spdlog::debug("Decompressing contents with {}", _meta.content_encoding);
343 
344  inflateInit2(&zs, 15 | ((_meta.content_encoding == "gzip")?16:0));
345  _buffer = nullptr;
346  auto zstate = inflate(&zs, Z_FINISH);
347  size_t last_out = 0;
348  while (zstate == Z_OK) {
349  spdlog::debug("Part decompressed: {} bytes", 16384-zs.avail_out);
350  _buffer = reinterpret_cast<char*>(realloc(_buffer, zs.total_out));
351  memcpy(_buffer+last_out, decomp_buffer.get(), 16384-zs.avail_out);
352  last_out = zs.total_out;
353  _own_buffer = true;
354  zs.avail_out = 16384;
355  zs.next_out = decomp_buffer.get();
356  zstate = inflate(&zs, Z_FINISH);
357  }
358  if (zstate==Z_STREAM_END) {
359  if (last_out != zs.total_out) {
360  spdlog::debug("Finish decompress, last block is {} bytes. Total {} bytes", 16384-zs.avail_out, zs.total_out);
361  _buffer = reinterpret_cast<char*>(realloc(_buffer, zs.total_out));
362  memcpy(_buffer+last_out, decomp_buffer.get(), 16384-zs.avail_out);
363  _own_buffer = true;
364  }
365  if (!_meta.content_length) {
366  _meta.content_length = zs.total_out;
367  } else if (_meta.content_length != zs.total_out) {
368  spdlog::error("Decompressed length does not match expected Content-Length ({} != {})", _meta.content_length, zs.total_out);
369  }
370  } else {
371  spdlog::error("Error decompressing file {}: {}", _meta.toi, zs.msg);
372  throw zs.msg;
373  }
374 
375  if (own_comp) free(comp_buffer);
376  } else {
377  spdlog::error("Unknown Content-Encoding {}", _meta.content_encoding);
378  throw "Content-Encoding not known";
379  }
380 
381  _been_decoded = true;
382  _been_encoded = false;
383 
384  // Check MD5
385  if (!_meta.content_md5.empty()) {
386  unsigned char md5[MD5_DIGEST_LENGTH];
387  MD5((const unsigned char*)buffer(), length(), md5);
388 
389  auto content_md5 = base64_decode(_meta.content_md5);
390  if (memcmp(md5, content_md5.c_str(), MD5_DIGEST_LENGTH) != 0) {
391  spdlog::debug("MD5 mismatch for TOI {}, discarding", _meta.toi);
392 
393  // MD5 mismatch, try again
394  for (auto& block : _source_blocks) {
395  for (auto& symbol : block.second.symbols) {
396  symbol.second.complete = false;
397  }
398  block.second.complete = false;
399  }
400  _complete = false;
401  }
402  }
403  }
404 }
char * buffer() const
Get the data buffer.
Definition: File.h:85

◆ encode()

auto LibFlute::File::encode ( )

Encode the buffer using the Content-Encoding.

Definition at line 274 of file File.cpp.

275 {
276  if (!_been_encoded && !_meta.content_encoding.empty()) {
277  if (_meta.content_encoding == "gzip" || _meta.content_encoding=="deflate") {
278  auto decomp_buffer = _buffer;
279  bool own_decomp = _own_buffer;
280  std::shared_ptr<unsigned char> comp_buffer(new unsigned char[16384]);
281  z_stream zs = {
282  .next_in = reinterpret_cast<unsigned char*>(decomp_buffer),
283  .avail_in = static_cast<uint32_t>(_meta.content_length),
284  .next_out = comp_buffer.get(),
285  .avail_out = 16384
286  };
287  spdlog::debug("Compressing contents with {}", _meta.content_encoding);
288 
289  if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY) == Z_OK) {
290  _buffer = nullptr;
291  auto zstate = deflate(&zs, Z_FINISH);
292  size_t last_out = 0;
293  while (zstate == Z_OK) {
294  spdlog::debug("Part compressed: {} bytes", 16384-zs.avail_out);
295  _buffer = reinterpret_cast<char*>(realloc(_buffer, zs.total_out));
296  memcpy(_buffer+last_out, comp_buffer.get(), 16384-zs.avail_out);
297  last_out = zs.total_out;
298  _own_buffer = true;
299  zs.avail_out = 16384;
300  zs.next_out = comp_buffer.get();
301  zstate = inflate(&zs, Z_FINISH);
302  }
303  if (zstate==Z_STREAM_END) {
304  if (last_out != zs.total_out) {
305  spdlog::debug("Finish compress, last block is {} bytes. Total {} bytes", 16384-zs.avail_out, zs.total_out);
306  _buffer = reinterpret_cast<char*>(realloc(_buffer, zs.total_out));
307  memcpy(_buffer+last_out, comp_buffer.get(), 16384-zs.avail_out);
308  _own_buffer = true;
309  }
310  _meta.fec_oti.transfer_length = zs.total_out;
311  } else {
312  spdlog::error("Error compressing file {}: {}", _meta.toi, zs.msg);
313  throw zs.msg;
314  }
315  deflateEnd(&zs);
316 
317  if (own_decomp) free(decomp_buffer);
318  }
319  } else {
320  spdlog::error("Unknown Content-Encoding {}", _meta.content_encoding);
321  throw "Content-Encoding not known";
322  }
323 
324  _been_encoded = true;
325  _been_decoded = false;
326  }
327 }

◆ fdt_instance_id()

uint16_t LibFlute::File::fdt_instance_id ( )
inline

Get the FDT instance ID.

Definition at line 152 of file File.h.

152 { return _fdt_instance_id; };

◆ fec_oti()

const FecOti& LibFlute::File::fec_oti ( ) const
inline

Get the FEC OTI values.

Definition at line 112 of file File.h.

112 { return _meta.fec_oti; };

◆ get_next_symbols()

auto LibFlute::File::get_next_symbols ( size_t  max_size)

Get the next encoding symbols that fit in max_size bytes.

Definition at line 233 of file File.cpp.

234 {
235  int nof_symbols = std::ceil((float)(max_size - 4) / (float)_meta.fec_oti.encoding_symbol_length);
236  auto cnt = 0;
237  std::vector<EncodingSymbol> symbols;
238 
239  for (auto& block : _source_blocks) {
240  if (cnt >= nof_symbols) break;
241 
242  if (!block.second.complete) {
243  for (auto& symbol : block.second.symbols) {
244  if (cnt >= nof_symbols) break;
245 
246  if (!symbol.second.complete && !symbol.second.queued) {
247  symbols.emplace_back(symbol.first, block.first, symbol.second.data, symbol.second.length, _meta.fec_oti.encoding_id);
248  symbol.second.queued = true;
249  cnt++;
250  }
251  }
252  }
253  }
254  return symbols;
255 
256 }
uint32_t encoding_symbol_length
Definition: flute_types.h:55

◆ is_encoded()

bool LibFlute::File::is_encoded ( ) const
inline

Check if the buffer is content encoded.

Definition at line 107 of file File.h.

107 { return _been_encoded || !_been_decoded; };

◆ length()

size_t LibFlute::File::length ( ) const
inline

Get the data buffer length.

Definition at line 90 of file File.h.

90 { return _been_decoded?_meta.content_length:_meta.fec_oti.transfer_length; };

◆ log_access()

void LibFlute::File::log_access ( )
inline

Log access to the file by incrementing a counter.

Definition at line 127 of file File.h.

127 { _access_count++; };

◆ mark_completed()

auto LibFlute::File::mark_completed ( const std::vector< EncodingSymbol > &  symbols,
bool  success 
)

Mark encoding symbols as completed.

Definition at line 258 of file File.cpp.

259 {
260  for (auto& symbol : symbols) {
261  auto block = _source_blocks.find(symbol.source_block_number());
262  if (block != _source_blocks.end()) {
263  auto sym = block->second.symbols.find(symbol.id());
264  if (sym != block->second.symbols.end()) {
265  sym->second.queued = false;
266  sym->second.complete = success;
267  }
268  check_source_block_completion(block->second);
269  check_file_completion();
270  }
271  }
272 }

◆ meta()

const LibFlute::FileDeliveryTable::FileEntry& LibFlute::File::meta ( ) const
inline

Get the file metadata from its FDT entry.

Definition at line 117 of file File.h.

117 { return _meta; };

◆ put_symbol()

auto LibFlute::File::put_symbol ( const EncodingSymbol symbol)

Write the data from an encoding symbol into the appropriate place in the buffer.

Definition at line 142 of file File.cpp.

143 {
144  if (symbol.source_block_number() > _source_blocks.size()) {
145  throw "Source Block number too high";
146  }
147 
148  SourceBlock& source_block = _source_blocks[ symbol.source_block_number() ];
149 
150  if (symbol.id() > source_block.symbols.size()) {
151  throw "Encoding Symbol ID too high";
152  }
153 
154  SourceBlock::Symbol& target_symbol = source_block.symbols[symbol.id()];
155 
156  if (!target_symbol.complete) {
157  symbol.decode_to(target_symbol.data, target_symbol.length);
158  target_symbol.complete = true;
159 
160  check_source_block_completion(source_block);
161  check_file_completion();
162  }
163 
164 }

◆ received_at()

unsigned long LibFlute::File::received_at ( ) const
inline

Timestamp of file reception.

Definition at line 122 of file File.h.

122 { return _received_at; };

◆ set_fdt_instance_id()

void LibFlute::File::set_fdt_instance_id ( uint16_t  id)
inline

Set the FDT instance ID.

Definition at line 147 of file File.h.

147 { _fdt_instance_id = id; };

The documentation for this class was generated from the following files: