Flowgrind
Advanced TCP traffic generator
flowgrindd.c
Go to the documentation of this file.
1 
6 /*
7  * Copyright (C) 2013-2014 Alexander Zimmermann <alexander.zimmermann@netapp.com>
8  * Copyright (C) 2010-2013 Arnd Hannemann <arnd@arndnet.de>
9  * Copyright (C) 2010-2013 Christian Samsel <christian.samsel@rwth-aachen.de>
10  * Copyright (C) 2009 Tim Kosse <tim.kosse@gmx.de>
11  * Copyright (C) 2007-2008 Daniel Schaffrath <daniel.schaffrath@mac.com>
12  *
13  * This file is part of Flowgrind.
14  *
15  * Flowgrind is free software: you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation, either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * Flowgrind is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with Flowgrind. If not, see <http://www.gnu.org/licenses/>.
27  *
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif /* HAVE_CONFIG_H */
33 
34 #ifdef __DARWIN__
35 
36 #define daemon fake_daemon_function
37 #endif /* __DARWIN__ */
38 
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <pthread.h>
43 #include <errno.h>
44 #include <signal.h>
45 #include <syslog.h>
46 #include <string.h>
47 #include <sys/utsname.h>
48 #include <sys/wait.h>
49 #include <netinet/in.h>
50 #include <netinet/tcp.h>
51 #include <fcntl.h>
52 #include <netdb.h>
53 #include <sys/stat.h>
54 
55 /* xmlrpc-c */
56 #include <xmlrpc-c/base.h>
57 #include <xmlrpc-c/server.h>
58 #include <xmlrpc-c/server_abyss.h>
59 #include <xmlrpc-c/util.h>
60 
61 #include "common.h"
62 #include "daemon.h"
63 #include "fg_log.h"
64 #include "fg_affinity.h"
65 #include "fg_error.h"
66 #include "fg_math.h"
67 #include "fg_progname.h"
68 #include "fg_string.h"
69 #include "fg_time.h"
70 #include "fg_definitions.h"
71 #include "debug.h"
72 #include "fg_argparser.h"
73 #include "fg_rpc_server.h"
74 
75 #ifdef HAVE_LIBPCAP
76 #include "fg_pcap.h"
77 #endif /* HAVE_LIBPCAP */
78 
79 #ifdef __DARWIN__
80 
81 #undef daemon
82 extern int daemon(int, int);
83 #endif /* __DARWIN__ */
84 
86 #define PARSE_ERR(err_msg, ...) do { \
87  errx(err_msg, ##__VA_ARGS__); \
88  usage(EXIT_FAILURE); \
89 } while (0)
90 
91 /* External global variables */
92 extern const char *progname;
93 
94 /* XXX add a brief description doxygen */
95 static unsigned port = DEFAULT_LISTEN_PORT;
96 
97 /* XXX add a brief description doxygen */
98 static char *rpc_bind_addr = NULL;
99 
101 static int core;
102 
104 static struct arg_parser parser;
105 
106 /* Forward declarations */
107 static void usage(short status) __attribute__((noreturn));
108 static void tear_down_daemon(void);
109 
118 static void usage(short status)
119 {
120  /* Syntax error. Emit 'try help' to stderr and exit */
121  if (status != EXIT_SUCCESS) {
122  fprintf(stderr, "Try '%s -h' for more information\n", progname);
123  exit(status);
124  }
125 
126  fprintf(stdout,
127  "Usage: %1$s [OPTION]...\n"
128  "Advanced TCP traffic generator for Linux, FreeBSD, and Mac OS X.\n\n"
129 
130  "Mandatory arguments to long options are mandatory for short options too.\n"
131  " -b ADDR XML-RPC server bind address\n"
132  " -c # bound daemon to specific CPU. First CPU is 0\n"
133 #ifdef DEBUG
134  " -d, --debug increase debugging verbosity. Add option multiple times to\n"
135  " increase the verbosity (no daemon, log to stderr)\n"
136 #else /* DEBUG */
137  " -d don't fork into background, log to stderr\n"
138 #endif /* DEBUG */
139  " -h, --help display this help and exit\n"
140  " -p # XML-RPC server port\n"
141 #ifdef HAVE_LIBPCAP
142  " -w DIR target directory for dump files. The daemon must be run as root\n"
143 #endif /* HAVE_LIBPCAP */
144  " -v, --version print version information and exit\n",
145  progname);
146  exit(EXIT_SUCCESS);
147 }
148 
154 static void sighandler(int sig)
155 {
156  int status;
157 
158  switch (sig) {
159  case SIGCHLD:
160  while (waitpid(-1, &status, WNOHANG) > 0)
161  logging(LOG_NOTICE, "child returned (status = %d)",
162  status);
163  break;
164  case SIGHUP:
165  logging(LOG_NOTICE, "caught SIGHUP. don't know what to do.");
166  break;
167  case SIGALRM:
168  logging(LOG_NOTICE, "caught SIGALRM, don't know what to do.");
169  break;
170  case SIGPIPE:
171  break;
172  case SIGINT:
173  case SIGTERM:
174  logging(LOG_NOTICE, "caught SIGINT/SIGTERM, tear down daemon");
176  break;
177  default:
178  logging(LOG_ALERT, "caught signal %d, but don't remember "
179  "intercepting it, aborting...", sig);
180  abort();
181  }
182 }
183 
185 {
186  int flags;
187 
188  if (pipe(daemon_pipe) == -1)
189  crit("could not create pipe");
190 
191  if ((flags = fcntl(daemon_pipe[0], F_GETFL, 0)) == -1)
192  flags = 0;
193  fcntl(daemon_pipe[0], F_SETFL, flags | O_NONBLOCK);
194 
195  pthread_mutex_init(&mutex, NULL);
196 
197  int rc = pthread_create(&daemon_thread, NULL, daemon_main, 0);
198  if (rc)
199  critc(rc, "could not start thread");
200 }
201 
203 {
204  pthread_t thread = pthread_self();
205  int rc = pthread_setaffinity(thread, core);
206 
207  if (rc)
208  logging(LOG_WARNING, "failed to bind %s (PID %d) to CPU core %i",
209  progname, getpid(), core);
210  else
211  DEBUG_MSG(LOG_INFO, "bind %s (PID %d) to CPU core %i",
212  progname, getpid(), core);
213 }
214 
215 #ifdef HAVE_LIBPCAP
217  if (!dump_dir)
218  dump_dir = getcwd(NULL, 0);
219 
220  struct stat dirstats;
221 
222  if (stat(dump_dir, &dirstats) == -1) {
223  DEBUG_MSG(LOG_WARNING, "unable to stat %s: %s", dump_dir,
224  strerror(errno));
225  return 0;
226  }
227 
228  if (!S_ISDIR(dirstats.st_mode)) {
229  DEBUG_MSG(LOG_ERR, "provided path %s is not a directory",
230  dump_dir);
231  return 0;
232  }
233 
234  if (access(dump_dir, W_OK | X_OK) == -1) {
235  DEBUG_MSG(LOG_ERR, "insufficent permissions to access %s: %s",
236  dump_dir, strerror(errno));
237  return 0;
238  }
239 
240  /* ensure path contains terminating slash */
241  if (dump_dir[strlen(dump_dir) - 1] != '/')
242  asprintf_append(&dump_dir, "/");
243 
244  return 1;
245 }
246 #endif /* HAVE_LIBPCAP */
247 
254 static void parse_cmdline(int argc, char *argv[])
255 {
256  const struct ap_Option options[] = {
257  {'b', 0, ap_yes, 0, 0},
258  {'c', 0, ap_yes, 0, 0},
259 #ifdef DEBUG
260  {'d', "debug", ap_no, 0, 0},
261 #else /* DEBUG */
262  {'d', 0, ap_no, 0, 0},
263 #endif
264  {'h', "help", ap_no, 0, 0},
265  {'o', 0, ap_yes, 0, 0},
266  {'p', 0, ap_yes, 0, 0},
267  {'v', "version", ap_no, 0, 0},
268 #ifdef HAVE_LIBPCAP
269  {'w', 0, ap_yes, 0, 0},
270 #endif /* HAVE_LIBPCAP */
271  {0, 0, ap_no, 0, 0}
272  };
273 
274  if (!ap_init(&parser, argc, (const char* const*) argv, options, 0))
275  critx("could not allocate memory for option parser");
276  if (ap_error(&parser))
277  PARSE_ERR("%s", ap_error(&parser));
278 
279  /* parse command line */
280  for (int argind = 0; argind < ap_arguments(&parser); argind++) {
281  const int code = ap_code(&parser, argind);
282  const char *arg = ap_argument(&parser, argind);
283 
284  switch (code) {
285  case 0:
286  PARSE_ERR("invalid argument: %s", arg);
287  case 'b':
288  rpc_bind_addr = strdup(arg);
289  if (sscanf(arg, "%s", rpc_bind_addr) != 1)
290  PARSE_ERR("failed to parse bind address");
291  break;
292  case 'c':
293  if (sscanf(arg, "%u", &core) != 1)
294  PARSE_ERR("failed to parse CPU number");
295  break;
296  case 'd':
297 #ifdef DEBUG
299 #endif /* DEBUG */
300  break;
301  case 'h':
302  usage(EXIT_SUCCESS);
303  break;
304  case 'p':
305  if (sscanf(arg, "%u", &port) != 1)
306  PARSE_ERR("failed to parse port number");
307  break;
308 #ifdef HAVE_LIBPCAP
309  case 'w':
310  dump_dir = strdup(arg);
311  break;
312 #endif /* HAVE_LIBPCAP */
313  case 'v':
314  fprintf(stdout, "%s %s\%s\n%s\n\n%s\n", progname,
317  exit(EXIT_SUCCESS);
318  break;
319  default:
320  PARSE_ERR("uncaught option: %s", arg);
321  break;
322  }
323  }
324 
325 #ifdef HAVE_LIBPCAP
326  if (!process_dump_dir()) {
327  if (ap_is_used(&parser, 'w'))
328  PARSE_ERR("the dump directory %s for tcpdumps does "
329  "either not exist or you have insufficient "
330  "permissions to write to it", dump_dir);
331  else
332  warnx("tcpdumping will not be available since you "
333  "don't have sufficient permissions to write to "
334  "%s", dump_dir);
335  }
336 #endif /* HAVE_LIBPCAP */
337 }
338 
339 static void sanity_check(void)
340 {
341  if (core < 0) {
342  errx("CPU binding failed. Given CPU ID is negative");
343  exit(EXIT_FAILURE);
344  }
345 
346  if (core > get_ncores(NCORE_CURRENT)) {
347  errx("CPU binding failed. Given CPU ID is higher then "
348  "available CPU cores");
349  exit(EXIT_FAILURE);
350  }
351 
352  /* TODO more sanity checks... (e.g. if port is in valid range) */
353 }
354 
358 static void tear_down_daemon(void)
359 {
360  ap_free(&parser);
361  close_logging();
362  exit(EXIT_SUCCESS);
363 }
364 
365 int main(int argc, char *argv[])
366 {
367  /* Info about the xmlrpc server */
368  struct fg_rpc_server server;
369 
370  /* Initialize sighandler */
371  struct sigaction sa;
372  sa.sa_handler = sighandler;
373  sa.sa_flags = 0;
374  sigemptyset (&sa.sa_mask);
375  if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
376  crit("could not ignore SIGPIPE");
377  if (sigaction (SIGHUP, &sa, NULL))
378  critx("could not set handler for SIGUP");
379  if (sigaction (SIGALRM, &sa, NULL))
380  critx("could not set handler for SIGALRM");
381  if (sigaction (SIGCHLD, &sa, NULL))
382  critx("could not set handler for SIGCHLD");
383  if (sigaction(SIGINT, &sa, NULL))
384  critx("could not set handler for SIGINT");
385  if (sigaction(SIGTERM, &sa, NULL))
386  critx("could not set handler for SIGTERM");
387 
388  set_progname(argv[0]);
389  parse_cmdline(argc, argv);
390  sanity_check();
391 
392  /* Initialize logging */
393  if (!ap_is_used(&parser, 'd'))
395  else
397 
399 
400 #ifdef HAVE_LIBPCAP
401  fg_pcap_init();
402 #endif /* HAVE_LIBPCAP */
403 
405 
406  /* Push flowgrindd into the background */
407  if (!ap_is_used(&parser, 'd')) {
408  /* Need to call daemon() before creating the thread because
409  * it internally calls fork() which does not copy threads. */
410  if (daemon(0, 0) == -1)
411  crit("daemon() failed");
412  logging(LOG_NOTICE, "flowgrindd daemonized");
413  }
414 
415  if (ap_is_used(&parser, 'c'))
417 
419 
420  /* This will block */
421  run_rpc_server(&server);
422  critx("control should never reach end of main()");
423 }
DEBUG_MSG
#define DEBUG_MSG(LVL, MSG,...)
Print debug message to standard error.
Definition: debug.h:49
fg_pcap.h
Packet capture support for the Flowgrind daemon.
sanity_check
static void sanity_check(void)
Definition: flowgrindd.c:339
fg_pcap_init
int fg_pcap_init(void)
Initialize flowgrind's pcap library.
Definition: fg_pcap.c:84
daemon
#define daemon
Temporarily renaming daemon() so compiler does not see the warning on OS X.
Definition: flowgrindd.c:36
fg_string.h
Functions to manipulate strings used by Flowgrind.
fg_progname.h
Program name management.
fg_affinity.h
CPU affinity routines used by Flowgrind.
daemon_main
void * daemon_main(void *ptr __attribute__((unused)))
Definition: daemon.c:800
fg_log.h
ap_code
int ap_code(const struct arg_parser *const ap, const int i)
Returns the code of a parsed option with given index.
Definition: fg_argparser.c:468
tear_down_daemon
static void tear_down_daemon(void)
Gracefully tear down daemon.
Definition: flowgrindd.c:358
ap_argument
const char * ap_argument(const struct arg_parser *const ap, const int i)
Returns the argument of a parsed option.
Definition: fg_argparser.c:478
ap_error
const char * ap_error(const struct arg_parser *const ap)
Get the string containing errors encountered during parsing.
Definition: fg_argparser.c:458
init_rpc_server
void init_rpc_server(struct fg_rpc_server *server, char *rpc_bind_addr, unsigned port)
Initializes the xmlrpc server.
Definition: fg_rpc_server.c:835
crit
#define crit(...)
To report an critical error w/ the corresponding system error message.
Definition: fg_error.h:36
FLOWGRIND_COPYRIGHT
#define FLOWGRIND_COPYRIGHT
Flowgrind's copyright year.
Definition: common.h:82
NCORE_CURRENT
@ NCORE_CURRENT
Processors available to the current process.
Definition: fg_affinity.h:40
port
static unsigned port
Definition: flowgrindd.c:95
arg_parser
Internal state of the argument parser.
Definition: fg_argparser.h:73
LOGGING_STDERR
@ LOGGING_STDERR
Log to stderr.
Definition: fg_log.h:41
logging
void logging(int priority, const char *fmt,...)
Definition: fg_log.c:69
fg_error.h
Error-reporting routines used by Flowgrind.
ap_no
@ ap_no
Option without argument (flag).
Definition: fg_argparser.h:37
warnx
#define warnx(...)
To report a warning w/ a system error message.
Definition: fg_error.h:54
sighandler
static void sighandler(int sig)
Signal handler to catching signals.
Definition: flowgrindd.c:154
fg_rpc_server
Information about the daemons XMLrpc server.
Definition: fg_rpc_server.h:49
rpc_bind_addr
static char * rpc_bind_addr
Definition: flowgrindd.c:98
ap_yes
@ ap_yes
Argument required.
Definition: fg_argparser.h:39
run_rpc_server
void run_rpc_server(struct fg_rpc_server *server)
Enters the xmlrpc server mainloop.
Definition: fg_rpc_server.c:878
get_ncores
int get_ncores(enum ncore_query query)
Return either the total number of configured or available cores.
Definition: fg_affinity.c:56
ap_Option::code
int code
Short option letter or code (code != 0).
Definition: fg_argparser.h:47
ap_is_used
bool ap_is_used(const struct arg_parser *const ap, int code)
Returns true if the option specified by code was given at least once.
Definition: fg_argparser.c:503
mutex
pthread_mutex_t mutex
Definition: daemon.c:93
increase_debuglevel
void increase_debuglevel()
Decrease debug level.
Definition: debug.c:50
main
int main(int argc, char *argv[])
Definition: flowgrindd.c:365
errx
#define errx(...)
To report an error w/o a system error message.
Definition: fg_error.h:47
ap_free
void ap_free(struct arg_parser *const ap)
Free internal state of arg-parser.
Definition: fg_argparser.c:448
critc
#define critc(code,...)
To report an critical error w/ the system error message 'code'.
Definition: fg_error.h:38
FLOWGRIND_COPYING
#define FLOWGRIND_COPYING
Standard GPL3 no warranty message.
Definition: common.h:85
critx
#define critx(...)
To report an critical error w/o a system error message.
Definition: fg_error.h:40
fg_rpc_server.h
RPCServer related functions and structs used by the Flowgrind daemon.
FLOWGRIND_AUTHORS
#define FLOWGRIND_AUTHORS
Flowgrind's authors in a printable string.
Definition: common.h:91
parse_cmdline
static void parse_cmdline(int argc, char *argv[])
Parse command line options to initialize global options.
Definition: flowgrindd.c:254
ap_arguments
int ap_arguments(const struct arg_parser *const ap)
Number of arguments parsed (may be different from argc).
Definition: fg_argparser.c:463
fg_argparser.h
Command line argument parser.
usage
static void usage(short status) __attribute__((noreturn))
Print usage or error message and exit.
Definition: flowgrindd.c:118
core
static int core
CPU core to which flowgrindd should bind to.
Definition: flowgrindd.c:101
dump_dir
char * dump_dir
Definition: daemon.c:91
ap_Option
Defines a valid command line option.
Definition: fg_argparser.h:45
HAVE_LIBPCAP
#define HAVE_LIBPCAP
Definition: config.h:53
fg_definitions.h
Common definitions used by the Flowgrind daemon, controller, and libs.
fg_time.h
Timing related routines used by Flowgrind.
FLOWGRIND_VERSION
#define FLOWGRIND_VERSION
Flowgrind version number.
Definition: common.h:44
bind_daemon_to_core
void bind_daemon_to_core(void)
Definition: flowgrindd.c:202
daemon_pipe
int daemon_pipe[2]
Definition: daemon.c:87
parser
static struct arg_parser parser
Command line option parser.
Definition: flowgrindd.c:104
common.h
Data structures used by the Flowgrind daemon and controller.
set_progname
void set_progname(const char *argv0)
Set global variable 'progname', based on argv[0].
Definition: fg_progname.c:37
close_logging
void close_logging(void)
Close logging stream.
Definition: fg_log.c:57
daemon_thread
pthread_t daemon_thread
Definition: daemon.c:89
process_dump_dir
int process_dump_dir()
Definition: flowgrindd.c:216
config.h
asprintf_append
int asprintf_append(char **strp, const char *fmt,...)
Definition: fg_string.c:98
PARSE_ERR
#define PARSE_ERR(err_msg,...)
Print error message, usage string and exit.
Definition: flowgrindd.c:86
pthread_setaffinity
int pthread_setaffinity(pthread_t thread, unsigned core)
Set CPU affinity of the thread thread to the core core.
Definition: fg_affinity.c:75
progname
const char * progname
String containing name the program is called with.
Definition: fg_progname.c:35
DEFAULT_LISTEN_PORT
#define DEFAULT_LISTEN_PORT
Daemon's default listen port.
Definition: common.h:55
flows
struct linked_list flows
Definition: daemon.c:103
create_daemon_thread
void create_daemon_thread()
Definition: flowgrindd.c:184
ap_init
bool ap_init(struct arg_parser *const ap, const int argc, const char *const argv[], const struct ap_Option options[], const char in_order)
Initialize the arg-parser given command line and user-defined options.
Definition: fg_argparser.c:374
fg_math.h
Routines for statistics and advanced traffic generation.
debug.h
Debugging routines for Flowgrind controller and daemon.
fg_list_init
int fg_list_init(struct linked_list *const list)
Initializes the list by setting its head and tail to NULL and its size to 0.
Definition: fg_list.c:34
daemon.h
Routines used by the Flowgrind daemon.
init_logging
void init_logging(enum log_streams stream)
Open logging stream.
Definition: fg_log.c:43
LOGGING_SYSLOG
@ LOGGING_SYSLOG
Log to syslog.
Definition: fg_log.h:39