libflute
Classes | Functions | Variables
flute-transmitter.cpp File Reference
#include <argp.h>
#include <cstdio>
#include <cstdlib>
#include <chrono>
#include <iostream>
#include <list>
#include <vector>
#include <fstream>
#include <string>
#include <filesystem>
#include <libconfig.h++>
#include <boost/asio.hpp>
#include <openssl/sha.h>
#include "spdlog/async.h"
#include "spdlog/spdlog.h"
#include "spdlog/sinks/syslog_sink.h"
#include "Version.h"
#include "../utils/base64.h"
#include "Transmitter.h"
Include dependency graph for flute-transmitter.cpp:

Go to the source code of this file.

Classes

struct  ft_arguments
 Holds all options passed on the command line. More...
 

Functions

static void print_version (FILE *stream, struct argp_state *)
 Print the program version in MAJOR.MINOR.PATCH format. More...
 
static auto parse_opt (int key, char *arg, struct argp_state *state) -> error_t
 Parses the command line options into the arguments struct. More...
 
static void send_with_new_api (struct ft_arguments &arguments)
 
static void send_with_old_api (struct ft_arguments &arguments)
 
auto main (int argc, char **argv) -> int
 Main entry point for the program. More...
 

Variables

void(* argp_program_version_hook )(FILE *, struct argp_state *) = print_version
 
const char * argp_program_bug_address = "Austrian Broadcasting Services <obeca@ors.at>"
 
static char doc [] = "FLUTE/ALC transmitter demo"
 
static struct argp_option options []
 
static char args_doc [] = "[FILE...]"
 
static struct argp argp
 

Function Documentation

◆ main()

auto main ( int  argc,
char **  argv 
) -> int

Main entry point for the program.

Parameters
argcCommand line agument count
argvCommand line arguments
Returns
0 on clean exit, -1 on failure

Definition at line 304 of file flute-transmitter.cpp.

304  {
305  struct ft_arguments arguments;
306  /* Default values */
307  arguments.mcast_target = "238.1.1.95";
308 
309  argp_parse(&argp, argc, argv, 0, nullptr, &arguments);
310 
311  // Set up logging
312  std::string ident = "flute-transmitter";
313  auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID | LOG_PERROR | LOG_CONS );
314 
315  spdlog::set_level(
316  static_cast<spdlog::level::level_enum>(arguments.log_level));
317  spdlog::set_pattern("[%H:%M:%S.%f %z] [%^%l%$] [thr %t] %v");
318 
319  spdlog::set_default_logger(syslog_logger);
320  spdlog::info("FLUTE transmitter demo starting up");
321 
322  try {
323  if (arguments.new_api) {
324  send_with_new_api(arguments);
325  } else {
326  send_with_old_api(arguments);
327  }
328  } catch (std::exception ex ) {
329  spdlog::error("Exiting on unhandled exception: %s", ex.what());
330  }
331 
332 exit:
333  return 0;
334 }
static void send_with_new_api(struct ft_arguments &arguments)
static struct argp argp
static void send_with_old_api(struct ft_arguments &arguments)
Holds all options passed on the command line.
const char * mcast_target

◆ parse_opt()

static auto parse_opt ( int  key,
char *  arg,
struct argp_state *  state 
) -> error_t
static

Parses the command line options into the arguments struct.

Definition at line 93 of file flute-transmitter.cpp.

93  {
94  auto arguments = static_cast<struct ft_arguments *>(state->input);
95  switch (key) {
96  case 'e':
97  arguments->gen_etags = true;
98  arguments->new_api = true;
99  break;
100  case 'm':
101  arguments->mcast_target = arg;
102  break;
103  case 'k':
104  arguments->aes_key = arg;
105  arguments->enable_ipsec = true;
106  break;
107  case 'p':
108  arguments->mcast_port = static_cast<unsigned short>(strtoul(arg, nullptr, 10));
109  break;
110  case 't':
111  arguments->mtu = static_cast<unsigned short>(strtoul(arg, nullptr, 10));
112  break;
113  case 'r':
114  arguments->rate_limit = static_cast<uint32_t>(strtoul(arg, nullptr, 10));
115  break;
116  case 'l':
117  arguments->log_level = static_cast<unsigned>(strtoul(arg, nullptr, 10));
118  break;
119  case 'g':
120  arguments->use_gzip = true;
121  arguments->new_api = true;
122  break;
123  case 'T':
124  arguments->tsi = static_cast<uint64_t>(strtoul(arg, nullptr, 10));
125  break;
126  case 'n':
127  arguments->new_api = true;
128  break;
129  case 'R':
130  arguments->retransmit_count = static_cast<size_t>(strtoul(arg, nullptr, 10));
131  arguments->new_api = true;
132  break;
133  case ARGP_KEY_NO_ARGS:
134  argp_usage (state);
135  case ARGP_KEY_ARG:
136  arguments->files = &state->argv[state->next-1];
137  state->next = state->argc;
138  break;
139  default:
140  return ARGP_ERR_UNKNOWN;
141  }
142  return 0;
143 }

