libflute
flute-transmitter.cpp
Go to the documentation of this file.
1 
2 #include <cstdio>
3 #include <iostream>
4 #include <argp.h>
5 
6 #include <cstdlib>
7 
8 #include <fstream>
9 #include <string>
10 #include <filesystem>
11 #include <libconfig.h++>
12 #include <boost/asio.hpp>
13 
14 #include "spdlog/async.h"
15 #include "spdlog/spdlog.h"
16 #include "spdlog/sinks/syslog_sink.h"
17 
18 #include "Transmitter.h"
19 
20 
21 using libconfig::Config;
22 using libconfig::FileIOException;
23 using libconfig::ParseException;
24 
25 using std::placeholders::_1;
26 using std::placeholders::_2;
27 using std::placeholders::_3;
28 
29 static void print_version(FILE *stream, struct argp_state *state);
30 void (*argp_program_version_hook)(FILE *, struct argp_state *) = print_version;
31 const char *argp_program_bug_address = "Austrian Broadcasting Services <obeca@ors.at>";
32 static char doc[] = "FLUTE/ALC transmitter demo"; // NOLINT
33 
34 static struct argp_option options[] = { // NOLINT
35  {"target", 'm', "IP", 0, "Target multicast address (default: 238.1.1.95)", 0},
36  {"port", 'p', "PORT", 0, "Target port (default: 40085)", 0},
37  {"mtu", 't', "BYTES", 0, "Path MTU to size ALC packets for (default: 1500)", 0},
38  {"rate-limit", 'r', "KBPS", 0, "Transmit rate limit (kbps), 0 = no limit, default: 1000 (1 Mbps)", 0},
39  {"ipsec-key", 'k', "KEY", 0, "To enable IPSec/ESP encryption of packets, provide a hex-encoded AES key here", 0},
40  {"log-level", 'l', "LEVEL", 0,
41  "Log verbosity: 0 = trace, 1 = debug, 2 = info, 3 = warn, 4 = error, 5 = "
42  "critical, 6 = none. Default: 2.",
43  0},
44  {nullptr, 0, nullptr, 0, nullptr, 0}};
45 
49 struct ft_arguments {
50  const char *mcast_target = {};
51  bool enable_ipsec = false;
52  const char *aes_key = {};
53  unsigned short mcast_port = 40085;
54  unsigned short mtu = 1500;
55  uint32_t rate_limit = 1000;
56  unsigned log_level = 2;
57  char **files;
58 };
59 
63 static auto parse_opt(int key, char *arg, struct argp_state *state) -> error_t {
64  auto arguments = static_cast<struct ft_arguments *>(state->input);
65  switch (key) {
66  case 'm':
67  arguments->mcast_target = arg;
68  break;
69  case 'k':
70  arguments->aes_key = arg;
71  arguments->enable_ipsec = true;
72  break;
73  case 'p':
74  arguments->mcast_port = static_cast<unsigned short>(strtoul(arg, nullptr, 10));
75  break;
76  case 't':
77  arguments->mtu = static_cast<unsigned short>(strtoul(arg, nullptr, 10));
78  break;
79  case 'r':
80  arguments->rate_limit = static_cast<uint32_t>(strtoul(arg, nullptr, 10));
81  break;
82  case 'l':
83  arguments->log_level = static_cast<unsigned>(strtoul(arg, nullptr, 10));
84  break;
85  case ARGP_KEY_NO_ARGS:
86  argp_usage (state);
87  case ARGP_KEY_ARG:
88  arguments->files = &state->argv[state->next-1];
89  state->next = state->argc;
90  break;
91  default:
92  return ARGP_ERR_UNKNOWN;
93  }
94  return 0;
95 }
96 
97 static char args_doc[] = "[FILE...]";
98 static struct argp argp = {options, parse_opt, args_doc, doc,
99  nullptr, nullptr, nullptr};
100 
104 void print_version(FILE *stream, struct argp_state * /*state*/) {
105  fprintf(stream, "1.0.0\n");
106 }
107 
108 
109 
117 auto main(int argc, char **argv) -> int {
118  struct ft_arguments arguments;
119  /* Default values */
120  arguments.mcast_target = "238.1.1.95";
121 
122  argp_parse(&argp, argc, argv, 0, nullptr, &arguments);
123 
124  // Set up logging
125  std::string ident = "flute-transmitter";
126  auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID | LOG_PERROR | LOG_CONS );
127 
128  spdlog::set_level(
129  static_cast<spdlog::level::level_enum>(arguments.log_level));
130  spdlog::set_pattern("[%H:%M:%S.%f %z] [%^%l%$] [thr %t] %v");
131 
132  spdlog::set_default_logger(syslog_logger);
133  spdlog::info("FLUTE transmitter demo starting up");
134 
135 
136  // We're responsible for buffer management, so create a vector of structs that
137  // are going to hold the data buffers
138  struct FsFile {
139  std::string location;
140  char* buffer;
141  size_t len;
142  uint32_t toi;
143  };
144  std::vector<FsFile> files;
145 
146  // read the file contents into the buffers
147  for (int j = 0; arguments.files[j]; j++) {
148  std::string location = arguments.files[j];
149  std::ifstream file(arguments.files[j], std::ios::binary | std::ios::ate);
150  std::streamsize size = file.tellg();
151  file.seekg(0, std::ios::beg);
152 
153  char* buffer = (char*)malloc(size);
154  file.read(buffer, size);
155  files.push_back(FsFile{ arguments.files[j], buffer, (size_t)size});
156  }
157 
158  // Create a Boost io_service
159  boost::asio::io_service io;
160 
161  // Construct the transmitter class
162  LibFlute::Transmitter transmitter(
163  arguments.mcast_target,
164  arguments.mcast_port,
165  0,
166  arguments.mtu,
167  arguments.rate_limit,
168  io);
169 
170  // Configure IPSEC ESP, if enabled
171  if (arguments.enable_ipsec)
172  {
173  transmitter.enable_ipsec(1, arguments.aes_key);
174  }
175 
176  // Register a completion callback
177  transmitter.register_completion_callback(
178  [&files](uint32_t toi) {
179  for (auto& file : files) {
180  if (file.toi == toi) {
181  spdlog::info("{} (TOI {}) has been transmitted",
182  file.location, file.toi);
183  // could free() the buffer here
184  }
185  }
186  });
187 
188  // Queue all the files
189  for (auto& file : files) {
190  file.toi = transmitter.send( file.location,
191  "application/octet-stream",
192  transmitter.seconds_since_epoch() + 60, // 1 minute from now
193  file.buffer,
194  file.len
195  );
196  spdlog::info("Queued {} ({} bytes) for transmission, TOI is {}",
197  file.location, file.len, file.toi);
198  }
199 
200  // Start the io_service, and thus sending data
201  io.run();
202 
203 exit:
204  return 0;
205 }
FLUTE transmitter class.
Definition: Transmitter.h:34
uint64_t seconds_since_epoch()
Convenience function to get the current timestamp for expiry calculation.
Definition: Transmitter.cpp:71
uint16_t send(const std::string &content_location, const std::string &content_type, uint32_t expires, char *data, size_t length)
Transmit a file.
Definition: Transmitter.cpp:93
void enable_ipsec(uint32_t spi, const std::string &aes_key)
Enable IPSEC ESP encryption of FLUTE payloads.
Definition: Transmitter.cpp:60
void register_completion_callback(completion_callback_t cb)
Register a callback for file transmission completion notifications.
Definition: Transmitter.h:103
static void print_version(FILE *stream, struct argp_state *state)
Print the program version in MAJOR.MINOR.PATCH format.
auto main(int argc, char **argv) -> int
Main entry point for the program.
static char args_doc[]
const char * argp_program_bug_address
static struct argp argp
static struct argp_option options[]
void(* argp_program_version_hook)(FILE *, struct argp_state *)
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[]
Holds all options passed on the command line.
unsigned log_level
log level
const char * mcast_target
unsigned short mcast_port
const char * aes_key
unsigned short mtu