main.c (125 lines of code) (raw):
/*
* Copyright (C) 2016, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the LICENSE file in
* the root directory of this source tree.
*/
#include <stdlib.h>
#include <signal.h>
#include <dlfcn.h>
#include <arpa/inet.h>
#include <getopt.h>
#include "include/common.h"
#include "include/output.h"
#include "include/threads.h"
#include "include/listener.h"
static void parse_arguments(int argc, char **argv, struct netconsd_params *p)
{
int i;
char *tmp;
static const char *optstr = "hw:l:b:a:u:g:";
static const struct option optlong[] = {
{
.name = "help",
.has_arg = no_argument,
.val = 'h',
},
{
.name = NULL,
},
};
while (1) {
i = getopt_long(argc, argv, optstr, optlong, NULL);
switch (i) {
case 'w':
p->nr_workers = atoi(optarg);
break;
case 'l':
p->nr_listeners = atoi(optarg);
break;
case 'b':
p->mmsg_batch = atoi(optarg);
break;
case 'a':
if (!inet_pton(AF_INET6, optarg, &p->listen_addr.sin6_addr))
fatal("invalid listen address\n");
debug("listening for address %s\n", optarg);
break;
case 'u':
p->listen_addr.sin6_port = htons(atoi(optarg));
break;
case 'g':
tmp = index(optarg, '/');
if (!tmp)
fatal("'-g' expects 'INTERVAL/AGE' in ms\n");
p->gc_int_ms = atoi(optarg);
p->gc_age_ms = atoi(tmp + 1);
if (p->gc_age_ms < p->gc_int_ms)
fatal("GC age must be >= GC interval\n");
break;
case -1:
goto done;
case 'h':
printf("Usage: %s [-w workers] [-l listeners] "
"[-b mmsg_batch] [-a udp_listen_addr] [-u udp_listen_port] "
"[-g '${interval}/${age}'] [output module path] "
"[another output module path...]\n", argv[0]);
exit(0);
default:
exit(1);
}
}
done:
/*
* Register output modules
*/
if (optind == argc)
warn("You passed no output modules, which is sort of silly\n");
if (argc - optind > MAXOUTS)
fatal("Too many output mods: %d>%d\n", argc - optind, MAXOUTS);
for (i = optind; i < argc; i++)
if (register_output_module(argv[i], p->nr_workers))
fatal("Can't register '%s'\n", argv[i]);
}
/*
* This exists to kick the blocking recvmmsg() call in the listener threads, so
* they get -EINTR, notice the stop flag, and terminate.
*
* See also: stop_and_wait_for_listeners() in threads.c
*/
static void interrupter_handler(int sig)
{
return;
}
/*
* Initialize the set of signals for which we try to terminate gracefully.
*/
static void init_sigset(sigset_t *set)
{
sigemptyset(set);
sigaddset(set, SIGTERM);
sigaddset(set, SIGINT);
sigaddset(set, SIGHUP);
}
static void init_sighandlers(void)
{
struct sigaction ignorer = {
.sa_handler = SIG_IGN,
};
struct sigaction interrupter = {
.sa_handler = interrupter_handler,
.sa_flags = SA_NODEFER,
};
sigaction(SIGUSR1, &interrupter, NULL);
sigaction(SIGPIPE, &ignorer, NULL);
}
int main(int argc, char **argv)
{
int num;
sigset_t set;
struct tctl *ctl;
struct netconsd_params params = {
.nr_workers = 2,
.nr_listeners = 1,
.mmsg_batch = 512,
.gc_int_ms = 0,
.gc_age_ms = 0,
.listen_addr = {
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_ANY_INIT,
.sin6_port = htons(1514),
}
};
parse_arguments(argc, argv, ¶ms);
init_sighandlers();
init_sigset(&set);
sigprocmask(SIG_BLOCK, &set, NULL);
ctl = create_threads(¶ms);
sigwait(&set, &num);
log("Signal: '%s', terminating\n", strsignal(num));
destroy_threads(ctl);
destroy_output_modules();
return 0;
}