3#include <condition_variable>
17#include <boost/program_options.hpp>
24namespace bpo = boost::program_options;
28constexpr std::uint16_t DEFAULT_XMLRPC_PORT{1082};
30std::pair<bool, bpo::variables_map> parse_cmdline(
int argc,
char** argv);
31std::pair<std::string_view, int> parse_ip_port_combo(std::string_view ip_port_combo);
37 std::cout <<
"[INFO] ";
41std::ostream& warning()
43 std::cout <<
"[WARN] ";
49 std::cout <<
"[ERR] ";
53bool block_signals(
const sigset_t& signals)
57 int r = sigprocmask(SIG_BLOCK, &signals,
nullptr);
59 error() <<
"Failed to block signals: " << strerror(errno) << std::endl;
66bool wait_for_signals(
const sigset_t& signals, std::chrono::seconds timeout)
68 timespec ts{timeout.count(), 0};
72 r = sigtimedwait(&signals,
nullptr, &ts);
73 }
while (r == -1 && errno == EINTR);
74 if (r == -1 && errno != EAGAIN) {
75 throw std::system_error(errno, std::system_category(),
"Failed to wait for signals");
81int main(
int argc,
char** argv)
84 sigemptyset(&signal_set);
85 for (
int signal : {SIGTERM, SIGINT, SIGQUIT}) {
86 sigaddset(&signal_set, signal);
89 if (!block_signals(signal_set)) {
93 const auto& [cmdline_valid, cmdline_vm] = parse_cmdline(argc, argv);
98 const std::string listen_ip{
99 cmdline_vm.count(
"listen-ip") > 0 ? cmdline_vm[
"listen-ip"].as<std::string>() :
""};
100 const uint16_t listen_port{cmdline_vm[
"listen-port"].as<uint16_t>()};
101 const std::vector<std::string> redis_server_connstrs{
102 cmdline_vm[
"redis-server"].as<std::vector<std::string>>()};
106 for (
const auto& connstr : redis_server_connstrs) {
107 const auto& [ip, port] = parse_ip_port_combo(connstr);
116 info() <<
"Connecting to redis servers\n";
121 request_handler.register_method_handlers(xmlrpc_server);
123 info() <<
"Starting XML-RPC server and request handler\n";
124 xmlrpc_server.
start();
126 while (!wait_for_signals(signal_set, std::chrono::minutes(1))) {
127 if (!redis.is_connected()) {
128 warning() <<
"Lost connection to Redis server. Reconnecting\n";
134 info() <<
"Stopping AdminDB ARPwatch interface\n";
135 xmlrpc_server.stop();
143std::pair<bool, bpo::variables_map> parse_cmdline(
int argc,
char** argv)
145 bpo::options_description options_desc{
"ARPwatch XML-RPC interface for Kea DHCP servers"};
147 options_desc.add_options()
149 "Print this help message and exit")
150 (
"listen-ip,i", bpo::value<std::string>(),
151 "IP address to listen for XML-RPC requests on")
152 (
"listen-port,l", bpo::value<uint16_t>()->default_value(DEFAULT_XMLRPC_PORT),
153 "Port to listen for XML-RPC reqeuests on")
154 (
"redis-server,r", bpo::value<std::vector<std::string>>(),
155 "Redis server(s) to query")
159 bpo::variables_map vm;
160 bpo::store(bpo::parse_command_line(argc, argv, options_desc), vm);
165 if (vm.count(
"help") > 0) {
166 std::clog << options_desc <<
'\n';
172 if (vm.count(
"redis-server") == 0) {
173 std::clog <<
"Missing --redis-server!\n";
177 return std::make_pair(retval, std::move(vm));
180std::pair<std::string_view, int> parse_ip_port_combo(std::string_view ip_port_combo)
182 const auto separator = ip_port_combo.find_last_of(
':');
184 if (separator == std::string_view::npos) {
185 return std::make_pair(ip_port_combo, 0);
188 std::string_view ip = ip_port_combo.substr(0, separator);
189 std::string_view port_str = ip_port_combo.substr(separator + 1);
191 return std::make_pair(ip, boost::lexical_cast<int>(port_str));
203 struct in6_addr in6_a
206 int is_v6 = inet_pton(AF_INET6, ip.c_str(), &in6_a);
209 const struct sockaddr_in6 sin6
211 .sin6_family = AF_INET6, .sin6_port = port, .sin6_flowinfo = 0, .sin6_addr = in6_a,
215 return aai::XmlRpcServer{
reinterpret_cast<const struct sockaddr*
>(&sin6),
sizeof(sin6)};
221 int is_v4 = inet_pton(AF_INET, ip.c_str(), &in4_a);
224 throw std::invalid_argument{
"Invalid listen IP address"};
227 const struct sockaddr_in sin4
229 .sin_family = AF_INET, .sin_port = port, .sin_addr = in4_a, .sin_zero = {
241 return aai::XmlRpcServer{
reinterpret_cast<const struct sockaddr*
>(&sin4),
sizeof(sin4)};
int main(int argc, char **argv)
Wrapper around HiredisAdapter for multi-client support.
High-level handler for ARPwatch requests.
Abstraction for an XML-RPC server.
void start()
Start the XML-RPC server.
std::vector< HiredisAdapter > redis_adapters