From 6bd86ee138ba0652f5d0a90b4744a0e34faf2066 Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Tue, 3 Jun 2014 16:15:24 -0400 Subject: [PATCH] hddtemp: Lift 1024-byte response limit Dynamically scale the response buffer, up to a maximum of 1 MB. --- src/hddtemp.c | 72 +++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/src/hddtemp.c b/src/hddtemp.c index 4840e14a..4e275dc8 100644 --- a/src/hddtemp.c +++ b/src/hddtemp.c @@ -40,6 +40,7 @@ # include # include # include /* for basename */ +# include #if HAVE_LINUX_MAJOR_H # include @@ -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 */ -- 2.11.0