2 * collectd-td - collectd traffic generator
3 * Copyright (C) 2013 Florian octo Forster
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Florian Forster <ff at octo.it>
35 #include <sys/types.h>
36 #include <sys/socket.h>
40 # define __attribute__(x) /**/
43 #define DEF_NODE "localhost"
44 #define DEF_SERVICE "8125"
46 #define DEF_NUM_COUNTERS 1000
47 #define DEF_NUM_TIMERS 1000
48 #define DEF_NUM_GAUGES 100
49 #define DEF_NUM_SETS 100
50 #define DEF_SET_SIZE 128
52 static int conf_num_counters = DEF_NUM_COUNTERS;
53 static int conf_num_timers = DEF_NUM_TIMERS;
54 static int conf_num_gauges = DEF_NUM_GAUGES;
55 static int conf_num_sets = DEF_NUM_SETS;
56 static int conf_set_size = DEF_SET_SIZE;
57 static const char *conf_node = DEF_NODE;
58 static const char *conf_service = DEF_SERVICE;
62 static struct sigaction sigint_action;
63 static struct sigaction sigterm_action;
65 static _Bool loop = 1;
67 __attribute__((noreturn))
68 static void exit_usage (int exit_status) /* {{{ */
70 fprintf ((exit_status == EXIT_FAILURE) ? stderr : stdout,
71 PACKAGE_NAME" -- statsd traffic generator\n"
73 " Usage: statsd-ng [OPTION]\n"
76 " -c <number> Number of counters to emulate. (Default: %i)\n"
77 " -t <number> Number of timers to emulate. (Default: %i)\n"
78 " -g <number> Number of gauges to emulate. (Default: %i)\n"
79 " -s <number> Number of sets to emulate. (Default: %i)\n"
80 " -S <size> Number of elements in each set. (Default: %i)\n"
81 " -d <dest> Destination address of the network packets.\n"
82 " (Default: "DEF_NODE")\n"
83 " -D <port> Destination port of the network packets.\n"
84 " (Default: "DEF_SERVICE")\n"
85 " -h Print usage information (this output).\n"
87 "Copyright (C) 2013 Florian Forster\n"
88 "Licensed under the GNU General Public License, version 2 (GPLv2)\n",
89 DEF_NUM_COUNTERS, DEF_NUM_TIMERS, DEF_NUM_GAUGES,
90 DEF_NUM_SETS, DEF_SET_SIZE);
92 } /* }}} void exit_usage */
94 static void signal_handler (int signal __attribute__((unused))) /* {{{ */
97 } /* }}} void signal_handler */
99 static int sock_open (void) /* {{{ */
101 struct addrinfo ai_hints;
102 struct addrinfo *ai_list = NULL;
103 struct addrinfo *ai_ptr;
107 memset (&ai_hints, 0, sizeof (ai_hints));
109 ai_hints.ai_flags = AI_ADDRCONFIG;
111 ai_hints.ai_family = AF_UNSPEC;
112 ai_hints.ai_socktype = SOCK_DGRAM;
114 status = getaddrinfo (conf_node, conf_service, &ai_hints, &ai_list);
117 fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (status));
121 for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
125 fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
131 status = connect (fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
142 freeaddrinfo (ai_list);
146 fprintf (stderr, "Opening network socket failed.\n");
151 } /* }}} int sock_open */
153 static int send_random_event (void) /* {{{ */
155 long conf_num_total = conf_num_counters + conf_num_timers
156 + conf_num_gauges + conf_num_sets;
157 /* Not completely fair, but good enough for our use-case. */
158 long rnd = lrand48 () % conf_num_total;
160 long value = lrand48 ();
167 if (rnd < conf_num_counters)
171 value = (value % 8) + 1;
173 else if (rnd < (conf_num_counters + conf_num_timers))
177 value = (value % 1024) + 1;
179 else if (rnd < (conf_num_counters + conf_num_timers + conf_num_gauges))
183 value = (value % 128) - 64;
189 value %= conf_set_size;
192 buffer_size = snprintf (buffer, sizeof (buffer), "%06li:%li|%s",
194 assert (buffer_size > 0);
195 if (((size_t) buffer_size) >= sizeof (buffer))
197 assert (buffer[buffer_size] == 0);
199 status = send (sock, buffer, (size_t) buffer_size, /* flags = */ 0);
202 fprintf (stderr, "send failed: %s", strerror (errno));
207 } /* }}} int send_random_event */
209 static int get_integer_opt (const char *str, int *ret_value) /* {{{ */
216 tmp = (int) strtol (str, &endptr, /* base = */ 0);
219 fprintf (stderr, "Unable to parse option as a number: \"%s\": %s\n",
220 str, strerror (errno));
223 else if (endptr == str)
225 fprintf (stderr, "Unable to parse option as a number: \"%s\"\n", str);
228 else if (*endptr != 0)
230 fprintf (stderr, "Garbage after end of value: \"%s\"\n", str);
236 } /* }}} int get_integer_opt */
238 static int read_options (int argc, char **argv) /* {{{ */
242 while ((opt = getopt (argc, argv, "c:t:g:s:S:d:D:h")) != -1)
247 get_integer_opt (optarg, &conf_num_counters);
251 get_integer_opt (optarg, &conf_num_timers);
255 get_integer_opt (optarg, &conf_num_gauges);
259 get_integer_opt (optarg, &conf_num_sets);
263 get_integer_opt (optarg, &conf_set_size);
271 conf_service = optarg;
275 exit_usage (EXIT_SUCCESS);
278 exit_usage (EXIT_FAILURE);
280 } /* while (getopt) */
283 } /* }}} int read_options */
285 int main (int argc, char **argv) /* {{{ */
287 read_options (argc, argv);
289 sigint_action.sa_handler = signal_handler;
290 sigaction (SIGINT, &sigint_action, /* old = */ NULL);
292 sigterm_action.sa_handler = signal_handler;
293 sigaction (SIGTERM, &sigterm_action, /* old = */ NULL);
299 send_random_event ();
309 /* vim: set sw=2 sts=2 et fdm=marker : */