/*************************************************************************** * Copyright (C) 02/2010 by Olaf Rempel * * razzor@kopf-tisch.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include "configfile.h" #include "helper.h" #include "list.h" #include "logging.h" #include "plugins.h" #include "probe.h" #include "sockaddr.h" #define TS2_RESP_SIZE 1024 struct sammler_plugin plugin; struct server_entry { struct list_head list; char *name; int errors; struct sockaddr_in sa; }; static LIST_HEAD(server_list); static char *ts2_resp_buf; static const char *ds_def = { "DS:users:GAUGE:90:0:U " "DS:channels:GAUGE:90:0:U " }; static const char * get_ds(int ds_id) { return ds_def; } static int probe(void) { struct server_entry *entry; list_for_each_entry(entry, &server_list, list) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { log_print(LOG_WARN, "plugin ts2: socket()"); continue; } int ret = connect(sock, (struct sockaddr *)&entry->sa, sizeof(entry->sa)); if (ret != 0) { if (entry->errors++ == 0) log_print(LOG_ERROR, "plugin ts2: connect(%s)", get_sockaddr_buf(&entry->sa)); close(sock); continue; } /* read prompt "[TS]" */ int len = read(sock, ts2_resp_buf, TS2_RESP_SIZE); if (len <= 0) { if (entry->errors++ == 0) log_print(LOG_ERROR, "ts2: read(1)"); close(sock); continue; } if (strncmp(ts2_resp_buf, "[TS]", 4) != 0) { if (entry->errors++ == 0) log_print(LOG_ERROR, "ts2: invalid prompt from server"); close(sock); continue; } /* query "general informations" */ char cmd1[] = "gi\n"; write(sock, cmd1, sizeof(cmd1)); len = read(sock, ts2_resp_buf, TS2_RESP_SIZE); if (len <= 0) { if (entry->errors++ == 0) log_print(LOG_ERROR, "ts2: read(2)"); close(sock); continue; } /* send quit (but we close the socket anyway..) */ char cmd2[] = "quit"; write(sock, cmd2, sizeof(cmd2)); close(sock); /* terminate response */ ts2_resp_buf[len] = '\0'; char *tok, *tmp, *resp = ts2_resp_buf; int users = 0, channels = 0; while ((tok = strtok_r(resp, "\r\n", &tmp)) != NULL) { /* total_users_online=14 */ if (strncmp(tok, "total_users_online", 18) == 0) { users = atoi(tok +19); /* total_channels=3 */ } else if (strncmp(tok, "total_channels", 14) == 0) { channels = atoi(tok +15); } resp = NULL; } char filename[32]; len = snprintf(filename, sizeof(filename), "ts2-%s.rrd", entry->name); if (len < 0 || len >= sizeof(filename)) continue; probe_submit(&plugin, filename, 0, "%d:%d", users, channels); if (entry->errors > 0) { log_print(LOG_ERROR, "plugin ts2: success (%s) after %d errors", entry->name, entry->errors); entry->errors = 0; } } return 0; } static int init_cb(struct strtoken *tokens, void *privdata) { if (tokens->count != 2) { log_print(LOG_ERROR, "p_ts2: parse error"); return -1; } struct server_entry *entry = malloc(sizeof(struct server_entry)); if (entry == NULL) { log_print(LOG_ERROR, "p_ts2: out of memory"); return -1; } entry->name = strdup(tokens->field[0]); entry->errors = 0; if (parse_sockaddr(tokens->field[1], &entry->sa) < 0) { log_print(LOG_ERROR, "p_ts2: invalid address: <%s>", tokens->field[1]); free(entry->name); free(entry); return -1; } log_print(LOG_INFO, "p_ts2: added server '%s'", entry->name); list_add_tail(&entry->list, &server_list); return 0; } static int init(void) { ts2_resp_buf = malloc(TS2_RESP_SIZE); if (ts2_resp_buf == NULL) { log_print(LOG_ERROR, "p_ts2: out of memory"); return -1; } config_get_strtokens("p_ts2", "server", ",", 2, init_cb, NULL); return 0; } static int fini(void) { struct server_entry *entry, *tmp; list_for_each_entry_safe(entry, tmp, &server_list, list) { free(entry->name); free(entry); } free(ts2_resp_buf); return 0; } struct sammler_plugin plugin = { .name = "ts2", .interval = 60, .init = &init, .fini = &fini, .probe = &probe, .get_ds = &get_ds, };