2 * collectd - src/olsrd.c
3 * Copyright (C) 2009 Florian octo Forster
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 * Florian octo Forster <octo at collectd.org>
32 #include <sys/types.h>
34 #include <netinet/in.h>
35 #include <netinet/tcp.h>
37 #define OLSRD_DEFAULT_NODE "localhost"
38 #define OLSRD_DEFAULT_SERVICE "2006"
40 static const char *config_keys[] =
48 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
50 static char *config_node = NULL;
51 static char *config_service = NULL;
53 #define OLSRD_WANT_NOT 0
54 #define OLSRD_WANT_SUMMARY 1
55 #define OLSRD_WANT_DETAIL 2
56 static int config_want_links = OLSRD_WANT_DETAIL;
57 static int config_want_routes = OLSRD_WANT_SUMMARY;
58 static int config_want_topology = OLSRD_WANT_SUMMARY;
60 static const char *olsrd_get_node (void) /* {{{ */
62 if (config_node != NULL)
64 return (OLSRD_DEFAULT_NODE);
65 } /* }}} const char *olsrd_get_node */
67 static const char *olsrd_get_service (void) /* {{{ */
69 if (config_service != NULL)
70 return (config_service);
71 return (OLSRD_DEFAULT_SERVICE);
72 } /* }}} const char *olsrd_get_service */
74 static void olsrd_set_node (const char *node) /* {{{ */
83 } /* }}} void olsrd_set_node */
85 static void olsrd_set_service (const char *service) /* {{{ */
90 tmp = strdup (service);
94 } /* }}} void olsrd_set_service */
96 static void olsrd_set_detail (int *varptr, const char *detail, /* {{{ */
99 if (strcasecmp ("No", detail) == 0)
100 *varptr = OLSRD_WANT_NOT;
101 else if (strcasecmp ("Summary", detail) == 0)
102 *varptr = OLSRD_WANT_SUMMARY;
103 else if (strcasecmp ("Detail", detail) == 0)
104 *varptr = OLSRD_WANT_DETAIL;
107 ERROR ("olsrd plugin: Invalid argument given to the `%s' configuration "
108 "option: `%s'. Expected: `No', `Summary', or `Detail'.",
111 } /* }}} void olsrd_set_detail */
113 /* Strip trailing newline characters. Returns length of string. */
114 static size_t strchomp (char *buffer) /* {{{ */
118 buffer_len = strlen (buffer);
119 while ((buffer_len > 0)
120 && ((buffer[buffer_len - 1] == '\r')
121 || (buffer[buffer_len - 1] == '\n')))
124 buffer[buffer_len] = 0;
128 } /* }}} size_t strchomp */
130 static size_t strtabsplit (char *string, char **fields, size_t size) /* {{{ */
139 while ((fields[i] = strtok_r (ptr, " \t\r\n", &saveptr)) != NULL)
149 } /* }}} size_t strtabsplit */
151 static FILE *olsrd_connect (void) /* {{{ */
153 struct addrinfo ai_hints = { 0 };
154 struct addrinfo *ai_list, *ai_ptr;
160 ai_hints.ai_flags |= AI_ADDRCONFIG;
162 ai_hints.ai_family = PF_UNSPEC;
163 ai_hints.ai_socktype = SOCK_STREAM;
164 ai_hints.ai_protocol = IPPROTO_TCP;
167 ai_return = getaddrinfo (olsrd_get_node (), olsrd_get_service (),
168 &ai_hints, &ai_list);
171 ERROR ("olsrd plugin: getaddrinfo (%s, %s) failed: %s",
172 olsrd_get_node (), olsrd_get_service (),
173 gai_strerror (ai_return));
178 for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
184 fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
187 ERROR ("olsrd plugin: socket failed: %s",
188 sstrerror (errno, errbuf, sizeof (errbuf)));
192 status = connect (fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
195 ERROR ("olsrd plugin: connect failed: %s",
196 sstrerror (errno, errbuf, sizeof (errbuf)));
201 fh = fdopen (fd, "r+");
204 ERROR ("olsrd plugin: fdopen failed.");
212 freeaddrinfo (ai_list);
215 } /* }}} FILE *olsrd_connect */
217 __attribute__ ((nonnull(2)))
218 static void olsrd_submit (const char *plugin_instance, /* {{{ */
219 const char *type, const char *type_instance, gauge_t value)
222 value_list_t vl = VALUE_LIST_INIT;
224 values[0].gauge = value;
229 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
230 sstrncpy (vl.plugin, "olsrd", sizeof (vl.plugin));
231 if (plugin_instance != NULL)
232 sstrncpy (vl.plugin_instance, plugin_instance,
233 sizeof (vl.plugin_instance));
234 sstrncpy (vl.type, type, sizeof (vl.type));
235 if (type_instance != NULL)
236 sstrncpy (vl.type_instance, type_instance,
237 sizeof (vl.type_instance));
239 plugin_dispatch_values (&vl);
240 } /* }}} void olsrd_submit */
242 static int olsrd_cb_ignore (int lineno, /* {{{ */
243 size_t fields_num, char **fields)
246 } /* }}} int olsrd_cb_ignore */
248 static int olsrd_cb_links (int lineno, /* {{{ */
249 size_t fields_num, char **fields)
259 static uint32_t links_num;
260 static double lq_sum;
261 static uint32_t lq_num;
262 static double nlq_sum;
263 static uint32_t nlq_num;
270 if (config_want_links == OLSRD_WANT_NOT)
273 /* Special handling of the first line. */
285 /* Special handling of the last line. */
288 DEBUG ("olsrd plugin: Number of links: %"PRIu32, links_num);
289 olsrd_submit (/* p.-inst = */ "links", /* type = */ "links",
290 /* t.-inst = */ NULL, (gauge_t) links_num);
294 lq = lq_sum / ((double) lq_num);
295 DEBUG ("olsrd plugin: Average LQ: %g", lq);
296 olsrd_submit (/* p.-inst = */ "links", /* type = */ "signal_quality",
301 nlq = nlq_sum / ((double) nlq_num);
302 DEBUG ("olsrd plugin: Average NLQ: %g", nlq);
303 olsrd_submit (/* p.-inst = */ "links", /* type = */ "signal_quality",
316 lq = strtod (fields[3], &endptr);
317 if ((errno != 0) || (endptr == fields[3]))
319 ERROR ("olsrd plugin: Cannot parse link quality: %s", fields[3]);
329 if (config_want_links == OLSRD_WANT_DETAIL)
331 char type_instance[DATA_MAX_NAME_LEN];
333 ssnprintf (type_instance, sizeof (type_instance), "%s-%s-lq",
334 fields[0], fields[1]);
336 DEBUG ("olsrd plugin: links: type_instance = %s; lq = %g;",
338 olsrd_submit (/* p.-inst = */ "links", /* type = */ "signal_quality",
345 nlq = strtod (fields[4], &endptr);
346 if ((errno != 0) || (endptr == fields[4]))
348 ERROR ("olsrd plugin: Cannot parse neighbor link quality: %s", fields[4]);
358 if (config_want_links == OLSRD_WANT_DETAIL)
360 char type_instance[DATA_MAX_NAME_LEN];
362 ssnprintf (type_instance, sizeof (type_instance), "%s-%s-rx",
363 fields[0], fields[1]);
365 DEBUG ("olsrd plugin: links: type_instance = %s; nlq = %g;",
367 olsrd_submit (/* p.-inst = */ "links", /* type = */ "signal_quality",
373 } /* }}} int olsrd_cb_links */
375 static int olsrd_cb_routes (int lineno, /* {{{ */
376 size_t fields_num, char **fields)
385 static uint32_t routes_num;
386 static uint32_t metric_sum;
387 static uint32_t metric_num;
388 static double etx_sum;
389 static uint32_t etx_num;
395 if (config_want_routes == OLSRD_WANT_NOT)
398 /* Special handling of the first line */
410 /* Special handling after the last line */
415 DEBUG ("olsrd plugin: Number of routes: %"PRIu32, routes_num);
416 olsrd_submit (/* p.-inst = */ "routes", /* type = */ "routes",
417 /* t.-inst = */ NULL, (gauge_t) routes_num);
421 metric_avg = ((double) metric_sum) / ((double) metric_num);
422 DEBUG ("olsrd plugin: Average metric: %g", metric_avg);
423 olsrd_submit (/* p.-inst = */ "routes", /* type = */ "route_metric",
424 "average", metric_avg);
428 etx = etx_sum / ((double) etx_sum);
429 DEBUG ("olsrd plugin: Average ETX: %g", etx);
430 olsrd_submit (/* p.-inst = */ "routes", /* type = */ "route_etx",
443 metric = (uint32_t) strtoul (fields[2], &endptr, 0);
444 if ((errno != 0) || (endptr == fields[2]))
446 ERROR ("olsrd plugin: Unable to parse metric: %s", fields[2]);
451 metric_sum += metric;
453 if (config_want_routes == OLSRD_WANT_DETAIL)
455 DEBUG ("olsrd plugin: destination = %s; metric = %"PRIu32";",
457 olsrd_submit (/* p.-inst = */ "routes", /* type = */ "route_metric",
458 /* t.-inst = */ fields[0], (gauge_t) metric);
464 etx = strtod (fields[3], &endptr);
465 if ((errno != 0) || (endptr == fields[3]))
467 ERROR ("olsrd plugin: Unable to parse ETX: %s", fields[3]);
477 if (config_want_routes == OLSRD_WANT_DETAIL)
479 DEBUG ("olsrd plugin: destination = %s; etx = %g;",
481 olsrd_submit (/* p.-inst = */ "routes", /* type = */ "route_etx",
482 /* t.-inst = */ fields[0], etx);
487 } /* }}} int olsrd_cb_routes */
489 static int olsrd_cb_topology (int lineno, /* {{{ */
490 size_t fields_num, char **fields)
499 static double lq_sum;
500 static uint32_t lq_num;
502 static uint32_t links_num;
507 if (config_want_topology == OLSRD_WANT_NOT)
510 /* Special handling of the first line */
520 /* Special handling after the last line */
523 DEBUG ("olsrd plugin: topology: Number of links: %"PRIu32, links_num);
524 olsrd_submit (/* p.-inst = */ "topology", /* type = */ "links",
525 /* t.-inst = */ NULL, (gauge_t) links_num);
529 lq = lq_sum / ((double) lq_sum);
530 DEBUG ("olsrd plugin: topology: Average link quality: %g", lq);
531 olsrd_submit (/* p.-inst = */ "topology", /* type = */ "signal_quality",
532 /* t.-inst = */ "average", lq);
544 lq = strtod (fields[2], &endptr);
545 if ((errno != 0) || (endptr == fields[2]))
547 ERROR ("olsrd plugin: Unable to parse LQ: %s", fields[2]);
557 if (config_want_topology == OLSRD_WANT_DETAIL)
559 char type_instance[DATA_MAX_NAME_LEN] = { 0 };
561 ssnprintf (type_instance, sizeof (type_instance), "%s-%s-lq",
562 fields[0], fields[1]);
563 DEBUG ("olsrd plugin: type_instance = %s; lq = %g;", type_instance, lq);
564 olsrd_submit (/* p.-inst = */ "topology", /* type = */ "signal_quality",
569 if (config_want_topology == OLSRD_WANT_DETAIL)
575 nlq = strtod (fields[3], &endptr);
576 if ((errno != 0) || (endptr == fields[3]))
578 ERROR ("olsrd plugin: Unable to parse NLQ: %s", fields[3]);
582 char type_instance[DATA_MAX_NAME_LEN] = { 0 };
584 ssnprintf (type_instance, sizeof (type_instance), "%s-%s-nlq",
585 fields[0], fields[1]);
586 DEBUG ("olsrd plugin: type_instance = %s; nlq = %g;", type_instance, nlq);
587 olsrd_submit (/* p.-inst = */ "topology", /* type = */ "signal_quality",
593 } /* }}} int olsrd_cb_topology */
595 static int olsrd_read_table (FILE *fh, /* {{{ */
596 int (*callback) (int lineno, size_t fields_num, char **fields))
607 while (fgets (buffer, sizeof (buffer), fh) != NULL)
609 /* An empty line ends the table. */
610 buffer_len = strchomp (buffer);
613 (*callback) (lineno, /* fields_num = */ 0, /* fields = */ NULL);
617 fields_num = strtabsplit (buffer, fields, STATIC_ARRAY_SIZE (fields));
619 (*callback) (lineno, fields_num, fields);
621 } /* while (fgets) */
624 } /* }}} int olsrd_read_table */
626 static int olsrd_config (const char *key, const char *value) /* {{{ */
628 if (strcasecmp ("Host", key) == 0)
629 olsrd_set_node (value);
630 else if (strcasecmp ("Port", key) == 0)
631 olsrd_set_service (value);
632 else if (strcasecmp ("CollectLinks", key) == 0)
633 olsrd_set_detail (&config_want_links, value, key);
634 else if (strcasecmp ("CollectRoutes", key) == 0)
635 olsrd_set_detail (&config_want_routes, value, key);
636 else if (strcasecmp ("CollectTopology", key) == 0)
637 olsrd_set_detail (&config_want_topology, value, key);
640 ERROR ("olsrd plugin: Unknown configuration option given: %s", key);
645 } /* }}} int olsrd_config */
647 static int olsrd_read (void) /* {{{ */
653 fh = olsrd_connect ();
660 while (fgets (buffer, sizeof (buffer), fh) != NULL)
662 buffer_len = strchomp (buffer);
666 if (strcmp ("Table: Links", buffer) == 0)
667 olsrd_read_table (fh, olsrd_cb_links);
668 else if (strcmp ("Table: Neighbors", buffer) == 0)
669 olsrd_read_table (fh, olsrd_cb_ignore);
670 else if (strcmp ("Table: Topology", buffer) == 0)
671 olsrd_read_table (fh, olsrd_cb_topology);
672 else if (strcmp ("Table: HNA", buffer) == 0)
673 olsrd_read_table (fh, olsrd_cb_ignore);
674 else if (strcmp ("Table: MID", buffer) == 0)
675 olsrd_read_table (fh, olsrd_cb_ignore);
676 else if (strcmp ("Table: Routes", buffer) == 0)
677 olsrd_read_table (fh, olsrd_cb_routes);
678 else if ((strcmp ("HTTP/1.0 200 OK", buffer) == 0)
679 || (strcmp ("Content-type: text/plain", buffer) == 0))
685 DEBUG ("olsrd plugin: Unable to handle line: %s", buffer);
687 } /* while (fgets) */
692 } /* }}} int olsrd_read */
694 static int olsrd_shutdown (void) /* {{{ */
697 sfree (config_service);
700 } /* }}} int olsrd_shutdown */
702 void module_register (void)
704 plugin_register_config ("olsrd", olsrd_config,
705 config_keys, config_keys_num);
706 plugin_register_read ("olsrd", olsrd_read);
707 plugin_register_shutdown ("olsrd", olsrd_shutdown);
708 } /* void module_register */
710 /* vim: set sw=2 sts=2 et fdm=marker : */