Merge branch 'collectd-5.7' into collectd-5.8
[collectd.git] / src / teamspeak2.c
index 1bd969b..4d68f61 100644 (file)
 #include "common.h"
 #include "plugin.h"
 
-#include <netinet/in.h>
 #include <arpa/inet.h>
-#include <sys/types.h>
 #include <netdb.h>
+#include <netinet/in.h>
+#include <sys/types.h>
 
 /*
  * Defines
  */
 /* Default host and port */
-#define DEFAULT_HOST   "127.0.0.1"
-#define DEFAULT_PORT   "51234"
+#define DEFAULT_HOST "127.0.0.1"
+#define DEFAULT_PORT "51234"
 
 /*
  * Variables
  */
 /* Server linked list structure */
-typedef struct vserver_list_s
-{
-       int port;
-       struct vserver_list_s *next;
+typedef struct vserver_list_s {
+  int port;
+  struct vserver_list_s *next;
 } vserver_list_t;
 static vserver_list_t *server_list = NULL;
 
@@ -57,784 +56,675 @@ static FILE *global_read_fh = NULL;
 static FILE *global_write_fh = NULL;
 
 /* Config data */
-static const char *config_keys[] =
-{
-       "Host",
-       "Port",
-       "Server"
-};
-static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+static const char *config_keys[] = {"Host", "Port", "Server"};
+static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
 
 /*
  * Functions
  */
-static int tss2_add_vserver (int vserver_port)
-{
-       /*
-        * Adds a new vserver to the linked list
-        */
-       vserver_list_t *entry;
-
-       /* Check port range */
-       if ((vserver_port <= 0) || (vserver_port > 65535))
-       {
-               ERROR ("teamspeak2 plugin: VServer port is invalid: %i",
-                               vserver_port);
-               return (-1);
-       }
-
-       /* Allocate memory */
-       entry = calloc (1, sizeof (*entry));
-       if (entry == NULL)
-       {
-               ERROR ("teamspeak2 plugin: calloc failed.");
-               return (-1);
-       }
-
-       /* Save data */
-       entry->port = vserver_port;
-
-       /* Insert to list */
-       if(server_list == NULL) {
-               /* Add the server as the first element */
-               server_list = entry;
-       }
-       else {
-               vserver_list_t *prev;
-
-               /* Add the server to the end of the list */
-               prev = server_list;
-               while (prev->next != NULL)
-                       prev = prev->next;
-               prev->next = entry;
-       }
-
-       INFO ("teamspeak2 plugin: Registered new vserver: %i", vserver_port);
-
-       return (0);
+static int tss2_add_vserver(int vserver_port) {
+  /*
+   * Adds a new vserver to the linked list
+   */
+  vserver_list_t *entry;
+
+  /* Check port range */
+  if ((vserver_port <= 0) || (vserver_port > 65535)) {
+    ERROR("teamspeak2 plugin: VServer port is invalid: %i", vserver_port);
+    return -1;
+  }
+
+  /* Allocate memory */
+  entry = calloc(1, sizeof(*entry));
+  if (entry == NULL) {
+    ERROR("teamspeak2 plugin: calloc failed.");
+    return -1;
+  }
+
+  /* Save data */
+  entry->port = vserver_port;
+
+  /* Insert to list */
+  if (server_list == NULL) {
+    /* Add the server as the first element */
+    server_list = entry;
+  } else {
+    vserver_list_t *prev;
+
+    /* Add the server to the end of the list */
+    prev = server_list;
+    while (prev->next != NULL)
+      prev = prev->next;
+    prev->next = entry;
+  }
+
+  INFO("teamspeak2 plugin: Registered new vserver: %i", vserver_port);
+
+  return 0;
 } /* int tss2_add_vserver */
 
-static void tss2_submit_gauge (const char *plugin_instance,
-               const char *type, const char *type_instance,
-               gauge_t value)
-{
-       /*
-        * Submits a gauge value to the collectd daemon
-        */
-       value_list_t vl = VALUE_LIST_INIT;
+static void tss2_submit_gauge(const char *plugin_instance, const char *type,
+                              const char *type_instance, gauge_t value) {
+  /*
+   * Submits a gauge value to the collectd daemon
+   */
+  value_list_t vl = VALUE_LIST_INIT;
 
-       vl.values     = &(value_t) { .gauge = value };
-       vl.values_len = 1;
-       sstrncpy (vl.plugin, "teamspeak2", sizeof (vl.plugin));
+  vl.values = &(value_t){.gauge = value};
+  vl.values_len = 1;
+  sstrncpy(vl.plugin, "teamspeak2", sizeof(vl.plugin));
 
-       if (plugin_instance != NULL)
-               sstrncpy (vl.plugin_instance, plugin_instance,
-                               sizeof (vl.plugin_instance));
+  if (plugin_instance != NULL)
+    sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance));
 
-       sstrncpy (vl.type, type, sizeof (vl.type));
+  sstrncpy(vl.type, type, sizeof(vl.type));
 
-       if (type_instance != NULL)
-               sstrncpy (vl.type_instance, type_instance,
-                               sizeof (vl.type_instance));
+  if (type_instance != NULL)
+    sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
 
-       plugin_dispatch_values (&vl);
+  plugin_dispatch_values(&vl);
 } /* void tss2_submit_gauge */
 
-static void tss2_submit_io (const char *plugin_instance, const char *type,
-               derive_t rx, derive_t tx)
-{
-       /*
-        * Submits the io rx/tx tuple to the collectd daemon
-        */
-       value_list_t vl = VALUE_LIST_INIT;
-       value_t values[] = {
-               { .derive = rx },
-               { .derive = tx },
-       };
-
-       vl.values     = values;
-       vl.values_len = STATIC_ARRAY_SIZE (values);
-       sstrncpy (vl.plugin, "teamspeak2", sizeof (vl.plugin));
-
-       if (plugin_instance != NULL)
-               sstrncpy (vl.plugin_instance, plugin_instance,
-                               sizeof (vl.plugin_instance));
-
-       sstrncpy (vl.type, type, sizeof (vl.type));
-
-       plugin_dispatch_values (&vl);
+static void tss2_submit_io(const char *plugin_instance, const char *type,
+                           derive_t rx, derive_t tx) {
+  /*
+   * Submits the io rx/tx tuple to the collectd daemon
+   */
+  value_list_t vl = VALUE_LIST_INIT;
+  value_t values[] = {
+      {.derive = rx}, {.derive = tx},
+  };
+
+  vl.values = values;
+  vl.values_len = STATIC_ARRAY_SIZE(values);
+  sstrncpy(vl.plugin, "teamspeak2", sizeof(vl.plugin));
+
+  if (plugin_instance != NULL)
+    sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance));
+
+  sstrncpy(vl.type, type, sizeof(vl.type));
+
+  plugin_dispatch_values(&vl);
 } /* void tss2_submit_gauge */
 
