libflute
flute-receiver.cpp
Go to the documentation of this file.
1 // libflute - FLUTE/ALC library
2 //
3 // Copyright (C) 2021 Klaus Kühnhammer (Österreichische Rundfunksender GmbH & Co KG)
4 //
5 // Licensed under the License terms and conditions for use, reproduction, and
6 // distribution of 5G-MAG software (the “License”). You may not use this file
7 // except in compliance with the License. You may obtain a copy of the License at
8 // https://www.5g-mag.com/reference-tools. Unless required by applicable law or
9 // agreed to in writing, software distributed under the License is distributed on
10 // an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 // or implied.
12 //
13 // See the License for the specific language governing permissions and limitations
14 // under the License.
15 //
16 #include <cstdio>
17 #include <iostream>
18 #include <argp.h>
19 
20 #include <cstdlib>
21 
22 #include <fstream>
23 #include <string>
24 #include <filesystem>
25 #include <libconfig.h++>
26 #include <boost/asio.hpp>
27 
28 #include "spdlog/async.h"
29 #include "spdlog/spdlog.h"
30 #include "spdlog/sinks/syslog_sink.h"
31 
32 #include "Version.h"
33 #include "Receiver.h"
34 #include "File.h"
35 
36 
37 using libconfig::Config;
38 using libconfig::FileIOException;
39 using libconfig::ParseException;
40 
41 static void print_version(FILE *stream, struct argp_state *state);
42 void (*argp_program_version_hook)(FILE *, struct argp_state *) = print_version;
43 const char *argp_program_bug_address = "Austrian Broadcasting Services <obeca@ors.at>";
44 static char doc[] = "FLUTE/ALC receiver demo"; // NOLINT
45 
46 static struct argp_option options[] = { // NOLINT
47  {"interface", 'i', "IF", 0, "IP address of the interface to bind flute receivers to (default: 0.0.0.0)", 0},
48  {"target", 'm', "IP", 0, "Multicast address to receive on (default: 238.1.1.95)", 0},
49  {"port", 'p', "PORT", 0, "Multicast port (default: 40085)", 0},
50  {"ipsec-key", 'k', "KEY", 0, "To enable IPSec/ESP decryption of packets, provide a hex-encoded AES key here", 0},
51  {"log-level", 'l', "LEVEL", 0,
52  "Log verbosity: 0 = trace, 1 = debug, 2 = info, 3 = warn, 4 = error, 5 = "
53  "critical, 6 = none. Default: 2.",
54  0},
55  {"tsi", 'T', "ID", 0, "The TSI to use for the FLUTE session (default: 16)", 0},
56  {"output-path", 'o', "PATH", 0, "Directory to save received files", 0},
57  {nullptr, 0, nullptr, 0, nullptr, 0}};
58 
62 struct ft_arguments {
63  const char *flute_interface = {};
64  const char *mcast_target = {};
65  bool enable_ipsec = false;
66  const char *aes_key = {};
67  unsigned short mcast_port = 40085;
68  unsigned log_level = 2;
69  char **files;
70  uint64_t tsi = 16;
71  const char *output_path = nullptr;
72 };
73 
77 static auto parse_opt(int key, char *arg, struct argp_state *state) -> error_t {
78  auto arguments = static_cast<struct ft_arguments *>(state->input);
79  switch (key) {
80  case 'm':
81  arguments->mcast_target = arg;
82  break;
83  case 'i':
84  arguments->flute_interface = arg;
85  break;
86  case 'k':
87  arguments->aes_key = arg;
88  arguments->enable_ipsec = true;
89  break;
90  case 'p':
91  arguments->mcast_port = static_cast<unsigned short>(strtoul(arg, nullptr, 10));
92  break;
93  case 'l':
94  arguments->log_level = static_cast<unsigned>(strtoul(arg, nullptr, 10));
95  break;
96  case 'T':
97  arguments->tsi = static_cast<uint64_t>(strtoul(arg, nullptr, 10));
98  break;
99  case 'o':
100  arguments->output_path = arg;
101  break;
102  default:
103  return ARGP_ERR_UNKNOWN;
104  }
105  return 0;
106 }
107 
108 static struct argp argp = {options, parse_opt, nullptr, doc,
109  nullptr, nullptr, nullptr};
110 
114 void print_version(FILE *stream, struct argp_state * /*state*/) {
115  fprintf(stream, "%s.%s.%s\n", std::to_string(VERSION_MAJOR).c_str(),
116  std::to_string(VERSION_MINOR).c_str(),
117  std::to_string(VERSION_PATCH).c_str());
118 }
119 
120 
121 
129 auto main(int argc, char **argv) -> int {
130  struct ft_arguments arguments;
131  /* Default values */
132  arguments.mcast_target = "238.1.1.95";
133  arguments.flute_interface= "0.0.0.0";
134 
135  // Parse the arguments
136  argp_parse(&argp, argc, argv, 0, nullptr, &arguments);
137 
138  // Set up logging
139  std::string ident = "flute-receiver";
140  auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID | LOG_PERROR | LOG_CONS );
141 
142  spdlog::set_level(
143  static_cast<spdlog::level::level_enum>(arguments.log_level));
144  spdlog::set_pattern("[%H:%M:%S.%f %z] [%^%l%$] [thr %t] %v");
145 
146  spdlog::set_default_logger(syslog_logger);
147  spdlog::info("FLUTE receiver demo starting up");
148 
149  try {
150  // Create a Boost io_context
151  boost::asio::io_context io;
152 
153  // Create the receiver
154  LibFlute::Receiver receiver(
155  arguments.flute_interface,
156  arguments.mcast_target,
157  (short)arguments.mcast_port,
158  arguments.tsi,
159  io);
160 
161  // Configure IPSEC, if enabled
162  if (arguments.enable_ipsec)
163  {
164  receiver.enable_ipsec(1, arguments.aes_key);
165  }
166 
168  [output_path = arguments.output_path](std::shared_ptr<LibFlute::File> file) { //NOLINT
169  std::string out_file = file->meta().content_location;
170  if (output_path && std::strlen(output_path) > 0) {
171  out_file = (std::filesystem::path(output_path) / std::filesystem::path(out_file).filename()).string();
172  }
173 
174  spdlog::info("{} (TOI {}) has been received",
175  out_file, file->meta().toi);
176  FILE *fd = fopen(out_file.c_str(), "wb");
177  fwrite(file->buffer(), 1, file->length(), fd);
178  fclose(fd);
179  });
180 
181  // Start the IO service
182  io.run();
183  } catch (std::exception ex ) {
184  spdlog::error("Exiting on unhandled exception: %s", ex.what());
185  }
186 
187 exit:
188  return 0;
189 }
FLUTE receiver class.
Definition: Receiver.h:29
void register_completion_callback(completion_callback_t cb)
Register a callback for file reception notifications.
Definition: Receiver.h:86
void enable_ipsec(uint32_t spi, const std::string &aes_key)
Enable IPSEC ESP decryption of FLUTE payloads.
Definition: Receiver.cpp:51
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.
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
const char * output_path
unsigned short mcast_port
const char * aes_key
const char * flute_interface
file path of the config file.