**/
#include "collectd.h"
+
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include <netdb.h>
-#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
struct memcached_s
{
char *name;
- char *socket;
char *host;
- char *port;
+ char *socket;
+ char *connhost;
+ char *connport;
};
typedef struct memcached_s memcached_t;
static _Bool memcached_have_instances = 0;
-static void memcached_free (memcached_t *st)
+static void memcached_free (void *arg)
{
+ memcached_t *st = arg;
if (st == NULL)
return;
sfree (st->name);
- sfree (st->socket);
sfree (st->host);
- sfree (st->port);
+ sfree (st->socket);
+ sfree (st->connhost);
+ sfree (st->connport);
sfree (st);
}
static int memcached_connect_unix (memcached_t *st)
{
- struct sockaddr_un serv_addr;
+ struct sockaddr_un serv_addr = { 0 };
int fd;
- memset (&serv_addr, 0, sizeof (serv_addr));
serv_addr.sun_family = AF_UNIX;
sstrncpy (serv_addr.sun_path, st->socket,
sizeof (serv_addr.sun_path));
static int memcached_connect_inet (memcached_t *st)
{
- char *host;
- char *port;
-
- struct addrinfo ai_hints;
- struct addrinfo *ai_list, *ai_ptr;
+ struct addrinfo *ai_list;
int status;
int fd = -1;
- memset (&ai_hints, 0, sizeof (ai_hints));
- ai_hints.ai_flags = 0;
-#ifdef AI_ADDRCONFIG
- ai_hints.ai_flags |= AI_ADDRCONFIG;
-#endif
- ai_hints.ai_family = AF_UNSPEC;
- ai_hints.ai_socktype = SOCK_STREAM;
- ai_hints.ai_protocol = 0;
+ struct addrinfo ai_hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_flags = AI_ADDRCONFIG,
+ .ai_socktype = SOCK_STREAM
+ };
- host = (st->host != NULL) ? st->host : MEMCACHED_DEF_HOST;
- port = (st->port != NULL) ? st->port : MEMCACHED_DEF_PORT;
-
- ai_list = NULL;
- status = getaddrinfo (host, port, &ai_hints, &ai_list);
+ status = getaddrinfo (st->connhost, st->connport, &ai_hints, &ai_list);
if (status != 0)
{
char errbuf[1024];
ERROR ("memcached plugin: memcached_connect_inet: "
"getaddrinfo(%s,%s) failed: %s",
- host, port,
+ st->connhost, st->connport,
(status == EAI_SYSTEM)
? sstrerror (errno, errbuf, sizeof (errbuf))
: gai_strerror (status));
return (-1);
}
- for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
+ for (struct addrinfo *ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
{
/* create our socket descriptor */
fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
static int memcached_query_daemon (char *buffer, size_t buffer_size, memcached_t *st)
{
- int fd = -1;
- int status;
+ int fd, status;
size_t buffer_fill;
fd = memcached_connect (st);
static void memcached_init_vl (value_list_t *vl, memcached_t const *st)
{
sstrncpy (vl->plugin, "memcached", sizeof (vl->plugin));
- if (strcmp (st->name, "__legacy__") == 0) /* legacy mode */
- {
- sstrncpy (vl->host, hostname_g, sizeof (vl->host));
- }
- else
- {
- if (st->socket != NULL)
- sstrncpy (vl->host, hostname_g, sizeof (vl->host));
- else
- sstrncpy (vl->host,
- (st->host != NULL) ? st->host : MEMCACHED_DEF_HOST,
- sizeof (vl->host));
+ if (st->host != NULL)
+ sstrncpy (vl->host, st->host, sizeof (vl->host));
+ if (st->name != NULL)
sstrncpy (vl->plugin_instance, st->name, sizeof (vl->plugin_instance));
- }
}
static void submit_derive (const char *type, const char *type_inst,
derive_t value, memcached_t *st)
{
- value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
- memcached_init_vl (&vl, st);
-
- values[0].derive = value;
- vl.values = values;
+ memcached_init_vl (&vl, st);
+ vl.values = &(value_t) { .derive = value };
vl.values_len = 1;
sstrncpy (vl.type, type, sizeof (vl.type));
if (type_inst != NULL)
static void submit_derive2 (const char *type, const char *type_inst,
derive_t value0, derive_t value1, memcached_t *st)
{
- value_t values[2];
value_list_t vl = VALUE_LIST_INIT;
- memcached_init_vl (&vl, st);
-
- values[0].derive = value0;
- values[1].derive = value1;
+ value_t values[] = {
+ { .derive = value0 },
+ { .derive = value1 },
+ };
+ memcached_init_vl (&vl, st);
vl.values = values;
- vl.values_len = 2;
+ vl.values_len = STATIC_ARRAY_SIZE (values);
sstrncpy (vl.type, type, sizeof (vl.type));
if (type_inst != NULL)
sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
static void submit_gauge (const char *type, const char *type_inst,
gauge_t value, memcached_t *st)
{
- value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
- memcached_init_vl (&vl, st);
-
- values[0].gauge = value;
- vl.values = values;
+ memcached_init_vl (&vl, st);
+ vl.values = &(value_t) { .gauge = value };
vl.values_len = 1;
sstrncpy (vl.type, type, sizeof (vl.type));
if (type_inst != NULL)
static void submit_gauge2 (const char *type, const char *type_inst,
gauge_t value0, gauge_t value1, memcached_t *st)
{
- value_t values[2];
value_list_t vl = VALUE_LIST_INIT;
- memcached_init_vl (&vl, st);
-
- values[0].gauge = value0;
- values[1].gauge = value1;
+ value_t values[] = {
+ { .gauge = value0 },
+ { .gauge = value1 },
+ };
+ memcached_init_vl (&vl, st);
vl.values = values;
- vl.values_len = 2;
+ vl.values_len = STATIC_ARRAY_SIZE (values);
sstrncpy (vl.type, type, sizeof (vl.type));
if (type_inst != NULL)
sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
static int memcached_add_read_callback (memcached_t *st)
{
- user_data_t ud;
char callback_name[3*DATA_MAX_NAME_LEN];
int status;
- memset (&ud, 0, sizeof (ud));
- ud.data = st;
- ud.free_func = (void *) memcached_free;
+ ssnprintf (callback_name, sizeof (callback_name), "memcached/%s",
+ (st->name != NULL) ? st->name : "__legacy__");
+
+ /* If no <Address> used then:
+ * - Connect to the destination specified by <Host>, if present.
+ * If not, use the default address.
+ * - Use the default hostname (set st->host to NULL), if
+ * - Legacy mode is used (no configuration options at all), or
+ * - "Host" option is not provided, or
+ * - "Host" option is set to "localhost" or "127.0.0.1".
+ *
+ * If <Address> used then host may be set to "localhost" or "127.0.0.1"
+ * explicitly.
+ */
+ if (st->connhost == NULL)
+ {
+ if (st->host)
+ {
+ st->connhost = strdup(st->host);
+ if (st->connhost == NULL)
+ return (ENOMEM);
- assert (st->name != NULL);
- ssnprintf (callback_name, sizeof (callback_name), "memcached/%s", st->name);
+ if ((strcmp ("127.0.0.1", st->host) == 0)
+ || (strcmp ("localhost", st->host) == 0))
+ sfree(st->host);
+ }
+ else
+ {
+ st->connhost = strdup(MEMCACHED_DEF_HOST);
+ if (st->connhost == NULL)
+ return (ENOMEM);
+ }
+ }
+
+ if (st->connport == NULL)
+ {
+ st->connport = strdup(MEMCACHED_DEF_PORT);
+ if (st->connport == NULL)
+ return (ENOMEM);
+ }
+
+ assert (st->connhost != NULL);
+ assert (st->connport != NULL);
status = plugin_register_complex_read (/* group = */ "memcached",
/* name = */ callback_name,
/* callback = */ memcached_read,
- /* interval = */ NULL,
- /* user_data = */ &ud);
+ /* interval = */ 0,
+ &(user_data_t) {
+ .data = st,
+ .free_func = memcached_free,
+ });
+
return (status);
} /* int memcached_add_read_callback */
* <Plugin memcached>
* <Instance "instance_name">
* Host foo.zomg.com
+ * Address 1.2.3.4
* Port "1234"
* </Instance>
* </Plugin>
static int config_add_instance(oconfig_item_t *ci)
{
memcached_t *st;
- int i;
int status = 0;
/* Disable automatic generation of default instance in the init callback. */
memcached_have_instances = 1;
- st = malloc (sizeof (*st));
+ st = calloc (1, sizeof (*st));
if (st == NULL)
{
- ERROR ("memcached plugin: malloc failed.");
- return (-1);
+ ERROR ("memcached plugin: calloc failed.");
+ return (ENOMEM);
}
- memset (st, 0, sizeof (*st));
st->name = NULL;
- st->socket = NULL;
st->host = NULL;
- st->port = NULL;
+ st->socket = NULL;
+ st->connhost = NULL;
+ st->connport = NULL;
- if (strcasecmp (ci->key, "Plugin") == 0) /* default instance */
- st->name = sstrdup ("__legacy__");
- else /* <Instance /> block */
+ if (strcasecmp (ci->key, "Instance") == 0)
status = cf_util_get_string (ci, &st->name);
+
if (status != 0)
{
sfree (st);
return (status);
}
- assert (st->name != NULL);
- for (i = 0; i < ci->children_num; i++)
+ for (int i = 0; i < ci->children_num; i++)
{
oconfig_item_t *child = ci->children + i;
status = cf_util_get_string (child, &st->socket);
else if (strcasecmp ("Host", child->key) == 0)
status = cf_util_get_string (child, &st->host);
+ else if (strcasecmp ("Address", child->key) == 0)
+ status = cf_util_get_string (child, &st->connhost);
else if (strcasecmp ("Port", child->key) == 0)
- status = cf_util_get_service (child, &st->port);
+ status = cf_util_get_service (child, &st->connport);
else
{
WARNING ("memcached plugin: Option `%s' not allowed here.",
{
int status = 0;
_Bool have_instance_block = 0;
- int i;
- for (i = 0; i < ci->children_num; i++)
+ for (int i = 0; i < ci->children_num; i++)
{
oconfig_item_t *child = ci->children + i;
return (0);
/* No instances were configured, lets start a default instance. */
- st = malloc (sizeof (*st));
+ st = calloc (1, sizeof (*st));
if (st == NULL)
return (ENOMEM);
- memset (st, 0, sizeof (*st));
- st->name = sstrdup ("__legacy__");
- st->socket = NULL;
+ st->name = NULL;
st->host = NULL;
- st->port = NULL;
+ st->socket = NULL;
+ st->connhost = NULL;
+ st->connport = NULL;
status = memcached_add_read_callback (st);
if (status == 0)