Code

collectd-tg: Improve handling of integer command line args.
[collectd.git] / src / collectd-tg.c
1 /**
2  * collectd-td - collectd traffic generator
3  * Copyright (C) 2010  Florian octo Forster
4  *
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.
8  *
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.
13  *
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
17  *
18  * Authors:
19  *   Florian Forster <ff at octo.it>
20  **/
22 #if HAVE_CONFIG_H
23 # include "config.h"
24 #endif
26 #ifndef _ISOC99_SOURCE
27 # define _ISOC99_SOURCE
28 #endif
30 #ifndef _POSIX_C_SOURCE
31 # define _POSIX_C_SOURCE 200809L
32 #endif
34 #ifndef _XOPEN_SOURCE
35 # define _XOPEN_SOURCE 700
36 #endif
38 #if !__GNUC__
39 # define __attribute__(x) /**/
40 #endif
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <time.h>
47 #include <signal.h>
48 #include <errno.h>
50 #include "utils_heap.h"
52 #include "libcollectdclient/collectd/client.h"
53 #include "libcollectdclient/collectd/network.h"
54 #include "libcollectdclient/collectd/network_buffer.h"
56 #define DEF_NUM_HOSTS 1000
57 #define DEF_NUM_PLUGINS 20
58 #define DEF_NUM_VALUES 100000
60 static int conf_num_hosts = DEF_NUM_HOSTS;
61 static int conf_num_plugins = DEF_NUM_PLUGINS;
62 static int conf_num_values = DEF_NUM_VALUES;
63 static const char *conf_destination = NET_DEFAULT_V6_ADDR;
64 static const char *conf_service = NET_DEFAULT_PORT;
66 static lcc_network_t *net;
68 static c_heap_t *values_heap = NULL;
70 static struct sigaction sigint_action;
71 static struct sigaction sigterm_action;
73 static _Bool loop = 1;
75 __attribute__((noreturn))
76 static void exit_usage (int exit_status) /* {{{ */
77 {
78   fprintf ((exit_status == EXIT_FAILURE) ? stderr : stdout,
79       "collectd-tg -- collectd traffic generator\n"
80       "\n"
81       "  Usage: collectd-ng [OPTION]\n"
82       "\n"
83       "  Valid options:\n"
84       "    -n <number>    Number of value lists. (Default: %i)\n"
85       "    -H <number>    Number of hosts to emulate. (Default: %i)\n"
86       "    -p <number>    Number of plugins to emulate. (Default: %i)\n"
87       "    -d <dest>      Destination address of the network packets.\n"
88       "                   (Default: %s)\n"
89       "    -D <port>      Destination port of the network packets.\n"
90       "                   (Default: %s)\n"
91       "    -h             Print usage information (this output).\n"
92       "\n"
93       "Copyright (C) 2010  Florian Forster\n"
94       "Licensed under the GNU General Public License, version 2 (GPLv2)\n",
95       DEF_NUM_VALUES, DEF_NUM_HOSTS, DEF_NUM_PLUGINS,
96       NET_DEFAULT_V6_ADDR, NET_DEFAULT_PORT);
97   exit (exit_status);
98 } /* }}} void exit_usage */
100 static void signal_handler (int signal) /* {{{ */
102   loop = 0;
103 } /* }}} void signal_handler */
105 static int compare_time (const void *v0, const void *v1) /* {{{ */
107   const lcc_value_list_t *vl0 = v0;
108   const lcc_value_list_t *vl1 = v1;
110   if (vl0->time < vl1->time)
111     return (-1);
112   else if (vl0->time > vl1->time)
113     return (1);
114   else
115     return (0);
116 } /* }}} int compare_time */
118 static int get_boundet_random (int min, int max) /* {{{ */
120   int range;
122   if (min >= max)
123     return (-1);
124   if (min == (max - 1))
125     return (min);
127   range = max - min;
129   return (min + ((int) (((double) range) * ((double) random ()) / (((double) RAND_MAX) + 1.0))));
130 } /* }}} int get_boundet_random */
132 #if 0
133 static int dump_network_buffer (void) /* {{{ */
135   char buffer[LCC_NETWORK_BUFFER_SIZE_DEFAULT];
136   size_t buffer_size;
137   int status;
138   size_t offset;
140   memset (buffer, 0, sizeof (buffer));
141   buffer_size = sizeof (buffer);
143   status = lcc_network_buffer_get (nb, buffer, &buffer_size);
144   if (status != 0)
145   {
146     fprintf (stderr, "lcc_network_buffer_get failed with status %i.\n",
147         status);
148     return (status);
149   }
151   if (buffer_size > sizeof (buffer))
152     buffer_size = sizeof (buffer);
154   for (offset = 0; offset < buffer_size; offset += 16)
155   {
156     size_t i;
158     for (i = 0; (i < 16) && ((offset + i) < buffer_size); i++)
159     {
160       uint8_t v = (uint8_t) buffer[offset + i];
161       printf ("%02"PRIx8" ", v);
162     }
163     for (; i < 16; i++)
164       printf ("   ");
165     printf ("   ");
166     for (i = 0; (i < 16) && ((offset + i) < buffer_size); i++)
167     {
168       uint8_t v = (uint8_t) buffer[offset + i];
169       if ((v >= 32) && (v < 128))
170         printf ("%c", (int) buffer[offset + i]);
171       else
172         printf (".");
173     }
174     printf ("\n");
175   }
177   return (0);
178 } /* }}} int dump_network_buffer */
179 #endif
181 static lcc_value_list_t *create_value_list (void) /* {{{ */
183   lcc_value_list_t *vl;
184   int host_num;
186   vl = malloc (sizeof (*vl));
187   if (vl == NULL)
188   {
189     fprintf (stderr, "malloc failed.\n");
190     return (NULL);
191   }
192   memset (vl, 0, sizeof (*vl));
194   vl->values = calloc (/* nmemb = */ 1, sizeof (*vl->values));
195   if (vl->values == NULL)
196   {
197     fprintf (stderr, "calloc failed.\n");
198     free (vl);
199     return (NULL);
200   }
202   vl->values_types = calloc (/* nmemb = */ 1, sizeof (*vl->values_types));
203   if (vl->values_types == NULL)
204   {
205     fprintf (stderr, "calloc failed.\n");
206     free (vl->values);
207     free (vl);
208     return (NULL);
209   }
211   vl->values_len = 1;
213   host_num = get_boundet_random (0, conf_num_hosts);
215   vl->interval = 10;
216   vl->time = time (NULL) - (host_num % vl->interval);
218   if (get_boundet_random (0, 2) == 0)
219     vl->values_types[0] = LCC_TYPE_GAUGE;
220   else
221     vl->values_types[0] = LCC_TYPE_DERIVE;
223   snprintf (vl->identifier.host, sizeof (vl->identifier.host),
224       "host%04i", host_num);
225   snprintf (vl->identifier.plugin, sizeof (vl->identifier.plugin),
226       "plugin%03i", get_boundet_random (0, conf_num_plugins));
227   strncpy (vl->identifier.type,
228       (vl->values_types[0] == LCC_TYPE_GAUGE) ? "gauge" : "derive",
229       sizeof (vl->identifier.type));
230   snprintf (vl->identifier.type_instance, sizeof (vl->identifier.type_instance),
231       "ti%li", random ());
233   return (vl);
234 } /* }}} int create_value_list */
236 static void destroy_value_list (lcc_value_list_t *vl) /* {{{ */
238   if (vl == NULL)
239     return;
241   free (vl->values);
242   free (vl->values_types);
243   free (vl);
244 } /* }}} void destroy_value_list */
246 static int send_value (lcc_value_list_t *vl) /* {{{ */
248   int status;
250   if (vl->values_types[0] == LCC_TYPE_GAUGE)
251     vl->values[0].gauge = 100.0 * ((gauge_t) random ()) / (((gauge_t) RAND_MAX) + 1.0);
252   else
253     vl->values[0].derive += get_boundet_random (0, 100);
255   status = lcc_network_values_send (net, vl);
256   if (status != 0)
257     fprintf (stderr, "lcc_network_values_send failed with status %i.\n", status);
259   vl->time += vl->interval;
261   return (0);
262 } /* }}} int send_value */
264 static int get_integer_opt (const char *str, int *ret_value) /* {{{ */
266   char *endptr;
267   int tmp;
269   errno = 0;
270   endptr = NULL;
271   tmp = (int) strtol (str, &endptr, /* base = */ 0);
272   if (errno != 0)
273   {
274     fprintf (stderr, "Unable to parse option as a number: \"%s\": %s\n",
275         str, strerror (errno));
276     exit (EXIT_FAILURE);
277   }
278   else if (endptr == str)
279   {
280     fprintf (stderr, "Unable to parse option as a number: \"%s\"\n", str);
281     exit (EXIT_FAILURE);
282   }
283   else if (*endptr != 0)
284   {
285     fprintf (stderr, "Garbage after end of value: \"%s\"\n", str);
286     exit (EXIT_FAILURE);
287   }
289   *ret_value = tmp;
290   return (0);
291 } /* }}} int get_integer_opt */
293 static int read_options (int argc, char **argv) /* {{{ */
295   int opt;
297   while ((opt = getopt (argc, argv, "n:H:p:i:d:D:h")) != -1)
298   {
299     switch (opt)
300     {
301       case 'n':
302         get_integer_opt (optarg, &conf_num_values);
303         break;
305       case 'H':
306         get_integer_opt (optarg, &conf_num_hosts);
307         break;
309       case 'p':
310         get_integer_opt (optarg, &conf_num_plugins);
311         break;
313       case 'd':
314         conf_destination = optarg;
315         break;
317       case 'D':
318         conf_service = optarg;
319         break;
321       case 'h':
322         exit_usage (EXIT_SUCCESS);
324       default:
325         exit_usage (EXIT_FAILURE);
326     } /* switch (opt) */
327   } /* while (getopt) */
329   return (0);
330 } /* }}} int read_options */
332 int main (int argc, char **argv) /* {{{ */
334   int i;
335   time_t last_time;
336   int values_sent = 0;
338   read_options (argc, argv);
340   sigint_action.sa_handler = signal_handler;
341   sigaction (SIGINT, &sigint_action, /* old = */ NULL);
343   sigterm_action.sa_handler = signal_handler;
344   sigaction (SIGTERM, &sigterm_action, /* old = */ NULL);
347   values_heap = c_heap_create (compare_time);
348   if (values_heap == NULL)
349   {
350     fprintf (stderr, "c_heap_create failed.\n");
351     exit (EXIT_FAILURE);
352   }
354   net = lcc_network_create ();
355   if (net == NULL)
356   {
357     fprintf (stderr, "lcc_network_create failed.\n");
358     exit (EXIT_FAILURE);
359   }
360   else
361   {
362     lcc_server_t *srv;
363     
364     srv = lcc_server_create (net, conf_destination, conf_service);
365     if (srv == NULL)
366     {
367       fprintf (stderr, "lcc_server_create failed.\n");
368       exit (EXIT_FAILURE);
369     }
371     lcc_server_set_ttl (srv, 42);
372 #if 0
373     lcc_server_set_security_level (srv, ENCRYPT,
374         "admin", "password1");
375 #endif
376   }
378   fprintf (stdout, "Creating %i values ... ", conf_num_values);
379   fflush (stdout);
380   for (i = 0; i < conf_num_values; i++)
381   {
382     lcc_value_list_t *vl;
384     vl = create_value_list ();
385     if (vl == NULL)
386     {
387       fprintf (stderr, "create_value_list failed.\n");
388       exit (EXIT_FAILURE);
389     }
391     c_heap_insert (values_heap, vl);
392   }
393   fprintf (stdout, "done\n");
395   last_time = 0;
396   while (loop)
397   {
398     lcc_value_list_t *vl = c_heap_get_root (values_heap);
400     if (vl == NULL)
401       break;
403     if (vl->time != last_time)
404     {
405       printf ("%i values have been sent.\n", values_sent);
407       /* Check if we need to sleep */
408       time_t now = time (NULL);
410       while (now < vl->time)
411       {
412         /* 1 / 100 second */
413         struct timespec ts = { 0, 10000000 };
414         nanosleep (&ts, /* remaining = */ NULL);
415         now = time (NULL);
416       }
417       last_time = vl->time;
418     }
420     send_value (vl);
421     values_sent++;
423     c_heap_insert (values_heap, vl);
424   }
426   fprintf (stdout, "Shutting down.\n");
427   fflush (stdout);
429   while (42)
430   {
431     lcc_value_list_t *vl = c_heap_get_root (values_heap);
432     if (vl == NULL)
433       break;
434     destroy_value_list (vl);
435   }
436   c_heap_destroy (values_heap);
438   lcc_network_destroy (net);
439   exit (EXIT_SUCCESS);
440   return (0);
441 } /* }}} int main */
443 /* vim: set sw=2 sts=2 et fdm=marker : */