◆ print_version()

void print_version ( FILE *  stream,
struct argp_state *  state 
)
static

Print the program version in MAJOR.MINOR.PATCH format.

Definition at line 152 of file flute-transmitter.cpp.

152  {
153  fprintf(stream, "%s.%s.%s\n", std::to_string(VERSION_MAJOR).c_str(),
154  std::to_string(VERSION_MINOR).c_str(),
155  std::to_string(VERSION_PATCH).c_str());
156 }

◆ send_with_new_api()

static void send_with_new_api ( struct ft_arguments arguments)
static

Definition at line 158 of file flute-transmitter.cpp.

159 {
160  struct fileEntry {
161  fileEntry(LibFlute::Transmitter::FileDescription *fd, size_t init_count = 0) :file(fd), transmitted_count(init_count) {};
162 
163  std::shared_ptr<LibFlute::Transmitter::FileDescription> file;
164  size_t transmitted_count;
165  };
166 
167  std::list<fileEntry> files;
168 
169  for (int j = 0; arguments.files[j]; j++) {
170  auto fd = new LibFlute::Transmitter::FileDescription(arguments.files[j], arguments.files[j]);
171  fd->set_content_type("application/octet-stream");
172  fd->set_expiry_time(std::chrono::system_clock::now() + 60s);
173  if (arguments.use_gzip) {
175  }
176  if (arguments.gen_etags) {
177  std::array<unsigned char, SHA_DIGEST_LENGTH> digest;
178  SHA1(reinterpret_cast<const unsigned char*>(fd->data()), fd->data_length(), digest.data());
179  fd->set_etag(base64_encode(digest.data(), SHA_DIGEST_LENGTH));
180  }
181  files.emplace_back(fd);
182  }
183 
184  // Create a Boost io_context
185  boost::asio::io_context io;
186 
187  // Construct the transmitter class
188  LibFlute::Transmitter transmitter(
189  arguments.mcast_target,
190  (short)arguments.mcast_port,
191  arguments.tsi,
192  arguments.mtu,
193  arguments.rate_limit,
195 
196  // Configure IPSEC ESP, if enabled
197  if (arguments.enable_ipsec)
198  {
199  transmitter.enable_ipsec(1, arguments.aes_key);
200  }
201 
202  // Register a completion callback
203  transmitter.register_completion_callback(
204  [&files, &arguments, &transmitter](uint32_t toi) -> void {
205  for (auto& f : files) {
206  if (f.file->toi() == toi) {
207  spdlog::info("{} (TOI {}) has been transmitted", f.file->file_entry().content_location, f.file->toi());
208  f.transmitted_count++;
209  if (f.transmitted_count < arguments.retransmit_count) {
210  transmitter.send(f.file);
211  }
212  }
213  }
214  });
215 
216  // Queue all the files
217  for (const auto& file : files) {
218  auto toi = transmitter.send( file.file );
219  const auto &file_entry = file.file->file_entry();
220  spdlog::info("Queued {} ({} bytes ({} bytes transmitted)) for transmission, TOI is {}",
221  file_entry.content_location, file_entry.content_length, file_entry.fec_oti.transfer_length, toi);
222  }
223 
224  // Start the io_context, and thus sending data
225  io.run();
226 }
File Description object.
Definition: Transmitter.h:51
FLUTE transmitter class.
Definition: Transmitter.h:40
unsigned short mcast_port
const char * aes_key
unsigned short mtu

◆ send_with_old_api()

static void send_with_old_api ( struct ft_arguments arguments)
static

Definition at line 228 of file flute-transmitter.cpp.

229 {
230  // We're responsible for buffer management, so create a vector of structs that
231  // are going to hold the data buffers
232  struct FsFile {
233  std::string location;
234  char* buffer;
235  size_t len;
236  uint32_t toi;
237  };
238  std::vector<FsFile> files;
239 
240  // read the file contents into the buffers
241  for (int j = 0; arguments.files[j]; j++) {
242  const std::string &location = arguments.files[j];
243  std::ifstream file(location, std::ios::binary | std::ios::ate);
244  std::streamsize size = file.tellg();
245  file.seekg(0, std::ios::beg);
246 
247  char* buffer = (char*)malloc(size);
248  file.read(buffer, size);
249  files.push_back(FsFile{ location, buffer, (size_t)size});
250  }
251 
252  // Create a Boost io_context
253  boost::asio::io_context io;
254 
255  // Construct the transmitter class
256  LibFlute::Transmitter transmitter(
257  arguments.mcast_target,
258  (short)arguments.mcast_port,
259  arguments.tsi,
260  arguments.mtu,
261  arguments.rate_limit,
263 
264  // Configure IPSEC ESP, if enabled
265  if (arguments.enable_ipsec)
266  {
267  transmitter.enable_ipsec(1, arguments.aes_key);
268  }
269 
270  // Register a completion callback
271  transmitter.register_completion_callback(
272  [&files](uint32_t toi) -> void {
273  for (auto& file : files) {
274  if (file.toi == toi) {
275  spdlog::info("{} (TOI {}) has been transmitted", file.location, file.toi);
276  // could free() the buffer here
277  }
278  }
279  });
280 
281  // Queue all the files
282  for (auto& file : files) {
283  file.toi = transmitter.send( file.location,
284  "application/octet-stream",
285  transmitter.seconds_since_epoch() + 60, // 1 minute from now
286  file.buffer,
287  file.len
288  );
289  spdlog::info("Queued {} ({} bytes) for transmission, TOI is {}",
290  file.location, file.len, file.toi);
291  }
292 
293  // Start the io_context, and thus sending data
294  io.run();
295 }

Variable Documentation

◆ argp

struct argp argp
static
Initial value:
nullptr, nullptr, nullptr}
static char args_doc[]
static struct argp_option options[]
static auto parse_opt(int key, char *arg, struct argp_state *state) -> error_t
Parses the command line options into the arguments struct.
static char doc[]

Definition at line 145 of file flute-transmitter.cpp.

◆ argp_program_bug_address

const char* argp_program_bug_address = "Austrian Broadcasting Services <obeca@ors.at>"

Definition at line 51 of file flute-transmitter.cpp.

◆ argp_program_version_hook

void(* argp_program_version_hook) (FILE *, struct argp_state *) ( FILE *  ,
struct argp_state *   
) = print_version

Definition at line 50 of file flute-transmitter.cpp.

◆ args_doc

char args_doc[] = "[FILE...]"
static

Definition at line 145 of file flute-transmitter.cpp.

◆ doc

char doc[] = "FLUTE/ALC transmitter demo"
static

Definition at line 52 of file flute-transmitter.cpp.

◆ options

struct argp_option options[]
static
Initial value:
= {
{"target", 'm', "IP", 0, "Target multicast address (default: 238.1.1.95)", 0},
{"port", 'p', "PORT", 0, "Target port (default: 40085)", 0},
{"mtu", 't', "BYTES", 0, "Path MTU to size ALC packets for (default: 1500)", 0},
{"rate-limit", 'r', "KBPS", 0, "Transmit rate limit (kbps), 0 = no limit, default: 1000 (1 Mbps)", 0},
{"ipsec-key", 'k', "KEY", 0, "To enable IPSec/ESP encryption of packets, provide a hex-encoded AES key here", 0},
{"log-level", 'l', "LEVEL", 0,
"Log verbosity: 0 = trace, 1 = debug, 2 = info, 3 = warn, 4 = error, 5 = "
"critical, 6 = none (default: 2)",
0},
{"gzip", 'g', nullptr, 0, "Use gzip to compress the contents, implies -n option", 0},
{"tsi", 'T', "ID", 0, "The TSI to use for the FLUTE session (default: 16)", 0},
{"new-api", 'n', nullptr, 0, "Use the new FileDescription API", 0},
{"retransmit", 'R', "COUNT", 0, "Number of times to repeatedly transmit a file, implies -n option (default: 1)", 0},
{"etags", 'e', nullptr, 0, "Enable generation of ETag values for each file, implies -n option (default: no ETags)", 0},
{nullptr, 0, nullptr, 0, nullptr, 0}}

Definition at line 52 of file flute-transmitter.cpp.