X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fteamspeak2.c;h=4d68f61f0ee4f21865e2573452a7318de10cb1b5;hp=1bd969bd9e158dcbf6d7bb92c5fd9e68f70ce599;hb=1159cb5d383c55a80a0db100b8f7aadcf44740a5;hpb=c442c66d9e98852f1b8eaa1b816d6ee7f84d0342 diff --git a/src/teamspeak2.c b/src/teamspeak2.c index 1bd969bd..4d68f61f 100644 --- a/src/teamspeak2.c +++ b/src/teamspeak2.c @@ -26,26 +26,25 @@ #include "common.h" #include "plugin.h" -#include #include -#include #include +#include +#include /* * 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 : */