libcollectdclient: Fix the SSTRCAT macro.
[collectd.git] / src / libcollectdclient / client.c
index deda6eb..847eafc 100644 (file)
 # define __attribute__(x) /**/
 #endif
 
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "lcc_features.h"
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <assert.h>
 #include <errno.h>
+#include <math.h>
 #include <netdb.h>
 
 #include "client.h"
 
+/* NI_MAXHOST has been obsoleted by RFC 3493 which is a reason for SunOS 5.11
+ * to no longer define it. We'll use the old, RFC 2553 value here. */
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif
+
+/* Secure/static macros. They work like `strcpy' and `strcat', but assure null
+ * termination. They work for static buffers only, because they use `sizeof'.
+ * The `SSTRCATF' combines the functionality of `snprintf' and `strcat' which
+ * is very useful to add formatted stuff to the end of a buffer. */
 #define SSTRCPY(d,s) do { \
-  strncpy ((d), (s), sizeof (d)); \
-  (d)[sizeof (d) - 1] = 0; \
-} while (0)
+    strncpy ((d), (s), sizeof (d)); \
+    (d)[sizeof (d) - 1] = 0; \
+  } while (0)
+
+#define SSTRCAT(d,s) do { \
+    size_t _l = strlen (d); \
+    strncpy ((d) + _l, (s), sizeof (d) - _l); \
+    (d)[sizeof (d) - 1] = 0; \
+  } while (0)
+
+#define SSTRCATF(d, ...) do { \
+    char _b[sizeof (d)]; \
+    snprintf (_b, sizeof (_b), __VA_ARGS__); \
+    _b[sizeof (_b) - 1] = 0; \
+    SSTRCAT ((d), _b); \
+  } while (0)
+    
 
 #define LCC_SET_ERRSTR(c, ...) do { \
   snprintf ((c)->errbuf, sizeof ((c)->errbuf), __VA_ARGS__); \
   (c)->errbuf[sizeof ((c)->errbuf) - 1] = 0; \
 } while (0)
 
-#if 1
+#if COLLECT_DEBUG
 # define LCC_DEBUG(...) printf (__VA_ARGS__)
 #else
 # define LCC_DEBUG(...) /**/
@@ -125,7 +156,7 @@ static char *lcc_strdup (const char *str) /* {{{ */
 } /* }}} char *lcc_strdup */
 
 __attribute__((nonnull (1, 2)))
