AC_CHECK_HEADERS(sys/types.h)
AC_CHECK_HEADERS(sys/socket.h)
AC_CHECK_HEADERS(sys/select.h)
-AC_CHECK_HEADERS(sys/poll.h)
+AC_CHECK_HEADERS(poll.h)
AC_CHECK_HEADERS(netdb.h)
AC_CHECK_HEADERS(arpa/inet.h)
AC_CHECK_HEADERS(sys/resource.h)
AC_COLLECTD([memory], [disable], [module], [memory statistics])
AC_COLLECTD([multimeter],[disable], [module], [multimeter statistics])
AC_COLLECTD([mysql], [disable], [module], [mysql statistics])
+AC_COLLECTD([network], [disable], [module], [network functionality])
AC_COLLECTD([nfs], [disable], [module], [nfs statistics])
AC_COLLECTD([ntpd], [disable], [module], [nfs statistics])
AC_COLLECTD([ping], [disable], [module], [ping statistics])
memory . . . . . . $enable_memory
multimeter . . . . $enable_multimeter
mysql . . . . . . . $enable_mysql
+ network . . . . . . $enable_network
nfs . . . . . . . . $enable_nfs
ntpd . . . . . . . $enable_ntpd
ping . . . . . . . $enable_ping
collectd_SOURCES = collectd.c collectd.h \
utils_debug.c utils_debug.h \
utils_mount.c utils_mount.h \
+ utils_llist.c utils_llist.h \
utils_ignorelist.c utils_ignorelist.h \
common.c common.h \
- network.c network.h \
plugin.c plugin.h \
configfile.c configfile.h
collectd_CPPFLAGS = $(LTDLINCL)
# Link to these libraries..
collectd_LDFLAGS = -export-dynamic
-if BUILD_WITH_RRDTOOL
-collectd_LDFLAGS += -lm -lrrd
-endif
if BUILD_WITH_LIBRT
collectd_LDFLAGS += -lrt
endif
collectd_DEPENDENCIES += mysql.la
endif
+if BUILD_MODULE_NETWORK
+pkglib_LTLIBRARIES += network.la
+network_la_SOURCES = network.c
+network_la_LDFLAGS = -module -avoid-version
+if BUILD_WITH_LIBSOCKET
+network_la_LDFLAGS += -lsocket
+endif
+if BUILD_WITH_LIBPTHREAD
+network_la_LDFLAGS += -lpthread
+endif
+collectd_LDADD += "-dlopen" network.la
+collectd_DEPENDENCIES += network.la
+endif
+
if BUILD_MODULE_NFS
pkglib_LTLIBRARIES += nfs.la
nfs_la_SOURCES = nfs.c
collectd_DEPENDENCIES += processes.la
endif
+if BUILD_WITH_RRDTOOL
+pkglib_LTLIBRARIES += rrdtool.la
+rrdtool_la_SOURCES = rrdtool.c
+rrdtool_la_LDFLAGS = -module -avoid-version -lrrd
+collectd_LDADD += "-dlopen" rrdtool.la
+collectd_DEPENDENCIES += rrdtool.la
+endif
+
if BUILD_MODULE_SENSORS
pkglib_LTLIBRARIES += sensors.la
sensors_la_SOURCES = sensors.c
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Free Software Foundation; only version 2 of the License is applicable.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
#if HAVE_LIBRRD
static int start_server (void)
{
+ /* FIXME */
+#if 0
char *host;
char *type;
char *instance;
if (values != NULL) free (values); values = NULL;
}
+#endif
return (0);
} /* static int start_server (void) */
#endif /* HAVE_LIBRRD */
=back
+=head2 Plugin C<rrdtool>
+
+=over 4
+
+=item B<CacheTimeout> I<Seconds>
+
+If this option is set to a value greater than zero, the C<rrdtool>-plugin will
+write values every I<Seconds> seconds to the RRD-files. Writing multiple values
+at once reduces IO-operations and thus lessens the load produced by updating
+the files. The tradeoff is that the graphs kind of "drag behind" and that more
+memory is used.
+
+=back
+
=head2 Plugin C<sensors>
=over 4
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Free Software Foundation; only version 2 of the License is applicable.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
# include <math.h>
#endif
+/* for ntohl and htonl */
+#if HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
extern int operating_mode;
#ifdef HAVE_LIBKSTAT
extern kstat_ctl_t *kc;
#endif
-#ifdef HAVE_LIBRRD
-#if 0
-static char *rra_def[] =
-{
- "RRA:AVERAGE:0.0:1:1500",
- "RRA:AVERAGE:0.2:6:1500",
- "RRA:AVERAGE:0.1:180:1680",
- "RRA:AVERAGE:0.1:2160:1520",
- "RRA:MIN:0.0:1:1500",
- "RRA:MIN:0.2:6:1500",
- "RRA:MIN:0.1:180:1680",
- "RRA:MIN:0.1:2160:1520",
- "RRA:MAX:0.0:1:1500",
- "RRA:MAX:0.2:6:1500",
- "RRA:MAX:0.1:180:1680",
- "RRA:MAX:0.1:2160:1520",
- NULL
-};
-static int rra_num = 12;
-#endif
-
-static int rra_timespans[] =
-{
- 3600,
- 86400,
- 604800,
- 2678400,
- 31622400,
- 0
-};
-static int rra_timespans_num = 5;
-
-static char *rra_types[] =
-{
- "AVERAGE",
- "MIN",
- "MAX",
- NULL
-};
-static int rra_types_num = 3;
-#endif /* HAVE_LIBRRD */
-
void sstrncpy (char *d, const char *s, int len)
{
strncpy (d, s, len);
return (0);
}
-static int check_create_dir (const char *file_orig)
+int check_create_dir (const char *file_orig)
{
struct stat statbuf;
return (0);
}
-/* * * * *
- * Magic *
- * * * * */
-#if HAVE_LIBRRD
-static int rra_get (char ***ret)
-{
- static char **rra_def = NULL;
- static int rra_num = 0;
-
- int rra_max = rra_timespans_num * rra_types_num;
-
- int step;
- int rows;
- int span;
-
- int cdp_num;
- int cdp_len;
- int i, j;
-
- char buffer[64];
-
- if ((rra_num != 0) && (rra_def != NULL))
- {
- *ret = rra_def;
- return (rra_num);
- }
-
- if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
- return (-1);
- memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
-
- step = atoi (COLLECTD_STEP);
- rows = atoi (COLLECTD_ROWS);
-
- if ((step <= 0) || (rows <= 0))
- {
- *ret = NULL;
- return (-1);
- }
-
- cdp_len = 0;
- for (i = 0; i < rra_timespans_num; i++)
- {
- span = rra_timespans[i];
-
- if ((span / step) < rows)
- continue;
-
- if (cdp_len == 0)
- cdp_len = 1;
- else
- cdp_len = (int) floor (((double) span) / ((double) (rows * step)));
-
- cdp_num = (int) ceil (((double) span) / ((double) (cdp_len * step)));
-
- for (j = 0; j < rra_types_num; j++)
- {
- if (rra_num >= rra_max)
- break;
-
- if (snprintf (buffer, sizeof(buffer), "RRA:%s:%3.1f:%u:%u",
- rra_types[j], COLLECTD_XFF,
- cdp_len, cdp_num) >= sizeof (buffer))
- {
- syslog (LOG_ERR, "rra_get: Buffer would have been truncated.");
- continue;
- }
-
- rra_def[rra_num++] = sstrdup (buffer);
- }
- }
-
-#if COLLECT_DEBUG
- DBG ("rra_num = %i", rra_num);
- for (i = 0; i < rra_num; i++)
- DBG (" %s", rra_def[i]);
-#endif
-
- *ret = rra_def;
- return (rra_num);
-}
-#endif /* HAVE_LIBRRD */
-
static int log_create_file (char *filename, char **ds_def, int ds_num)
{
FILE *log;
return 0;
}
-static int log_update_file (char *host, char *file, char *values,
+int log_update_file (char *host, char *file, char *values,
char **ds_def, int ds_num)
{
char *tmp;
return (0);
} /* int log_update_file */
-#if HAVE_LIBRRD
-static int rrd_create_file (char *filename, char **ds_def, int ds_num)
-{
- char **argv;
- int argc;
- char **rra_def;
- int rra_num;
- int i, j;
- int status = 0;
-
- if (check_create_dir (filename))
- return (-1);
-
- if ((rra_num = rra_get (&rra_def)) < 1)
- {
- syslog (LOG_ERR, "rra_create failed: Could not calculate RRAs");
- return (-1);
- }
-
- argc = ds_num + rra_num + 4;
-
- if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
- {
- syslog (LOG_ERR, "rrd_create failed: %s", strerror (errno));
- return (-1);
- }
-
- argv[0] = "create";
- argv[1] = filename;
- argv[2] = "-s";
- argv[3] = COLLECTD_STEP;
-
- j = 4;
- for (i = 0; i < ds_num; i++)
- argv[j++] = ds_def[i];
- for (i = 0; i < rra_num; i++)
- argv[j++] = rra_def[i];
- argv[j] = NULL;
-
- optind = 0; /* bug in librrd? */
- rrd_clear_error ();
- if (rrd_create (argc, argv) == -1)
- {
- syslog (LOG_ERR, "rrd_create failed: %s: %s", filename, rrd_get_error ());
- status = -1;
- }
-
- free (argv);
-
- return (status);
-}
-#endif /* HAVE_LIBRRD */
-
-int rrd_update_file (char *host, char *file, char *values,
- char **ds_def, int ds_num)
-{
-#if HAVE_LIBRRD
- struct stat statbuf;
- char full_file[1024];
- char *argv[4] = { "update", full_file, values, NULL };
-#endif /* HAVE_LIBRRD */
-
- /* I'd rather have a function `common_update_file' to make this
- * decission, but for that we'd need to touch all plugins.. */
- if (operating_mode == MODE_LOG)
- return (log_update_file (host, file, values,
- ds_def, ds_num));
-
-#if HAVE_LIBRRD
- /* host == NULL => local mode */
- if (host != NULL)
- {
- if (snprintf (full_file, 1024, "%s/%s", host, file) >= 1024)
- return (-1);
- }
- else
- {
- if (snprintf (full_file, 1024, "%s", file) >= 1024)
- return (-1);
- }
-
- if (stat (full_file, &statbuf) == -1)
- {
- if (errno == ENOENT)
- {
- if (rrd_create_file (full_file, ds_def, ds_num))
- return (-1);
- }
- else
- {
- syslog (LOG_ERR, "stat %s: %s", full_file, strerror (errno));
- return (-1);
- }
- }
- else if (!S_ISREG (statbuf.st_mode))
- {
- syslog (LOG_ERR, "stat %s: Not a regular file!", full_file);
- return (-1);
- }
-
- optind = 0; /* bug in librrd? */
- rrd_clear_error ();
- if (rrd_update (3, argv) == -1)
- {
- syslog (LOG_WARNING, "rrd_update failed: %s: %s", full_file, rrd_get_error ());
- return (-1);
- }
- return (0);
-/* #endif HAVE_LIBRRD */
-
-#else
- syslog (LOG_ERR, "`rrd_update_file' was called, but collectd isn't linked against librrd!");
- return (-1);
-#endif
-}
#ifdef HAVE_LIBKSTAT
int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
return (retval);
}
#endif /* HAVE_LIBKSTAT */
+
+unsigned long long ntohll (unsigned long long n)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ return (n);
+#else
+ return (((unsigned long long) ntohl (n)) << 32) + ntohl (n >> 32);
+#endif
+}
+
+unsigned long long htonll (unsigned long long n)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ return (n);
+#else
+ return (((unsigned long long) htonl (n)) << 32) + htonl (n >> 32);
+#endif
+}
/* FIXME: `timeval_sub_timespec' needs a description */
int timeval_sub_timespec (struct timeval *tv0, struct timeval *tv1, struct timespec *ret);
-int rrd_update_file (char *host, char *file, char *values,
- char **ds_def, int ds_num);
+int check_create_dir (const char *file_orig);
#ifdef HAVE_LIBKSTAT
int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name);
long long get_kstat_value (kstat_t *ksp, char *name);
#endif
+unsigned long long ntohll (unsigned long long n);
+unsigned long long htonll (unsigned long long n);
+
#endif /* COMMON_H */
typedef struct cf_callback
{
- char *type;
- int (*callback) (char *, char *);
- char **keys;
+ const char *type;
+ int (*callback) (const char *, const char *);
+ const char **keys;
int keys_num;
struct cf_callback *next;
} cf_callback_t;
return (ret);
}
-void cf_unregister (char *type)
+void cf_unregister (const char *type)
{
cf_callback_t *this, *prev;
}
}
-void cf_register (char *type,
- int (*callback) (char *, char *),
- char **keys, int keys_num)
+void cf_register (const char *type,
+ int (*callback) (const char *, const char *),
+ const char **keys, int keys_num)
{
cf_callback_t *cf_cb;
char buf[64];
return (LC_CBRET_OKAY);
}
-static int cf_callback_socket (const char *shortvar, const char *var,
- const char *arguments, const char *value, lc_flags_t flags,
- void *extra)
-{
- char *buffer;
-
- char *fields[3];
- int numfields;
-
- char *node;
- char *service = NET_DEFAULT_PORT;
-
- DEBUG_CALLBACK (shortvar, var, arguments, value);
-
- buffer = strdup (value);
- if (buffer == NULL)
- return (LC_CBRET_ERROR);
-
- numfields = strsplit (buffer, fields, 3);
-
- if ((numfields != 1) && (numfields != 2))
- {
- syslog (LOG_ERR, "Invalid number of arguments to `%s'",
- shortvar);
- free (buffer);
- return (LC_CBRET_ERROR);
- }
-
- node = fields[0];
- if (numfields == 2)
- service = fields[1];
-
- /* Still return `LC_CBRET_OKAY' because this is not an syntax error */
- if (network_create_socket (node, service) < 1)
- syslog (LOG_ERR, "network_create_socket (%s, %s) failed",
- node, service);
-
- free (buffer);
-
- return (LC_CBRET_OKAY);
-}
-
/*
* `cf_callback_plugin'
* Start/end section `plugin'
lc_register_callback ("LoadPlugin", SHORTOPT_NONE,
LC_VAR_STRING, cf_callback_mode_loadmodule, NULL);
- lc_register_callback ("Listen", SHORTOPT_NONE,
- LC_VAR_STRING, cf_callback_socket, NULL);
- lc_register_callback ("Server", SHORTOPT_NONE,
- LC_VAR_STRING, cf_callback_socket, NULL);
-
for (i = 0; i < cf_mode_num; i++)
{
cf_mode_item_t *item;
* `type' Name of the plugin (must be the same as passed to
* `plugin_register'
*/
-void cf_unregister (char *type);
+void cf_unregister (const char *type);
/*
* DESCRIPTION
* exists for each `type' at any time. This means that `cf_register' may be
* called multiple times, but only the last call will have an effect.
*/
-void cf_register (char *type,
- int (*callback) (char *, char *),
- char **keys, int keys_num);
+void cf_register (const char *type,
+ int (*callback) (const char *, const char *),
+ const char **keys, int keys_num);
/*
* DESCRIPTION
#if HAVE_LIBPCAP && HAVE_LIBPTHREAD
# include <pthread.h>
# include <pcap.h>
-# include <sys/poll.h>
+# include <poll.h>
# define DNS_HAVE_READ 1
#else
# define DNS_HAVE_READ 0
#endif
#endif /* defined(HAVE_GETLOADAVG) */
-static char *load_file = "load.rrd";
-
-static char *ds_def[] =
+static data_source_t dsrc[3] =
{
- "DS:shortterm:GAUGE:"COLLECTD_HEARTBEAT":0:100",
- "DS:midterm:GAUGE:"COLLECTD_HEARTBEAT":0:100",
- "DS:longterm:GAUGE:"COLLECTD_HEARTBEAT":0:100",
- NULL
+ {"shortterm", DS_TYPE_GAUGE, 0.0, 100.0},
+ {"midterm", DS_TYPE_GAUGE, 0.0, 100.0},
+ {"longterm", DS_TYPE_GAUGE, 0.0, 100.0}
};
-static int ds_num = 3;
-
-static void load_init (void)
-{
- return;
-}
-static void load_write (char *host, char *inst, char *val)
+static data_set_t ds =
{
- rrd_update_file (host, load_file, val, ds_def, ds_num);
-}
+ "load", 3, dsrc
+};
#if LOAD_HAVE_READ
-#define BUFSIZE 256
static void load_submit (double snum, double mnum, double lnum)
{
- char buf[BUFSIZE];
-
- if (snprintf (buf, BUFSIZE, "%u:%.2f:%.2f:%.2f", (unsigned int) curtime,
- snum, mnum, lnum) >= BUFSIZE)
- return;
-
- plugin_submit (MODULE_NAME, "-", buf);
+ value_t values[3];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].gauge = snum;
+ values[1].gauge = mnum;
+ values[2].gauge = lnum;
+
+ vl.values = values;
+ vl.values_len = 3;
+ vl.time = time (NULL);
+ strcpy (vl.host, hostname);
+ strcpy (vl.plugin, "load");
+ strcpy (vl.plugin_instance, "");
+ strcpy (vl.type_instance, "");
+
+ plugin_dispatch_values ("load", &vl);
}
-#undef BUFSIZE
-static void load_read (void)
+static int load_read (void)
{
#if defined(HAVE_GETLOADAVG)
double load[3];
load_submit (snum, mnum, lnum);
#endif /* HAVE_LIBSTATGRAB */
+
+ return (0);
}
-#else
-# define load_read NULL
#endif /* LOAD_HAVE_READ */
void module_register (void)
{
- plugin_register (MODULE_NAME, load_init, load_read, load_write);
+ plugin_register_data_set (&ds);
+#if LOAD_HAVE_READ
+ plugin_register_read ("load", load_read);
+#endif
}
#undef MODULE_NAME
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Free Software Foundation; only version 2 of the License is applicable.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* Florian octo Forster <octo at verplant.org>
**/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <syslog.h>
-#include <errno.h>
-
-#include "network.h"
+#include "collectd.h"
+#include "plugin.h"
#include "common.h"
#include "configfile.h"
#include "utils_debug.h"
+#include "network.h"
+
+#if HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#if HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#if HAVE_POLL_H
+# include <poll.h>
+#endif
+
/* 1500 - 40 - 8 = Ethernet packet - IPv6 header - UDP header */
/* #define BUFF_SIZE 1452 */
#define BUFF_SIZE 4096
-extern int operating_mode;
-
+/*
+ * Private data types
+ */
typedef struct sockent
{
int fd;
- int mode;
struct sockaddr_storage *addr;
socklen_t addrlen;
struct sockent *next;
} sockent_t;
-static sockent_t *socklist_head = NULL;
+/* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-------+-----------------------+-------------------------------+
+ * ! Ver. ! ! Length !
+ * +-------+-----------------------+-------------------------------+
+ */
+struct part_header_s
+{
+ uint16_t type;
+ uint16_t length;
+};
+typedef struct part_header_s part_header_t;
+
+/* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-------------------------------+-------------------------------+
+ * ! Type ! Length !
+ * +-------------------------------+-------------------------------+
+ * : (Length - 4) Bytes :
+ * +---------------------------------------------------------------+
+ */
+struct part_string_s
+{
+ part_header_t *head;
+ char *value;
+};
+typedef struct part_string_s part_string_t;
+
+/* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-------------------------------+-------------------------------+
+ * ! Type ! Length !
+ * +-------------------------------+-------------------------------+
+ * : (Length - 4 == 2 || 4 || 8) Bytes :
+ * +---------------------------------------------------------------+
+ */
+struct part_number_s
+{
+ part_header_t *head;
+ uint64_t *value;
+};
+typedef struct part_number_s part_number_t;
+
+/* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-------------------------------+-------------------------------+
+ * ! Type ! Length !
+ * +-------------------------------+---------------+---------------+
+ * ! Num of values ! Type0 ! Type1 !
+ * +-------------------------------+---------------+---------------+
+ * ! Value0 !
+ * ! !
+ * +---------------------------------------------------------------+
+ * ! Value1 !
+ * ! !
+ * +---------------------------------------------------------------+
+ */
+struct part_values_s
+{
+ part_header_t *head;
+ uint16_t *num_values;
+ uint8_t *values_types;
+ value_t *values;
+};
+typedef struct part_values_s part_values_t;
+
+/*
+ * Private variables
+ */
+static const char *config_keys[] =
+{
+ "Listen",
+ "Server",
+ "TimeToLive",
+ NULL
+};
+static int config_keys_num = 3;
+
+static int network_config_ttl = 0;
+
+static sockent_t *sending_sockets = NULL;
+
+static struct pollfd *listen_sockets = NULL;
+static int listen_sockets_num = 0;
+static pthread_t listen_thread = 0;
+static int listen_loop = 0;
+
+/*
+ * Private functions
+ */
+static int write_part_values (char **ret_buffer, int *ret_buffer_len,
+ const data_set_t *ds, const value_list_t *vl)
+{
+ part_values_t pv;
+ int i;
+
+ i = 6 + (9 * vl->values_len);
+ if (*ret_buffer_len < i)
+ return (-1);
+ *ret_buffer_len -= i;
+
+ pv.head = (part_header_t *) *ret_buffer;
+ pv.num_values = (uint16_t *) (pv.head + 1);
+ pv.values_types = (uint8_t *) (pv.num_values + 1);
+ pv.values = (value_t *) (pv.values_types + vl->values_len);
+ *ret_buffer = (void *) (pv.values + vl->values_len);
+
+ pv.head->type = htons (TYPE_VALUES);
+ pv.head->length = htons (6 + (9 * vl->values_len));
+ *pv.num_values = htons ((uint16_t) vl->values_len);
+
+ for (i = 0; i < vl->values_len; i++)
+ {
+ if (ds->ds[i].type == DS_TYPE_COUNTER)
+ {
+ pv.values_types[i] = DS_TYPE_COUNTER;
+ pv.values[i].counter = htonll (vl->values[i].counter);
+ }
+ else
+ {
+ pv.values_types[i] = DS_TYPE_GAUGE;
+ pv.values[i].gauge = vl->values[i].gauge;
+ }
+ } /* for (values) */
-static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
+ return (0);
+} /* int write_part_values */
+
+static int write_part_number (char **ret_buffer, int *ret_buffer_len,
+ int type, uint64_t value)
{
- char *ttl_str;
- int ttl_int;
+ part_number_t pn;
- ttl_str = cf_get_option ("TimeToLive", NULL);
- if (ttl_str == NULL)
+ if (*ret_buffer_len < 12)
return (-1);
- ttl_int = atoi (ttl_str);
- if ((ttl_int < 1) || (ttl_int > 255))
+ pn.head = (part_header_t *) *ret_buffer;
+ pn.value = (uint64_t *) (pn.head + 1);
+
+ pn.head->type = htons (type);
+ pn.head->length = htons (12);
+ *pn.value = htonll (value);
+
+ *ret_buffer = (char *) (pn.value + 1);
+ *ret_buffer_len -= 12;
+
+ return (0);
+} /* int write_part_number */
+
+static int write_part_string (char **ret_buffer, int *ret_buffer_len,
+ int type, const char *str, int str_len)
+{
+ part_string_t ps;
+ int len;
+
+ if (str_len < 1)
+ return (-1);
+
+ len = 4 + str_len + 1;
+ if (*ret_buffer_len < len)
+ return (-1);
+ *ret_buffer_len -= len;
+
+ ps.head = (part_header_t *) *ret_buffer;
+ ps.value = (char *) (ps.head + 1);
+
+ ps.head->type = htons ((uint16_t) type);
+ ps.head->length = htons ((uint16_t) str_len + 5);
+ memcpy (ps.value, str, str_len);
+ ps.value[str_len] = '\0';
+ *ret_buffer = (void *) (ps.value + (str_len + 1));
+
+ return (0);
+} /* int write_part_string */
+
+static int parse_part_values (void **ret_buffer, int *ret_buffer_len,
+ value_t **ret_values, int *ret_num_values)
+{
+ char *buffer = *ret_buffer;
+ int buffer_len = *ret_buffer_len;
+ part_values_t pv;
+ int i;
+
+ uint16_t h_length;
+ uint16_t h_type;
+ uint16_t h_num;
+
+ if (buffer_len < (15))
+ {
+ DBG ("packet is too short: buffer_len = %i", buffer_len);
+ return (-1);
+ }
+
+ pv.head = (part_header_t *) buffer;
+ h_length = ntohs (pv.head->length);
+ h_type = ntohs (pv.head->type);
+
+ assert (h_type == TYPE_VALUES);
+
+ pv.num_values = (uint16_t *) (pv.head + 1);
+ h_num = ntohs (*pv.num_values);
+
+ if (h_num != ((h_length - 6) / 9))
{
- syslog (LOG_WARNING, "A TTL value of %i is invalid.", ttl_int);
+ DBG ("`length' and `num of values' don't match");
return (-1);
}
- DBG ("ttl = %i", ttl_int);
+ pv.values_types = (uint8_t *) (pv.num_values + 1);
+ pv.values = (value_t *) (pv.values_types + h_num);
+
+ for (i = 0; i < h_num; i++)
+ if (pv.values_types[i] == DS_TYPE_COUNTER)
+ pv.values[i].counter = ntohll (pv.values[i].counter);
+
+ *ret_buffer = (void *) (pv.values + h_num);
+ *ret_buffer_len = buffer_len - h_length;
+ *ret_num_values = h_num;
+ *ret_values = pv.values;
+
+ return (0);
+} /* int parse_part_values */
+
+static int parse_part_number (void **ret_buffer, int *ret_buffer_len,
+ uint64_t *value)
+{
+ part_number_t pn;
+ uint16_t len;
+
+ pn.head = (part_header_t *) *ret_buffer;
+ pn.value = (uint64_t *) (pn.head + 1);
+
+ len = ntohs (pn.head->length);
+ if (len != 12)
+ return (-1);
+ if (len > *ret_buffer_len)
+ return (-1);
+ *value = ntohll (*pn.value);
+
+ *ret_buffer = (void *) (pn.value + 1);
+ *ret_buffer_len -= len;
+
+ return (0);
+} /* int parse_part_number */
+
+static int parse_part_string (void **ret_buffer, int *ret_buffer_len,
+ char *output, int output_len)
+{
+ char *buffer = *ret_buffer;
+ int buffer_len = *ret_buffer_len;
+ part_string_t ps;
+
+ uint16_t h_length;
+ uint16_t h_type;
+
+ DBG ("ret_buffer = %p; ret_buffer_len = %i; output = %p; output_len = %i;",
+ *ret_buffer, *ret_buffer_len,
+ (void *) output, output_len);
+
+ ps.head = (part_header_t *) buffer;
+
+ h_length = ntohs (ps.head->length);
+ h_type = ntohs (ps.head->type);
+
+ DBG ("length = %hu; type = %hu;", h_length, h_type);
+
+ if (buffer_len < h_length)
+ {
+ DBG ("packet is too short");
+ return (-1);
+ }
+ assert ((h_type == TYPE_HOST)
+ || (h_type == TYPE_PLUGIN)
+ || (h_type == TYPE_PLUGIN_INSTANCE)
+ || (h_type == TYPE_TYPE)
+ || (h_type == TYPE_TYPE_INSTANCE));
+
+ ps.value = buffer + 4;
+ if (ps.value[h_length - 5] != '\0')
+ {
+ DBG ("String does not end with a nullbyte");
+ return (-1);
+ }
+
+ if (output_len < (h_length - 4))
+ {
+ DBG ("output buffer is too small");
+ return (-1);
+ }
+ strcpy (output, ps.value);
+
+ DBG ("output = %s", output);
+
+ *ret_buffer = (void *) (buffer + h_length);
+ *ret_buffer_len = buffer_len - h_length;
+
+ return (0);
+} /* int parse_part_string */
+
+static int parse_packet (void *buffer, int buffer_len)
+{
+ part_header_t *header;
+ int status;
+
+ value_list_t vl = VALUE_LIST_INIT;
+ char type[DATA_MAX_NAME_LEN];
+
+ DBG ("buffer = %p; buffer_len = %i;", buffer, buffer_len);
+
+ memset (&vl, '\0', sizeof (vl));
+ memset (&type, '\0', sizeof (type));
+ status = 0;
+
+ while ((status == 0) && (buffer_len > sizeof (part_header_t)))
+ {
+ header = (part_header_t *) buffer;
+
+ if (ntohs (header->length) > buffer_len)
+ break;
+
+ if (header->type == htons (TYPE_VALUES))
+ {
+ status = parse_part_values (&buffer, &buffer_len,
+ &vl.values, &vl.values_len);
+
+ if (status != 0)
+ {
+ DBG ("parse_part_values failed.");
+ break;
+ }
+
+ if ((vl.time > 0)
+ && (strlen (vl.host) > 0)
+ && (strlen (vl.plugin) > 0)
+ && (strlen (type) > 0))
+ {
+ DBG ("dispatching values");
+ plugin_dispatch_values (type, &vl);
+ }
+ else
+ {
+ DBG ("NOT dispatching values");
+ }
+ }
+ else if (header->type == ntohs (TYPE_TIME))
+ {
+ uint64_t tmp = 0;
+ status = parse_part_number (&buffer, &buffer_len, &tmp);
+ if (status == 0)
+ vl.time = (time_t) tmp;
+ }
+ else if (header->type == ntohs (TYPE_HOST))
+ {
+ status = parse_part_string (&buffer, &buffer_len,
+ vl.host, sizeof (vl.host));
+ }
+ else if (header->type == ntohs (TYPE_PLUGIN))
+ {
+ status = parse_part_string (&buffer, &buffer_len,
+ vl.plugin, sizeof (vl.plugin));
+ }
+ else if (header->type == ntohs (TYPE_PLUGIN_INSTANCE))
+ {
+ status = parse_part_string (&buffer, &buffer_len,
+ vl.plugin_instance, sizeof (vl.plugin_instance));
+ }
+ else if (header->type == ntohs (TYPE_TYPE))
+ {
+ status = parse_part_string (&buffer, &buffer_len,
+ type, sizeof (type));
+ }
+ else if (header->type == ntohs (TYPE_TYPE_INSTANCE))
+ {
+ status = parse_part_string (&buffer, &buffer_len,
+ vl.type_instance, sizeof (vl.type_instance));
+ }
+ else
+ {
+ DBG ("Unknown part type: 0x%0hx", header->type);
+ buffer = ((char *) buffer) + header->length;
+ }
+ } /* while (buffer_len > sizeof (part_header_t)) */
+
+ return (0);
+} /* int parse_packet */
+
+static void free_sockent (sockent_t *se)
+{
+ sockent_t *next;
+ while (se != NULL)
+ {
+ next = se->next;
+ free (se->addr);
+ free (se);
+ se = next;
+ }
+} /* void free_sockent */
+
+/*
+ * int network_set_ttl
+ *
+ * Set the `IP_MULTICAST_TTL', `IP_TTL', `IPV6_MULTICAST_HOPS' or
+ * `IPV6_UNICAST_HOPS', depending on which option is applicable.
+ *
+ * The `struct addrinfo' is used to destinguish between unicast and multicast
+ * sockets.
+ */
+static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
+{
+ if ((network_config_ttl < 1) || (network_config_ttl > 255))
+ return (-1);
+
+ DBG ("ttl = %i", network_config_ttl);
if (ai->ai_family == AF_INET)
{
optname = IP_TTL;
if (setsockopt (se->fd, IPPROTO_IP, optname,
- &ttl_int, sizeof (ttl_int)) == -1)
+ &network_config_ttl,
+ sizeof (network_config_ttl)) == -1)
{
syslog (LOG_ERR, "setsockopt: %s", strerror (errno));
return (-1);
optname = IPV6_UNICAST_HOPS;
if (setsockopt (se->fd, IPPROTO_IPV6, optname,
- &ttl_int, sizeof (ttl_int)) == -1)
+ &network_config_ttl,
+ sizeof (network_config_ttl)) == -1)
{
syslog (LOG_ERR, "setsockopt: %s", strerror (errno));
return (-1);
}
return (0);
-}
+} /* int network_set_ttl */
static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai)
{
}
return (0);
-}
+} /* int network_bind_socket */
-int network_create_socket (const char *node, const char *service)
+static sockent_t *network_create_socket (const char *node,
+ const char *service,
+ int listen)
{
- sockent_t *socklist_tail;
-
struct addrinfo ai_hints;
struct addrinfo *ai_list, *ai_ptr;
int ai_return;
- int num_added = 0;
+ sockent_t *se_head = NULL;
+ sockent_t *se_tail = NULL;
DBG ("node = %s, service = %s", node, service);
- if (operating_mode == MODE_LOCAL || operating_mode == MODE_LOG)
- {
- syslog (LOG_WARNING, "network_create_socket: There is no point opening a socket when you are in mode `%s'.",
- operating_mode == MODE_LOCAL ? "Local" : "Log");
- return (-1);
- }
-
- socklist_tail = socklist_head;
- while ((socklist_tail != NULL) && (socklist_tail->next != NULL))
- socklist_tail = socklist_tail->next;
-
memset (&ai_hints, '\0', sizeof (ai_hints));
ai_hints.ai_flags = 0;
#ifdef AI_PASSIVE
#ifdef AI_ADDRCONFIG
ai_hints.ai_flags |= AI_ADDRCONFIG;
#endif
- ai_hints.ai_family = PF_UNSPEC;
+ ai_hints.ai_family = AF_UNSPEC;
ai_hints.ai_socktype = SOCK_DGRAM;
ai_hints.ai_protocol = IPPROTO_UDP;
- if ((ai_return = getaddrinfo (node, service, &ai_hints, &ai_list)) != 0)
+ ai_return = getaddrinfo (node, service, &ai_hints, &ai_list);
+ if (ai_return != 0)
{
syslog (LOG_ERR, "getaddrinfo (%s, %s): %s",
- node == NULL ? "(null)" : node,
- service == NULL ? "(null)" : service,
- ai_return == EAI_SYSTEM ? strerror (errno) : gai_strerror (ai_return));
- return (-1);
+ (node == NULL) ? "(null)" : node,
+ (service == NULL) ? "(null)" : service,
+ (ai_return == EAI_SYSTEM)
+ ? strerror (errno)
+ : gai_strerror (ai_return));
+ return (NULL);
}
for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
memcpy (se->addr, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
se->addrlen = ai_ptr->ai_addrlen;
- se->mode = operating_mode;
- se->fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
+ se->fd = socket (ai_ptr->ai_family,
+ ai_ptr->ai_socktype,
+ ai_ptr->ai_protocol);
se->next = NULL;
if (se->fd == -1)
continue;
}
- if (operating_mode == MODE_SERVER)
+ if (listen != 0)
{
if (network_bind_socket (se, ai_ptr) != 0)
{
continue;
}
}
- else if (operating_mode == MODE_CLIENT)
+ else /* listen == 0 */
{
network_set_ttl (se, ai_ptr);
}
- if (socklist_tail == NULL)
+ if (se_tail == NULL)
{
- socklist_head = se;
- socklist_tail = se;
+ se_head = se;
+ se_tail = se;
}
else
{
- socklist_tail->next = se;
- socklist_tail = se;
+ se_tail->next = se;
+ se_tail = se;
}
- num_added++;
-
/* We don't open more than one write-socket per node/service pair.. */
- if (operating_mode == MODE_CLIENT)
+ if (listen == 0)
break;
}
freeaddrinfo (ai_list);
- return (num_added);
-}
+ return (se_head);
+} /* sockent_t *network_create_socket */
-static int network_connect_default (void)
+static sockent_t *network_create_default_socket (int listen)
{
- int ret;
+ sockent_t *se_ptr = NULL;
+ sockent_t *se_head = NULL;
+ sockent_t *se_tail = NULL;
- if (socklist_head != NULL)
- return (0);
+ se_ptr = network_create_socket (NET_DEFAULT_V6_ADDR,
+ NET_DEFAULT_PORT, listen);
- DBG ("socklist_head is NULL");
+ /* Don't send to the same machine in IPv6 and IPv4 if both are available. */
+ if ((listen == 0) && (se_ptr != NULL))
+ return (se_ptr);
- ret = 0;
+ if (se_ptr != NULL)
+ {
+ se_head = se_ptr;
+ se_tail = se_ptr;
+ while (se_tail->next != NULL)
+ se_tail = se_tail->next;
+ }
- if (network_create_socket (NET_DEFAULT_V6_ADDR, NET_DEFAULT_PORT) > 0)
- ret++;
+ se_ptr = network_create_socket (NET_DEFAULT_V4_ADDR, NET_DEFAULT_PORT, listen);
- /* Don't use IPv4 and IPv6 in parallel by default.. */
- if ((operating_mode == MODE_CLIENT) && (ret != 0))
- return (ret);
+ if (se_tail == NULL)
+ return (se_ptr);
- if (network_create_socket (NET_DEFAULT_V4_ADDR, NET_DEFAULT_PORT) > 0)
- ret++;
+ se_tail->next = se_ptr;
+ return (se_head);
+} /* sockent_t *network_create_default_socket */
- if (ret == 0)
- ret = -1;
+static int network_add_listen_socket (const char *node, const char *service)
+{
+ sockent_t *se;
+ sockent_t *se_ptr;
+ int se_num = 0;
- return (ret);
-}
+ if (service == NULL)
+ service = NET_DEFAULT_PORT;
-static int network_get_listen_socket (void)
-{
- int fd;
- int max_fd;
- int status;
+ if (node == NULL)
+ se = network_create_default_socket (1 /* listen == true */);
+ else
+ se = network_create_socket (node, service, 1 /* listen == true */);
- fd_set readfds;
- sockent_t *se;
+ if (se == NULL)
+ return (-1);
- if (socklist_head == NULL)
- network_connect_default ();
+ for (se_ptr = se; se_ptr != NULL; se_ptr = se_ptr->next)
+ se_num++;
- FD_ZERO (&readfds);
- max_fd = -1;
- for (se = socklist_head; se != NULL; se = se->next)
+ listen_sockets = (struct pollfd *) realloc (listen_sockets,
+ (listen_sockets_num + se_num)
+ * sizeof (struct pollfd));
+
+ for (se_ptr = se; se_ptr != NULL; se_ptr = se_ptr->next)
{
- if (se->mode != operating_mode)
- continue;
+ listen_sockets[listen_sockets_num].fd = se_ptr->fd;
+ listen_sockets[listen_sockets_num].events = POLLIN | POLLPRI;
+ listen_sockets[listen_sockets_num].revents = 0;
+ listen_sockets_num++;
+ } /* for (se) */
- FD_SET (se->fd, &readfds);
- if (se->fd >= max_fd)
- max_fd = se->fd + 1;
- }
+ free_sockent (se);
+ return (0);
+} /* int network_add_listen_socket */
- if (max_fd == -1)
- {
- syslog (LOG_WARNING, "No listen sockets found!");
- return (-1);
- }
+static int network_add_sending_socket (const char *node, const char *service)
+{
+ sockent_t *se;
+ sockent_t *se_ptr;
- status = select (max_fd, &readfds, NULL, NULL, NULL);
+ if (service == NULL)
+ service = NET_DEFAULT_PORT;
- if (status == -1)
- {
- if (errno != EINTR)
- syslog (LOG_ERR, "select: %s", strerror (errno));
+ if (node == NULL)
+ se = network_create_default_socket (0 /* listen == false */);
+ else
+ se = network_create_socket (node, service, 0 /* listen == false */);
+
+ if (se == NULL)
return (-1);
- }
- fd = -1;
- for (se = socklist_head; se != NULL; se = se->next)
+ if (sending_sockets == NULL)
{
- if (se->mode != operating_mode)
- continue;
-
- if (FD_ISSET (se->fd, &readfds))
- {
- fd = se->fd;
- break;
- }
+ sending_sockets = se;
+ return (0);
}
- if (fd == -1)
- syslog (LOG_WARNING, "No socket ready..?");
+ for (se_ptr = sending_sockets; se_ptr->next != NULL; se_ptr = se_ptr->next)
+ /* seek end */;
- DBG ("fd = %i", fd);
- return (fd);
-}
+ se_ptr->next = se;
+ return (0);
+} /* int network_get_listen_socket */
-int network_receive (char **host, char **type, char **inst, char **value)
+int network_receive (void)
{
- int fd;
char buffer[BUFF_SIZE];
+ int buffer_len;
- struct sockaddr_storage addr;
- socklen_t addrlen;
+ int i;
int status;
- char *fields[4];
-
- assert (operating_mode == MODE_SERVER);
-
- *host = NULL;
- *type = NULL;
- *inst = NULL;
- *value = NULL;
-
- if ((fd = network_get_listen_socket ()) < 0)
- return (-1);
+ if (listen_sockets_num == 0)
+ network_add_listen_socket (NULL, NULL);
- addrlen = sizeof (addr);
- if (recvfrom (fd, buffer, BUFF_SIZE, 0, (struct sockaddr *) &addr, &addrlen) == -1)
+ if (listen_sockets_num == 0)
{
- syslog (LOG_ERR, "recvfrom: %s", strerror (errno));
+ syslog (LOG_ERR, "network: Failed to open a listening socket.");
return (-1);
}
- if ((*host = (char *) malloc (BUFF_SIZE)) == NULL)
+ while (listen_loop == 0)
{
- syslog (LOG_EMERG, "malloc: %s", strerror (errno));
- return (-1);
- }
+ status = poll (listen_sockets, listen_sockets_num, -1);
- status = getnameinfo ((struct sockaddr *) &addr, addrlen,
- *host, BUFF_SIZE, NULL, 0, 0);
- if (status != 0)
- {
- free (*host); *host = NULL;
- syslog (LOG_ERR, "getnameinfo: %s",
- status == EAI_SYSTEM ? strerror (errno) : gai_strerror (status));
- return (-1);
- }
-
- if (strsplit (buffer, fields, 4) != 3)
- {
- syslog (LOG_WARNING, "Invalid message from `%s'", *host);
- free (*host); *host = NULL;
- return (1);
- }
-
- if ((*type = strdup (fields[0])) == NULL)
- {
- syslog (LOG_EMERG, "strdup: %s", strerror (errno));
- free (*host); *host = NULL;
- return (-1);
- }
+ if (status <= 0)
+ {
+ if (errno == EINTR)
+ continue;
+ syslog (LOG_ERR, "poll failed: %s",
+ strerror (errno));
+ return (-1);
+ }
- if ((*inst = strdup (fields[1])) == NULL)
- {
- syslog (LOG_EMERG, "strdup: %s", strerror (errno));
- free (*host); *host = NULL;
- free (*type); *type = NULL;
- return (-1);
- }
+ for (i = 0; (i < listen_sockets_num) && (status > 0); i++)
+ {
+ if ((listen_sockets[i].revents & (POLLIN | POLLPRI)) == 0)
+ continue;
+ status--;
- if ((*value = strdup (fields[2])) == NULL)
- {
- syslog (LOG_EMERG, "strdup: %s", strerror (errno));
- free (*host); *host = NULL;
- free (*type); *type = NULL;
- free (*inst); *inst = NULL;
- return (-1);
- }
+ buffer_len = recv (listen_sockets[i].fd,
+ buffer, sizeof (buffer),
+ 0 /* no flags */);
+ if (buffer_len < 0)
+ {
+ syslog (LOG_ERR, "recv failed: %s", strerror (errno));
+ return (-1);
+ }
- DBG ("host = %s, type = %s, inst = %s, value = %s",
- *host, *type, *inst, *value);
+ parse_packet (buffer, buffer_len);
+ } /* for (listen_sockets) */
+ } /* while (listen_loop == 0) */
return (0);
}
+static void *receive_thread (void *arg)
+{
+ return (network_receive () ? (void *) 1 : (void *) 0);
+} /* void *receive_thread */
+
+#if 0
int network_send (char *type, char *inst, char *value)
{
char buf[BUFF_SIZE];
buflen++;
if (socklist_head == NULL)
- network_connect_default ();
+ network_create_default_socket (0 /* listen == false */);
ret = 0;
for (se = socklist_head; se != NULL; se = se->next)
{
- if (se->mode != operating_mode)
- continue;
-
while (1)
{
status = sendto (se->fd, buf, buflen, 0,
syslog (LOG_WARNING, "Message wasn't sent to anybody..");
return (ret);
+} /* int network_send */
+#endif
+
+static int network_write (const data_set_t *ds, const value_list_t *vl)
+{
+ char buf[BUFF_SIZE];
+ char *buf_ptr;
+ int buf_len;
+
+ sockent_t *se;
+
+ DBG ("time = %u; host = %s; "
+ "plugin = %s; plugin_instance = %s; "
+ "type = %s; type_instance = %s;",
+ (unsigned int) vl->time, vl->host,
+ vl->plugin, vl->plugin_instance,
+ ds->type, vl->type_instance);
+
+ buf_len = sizeof (buf);
+ buf_ptr = buf;
+ if (write_part_string (&buf_ptr, &buf_len, TYPE_HOST,
+ vl->host, strlen (vl->host)) != 0)
+ return (-1);
+ if (write_part_number (&buf_ptr, &buf_len, TYPE_TIME,
+ (uint64_t) vl->time))
+ return (-1);
+ if (write_part_string (&buf_ptr, &buf_len, TYPE_PLUGIN,
+ vl->plugin, strlen (vl->plugin)) != 0)
+ return (-1);
+ if (strlen (vl->plugin_instance) > 0)
+ if (write_part_string (&buf_ptr, &buf_len, TYPE_PLUGIN_INSTANCE,
+ vl->plugin_instance,
+ strlen (vl->plugin_instance)) != 0)
+ return (-1);
+ if (write_part_string (&buf_ptr, &buf_len, TYPE_TYPE,
+ ds->type, strlen (ds->type)) != 0)
+ return (-1);
+ if (strlen (vl->type_instance) > 0)
+ if (write_part_string (&buf_ptr, &buf_len, TYPE_PLUGIN_INSTANCE,
+ vl->type_instance,
+ strlen (vl->type_instance)) != 0)
+ return (-1);
+
+ write_part_values (&buf_ptr, &buf_len, ds, vl);
+
+ buf_len = sizeof (buf) - buf_len;
+
+ for (se = sending_sockets; se != NULL; se = se->next)
+ {
+ int status;
+
+ while (42)
+ {
+ status = sendto (se->fd, buf, buf_len, 0 /* no flags */,
+ (struct sockaddr *) se->addr, se->addrlen);
+ if (status < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ syslog (LOG_ERR, "network: sendto failed: %s",
+ strerror (errno));
+ break;
+ }
+
+ break;
+ } /* while (42) */
+ } /* for (sending_sockets) */
+
+ return 0;
+}
+
+static int network_config (const char *key, const char *val)
+{
+ char *node;
+ char *service;
+
+ char *fields[3];
+ int fields_num;
+
+ if ((strcasecmp ("Listen", key) == 0)
+ || (strcasecmp ("Server", key) == 0))
+ {
+ char *val_cpy = strdup (val);
+ if (val_cpy == NULL)
+ return (1);
+
+ service = NET_DEFAULT_PORT;
+ fields_num = strsplit (val_cpy, fields, 3);
+ if ((fields_num != 1)
+ && (fields_num != 2))
+ return (1);
+ else if (fields_num == 2)
+ service = fields[1];
+ node = fields[0];
+
+ if (strcasecmp ("Listen", key) == 0)
+ network_add_listen_socket (node, service);
+ else
+ network_add_sending_socket (node, service);
+ }
+ else if (strcasecmp ("TimeToLive", key) == 0)
+ {
+ int tmp = atoi (val);
+ if ((tmp > 0) && (tmp < 256))
+ network_config_ttl = tmp;
+ else
+ return (1);
+ }
+ else
+ {
+ return (-1);
+ }
+ return (0);
+}
+
+static int network_shutdown (void)
+{
+ DBG ("Shutting down.");
+
+ listen_loop++;
+
+ pthread_kill (listen_thread, SIGTERM);
+ pthread_join (listen_thread, NULL /* no return value */);
+
+ listen_thread = 0;
+
+ return (0);
+}
+
+static int network_init (void)
+{
+ plugin_register_shutdown ("network", network_shutdown);
+
+ /* setup socket(s) and so on */
+ if (sending_sockets != NULL)
+ plugin_register_write ("network", network_write);
+
+ if ((listen_sockets_num != 0) && (listen_thread == 0))
+ {
+ int status;
+
+ status = pthread_create (&listen_thread, NULL /* no attributes */,
+ receive_thread, NULL /* no argument */);
+
+ if (status != 0)
+ syslog (LOG_ERR, "network: pthread_create failed: %s",
+ strerror (errno));
+ }
+ return (0);
+} /* int network_init */
+
+void module_register (void)
+{
+ plugin_register_config ("network", network_config,
+ config_keys, config_keys_num);
+ plugin_register_init ("network", network_init);
}
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Free Software Foundation; only version 2 of the License is applicable.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
#define NET_DEFAULT_V6_ADDR "ff18::efc0:4a42"
#define NET_DEFAULT_PORT "25826"
-int network_create_socket (const char *node, const char *service);
-int network_receive (char **host, char **type, char **instance, char **value);
-int network_send (char *type, char *instance, char *value);
+#define TYPE_HOST 0x0000
+#define TYPE_TIME 0x0001
+#define TYPE_PLUGIN 0x0002
+#define TYPE_PLUGIN_INSTANCE 0x0003
+#define TYPE_TYPE 0x0004
+#define TYPE_TYPE_INSTANCE 0x0005
+#define TYPE_VALUES 0x0006
#endif /* NETWORK_H */
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Free Software Foundation; only version 2 of the License is applicable.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
#include "collectd.h"
#include "common.h"
#include "plugin.h"
+#include "utils_debug.h"
#define MODULE_NAME "nfs"
# define NFS_HAVE_READ 0
#endif
-static char *nfs2_procedures_file = "nfs2_procedures-%s.rrd";
-static char *nfs3_procedures_file = "nfs3_procedures-%s.rrd";
-
/*
see /proc/net/rpc/nfs
see http://www.missioncriticallinux.com/orph/NFS-Statistics
21 commit
*/
-static char *nfs2_procedures_ds_def[] =
+static data_source_t procedure_dsrc[1] =
+{
+ {"value", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
+
+static data_set_t procedure_ds =
+{
+ "nfs_procedure", 1, procedure_dsrc
+};
+
+static const char *nfs2_procedures_names[] =
{
- "DS:null:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:getattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:setattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:root:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:lookup:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:readlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:read:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:wrcache:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:write:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:create:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:remove:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:rename:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:link:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:symlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:mkdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:rmdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:readdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:fsstat:COUNTER:"COLLECTD_HEARTBEAT":0:U",
+ "null",
+ "getattr",
+ "setattr",
+ "root",
+ "lookup",
+ "readlink",
+ "read",
+ "wrcache",
+ "write",
+ "create",
+ "remove",
+ "rename",
+ "link",
+ "symlink",
+ "mkdir",
+ "rmdir",
+ "readdir",
+ "fsstat",
NULL
};
-static int nfs2_procedures_ds_num = 18;
+static int nfs2_procedures_names_num = 18;
-static char *nfs3_procedures_ds_def[] =
+static const char *nfs3_procedures_names[] =
{
- "DS:null:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:getattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:setattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:lookup:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:access:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:readlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:read:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:write:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:create:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:mkdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:symlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:mknod:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:remove:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:rmdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:rename:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:link:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:readdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:readdirplus:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:fsstat:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:fsinfo:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:pathconf:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:commit:COUNTER:"COLLECTD_HEARTBEAT":0:U",
+ "null",
+ "getattr",
+ "setattr",
+ "lookup",
+ "access",
+ "readlink",
+ "read",
+ "write",
+ "create",
+ "mkdir",
+ "symlink",
+ "mknod",
+ "remove",
+ "rmdir",
+ "rename",
+ "link",
+ "readdir",
+ "readdirplus",
+ "fsstat",
+ "fsinfo",
+ "pathconf",
+ "commit",
NULL
};
-static int nfs3_procedures_ds_num = 22;
+static int nfs3_procedures_names_num = 22;
#if HAVE_LIBKSTAT && 0
extern kstat_ctl_t *kc;
/* Possibly TODO: NFSv4 statistics */
-static void nfs_init (void)
+#if 0
+static int nfs_init (void)
{
#if HAVE_LIBKSTAT && 0
kstat_t *ksp_chain;
}
#endif
- return;
-}
+ return (0);
+} /* int nfs_init */
+#endif
#define BUFSIZE 1024
-static void nfs2_procedures_write (char *host, char *inst, char *val)
-{
- char filename[BUFSIZE];
-
- if (snprintf (filename, BUFSIZE, nfs2_procedures_file, inst) > BUFSIZE)
- return;
-
- rrd_update_file (host, filename, val, nfs2_procedures_ds_def,
- nfs2_procedures_ds_num);
-}
-
-static void nfs3_procedures_write (char *host, char *inst, char *val)
-{
- char filename[BUFSIZE];
-
- if (snprintf (filename, BUFSIZE, nfs3_procedures_file, inst) > BUFSIZE)
- return;
-
- rrd_update_file (host, filename, val, nfs3_procedures_ds_def,
- nfs3_procedures_ds_num);
-}
-
#if NFS_HAVE_READ
-static void nfs2_procedures_submit (unsigned long long *val, char *inst)
-{
- char buf[BUFSIZE];
- int retval = 0;
-
- retval = snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
- "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
- "%llu:%llu:%llu", /* 18x %llu */
- (unsigned int) curtime,
- val[0], val[1], val[2], val[3], val[4], val[5], val[6],
- val[7], val[8], val[9], val[10], val[11], val[12],
- val[13], val[14], val[15], val[16], val[17]);
-
-
- if (retval >= BUFSIZE)
- return;
- else if (retval < 0)
- {
- syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
- return;
- }
-
- plugin_submit ("nfs2_procedures", inst, buf);
-}
-
-static void nfs3_procedures_submit (unsigned long long *val, char *inst)
+static void nfs_procedures_submit (const char *plugin_instance,
+ unsigned long long *val, const char **names, int len)
{
- char buf[BUFSIZE];
- int retval = 0;
-
- retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
- "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
- "%llu:%llu:%llu:%llu:%llu:%llu:%llu", /* 22x %llu */
- (unsigned int) curtime,
- val[0], val[1], val[2], val[3], val[4], val[5], val[6],
- val[7], val[8], val[9], val[10], val[11], val[12],
- val[13], val[14], val[15], val[16], val[17], val[18],
- val[19], val[20], val[21]);
-
- if (retval >= BUFSIZE)
- return;
- else if (retval < 0)
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+ int i;
+
+ vl.values = values;
+ vl.values_len = 1;
+ vl.time = time (NULL);
+ strcpy (vl.host, hostname);
+ strcpy (vl.plugin, "nfs");
+ strncpy (vl.plugin_instance, plugin_instance,
+ sizeof (vl.plugin_instance));
+
+ for (i = 0; i < len; i++)
{
- syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
- return;
+ values[0].counter = val[i];
+ strncpy (vl.type_instance, names[i],
+ sizeof (vl.type_instance));
+ DBG ("%s-%s/nfs_procedure-%s = %llu",
+ vl.plugin, vl.plugin_instance,
+ vl.type_instance, val[i]);
+ plugin_dispatch_values ("nfs_procedure", &vl);
}
-
- plugin_submit("nfs3_procedures", inst, buf);
-}
+} /* void nfs_procedures_submit */
#endif /* NFS_HAVE_READ */
#if KERNEL_LINUX
{
char buffer[BUFSIZE];
+ char plugin_instance[DATA_MAX_NAME_LEN];
+
char *fields[48];
int numfields = 0;
{
numfields = strsplit (buffer, fields, 48);
- if (numfields < 2)
+ if (((numfields - 2) != nfs2_procedures_names_num)
+ && ((numfields - 2)
+ != nfs3_procedures_names_num))
continue;
- if (strncmp (fields[0], "proc2", 5) == 0)
+ if (strcmp (fields[0], "proc2") == 0)
{
int i;
unsigned long long *values;
- if (numfields - 2 != nfs2_procedures_ds_num)
+ if ((numfields - 2) != nfs2_procedures_names_num)
{
- syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS2 statistics.", numfields - 2);
+ syslog (LOG_WARNING, "nfs plugin: Wrong "
+ "number of fields (= %i) "
+ "for NFSv2 statistics.",
+ numfields - 2);
continue;
}
- if ((values = (unsigned long long *) malloc (nfs2_procedures_ds_num * sizeof (unsigned long long))) == NULL)
+ snprintf (plugin_instance, sizeof (plugin_instance),
+ "v2%s", inst);
+ plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
+
+ values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
+ if (values == NULL)
{
- syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
+ syslog (LOG_ERR, "nfs plugin: malloc "
+ "failed: %s",
+ strerror (errno));
continue;
}
- for (i = 0; i < nfs2_procedures_ds_num; i++)
+ for (i = 0; i < nfs2_procedures_names_num; i++)
values[i] = atoll (fields[i + 2]);
- nfs2_procedures_submit (values, inst);
+ nfs_procedures_submit (plugin_instance, values,
+ nfs2_procedures_names,
+ nfs2_procedures_names_num);
free (values);
}
int i;
unsigned long long *values;
- if (numfields - 2 != nfs3_procedures_ds_num)
+ if ((numfields - 2) != nfs3_procedures_names_num)
{
- syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS3 statistics.", numfields - 2);
+ syslog (LOG_WARNING, "nfs plugin: Wrong "
+ "number of fields (= %i) "
+ "for NFSv3 statistics.",
+ numfields - 2);
continue;
}
- if ((values = (unsigned long long *) malloc (nfs3_procedures_ds_num * sizeof (unsigned long long))) == NULL)
+ snprintf (plugin_instance, sizeof (plugin_instance),
+ "v3%s", inst);
+ plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
+
+ values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
+ if (values == NULL)
{
- syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
+ syslog (LOG_ERR, "nfs plugin: malloc "
+ "failed: %s",
+ strerror (errno));
continue;
}
- for (i = 0; i < nfs3_procedures_ds_num; i++)
+ for (i = 0; i < nfs3_procedures_names_num; i++)
values[i] = atoll (fields[i + 2]);
- nfs3_procedures_submit (values, inst);
+ nfs_procedures_submit (plugin_instance, values,
+ nfs3_procedures_names,
+ nfs3_procedures_names_num);
free (values);
}
- }
-}
+ } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
+} /* void nfs_read_stats_file */
#endif /* defined(KERNEL_LINUX) */
#undef BUFSIZE
#endif
#if NFS_HAVE_READ
-static void nfs_read (void)
+static int nfs_read (void)
{
#if KERNEL_LINUX
FILE *fh;
if (nfs2_ksp_server != NULL)
nfs2_read_kstat (nfs2_ksp_server, "server");
#endif /* defined(HAVE_LIBKSTAT) */
+
+ return (0);
}
-#else
-# define nfs_read NULL
#endif /* NFS_HAVE_READ */
void module_register (void)
{
- plugin_register (MODULE_NAME, nfs_init, nfs_read, NULL);
- plugin_register ("nfs2_procedures", NULL, NULL, nfs2_procedures_write);
- plugin_register ("nfs3_procedures", NULL, NULL, nfs3_procedures_write);
+ plugin_register_data_set (&procedure_ds);
+
+#if NFS_HAVE_READ
+ plugin_register_read ("nfs", nfs_read);
+#endif
}
#undef MODULE_NAME
#if HAVE_NETINET_TCP_H
# include <netinet/tcp.h>
#endif
-#if HAVE_SYS_POLL_H
-# include <sys/poll.h>
+#if HAVE_POLL_H
+# include <poll.h>
#endif
static char *config_keys[] =
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Free Software Foundation; only version 2 of the License is applicable.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
#include <ltdl.h>
#include "plugin.h"
-#include "network.h"
+#include "configfile.h"
+#include "utils_llist.h"
#include "utils_debug.h"
-typedef struct plugin
-{
- char *type;
- void (*init) (void);
- void (*read) (void);
- void (*write) (char *host, char *inst, char *val);
- void (*shutdown) (void);
- struct plugin *next;
-} plugin_t;
-
-static plugin_t *first_plugin = NULL;
-
-extern int operating_mode;
+/*
+ * Private variables
+ */
+static llist_t *list_init;
+static llist_t *list_read;
+static llist_t *list_write;
+static llist_t *list_shutdown;
+static llist_t *list_data_set;
static char *plugindir = NULL;
-char *plugin_get_dir (void)
+char hostname[DATA_MAX_NAME_LEN] = "localhost";
+
+/*
+ * Static functions
+ */
+static const char *plugin_get_dir (void)
{
if (plugindir == NULL)
return (PLUGINDIR);
return (plugindir);
}
-void plugin_set_dir (const char *dir)
-{
- if (plugindir != NULL)
- free (plugindir);
-
- if (dir == NULL)
- plugindir = NULL;
- else if ((plugindir = strdup (dir)) == NULL)
- syslog (LOG_ERR, "strdup: %s", strerror (errno));
-}
-
-/*
- * Returns the number of plugins registered
- */
-int plugin_count (void)
-{
- int i;
- plugin_t *p;
-
- for (i = 0, p = first_plugin; p != NULL; p = p->next)
- i++;
-
- return (i);
-}
-
-/*
- * Returns the plugins with the type `type' or NULL if it's not found.
- */
-plugin_t *plugin_search (const char *type)
+static int register_callback (llist_t **list, const char *name, void *callback)
{
- plugin_t *ret;
+ llentry_t *le;
- if (type == NULL)
- return (NULL);
-
- for (ret = first_plugin; ret != NULL; ret = ret->next)
- if (strcmp (ret->type, type) == 0)
- break;
+ if ((*list == NULL)
+ && ((*list = llist_create ()) == NULL))
+ return (-1);
- return (ret);
-}
+ le = llist_search (*list, name);
+ if (le == NULL)
+ {
+ le = llentry_create (name, callback);
+ if (le == NULL)
+ return (-1);
-/*
- * Returns true if the plugin is loaded (i.e. `exists') and false otherwise.
- * This is used in `configfile.c' to skip sections that are not needed..
- */
-int plugin_exists (char *type)
-{
- if (plugin_search (type) == NULL)
- return (0);
+ llist_append (*list, le);
+ }
else
- return (1);
-}
+ {
+ le->value = callback;
+ }
+
+ return (0);
+} /* int register_callback */
/*
* (Try to) load the shared object `file'. Won't complain if it isn't a shared
* object, but it will bitch about a shared object not having a
* ``module_register'' symbol..
*/
-int plugin_load_file (char *file)
+static int plugin_load_file (char *file)
{
lt_dlhandle dlh;
void (*reg_handle) (void);
return (0);
}
+/*
+ * Public functions
+ */
+void plugin_set_dir (const char *dir)
+{
+ if (plugindir != NULL)
+ free (plugindir);
+
+ if (dir == NULL)
+ plugindir = NULL;
+ else if ((plugindir = strdup (dir)) == NULL)
+ syslog (LOG_ERR, "strdup failed: %s", strerror (errno));
+}
+
#define BUFSIZE 512
int plugin_load (const char *type)
{
DIR *dh;
- char *dir;
+ const char *dir;
char filename[BUFSIZE];
char typename[BUFSIZE];
int typename_len;
dir = plugin_get_dir ();
ret = 1;
- /* don't load twice */
- if (plugin_search (type) != NULL)
- return (0);
-
/* `cpu' should not match `cpufreq'. To solve this we add `.so' to the
* type when matching the filename */
if (snprintf (typename, BUFSIZE, "%s.so", type) >= BUFSIZE)
}
/*
- * (Try to) load all plugins in `dir'. Returns the number of loaded plugins..
+ * The `register_*' functions follow
*/
-int plugin_load_all (char *dir)
+int plugin_register_config (const char *name,
+ int (*callback) (const char *key, const char *val),
+ const char **keys, int keys_num)
{
- DIR *dh;
- struct dirent *de;
- char filename[BUFSIZE];
- struct stat statbuf;
-
- if (dir == NULL)
- dir = plugin_get_dir ();
- else
- plugin_set_dir (dir);
-
- if ((dh = opendir (dir)) == NULL)
- {
- syslog (LOG_ERR, "opendir (%s): %s", dir, strerror (errno));
- return (0);
- }
+ cf_register (name, callback, keys, keys_num);
+ return (0);
+} /* int plugin_register_config */
- while ((de = readdir (dh)) != NULL)
- {
- if (snprintf (filename, BUFSIZE, "%s/%s", dir, de->d_name) >= BUFSIZE)
- {
- syslog (LOG_WARNING, "snprintf: truncated: %s/%s", dir, de->d_name);
- continue;
- }
+int plugin_register_init (const char *name,
+ int (*callback) (void))
+{
+ return (register_callback (&list_init, name, (void *) callback));
+} /* plugin_register_init */
- if (lstat (filename, &statbuf) == -1)
- {
- syslog (LOG_WARNING, "stat %s: %s", filename, strerror (errno));
- continue;
- }
- else if (!S_ISREG (statbuf.st_mode))
- {
- continue;
- }
+int plugin_register_read (const char *name,
+ int (*callback) (void))
+{
+ return (register_callback (&list_read, name, (void *) callback));
+} /* int plugin_register_read */
- plugin_load_file (filename);
- }
+int plugin_register_write (const char *name,
+ int (*callback) (const data_set_t *ds, const value_list_t *vl))
+{
+ return (register_callback (&list_write, name, (void *) callback));
+} /* int plugin_register_write */
- closedir (dh);
+int plugin_register_shutdown (char *name,
+ int (*callback) (void))
+{
+ return (register_callback (&list_shutdown, name, (void *) callback));
+} /* int plugin_register_shutdown */
- return (plugin_count ());
-}
-#undef BUFSIZE
+int plugin_register_data_set (const data_set_t *ds)
+{
+ return (register_callback (&list_data_set, ds->type, (void *) ds));
+} /* int plugin_register_data_set */
-/*
- * Call `init' on all plugins (if given)
- */
void plugin_init_all (void)
{
- plugin_t *p;
+ int (*callback) (void);
+ llentry_t *le;
- for (p = first_plugin; p != NULL; p = p->next)
- if (p->init != NULL)
- (*p->init) ();
-}
+ gethostname (hostname, sizeof (hostname));
-/*
- * Call `read' on all plugins (if given)
- */
-void plugin_read_all (const int *loop)
-{
- plugin_t *p;
-
- for (p = first_plugin; (*loop == 0) && (p != NULL); p = p->next)
- if (p->read != NULL)
- (*p->read) ();
-}
+ if (list_init == NULL)
+ return;
-/*
- * Call `shutdown' on all plugins (if given)
- */
-void plugin_shutdown_all (void)
-{
- plugin_t *p;
+ le = llist_head (list_init);
+ while (le != NULL)
+ {
+ callback = le->value;
+ (*callback) ();
- for (p = first_plugin; NULL != p; p = p->next)
- if (NULL != p->shutdown)
- (*p->shutdown) ();
- return;
-}
+ le = le->next;
+ }
+} /* void plugin_init_all */
-/*
- * Add plugin to the linked list of registered plugins.
- */
-void plugin_register (char *type,
- void (*init) (void),
- void (*read) (void),
- void (*write) (char *, char *, char *))
+void plugin_read_all (const int *loop)
{
- plugin_t *p;
+ int (*callback) (void);
+ llentry_t *le;
- if (plugin_search (type) != NULL)
+ if (list_read == NULL)
return;
-#ifdef HAVE_LIBRRD
- if (operating_mode != MODE_SERVER)
-#endif
- if ((init != NULL) && (read == NULL))
- syslog (LOG_NOTICE, "Plugin `%s' doesn't provide a read function.", type);
-
- if ((p = (plugin_t *) malloc (sizeof (plugin_t))) == NULL)
- return;
-
- if ((p->type = strdup (type)) == NULL)
+ le = llist_head (list_read);
+ while ((*loop == 0) && (le != NULL))
{
- free (p);
- return;
+ callback = le->value;
+ (*callback) ();
+
+ le = le->next;
}
+} /* void plugin_read_all */
+
+void plugin_shutdown_all (void)
+{
+ int (*callback) (void);
+ llentry_t *le;
- p->init = init;
- p->read = read;
- p->write = write;
+ if (list_shutdown == NULL)
+ return;
- p->shutdown = NULL;
+ le = llist_head (list_shutdown);
+ while (le != NULL)
+ {
+ callback = le->value;
+ (*callback) ();
- p->next = first_plugin;
- first_plugin = p;
-}
+ le = le->next;
+ }
+} /* void plugin_shutdown_all */
-/*
- * Register the shutdown function (optional).
- */
-int plugin_register_shutdown (char *type, void (*shutdown) (void))
+int plugin_dispatch_values (const char *name, const value_list_t *vl)
{
- plugin_t *p = plugin_search (type);
+ int (*callback) (const data_set_t *, const value_list_t *);
+ data_set_t *ds;
+ llentry_t *le;
- if (NULL == p)
- return -1;
+ if (list_write == NULL)
+ return (-1);
- p->shutdown = shutdown;
- return 0;
-}
+ le = llist_search (list_data_set, name);
+ if (le == NULL)
+ {
+ DBG ("No such dataset registered: %s", name);
+ return (-1);
+ }
-/*
- * Send received data back to the plugin/module which will append DS
- * definitions and pass it on to ``rrd_update_file''.
- */
-void plugin_write (char *host, char *type, char *inst, char *val)
-{
- plugin_t *p;
+ ds = (data_set_t *) le->value;
- if ((p = plugin_search (type)) == NULL)
- return;
+ DBG ("time = %u; host = %s; "
+ "plugin = %s; plugin_instance = %s; "
+ "type = %s; type_instance = %s;",
+ (unsigned int) vl->time, vl->host,
+ vl->plugin, vl->plugin_instance,
+ ds->type, vl->type_instance);
- if (p->write == NULL)
- return;
+ le = llist_head (list_write);
+ while (le != NULL)
+ {
+ callback = le->value;
+ (*callback) (ds, vl);
- (*p->write) (host, inst, val);
-}
+ le = le->next;
+ }
-/*
- * Receive data from the plugin/module and get it somehow to ``plugin_write'':
- * Either using ``network_send'' (when in network/client mode) or call it
- * directly (in local mode).
- */
-void plugin_submit (char *type, char *inst, char *val)
-{
- if (operating_mode == MODE_CLIENT)
- network_send (type, inst, val);
- else
- plugin_write (NULL, type, inst, val);
+ return (0);
}
void plugin_complain (int level, complain_t *c, const char *format, ...)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Free Software Foundation; only version 2 of the License is applicable.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* Florian octo Forster <octo at verplant.org>
**/
+#define DATA_MAX_NAME_LEN 64
+
+#define DS_TYPE_COUNTER 0
+#define DS_TYPE_GAUGE 1
+
/*
- *
+ * Public data types
*/
+typedef unsigned long long counter_t;
+typedef double gauge_t;
+
+union value_u
+{
+ counter_t counter;
+ gauge_t gauge;
+};
+typedef union value_u value_t;
+
+struct value_list_s
+{
+ value_t *values;
+ int values_len;
+ time_t time;
+ char host[DATA_MAX_NAME_LEN];
+ char plugin[DATA_MAX_NAME_LEN];
+ char plugin_instance[DATA_MAX_NAME_LEN];
+ char type_instance[DATA_MAX_NAME_LEN];
+};
+typedef struct value_list_s value_list_t;
+
+#define VALUE_LIST_INIT { NULL, 0, 0, "localhost", "", "", "" }
+
+struct data_source_s
+{
+ char name[DATA_MAX_NAME_LEN];
+ int type;
+ double min;
+ double max;
+};
+typedef struct data_source_s data_source_t;
+
+struct data_set_s
+{
+ char type[DATA_MAX_NAME_LEN];
+ int ds_num;
+ data_source_t *ds;
+};
+typedef struct data_set_s data_set_t;
+
typedef struct complain_s
{
unsigned int interval; /* how long we wait for reporting this error again */
unsigned int delay; /* how many more iterations we still need to wait */
} complain_t;
+extern char hostname[DATA_MAX_NAME_LEN];
+
/*
* NAME
* plugin_set_dir
/*
* NAME
- * plugin_count
- *
- * DESCRIPTION
- * trivial
- *
- * RETURN VALUE
- * The number of currently loaded plugins
- */
-int plugin_count (void);
-
-/*
- * NAME
- * plugin_exists
- *
- * DESCRIPTION
- * trivial
- *
- * ARGUMENTS
- * `type' Name of the plugin.
- *
- * RETURN VALUE
- * Returns non-zero if a plugin with the name $type is found and zero
- * otherwise.
- */
-int plugin_exists (char *type);
-
-/*
- * NAME
* plugin_load
*
* DESCRIPTION
* NOTES
* No attempt is made to re-load an already loaded module.
*/
-int plugin_load (const char *type);
+int plugin_load (const char *name);
-int plugin_load_all (char *dir);
void plugin_init_all (void);
void plugin_read_all (const int *loop);
-
void plugin_shutdown_all (void);
-void plugin_register (char *type,
- void (*init) (void),
- void (*read) (void),
- void (*write) (char *, char *, char *));
-
-int plugin_register_shutdown (char *, void (*) (void));
+/*
+ * The `plugin_register_*' functions are used to make `config', `init',
+ * `read', `write' and `shutdown' functions known to the plugin
+ * infrastructure. Also, the data-formats are made public like this.
+ */
+int plugin_register_config (const char *name,
+ int (*callback) (const char *key, const char *val),
+ const char **keys, int keys_num);
+int plugin_register_init (const char *name,
+ int (*callback) (void));
+int plugin_register_read (const char *name,
+ int (*callback) (void));
+int plugin_register_write (const char *name,
+ int (*callback) (const data_set_t *ds, const value_list_t *vl));
+int plugin_register_shutdown (char *name,
+ int (*callback) (void));
+int plugin_register_data_set (const data_set_t *ds);
/*
* NAME
- * plugin_write
+ * plugin_dispatch_values
*
* DESCRIPTION
- * Searches the plugin for `type' in the plugin-list. If found, and a `write'
- * function is registered, it's called. If either the plugin is not found or
- * the plugin doesn't provide a `write' function this function will return
- * without further notice.
+ * This function is called by reading processes with the values they've
+ * aquired. The function fetches the data-set definition (that has been
+ * registered using `plugin_register_data_set') and calls _all_ registered
+ * write-functions.
*
* ARGUMENTS
- * `host' Host(name) from which the data originates.
- * `type' Name of the plugin.
- * `inst' Instance (passed to the plugin's `write' function.
- * `val' Values for the RRD files. Also passed to the plugin.
+ * `name' Name/type of the data-set that describe the values in `vl'.
+ * `vl' Value list of the values that have been read by a `read'
+ * function.
*/
-void plugin_write (char *host, char *type, char *inst, char *val);
-
-void plugin_submit (char *type, char *inst, char *val);
-
+int plugin_dispatch_values (const char *name, const value_list_t *vl);
+/* TODO: Move plugin_{complain,relief} into `utils_complain.[ch]'. -octo */
void plugin_complain (int level, complain_t *c, const char *format, ...);
void plugin_relief (int level, complain_t *c, const char *format, ...);
--- /dev/null
+/**
+ * collectd - src/rrdtool.c
+ * Copyright (C) 2006 Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+#include "utils_llist.h"
+#include "utils_debug.h"
+
+/*
+ * This weird macro cascade forces the glibc to define `NAN'. I don't know
+ * another way to solve this, so more intelligent solutions are welcome. -octo
+ */
+#ifndef __USE_ISOC99
+# define DISABLE__USE_ISOC99 1
+# define __USE_ISOC99 1
+#endif
+#include <math.h>
+#ifdef DISABLE__USE_ISOC99
+# undef DISABLE__USE_ISOC99
+# undef __USE_ISOC99
+#endif
+
+/*
+ * Private types
+ */
+struct rrd_cache_s
+{
+ int values_num;
+ char **values;
+ time_t first_value;
+};
+typedef struct rrd_cache_s rrd_cache_t;
+
+/*
+ * Private variables
+ */
+static int rra_timespans[] =
+{
+ 3600,
+ 86400,
+ 604800,
+ 2678400,
+ 31622400,
+ 0
+};
+static int rra_timespans_num = 5;
+
+static char *rra_types[] =
+{
+ "AVERAGE",
+ "MIN",
+ "MAX",
+ NULL
+};
+static int rra_types_num = 3;
+
+static const char *config_keys[] =
+{
+ "CacheTimeout",
+ NULL
+};
+static int config_keys_num = 1;
+
+static int cache_timeout = 0;
+static time_t cache_flush;
+static llist_t *cache = NULL;
+
+/* * * * * * * * * *
+ * WARNING: Magic *
+ * * * * * * * * * */
+static int rra_get (char ***ret)
+{
+ static char **rra_def = NULL;
+ static int rra_num = 0;
+
+ int rra_max = rra_timespans_num * rra_types_num;
+
+ int step;
+ int rows;
+ int span;
+
+ int cdp_num;
+ int cdp_len;
+ int i, j;
+
+ char buffer[64];
+
+ if ((rra_num != 0) && (rra_def != NULL))
+ {
+ *ret = rra_def;
+ return (rra_num);
+ }
+
+ if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
+ return (-1);
+ memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
+
+ step = atoi (COLLECTD_STEP);
+ rows = atoi (COLLECTD_ROWS);
+
+ if ((step <= 0) || (rows <= 0))
+ {
+ *ret = NULL;
+ return (-1);
+ }
+
+ cdp_len = 0;
+ for (i = 0; i < rra_timespans_num; i++)
+ {
+ span = rra_timespans[i];
+
+ if ((span / step) < rows)
+ continue;
+
+ if (cdp_len == 0)
+ cdp_len = 1;
+ else
+ cdp_len = (int) floor (((double) span) / ((double) (rows * step)));
+
+ cdp_num = (int) ceil (((double) span) / ((double) (cdp_len * step)));
+
+ for (j = 0; j < rra_types_num; j++)
+ {
+ if (rra_num >= rra_max)
+ break;
+
+ if (snprintf (buffer, sizeof(buffer), "RRA:%s:%3.1f:%u:%u",
+ rra_types[j], COLLECTD_XFF,
+ cdp_len, cdp_num) >= sizeof (buffer))
+ {
+ syslog (LOG_ERR, "rra_get: Buffer would have been truncated.");
+ continue;
+ }
+
+ rra_def[rra_num++] = sstrdup (buffer);
+ }
+ }
+
+#if COLLECT_DEBUG
+ DBG ("rra_num = %i", rra_num);
+ for (i = 0; i < rra_num; i++)
+ DBG (" %s", rra_def[i]);
+#endif
+
+ *ret = rra_def;
+ return (rra_num);
+}
+
+static void ds_free (int ds_num, char **ds_def)
+{
+ int i;
+
+ for (i = 0; i < ds_num; i++)
+ if (ds_def[i] != NULL)
+ free (ds_def[i]);
+ free (ds_def);
+}
+
+static int ds_get (char ***ret, const data_set_t *ds)
+{
+ char **ds_def;
+ int ds_num;
+
+ char min[32];
+ char max[32];
+ char buffer[128];
+
+ DBG ("ds->ds_num = %i", ds->ds_num);
+
+ ds_def = (char **) malloc (ds->ds_num * sizeof (char *));
+ if (ds_def == NULL)
+ {
+ syslog (LOG_ERR, "rrdtool plugin: malloc failed: %s",
+ strerror (errno));
+ return (-1);
+ }
+ memset (ds_def, '\0', ds->ds_num * sizeof (char *));
+
+ for (ds_num = 0; ds_num < ds->ds_num; ds_num++)
+ {
+ data_source_t *d = ds->ds + ds_num;
+ char *type;
+ int status;
+
+ ds_def[ds_num] = NULL;
+
+ if (d->type == DS_TYPE_COUNTER)
+ type = "COUNTER";
+ else if (d->type == DS_TYPE_GAUGE)
+ type = "GAUGE";
+ else
+ {
+ syslog (LOG_ERR, "rrdtool plugin: Unknown DS type: %i",
+ d->type);
+ break;
+ }
+
+ if (d->min == NAN)
+ {
+ strcpy (min, "U");
+ }
+ else
+ {
+ snprintf (min, sizeof (min), "%lf", d->min);
+ min[sizeof (min) - 1] = '\0';
+ }
+
+ if (d->max == NAN)
+ {
+ strcpy (max, "U");
+ }
+ else
+ {
+ snprintf (max, sizeof (max), "%lf", d->max);
+ max[sizeof (max) - 1] = '\0';
+ }
+
+ status = snprintf (buffer, sizeof (buffer),
+ "DS:%s:%s:%s:%s:%s",
+ d->name, type, COLLECTD_HEARTBEAT,
+ min, max);
+ if ((status < 1) || (status >= sizeof (buffer)))
+ break;
+
+ ds_def[ds_num] = sstrdup (buffer);
+ } /* for ds_num = 0 .. ds->ds_num */
+
+#if COLLECT_DEBUG
+{
+ int i;
+ DBG ("ds_num = %i", ds_num);
+ for (i = 0; i < ds_num; i++)
+ DBG (" %s", ds_def[i]);
+}
+#endif
+
+ if (ds_num != ds->ds_num)
+ {
+ ds_free (ds_num, ds_def);
+ return (-1);
+ }
+
+ *ret = ds_def;
+ return (ds_num);
+}
+
+static int rrd_create_file (char *filename, const data_set_t *ds)
+{
+ char **argv;
+ int argc;
+ char **rra_def;
+ int rra_num;
+ char **ds_def;
+ int ds_num;
+ int i, j;
+ int status = 0;
+
+ if (check_create_dir (filename))
+ return (-1);
+
+ if ((rra_num = rra_get (&rra_def)) < 1)
+ {
+ syslog (LOG_ERR, "rrd_create_file failed: Could not calculate RRAs");
+ return (-1);
+ }
+
+ if ((ds_num = ds_get (&ds_def, ds)) < 1)
+ {
+ syslog (LOG_ERR, "rrd_create_file failed: Could not calculate DSes");
+ return (-1);
+ }
+
+ argc = ds_num + rra_num + 4;
+
+ if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
+ {
+ syslog (LOG_ERR, "rrd_create failed: %s", strerror (errno));
+ return (-1);
+ }
+
+ argv[0] = "create";
+ argv[1] = filename;
+ argv[2] = "-s";
+ argv[3] = COLLECTD_STEP;
+
+ j = 4;
+ for (i = 0; i < ds_num; i++)
+ argv[j++] = ds_def[i];
+ for (i = 0; i < rra_num; i++)
+ argv[j++] = rra_def[i];
+ argv[j] = NULL;
+
+ optind = 0; /* bug in librrd? */
+ rrd_clear_error ();
+ if (rrd_create (argc, argv) == -1)
+ {
+ syslog (LOG_ERR, "rrd_create failed: %s: %s", filename, rrd_get_error ());
+ status = -1;
+ }
+
+ free (argv);
+ ds_free (ds_num, ds_def);
+
+ return (status);
+}
+
+static int value_list_to_string (char *buffer, int buffer_len,
+ const data_set_t *ds, const value_list_t *vl)
+{
+ int offset;
+ int status;
+ int i;
+
+ memset (buffer, '\0', sizeof (buffer_len));
+
+ status = snprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+ if ((status < 1) || (status >= buffer_len))
+ return (-1);
+ offset = status;
+
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ if ((ds->ds[i].type != DS_TYPE_COUNTER)
+ && (ds->ds[i].type != DS_TYPE_GAUGE))
+ return (-1);
+
+ if (ds->ds[i].type == DS_TYPE_COUNTER)
+ status = snprintf (buffer + offset, buffer_len - offset,
+ ":%llu", vl->values[i].counter);
+ else
+ status = snprintf (buffer + offset, buffer_len - offset,
+ ":%lf", vl->values[i].gauge);
+
+ if ((status < 1) || (status >= (buffer_len - offset)))
+ return (-1);
+
+ offset += status;
+ } /* for ds->ds_num */
+
+ return (0);
+} /* int value_list_to_string */
+
+static int value_list_to_filename (char *buffer, int buffer_len,
+ const data_set_t *ds, const value_list_t *vl)
+{
+ int offset = 0;
+ int status;
+
+ status = snprintf (buffer + offset, buffer_len - offset,
+ "%s/", vl->host);
+ if ((status < 1) || (status >= buffer_len - offset))
+ return (-1);
+ offset += status;
+
+ if (strlen (vl->plugin_instance) > 0)
+ status = snprintf (buffer + offset, buffer_len - offset,
+ "%s-%s/", vl->plugin, vl->plugin_instance);
+ else
+ status = snprintf (buffer + offset, buffer_len - offset,
+ "%s/", vl->plugin);
+ if ((status < 1) || (status >= buffer_len - offset))
+ return (-1);
+ offset += status;
+
+ if (strlen (vl->type_instance) > 0)
+ status = snprintf (buffer + offset, buffer_len - offset,
+ "%s-%s.rrd", ds->type, vl->type_instance);
+ else
+ status = snprintf (buffer + offset, buffer_len - offset,
+ "%s.rrd", ds->type);
+ if ((status < 1) || (status >= buffer_len - offset))
+ return (-1);
+ offset += status;
+
+ return (0);
+} /* int value_list_to_filename */
+
+static rrd_cache_t *rrd_cache_insert (const char *filename,
+ const char *value)
+{
+ rrd_cache_t *rc = NULL;
+ llentry_t *le = NULL;
+
+ if (cache != NULL)
+ {
+ le = llist_search (cache, filename);
+ if (le != NULL)
+ rc = (rrd_cache_t *) le->value;
+ }
+
+ if (rc == NULL)
+ {
+ rc = (rrd_cache_t *) malloc (sizeof (rrd_cache_t));
+ if (rc == NULL)
+ return (NULL);
+ rc->values_num = 0;
+ rc->values = NULL;
+ rc->first_value = 0;
+ }
+
+ rc->values = (char **) realloc ((void *) rc->values,
+ (rc->values_num + 1) * sizeof (char *));
+ if (rc->values == NULL)
+ {
+ syslog (LOG_ERR, "rrdtool plugin: realloc failed: %s",
+ strerror (errno));
+ free (rc);
+ if (le != NULL)
+ {
+ llist_remove (cache, le);
+ llentry_destroy (le);
+ }
+ return (NULL);
+ }
+
+ rc->values[rc->values_num] = strdup (value);
+ if (rc->values[rc->values_num] != NULL)
+ rc->values_num++;
+
+ if (rc->values_num == 1)
+ rc->first_value = time (NULL);
+
+ if ((cache != NULL) && (le == NULL))
+ {
+ le = llentry_create (filename, (void *) rc);
+ if (le != NULL)
+ llist_prepend (cache, le);
+ }
+
+ DBG ("rrd_cache_insert (%s, %s) = %p", filename, value, (void *) rc);
+
+ return (rc);
+} /* rrd_cache_t *rrd_cache_insert */
+
+static int rrd_write_cache_entry (const char *filename, rrd_cache_t *rc)
+{
+ char **argv;
+ int argc;
+
+ char *fn;
+ int status;
+
+ argc = rc->values_num + 2;
+ argv = (char **) malloc ((argc + 1) * sizeof (char *));
+ if (argv == NULL)
+ return (-1);
+
+ fn = strdup (filename);
+ if (fn == NULL)
+ {
+ free (argv);
+ return (-1);
+ }
+
+ argv[0] = "update";
+ argv[1] = fn;
+ memcpy (argv + 2, rc->values, rc->values_num * sizeof (char *));
+ argv[argc] = NULL;
+
+ DBG ("rrd_update (argc = %i, argv = %p)", argc, (void *) argv);
+
+ optind = 0; /* bug in librrd? */
+ rrd_clear_error ();
+ status = rrd_update (argc, argv);
+
+ free (argv);
+ free (fn);
+
+ free (rc->values);
+ rc->values = NULL;
+ rc->values_num = 0;
+
+ if (status != 0)
+ {
+ syslog (LOG_WARNING, "rrd_update failed: %s: %s",
+ filename, rrd_get_error ());
+ return (-1);
+ }
+
+ return (0);
+} /* int rrd_update_file */
+
+static void rrd_cache_flush (int timeout)
+{
+ llentry_t *le;
+ rrd_cache_t *rc;
+ time_t now;
+
+ if (cache == NULL)
+ return;
+
+ DBG ("Flushing cache, timeout = %i", timeout);
+
+ now = time (NULL);
+
+ /* Remove empty entries */
+ le = llist_head (cache);
+ while (le != NULL)
+ {
+ llentry_t *next = le->next;
+ rc = (rrd_cache_t *) le->value;
+ if (rc->values_num == 0)
+ {
+ DBG ("Removing cache entry for `%s'", le->key);
+ free (rc->values);
+ free (rc);
+ llist_remove (cache, le);
+ }
+ le = next;
+ }
+
+ /* Write timed out entries */
+ le = llist_head (cache);
+ while (le != NULL)
+ {
+ rc = (rrd_cache_t *) le->value;
+ if ((now - rc->first_value) >= timeout)
+ rrd_write_cache_entry (le->key, rc);
+
+ le = le->next;
+ }
+
+ cache_flush = now;
+} /* void rrd_cache_flush */
+
+static int rrd_write (const data_set_t *ds, const value_list_t *vl)
+{
+ struct stat statbuf;
+ char filename[512];
+ char values[512];
+ rrd_cache_t *rc;
+ time_t now;
+
+ if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
+ return (-1);
+
+ if (value_list_to_string (values, sizeof (values), ds, vl) != 0)
+ return (-1);
+
+ if (stat (filename, &statbuf) == -1)
+ {
+ if (errno == ENOENT)
+ {
+ if (rrd_create_file (filename, ds))
+ return (-1);
+ }
+ else
+ {
+ syslog (LOG_ERR, "stat(%s) failed: %s",
+ filename, strerror (errno));
+ return (-1);
+ }
+ }
+ else if (!S_ISREG (statbuf.st_mode))
+ {
+ syslog (LOG_ERR, "stat(%s): Not a regular file!",
+ filename);
+ return (-1);
+ }
+
+ rc = rrd_cache_insert (filename, values);
+ if (rc == NULL)
+ return (-1);
+
+ if (cache == NULL)
+ {
+ rrd_write_cache_entry (filename, rc);
+ free (rc->values);
+ free (rc);
+ return (0);
+ }
+
+ now = time (NULL);
+
+ DBG ("age (%s) = %i", filename, now - rc->first_value);
+
+ if ((now - rc->first_value) >= cache_timeout)
+ rrd_write_cache_entry (filename, rc);
+
+ if ((time (NULL) - cache_flush) >= cache_timeout)
+ {
+ rrd_cache_flush (cache_timeout);
+ }
+
+ return (0);
+} /* int rrd_dispatch */
+
+static int rrd_config (const char *key, const char *val)
+{
+ if (strcasecmp ("CacheTimeout", key) == 0)
+ {
+ int tmp = atoi (val);
+ if (tmp < 0)
+ {
+ fprintf (stderr, "rrdtool: `CacheTimeout' must "
+ "be greater than 0.\n");
+ return (1);
+ }
+ cache_timeout = tmp;
+ }
+ else
+ {
+ return (-1);
+ }
+ return (0);
+} /* int rrd_config */
+
+static int rrd_shutdown (void)
+{
+ rrd_cache_flush (-1);
+
+ return (0);
+} /* int rrd_shutdown */
+
+static int rrd_init (void)
+{
+ if (cache_timeout < 2)
+ {
+ cache_timeout = 0;
+ }
+ else
+ {
+ cache = llist_create ();
+ cache_flush = time (NULL);
+ plugin_register_shutdown ("rrdtool", rrd_shutdown);
+ }
+ return (0);
+} /* int rrd_init */
+
+void module_register (void)
+{
+ plugin_register_config ("rrdtool", rrd_config,
+ config_keys, config_keys_num);
+ plugin_register_init ("rrdtool", rrd_init);
+ plugin_register_write ("rrdtool", rrd_write);
+}
* - config IgnoreSelected option
**/
+
+
#include "collectd.h"
#include "common.h"
#include "plugin.h"
#include "utils_ignorelist.h"
#include "utils_debug.h"
-#define MODULE_NAME "sensors"
-#define MODULE_NAME_VOLTAGE MODULE_NAME"_voltage"
+/*
+ * This weird macro cascade forces the glibc to define `NAN'. I don't know
+ * another way to solve this, so more intelligent solutions are welcome. -octo
+ */
+#ifndef __USE_ISOC99
+# define DISABLE__USE_ISOC99 1
+# define __USE_ISOC99 1
+#endif
+#include <math.h>
+#ifdef DISABLE__USE_ISOC99
+# undef DISABLE__USE_ISOC99
+# undef __USE_ISOC99
+#endif
#if defined(HAVE_SENSORS_SENSORS_H)
# include <sensors/sensors.h>
# define SENSORS_HAVE_READ 0
#endif
-#define BUFSIZE 512
-
-/* temperature and fan sensors */
-static char *ds_def[] =
+static data_source_t data_source[1] =
{
- "DS:value:GAUGE:"COLLECTD_HEARTBEAT":U:U",
- NULL
+ {"value", DS_TYPE_GAUGE, NAN, NAN}
};
-static int ds_num = 1;
-
-/* voltage sensors */
-static char *sensor_voltage_ds_def[] =
+static data_set_t fanspeed_ds =
{
- "DS:voltage:GAUGE:"COLLECTD_HEARTBEAT":U:U",
- NULL
+ "fanspeed", 1, data_source
};
-static int sensor_voltage_ds_num = 1;
-
-/* old naming */
-static char *old_filename_format = "sensors-%s.rrd";
-/* end old naming */
-/* new naming <chip-bus-address/type-feature */
-static char *extended_filename_format = "lm_sensors-%s.rrd";
+static data_set_t temperature_ds =
+{
+ "temperature", 1, data_source
+};
-#define SENSOR_TYPE_UNKNOWN 0
-#define SENSOR_TYPE_VOLTAGE 1
-#define SENSOR_TYPE_FANSPEED 2
-#define SENSOR_TYPE_TEMPERATURE 3
+static data_set_t voltage_ds =
+{
+ "voltage", 1, data_source
+};
#if SENSORS_HAVE_READ
-static char *sensor_type_prefix[] =
+#define SENSOR_TYPE_VOLTAGE 0
+#define SENSOR_TYPE_FANSPEED 1
+#define SENSOR_TYPE_TEMPERATURE 2
+#define SENSOR_TYPE_UNKNOWN 3
+
+static char *sensor_to_type[] =
{
- "unknown",
"voltage",
"fanspeed",
"temperature",
NULL
};
-#endif
-typedef struct sensors_labeltypes {
+struct sensors_labeltypes_s
+{
char *label;
int type;
-} sensors_labeltypes;
+};
+typedef struct sensors_labeltypes_s sensors_labeltypes_t;
/*
* finite list of known labels extracted from lm_sensors
*/
-#if SENSORS_HAVE_READ
-static sensors_labeltypes known_features[] =
+static sensors_labeltypes_t known_features[] =
{
{ "fan1", SENSOR_TYPE_FANSPEED },
{ "fan2", SENSOR_TYPE_FANSPEED },
{ "2.5V", SENSOR_TYPE_VOLTAGE },
{ "2.0V", SENSOR_TYPE_VOLTAGE },
{ "12V", SENSOR_TYPE_VOLTAGE },
- { 0, -1 }
+ { (char *) 0, SENSOR_TYPE_UNKNOWN }
};
-#endif
/* end new naming */
-static char *config_keys[] =
+static const char *config_keys[] =
{
"Sensor",
"IgnoreSelected",
- "ExtendedSensorNaming",
NULL
};
-static int config_keys_num = 3;
+static int config_keys_num = 2;
static ignorelist_t *sensor_list;
-/*
- * sensor_extended_naming:
- * 0 => default is to create chip-feature
- * 1 => use new naming scheme chip-bus-address/type-feature
- */
-static int sensor_extended_naming = 0;
-
-#if SENSORS_HAVE_READ
-# ifndef SENSORS_CONF_PATH
-# define SENSORS_CONF_PATH "/etc/sensors.conf"
-# endif
+#ifndef SENSORS_CONF_PATH
+# define SENSORS_CONF_PATH "/etc/sensors.conf"
+#endif
static const char *conffile = SENSORS_CONF_PATH;
/* SENSORS_CONF_PATH */
} featurelist_t;
featurelist_t *first_feature = NULL;
-#endif /* if SENSORS_HAVE_READ */
-static int sensors_config (char *key, char *value)
+static int sensors_config (const char *key, const char *value)
{
if (sensor_list == NULL)
sensor_list = ignorelist_create (1);
{
if (ignorelist_add (sensor_list, value))
{
- syslog (LOG_EMERG, MODULE_NAME": Cannot add value to ignorelist.");
+ syslog (LOG_ERR, "sensors plugin: "
+ "Cannot add value to ignorelist.");
return (1);
}
}
|| (strcasecmp (value, "On") == 0))
ignorelist_set_invert (sensor_list, 0);
}
- else if (strcasecmp (key, "ExtendedSensorNaming") == 0)
- {
- if ((strcasecmp (value, "True") == 0)
- || (strcasecmp (value, "Yes") == 0)
- || (strcasecmp (value, "On") == 0))
- sensor_extended_naming = 1;
- else
- sensor_extended_naming = 0;
- }
else
{
return (-1);
return (0);
}
-#if SENSORS_HAVE_READ
void sensors_free_features (void)
{
featurelist_t *thisft;
status = stat (conffile, &statbuf);
if (status != 0)
{
- syslog (LOG_ERR, MODULE_NAME": stat(%s) failed: %s",
+ syslog (LOG_ERR, "sensors plugin: stat (%s) failed: %s",
conffile, strerror (errno));
sensors_config_mtime = 0;
}
if (sensors_config_mtime != 0)
{
- syslog (LOG_NOTICE, MODULE_NAME": Reloading config from %s",
+ syslog (LOG_NOTICE, "sensors plugin: Reloading config from %s",
conffile);
sensors_free_features ();
sensors_config_mtime = 0;
fh = fopen (conffile, "r");
if (fh == NULL)
{
- syslog (LOG_ERR, MODULE_NAME": fopen(%s) failed: %s",
+ syslog (LOG_ERR, "sensors plugin: fopen(%s) failed: %s",
conffile, strerror(errno));
return;
}
fclose (fh);
if (status != 0)
{
- syslog (LOG_ERR, MODULE_NAME": Cannot initialize sensors. "
+ syslog (LOG_ERR, "sensors plugin: Cannot initialize sensors. "
"Data will not be collected.");
return;
}
if ((new_feature = (featurelist_t *) malloc (sizeof (featurelist_t))) == NULL)
{
DBG ("malloc: %s", strerror (errno));
- syslog (LOG_ERR, MODULE_NAME": malloc: %s",
+ syslog (LOG_ERR, "sensors plugin: malloc: %s",
strerror (errno));
break;
}
if (first_feature == NULL)
{
sensors_cleanup ();
- syslog (LOG_INFO, MODULE_NAME": lm_sensors reports no features. "
- "Data will not be collected.");
+ syslog (LOG_INFO, "sensors plugin: lm_sensors reports no "
+ "features. Data will not be collected.");
}
} /* void sensors_load_conf */
-#endif /* if SENSORS_HAVE_READ */
-
-static void collectd_sensors_init (void)
-{
- return;
-}
-static void sensors_shutdown (void)
+static int sensors_shutdown (void)
{
-#if SENSORS_HAVE_READ
sensors_free_features ();
-#endif /* if SENSORS_HAVE_READ */
-
- if (NULL != sensor_list)
- ignorelist_free (sensor_list);
-}
-
-static void sensors_voltage_write (char *host, char *inst, char *val)
-{
- char file[BUFSIZE];
- int status;
-
- /* skip ignored in our config */
- if ((NULL != sensor_list) && ignorelist_match (sensor_list, inst))
- return;
-
- /* extended sensor naming */
- if(sensor_extended_naming)
- status = snprintf (file, BUFSIZE, extended_filename_format, inst);
- else
- status = snprintf (file, BUFSIZE, old_filename_format, inst);
-
- if ((status < 1) || (status >= BUFSIZE))
- return;
-
- rrd_update_file (host, file, val, sensor_voltage_ds_def, sensor_voltage_ds_num);
-}
-
-static void sensors_write (char *host, char *inst, char *val)
-{
- char file[BUFSIZE];
- int status;
-
- /* skip ignored in our config */
- if ((NULL != sensor_list) && ignorelist_match (sensor_list, inst))
- return;
-
- /* extended sensor naming */
- if (sensor_extended_naming)
- status = snprintf (file, BUFSIZE, extended_filename_format, inst);
- else
- status = snprintf (file, BUFSIZE, old_filename_format, inst);
-
- if ((status < 1) || (status >= BUFSIZE))
- return;
+ ignorelist_free (sensor_list);
- rrd_update_file (host, file, val, ds_def, ds_num);
-}
+ return (0);
+} /* int sensors_shutdown */
-#if SENSORS_HAVE_READ
-static void sensors_submit (const char *feat_name,
- const char *chip_prefix, double value, int type)
+static void sensors_submit (const char *plugin_instance,
+ const char *type, const char *type_instance,
+ double val)
{
- char buf[BUFSIZE];
- char inst[BUFSIZE];
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
- if (snprintf (inst, BUFSIZE, "%s-%s", chip_prefix, feat_name)
- >= BUFSIZE)
+ if (ignorelist_match (sensor_list, type_instance))
return;
- /* skip ignored in our config */
- if ((NULL != sensor_list) && ignorelist_match (sensor_list, inst))
- return;
+ values[0].gauge = val;
- if (snprintf (buf, BUFSIZE, "%u:%.3f", (unsigned int) curtime,
- value) >= BUFSIZE)
- return;
+ vl.values = values;
+ vl.values_len = 1;
+ vl.time = time (NULL);
+ strcpy (vl.host, hostname);
+ strcpy (vl.plugin, "sensors");
+ strcpy (vl.plugin_instance, plugin_instance);
+ strcpy (vl.type_instance, type_instance);
- if (type == SENSOR_TYPE_VOLTAGE)
- {
- DBG ("%s: %s/%s, %s", MODULE_NAME_VOLTAGE,
- sensor_type_prefix[type], inst, buf);
- plugin_submit (MODULE_NAME_VOLTAGE, inst, buf);
- }
- else
- {
- DBG ("%s: %s/%s, %s", MODULE_NAME,
- sensor_type_prefix[type], inst, buf);
- plugin_submit (MODULE_NAME, inst, buf);
- }
-}
+ plugin_dispatch_values (type, &vl);
+} /* void sensors_submit */
-static void sensors_read (void)
+static int sensors_read (void)
{
featurelist_t *feature;
double value;
- char chip_fullprefix[BUFSIZE];
+ char chip_fullprefix[512];
+
+ char plugin_instance[DATA_MAX_NAME_LEN];
+ char type_instance[DATA_MAX_NAME_LEN];
sensors_load_conf ();
if (sensors_get_feature (*feature->chip, feature->data->number, &value) < 0)
continue;
- if (sensor_extended_naming)
+ /* full chip name logic borrowed from lm_sensors */
+ if (feature->chip->bus == SENSORS_CHIP_NAME_BUS_ISA)
{
- /* full chip name logic borrowed from lm_sensors */
- if (feature->chip->bus == SENSORS_CHIP_NAME_BUS_ISA)
- {
- if (snprintf (chip_fullprefix, BUFSIZE, "%s-isa-%04x/%s",
- feature->chip->prefix,
- feature->chip->addr,
- sensor_type_prefix[feature->type])
- >= BUFSIZE)
- continue;
- }
- else if (feature->chip->bus == SENSORS_CHIP_NAME_BUS_DUMMY)
- {
- if (snprintf (chip_fullprefix, BUFSIZE, "%s-%s-%04x/%s",
- feature->chip->prefix,
- feature->chip->busname,
- feature->chip->addr,
- sensor_type_prefix[feature->type])
- >= BUFSIZE)
- continue;
- }
- else
- {
- if (snprintf (chip_fullprefix, BUFSIZE, "%s-i2c-%d-%02x/%s",
- feature->chip->prefix,
- feature->chip->bus,
- feature->chip->addr,
- sensor_type_prefix[feature->type])
- >= BUFSIZE)
- continue;
- }
-
- sensors_submit (feature->data->name,
- chip_fullprefix,
- value, feature->type);
+ if (snprintf (plugin_instance, DATA_MAX_NAME_LEN, "%s-isa-%04x",
+ feature->chip->prefix,
+ feature->chip->addr)
+ >= 512)
+ continue;
+ }
+ else if (feature->chip->bus == SENSORS_CHIP_NAME_BUS_DUMMY)
+ {
+ if (snprintf (plugin_instance, 512, "%s-%s-%04x",
+ feature->chip->prefix,
+ feature->chip->busname,
+ feature->chip->addr)
+ >= 512)
+ continue;
}
else
{
- sensors_submit (feature->data->name,
- feature->chip->prefix,
- value, feature->type);
+ if (snprintf (plugin_instance, 512, "%s-i2c-%d-%02x",
+ feature->chip->prefix,
+ feature->chip->bus,
+ feature->chip->addr)
+ >= 512)
+ continue;
}
+
+ strncpy (type_instance, feature->data->name, DATA_MAX_NAME_LEN);
+
+ sensors_submit (plugin_instance,
+ sensor_to_type[feature->type]
+ type_instance,
+ value);
} /* for feature = first_feature .. NULL */
-} /* void sensors_read */
-#else
-# define sensors_read NULL
+} /* int sensors_read */
#endif /* SENSORS_HAVE_READ */
void module_register (void)
{
- plugin_register (MODULE_NAME, collectd_sensors_init, sensors_read, sensors_write);
- plugin_register (MODULE_NAME_VOLTAGE, NULL, NULL, sensors_voltage_write);
- plugin_register_shutdown (MODULE_NAME, sensors_shutdown);
- cf_register (MODULE_NAME, sensors_config, config_keys, config_keys_num);
-}
+ plugin_register_data_set (&fanspeed_ds);
+ plugin_register_data_set (&temperature_ds);
+ plugin_register_data_set (&voltage_ds);
-#undef BUFSIZE
-#undef MODULE_NAME
+#if SENSORS_HAVE_READ
+ plugin_register_config ("sensors", sensors_config,
+ config_keys, config_keys_num);
+ plugin_register_read ("sensors", sensors_read);
+ plugin_register_shutdown ("sensors", sensors_shutdown);
+#endif
+} /* void module_register */
/*
* (Module-)Global variables
*/
-/* TODO: Move this to `interface-%s/<blah>.rrd' in version 4. */
-static char *bytes_file = "traffic-%s.rrd";
-static char *packets_file = "interface-%s/if_packets.rrd";
-static char *errors_file = "interface-%s/if_errors.rrd";
-/* TODO: Maybe implement multicast and broadcast counters */
+/* 2^32 = 4294967296 = ~4.2GByte/s = ~34GBit/s */
+static data_source_t octets_dsrc[2] =
+{
+ {"rx", DS_TYPE_COUNTER, 0, 4294967295.0},
+ {"tx", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
-static char *config_keys[] =
+static data_set_t octets_ds =
{
- "Interface",
- "IgnoreSelected",
- NULL
+ "if_octets", 2, octets_dsrc
};
-static int config_keys_num = 2;
-static char *bytes_ds_def[] =
+static data_source_t packets_dsrc[2] =
{
- "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- NULL
+ {"rx", DS_TYPE_COUNTER, 0, 4294967295.0},
+ {"tx", DS_TYPE_COUNTER, 0, 4294967295.0}
};
-static int bytes_ds_num = 2;
-static char *packets_ds_def[] =
+static data_set_t packets_ds =
{
- "DS:rx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:tx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- NULL
+ "if_packets", 2, packets_dsrc
+};
+
+static data_source_t errors_dsrc[2] =
+{
+ {"rx", DS_TYPE_COUNTER, 0, 4294967295.0},
+ {"tx", DS_TYPE_COUNTER, 0, 4294967295.0}
};
-static int packets_ds_num = 2;
-static char *errors_ds_def[] =
+static data_set_t errors_ds =
{
- "DS:rx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:tx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
+ "if_errors", 2, errors_dsrc
+};
+
+static const char *config_keys[] =
+{
+ "Interface",
+ "IgnoreSelected",
NULL
};
-static int errors_ds_num = 2;
+static int config_keys_num = 2;
static char **if_list = NULL;
static int if_list_num = 0;
static int numif = 0;
#endif /* HAVE_LIBKSTAT */
-static int traffic_config (char *key, char *value)
+static int interface_config (const char *key, const char *value)
{
char **temp;
return (0);
}
-static void traffic_init (void)
+#if HAVE_LIBKSTAT
+static int traffic_init (void)
{
-#if HAVE_GETIFADDRS
- /* nothing */
-/* #endif HAVE_GETIFADDRS */
-
-#elif KERNEL_LINUX
- /* nothing */
-/* #endif KERNEL_LINUX */
-
-#elif HAVE_LIBKSTAT
+#if HAVE_LIBKSTAT
kstat_t *ksp_chain;
unsigned long long val;
numif = 0;
if (kc == NULL)
- return;
+ return (-1);
for (numif = 0, ksp_chain = kc->kc_chain;
(numif < MAX_NUMIF) && (ksp_chain != NULL);
continue;
ksp[numif++] = ksp_chain;
}
-/* #endif HAVE_LIBKSTAT */
-
-#elif HAVE_LIBSTATG
- /* nothing */
-#endif /* HAVE_LIBSTATG */
+#endif /* HAVE_LIBKSTAT */
- return;
-}
+ return (0);
+} /* int traffic_init */
+#endif /* HAVE_LIBKSTAT */
/*
* Check if this interface/instance should be ignored. This is called from
if (strcasecmp (interface, if_list[i]) == 0)
return (if_list_action);
return (1 - if_list_action);
-}
-
-static void generic_write (char *host, char *inst, char *val,
- char *file_template,
- char **ds_def, int ds_num)
-{
- char file[512];
- int status;
-
- if (check_ignore_if (inst))
- return;
-
- status = snprintf (file, BUFSIZE, file_template, inst);
- if (status < 1)
- return;
- else if (status >= 512)
- return;
-
- rrd_update_file (host, file, val, ds_def, ds_num);
-}
-
-static void bytes_write (char *host, char *inst, char *val)
-{
- generic_write (host, inst, val, bytes_file, bytes_ds_def, bytes_ds_num);
-}
-
-static void packets_write (char *host, char *inst, char *val)
-{
- generic_write (host, inst, val, packets_file, packets_ds_def, packets_ds_num);
-}
-
-static void errors_write (char *host, char *inst, char *val)
-{
- generic_write (host, inst, val, errors_file, errors_ds_def, errors_ds_num);
-}
+} /* int check_ignore_if */
#if TRAFFIC_HAVE_READ
-static void bytes_submit (char *dev,
+static void if_submit (const char *dev, const char *type,
unsigned long long rx,
unsigned long long tx)
{
- char buf[512];
- int status;
+ value_t values[2];
+ value_list_t vl = VALUE_LIST_INIT;
if (check_ignore_if (dev))
return;
- status = snprintf (buf, 512, "%u:%lld:%lld",
- (unsigned int) curtime,
- rx, tx);
- if ((status >= 512) || (status < 1))
- return;
-
- plugin_submit (MODULE_NAME, dev, buf);
-}
-
-#if HAVE_GETIFADDRS || KERNEL_LINUX || HAVE_LIBKSTAT
-static void packets_submit (char *dev,
- unsigned long long rx,
- unsigned long long tx)
-{
- char buf[512];
- int status;
-
- if (check_ignore_if (dev))
- return;
-
- status = snprintf (buf, 512, "%u:%lld:%lld",
- (unsigned int) curtime,
- rx, tx);
- if ((status >= 512) || (status < 1))
- return;
- plugin_submit ("if_packets", dev, buf);
-}
-
-static void errors_submit (char *dev,
- unsigned long long rx,
- unsigned long long tx)
-{
- char buf[512];
- int status;
+ values[0].counter = rx;
+ values[1].counter = tx;
- if (check_ignore_if (dev))
- return;
+ vl.values = values;
+ vl.values_len = 2;
+ vl.time = time (NULL);
+ strcpy (vl.host, hostname);
+ strcpy (vl.plugin, "interface");
+ strcpy (vl.plugin_instance, "");
+ strncpy (vl.type_instance, dev, sizeof (vl.type_instance));
- status = snprintf (buf, 512, "%u:%lld:%lld",
- (unsigned int) curtime,
- rx, tx);
- if ((status >= 512) || (status < 1))
- return;
- plugin_submit ("if_errors", dev, buf);
-}
-#endif /* HAVE_GETIFADDRS || KERNEL_LINUX || HAVE_LIBKSTAT */
+ plugin_dispatch_values (type, &vl);
+} /* void if_submit */
-static void traffic_read (void)
+static int traffic_read (void)
{
#if HAVE_GETIFADDRS
struct ifaddrs *if_list;
if ((if_data = (struct IFA_DATA *) if_ptr->ifa_data) == NULL)
continue;
- bytes_submit (if_ptr->ifa_name,
+ if_submit (if_ptr->ifa_name, "if_octets",
if_data->IFA_RX_BYTES,
if_data->IFA_TX_BYTES);
- packets_submit (if_ptr->ifa_name,
+ if_submit (if_ptr->ifa_name, "if_packets",
if_data->IFA_RX_PACKT,
if_data->IFA_TX_PACKT);
- errors_submit (if_ptr->ifa_name,
+ if_submit (if_ptr->ifa_name, "if_errors",
if_data->IFA_RX_ERROR,
if_data->IFA_TX_ERROR);
}
if ((fh = fopen ("/proc/net/dev", "r")) == NULL)
{
syslog (LOG_WARNING, "traffic: fopen: %s", strerror (errno));
- return;
+ return (-1);
}
while (fgets (buffer, 1024, fh) != NULL)
incoming = atoll (fields[0]);
outgoing = atoll (fields[8]);
- bytes_submit (device, incoming, outgoing);
+ if_submit (device, "if_octets", incoming, outgoing);
incoming = atoll (fields[1]);
outgoing = atoll (fields[9]);
- packets_submit (device, incoming, outgoing);
+ if_submit (device, "if_packets", incoming, outgoing);
incoming = atoll (fields[2]);
outgoing = atoll (fields[10]);
- errors_submit (device, incoming, outgoing);
+ if_submit (device, "if_errors", incoming, outgoing);
}
fclose (fh);
rx = get_kstat_value (ksp[i], "rbytes");
tx = get_kstat_value (ksp[i], "obytes");
if ((rx != -1LL) || (tx != -1LL))
- bytes_submit (ksp[i]->ks_name, rx, tx);
+ if_submit (ksp[i]->ks_name, "if_octets", rx, tx);
rx = get_kstat_value (ksp[i], "ipackets");
tx = get_kstat_value (ksp[i], "opackets");
if ((rx != -1LL) || (tx != -1LL))
- packets_submit (ksp[i]->ks_name, rx, tx);
+ if_submit (ksp[i]->ks_name, "if_packets", rx, tx);
rx = get_kstat_value (ksp[i], "ierrors");
tx = get_kstat_value (ksp[i], "oerrors");
if ((rx != -1LL) || (tx != -1LL))
- errors_submit (ksp[i]->ks_name, rx, tx);
+ if_submit (ksp[i]->ks_name, "if_errors", rx, tx);
}
/* #endif HAVE_LIBKSTAT */
ios = sg_get_network_io_stats (&num);
for (i = 0; i < num; i++)
- bytes_submit (ios[i].interface_name, ios[i].rx, ios[i].tx);
+ if_submit (ios[i].interface_name, "if_octets", ios[i].rx, ios[i].tx);
#endif /* HAVE_LIBSTATGRAB */
-}
-#else
-#define traffic_read NULL
+
+ return (0);
+} /* int traffic_read */
#endif /* TRAFFIC_HAVE_READ */
void module_register (void)
{
- plugin_register (MODULE_NAME, traffic_init, traffic_read, bytes_write);
- plugin_register ("if_packets", NULL, NULL, packets_write);
- plugin_register ("if_errors", NULL, NULL, errors_write);
- cf_register (MODULE_NAME, traffic_config, config_keys, config_keys_num);
+ plugin_register_data_set (&octets_ds);
+ plugin_register_data_set (&packets_ds);
+ plugin_register_data_set (&errors_ds);
+
+ plugin_register_config ("interface", interface_config,
+ config_keys, config_keys_num);
+
+#if HAVE_LIBKSTAT
+ plugin_register_init ("interface", traffic_init);
+#endif
+
+#if TRAFFIC_HAVE_READ
+ plugin_register_read ("interface", traffic_read);
+#endif
}
#undef BUFSIZE
--- /dev/null
+/**
+ * collectd - src/utils_llist.c
+ * Copyright (C) 2006 Florian Forster <octo at verplant.org>
+ *
+ * This program is free software; you can redistribute it and/
+ * or modify it under the terms of the GNU General Public Li-
+ * cence as published by the Free Software Foundation; only
+ * version 2 of the Licence is applicable.
+ *
+ * This program is distributed in the hope that it will be use-
+ * ful, but WITHOUT ANY WARRANTY; without even the implied war-
+ * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * Licence along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ * Authors:
+ * Florian Forster <octo at verplant.org>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils_llist.h"
+
+/*
+ * Private data types
+ */
+struct llist_s
+{
+ llentry_t *head;
+ llentry_t *tail;
+};
+
+/*
+ * Public functions
+ */
+llist_t *llist_create (void)
+{
+ llist_t *ret;
+
+ ret = (llist_t *) malloc (sizeof (llist_t));
+ if (ret == NULL)
+ return (NULL);
+
+ memset (ret, '\0', sizeof (llist_t));
+
+ return (ret);
+}
+
+void llist_destroy (llist_t *l)
+{
+ llentry_t *e_this;
+ llentry_t *e_next;
+
+ for (e_this = l->head; e_this != NULL; e_this = e_next)
+ {
+ e_next = e_this->next;
+ llentry_destroy (e_this);
+ }
+
+ free (l);
+}
+
+llentry_t *llentry_create (const char *key, void *value)
+{
+ llentry_t *e;
+
+ e = (llentry_t *) malloc (sizeof (llentry_t));
+ if (e == NULL)
+ return (NULL);
+
+ e->key = strdup (key);
+ e->value = value;
+ e->next = NULL;
+
+ if (e->key == NULL)
+ {
+ free (e);
+ return (NULL);
+ }
+
+ return (e);
+}
+
+void llentry_destroy (llentry_t *e)
+{
+ free (e->key);
+ free (e);
+}
+
+void llist_append (llist_t *l, llentry_t *e)
+{
+ e->next = NULL;
+
+ if (l->tail == NULL)
+ l->head = e;
+ else
+ l->tail->next = e;
+
+ l->tail = e;
+}
+
+void llist_prepend (llist_t *l, llentry_t *e)
+{
+ e->next = l->head;
+ l->head = e;
+}
+
+void llist_remove (llist_t *l, llentry_t *e)
+{
+ llentry_t *prev;
+
+ prev = l->head;
+ while ((prev != NULL) && (prev->next != e))
+ prev = prev->next;
+
+ if (prev != NULL)
+ prev->next = e->next;
+ if (l->head == e)
+ l->head = e->next;
+ if (l->tail == e)
+ l->tail = prev;
+}
+
+llentry_t *llist_search (llist_t *l, const char *key)
+{
+ llentry_t *e;
+
+ for (e = l->head; e != NULL; e = e->next)
+ if (strcmp (key, e->key) == 0)
+ break;
+
+ return (e);
+}
+
+llentry_t *llist_head (llist_t *l)
+{
+ return (l->head);
+}
+
+llentry_t *llist_tail (llist_t *l)
+{
+ return (l->tail);
+}
--- /dev/null
+/**
+ * collectd - src/utils_llist.h
+ * Copyright (C) 2006 Florian Forster <octo at verplant.org>
+ *
+ * This program is free software; you can redistribute it and/
+ * or modify it under the terms of the GNU General Public Li-
+ * cence as published by the Free Software Foundation; only
+ * version 2 of the Licence is applicable.
+ *
+ * This program is distributed in the hope that it will be use-
+ * ful, but WITHOUT ANY WARRANTY; without even the implied war-
+ * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * Licence along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ * Authors:
+ * Florian Forster <octo at verplant.org>
+ */
+
+#ifndef UTILS_LLIST_H
+#define UTILS_LLIST_H 1
+
+/*
+ * Data types
+ */
+struct llentry_s
+{
+ char *key;
+ void *value;
+ struct llentry_s *next;
+};
+typedef struct llentry_s llentry_t;
+
+struct llist_s;
+typedef struct llist_s llist_t;
+
+/*
+ * Functions
+ */
+llist_t *llist_create (void);
+void llist_destroy (llist_t *l);
+
+llentry_t *llentry_create (const char *key, void *value);
+void llentry_destroy (llentry_t *e);
+
+void llist_append (llist_t *l, llentry_t *e);
+void llist_prepend (llist_t *l, llentry_t *e);
+void llist_remove (llist_t *l, llentry_t *e);
+
+llentry_t *llist_search (llist_t *l, const char *key);
+
+llentry_t *llist_head (llist_t *l);
+llentry_t *llist_tail (llist_t *l);
+
+#endif /* UTILS_LLIST_H */