-static void tss2_close_socket (void)
-{
-       /*
-        * Closes all sockets
-        */
-       if (global_write_fh != NULL)
-       {
-               fputs ("quit\r\n", global_write_fh);
-       }
-
-       if (global_read_fh != NULL)
-       {
-               fclose (global_read_fh);
-               global_read_fh = NULL;
-       }
-
-       if (global_write_fh != NULL)
-       {
-               fclose (global_write_fh);
-               global_write_fh = NULL;
-       }
+static void tss2_close_socket(void) {
+  /*
+   * Closes all sockets
+   */
+  if (global_write_fh != NULL) {
+    fputs("quit\r\n", global_write_fh);
+  }
+
+  if (global_read_fh != NULL) {
+    fclose(global_read_fh);
+    global_read_fh = NULL;
+  }
+
+  if (global_write_fh != NULL) {
+    fclose(global_write_fh);
+    global_write_fh = NULL;
+  }
 } /* void tss2_close_socket */
 
-static int tss2_get_socket (FILE **ret_read_fh, FILE **ret_write_fh)
-{
-       /*
-        * Returns connected file objects or establishes the connection
-        * if it's not already present
-        */
-       struct addrinfo *ai_head;
-       int sd = -1;
-       int status;
-
-       /* Check if we already got opened connections */
-       if ((global_read_fh != NULL) && (global_write_fh != NULL))
-       {
-               /* If so, use them */
-               if (ret_read_fh != NULL)
-                       *ret_read_fh = global_read_fh;
-               if (ret_write_fh != NULL)
-                       *ret_write_fh = global_write_fh;
-               return (0);
-       }
-
-       /* Get all addrs for this hostname */
-       struct addrinfo ai_hints = {
-               .ai_family = AF_UNSPEC,
-               .ai_flags = AI_ADDRCONFIG,
-               .ai_socktype = SOCK_STREAM
-       };
-
-       status = getaddrinfo ((config_host != NULL) ? config_host : DEFAULT_HOST,
-                       (config_port != NULL) ? config_port : DEFAULT_PORT,
-                       &ai_hints,
-                       &ai_head);
-       if (status != 0)
-       {
-               ERROR ("teamspeak2 plugin: getaddrinfo failed: %s",
-                               gai_strerror (status));
-               return (-1);
-       }
-
-       /* Try all given hosts until we can connect to one */
-       for (struct addrinfo *ai_ptr = ai_head; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
-       {
-               /* Create socket */
-               sd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype,
-                               ai_ptr->ai_protocol);
-               if (sd < 0)
-               {
-                       char errbuf[1024];
-                       WARNING ("teamspeak2 plugin: socket failed: %s",
-                                       sstrerror (errno, errbuf, sizeof (errbuf)));
-                       continue;
-               }
-
-               /* Try to connect */
-               status = connect (sd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
-               if (status != 0)
-               {
-                       char errbuf[1024];
-                       WARNING ("teamspeak2 plugin: connect failed: %s",
-                                       sstrerror (errno, errbuf, sizeof (errbuf)));
-                       close (sd);
-                       sd = -1;
-                       continue;
-               }
-
-               /*
-                * Success, we can break. Don't need more than one connection
-                */
-               break;
-       } /* for (ai_ptr) */
-
-       freeaddrinfo (ai_head);
-
-       /* Check if we really got connected */
-       if (sd < 0)
-               return (-1);
-
-       /* Create file objects from sockets */
-       global_read_fh = fdopen (sd, "r");
-       if (global_read_fh == NULL)
-       {
-               char errbuf[1024];
-               ERROR ("teamspeak2 plugin: fdopen failed: %s",
-                               sstrerror (errno, errbuf, sizeof (errbuf)));
-               close (sd);
-               return (-1);
-       }
-
-       global_write_fh = fdopen (sd, "w");
-       if (global_write_fh == NULL)
-       {
-               char errbuf[1024];
-               ERROR ("teamspeak2 plugin: fdopen failed: %s",
-                               sstrerror (errno, errbuf, sizeof (errbuf)));
-               tss2_close_socket ();
-               return (-1);
-       }
-
-       { /* Check that the server correctly identifies itself. */
-               char buffer[4096];
-               char *buffer_ptr;
-
-               buffer_ptr = fgets (buffer, sizeof (buffer), global_read_fh);
-               if (buffer_ptr == NULL)
-               {
-                       WARNING ("teamspeak2 plugin: Unexpected EOF received "
-                                       "from remote host %s:%s.",
-                                       config_host ? config_host : DEFAULT_HOST,
-                                       config_port ? config_port : DEFAULT_PORT);
-               }
-               buffer[sizeof (buffer) - 1] = 0;
-
-               if (memcmp ("[TS]\r\n", buffer, 6) != 0)
-               {
-                       ERROR ("teamspeak2 plugin: Unexpected response when connecting "
-                                       "to server. Expected ``[TS]'', got ``%s''.",
-                                       buffer);
-                       tss2_close_socket ();
-                       return (-1);
-               }
-               DEBUG ("teamspeak2 plugin: Server send correct banner, connected!");
-       }
-
-       /* Copy the new filehandles to the given pointers */
-       if (ret_read_fh != NULL)
-               *ret_read_fh = global_read_fh;
-       if (ret_write_fh != NULL)
-               *ret_write_fh = global_write_fh;
-       return (0);
+static int tss2_get_socket(FILE **ret_read_fh, FILE **ret_write_fh) {
+  /*
+   * Returns connected file objects or establishes the connection
+   * if it's not already present
+   */
+  struct addrinfo *ai_head;
+  int sd = -1;
+  int status;
+
+  /* Check if we already got opened connections */
+  if ((global_read_fh != NULL) && (global_write_fh != NULL)) {
+    /* If so, use them */
+    if (ret_read_fh != NULL)
+      *ret_read_fh = global_read_fh;
+    if (ret_write_fh != NULL)
+      *ret_write_fh = global_write_fh;
+    return 0;
+  }
+
+  /* Get all addrs for this hostname */
+  struct addrinfo ai_hints = {.ai_family = AF_UNSPEC,
+                              .ai_flags = AI_ADDRCONFIG,
+                              .ai_socktype = SOCK_STREAM};
+
+  status = getaddrinfo((config_host != NULL) ? config_host : DEFAULT_HOST,
+                       (config_port != NULL) ? config_port : DEFAULT_PORT,
+                       &ai_hints, &ai_head);
+  if (status != 0) {
+    ERROR("teamspeak2 plugin: getaddrinfo failed: %s", gai_strerror(status));
+    return -1;
+  }
+
+  /* Try all given hosts until we can connect to one */
+  for (struct addrinfo *ai_ptr = ai_head; ai_ptr != NULL;
+       ai_ptr = ai_ptr->ai_next) {
+    /* Create socket */
+    sd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
+    if (sd < 0) {
+      char errbuf[1024];
+      WARNING("teamspeak2 plugin: socket failed: %s",
+              sstrerror(errno, errbuf, sizeof(errbuf)));
+      continue;
+    }
+
+    /* Try to connect */
+    status = connect(sd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
+    if (status != 0) {
+      char errbuf[1024];
+      WARNING("teamspeak2 plugin: connect failed: %s",
+              sstrerror(errno, errbuf, sizeof(errbuf)));
+      close(sd);
+      sd = -1;
+      continue;
+    }
+
+    /*
+     * Success, we can break. Don't need more than one connection
+     */
+    break;
+  } /* for (ai_ptr) */
+
+  freeaddrinfo(ai_head);
+
+  /* Check if we really got connected */
+  if (sd < 0)
+    return -1;
+
+  /* Create file objects from sockets */
+  global_read_fh = fdopen(sd, "r");
+  if (global_read_fh == NULL) {
+    char errbuf[1024];
+    ERROR("teamspeak2 plugin: fdopen failed: %s",
+          sstrerror(errno, errbuf, sizeof(errbuf)));
+    close(sd);
+    return -1;
+  }
+
+  global_write_fh = fdopen(sd, "w");
+  if (global_write_fh == NULL) {
+    char errbuf[1024];
+    ERROR("teamspeak2 plugin: fdopen failed: %s",
+          sstrerror(errno, errbuf, sizeof(errbuf)));
+    tss2_close_socket();
+    return -1;
+  }
+
+  { /* Check that the server correctly identifies itself. */
+    char buffer[4096];
+    char *buffer_ptr;
+
+    buffer_ptr = fgets(buffer, sizeof(buffer), global_read_fh);
+    if (buffer_ptr == NULL) {
+      WARNING("teamspeak2 plugin: Unexpected EOF received "
+              "from remote host %s:%s.",
+              config_host ? config_host : DEFAULT_HOST,
+              config_port ? config_port : DEFAULT_PORT);
+    }
+    buffer[sizeof(buffer) - 1] = 0;
+
+    if (memcmp("[TS]\r\n", buffer, 6) != 0) {
+      ERROR("teamspeak2 plugin: Unexpected response when connecting "
+            "to server. Expected ``[TS]'', got ``%s''.",
+            buffer);
+      tss2_close_socket();
+      return -1;
+    }
+    DEBUG("teamspeak2 plugin: Server send correct banner, connected!");
+  }
+
+  /* Copy the new filehandles to the given pointers */
+  if (ret_read_fh != NULL)
+    *ret_read_fh = global_read_fh;
+  if (ret_write_fh != NULL)
+    *ret_write_fh = global_write_fh;
+  return 0;
 } /* int tss2_get_socket */
 
-static int tss2_send_request (FILE *fh, const char *request)
-{
-       /*
-        * This function puts a request to the server socket
-        */
-       int status;
-
-       status = fputs (request, fh);
-       if (status < 0)
-       {
-               ERROR ("teamspeak2 plugin: fputs failed.");
-               tss2_close_socket ();
-               return (-1);
-       }
-       fflush (fh);
-
-       return (0);
+static int tss2_send_request(FILE *fh, const char *request) {
+  /*
+   * This function puts a request to the server socket
+   */
+  int status;
+
+  status = fputs(request, fh);
+  if (status < 0) {
+    ERROR("teamspeak2 plugin: fputs failed.");
+    tss2_close_socket();
+    return -1;
+  }
+  fflush(fh);
+
+  return 0;
 } /* int tss2_send_request */
 
-static int tss2_receive_line (FILE *fh, char *buffer, int buffer_size)
-{
-       /*
-        * Receive a single line from the given file object
-        */
-       char *temp;
-
-       /*
-        * fgets is blocking but much easier then doing anything else
-        * TODO: Non-blocking Version would be safer
-        */
-       temp = fgets (buffer, buffer_size, fh);
-       if (temp == NULL)
-       {
-               char errbuf[1024];
-               ERROR ("teamspeak2 plugin: fgets failed: %s",
-                               sstrerror (errno, errbuf, sizeof(errbuf)));
-               tss2_close_socket ();
-               return (-1);
-       }
-
-       buffer[buffer_size - 1] = 0;
-       return (0);
+static int tss2_receive_line(FILE *fh, char *buffer, int buffer_size) {
+  /*
+   * Receive a single line from the given file object
+   */
+  char *temp;
+
+  /*
+   * fgets is blocking but much easier then doing anything else
+   * TODO: Non-blocking Version would be safer
+   */
+  temp = fgets(buffer, buffer_size, fh);
+  if (temp == NULL) {
+    char errbuf[1024];
+    ERROR("teamspeak2 plugin: fgets failed: %s",
+          sstrerror(errno, errbuf, sizeof(errbuf)));
+    tss2_close_socket();
+    return -1;
+  }
+
+  buffer[buffer_size - 1] = 0;
+  return 0;
 } /* int tss2_receive_line */
 
-static int tss2_select_vserver (FILE *read_fh, FILE *write_fh, vserver_list_t *vserver)
-{
-       /*
-        * Tell the server to select the given vserver
-        */
-       char command[128];
-       char response[128];
-       int status;
-
-       /* Send request */
-       ssnprintf (command, sizeof (command), "sel %i\r\n", vserver->port);
-
-       status = tss2_send_request (write_fh, command);
-       if (status != 0)
-       {
-               ERROR ("teamspeak2 plugin: tss2_send_request (%s) failed.", command);
-               return (-1);
-       }
-
-       /* Get answer */
-       status = tss2_receive_line (read_fh, response, sizeof (response));
-       if (status != 0)
-       {
-               ERROR ("teamspeak2 plugin: tss2_receive_line failed.");
-               return (-1);
-       }
-       response[sizeof (response) - 1] = 0;
-
-       /* Check answer */
-       if ((strncasecmp ("OK", response, 2) == 0)
-                       && ((response[2] == 0)
-                               || (response[2] == '\n')
-                               || (response[2] == '\r')))
-               return (0);
-
-       ERROR ("teamspeak2 plugin: Command ``%s'' failed. "
-                       "Response received from server was: ``%s''.",
-                       command, response);
-       return (-1);
+static int tss2_select_vserver(FILE *read_fh, FILE *write_fh,
+                               vserver_list_t *vserver) {
+  /*
+   * Tell the server to select the given vserver
+   */
+  char command[128];
+  char response[128];
+  int status;
+
+  /* Send request */
+  snprintf(command, sizeof(command), "sel %i\r\n", vserver->port);
+
+  status = tss2_send_request(write_fh, command);
+  if (status != 0) {
+    ERROR("teamspeak2 plugin: tss2_send_request (%s) failed.", command);
+    return -1;
+  }
+
+  /* Get answer */
+  status = tss2_receive_line(read_fh, response, sizeof(response));
+  if (status != 0) {
+    ERROR("teamspeak2 plugin: tss2_receive_line failed.");
+    return -1;
+  }
+  response[sizeof(response) - 1] = 0;
+
+  /* Check answer */
+  if ((strncasecmp("OK", response, 2) == 0) &&
+      ((response[2] == 0) || (response[2] == '\n') || (response[2] == '\r')))
+    return 0;
+
+  ERROR("teamspeak2 plugin: Command ``%s'' failed. "
+        "Response received from server was: ``%s''.",
+        command, response);
+  return -1;
 } /* int tss2_select_vserver */
 
-static int tss2_vserver_gapl (FILE *read_fh, FILE *write_fh,
-               gauge_t *ret_value)
-{
-       /*
-        * Reads the vserver's average packet loss and submits it to collectd.
-        * Be sure to run the tss2_read_vserver function before calling this so
-        * the vserver is selected correctly.
-        */
-       gauge_t packet_loss = NAN;
-       int status;
-
-       status = tss2_send_request (write_fh, "gapl\r\n");
-       if (status != 0)
-       {
-               ERROR("teamspeak2 plugin: tss2_send_request (gapl) failed.");
-               return (-1);
-       }
-
-       while (42)
-       {
-               char buffer[4096];
-               char *value;
-               char *endptr = NULL;
-
-               status = tss2_receive_line (read_fh, buffer, sizeof (buffer));
-               if (status != 0)
-               {
-                       /* Set to NULL just to make sure no one uses these FHs anymore. */
-                       read_fh = NULL;
-                       write_fh = NULL;
-                       ERROR ("teamspeak2 plugin: tss2_receive_line failed.");
-                       return (-1);
-               }
-               buffer[sizeof (buffer) - 1] = 0;
-
-               if (strncmp ("average_packet_loss=", buffer,
-                                       strlen ("average_packet_loss=")) == 0)
-               {
-                       /* Got average packet loss, now interpret it */
-                       value = &buffer[20];
-                       /* Replace , with . */
-                       while (*value != 0)
-                       {
-                               if (*value == ',')
-                               {
-                                       *value = '.';
-                                       break;
-                               }
-                               value++;
-                       }
-
-                       value = &buffer[20];
-
-                       packet_loss = strtod (value, &endptr);
-                       if (value == endptr)
-                       {
-                               /* Failed */
-                               WARNING ("teamspeak2 plugin: Could not read average package "
-                                               "loss from string: %s", buffer);
-                               continue;
-                       }
-               }
-               else if (strncasecmp ("OK", buffer, 2) == 0)
-               {
-                       break;
-               }
-               else if (strncasecmp ("ERROR", buffer, 5) == 0)
-               {
-                       ERROR ("teamspeak2 plugin: Server returned an error: %s", buffer);
-                       return (-1);
-               }
-               else
-               {
-                       WARNING ("teamspeak2 plugin: Server returned unexpected string: %s",
-                                       buffer);
-               }
-       }
-
-       *ret_value = packet_loss;
-       return (0);
+static int tss2_vserver_gapl(FILE *read_fh, FILE *write_fh,
+                             gauge_t *ret_value) {
+  /*
+   * Reads the vserver's average packet loss and submits it to collectd.
+   * Be sure to run the tss2_read_vserver function before calling this so
+   * the vserver is selected correctly.
+   */
+  gauge_t packet_loss = NAN;
+  int status;
+
+  status = tss2_send_request(write_fh, "gapl\r\n");
+  if (status != 0) {
+    ERROR("teamspeak2 plugin: tss2_send_request (gapl) failed.");
+    return -1;
+  }
+
+  while (42) {
+    char buffer[4096];
+    char *value;
+    char *endptr = NULL;
+
+    status = tss2_receive_line(read_fh, buffer, sizeof(buffer));
+    if (status != 0) {
+      /* Set to NULL just to make sure no one uses these FHs anymore. */
+      read_fh = NULL;
+      write_fh = NULL;
+      ERROR("teamspeak2 plugin: tss2_receive_line failed.");
+      return -1;
+    }
+    buffer[sizeof(buffer) - 1] = 0;
+
+    if (strncmp("average_packet_loss=", buffer,
+                strlen("average_packet_loss=")) == 0) {
+      /* Got average packet loss, now interpret it */
+      value = &buffer[20];
+      /* Replace , with . */
+      while (*value != 0) {
+        if (*value == ',') {
+          *value = '.';
+          break;
+        }
+        value++;
+      }
+
+      value = &buffer[20];
+
+      packet_loss = strtod(value, &endptr);
+      if (value == endptr) {
+        /* Failed */
+        WARNING("teamspeak2 plugin: Could not read average package "
+                "loss from string: %s",
+                buffer);
+        continue;
+      }
+    } else if (strncasecmp("OK", buffer, 2) == 0) {
+      break;
+    } else if (strncasecmp("ERROR", buffer, 5) == 0) {
+      ERROR("teamspeak2 plugin: Server returned an error: %s", buffer);
+      return -1;
+    } else {
+      WARNING("teamspeak2 plugin: Server returned unexpected string: %s",
+              buffer);
+    }
+  }
+
+  *ret_value = packet_loss;
+  return 0;
 } /* int tss2_vserver_gapl */
 
-static int tss2_read_vserver (vserver_list_t *vserver)
-{
-       /*
-        * Poll information for the given vserver and submit it to collect.
-        * If vserver is NULL the global server information will be queried.
-        */
-       int status;
-
-       gauge_t users = NAN;
-       gauge_t channels = NAN;
-       gauge_t servers = NAN;
-       derive_t rx_octets = 0;
-       derive_t tx_octets = 0;
-       derive_t rx_packets = 0;
-       derive_t tx_packets = 0;
-       gauge_t packet_loss = NAN;
-       int valid = 0;
-
-       char plugin_instance[DATA_MAX_NAME_LEN] = { 0 };
-
-       FILE *read_fh;
-       FILE *write_fh;
-
-       /* Get the send/receive sockets */
-       status = tss2_get_socket (&read_fh, &write_fh);
-       if (status != 0)
-       {
-               ERROR ("teamspeak2 plugin: tss2_get_socket failed.");
-               return (-1);
-       }
-
-       if (vserver == NULL)
-       {
-               /* Request global information */
-               status = tss2_send_request (write_fh, "gi\r\n");
-       }
-       else
-       {
-               /* Request server information */
-               ssnprintf (plugin_instance, sizeof (plugin_instance), "vserver%i",
-                               vserver->port);
-
-               /* Select the server */
-               status = tss2_select_vserver (read_fh, write_fh, vserver);
-               if (status != 0)
-                       return (status);
-
-               status = tss2_send_request (write_fh, "si\r\n");
-       }
-
-       if (status != 0)
-       {
-               ERROR ("teamspeak2 plugin: tss2_send_request failed.");
-               return (-1);
-       }
-
-       /* Loop until break */
-       while (42)
-       {
-               char buffer[4096];
-               char *key;
-               char *value;
-               char *endptr = NULL;
-
-               /* Read one line of the server's answer */
-               status = tss2_receive_line (read_fh, buffer, sizeof (buffer));
-               if (status != 0)
-               {
-                       /* Set to NULL just to make sure no one uses these FHs anymore. */
-                       read_fh = NULL;
-                       write_fh = NULL;
-                       ERROR ("teamspeak2 plugin: tss2_receive_line failed.");
-                       break;
-               }
-
-               if (strncasecmp ("ERROR", buffer, 5) == 0)
-               {
-                       ERROR ("teamspeak2 plugin: Server returned an error: %s",
-                                       buffer);
-                       break;
-               }
-               else if (strncasecmp ("OK", buffer, 2) == 0)
-               {
-                       break;
-               }
-
-               /* Split line into key and value */
-               key = strchr (buffer, '_');
-               if (key == NULL)
-               {
-                       DEBUG ("teamspeak2 plugin: Cannot parse line: %s", buffer);
-                       continue;
-               }
-               key++;
-
-               /* Evaluate assignment */
-               value = strchr (key, '=');
-               if (value == NULL)
-               {
-                       DEBUG ("teamspeak2 plugin: Cannot parse line: %s", buffer);
-                       continue;
-               }
-               *value = 0;
-               value++;
-
-               /* Check for known key and save the given value */
-               /* global info: users_online,
-                * server info: currentusers. */
-               if ((strcmp ("currentusers", key) == 0)
-                               || (strcmp ("users_online", key) == 0))
-               {
-                       users = strtod (value, &endptr);
-                       if (value != endptr)
-                               valid |= 0x01;
-               }
-               /* global info: channels,
-                * server info: currentchannels. */
-               else if ((strcmp ("currentchannels", key) == 0)
-                               || (strcmp ("channels", key) == 0))
-               {
-                       channels = strtod (value, &endptr);
-                       if (value != endptr)
-                               valid |= 0x40;
-               }
-               /* global only */
-               else if (strcmp ("servers", key) == 0)
-               {
-                       servers = strtod (value, &endptr);
-                       if (value != endptr)
-                               valid |= 0x80;
-               }
-               else if (strcmp ("bytesreceived", key) == 0)
-               {
-                       rx_octets = strtoll (value, &endptr, 0);
-                       if (value != endptr)
-                               valid |= 0x02;
-               }
-               else if (strcmp ("bytessend", key) == 0)
-               {
-                       tx_octets = strtoll (value, &endptr, 0);
-                       if (value != endptr)
-                               valid |= 0x04;
-               }
-               else if (strcmp ("packetsreceived", key) == 0)
-               {
-                       rx_packets = strtoll (value, &endptr, 0);
-                       if (value != endptr)
-                               valid |= 0x08;
-               }
-               else if (strcmp ("packetssend", key) == 0)
-               {
-                       tx_packets = strtoll (value, &endptr, 0);
-                       if (value != endptr)
-                               valid |= 0x10;
-               }
-               else if ((strncmp ("allow_codec_", key, strlen ("allow_codec_")) == 0)
-                               || (strncmp ("bwinlast", key, strlen ("bwinlast")) == 0)
-                               || (strncmp ("bwoutlast", key, strlen ("bwoutlast")) == 0)
-                               || (strncmp ("webpost_", key, strlen ("webpost_")) == 0)
-                               || (strcmp ("adminemail", key) == 0)
-                               || (strcmp ("clan_server", key) == 0)
-                               || (strcmp ("countrynumber", key) == 0)
-                               || (strcmp ("id", key) == 0)
-                               || (strcmp ("ispname", key) == 0)
-                               || (strcmp ("linkurl", key) == 0)
-                               || (strcmp ("maxusers", key) == 0)
-                               || (strcmp ("name", key) == 0)
-                               || (strcmp ("password", key) == 0)
-                               || (strcmp ("platform", key) == 0)
-                               || (strcmp ("server_platform", key) == 0)
-                               || (strcmp ("server_uptime", key) == 0)
-                               || (strcmp ("server_version", key) == 0)
-                               || (strcmp ("udpport", key) == 0)
-                               || (strcmp ("uptime", key) == 0)
-                               || (strcmp ("users_maximal", key) == 0)
-                               || (strcmp ("welcomemessage", key) == 0))
-                       /* ignore */;
-               else
-               {
-                       INFO ("teamspeak2 plugin: Unknown key-value-pair: "
-                                       "key = %s; value = %s;", key, value);
-               }
-       } /* while (42) */
-
-       /* Collect vserver packet loss rates only if the loop above did not exit
-        * with an error. */
-       if ((status == 0) && (vserver != NULL))
-       {
-               status = tss2_vserver_gapl (read_fh, write_fh, &packet_loss);
-               if (status == 0)
-               {
-                       valid |= 0x20;
-               }
-               else
-               {
-                       WARNING ("teamspeak2 plugin: Reading package loss "
-                                       "for vserver %i failed.", vserver->port);
-               }
-       }
-
-       if ((valid & 0x01) == 0x01)
-               tss2_submit_gauge (plugin_instance, "users", NULL, users);
-
-       if ((valid & 0x06) == 0x06)
-               tss2_submit_io (plugin_instance, "io_octets", rx_octets, tx_octets);
-
-       if ((valid & 0x18) == 0x18)
-               tss2_submit_io (plugin_instance, "io_packets", rx_packets, tx_packets);
-
-       if ((valid & 0x20) == 0x20)
-               tss2_submit_gauge (plugin_instance, "percent", "packet_loss", packet_loss);
-
-       if ((valid & 0x40) == 0x40)
-               tss2_submit_gauge (plugin_instance, "gauge", "channels", channels);
-
-       if ((valid & 0x80) == 0x80)
-               tss2_submit_gauge (plugin_instance, "gauge", "servers", servers);
-
-       if (valid == 0)
-               return (-1);
-       return (0);
+static int tss2_read_vserver(vserver_list_t *vserver) {
+  /*
+   * Poll information for the given vserver and submit it to collect.
+   * If vserver is NULL the global server information will be queried.
+   */
+  int status;
+
+  gauge_t users = NAN;
+  gauge_t channels = NAN;
+  gauge_t servers = NAN;
+  derive_t rx_octets = 0;
+  derive_t tx_octets = 0;
+  derive_t rx_packets = 0;
+  derive_t tx_packets = 0;
+  gauge_t packet_loss = NAN;
+  int valid = 0;
+
+  char plugin_instance[DATA_MAX_NAME_LEN] = {0};
+
+  FILE *read_fh;
+  FILE *write_fh;
+
+  /* Get the send/receive sockets */
+  status = tss2_get_socket(&read_fh, &write_fh);
+  if (status != 0) {
+    ERROR("teamspeak2 plugin: tss2_get_socket failed.");
+    return -1;
+  }
+
+  if (vserver == NULL) {
+    /* Request global information */
+    status = tss2_send_request(write_fh, "gi\r\n");
+  } else {
+    /* Request server information */
+    snprintf(plugin_instance, sizeof(plugin_instance), "vserver%i",
+             vserver->port);
+
+    /* Select the server */
+    status = tss2_select_vserver(read_fh, write_fh, vserver);
+    if (status != 0)
+      return status;
+
+    status = tss2_send_request(write_fh, "si\r\n");
+  }
+
+  if (status != 0) {
+    ERROR("teamspeak2 plugin: tss2_send_request failed.");
+    return -1;
+  }
+
+  /* Loop until break */
+  while (42) {
+    char buffer[4096];
+    char *key;
+    char *value;
+    char *endptr = NULL;
+
+    /* Read one line of the server's answer */
+    status = tss2_receive_line(read_fh, buffer, sizeof(buffer));
+    if (status != 0) {
+      /* Set to NULL just to make sure no one uses these FHs anymore. */
+      read_fh = NULL;
+      write_fh = NULL;
+      ERROR("teamspeak2 plugin: tss2_receive_line failed.");
+      break;
+    }
+
+    if (strncasecmp("ERROR", buffer, 5) == 0) {
+      ERROR("teamspeak2 plugin: Server returned an error: %s", buffer);
+      break;
+    } else if (strncasecmp("OK", buffer, 2) == 0) {
+      break;
+    }
+
+    /* Split line into key and value */
+    key = strchr(buffer, '_');
+    if (key == NULL) {
+      DEBUG("teamspeak2 plugin: Cannot parse line: %s", buffer);
+      continue;
+    }
+    key++;
+
+    /* Evaluate assignment */
+    value = strchr(key, '=');
+    if (value == NULL) {
+      DEBUG("teamspeak2 plugin: Cannot parse line: %s", buffer);
+      continue;
+    }
+    *value = 0;
+    value++;
+
+    /* Check for known key and save the given value */
+    /* global info: users_online,
+     * server info: currentusers. */
+    if ((strcmp("currentusers", key) == 0) ||
+        (strcmp("users_online", key) == 0)) {
+      users = strtod(value, &endptr);
+      if (value != endptr)
+        valid |= 0x01;
+    }
+    /* global info: channels,
+     * server info: currentchannels. */
+    else if ((strcmp("currentchannels", key) == 0) ||
+             (strcmp("channels", key) == 0)) {
+      channels = strtod(value, &endptr);
+      if (value != endptr)
+        valid |= 0x40;
+    }
+    /* global only */
+    else if (strcmp("servers", key) == 0) {
+      servers = strtod(value, &endptr);
+      if (value != endptr)
+        valid |= 0x80;
+    } else if (strcmp("bytesreceived", key) == 0) {
+      rx_octets = strtoll(value, &endptr, 0);
+      if (value != endptr)
+        valid |= 0x02;
+    } else if (strcmp("bytessend", key) == 0) {
+      tx_octets = strtoll(value, &endptr, 0);
+      if (value != endptr)
+        valid |= 0x04;
+    } else if (strcmp("packetsreceived", key) == 0) {
+      rx_packets = strtoll(value, &endptr, 0);
+      if (value != endptr)
+        valid |= 0x08;
+    } else if (strcmp("packetssend", key) == 0) {
+      tx_packets = strtoll(value, &endptr, 0);
+      if (value != endptr)
+        valid |= 0x10;
+    } else if ((strncmp("allow_codec_", key, strlen("allow_codec_")) == 0) ||
+               (strncmp("bwinlast", key, strlen("bwinlast")) == 0) ||
+               (strncmp("bwoutlast", key, strlen("bwoutlast")) == 0) ||
+               (strncmp("webpost_", key, strlen("webpost_")) == 0) ||
+               (strcmp("adminemail", key) == 0) ||
+               (strcmp("clan_server", key) == 0) ||
+               (strcmp("countrynumber", key) == 0) ||
+               (strcmp("id", key) == 0) || (strcmp("ispname", key) == 0) ||
+               (strcmp("linkurl", key) == 0) ||
+               (strcmp("maxusers", key) == 0) || (strcmp("name", key) == 0) ||
+               (strcmp("password", key) == 0) ||
+               (strcmp("platform", key) == 0) ||
+               (strcmp("server_platform", key) == 0) ||
+               (strcmp("server_uptime", key) == 0) ||
+               (strcmp("server_version", key) == 0) ||
+               (strcmp("udpport", key) == 0) || (strcmp("uptime", key) == 0) ||
+               (strcmp("users_maximal", key) == 0) ||
+               (strcmp("welcomemessage", key) == 0))
+      /* ignore */;
+    else {
+      INFO("teamspeak2 plugin: Unknown key-value-pair: "
+           "key = %s; value = %s;",
+           key, value);
+    }
+  } /* while (42) */
+
+  /* Collect vserver packet loss rates only if the loop above did not exit
+   * with an error. */
+  if ((status == 0) && (vserver != NULL)) {
+    status = tss2_vserver_gapl(read_fh, write_fh, &packet_loss);
+    if (status == 0) {
+      valid |= 0x20;
+    } else {
+      WARNING("teamspeak2 plugin: Reading package loss "
+              "for vserver %i failed.",
+              vserver->port);
+    }
+  }
+
+  if ((valid & 0x01) == 0x01)
+    tss2_submit_gauge(plugin_instance, "users", NULL, users);
+
+  if ((valid & 0x06) == 0x06)
+    tss2_submit_io(plugin_instance, "io_octets", rx_octets, tx_octets);
+
+  if ((valid & 0x18) == 0x18)
+    tss2_submit_io(plugin_instance, "io_packets", rx_packets, tx_packets);
+
+  if ((valid & 0x20) == 0x20)
+    tss2_submit_gauge(plugin_instance, "percent", "packet_loss", packet_loss);
+
+  if ((valid & 0x40) == 0x40)
+    tss2_submit_gauge(plugin_instance, "gauge", "channels", channels);
+
+  if ((valid & 0x80) == 0x80)
+    tss2_submit_gauge(plugin_instance, "gauge", "servers", servers);
+
+  if (valid == 0)
+    return -1;
+  return 0;
 } /* int tss2_read_vserver */
 
-static int tss2_config (const char *key, const char *value)
-{
-       /*
-        * Interpret configuration values
-        */
-       if (strcasecmp ("Host", key) == 0)
-       {
-               char *temp;
-
-               temp = strdup (value);
-               if (temp == NULL)
-               {
-                       ERROR("teamspeak2 plugin: strdup failed.");
-                       return (1);
-               }
-               sfree (config_host);
-               config_host = temp;
-       }
-       else if (strcasecmp ("Port", key) == 0)
-       {
-               char *temp;
-
-               temp = strdup (value);
-               if (temp == NULL)
-               {
-                       ERROR("teamspeak2 plugin: strdup failed.");
-                       return (1);
-               }
-               sfree (config_port);
-               config_port = temp;
-       }
-       else if (strcasecmp ("Server", key) == 0)
-       {
-               /* Server variable found */
-               int status;
-
-               status = tss2_add_vserver (atoi (value));
-               if (status != 0)
-                       return (1);
-       }
-       else
-       {
-               /* Unknown variable found */
-               return (-1);
-       }
-
-       return 0;
+static int tss2_config(const char *key, const char *value) {
+  /*
+   * Interpret configuration values
+   */
+  if (strcasecmp("Host", key) == 0) {
+    char *temp;
+
+    temp = strdup(value);
+    if (temp == NULL) {
+      ERROR("teamspeak2 plugin: strdup failed.");
+      return 1;
+    }
+    sfree(config_host);
+    config_host = temp;
+  } else if (strcasecmp("Port", key) == 0) {
+    char *temp;
+
+    temp = strdup(value);
+    if (temp == NULL) {
+      ERROR("teamspeak2 plugin: strdup failed.");
+      return 1;
+    }
+    sfree(config_port);
+    config_port = temp;
+  } else if (strcasecmp("Server", key) == 0) {
+    /* Server variable found */
+    int status;
+
+    status = tss2_add_vserver(atoi(value));
+    if (status != 0)
+      return 1;
+  } else {
+    /* Unknown variable found */
+    return -1;
+  }
+
+  return 0;
 } /* int tss2_config */
 
-static int tss2_read (void)
-{
-       /*
-        * Poll function which collects global and vserver information
-        * and submits it to collectd
-        */
-       int success = 0;
-       int status;
-
-       /* Handle global server variables */
-       status = tss2_read_vserver (NULL);
-       if (status == 0)
-       {
-               success++;
-       }
-       else
-       {
-               WARNING ("teamspeak2 plugin: Reading global server variables failed.");
-       }
-
-       /* Handle vservers */
-       for (vserver_list_t *vserver = server_list; vserver != NULL; vserver = vserver->next)
-       {
-               status = tss2_read_vserver (vserver);
-               if (status == 0)
-               {
-                       success++;
-               }
-               else
-               {
-                       WARNING ("teamspeak2 plugin: Reading statistics "
-                                       "for vserver %i failed.", vserver->port);
-                       continue;
-               }
-       }
-
-       if (success == 0)
-               return (-1);
-       return (0);
+static int tss2_read(void) {
+  /*
+   * Poll function which collects global and vserver information
+   * and submits it to collectd
+   */
+  int success = 0;
+  int status;
+
+  /* Handle global server variables */
+  status = tss2_read_vserver(NULL);
+  if (status == 0) {
+    success++;
+  } else {
+    WARNING("teamspeak2 plugin: Reading global server variables failed.");
+  }
+
+  /* Handle vservers */
+  for (vserver_list_t *vserver = server_list; vserver != NULL;
+       vserver = vserver->next) {
+    status = tss2_read_vserver(vserver);
+    if (status == 0) {
+      success++;
+    } else {
+      WARNING("teamspeak2 plugin: Reading statistics "
+              "for vserver %i failed.",
+              vserver->port);
+      continue;
+    }
+  }
+
+  if (success == 0)
+    return -1;
+  return 0;
 } /* int tss2_read */
 
-static int tss2_shutdown(void)
-{
-       /*
-        * Shutdown handler
-        */
-       vserver_list_t *entry;
+static int tss2_shutdown(void) {
+  /*
+   * Shutdown handler
+   */
+  vserver_list_t *entry;
 
-       tss2_close_socket ();
+  tss2_close_socket();
 
-       entry = server_list;
-       server_list = NULL;
-       while (entry != NULL)
-       {
-               vserver_list_t *next;
+  entry = server_list;
+  server_list = NULL;
+  while (entry != NULL) {
+    vserver_list_t *next;
 
-               next = entry->next;
-               sfree (entry);
-               entry = next;
-       }
+    next = entry->next;
+    sfree(entry);
+    entry = next;
+  }
 
-       /* Get rid of the configuration */
-       sfree (config_host);
-       sfree (config_port);
+  /* Get rid of the configuration */
+  sfree(config_host);
+  sfree(config_port);
 
-    return (0);
+  return 0;
 } /* int tss2_shutdown */
 
-void module_register(void)
-{
-       /*
-        * Mandatory module_register function
-        */
-       plugin_register_config ("teamspeak2", tss2_config,
-                       config_keys, config_keys_num);
-       plugin_register_read ("teamspeak2", tss2_read);
-       plugin_register_shutdown ("teamspeak2", tss2_shutdown);
+void module_register(void) {
+  /*
+   * Mandatory module_register function
+   */
+  plugin_register_config("teamspeak2", tss2_config, config_keys,
+                         config_keys_num);
+  plugin_register_read("teamspeak2", tss2_read);
+  plugin_register_shutdown("teamspeak2", tss2_shutdown);
 } /* void module_register */
-
-/* vim: set sw=4 ts=4 : */