-static char *lcc_strescape (char *dest, char *src, size_t dest_size) /* {{{ */
+static char *lcc_strescape (char *dest, const char *src, size_t dest_size) /* {{{ */
 {
   size_t dest_pos;
   size_t src_pos;
@@ -335,7 +366,9 @@ static int lcc_open_unixsocket (lcc_connection_t *c, const char *path) /* {{{ */
   assert (c->fh == NULL);
   assert (path != NULL);
 
-  fd = socket (PF_UNIX, SOCK_STREAM, /* protocol = */ 0);
+  /* Don't use PF_UNIX here, because it's broken on Mac OS X (10.4, possibly
+   * others). */
+  fd = socket (AF_UNIX, SOCK_STREAM, /* protocol = */ 0);
   if (fd < 0)
   {
     lcc_set_errno (c, errno);
@@ -503,6 +536,21 @@ static int lcc_open_socket (lcc_connection_t *c, const char *addr) /* {{{ */
 /*
  * Public functions
  */
+unsigned int lcc_version (void) /* {{{ */
+{
+  return (LCC_VERSION);
+} /* }}} unsigned int lcc_version */
+
+const char *lcc_version_string (void) /* {{{ */
+{
+  return (LCC_VERSION_STRING);
+} /* }}} const char *lcc_version_string */
+
+const char *lcc_version_extra (void) /* {{{ */
+{
+  return (LCC_VERSION_EXTRA);
+} /* }}} const char *lcc_version_extra */
+
 int lcc_connect (const char *address, lcc_connection_t **ret_con) /* {{{ */
 {
   lcc_connection_t *c;
@@ -578,6 +626,7 @@ int lcc_getval (lcc_connection_t *c, lcc_identifier_t *ident, /* {{{ */
   if (res.status != 0)
   {
     LCC_SET_ERRSTR (c, "Server error: %s", res.message);
+    lcc_response_free (&res);
     return (-1);
   }
 
@@ -662,11 +711,118 @@ int lcc_getval (lcc_connection_t *c, lcc_identifier_t *ident, /* {{{ */
   return (0);
 } /* }}} int lcc_getval */
 
-/* TODO: Implement lcc_putval */
-int lcc_putval (lcc_connection_t *c, const lcc_value_list_t *vl);
+int lcc_putval (lcc_connection_t *c, const lcc_value_list_t *vl) /* {{{ */
+{
+  char ident_str[6 * LCC_NAME_LEN];
+  char ident_esc[12 * LCC_NAME_LEN];
+  char command[1024] = "";
+  lcc_response_t res;
+  int status;
+  size_t i;
 
-/* TODO: Implement lcc_flush */
-int lcc_flush (lcc_connection_t *c, lcc_identifier_t *ident, int timeout);
+  if ((c == NULL) || (vl == NULL) || (vl->values_len < 1)
+      || (vl->values == NULL) || (vl->values_types == NULL))
+  {
+    lcc_set_errno (c, EINVAL);
+    return (-1);
+  }
+
+  status = lcc_identifier_to_string (c, ident_str, sizeof (ident_str),
+      &vl->identifier);
+  if (status != 0)
+    return (status);
+
+  SSTRCATF (command, "PUTVAL %s",
+      lcc_strescape (ident_esc, ident_str, sizeof (ident_esc)));
+
+  if (vl->interval > 0)
+    SSTRCATF (command, " interval=%i", vl->interval);
+
+  if (vl->time > 0)
+    SSTRCATF (command, "%u", (unsigned int) vl->time);
+  else
+    SSTRCAT (command, "N");
+
+  for (i = 0; i < vl->values_len; i++)
+  {
+    if (vl->values_types[i] == LCC_TYPE_COUNTER)
+      SSTRCATF (command, ":%"PRIu64, vl->values[i].counter);
+    else if (vl->values_types[i] == LCC_TYPE_GAUGE)
+    {
+      if (isnan (vl->values[i].gauge))
+        SSTRCPY (command, ":U");
+      else
+        SSTRCATF (command, ":%g", vl->values[i].gauge);
+    }
+  } /* for (i = 0; i < vl->values_len; i++) */
+
+  status = lcc_sendreceive (c, command, &res);
+  if (status != 0)
+    return (status);
+
+  if (res.status != 0)
+  {
+    LCC_SET_ERRSTR (c, "Server error: %s", res.message);
+    lcc_response_free (&res);
+    return (-1);
+  }
+
+  lcc_response_free (&res);
+  return (0);
+} /* }}} int lcc_putval */
+
+int lcc_flush (lcc_connection_t *c, const char *plugin, /* {{{ */
+    lcc_identifier_t *ident, int timeout)
+{
+  char command[1024] = "";
+  lcc_response_t res;
+  int status;
+
+  if (c == NULL)
+  {
+    lcc_set_errno (c, EINVAL);
+    return (-1);
+  }
+
+  SSTRCPY (command, "FLUSH");
+
+  if (timeout > 0)
+    SSTRCATF (command, " timeout=%i", timeout);
+
+  if (plugin != NULL)
+  {
+    char buffer[2 * LCC_NAME_LEN];
+    SSTRCATF (command, " plugin=%s",
+        lcc_strescape (buffer, plugin, sizeof (buffer)));
+  }
+
+  if (ident != NULL)
+  {
+    char ident_str[6 * LCC_NAME_LEN];
+    char ident_esc[12 * LCC_NAME_LEN];
+
+    status = lcc_identifier_to_string (c, ident_str, sizeof (ident_str), ident);
+    if (status != 0)
+      return (status);
+
+    SSTRCATF (command, " identifier=%s",
+        lcc_strescape (ident_esc, ident_str, sizeof (ident_esc)));
+  }
+
+  status = lcc_sendreceive (c, command, &res);
+  if (status != 0)
+    return (status);
+
+  if (res.status != 0)
+  {
+    LCC_SET_ERRSTR (c, "Server error: %s", res.message);
+    lcc_response_free (&res);
+    return (-1);
+  }
+
+  lcc_response_free (&res);
+  return (0);
+} /* }}} int lcc_flush */
 
 /* TODO: Implement lcc_putnotif */
 
@@ -696,6 +852,7 @@ int lcc_listval (lcc_connection_t *c, /* {{{ */
   if (res.status != 0)
   {
     LCC_SET_ERRSTR (c, "Server error: %s", res.message);
+    lcc_response_free (&res);
     return (-1);
   }