http plugin: http_write: Clean-up.
[collectd.git] / src / http.c
index 9dc7f80..8027220 100644 (file)
@@ -38,7 +38,7 @@
  */
 static const char *config_keys[] =
 {
-        "Location", "User", "Password"
+        "URL", "User", "Password"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
@@ -53,8 +53,8 @@ char curl_errbuf[CURL_ERROR_SIZE];
 
 #define SEND_BUFFER_SIZE 4096
 static char   send_buffer[SEND_BUFFER_SIZE];
-static char  *send_buffer_ptr;
-static int    send_buffer_fill;
+static size_t send_buffer_free;
+static size_t send_buffer_fill;
 
 static pthread_mutex_t  send_lock = PTHREAD_MUTEX_INITIALIZER;
 
@@ -104,76 +104,57 @@ static int http_init(void) /* {{{ */
         return (0);
 } /* }}} */
 
-static int http_value_list_to_string (char *buffer, int buffer_len, /* {{{ */
+static int http_value_list_to_string (char *buffer, /* {{{ */
+                size_t buffer_size,
                 const data_set_t *ds, const value_list_t *vl)
 {
-        int offset = 0;
+        size_t offset = 0;
         int status;
         int i;
-        gauge_t *rates = NULL;
 
         assert (0 == strcmp (ds->type, vl->type));
 
-        memset (buffer, '\0', buffer_len);
+        memset (buffer, 0, buffer_size);
 
-        for (i = 0; i < ds->ds_num; i++)
-        {
-                if ((ds->ds[i].type != DS_TYPE_COUNTER)
-                                && (ds->ds[i].type != DS_TYPE_GAUGE)
-                                && (ds->ds[i].type != DS_TYPE_DERIVE)
-                                && (ds->ds[i].type != DS_TYPE_ABSOLUTE))
-                        return (-1);
+#define BUFFER_ADD(...) do { \
+        status = ssnprintf (buffer + offset, buffer_size - offset, \
+                        __VA_ARGS__); \
+        if (status < 1) \
+                return (-1); \
+        else if (((size_t) status) >= (buffer_size - offset)) \
+                return (-1); \
+        else \
+                offset += ((size_t) status); \
+} while (0)
 
-                if (ds->ds[i].type == DS_TYPE_GAUGE)
-                {
-                        status = ssnprintf (buffer + offset, buffer_len - offset,
-                                        ":%lf", vl->values[i].gauge);
-                }
-                else if (ds->ds[i].type == DS_TYPE_COUNTER)
-                {
-                        if (rates == NULL)
-                                rates = uc_get_rate (ds, vl);
-                        if (rates == NULL)
-                        {
-                                WARNING ("csv plugin: "
-                                                "uc_get_rate failed.");
-                                return (-1);
-                        }
-                        status = ssnprintf (buffer + offset,
-                                        buffer_len - offset,
-                                        ":%lf", rates[i]);
-                }
-                else if (ds->ds[i].type == DS_TYPE_DERIVE)
-                {
-                        status = ssnprintf (buffer + offset,
-                                        buffer_len - offset,
-                                        ":%"PRIi64,
-                                        vl->values[i].derive);
-                }
-                else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
-                {
-                        status = ssnprintf (buffer + offset,
-                                        buffer_len - offset,
-                                        ":%"PRIu64,
-                                        vl->values[i].absolute);
-                }
+        BUFFER_ADD ("%lu", (unsigned long) vl->time);
 
-                if ((status < 1) || (status >= (buffer_len - offset)))
-                {
-                        sfree (rates);
-                        return (-1);
-                }
+        for (i = 0; i < ds->ds_num; i++)
+{
+        if (ds->ds[i].type == DS_TYPE_GAUGE)
+                BUFFER_ADD (":%f", vl->values[i].gauge);
+        else if (ds->ds[i].type == DS_TYPE_COUNTER)
+                BUFFER_ADD (":%llu", vl->values[i].counter);
+        else if (ds->ds[i].type == DS_TYPE_DERIVE)
+                BUFFER_ADD (":%"PRIi64, vl->values[i].derive);
+        else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
+                BUFFER_ADD (":%"PRIu64, vl->values[i].absolute);
+        else
+        {
+                ERROR ("http plugin: Unknown data source type: %i",
+                                ds->ds[i].type);
+                return (-1);
+        }
+} /* for ds->ds_num */
 
-                offset += status;
-        } /* for ds->ds_num */
+#undef BUFFER_ADD
 
-        sfree (rates);
-        return (0);
+return (0);
 } /* }}} int http_value_list_to_string */
 
 static int http_config (const char *key, const char *value) /* {{{ */
 {
-        if (strcasecmp ("Location", key) == 0)
+        if (strcasecmp ("URL", key) == 0)
         {
                 if (location != NULL)
                         free (location);
@@ -243,15 +224,16 @@ static int http_config (const char *key, const char *value) /* {{{ */
 static void http_init_buffer (void)  /* {{{ */
 {
         memset (send_buffer, 0, sizeof (send_buffer));
-        send_buffer_ptr = send_buffer;
+        send_buffer_free = sizeof (send_buffer);
         send_buffer_fill = 0;
 } /* }}} http_init_buffer */
 
 static int http_send_buffer (char *buffer) /* {{{ */
 {
         int status = 0;
+
         curl_easy_setopt (curl, CURLOPT_POSTFIELDS, buffer);
-        //status = curl_easy_perform (curl);
+        status = curl_easy_perform (curl);
         if (status != 0)
         {
                 ERROR ("http plugin: curl_easy_perform failed with staus %i: %s",
@@ -271,12 +253,12 @@ static int http_flush_buffer (void) /* {{{ */
         return (status);
 } /* }}} http_flush_buffer */
 
-static int http_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */
-                user_data_t __attribute__((unused)) *user_data)
+static int http_write_command (const data_set_t *ds, const value_list_t *vl) /* {{{ */
 {
-
-        char key[1024];
+        char key[10*DATA_MAX_NAME_LEN];
         char values[512];
+        char command[1024];
+        size_t command_len;
 
         int status;
 
@@ -285,42 +267,64 @@ static int http_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */
                 return -1;
         }
 
-        status = format_name( key, sizeof(key), vl->host, vl->plugin,
-                        vl->plugin_instance, vl->type, vl->type_instance );
-
+        /* Copy the identifier to `key' and escape it. */
+        status = FORMAT_VL (key, sizeof (key), vl);
         if (status != 0) {
                 ERROR ("http plugin: error with format_name");
                 return (status);
         }
+        escape_string (key, sizeof (key));
 
+        /* Convert the values to an ASCII representation and put that into
+         * `values'. */
         status = http_value_list_to_string (values, sizeof (values), ds, vl);
-
         if (status != 0) {
                 ERROR ("http plugin: error with http_value_list_to_string");
                 return (status);
         }
 
+        command_len = (size_t) ssnprintf (command, sizeof (command),
+                        "PUTVAL %s interval=%i %s\n",
+                        key, vl->interval, values);
+        if (command_len >= sizeof (command)) {
+                ERROR ("http plugin: Command buffer too small: "
+                                "Need %zu bytes.", command_len + 1);
+                return (-1);
+        }
 
         pthread_mutex_lock (&send_lock);
 
-        status = ssnprintf (send_buffer + send_buffer_fill, sizeof (send_buffer) - send_buffer_fill,
-                        "PUTVAL %s interval=%i %u%s\n",
-                        key, interval_g, vl->time, values);
-        send_buffer_fill += status;
-
-        if ((sizeof (send_buffer) - send_buffer_fill) < (sizeof(key) + sizeof(values)))
+        /* Check if we have enough space for this command. */
+        if (command_len >= send_buffer_free)
         {
                 status = http_flush_buffer();
                 if (status != 0)
+                {
+                        pthread_mutex_unlock (&send_lock);
                         return status;
-
+                }
         }
+        assert (command_len < send_buffer_free);
 
-        pthread_mutex_unlock (&send_lock);
+        /* `command_len + 1' because `command_len' does not include the
+         * trailing null byte. Neither does `send_buffer_fill'. */
+        memcpy (send_buffer + send_buffer_fill, command, command_len + 1);
+        send_buffer_fill += command_len;
+        send_buffer_free -= command_len;
 
+        pthread_mutex_unlock (&send_lock);
 
         return (0);
+} /* }}} int http_write_command */
 
+static int http_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */
+                user_data_t __attribute__((unused)) *user_data)
+{
+        int status;
+
+        status = http_write_command (ds, vl);
+
+        return (status);
 } /* }}} int http_write */
 
 static int http_shutdown (void) /* {{{ */
@@ -339,4 +343,4 @@ void module_register (void) /* {{{ */
         plugin_register_shutdown("http", http_shutdown);
 } /* }}} void module_register */
 
-/* vim: set fdm=marker sw=8 ts=8 tw=78 : */
+/* vim: set fdm=marker sw=8 ts=8 tw=78 et : */