hddtemp: Lift 1024-byte response limit
authorBenjamin Gilbert <bgilbert@cs.cmu.edu>
Tue, 3 Jun 2014 20:15:24 +0000 (16:15 -0400)
committerBenjamin Gilbert <bgilbert@backtick.net>
Mon, 19 Sep 2016 06:35:12 +0000 (01:35 -0500)
Dynamically scale the response buffer, up to a maximum of 1 MB.

src/hddtemp.c

index 4840e14..4e275dc 100644 (file)
@@ -40,6 +40,7 @@
 # include <netinet/in.h>
 # include <netinet/tcp.h>
 # include <libgen.h> /* for basename */
+# include <assert.h>
 
 #if HAVE_LINUX_MAJOR_H
 # include <linux/major.h>
@@ -47,6 +48,7 @@
 
 #define HDDTEMP_DEF_HOST "127.0.0.1"
 #define HDDTEMP_DEF_PORT "7634"
+#define HDDTEMP_MAX_RECV_BUF (1 << 20)
 
 static const char *config_keys[] =
 {
@@ -81,11 +83,15 @@ static char hddtemp_port[16];
  *  we need to create a new socket each time. Is there another way?
  *  Hm, maybe we can re-use the `sockaddr' structure? -octo
  */
-static int hddtemp_query_daemon (char *buffer, int buffer_size)
+static char *hddtemp_query_daemon (void)
 {
        int fd;
        ssize_t status;
+
+       char *buffer;
+       int buffer_size;
        int buffer_fill;
+       char *new_buffer;
 
        const char *host;
        const char *port;
@@ -116,7 +122,7 @@ static int hddtemp_query_daemon (char *buffer, int buffer_size)
                                (ai_return == EAI_SYSTEM)
                                ? sstrerror (errno, errbuf, sizeof (errbuf))
                                : gai_strerror (ai_return));
-               return (-1);
+               return (NULL);
        }
 
        fd = -1;
@@ -156,16 +162,41 @@ static int hddtemp_query_daemon (char *buffer, int buffer_size)
        if (fd < 0)
        {
                ERROR ("hddtemp plugin: Could not connect to daemon.");
-               return (-1);
+               return (NULL);
        }
 
        /* receive data from the hddtemp daemon */
-       memset (buffer, '\0', buffer_size);
-
+       buffer = NULL;
+       buffer_size = 0;
        buffer_fill = 0;
-       while ((status = read (fd, buffer + buffer_fill, buffer_size - buffer_fill)) != 0)
+       while (1)
        {
-               if (status == -1)
+               if (buffer_fill >= buffer_size - 1)
+               {
+                       if (buffer_size == 0)
+                               buffer_size = 1024;
+                       else
+                               buffer_size *= 2;
+                       if (buffer_size > HDDTEMP_MAX_RECV_BUF)
+                       {
+                               WARNING ("hddtemp plugin: Message from hddtemp has been "
+                                               "truncated.");
+                               break;
+                       }
+                       new_buffer = realloc (buffer, buffer_size);
+                       if (new_buffer == NULL) {
+                               close (fd);
+                               free (buffer);
+                               ERROR ("hddtemp plugin: Allocation failed.");
+                               return (NULL);
+                       }
+                       buffer = new_buffer;
+               }
+               status = read (fd, buffer + buffer_fill, buffer_size - buffer_fill - 1);
+               if (status == 0) {
+                       break;
+               }
+               else if (status == -1)
                {
                        char errbuf[1024];
 
@@ -175,30 +206,25 @@ static int hddtemp_query_daemon (char *buffer, int buffer_size)
                        ERROR ("hddtemp plugin: Error reading from socket: %s",
                                        sstrerror (errno, errbuf, sizeof (errbuf)));
                        close (fd);
-                       return (-1);
+                       free (buffer);
+                       return (NULL);
                }
                buffer_fill += status;
-
-               if (buffer_fill >= buffer_size)
-                       break;
        }
 
-       if (buffer_fill >= buffer_size)
-       {
-               buffer[buffer_size - 1] = '\0';
-               WARNING ("hddtemp plugin: Message from hddtemp has been "
-                               "truncated.");
-       }
-       else if (buffer_fill == 0)
+       if (buffer_fill == 0)
        {
                WARNING ("hddtemp plugin: Peer has unexpectedly shut down "
                                "the socket. Buffer: `%s'", buffer);
                close (fd);
-               return (-1);
+               free (buffer);
+               return (NULL);
        }
 
+       assert (buffer_fill < buffer_size);
+       buffer[buffer_fill] = '\0';
        close (fd);
-       return (0);
+       return (buffer);
 }
 
 static int hddtemp_config (const char *key, const char *value)
@@ -242,7 +268,7 @@ static void hddtemp_submit (char *type_instance, double value)
 
 static int hddtemp_read (void)
 {
-       char buf[1024];
+       char *buf;
        char *ptr;
        char *saveptr;
        char *name;
@@ -251,7 +277,8 @@ static int hddtemp_read (void)
        char *mode;
 
        /* get data from daemon */
-       if (hddtemp_query_daemon (buf, sizeof (buf)) < 0)
+       buf = hddtemp_query_daemon ();
+       if (buf == NULL)
                return (-1);
 
        /* NB: strtok_r will eat up "||" and leading "|"'s */
@@ -280,6 +307,7 @@ static int hddtemp_read (void)
                hddtemp_submit (name, temperature_value);
        }
        
+       free (buf);
        return (0);
 } /* int hddtemp_read */