20 #include "spdlog/spdlog.h"
25 short port, uint64_t tsi,
26 boost::asio::io_context& io_context)
29 , _mcast_address(address)
31 boost::asio::ip::udp::endpoint listen_endpoint(
32 boost::asio::ip::make_address(iface), port);
33 _socket.open(listen_endpoint.protocol());
34 _socket.set_option(boost::asio::ip::multicast::enable_loopback(
true));
35 _socket.set_option(boost::asio::ip::udp::socket::reuse_address(
true));
36 _socket.set_option(boost::asio::socket_base::receive_buffer_size(16*1024*1024));
37 _socket.bind(listen_endpoint);
41 boost::asio::ip::multicast::join_group(
42 boost::asio::ip::make_address(address)));
44 _socket.async_receive_from(
45 boost::asio::buffer(_data, max_length), _sender_endpoint,
46 boost::bind(&LibFlute::Receiver::handle_receive_from,
this,
47 boost::asio::placeholders::error,
48 boost::asio::placeholders::bytes_transferred));
56 auto LibFlute::Receiver::handle_receive_from(
const boost::system::error_code& error,
57 size_t bytes_recvd) ->
void
59 if (!_running)
return;
63 spdlog::trace(
"Received {} bytes", bytes_recvd);
67 if (alc.tsi() == _tsi) {
69 const std::lock_guard<std::mutex> lock(_files_mutex);
71 if (alc.toi() == 0 && (!_fdt || _fdt->instance_id() != alc.fdt_instance_id())) {
72 if (_files.find(alc.toi()) == _files.end()) {
74 _files.emplace(alc.toi(), std::make_shared<LibFlute::File>(fe));
78 if (_files.find(alc.toi()) != _files.end() && !_files[alc.toi()]->complete()) {
80 _data + alc.header_length(),
81 bytes_recvd - alc.header_length(),
82 _files[alc.toi()]->fec_oti(),
83 alc.content_encoding());
85 for (
const auto& symbol : encoding_symbols) {
86 spdlog::debug(
"received TOI {} SBN {} ID {}", alc.toi(), symbol.source_block_number(), symbol.id() );
87 _files[alc.toi()]->put_symbol(symbol);
90 auto file = _files[alc.toi()].get();
91 if (_files[alc.toi()]->complete()) {
92 for (
auto it = _files.cbegin(); it != _files.cend();)
94 if (it->second.get() != file && it->second->meta().content_location == file->meta().content_location)
96 spdlog::debug(
"Replacing file with TOI {}", it->first);
97 it = _files.erase(it);
107 spdlog::debug(
"File with TOI {} completed", alc.toi());
108 if (alc.toi() != 0 && _completion_cb) {
109 _completion_cb(_files[alc.toi()]);
110 _files.erase(alc.toi());
113 if (alc.toi() == 0) {
114 _fdt = std::make_unique<LibFlute::FileDeliveryTable>(
115 alc.fdt_instance_id(), _files[alc.toi()]->buffer(), _files[alc.toi()]->length());
117 _files.erase(alc.toi());
118 for (
const auto& file_entry : _fdt->file_entries()) {
120 if (_files.find(file_entry.toi) == _files.end()) {
121 spdlog::debug(
"Starting reception for file with TOI {}: {} ({})", file_entry.toi,
122 file_entry.content_location, file_entry.content_type);
123 _files.emplace(file_entry.toi, std::make_shared<LibFlute::File>(file_entry));
129 spdlog::trace(
"Discarding packet for unknown or already completed file with TOI {}", alc.toi());
132 spdlog::warn(
"Discarding packet for unknown TSI {}", alc.tsi());
134 }
catch (
const std::exception &ex) {
135 spdlog::warn(
"Failed to decode ALC/FLUTE packet: {}", ex.what());
138 _socket.async_receive_from(
139 boost::asio::buffer(_data, max_length), _sender_endpoint,
140 boost::bind(&LibFlute::Receiver::handle_receive_from,
this,
141 boost::asio::placeholders::error,
142 boost::asio::placeholders::bytes_transferred));
146 spdlog::error(
"receive_from error: {}", error.message());
152 std::vector<std::shared_ptr<LibFlute::File>> files;
153 for (
auto& f : _files) {
154 files.push_back(f.second);
161 const std::lock_guard<std::mutex> lock(_files_mutex);
162 for (
auto it = _files.cbegin(); it != _files.cend();)
164 auto age = time(
nullptr) - it->second->received_at();
165 if ( it->second->meta().content_location !=
"bootstrap.multipart" && age > max_age) {
166 it = _files.erase(it);
175 const std::lock_guard<std::mutex> lock(_files_mutex);
176 for (
auto it = _files.cbegin(); it != _files.cend();)
178 if ( it->second->meta().content_location == cl) {
179 it = _files.erase(it);
A class for parsing and creating ALC packets.
static std::vector< EncodingSymbol > from_payload(char *encoded_data, size_t data_len, const FecOti &fec_oti, ContentEncoding encoding)
Parse and construct all encoding symbols from a payload data buffer.
void remove_file_with_content_location(const std::string &cl)
Remove a file from the list that matches the passed content location.
std::vector< std::shared_ptr< LibFlute::File > > file_list()
List all current files.
void enable_ipsec(uint32_t spi, const std::string &aes_key)
Enable IPSEC ESP decryption of FLUTE payloads.
Receiver(const std::string &iface, const std::string &address, short port, uint64_t tsi, boost::asio::io_context &io_context)
Default constructor.
void remove_expired_files(unsigned max_age)
Remove files from the list that are older than max_age seconds.
void enable_esp(uint32_t spi, const std::string &dest_address, Direction direction, const std::string &key)
An entry for a file in the FDT.