/*
* Copyright (C) 2002-07 Luca Deri <deri@ntop.org>
*
* http://www.ntop.org/
*
* 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.
*/
/*
Aberrant RRD Behavior (http://cricket.sourceforge.net/aberrant/)
patch courtesy of Dominique Karg <dk@ipsoluciones.com>
*/
#include "rrdPlugin.h"
#ifndef _GETOPT_H
#define _GETOPT_H
#endif
#define REMOTE_SERVER_PORT 2005
static u_char useDaemon = 0;
static int sd = -1;
static struct sockaddr_in cliAddr, remoteServAddr;
#if defined(RRD_DEBUG) && (RRD_DEBUG > 0)
#define traceEventRRDebug(level, ...) { if(RRD_DEBUG >= level) \
traceEvent(CONST_TRACE_NOISY, "RRD_DEBUG: " __VA_ARGS__); \
}
#define traceEventRRDebugARGV(level) { if(RRD_DEBUG >= level) { \
int _iARGV; \
for(_iARGV=0; _iARGV<argc; _iARGV++) { \
traceEvent(CONST_TRACE_NOISY, "RRD_DEBUG: argv[%d] = %s", _iARGV, argv[_iARGV]); \
} \
} \
}
#else
#define traceEventRRDebug
#define traceEventRRDebugARGV
#endif
#ifdef WIN32
int optind, opterr;
unsigned long driveSerial;
#else
static u_short dumpPermissions;
#endif
static PthreadMutex rrdMutex;
static pthread_t rrdThread, rrdTrafficThread;
static unsigned short initialized = 0, active = 0, colorWarn = 0, graphErrCount = 0,
dumpInterval, dumpShortInterval, dumpDetail;
static unsigned short dumpDays, dumpHours, dumpMonths, dumpDelay;
static char *hostsFilter = NULL;
static Counter numRRDUpdates = 0, numTotalRRDUpdates = 0;
static unsigned long numRuns = 0, numRRDerrors = 0, numRRDCycles=0;
static time_t start_tm, end_tm, rrdTime;
static u_short dumpDomains, dumpFlows, dumpHosts,
dumpInterfaces, dumpASs, enableAberrant, dumpMatrix, shownCreate=0;
static Counter rrdGraphicRequests=0;
/* forward */
static void setPluginStatus(char * status);
static int initRRDfunct(void);
static void arbitraryActionPage(void);
static void statisticsPage(void);
static void printRRDPluginTrailer(void);
static void handleRRDHTTPrequest(char* url);
static char* spacer(char* str, char *tmpStr, int tmpStrLen,
char *metric_name, int metric_name_len);
static int graphCounter(char *rrdPath, char *rrdName, char *rrdTitle, char *rrdCounter,
char *startTime, char* endTime, char* rrdPrefix);
static void graphSummary(char *rrdPath, char *rrdName, int graphId, char *startTime, char* endTime, char* rrdPrefix, char *mode);
static void netflowSummary(char *rrdPath, int graphId, char *startTime, char* endTime, char* rrdPrefix, char *mode);
static void interfaceSummary(char *rrdPath, int graphId, char *startTime, char* endTime, char* rrdPrefix, char *mode);
static void updateCounter(char *hostPath, char *key, Counter value, char short_step);
static void updateGauge(char *hostPath, char *key, Counter value, char short_step);
static void updateTrafficCounter(char *hostPath, char *key, TrafficCounter *counter, char short_step);
char x2c(char *what);
static void termRRDfunct(u_char termNtop /* 0=term plugin, 1=term ntop */);
static void addRrdDelay();
#define MAX_NUM_RRDS 64
/* ************************************* */
static ExtraPage rrdExtraPages[] = {
{ NULL, CONST_RRD_STATISTICS_HTML, "Statistics" },
{ "graph.gif", CONST_RRD_ARBGRAPH_HTML, "Arbitrary Graphs" },
{ NULL, NULL, NULL }
};
static PluginInfo rrdPluginInfo[] = {
{
VERSION, /* current ntop version */
"Round-Robin Databases",
"This plugin is used to setup, activate and deactivate ntop's rrd support.<br>"
"This plugin also produces the graphs of rrd data, available via a<br>"
"link from the various 'Info about host xxxxx' reports.",
"2.8", /* version */
"<a HREF=\"http://luca.ntop.org/\" alt=\"Luca's home page\">L.Deri</A>",
"rrdPlugin", /* http://<host>:<port>/plugins/rrdPlugin */
1, /* Active by default */
ConfigureOnly, /* use extra pages for the views */
1, /* Inactive setup */
initRRDfunct, /* TermFunc */
termRRDfunct, /* TermFunc */
NULL, /* PluginFunc */
handleRRDHTTPrequest,
NULL, /* no host creation/deletion handle */
NULL, /* no capture */
NULL, /* no status */
rrdExtraPages /* no extra pages */
}
};
/* ****************************************************** */
static char **calcpr=NULL;
static void calfree (void) {
if(calcpr) {
long i;
for(i=0; calcpr[i]; i++){
if(calcpr[i])
free(calcpr[i]);
}
if(calcpr)
free(calcpr);
}
}
/* ******************************************* */
static char* capitalizeInitial(char *str) {
char c = toupper(str[0]);
// traceEvent(CONST_TRACE_INFO, "RRD: (%s)", str);
str[0] = c;
return(str);
}
/* ******************************************* */
static void fillupArgv(int argc, int maxArgc, char *argv[]) {
int i;
for(i=argc; i<maxArgc; i++)
argv[i] = "";
optind = 1;
}
/* ******************************************* */
/* FIX: we need to handle MAC addresses/symbolic IP too */
static int validHostCommunity(char *host_ip /* 1.2.3.4 */) {
char buf[64], *community;
//traceEvent(CONST_TRACE_INFO, "RRD: validHostCommunity(%s)", host_ip);
community = findHostCommunity(inet_addr(host_ip), buf, sizeof(buf));
if(community && (!isAllowedCommunity(community)))
return(0);
return(1);
}
/* ******************************************* */
static void addRrdDelay() {
static struct timeval lastSleep;
struct timeval thisSleep;
float deltaMs;
if(dumpDelay == 0) return;
gettimeofday(&thisSleep, NULL);
deltaMs = (timeval_subtract(thisSleep, lastSleep) / 1000) - dumpDelay;
if(deltaMs > 0) {
#ifdef WIN32
Sleep((int)dumpDelay);
#else
struct timespec sleepAmount;
sleepAmount.tv_sec = 0; sleepAmount.tv_nsec = (int)dumpDelay * 1000;
nanosleep(&sleepAmount, NULL);
#endif
}
gettimeofday(&lastSleep, NULL);
}
/* ******************************************* */
static void createMultihostGraph(char *rrdName,
HostTraffic *rrdHosts[MAX_NUM_NETWORKS],
u_int32_t numRrdHosts,
char *startTime, char* endTime) {
char buf[512], hosts[512] = { '\0' };
int i;
for(i=0; i<numRrdHosts; i++) {
char *host_ip;
host_ip = (rrdHosts[i]->ethAddressString[0] != '\0') ? rrdHosts[i]->ethAddressString : rrdHosts[i]->hostNumIpAddress;
if((strlen(hosts) + strlen(host_ip)) < sizeof(hosts)) {
if(i > 0) strcat(hosts, ",");
strcat(hosts, host_ip);
strcat(hosts, "@");
strcat(hosts, rrdHosts[i]->hostResolvedName);
}
}
/*
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<A HREF=\"/" CONST_PLUGINS_HEADER "%s?mode=zoom&action=graphSummary&graphId=98&name=%s&start=%s&end=%s&key=%s\">",
rrdPluginInfo->pluginURLname, rrdName, startTime, endTime, hosts);
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<IMG SRC=\"/" CONST_PLUGINS_HEADER "%s?action=graphSummary&graphId=98&name=%s&start=%s&end=%s&key=%s\"></A>\n",
rrdPluginInfo->pluginURLname, rrdName, startTime, endTime, hosts);
sendString(buf);
*/
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"</td> <td><IMG SRC=\"/" CONST_PLUGINS_HEADER "%s?action=graphSummary&graphId=98&name=%s&start=%s&end=%s&key=%s\"></td>\n",
rrdPluginInfo->pluginURLname, rrdName, startTime, endTime, hosts);
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<td><A HREF=\"/" CONST_PLUGINS_HEADER "%s?mode=zoom&action=graphSummary&graphId=98&name=%s&start=%s&end=%s&key=%s\">"
"<IMG valign=top class=tooltip SRC=/graph_zoom.gif border=0></A>\n",
rrdPluginInfo->pluginURLname, rrdName, startTime, endTime, hosts);
sendString(buf);
}
/* ******************************************* */
static void expandRRDList(char *rrdName,
u_int32_t localNetworks[MAX_NUM_NETWORKS][4], /* [0]=network, [1]=mask, [2]=broadcast, [3]=mask_v6 */
u_short numLocalNetworks, char *startTime, char* endTime) {
char path[256], rrdName_copy[64], debug=0;
u_int32_t numRrdHosts = 0, i;
HostTraffic *rrdHosts[MAX_NUM_NETWORKS];
if(debug) traceEvent(CONST_TRACE_WARNING, "RRD: expandRRDList(%s)", rrdName);
safe_snprintf(__FILE__, __LINE__, rrdName_copy, sizeof(rrdName_copy), "%s", rrdName);
rrdName_copy[strlen(rrdName_copy)-strlen(CONST_RRD_EXTENSION)] = '\0';
for(i=0; i<numLocalNetworks; i++) {
struct stat statbuf;
HostTraffic *el;
HostAddr ha;
int j;
ha.hostFamily = AF_INET;
ha.addr._hostIp4Address.s_addr = localNetworks[i][0]; /* FIX: expand network */
if((el = findHostByNumIP(ha, 0, myGlobals.actualReportDeviceId)) != NULL) {
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/interfaces/%s/hosts/%s/%s",
myGlobals.rrdPath, myGlobals.device[myGlobals.actualReportDeviceId].uniqueIfName,
(el->ethAddressString[0] != '\0') ? el->ethAddressString : el->hostNumIpAddress,
rrdName);
for(j=strlen(myGlobals.rrdPath)
+strlen("/interfaces/")
+strlen(myGlobals.device[myGlobals.actualReportDeviceId].uniqueIfName)
+strlen("/hosts/"); j<strlen(path)-strlen(CONST_RRD_EXTENSION); j++)
if((path[j] == '.') || (path[j] == ':')) path[j] = '/';
revertSlashIfWIN32(path, 0);
if(debug) traceEvent(CONST_TRACE_WARNING, "RRD: expandRRDList(%s): %s", rrdName, path);
if(stat(path, &statbuf) == 0) {
if(debug) traceEvent(CONST_TRACE_WARNING, "RRD: ---> %s [%u]",
path, num_network_bits(localNetworks[i][1]));
rrdHosts[numRrdHosts++] = el;
}
}
}
if(numRrdHosts > 0)
createMultihostGraph(rrdName_copy, rrdHosts, numRrdHosts, startTime, endTime);
if(debug) traceEvent(CONST_TRACE_WARNING, "RRD: -------------------------");
}
/* ******************************************* */
static int cmpStrings(const void *_a, const void *_b)
{
char **str_a = (char**)_a;
char **str_b = (char**)_b;
/* traceEvent(CONST_TRACE_WARNING, "RRD: [%s][%s]", *str_a, *str_b); */
return(strcmp(*str_a, *str_b));
}
/* ******************************************* */
static void listResource(char *rrdPath, char *rrdTitle, char *cluster,
char *startTime, char* endTime) {
char path[512], url[512], hasNetFlow, buf[512];
DIR* directoryPointer=NULL;
struct dirent* dp;
int i, debug = 0;
#if 0
int numFailures = 0;
#endif
time_t now = time(NULL);
if(!validHostCommunity(rrdTitle)) {
returnHTTPpageBadCommunity();
return;
}
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s", myGlobals.rrdPath, rrdPath);
revertSlashIfWIN32(path, 0);
if(cluster == NULL)
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "Info about %s", rrdTitle);
else
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "Info about cluster %s", cluster);
printHTMLheader(buf, NULL, 0);
sendString("<p ALIGN=left>\n");
safe_snprintf(__FILE__, __LINE__, url, sizeof(url),
"/" CONST_PLUGINS_HEADER "%s?action=list&key=%s&title=%s&end=%u&cluster=%s",
rrdPluginInfo->pluginURLname,
rrdPath, rrdTitle, (unsigned long)now,
cluster ? cluster : "");
sendString("<script type=\"text/javascript\">\n"
" function send(f)\n"
" {\n"
" var chosen;\n"
" chosen=f.options[f.selectedIndex].value;\n"
" self.location=chosen;\n"
" } \n"
"</script>\n");
sendString("<form name=myform method=get>\n<b>Presets:</b> \n"
"<select name=presets onchange=\"send(this)\">\n");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<option value=\"%s&start=%u\" default>-----</option>\n", url, now - 86400);
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<option value=\"%s&start=%u\">Last Year</option>\n", url, now - 365*86400);
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<option value=\"%s&start=%u\">Last Month</option>\n", url, now - 30*86400);
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<option value=\"%s&start=%u\">Last Week</option>\n", url, now - 7*86400);
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<option value=\"%s&start=%u\">Last Day</option>\n", url, now - 86400);
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<option value=\"%s&start=%u\">Last 12h</option>\n", url, now - 12 * 3600);
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<option value=\"%s&start=%u\">Last 6h</option>\n", url, now - 6 * 86400);
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<option value=\"%s&start=%u\">Last Hour</option>\n", url, now - 86400);
sendString(buf);
sendString("</select></form></p>\n<center>\n<p>\n");
sendString("<TABLE BORDER=0 "TABLE_DEFAULTS">\n");
if(cluster == NULL) {
directoryPointer = opendir(path);
if(directoryPointer == NULL) {
sendString("</TABLE>");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "Unable to read directory %s", path);
traceEvent(CONST_TRACE_INFO, "RRD: %s", buf);
printFlagedWarning(buf);
sendString("</CENTER>");
printHTMLtrailer();
return;
}
hasNetFlow = 0;
while((dp = readdir(directoryPointer)) != NULL) {
if(strncmp(dp->d_name, "NF_", 3) == 0) {
hasNetFlow = 1;
break;
}
} /* while */
closedir(directoryPointer);
if(hasNetFlow) {
for(i=0; i<=2; i++) {
sendString("<TR><TD align=left>");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<IMG SRC=\"/" CONST_PLUGINS_HEADER "%s?action=netflowSummary"
"&graphId=%d&key=%s/&start=%s&end=%s\">\n",
rrdPluginInfo->pluginURLname,
i, rrdPath, startTime, endTime);
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"</td><td><A HREF=\"/" CONST_PLUGINS_HEADER "%s?"
"mode=zoom&action=netflowIfSummary&graphId=%d&key=%s/&start=%s&end=%s\">\n"
"<IMG valign=top class=tooltip SRC=/graph_zoom.gif border=0></A>\n",
rrdPluginInfo->pluginURLname, i, rrdPath, startTime, endTime);
sendString(buf);
sendString("</TD></TR>\n");
}
}
directoryPointer = opendir(path);
if(directoryPointer == NULL) {
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "Unable to read directory %s", path);
printFlagedWarning(buf);
sendString("</CENTER>");
printHTMLtrailer();
return;
} else {
// traceEvent(CONST_TRACE_WARNING, "RRD: reading directory %s", path); /* FIX */
}
while((dp = readdir(directoryPointer)) != NULL) {
char *rsrcName;
Counter total;
#if 0
float average;
#endif
int rc, isGauge;
if(dp->d_name[0] == '.') continue;
else if(strncmp(dp->d_name, "NF_", 3) == 0) continue;
else if(strlen(dp->d_name) < strlen(CONST_RRD_EXTENSION)+3)
continue;
rsrcName = &dp->d_name[strlen(dp->d_name)-strlen(CONST_RRD_EXTENSION)-3];
if(strcmp(rsrcName, "Num"CONST_RRD_EXTENSION) == 0)
isGauge = 1;
else
isGauge = 0;
rsrcName = &dp->d_name[strlen(dp->d_name)-strlen(CONST_RRD_EXTENSION)];
if(strcmp(rsrcName, CONST_RRD_EXTENSION))
continue;
#if 0
if(sumCounter(rrdPath, dp->d_name, "FAILURES", startTime, endTime, &total, &average) >= 0)
numFailures += total;
#endif
#if DISPLAY_ONLY_IF_THERE_S_DATA
rc = sumCounter(rrdPath, dp->d_name, "MAX", startTime, endTime, &total, &average);
#else
rc = 1, total = 1;
#endif
if(isGauge || ((rc >= 0) && (total > 0))) {
rsrcName = dp->d_name;
/* if(strcmp(rsrcName, "pktSent") || strcmp(rsrcName, "pktRcvd")) continue; */
if(strncmp(rsrcName, "IP_", 3)
|| strncmp(rsrcName, "tcp", 3)
|| strncmp(rsrcName, "udp", 3)
) {
if(!strstr(rsrcName, "Rcvd")) {
sendString("<TR><TD align=left>\n");
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "<img class=tooltip src=\"/" CONST_PLUGINS_HEADER "%s?"
"action=graphSummary&graphId=99&key=%s/&name=%s&title=%s&start=%s&end=%s\">\n",
rrdPluginInfo->pluginURLname,
rrdPath, rsrcName, rsrcName, startTime, endTime);
sendString(path);
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "</td><td align=right><A HREF=\"/" CONST_PLUGINS_HEADER "%s?"
"mode=zoom&action=graphSummary&graphId=99&key=%s/&name=%s&title=%s&start=%s&end=%s\">"
"<IMG valign=top class=tooltip SRC=/graph_zoom.gif border=0></A><p>\n",
rrdPluginInfo->pluginURLname, rrdPath, rsrcName, rsrcName, startTime, endTime);
sendString(path);
sendString("</TD></TR>\n");
}
}
}
} /* while */
closedir(directoryPointer);
} else {
/* Cluster */
char clusterAddresses[256] = { '\0' }, localAddresses[1024] = { '\0' };
u_int32_t localNetworks[MAX_NUM_NETWORKS][4]; /* [0]=network, [1]=mask, [2]=broadcast, [3]=mask_v6 */
u_short numLocalNetworks = 0, found = 0, num_rrds = 0;
char *keys[MAX_NUM_RRDS];
int k;
snprintf(buf, sizeof(buf), "cluster.%s", cluster);
if(fetchPrefsValue(buf, clusterAddresses, sizeof(clusterAddresses)) != -1) {
handleAddressLists(clusterAddresses, localNetworks, &numLocalNetworks,
localAddresses, sizeof(localAddresses),
CONST_HANDLEADDRESSLISTS_CLUSTERS);
}
for(i=0; i<numLocalNetworks; i++) {
HostTraffic *el;
HostAddr ha;
int j;
ha.hostFamily = AF_INET;
ha.addr._hostIp4Address.s_addr = localNetworks[i][0];
if((el = findHostByNumIP(ha, 0, myGlobals.actualReportDeviceId)) != NULL) {
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/interfaces/%s/hosts/%s",
myGlobals.rrdPath, myGlobals.device[myGlobals.actualReportDeviceId].uniqueIfName,
(el->ethAddressString[0] != '\0') ? el->ethAddressString : el->hostNumIpAddress);
for(j=strlen(path)-strlen((el->ethAddressString[0] != '\0') ? el->ethAddressString : el->hostNumIpAddress); j<strlen(path); j++)
if((path[j] == '.') || (path[j] == ':')) path[j] = '/';
revertSlashIfWIN32(path, 0);
if((directoryPointer = opendir(path)) != NULL) {
if(debug) traceEvent(CONST_TRACE_INFO, "RRD: Found %s", path);
while((dp = readdir(directoryPointer)) != NULL) {
if((dp->d_name[0] == '.') /* || (!strstr(dp->d_name, "Sent")) */)
continue;
else {
int duplicated = 0;
found = 1;
for(k=0; k<num_rrds; k++)
if(!strcmp(keys[k], dp->d_name)) {
duplicated = 1;
break;
}
if((!duplicated) && (num_rrds < (MAX_NUM_RRDS-1)))
keys[num_rrds++] = strdup(dp->d_name);
}
}
closedir(directoryPointer);
} else
if(debug) traceEvent(CONST_TRACE_INFO, "RRD: NOT found %s", path);
}
}
qsort(keys, num_rrds, sizeof(char*), cmpStrings);
sendString("<table border=0>\n");
for(k=0; k<num_rrds; k++) {
sendString("\n<!-- XXX -->\n");
if(strstr(keys[k], "Rcvd")) {
if((k > 0) && strstr(keys[k-1], "Rcvd"))
sendString("<td colspan=3> <td></tr>\n");
sendString("<tr><td>");
} else if(strstr(keys[k], "Sent")) {
if((k > 0) && strstr(keys[k-1], "Sent"))
sendString("<tr><td colspan=3> <td>");
else
sendString("<td>");
}
if(0)
sendString("Image</td><td>Link");
else
expandRRDList(keys[k], localNetworks, numLocalNetworks, startTime, endTime);
if(strstr(keys[k], "Rcvd"))
sendString("</td>");
else if(strstr(keys[k], "Sent"))
sendString("</td></tr>\n");
}
sendString("</table>");
if(!found) {
sendString("<tr><td>");
printFlagedWarning("<I>No data (yet) for this cluster</I>");
sendString("</td></tr>");
}
}
sendString("</TABLE>\n</CENTER>");
/*
sendString("<br><b>NOTE: total and average values are NOT absolute but "
"calculated on the specified time interval.</b>\n");
*/
printHTMLtrailer();
}
/* ******************************************* */
static int endsWith(char* label, char* pattern) {
int lenLabel, lenPattern;
lenLabel = strlen(label);
lenPattern = strlen(pattern);
if(lenPattern >= lenLabel)
return(0);
else
return(!strcmp(&label[lenLabel-lenPattern], pattern));
}
/* ************************ */
static void sendGraphFile(char* fileName, int doNotUnlink) {
FILE *fd;
int len;
char tmpStr[256];
int bufSize=sizeof(tmpStr)-1, totLen = 0;
memset(&tmpStr, 0, sizeof(tmpStr));
if((fd = fopen(fileName, "rb")) != NULL) {
for(;;) {
len = fread(tmpStr, sizeof(char), bufSize, fd);
if(len > 0) {
sendStringLen(tmpStr, len);
totLen += len;
}
if(len <= 0) break;
}
fclose(fd);
} else
traceEvent(CONST_TRACE_WARNING, "Unable to open file %s - graphic not sent", fileName);
if (doNotUnlink == 0) {
unlink(fileName);
}
}
/* ******************************* */
static char* sanitizeRrdPath(char *in_path) {
#ifdef WIN32
if(in_path[1] == ':') {
char *tmpStr;
tmpStr = (char*)malloc(strlen(in_path)+2);
if(tmpStr) {
tmpStr[0] = in_path[0];
tmpStr[1] = '\\';
strcpy(&tmpStr[2], &in_path[1]);
strcpy(in_path, tmpStr);
free(tmpStr);
}
}
#endif
return(in_path);
}
/* ******************************************* */
static int graphCounter(char *rrdPath, char *rrdName, char *rrdTitle, char *rrdCounter,
char *startTime, char* endTime, char *rrdPrefix) {
char path[512], *argv[64], buf[384], buf1[384], buf2[384], fname[384], *label, tmpStr[32];
char bufa1[384], bufa2[384], bufa3[384], show_trend = 1;
struct stat statbuf;
int argc = 0, rc, x, y;
double ymin,ymax;
#ifdef DEBUG
traceEvent(CONST_TRACE_INFO, "graphCounter(%s, %s, %s, %s, %s, %s...)",
rrdPath, rrdName, rrdTitle, rrdCounter, startTime, endTime);
#endif
memset(&buf, 0, sizeof(buf));
memset(&buf1, 0, sizeof(buf1));
memset(&buf2, 0, sizeof(buf2));
memset(&bufa1, 0, sizeof(bufa1));
memset(&bufa2, 0, sizeof(bufa2));
memset(&bufa3, 0, sizeof(bufa3));
if(strstr(rrdName, "AS"))
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s/AS/%s.rrd", myGlobals.rrdPath, rrdPath, rrdName);
else {
if(!strcmp(rrdName, "throughput")) {
#ifdef WIN32
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%u/%s%s.rrd", myGlobals.spoolPath, driveSerial, rrdPath, rrdName);
#else
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s%s.rrd", myGlobals.spoolPath, rrdPath, rrdName);
#endif
} else
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s%s.rrd", myGlobals.rrdPath, rrdPath, rrdName);
}
/* startTime[4] skips the 'now-' */
safe_snprintf(__FILE__, __LINE__, fname, sizeof(fname), "%s/%s/%s-%s%s%s",
myGlobals.rrdPath, rrd_subdirs[0], startTime, rrdPrefix, rrdName,
CHART_FORMAT);
revertSlashIfWIN32(path, 0);
revertSlashIfWIN32(fname, 0);
if(endsWith(rrdName, "Bytes")) label = "Bytes/s";
else if(endsWith(rrdName, "Pkts")) label = "Pkt/s";
else label = capitalizeInitial(rrdName);
if((!strcmp(endTime, "now"))
&& (!strcmp(startTime, "now-600s")))
show_trend = 0;
rrdGraphicRequests++;
if(stat(path, &statbuf) == 0) {
char metric_name[32];
if(isdigit(startTime[0]) && isdigit(endTime[0])) {
unsigned long _startTime, _endTime;
_startTime = atol(startTime);
_endTime = atol(endTime);
if(_startTime >= _endTime) {
char *tmp = startTime;
startTime = endTime;
endTime = tmp;
}
}
argv[argc++] = "rrd_graph";
argv[argc++] = fname;
argv[argc++] = "--lazy";
argv[argc++] = "--imgformat";
argv[argc++] = "PNG";
argv[argc++] = "--vertical-label";
argv[argc++] = label;
if((rrdTitle != NULL) && (rrdTitle[0] != '\0')) {
argv[argc++] = "--title";
argv[argc++] = rrdTitle;
}
argv[argc++] = "--start";
argv[argc++] = startTime;
argv[argc++] = "--end";
argv[argc++] = endTime;
argv[argc++] = "--slope-mode";
/* ********************* */
argv[argc++] = "--rigid";
argv[argc++] = "--base";
argv[argc++] = "1024";
argv[argc++] = "--height";
argv[argc++] = "120";
argv[argc++] = "--width";
argv[argc++] = "500";
argv[argc++] = "--alt-autoscale-max";
argv[argc++] = "--lower-limit";
argv[argc++] = "0";
/* ********************* */
#ifdef CONST_RRD_DEFAULT_FONT_NAME
argv[argc++] = "--font";
#ifdef CONST_RRD_DEFAULT_FONT_PATH
argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" \
CONST_RRD_DEFAULT_FONT_PATH CONST_RRD_DEFAULT_FONT_NAME;
#else
argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" CONST_RRD_DEFAULT_FONT_NAME;
#endif
#endif
revertDoubleColumnIfWIN32(path);
sanitizeRrdPath(path);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "DEF:ctr=%s:counter:AVERAGE", path);
argv[argc++] = buf;
safe_snprintf(__FILE__, __LINE__, buf1, sizeof(buf1), "AREA:ctr#00a000:%s",
spacer(capitalizeInitial(rrdCounter), tmpStr, sizeof(tmpStr),
metric_name, sizeof(metric_name)));
argv[argc++] = buf1;
if(show_trend) argv[argc++] = "CDEF:smoothed=ctr,1800,TREND";
argv[argc++] = "GPRINT:ctr:MIN:Min\\: %3.1lf%s";
argv[argc++] = "GPRINT:ctr:MAX:Max\\: %3.1lf%s";
argv[argc++] = "GPRINT:ctr:AVERAGE:Avg\\: %3.1lf%s";
argv[argc++] = "GPRINT:ctr:LAST:Last\\: %3.1lf%s\\n";
safe_snprintf(__FILE__, __LINE__, bufa1, sizeof(bufa1), "DEF:pred=%s:counter:HWPREDICT", path);
argv[argc++] = bufa1;
safe_snprintf(__FILE__, __LINE__, bufa2, sizeof(bufa2), "DEF:dev=%s:counter:DEVPREDICT", path);
argv[argc++] = bufa2;
safe_snprintf(__FILE__, __LINE__, bufa3, sizeof(bufa3), "DEF:fail=%s:counter:FAILURES", path);
argv[argc++] = bufa3;
if(enableAberrant) {
argv[argc++] = "TICK:fail#ffffa0:1.0:Anomalia";
argv[argc++] = "CDEF:upper=pred,dev,2,*,+";
argv[argc++] = "CDEF:lower=pred,dev,2,*,-";
argv[argc++] = "LINE1:upper#ff0000:Upper";
argv[argc++] = "LINE2:lower#a0ffff:Lower";
}
if(show_trend) argv[argc++] = "LINE1:smoothed#0000FF:Trend (30 min)";
accessMutex(&rrdMutex, "rrd_graph");
optind=0; /* reset gnu getopt */
opterr=0; /* no error messages */
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
rrd_clear_error();
addRrdDelay();
rc = rrd_graph(argc, argv, &calcpr, &x, &y, NULL, &ymin, &ymax);
calfree();
if(rc == 0) {
sendHTTPHeader(FLAG_HTTP_TYPE_PNG, 0, 1);
sendGraphFile(fname, 0);
unlink(fname);
} else {
traceEventRRDebugARGV(0);
if(++graphErrCount < 50) {
traceEvent(CONST_TRACE_ERROR, "RRD: rrd_graph() call failed, rc %d, %s",
rc, rrd_get_error() ? rrd_get_error() : "");
traceEvent(CONST_TRACE_INFO, "RRD: Failing file in graphCounter() is %s", path);
}
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("RRD Graph", NULL, 0);
safe_snprintf(__FILE__, __LINE__, path, sizeof(path),
"<I>Error while building graph of the requested file. %s</I>",
rrd_get_error() ? rrd_get_error() : "");
printFlagedWarning(path);
rrd_clear_error();
}
releaseMutex(&rrdMutex);
} else {
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("RRD Graph", NULL, 0);
printFlagedWarning("<I>Error while building graph of the requested file "
"(unknown RRD file)</I>");
rc = -1;
}
return(rc);
}
/* ******************************************* */
#define MAX_NUM_ENTRIES 32
#define MAX_BUF_LEN 128
#undef option_timespan
#define option_timespan(theStartTime, theLabel, selected) \
safe_snprintf(__FILE__, __LINE__, strbuf, sizeof(strbuf), \
"<option value=\"/" CONST_PLUGINS_HEADER "%s?action=netflowIfSummary" \
"&key=%s" \
"&graphId=%d" \
"&start=%u" \
"&end=%u" \
"&mode=zoom&name=%s\" %s>%s</option>\n", \
"rrdPlugin", rrdInterface, graphId, (unsigned int)theStartTime, (unsigned int)the_time, \
_rrdName, (selected == 1) ? "selected" : "", theLabel); sendString(strbuf);
/* ****************************** */
static void netflowSummary(char *rrdPath, int graphId, char *startTime, char* endTime, char *rrdPrefix, char *mode) {
char path[512], *argv[3*MAX_NUM_ENTRIES], buf[MAX_NUM_ENTRIES][MAX_BUF_LEN];
char buf1[MAX_NUM_ENTRIES][MAX_BUF_LEN], tmpStr[32],
buf2[MAX_NUM_ENTRIES][MAX_BUF_LEN], buf3[MAX_NUM_ENTRIES][MAX_BUF_LEN];
char fname[384], *label, _rrdName[256];
char **rrds = NULL;
int argc = 0, rc, x, y, i, entryId=0;
double ymin, ymax;
path[0] = '\0';
switch(graphId) {
case 0: rrds = (char**)rrd_summary_new_flows; label = "Flows"; break;
case 1: rrds = (char**)rrd_summary_new_nf_flows; label = "Flows"; break;
case 2: rrds = (char**)rrd_summary_new_nf_flows_size; label = "Bytes"; break;
}
/* startTime[4] skips the 'now-' */
safe_snprintf(__FILE__, __LINE__, fname, sizeof(fname), "%s/%s/%s-%s%d%s",
myGlobals.rrdPath, rrd_subdirs[0],
startTime, rrdPrefix, graphId,
CHART_FORMAT);
safe_snprintf(__FILE__, __LINE__, _rrdName, sizeof(_rrdName), "%s", rrdPath);
if(!strcmp(mode, "zoom")) {
char strbuf[LEN_GENERAL_WORK_BUFFER];
time_t the_time = time(NULL);
char *rrdInterface = rrdPath;
struct tm *the_tm;
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("" /* "Arbitrary Graph URL" */, NULL, 0);
sendString("<center>\n");
/* *************************************** */
/*
Graph time and zoom: code courtesy of
the Cacti (http://www.cacti.net) project.
*/
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/calendar.js\"></SCRIPT>\n");
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/lang/calendar-en.js\"></SCRIPT>\n");
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/calendar-setup.js\"></script>\n");
sendString("<SCRIPT type\"text/javascript\" src=\"/jscalendar/calendar-load.js\"></script>\n");
sendString("\n<p align=center>\n<FORM action=/plugins/rrdPlugin name=\"form_timespan_selector\" method=\"get\">\n"
"<TABLE width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">\n<TBODY><TR><TD align=center class=\"textHeader\" nowrap=\"\">\n"
"<b>Presets</b>: <SELECT name=\"predefined_timespan\" onchange=\"window.location=document.form_timespan_selector."
"predefined_timespan.options[document.form_timespan_selector.predefined_timespan.selectedIndex].value\">\n");
option_timespan(the_time-12*3600, "-----", 1);
option_timespan(the_time-1800, "Last Half Hour", 0);
option_timespan(the_time-3600, "Last Hour", 0);
option_timespan(the_time-2*3600, "Last 2 Hours", 0);
option_timespan(the_time-4*3600, "Last 4 Hours", 0);
option_timespan(the_time-6*3600, "Last 6 Hours", 0);
option_timespan(the_time-12*3600, "Last 12 Hours", 0);
option_timespan(the_time-86400, "Last Day", 0);
option_timespan(the_time-2*86400, "Last 2 Days", 0);
option_timespan(the_time-4*86400, "Last 4 Days", 0);
option_timespan(the_time-7*86400, "Last Week", 0);
option_timespan(the_time-30*86400, "Last Month", 0);
option_timespan(the_time-2*30*86400, "Last 2 Months", 0);
option_timespan(the_time-4*30*86400, "Last 4 Months", 0);
option_timespan(the_time-6*30*86400, "Last 6 Months", 0);
option_timespan(the_time-12*30*86400, "Last Year", 0);
sendString("</select>\n");
safe_snprintf(__FILE__, __LINE__, strbuf, sizeof(strbuf),
"<input type=hidden name=action value=netflowIfSummary>\n"
"<input type=hidden name=graphId value=\"%d\">\n"
"<input type=hidden name=key value=\"%s\">\n"
"<input type=hidden name=name value=\"%s\">\n"
"<input type=hidden name=start value=\"%s\">\n"
"<input type=hidden name=end value=\"%s\">\n"
"<input type=hidden name=mode value=\"zoom\">\n",
graphId, _rrdName, rrdInterface, startTime, endTime);
sendString(strbuf);
sendString(" <STRONG>From:</STRONG>\n<INPUT type=\"text\" name=\"date1\" id=\"date1\" size=\"16\" value=\"");
the_time = atol(startTime); the_tm = localtime(&the_time);
strftime(strbuf, sizeof(strbuf), "%Y-%m-%d %H:%M", the_tm); sendString(strbuf);
sendString("\">\n<INPUT type=\"image\" src=\"/calendar.gif\" alt=\"Start date selector\" border=\"0\" align=\"absmiddle\" onclick=\"return showCalendar('date1');\">\n");
sendString(" <strong>To:</strong>\n<INPUT type=\"text\" name=\"date2\" id=\"date2\" size=\"16\" value=\"");
the_time = atol(endTime); the_tm = localtime(&the_time);
strftime(strbuf, sizeof(strbuf), "%Y-%m-%d %H:%M", the_tm); sendString(strbuf);
sendString("\">\n<INPUT type=\"image\" src=\"/calendar.gif\" alt=\"End date selector\" border=\"0\" align=\"absmiddle\" onclick=\"return showCalendar('date2');\">\n"
"<INPUT type=\"submit\" value=\"Update Graph\">\n</FORM>\n</TD></TR></TBODY></TABLE>\n</p>\n");
/* *************************************** */
sendString("<SCRIPT type=\"text/javascript\" src=\"/zoom.js\"></SCRIPT>\n"
"<DIV id=\"zoomBox\" style=\"position: absolute; visibility: visible; background-image: initial; background-repeat: initial; "
"background-attachment: initial; background-position-x: initial; background-position-y: initial; background-color: orange; opacity: 0.5;\"></DIV>\n");
sendString("<DIV id=\"zoomSensitiveZone\" style=\"position:absolute; overflow:none; background-repeat: initial; background-attachment: initial; "
"background-position-x: initial; background-position-y: initial; visibility:visible; cursor:crosshair; background:blue; "
"filter:alpha(opacity=0); -moz-opacity:0; -khtml-opacity:0; opacity:0;\" oncontextmenu=\"return false\"></DIV>\n");
/*
NOTE:
If the graph size changes, please update the zoom.js file (search for L.Deri)
*/
safe_snprintf(__FILE__, __LINE__, strbuf, sizeof(strbuf),
"<img id=zoomGraphImage src=\"/" CONST_PLUGINS_HEADER "%s?action=netflowIfSummary"
"&graphId=%d"
"&key=%s"
"&name=%s"
"&start=%s"
"&end=%s"
"\" alt=\"graph image\" border=0></center>\n",
rrdPluginInfo->pluginURLname,
graphId,
rrdInterface, _rrdName,
startTime,
endTime);
sendString(strbuf);
sendString("\n<SCRIPT type=\"text/javascript\">\n\nvar cURLBase = \"/plugins/rrdPlugin?mode=zoom\";\n\n"
"// Global variables\nvar gZoomGraphName = \"zoomGraphImage\";\n"
"var gZoomGraphObj;\nvar gMouseObj;\nvar gUrlObj;\nvar gBrowserObj;\nvar gGraphWidth;\n"
"var gGraphHeight;\n\n\nwindow.onload = initBonsai;\n\n</SCRIPT>\n");
sendString("</center>\n");
printHTMLtrailer();
return;
}
revertSlashIfWIN32(fname, 0);
if(rrds == NULL) {
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("RRD Graph Summary", NULL, 0);
printFlagedWarning("<I>Error while building graph of the requested file "
"(unknown RRD files)</I>");
return;
}
rrdGraphicRequests++;
if(isdigit(startTime[0]) && isdigit(endTime[0])) {
unsigned long _startTime, _endTime;
_startTime = atol(startTime);
_endTime = atol(endTime);
if(_startTime >= _endTime) {
char *tmp = startTime;
startTime = endTime;
endTime = tmp;
}
}
argv[argc++] = "rrd_graph";
argv[argc++] = fname;
argv[argc++] = "--lazy";
argv[argc++] = "--imgformat";
argv[argc++] = "PNG";
argv[argc++] = "--vertical-label";
argv[argc++] = label;
argv[argc++] = "--start";
argv[argc++] = startTime;
argv[argc++] = "--end";
argv[argc++] = endTime;
argv[argc++] = "--slope-mode";
#ifdef CONST_RRD_DEFAULT_FONT_NAME
argv[argc++] = "--font";
#ifdef CONST_RRD_DEFAULT_FONT_PATH
argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" \
CONST_RRD_DEFAULT_FONT_PATH CONST_RRD_DEFAULT_FONT_NAME;
#else
argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" CONST_RRD_DEFAULT_FONT_NAME;
#endif
#endif
revertDoubleColumnIfWIN32(path);
for(i=0, entryId=0; rrds[i] != NULL; i++) {
struct stat statbuf;
if(!strcmp(rrds[i], "throughput")) {
#ifdef WIN32
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%u/%s%s.rrd", myGlobals.spoolPath, driveSerial, rrdPath, rrds[i]);
#else
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s%s.rrd", myGlobals.spoolPath, rrdPath, rrds[i]);
#endif
} else
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s%s.rrd", myGlobals.rrdPath, rrdPath, rrds[i]);
revertSlashIfWIN32(path, 0);
if(stat(path, &statbuf) == 0) {
char metric_name[32];
safe_snprintf(__FILE__, __LINE__, buf[entryId], MAX_BUF_LEN, "DEF:ctr%d=%s:counter:AVERAGE", entryId, path);
argv[argc++] = buf[entryId];
safe_snprintf(__FILE__, __LINE__, buf1[entryId], MAX_BUF_LEN, "%s:ctr%d%s:%s", entryId == 0 ? "AREA" : "STACK",
entryId, rrd_colors[entryId], spacer(&rrds[i][3], tmpStr, sizeof(tmpStr), metric_name, sizeof(metric_name)));
argv[argc++] = buf1[entryId];
safe_snprintf(__FILE__, __LINE__, buf2[entryId], MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":AVERAGE:Avg\\: %3.1lf%s\\t");
argv[argc++] = buf2[entryId];
safe_snprintf(__FILE__, __LINE__, buf3[entryId], MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":LAST:Last\\: %3.1lf%s\\n");
argv[argc++] = buf3[entryId];
entryId++;
} else {
// traceEvent(CONST_TRACE_WARNING, "RRD: Unable to find file %s", path);
}
if(entryId >= MAX_NUM_ENTRIES) break;
if(entryId >= CONST_NUM_BAR_COLORS) {
if(colorWarn == 0) {
traceEvent(CONST_TRACE_WARNING, "RRD: Number of defined bar colors less than max entries. Some graph(s) truncated");
colorWarn = 1;
}
break;
}
}
accessMutex(&rrdMutex, "rrd_graph");
optind=0; /* reset gnu getopt */
opterr=0; /* no error messages */
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
rrd_clear_error();
addRrdDelay();
rc = rrd_graph(argc, argv, &calcpr, &x, &y, NULL, &ymin, &ymax);
calfree();
if(rc == 0) {
sendHTTPHeader(FLAG_HTTP_TYPE_PNG, 0, 1);
sendGraphFile(fname, 0);
unlink(fname);
} else {
traceEventRRDebugARGV(3);
if(++graphErrCount < 50) {
traceEvent(CONST_TRACE_ERROR, "RRD: rrd_graph() call failed, rc %d, %s", rc, rrd_get_error() ? rrd_get_error() : "");
traceEvent(CONST_TRACE_INFO, "RRD: Failing file in netflowSummary() is %s", path);
}
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("RRD Graph Summary", NULL, 0);
safe_snprintf(__FILE__, __LINE__, path, sizeof(path),
"<I>Error while building graph of the requested file. %s</I>",
rrd_get_error() ? rrd_get_error() : "");
printFlagedWarning(path);
rrd_clear_error();
}
releaseMutex(&rrdMutex);
}
/* ******************************************* */
#define MAX_NUM_ENTRIES 32
#define MAX_BUF_LEN 128
#undef option_timespan
#define option_timespan(theStartTime, theLabel, selected) \
safe_snprintf(__FILE__, __LINE__, strbuf, sizeof(strbuf), \
"<option value=\"/" CONST_PLUGINS_HEADER "%s?action=netflowIfSummary" \
"&key=%s" \
"&graphId=%d" \
"&start=%u" \
"&end=%u" \
"&mode=zoom&name=%s\" %s>%s</option>\n", \
"rrdPlugin", rrdInterface, graphId, (unsigned int)theStartTime, (unsigned int)the_time, \
_rrdName, (selected == 1) ? "selected" : "", theLabel); sendString(strbuf);
static void interfaceSummary(char *rrdPath, int graphId, char *startTime, char* endTime, char *rrdPrefix, char *mode) {
char path[512], *argv[3*MAX_NUM_ENTRIES], buf[MAX_NUM_ENTRIES][MAX_BUF_LEN], buf0[MAX_NUM_ENTRIES][MAX_BUF_LEN];
char buf1[MAX_NUM_ENTRIES][MAX_BUF_LEN], tmpStr[32], metric_name[32],
buf2[MAX_NUM_ENTRIES][MAX_BUF_LEN], buf3[MAX_NUM_ENTRIES][MAX_BUF_LEN], buf4[MAX_NUM_ENTRIES][MAX_BUF_LEN];
char fname[384], *label, title[64], _rrdName[256];
char **rrds = NULL;
int argc = 0, rc, x, y, i, entryId=0;
double ymin, ymax;
path[0] = '\0';
safe_snprintf(__FILE__, __LINE__, _rrdName, sizeof(_rrdName), "%s", rrdPath);
switch(graphId) {
case 0: rrds = (char**)rrd_summary_nf_if_octets; label = "Bit/s"; break;
default: rrds = (char**)rrd_summary_nf_if_pkts; label = "Pkt/s"; break;
}
traceEvent(CONST_TRACE_WARNING, "-- 0 --> (%s)", "Hello");
if(!strcmp(mode, "zoom")) {
char strbuf[LEN_GENERAL_WORK_BUFFER];
time_t the_time = time(NULL);
char *rrdInterface = rrdPath;
struct tm *the_tm;
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("" /* "Arbitrary Graph URL" */, NULL, 0);
sendString("<center>\n");
/* *************************************** */
/*
Graph time and zoom: code courtesy of
the Cacti (http://www.cacti.net) project.
*/
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/calendar.js\"></SCRIPT>\n");
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/lang/calendar-en.js\"></SCRIPT>\n");
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/calendar-setup.js\"></script>\n");
sendString("<SCRIPT type\"text/javascript\" src=\"/jscalendar/calendar-load.js\"></script>\n");
sendString("\n<p align=center>\n<FORM action=/plugins/rrdPlugin name=\"form_timespan_selector\" method=\"get\">\n<TABLE width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">\n<TBODY><TR><TD align=center class=\"textHeader\" nowrap=\"\">\n<b>Presets</b>: <SELECT name=\"predefined_timespan\" onchange=\"window.location=document.form_timespan_selector.predefined_timespan.options[document.form_timespan_selector.predefined_timespan.selectedIndex].value\">\n");
option_timespan(the_time-12*3600, "-----", 1);
option_timespan(the_time-1800, "Last Half Hour", 0);
option_timespan(the_time-3600, "Last Hour", 0);
option_timespan(the_time-2*3600, "Last 2 Hours", 0);
option_timespan(the_time-4*3600, "Last 4 Hours", 0);
option_timespan(the_time-6*3600, "Last 6 Hours", 0);
option_timespan(the_time-12*3600, "Last 12 Hours", 0);
option_timespan(the_time-86400, "Last Day", 0);
option_timespan(the_time-2*86400, "Last 2 Days", 0);
option_timespan(the_time-4*86400, "Last 4 Days", 0);
option_timespan(the_time-7*86400, "Last Week", 0);
option_timespan(the_time-30*86400, "Last Month", 0);
option_timespan(the_time-2*30*86400, "Last 2 Months", 0);
option_timespan(the_time-4*30*86400, "Last 4 Months", 0);
option_timespan(the_time-6*30*86400, "Last 6 Months", 0);
option_timespan(the_time-12*30*86400, "Last Year", 0);
sendString("</select>\n");
safe_snprintf(__FILE__, __LINE__, strbuf, sizeof(strbuf),
"<input type=hidden name=action value=netflowIfSummary>\n"
"<input type=hidden name=graphId value=\"%d\">\n"
"<input type=hidden name=key value=\"%s\">\n"
"<input type=hidden name=name value=\"%s\">\n"
"<input type=hidden name=start value=\"%s\">\n"
"<input type=hidden name=end value=\"%s\">\n"
"<input type=hidden name=mode value=\"zoom\">\n",
graphId, _rrdName, rrdInterface, startTime, endTime);
sendString(strbuf);
sendString(" <STRONG>From:</STRONG>\n<INPUT type=\"text\" name=\"date1\" id=\"date1\" size=\"16\" value=\"");
the_time = atol(startTime); the_tm = localtime(&the_time);
strftime(strbuf, sizeof(strbuf), "%Y-%m-%d %H:%M", the_tm); sendString(strbuf);
sendString("\">\n<INPUT type=\"image\" src=\"/calendar.gif\" alt=\"Start date selector\" border=\"0\" align=\"absmiddle\" onclick=\"return showCalendar('date1');\">\n");
sendString(" <strong>To:</strong>\n<INPUT type=\"text\" name=\"date2\" id=\"date2\" size=\"16\" value=\"");
the_time = atol(endTime); the_tm = localtime(&the_time);
strftime(strbuf, sizeof(strbuf), "%Y-%m-%d %H:%M", the_tm); sendString(strbuf);
sendString("\">\n<INPUT type=\"image\" src=\"/calendar.gif\" alt=\"End date selector\" border=\"0\" align=\"absmiddle\" onclick=\"return showCalendar('date2');\">\n"
"<INPUT type=\"submit\" value=\"Update Graph\">\n</FORM>\n</TD></TR></TBODY></TABLE>\n</p>\n");
/* *************************************** */
sendString("<SCRIPT type=\"text/javascript\" src=\"/zoom.js\"></SCRIPT>\n"
"<DIV id=\"zoomBox\" style=\"position: absolute; visibility: visible; background-image: initial; background-repeat: initial; "
"background-attachment: initial; background-position-x: initial; background-position-y: initial; background-color: orange; opacity: 0.5;\"></DIV>\n");
sendString("<DIV id=\"zoomSensitiveZone\" style=\"position:absolute; overflow:none; background-repeat: initial; "
"background-attachment: initial; background-position-x: initial; background-position-y: initial; visibility:visible; "
"cursor:crosshair; background:blue; filter:alpha(opacity=0); -moz-opacity:0; -khtml-opacity:0; opacity:0;"
"\" oncontextmenu=\"return false\"></DIV>\n");
/*
NOTE:
If the graph size changes, please update the zoom.js file (search for L.Deri)
*/
safe_snprintf(__FILE__, __LINE__, strbuf, sizeof(strbuf),
"<img id=zoomGraphImage src=\"/" CONST_PLUGINS_HEADER "%s?action=netflowSummary"
"&graphId=%d"
"&key=%s"
"&name=%s"
"&start=%s"
"&end=%s"
"\" alt=\"graph image\" border=0></center>\n",
rrdPluginInfo->pluginURLname,
graphId,
rrdInterface, _rrdName,
startTime,
endTime);
sendString(strbuf);
sendString("\n<SCRIPT type=\"text/javascript\">\n\nvar cURLBase = \"/plugins/rrdPlugin?mode=zoom\";\n\n"
"// Global variables\nvar gZoomGraphName = \"zoomGraphImage\";\n"
"var gZoomGraphObj;\nvar gMouseObj;\nvar gUrlObj;\nvar gBrowserObj;\nvar gGraphWidth;\n"
"var gGraphHeight;\n\n\nwindow.onload = initBonsai;\n\n</SCRIPT>\n");
sendString("</center>\n");
printHTMLtrailer();
return;
}
/* startTime[4] skips the 'now-' */
safe_snprintf(__FILE__, __LINE__, fname, sizeof(fname), "%s/%s/%s/%s-%s%d%s",
myGlobals.rrdPath, rrd_subdirs[2], rrdPath,
startTime, rrdPrefix, graphId,
CHART_FORMAT);
revertSlashIfWIN32(fname, 0);
if(rrds == NULL) {
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("RRD Graph Summary", NULL, 0);
printFlagedWarning("<I>Error while building graph of the requested file "
"(unknown RRD files)</I>");
return;
}
for(i=strlen(rrdPath)-1; i>0; i--)
if(rrdPath[i] == '/')
break;
if(strstr(rrdPath, "/AS/"))
safe_snprintf(__FILE__, __LINE__, title, sizeof(title),
"AS %s", &rrdPath[i+1]);
else
safe_snprintf(__FILE__, __LINE__, title, sizeof(title),
"NetFlow Interface %s", &rrdPath[i+1]);
rrdGraphicRequests++;
if(isdigit(startTime[0]) && isdigit(endTime[0])) {
unsigned long _startTime, _endTime;
_startTime = atol(startTime);
_endTime = atol(endTime);
if(_startTime >= _endTime) {
char *tmp = startTime;
startTime = endTime;
endTime = tmp;
}
}
argv[argc++] = "rrd_graph";
argv[argc++] = fname;
argv[argc++] = "--lazy";
argv[argc++] = "--imgformat";
argv[argc++] = "PNG";
argv[argc++] = "--vertical-label";
argv[argc++] = label;
argv[argc++] = "--title";
argv[argc++] = title;
argv[argc++] = "--start";
argv[argc++] = startTime;
argv[argc++] = "--end";
argv[argc++] = endTime;
argv[argc++] = "--slope-mode";
argv[argc++] = "--width";
argv[argc++] = "500";
argv[argc++] = "--height";
argv[argc++] = "120";
argv[argc++] = "--alt-autoscale-max";
argv[argc++] = "--lower-limit";
argv[argc++] = "0";
#ifdef CONST_RRD_DEFAULT_FONT_NAME
argv[argc++] = "--font";
#ifdef CONST_RRD_DEFAULT_FONT_PATH
argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" \
CONST_RRD_DEFAULT_FONT_PATH CONST_RRD_DEFAULT_FONT_NAME;
#else
argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" CONST_RRD_DEFAULT_FONT_NAME;
#endif
#endif
for(i=0, entryId=0; rrds[i] != NULL; i++) {
struct stat statbuf;
if(!strcmp(rrds[i], "throughput")) {
#ifdef WIN32
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%u/%s/%s/%s.rrd",
myGlobals.spoolPath, driveSerial, rrd_subdirs[2], rrdPath, rrds[i]);
#else
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s/%s/%s.rrd",
myGlobals.spoolPath, rrd_subdirs[2], rrdPath, rrds[i]);
#endif
} else
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s/%s/%s.rrd",
myGlobals.rrdPath, rrd_subdirs[2], rrdPath, rrds[i]);
revertSlashIfWIN32(path, 0);
if(stat(path, &statbuf) == 0) {
safe_snprintf(__FILE__, __LINE__, buf[entryId], MAX_BUF_LEN, "DEF:bctr%d=%s:counter:AVERAGE", entryId, path);
argv[argc++] = buf[entryId];
safe_snprintf(__FILE__, __LINE__, buf0[entryId], MAX_BUF_LEN, "CDEF:ctr%d=bctr%d,8,*", entryId, entryId);
argv[argc++] = buf0[entryId];
safe_snprintf(__FILE__, __LINE__, buf1[entryId], MAX_BUF_LEN, "%s:ctr%d%s:%s", entryId == 0 ? "AREA" : "STACK",
entryId, rrd_colors[entryId], spacer(&rrds[i][2], tmpStr, sizeof(tmpStr), metric_name, sizeof(metric_name)));
argv[argc++] = buf1[entryId];
safe_snprintf(__FILE__, __LINE__, buf2[entryId], MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":LAST:Last\\: %8.2lf %s");
argv[argc++] = buf2[entryId];
safe_snprintf(__FILE__, __LINE__, buf3[entryId], MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":AVERAGE:Avg\\: %8.2lf %s");
argv[argc++] = buf3[entryId];
safe_snprintf(__FILE__, __LINE__, buf4[entryId], MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":MAX:Max\\: %8.2lf %s\\n");
argv[argc++] = buf4[entryId];
entryId++;
}
if(entryId >= MAX_NUM_ENTRIES) break;
if(entryId >= CONST_NUM_BAR_COLORS) {
if(colorWarn == 0) {
traceEvent(CONST_TRACE_WARNING, "RRD: Number of defined bar colors less than max entries. Some graph(s) truncated");
colorWarn = 1;
}
break;
}
}
/* traceEventRRDebugARGV(0); */
accessMutex(&rrdMutex, "rrd_graph");
optind=0; /* reset gnu getopt */
opterr=0; /* no error messages */
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
rrd_clear_error();
addRrdDelay();
rc = rrd_graph(argc, argv, &calcpr, &x, &y, NULL, &ymin, &ymax);
traceEventRRDebugARGV(3); // FIX
calfree();
if(rc == 0) {
sendHTTPHeader(FLAG_HTTP_TYPE_PNG, 0, 1);
sendGraphFile(fname, 0);
unlink(fname);
} else {
traceEventRRDebugARGV(3);
if(++graphErrCount < 50) {
traceEvent(CONST_TRACE_ERROR, "RRD: rrd_graph() call failed, rc %d, %s", rc, rrd_get_error() ? rrd_get_error() : "");
traceEvent(CONST_TRACE_INFO, "RRD: Failing file in netflowSummary() is %s", path);
}
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("RRD Graph Summary", NULL, 0);
safe_snprintf(__FILE__, __LINE__, path, sizeof(path),
"<I>Error while building graph of the requested file. %s</I>",
rrd_get_error() ? rrd_get_error() : "");
printFlagedWarning(path);
rrd_clear_error();
}
releaseMutex(&rrdMutex);
}
/* ******************************* */
static char* spacer(char* str, char *tmpStr, int tmpStrLen,
char *metric_name, int metric_name_len) {
int len = strlen(str), i;
char *token, *token_name, buf[32], debug = 0, *found, *key;
if((strlen(str) > 3) && (!strncmp(str, "IP_", 3))) str += 3;
if(debug) traceEvent(CONST_TRACE_WARNING, "-- 0 --> (%s)", str);
memset(tmpStr, 0, tmpStrLen);
if((token = strstr(str, "Bytes")) != NULL)
token_name = "Bytes";
else if((token = strstr(str, "Octets")) != NULL)
token_name = "Octets";
else if((token = strstr(str, "Pkts")) != NULL)
token_name = "Pkts";
else if((token = strstr(str, "Flows")) != NULL)
token_name = "Flows";
else if((token = strstr(str, "AS")) != NULL)
token_name = "AS";
else if((token = strstr(str, "Num")) != NULL)
token_name = "Num";
else
token = NULL, token_name = NULL;
if(debug) traceEvent(CONST_TRACE_WARNING, "-- 000 --> (%s)", str);
if(token) {
char add_trailer;
char save_char = token[0];
if(strlen(token_name) == strlen(token)) add_trailer = 0; else add_trailer = 1;
if(debug) traceEvent(CONST_TRACE_WARNING, "-- 11 --> (%s)(%s) [add_trailer=%d]", token, token_name, add_trailer);
if(add_trailer) {
if(debug) traceEvent(CONST_TRACE_WARNING, "-- 1 --> (%s)", str);
token[0] = '\0';
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%s%s", str, &token[strlen(token_name)]);
token[0] = save_char;
} else {
if(debug) traceEvent(CONST_TRACE_WARNING, "-- 2 --> (%s)", str);
len = strlen(str)-strlen(token);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%s", str);
buf[len] = '\0';
}
} else {
if(debug) traceEvent(CONST_TRACE_WARNING, "-- 3 --> (%s)", str);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%s", str);
}
if((found = strstr(buf, "Sent")) != NULL)
key = "Sent";
else if((found = strstr(buf, "Rcvd")) != NULL)
key = "Rcvd";
else if((found = strstr(buf, "Peers")) != NULL)
key = "Peers";
else
found = NULL;
if(found) {
found[0] = ' ';
for(i=1; i<(1+strlen(key)); i++) found[i] = key[i-1];
found[i] = '\0';
}
len = strlen(buf); if(len > 15) len = 15;
snprintf(tmpStr, len+1, "%s", buf);
for(i=len; i<15; i++) tmpStr[i] = ' ';
tmpStr[16] = '\0';
if(debug) traceEvent(CONST_TRACE_WARNING, "-- 4 --> (%s)", tmpStr);
if(token_name)
safe_snprintf(__FILE__, __LINE__, metric_name, metric_name_len, "%s", token_name);
else
memset(metric_name, 0, metric_name_len);
return(tmpStr);
}
/* ******************************* */
static char* formatTitle(char *str, char *buf, u_short buf_len) {
int len, shift = 0;
if(buf_len <= (strlen(str) + 10))
return(str); /* No much space */
if(!strncmp(str, "IP_", 3)) shift = 3;
safe_snprintf(__FILE__, __LINE__, buf, buf_len, "%s", &str[shift]);
len = strlen(buf);
if(!strcmp(&buf[len-7], "LocSent")) {
buf[len-7] = '\0';
strcat(buf, " Sent Locally");
} else if(!strcmp(&buf[len-9], "BytesSent")) {
buf[len-9] = '\0';
strcat(buf, " Sent (Bytes)");
} else if(!strcmp(&buf[len-7], "RemSent")) {
buf[len-7] = '\0';
strcat(buf, " Sent to Remote Hosts");
} else if(!strcmp(&buf[len-4], "Sent")) {
buf[len-4] = '\0';
strcat(buf, " Sent");
} else if(!strcmp(&buf[len-9], "BytesRcvd")) {
buf[len-9] = '\0';
strcat(buf, " Received (Bytes)");
} else if(!strcmp(&buf[len-7], "LocRcvd")) {
buf[len-7] = '\0';
strcat(buf, " Rcvd From Local Hosts");
} else if(!strcmp(&buf[len-11], "FromRemRcvd")) {
buf[len-11] = '\0';
strcat(buf, " Rcvd From Remote Hosts");
} else if(!strcmp(&buf[len-4], "Rcvd")) {
buf[len-4] = '\0';
strcat(buf, " Received");
}
return(buf);
}
/* ****************************** */
#undef option_timespan
#define option_timespan(theStartTime, theLabel, selected) \
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), \
"<option value=\"/" CONST_PLUGINS_HEADER "%s?action=graphSummary" \
"&key=%s" \
"&graphId=%d" \
"&start=%u" \
"&end=%u" \
"&mode=zoom&name=%s\" %s>%s</option>\n", \
"rrdPlugin", rrdInterface, graphId, (unsigned int)theStartTime, (unsigned int)the_time, \
_rrdName, (selected == 1) ? "selected" : "", theLabel); sendString(buf);
/* ******************************* */
#define MAX_NUM_RRD_ENTRIES 3
#define MAX_NUM_RRD_HOSTS 32
static void graphSummary(char *rrdPath, char *rrdName, int graphId,
char *startTime, char* endTime, char *rrdPrefix, char *mode) {
char path[512], *argv[6*MAX_NUM_ENTRIES], tmpStr[32], fname[384], *label, rrdPath_copy[512];
char buf0[MAX_NUM_ENTRIES][2*MAX_BUF_LEN], buf1[MAX_NUM_ENTRIES][2*MAX_BUF_LEN];
char buf3[MAX_NUM_ENTRIES][2*MAX_BUF_LEN];
char buf4[MAX_NUM_ENTRIES][2*MAX_BUF_LEN], buf5[MAX_NUM_ENTRIES][2*MAX_BUF_LEN], _rrdName[256];
char **rrds = NULL, ipRRDs[MAX_NUM_ENTRIES][MAX_BUF_LEN], *myRRDs[MAX_NUM_ENTRIES];
int argc = 0, rc, x, y, i, entryId=0, num_rrd_hosts_path = 0, j;
DIR* directoryPointer;
char *rrd_custom[MAX_NUM_RRD_ENTRIES], *rrd_hosts_path[MAX_NUM_RRD_HOSTS],
*rrd_hosts[MAX_NUM_RRD_HOSTS], file_a[32], file_b[32], title_buf[48];
double ymin,ymax;
i = strlen(rrdPath); if((i > 1) && (rrdPath[i-1] == '/')) rrdPath[i-1] = '\0';
path[0] = '\0', label = "";
safe_snprintf(__FILE__, __LINE__, _rrdName, sizeof(_rrdName), "%s", rrdName);
switch(graphId) {
case 0: rrds = (char**)rrd_summary_packets; label = "Pkt/s"; break;
case 1: rrds = (char**)rrd_summary_packet_sizes; label = "Pkt/s"; break;
case 2: rrds = (char**)rrd_summary_proto_bytes; label = "Bytes/s"; break;
case 3: rrds = (char**)rrd_summary_ipproto_bytes; label = "Bytes/s"; break;
case 4:
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s", myGlobals.rrdPath, rrdPath);
revertSlashIfWIN32(path, 0);
directoryPointer = opendir(path);
if(directoryPointer == NULL)
rrds = NULL;
else {
struct dirent* dp;
i = 0;
while((dp = readdir(directoryPointer)) != NULL) {
int len = strlen(dp->d_name);
if(dp->d_name[0] == '.') continue;
else if(len < 7 /* IP_ + .rrd */ ) continue;
else if(strncmp(dp->d_name, "IP_", 3)) continue;
else if(strstr(dp->d_name, "Flows")) continue;
len -= 4; if(len > MAX_BUF_LEN) len = MAX_BUF_LEN-1;
dp->d_name[len] = '\0';
safe_snprintf(__FILE__, __LINE__, ipRRDs[i], MAX_BUF_LEN, "%s", dp->d_name);
myRRDs[i] = ipRRDs[i];
i++; if(i >= MAX_NUM_ENTRIES) break;
}
myRRDs[i] = NULL;
rrds = (char**)myRRDs;
closedir(directoryPointer);
}
label = "Bytes/s";
break;
case 5: rrds = (char**)rrd_summary_local_remote_ip_bytes; label = "Bytes/s"; break;
case 6: rrds = (char**)rrd_summary_host_sentRcvd_packets; label = "Pkt/s"; break;
case 7: rrds = (char**)rrd_summary_host_sentRcvd_bytes; label = "Bytes/s"; break;
case 98:
{
char *host, *strTokPos;
rrd_custom[0] = rrdName;
rrd_custom[1] = NULL;
rrds = (char**)rrd_custom;
safe_snprintf(__FILE__, __LINE__, rrdPath_copy, sizeof(rrdPath_copy), "%s", rrdPath);
host = strtok_r(rrdPath_copy, ",", &strTokPos);
if(host) {
char tmpPath[64];
while(host != NULL) {
char *strTokPosHost, *the_host, *the_num_host;
if(num_rrd_hosts_path == MAX_NUM_RRD_HOSTS) break;
the_host = strtok_r(host, "@", &strTokPosHost);
the_num_host = strtok_r(NULL, "@", &strTokPosHost);
if((the_num_host == NULL) || (the_num_host[0] == '\0')) the_num_host = "no_name";
rrd_hosts[num_rrd_hosts_path] = strdup(the_num_host);
for(y=0; y<strlen(host); y++) if(host[y] == '.') host[y] = '/';
safe_snprintf(__FILE__, __LINE__, tmpPath, sizeof(tmpPath),
"interfaces/%s/hosts/%s",
myGlobals.device[myGlobals.actualReportDeviceId].uniqueIfName,
the_host);
for(y=strlen(tmpPath)-strlen(the_host); y<strlen(tmpPath); y++)
if((path[y] == '.') || (path[y] == ':')) path[y] = '/';
rrd_hosts_path[num_rrd_hosts_path++] = strdup(tmpPath);
host = strtok_r(NULL, ",", &strTokPos);
}
}
}
break;
case 99:
/* rrdName format can be IP_<proto><Rcvd|Sent><Bytes|Pkts> */
{
char *sent = strstr(rrdName, "Sent");
char *rcvd = strstr(rrdName, "Rcvd");
char *pkts = strstr(rrdName, "Pkts");
if(sent || rcvd) {
if(sent) sent[0] = '\0'; else rcvd[0] = '\0';
snprintf(file_a, sizeof(file_a), "%sSent", rrdName);
snprintf(file_b, sizeof(file_b), "%sRcvd", rrdName);
rrd_custom[0] = file_a;
rrd_custom[1] = file_b;
rrd_custom[2] = NULL;
rrds = (char**)rrd_custom;
/* traceEvent(CONST_TRACE_WARNING, "RRD: [%s][%s]", file_a, file_b); */
} else {
snprintf(file_a, sizeof(file_a), "%s", rrdName);
file_a[strlen(file_a)-strlen(CONST_RRD_EXTENSION)] = '\0';
rrd_custom[0] = file_a;
rrd_custom[1] = NULL;
rrds = (char**)rrd_custom;
/* traceEvent(CONST_TRACE_WARNING, "RRD: Not found [%s]", rrdName); */
}
if(pkts || strstr(rrdName, "pkt"))
label = "Pkt/s";
else if(strstr(rrdName, "Peers"))
label = "Contacted Peers";
else if(strstr(rrdName, "knownHosts"))
label = "Hosts";
else
label = "Bytes/s";
}
break;
}
if(!strcmp(mode, "zoom")) {
char buf[LEN_GENERAL_WORK_BUFFER];
time_t the_time = time(NULL);
char *rrdInterface = rrdPath;
struct tm *the_tm;
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("" /* "Arbitrary Graph URL" */, NULL, 0);
sendString("<center>\n");
/* *************************************** */
/*
Graph time and zoom: code courtesy of
the Cacti (http://www.cacti.net) project.
*/
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/calendar.js\"></SCRIPT>\n");
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/lang/calendar-en.js\"></SCRIPT>\n");
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/calendar-setup.js\"></script>\n");
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/calendar-load.js\"></script>\n");
sendString("\n<p align=center>\n<FORM action=/plugins/rrdPlugin name=\"form_timespan_selector\" method=\"get\">\n<TABLE width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">\n<TBODY><TR><TD align=center class=\"textHeader\" nowrap=\"\">\n<b>Presets</b>: <SELECT name=\"predefined_timespan\" onchange=\"window.location=document.form_timespan_selector.predefined_timespan.options[document.form_timespan_selector.predefined_timespan.selectedIndex].value\">\n");
option_timespan(the_time-12*3600, "-----", 1);
option_timespan(the_time-1800, "Last Half Hour", 0);
option_timespan(the_time-3600, "Last Hour", 0);
option_timespan(the_time-2*3600, "Last 2 Hours", 0);
option_timespan(the_time-4*3600, "Last 4 Hours", 0);
option_timespan(the_time-6*3600, "Last 6 Hours", 0);
option_timespan(the_time-12*3600, "Last 12 Hours", 0);
option_timespan(the_time-86400, "Last Day", 0);
option_timespan(the_time-2*86400, "Last 2 Days", 0);
option_timespan(the_time-4*86400, "Last 4 Days", 0);
option_timespan(the_time-7*86400, "Last Week", 0);
option_timespan(the_time-30*86400, "Last Month", 0);
option_timespan(the_time-2*30*86400, "Last 2 Months", 0);
option_timespan(the_time-4*30*86400, "Last 4 Months", 0);
option_timespan(the_time-6*30*86400, "Last 6 Months", 0);
option_timespan(the_time-12*30*86400, "Last Year", 0);
sendString("</select>\n");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<input type=hidden name=action value=graphSummary>\n"
"<input type=hidden name=key value=\"%s\">\n"
"<input type=hidden name=graphId value=\"%d\">\n"
"<input type=hidden name=name value=\"%s\">\n"
"<input type=hidden name=start value=\"%s\">\n"
"<input type=hidden name=end value=\"%s\">\n"
"<input type=hidden name=mode value=\"zoom\">\n",
rrdInterface, graphId, _rrdName, startTime, endTime);
sendString(buf);
sendString(" <STRONG>From:</STRONG>\n<INPUT type=\"text\" name=\"date1\" id=\"date1\" size=\"16\" value=\"");
the_time = atol(startTime); the_tm = localtime(&the_time);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M", the_tm); sendString(buf);
sendString("\">\n<INPUT type=\"image\" src=\"/calendar.gif\" alt=\"Start date selector\" border=\"0\" "
"align=\"absmiddle\" onclick=\"return showCalendar('date1');\">\n");
sendString(" <strong>To:</strong>\n<INPUT type=\"text\" name=\"date2\" id=\"date2\" size=\"16\" value=\"");
the_time = atol(endTime); the_tm = localtime(&the_time);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M", the_tm); sendString(buf);
sendString("\">\n<INPUT type=\"image\" src=\"/calendar.gif\" alt=\"End date selector\" border=\"0\" "
"align=\"absmiddle\" onclick=\"return showCalendar('date2');\">\n"
"<INPUT type=\"submit\" value=\"Update Graph\">\n</FORM>\n</TD></TR></TBODY></TABLE>\n</p>\n");
/* *************************************** */
sendString("<SCRIPT type=\"text/javascript\" src=\"/zoom.js\"></SCRIPT>\n"
"<DIV id=\"zoomBox\" style=\"position: absolute; visibility: visible; background-image: initial; background-repeat: initial; "
"background-attachment: initial; background-position-x: initial; background-position-y: initial; "
"background-color: orange; opacity: 0.5;\"></DIV>\n");
sendString("<DIV id=\"zoomSensitiveZone\" style=\"position:absolute; overflow:none; background-repeat: initial; background-attachment: initial; background-position-x: initial; background-position-y: initial; visibility:visible; cursor:crosshair; background:blue; filter:alpha(opacity=0); -moz-opacity:0; -khtml-opacity:0; opacity:0;\" oncontextmenu=\"return false\"></DIV>\n");
/*
NOTE:
If the graph size changes, please update the zoom.js file (search for L.Deri)
*/
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<img id=zoomGraphImage src=\"/" CONST_PLUGINS_HEADER "%s?action=graphSummary"
"&graphId=%d"
"&key=%s"
"&name=%s"
"&start=%s"
"&end=%s"
"\" alt=\"graph image\" border=0></center>\n",
rrdPluginInfo->pluginURLname,
graphId,
rrdInterface, _rrdName,
startTime,
endTime);
sendString(buf);
sendString("\n<SCRIPT type=\"text/javascript\">\n\nvar cURLBase = \"/plugins/rrdPlugin?mode=zoom\";\n\n"
"// Global variables\nvar gZoomGraphName = \"zoomGraphImage\";\n"
"var gZoomGraphObj;\nvar gMouseObj;\nvar gUrlObj;\nvar gBrowserObj;\nvar gGraphWidth;\n"
"var gGraphHeight;\n\n\nwindow.onload = initBonsai;\n\n</SCRIPT>\n");
sendString("</center>\n");
printHTMLtrailer();
return;
}
/* startTime[4] skips the 'now-' */
safe_snprintf(__FILE__, __LINE__, fname, sizeof(fname), "%s/%s/%s-%s%d%s",
myGlobals.rrdPath, rrd_subdirs[0],
startTime, rrdPrefix, graphId,
CHART_FORMAT);
revertSlashIfWIN32(fname, 0);
if(rrds == NULL) {
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("RRD Graph Summary", NULL, 0);
printFlagedWarning("<I>Error while building graph of the requested file "
"(unknown RRD files)</I>");
return;
}
if(isdigit(startTime[0]) && isdigit(endTime[0])) {
unsigned long _startTime, _endTime;
_startTime = atol(startTime);
_endTime = atol(endTime);
if(_startTime >= _endTime) {
char *tmp = startTime;
startTime = endTime;
endTime = tmp;
}
}
rrdGraphicRequests++;
argv[argc++] = "rrd_graph";
argv[argc++] = fname;
argv[argc++] = "--lazy";
argv[argc++] = "--imgformat";
argv[argc++] = "PNG";
argv[argc++] = "--vertical-label";
argv[argc++] = label;
argv[argc++] = "--start";
argv[argc++] = startTime;
argv[argc++] = "--end";
argv[argc++] = endTime;
argv[argc++] = "--slope-mode";
if(graphId == 98) {
argv[argc++] = "--title";
argv[argc++] = formatTitle(rrdName, title_buf, sizeof(title_buf));
}
#ifdef CONST_RRD_DEFAULT_FONT_NAME
argv[argc++] = "--font";
#ifdef CONST_RRD_DEFAULT_FONT_PATH
argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" \
CONST_RRD_DEFAULT_FONT_PATH CONST_RRD_DEFAULT_FONT_NAME;
#else
argv[argc++] = "DEFAULT:" CONST_RRD_DEFAULT_FONT_SIZE ":" CONST_RRD_DEFAULT_FONT_NAME;
#endif
#endif
revertDoubleColumnIfWIN32(path);
if(graphId != 98) {
rrd_hosts_path[num_rrd_hosts_path++] = strdup(rrdPath);
}
for(j=0, entryId=0; j<num_rrd_hosts_path; j++) {
for(i=0; rrds[i] != NULL; i++) {
struct stat statbuf;
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s/%s%s",
myGlobals.rrdPath, rrd_hosts_path[j], rrds[i], CONST_RRD_EXTENSION);
revertSlashIfWIN32(path, 0);
/* traceEvent(CONST_TRACE_WARNING, "-- 4 --> (%s) [%d/%d]", path, j, num_rrd_hosts_path); */
if(stat(path, &statbuf) == 0) {
char metric_name[32];
safe_snprintf(__FILE__, __LINE__, buf0[entryId], 2*MAX_BUF_LEN,
"DEF:ctr%d=%s:counter:AVERAGE", entryId, sanitizeRrdPath(path));
argv[argc++] = buf0[entryId];
safe_snprintf(__FILE__, __LINE__, buf1[entryId], 2*MAX_BUF_LEN,
"%s:ctr%d%s:%s", entryId == 0 ? "AREA" : "STACK",
entryId, rrd_colors[entryId],
spacer((graphId == 98) ? rrd_hosts[j] : rrds[i], tmpStr, sizeof(tmpStr),
metric_name, sizeof(metric_name)));
argv[argc++] = buf1[entryId];
/*
safe_snprintf(__FILE__, __LINE__, buf2[entryId], 2*MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":MIN:Min\\: %3.1lf%s");
argv[argc++] = buf2[entryId];
*/
safe_snprintf(__FILE__, __LINE__, buf3[entryId], 2*MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":MAX:Max\\: %3.1lf%s\\t");
argv[argc++] = buf3[entryId];
safe_snprintf(__FILE__, __LINE__, buf4[entryId], 2*MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":AVERAGE:Avg\\: %3.1lf%s\\t");
argv[argc++] = buf4[entryId];
safe_snprintf(__FILE__, __LINE__, buf5[entryId], 2*MAX_BUF_LEN, "GPRINT:ctr%d%s", entryId, ":LAST:Last\\: %3.1lf%s\\n");
argv[argc++] = buf5[entryId];
entryId++;
}
if(entryId >= MAX_NUM_ENTRIES) break;
if(entryId >= CONST_NUM_BAR_COLORS) {
if(colorWarn == 0) {
traceEvent(CONST_TRACE_ERROR,
"RRD: Number of defined bar colors less than max entries. Graphs may be truncated");
colorWarn = 1;
}
break;
}
}
}
accessMutex(&rrdMutex, "rrd_graph");
optind = 0; /* reset gnu getopt */
opterr = 0; /* no error messages */
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
rrd_clear_error();
addRrdDelay();
if(0) {
for(j=0; j<argc; j++)
traceEvent(CONST_TRACE_ERROR, "[%d] '%s'", j, argv[j]);
}
rc = rrd_graph(argc, argv, &calcpr, &x, &y, NULL, &ymin, &ymax);
calfree();
for(i=0; i<num_rrd_hosts_path; i++) {
if(graphId == 98) free(rrd_hosts[i]);
free(rrd_hosts_path[i]);
}
if(rc == 0) {
sendHTTPHeader(FLAG_HTTP_TYPE_PNG, 0, 1);
sendGraphFile(fname, 0);
unlink(fname);
} else {
traceEventRRDebugARGV(3);
if(++graphErrCount < 50) {
traceEvent(CONST_TRACE_ERROR, "RRD: rrd_graph() call failed, rc %d, %s", rc, rrd_get_error() ? rrd_get_error() : "");
traceEvent(CONST_TRACE_INFO, "RRD: Failing file in graphSummary() is %s", path);
}
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("RRD Graph Summary", NULL, 0);
safe_snprintf(__FILE__, __LINE__, path, sizeof(path),
"<I>Error while building graph of the requested file. %s</I>",
rrd_get_error() ? rrd_get_error() : "");
printFlagedWarning(path);
rrd_clear_error();
}
releaseMutex(&rrdMutex);
}
/* ******************************* */
static time_t checkLast(char *rrd) {
time_t lastTime;
char *argv[32];
int argc = 0;
argc = 0;
argv[argc++] = "rrd_last";
argv[argc++] = rrd;
accessMutex(&rrdMutex, "rrd_last");
optind=0; /* reset gnu getopt */
opterr=0; /* no error messages */
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
rrd_clear_error();
addRrdDelay();
lastTime = rrd_last(argc, argv);
releaseMutex(&rrdMutex);
return(lastTime);
}
/* ******************************* */
static void initUdp() {
struct hostent *h;
if(!useDaemon) return;
/* bind any port */
cliAddr.sin_family = AF_INET;
cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
cliAddr.sin_port = htons(0);
/* get server IP address (no check if input is IP address or DNS name */
h = gethostbyname("127.0.0.1");
if(h == NULL) {
traceEvent(CONST_TRACE_WARNING, "RRD: unknown RRD server host\n");
}
remoteServAddr.sin_family = h->h_addrtype;
memcpy((char *) &remoteServAddr.sin_addr.s_addr,
h->h_addr_list[0], h->h_length);
remoteServAddr.sin_port = htons(REMOTE_SERVER_PORT);
/* socket creation */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0) {
traceEvent(CONST_TRACE_WARNING, "RRD: cannot create RRD socket");
useDaemon = 0;
}
}
/* ******************************* */
static void updateUdpParams() {
char buf[512];
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "CFG %d\t%d\t%d\t%d\t%d\t%d",
dumpInterval, dumpShortInterval, dumpHours, dumpDays, dumpMonths, dumpDelay);
sendto(sd, buf, strlen(buf), 0,
(struct sockaddr *)&remoteServAddr,
sizeof(remoteServAddr));
}
/* ******************************* */
static void termUdp() {
if(!useDaemon) return;
if(sd < 0) return;
close(sd);
sd = -1;
}
/* ******************************* */
static void deleteRRD(char *basePath, char *key) {
char path[512];
int i;
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s%s.rrd", basePath, key);
/* Avoid path problems */
for(i=strlen(basePath); i<strlen(path); i++)
if(path[i] == '/') path[i]='_';
revertSlashIfWIN32(path, 0);
if(unlink(path) != 0)
traceEvent(CONST_TRACE_WARNING,
"THREADMGMT[t%lu]: RRD: deleteRRD(%s) failed: %s",
pthread_self(), path, strerror(errno));
}
/* ******************************* */
static void updateRRD(char *hostPath, char *key, Counter value, int isCounter, char short_step) {
if(useDaemon) {
char buf[128];
int rc;
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"CMD %s\t%s\t%lu\t%d\t%d",
hostPath, key, value, isCounter, short_step);
rc = sendto(sd, buf, strlen(buf), 0,
(struct sockaddr *)&remoteServAddr,
sizeof(remoteServAddr));
} else {
char path[512], *argv[32], cmd[64];
struct stat statbuf;
int argc = 0, rc, createdCounter = 0, i;
#ifdef MAX_RRD_PROCESS_BUFFER
struct timeval rrdStartOfProcessing,
rrdEndOfProcessing;
float elapsed;
#endif
if(value == 0) return;
#ifdef MAX_RRD_PROCESS_BUFFER
gettimeofday(&rrdStartOfProcessing, NULL);
#endif
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s%s.rrd", hostPath, key);
/* Avoid path problems */
for(i=strlen(hostPath); i<strlen(path); i++)
if(path[i] == '/') path[i]='_';
revertSlashIfWIN32(path, 0);
if(stat(path, &statbuf) != 0) {
char startStr[32], stepStr[32], counterStr[64], intervalStr[32];
char minStr[32], maxStr[32], daysStr[32], monthsStr[32];
char tempStr[64];
int step;
int value1, value2, rrdDumpInterval;
unsigned long topValue;
rrdDumpInterval = short_step ? (2*dumpShortInterval) : dumpInterval;
step = rrdDumpInterval;
topValue = 1000000000 /* 1 Gbit/s */;
if(strncmp(key, "pkt", 3) == 0) {
topValue /= 8*64 /* 64 bytes is the shortest packet we care of */;
} else {
topValue /= 8 /* 8 bytes */;
}
argv[argc++] = "rrd_create";
argv[argc++] = path;
argv[argc++] = "--start";
safe_snprintf(__FILE__, __LINE__, startStr, sizeof(startStr), "%u",
rrdTime-1 /* -1 avoids subsequent rrd_update call problems */);
argv[argc++] = startStr;
argv[argc++] = "--step";
safe_snprintf(__FILE__, __LINE__, stepStr, sizeof(stepStr), "%u", rrdDumpInterval);
argv[argc++] = stepStr;
if(isCounter) {
safe_snprintf(__FILE__, __LINE__, counterStr, sizeof(counterStr),
"DS:counter:COUNTER:%d:0:%u", 2*step, topValue);
} else {
/*
Unlimited (sort of)
Well I have decided to add a limit too in order to avoid crazy values.
*/
safe_snprintf(__FILE__, __LINE__, counterStr, sizeof(counterStr),
"DS:counter:GAUGE:%d:0:%u", 2*step, topValue);
}
argv[argc++] = counterStr;
/* rrdDumpInterval is in seconds. There are 60m*60s = 3600s in an hour.
* value1 is the # of rrdDumpIntervals per hour
*/
value1 = (60*60 + rrdDumpInterval - 1) / rrdDumpInterval;
/* value2 is the # of value1 (hours) for dumpHours hours */
value2 = value1 * dumpHours;
safe_snprintf(__FILE__, __LINE__, intervalStr, sizeof(intervalStr),
"RRA:AVERAGE:%.1f:1:%d", 0.5, value2);
argv[argc++] = intervalStr;
/* Store the MIN/MAX 5m value for a # of hours */
safe_snprintf(__FILE__, __LINE__, minStr, sizeof(minStr), "RRA:MIN:%.1f:1:%d",
0.5, dumpHours > 0 ? dumpHours : DEFAULT_RRD_HOURS);
argv[argc++] = minStr;
safe_snprintf(__FILE__, __LINE__, maxStr, sizeof(maxStr), "RRA:MAX:%.1f:1:%d",
0.5, dumpHours > 0 ? dumpHours : DEFAULT_RRD_HOURS);
argv[argc++] = maxStr;
if(dumpDays > 0) {
safe_snprintf(__FILE__, __LINE__, daysStr, sizeof(daysStr), "RRA:AVERAGE:%.1f:%d:%d",
0.5, value1, dumpDays * 24);
argv[argc++] = daysStr;
}
/* Compute the rollup - how many rrdDumpInterval seconds interval are in a day */
value1 = (24*60*60 + rrdDumpInterval - 1) / rrdDumpInterval;
if(dumpMonths > 0) {
safe_snprintf(__FILE__, __LINE__, monthsStr, sizeof(monthsStr),
"RRA:AVERAGE:%.1f:%d:%d",
0.5, value1, dumpMonths * 30);
argv[argc++] = monthsStr;
}
safe_snprintf(__FILE__, __LINE__, tempStr, sizeof(tempStr),
"RRA:HWPREDICT:1440:0.1:0.0035:20");
argv[argc++] = tempStr;
#if DEBUG
if(shownCreate == 0) {
char buf[LEN_GENERAL_WORK_BUFFER];
int i;
shownCreate=1;
memset(buf, 0, sizeof(buf));
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%s", argv[4]);
for (i=5; i<argc; i++) {
strncat(buf, " ", (sizeof(buf) - strlen(buf) - 1));
strncat(buf, argv[i], (sizeof(buf) - strlen(buf) - 1));
}
traceEvent(CONST_TRACE_INFO, "RRD: rrdtool create --start now-1 file %s", buf);
}
#endif
accessMutex(&rrdMutex, "rrd_create");
optind=0; /* reset gnu getopt */
opterr=0; /* no error messages */
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
rrd_clear_error();
addRrdDelay();
rc = rrd_create(argc, argv);
if(rrd_test_error()) {
char *err = rrd_get_error();
traceEventRRDebugARGV(3);
traceEvent(CONST_TRACE_WARNING, "RRD: rrd_create(%s) error: %s",
path, err ? err : "");
rrd_clear_error();
numRRDerrors++;
}
releaseMutex(&rrdMutex);
/* traceEventRRDebug("rrd_create(%s, %s)=%d", hostPath, key, rc); */
createdCounter = 1;
}
#if RRD_DEBUG > 0
{
if(checkLast(path) >= rrdTime)
traceEventRRDebug(0, "WARNING rrd_update not performed (RRD already updated)");
}
#endif
argc = 0;
argv[argc++] = "rrd_update";
argv[argc++] = path;
safe_snprintf(__FILE__, __LINE__, cmd, sizeof(cmd), "%u:%llu",
(unsigned int)rrdTime, (unsigned long long)value);
argv[argc++] = cmd;
accessMutex(&rrdMutex, "rrd_update");
optind=0; /* reset gnu getopt */
opterr=0; /* no error messages */
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
rrd_clear_error();
addRrdDelay();
rc = rrd_update(argc, argv);
numRRDUpdates++;
numTotalRRDUpdates++;
if(rrd_test_error()) {
int x;
char *rrdError;
traceEventRRDebugARGV(3);
numRRDerrors++;
rrdError = rrd_get_error();
if(rrdError != NULL) {
traceEvent(CONST_TRACE_WARNING, "RRD: rrd_update(%s) error: %s", path, rrdError);
traceEvent(CONST_TRACE_NOISY, "RRD: call stack (counter created: %d):", createdCounter);
for (x = 0; x < argc; x++)
traceEvent(CONST_TRACE_NOISY, "RRD: argv[%d]: %s", x, argv[x]);
if(!strcmp(rrdError, "error: illegal attempt to update using time")) {
char errTimeBuf1[32], errTimeBuf2[32], errTimeBuf3[32];
struct tm workT;
time_t rrdLast = checkLast(path);
strftime(errTimeBuf1, sizeof(errTimeBuf1), CONST_LOCALE_TIMESPEC, localtime_r(&myGlobals.actTime, &workT));
strftime(errTimeBuf2, sizeof(errTimeBuf2), CONST_LOCALE_TIMESPEC, localtime_r(&rrdTime, &workT));
strftime(errTimeBuf3, sizeof(errTimeBuf3), CONST_LOCALE_TIMESPEC, localtime_r(&rrdLast, &workT));
traceEvent(CONST_TRACE_WARNING,
"RRD: actTime = %d(%s), rrdTime %d(%s), lastUpd %d(%s)",
(int)myGlobals.actTime,
errTimeBuf1,
(int)rrdTime,
errTimeBuf2,
(int)rrdLast,
rrdLast == -1 ? "rrdlast ERROR" : errTimeBuf3);
} else if(strstr(rrdError, "is not an RRD file") || strstr(rrdError, "read operation failed")) {
unlink(path);
} else {
char do_delete = 0;
/* Delete empty RRD files */
if(stat(path, &statbuf) == 0) {
if(statbuf.st_size == 0) do_delete = 1;
} else
do_delete = 1;
if(do_delete) unlink(path);
}
rrd_clear_error();
} else {
traceEventRRDebug(0, "rrd_update(%s, %s, %s)=%d", hostPath, key, cmd, rc);
}
} else if(0) {
unsigned long step, ds_cnt;
rrd_value_t *data,*datai, _total, _val;
char **ds_namv, time_buf[32];
time_t start,end;
safe_snprintf(__FILE__, __LINE__, time_buf, sizeof(time_buf), "%u", rrdTime);
argc = 0;
argv[argc++] = "rrd_fetch";
argv[argc++] = path;
argv[argc++] = "FAILURES";
argv[argc++] = "--start";
argv[argc++] = time_buf;
argv[argc++] = "--end";
argv[argc++] = time_buf;
accessMutex(&rrdMutex, "rrd_fetch");
optind=0; /* reset gnu getopt */
opterr=0; /* no error messages */
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
rrd_clear_error();
addRrdDelay();
rc = rrd_fetch(argc, argv, &start, &end, &step, &ds_cnt, &ds_namv, &data);
releaseMutex(&rrdMutex);
if(rc != -1) {
datai = data, _total = 0;
for(i = start; i <= end; i += step) {
_val = *(datai++);
if(_val > 0)
_total += _val;
}
for(i=0;i<ds_cnt;i++) free(ds_namv[i]);
free(ds_namv);
free(data);
traceEvent(CONST_TRACE_WARNING, "Host %s: detected failure on key %s",
hostPath, key);
}
}
releaseMutex(&rrdMutex);
#ifdef MAX_RRD_PROCESS_BUFFER
gettimeofday(&rrdEndOfProcessing, NULL);
elapsed = timeval_subtract(rrdEndOfProcessing, rrdStartOfProcessing);
rrdprocessBuffer[++rrdprocessBufferCount & (MAX_RRD_PROCESS_BUFFER - 1)] = elapsed;
if(elapsed > rrdpmaxDelay)
rrdpmaxDelay = elapsed;
#endif
}
}
/* ******************************* */
static void updateCounter(char *hostPath, char *key, Counter value, char short_step) {
/* traceEvent(CONST_TRACE_INFO, "updateCounter: [%s][%s]", hostPath, key); */
updateRRD(hostPath, key, value, 1, short_step);
}
/* ******************************* */
static void updateGauge(char *hostPath, char *key, Counter value, char short_step) {
/* traceEvent(CONST_TRACE_INFO, "RRD: %s = %u", key, (unsigned long)value); */
updateRRD(hostPath, key, value, 0, short_step);
}
/* ******************************* */
static void updateTrafficCounter(char *hostPath, char *key, TrafficCounter *counter, char short_step) {
if(counter->modified) {
updateCounter(hostPath, key, counter->value, short_step);
counter->modified = 0;
}
}
/* ******************************* */
#ifndef WIN32
static void setGlobalPermissions(int permissionsFlag) {
switch (permissionsFlag) {
case CONST_RRD_PERMISSIONS_GROUP:
myGlobals.rrdDirectoryPermissions = CONST_RRD_D_PERMISSIONS_GROUP;
myGlobals.rrdUmask = CONST_RRD_UMASK_GROUP;
break;
case CONST_RRD_PERMISSIONS_EVERYONE:
myGlobals.rrdDirectoryPermissions = CONST_RRD_D_PERMISSIONS_EVERYONE;
myGlobals.rrdUmask = CONST_RRD_UMASK_EVERYONE;
break;
default:
myGlobals.rrdDirectoryPermissions = CONST_RRD_D_PERMISSIONS_PRIVATE;
myGlobals.rrdUmask = CONST_RRD_UMASK_PRIVATE;
break;
}
}
#endif
/* ******************************* */
static void commonRRDinit(void) {
char value[1024];
#ifdef WIN32
get_serial(&driveSerial);
#endif
initUdp();
shownCreate = 0;
#ifdef MAX_RRD_CYCLE_BUFFER
if(rrdcycleBufferInit == 0) {
rrdcycleBufferCount = 0;
rrdcycleBufferInit = 1;
memset(&rrdcycleBuffer, 0, sizeof(rrdcycleBuffer));
}
#endif
#ifdef MAX_RRD_PROCESS_BUFFER
if(rrdprocessBufferInit == 0) {
rrdprocessBufferCount = 0;
rrdprocessBufferInit = 1;
memset(&rrdprocessBuffer, 0, sizeof(rrdprocessBuffer));
}
#endif
if(fetchPrefsValue("rrd.dataDumpInterval", value, sizeof(value)) == -1) {
safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_INTERVAL);
storePrefsValue("rrd.dataDumpInterval", value);
dumpInterval = DEFAULT_RRD_INTERVAL;
} else {
dumpInterval = atoi(value);
}
if(fetchPrefsValue("rrd.dumpShortInterval", value, sizeof(value)) == -1) {
safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_SHORT_INTERVAL);
storePrefsValue("rrd.dumpShortInterval", value);
dumpShortInterval = DEFAULT_RRD_SHORT_INTERVAL;
} else {
dumpShortInterval = atoi(value);
}
if(fetchPrefsValue("rrd.dataDumpHours", value, sizeof(value)) == -1) {
safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_HOURS);
storePrefsValue("rrd.dataDumpHours", value);
dumpHours = DEFAULT_RRD_HOURS;
} else {
dumpHours = atoi(value);
}
if(fetchPrefsValue("rrd.dataDumpDays", value, sizeof(value)) == -1) {
safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_DAYS);
storePrefsValue("rrd.dataDumpDays", value);
dumpDays = DEFAULT_RRD_DAYS;
} else {
dumpDays = atoi(value);
}
if(fetchPrefsValue("rrd.dataDumpMonths", value, sizeof(value)) == -1) {
safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_MONTHS);
storePrefsValue("rrd.dataDumpMonths", value);
dumpMonths = DEFAULT_RRD_MONTHS;
} else {
dumpMonths = atoi(value);
}
if(fetchPrefsValue("rrd.rrdDumpDelay", value, sizeof(value)) == -1) {
safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_DUMP_DELAY);
storePrefsValue("rrd.rrdDumpDelay", value);
dumpDelay = DEFAULT_RRD_DUMP_DELAY;
} else
dumpDelay = atoi(value);
if(fetchPrefsValue("rrd.dataDumpDomains", value, sizeof(value)) == -1) {
storePrefsValue("rrd.dataDumpDomains", "0");
dumpDomains = 0;
} else {
dumpDomains = atoi(value);
}
if(fetchPrefsValue("rrd.dataDumpFlows", value, sizeof(value)) == -1) {
storePrefsValue("rrd.dataDumpFlows", "0");
dumpFlows = 0;
} else {
dumpFlows = atoi(value);
}
if(fetchPrefsValue("rrd.dataDumpHosts", value, sizeof(value)) == -1) {
storePrefsValue("rrd.dataDumpHosts", "0");
dumpHosts = 0;
} else {
dumpHosts = atoi(value);
}
if(fetchPrefsValue("rrd.dataDumpInterfaces", value, sizeof(value)) == -1) {
storePrefsValue("rrd.dataDumpInterfaces", "1");
dumpInterfaces = 1;
} else {
dumpInterfaces = atoi(value);
}
if(fetchPrefsValue("rrd.dumpASs", value, sizeof(value)) == -1) {
storePrefsValue("rrd.dumpASs", "1");
dumpASs = 1;
} else {
dumpASs = atoi(value);
}
if(fetchPrefsValue("rrd.enableAberrant", value, sizeof(value)) == -1) {
storePrefsValue("rrd.enableAberrant", "1");
enableAberrant = 1;
} else {
enableAberrant = atoi(value);
}
if(fetchPrefsValue("rrd.dataDumpMatrix", value, sizeof(value)) == -1) {
storePrefsValue("rrd.dataDumpMatrix", "0");
dumpMatrix = 0;
} else {
dumpMatrix = atoi(value);
}
if(hostsFilter != NULL) free(hostsFilter);
if(fetchPrefsValue("rrd.hostsFilter", value, sizeof(value)) == -1) {
int i;
value[0] = '\0';
for(i=0; i<myGlobals.numLocalNetworks; i++) {
char buf[64];
u_int32_t network = myGlobals.localNetworks[i][CONST_NETWORK_ENTRY];
u_int32_t netmask = myGlobals.localNetworks[i][CONST_NETMASK_ENTRY];
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"%d.%d.%d.%d/%d.%d.%d.%d",
(int) ((network >> 24) & 0xff), (int) ((network >> 16) & 0xff),
(int) ((network >> 8) & 0xff), (int) ((network >> 0) & 0xff),
(int) ((netmask >> 24) & 0xff), (int) ((netmask >> 16) & 0xff),
(int) ((netmask >> 8) & 0xff), (int) ((netmask >> 0) & 0xff));
if(value[0] != '\0') strcat(value, ",");
strcat(value, buf);
}
hostsFilter = strdup(value);
storePrefsValue("rrd.hostsFilter", hostsFilter);
/*
traceEvent(CONST_TRACE_INFO, "====> RRD: numLocalNetworks=%d [%s]",
myGlobals.numLocalNetworks, value);
*/
} else {
hostsFilter = strdup(value);
}
if(fetchPrefsValue("rrd.dataDumpDetail", value, sizeof(value)) == -1) {
safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", CONST_RRD_DETAIL_DEFAULT);
storePrefsValue("rrd.dataDumpDetail", value);
dumpDetail = CONST_RRD_DETAIL_DEFAULT;
} else {
dumpDetail = atoi(value);
}
if(fetchPrefsValue("rrd.rrdPath", value, sizeof(value)) == -1) {
char *thePath = "/rrd";
int len = strlen(myGlobals.dbPath)+strlen(thePath)+16, idx = 0;
if(myGlobals.rrdPath) free(myGlobals.rrdPath);
myGlobals.rrdPath = (char*)malloc(len);
#ifdef WIN32
safe_snprintf(__FILE__, __LINE__, myGlobals.rrdPath, len,
"%s/%u%s", &myGlobals.dbPath[idx], driveSerial, thePath);
revertSlashIfWIN32(myGlobals.rrdPath, 0);
#else
safe_snprintf(__FILE__, __LINE__, myGlobals.rrdPath,
len, "%s%s", &myGlobals.dbPath[idx], thePath);
#endif
len = strlen(myGlobals.rrdPath);
if(myGlobals.rrdPath[len-1] == '/') myGlobals.rrdPath[len-1] = '\0';
storePrefsValue("rrd.rrdPath", myGlobals.rrdPath);
} else {
int vlen = strlen(value)+1;
myGlobals.rrdPath = (char*)malloc(vlen);
unescape(myGlobals.rrdPath, vlen, value);
}
#ifndef WIN32
if(fetchPrefsValue("rrd.permissions", value, sizeof(value)) == -1) {
safe_snprintf(__FILE__, __LINE__, value, sizeof(value), "%d", DEFAULT_RRD_PERMISSIONS);
storePrefsValue("rrd.permissions", value);
dumpPermissions = DEFAULT_RRD_PERMISSIONS;
} else {
dumpPermissions = atoi(value);
}
setGlobalPermissions(dumpPermissions);
traceEvent(CONST_TRACE_INFO, "RRD: Mask for new directories is %04o",
myGlobals.rrdDirectoryPermissions);
umask(myGlobals.rrdUmask);
traceEvent(CONST_TRACE_INFO, "RRD: Mask for new files is %04o",
myGlobals.rrdUmask);
#endif
#ifdef RRD_DEBUG
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: Parameters:");
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpInterval %d seconds", dumpInterval);
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpShortInterval %d seconds", dumpShortInterval);
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpHours %d hours by %d seconds", dumpHours, dumpInterval);
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpDays %d days by hour", dumpDays);
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpMonths %d months by day", dumpMonths);
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpDomains %s", dumpDomains == 0 ? "no" : "yes");
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpFlows %s", dumpFlows == 0 ? "no" : "yes");
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpHosts %s", dumpHosts == 0 ? "no" : "yes");
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpInterfaces %s", dumpInterfaces == 0 ? "no" : "yes");
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpASs %s", dumpASs == 0 ? "no" : "yes");
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpMatrix %s", dumpMatrix == 0 ? "no" : "yes");
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: dumpDetail %s",
dumpDetail == FLAG_RRD_DETAIL_HIGH ? "high" :
(dumpDetail == FLAG_RRD_DETAIL_MEDIUM ? "medium" : "low"));
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: hostsFilter %s", hostsFilter);
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: rrdPath %s", myGlobals.rrdPath);
#ifndef WIN32
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: umask %04o", myGlobals.rrdUmask);
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: DirPerms %04o", myGlobals.rrdDirectoryPermissions);
#endif
#endif /* RRD_DEBUG */
if (MAX_NUM_ENTRIES > CONST_NUM_BAR_COLORS)
traceEvent(CONST_TRACE_WARNING, "RRD: Too few colors defined in rrd_colors - graphs could be truncated");
updateUdpParams();
initialized = 1;
}
/* ****************************** */
#undef option_timespan
#define option_timespan(theStartTime, theLabel, selected) \
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), \
"<option value=\"/" CONST_PLUGINS_HEADER "%s?action=" CONST_ARBITRARY_RRDREQUEST "&" CONST_ARBITRARY_IP "=%s" \
"&" CONST_ARBITRARY_INTERFACE "=%s" \
"&" CONST_ARBITRARY_FILE "=%s" \
"&start=%u" \
"&end=%u" \
"&counter=%s" \
"&title=%s&mode=zoom\" %s>%s</option>\n", \
"rrdPlugin", rrdIP, rrdInterface, rrdName, (unsigned int)theStartTime, (unsigned int)the_time, buf1, buf2, \
(selected == 1) ? "selected" : "", theLabel); sendString(buf);
/* ****************************** */
static void arbitraryAction(char *rrdName,
char *rrdInterface,
char *rrdIP,
char *_startTime,
char *_endTime,
char *rrdCounter,
char *rrdTitle,
char _which,
char *mode) {
int i, len, rc=0, argc = 0, argc1 = 0, countOK=0, countZERO=0;
char buf[LEN_GENERAL_WORK_BUFFER], rrdKey[64], *startTime, *endTime, time_buf[32];
time_t the_time;
struct tm *the_tm;
startTime = _startTime, endTime = _endTime;
if(atol(endTime) == 0) {
snprintf(time_buf, sizeof(time_buf), "%u", (u_int)time(NULL));
endTime = time_buf;
}
if(atol(startTime) > atol(endTime)) {
startTime = endTime;
}
if(!strcmp(mode, "zoom")) {
char buf1[LEN_GENERAL_WORK_BUFFER], buf2[LEN_GENERAL_WORK_BUFFER];
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("" /* "Arbitrary Graph URL" */, NULL, 0);
escape(buf1, sizeof(buf1), rrdCounter);
escape(buf2, sizeof(buf2), rrdTitle);
sendString("<center>\n");
/* *************************************** */
/*
Graph time and zoom: code courtesy of
the Cacti (http://www.cacti.net) project.
*/
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/calendar.js\"></SCRIPT>\n");
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/lang/calendar-en.js\"></SCRIPT>\n");
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/calendar-setup.js\"></script>\n");
sendString("<SCRIPT type=\"text/javascript\" src=\"/jscalendar/calendar-load.js\"></script>\n");
sendString("\n<p align=center>\n<FORM action=/plugins/rrdPlugin name=\"form_timespan_selector\" method=\"get\">\n<TABLE width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">\n<TBODY><TR><TD align=center class=\"textHeader\" nowrap=\"\">\n<b>Presets</b>: <SELECT name=\"predefined_timespan\" onchange=\"window.location=document.form_timespan_selector.predefined_timespan.options[document.form_timespan_selector.predefined_timespan.selectedIndex].value\">\n");
the_time = time(NULL);
option_timespan(the_time-12*3600, "-----", 1);
option_timespan(the_time-1800, "Last Half Hour", 0);
option_timespan(the_time-3600, "Last Hour", 0);
option_timespan(the_time-2*3600, "Last 2 Hours", 0);
option_timespan(the_time-4*3600, "Last 4 Hours", 0);
option_timespan(the_time-6*3600, "Last 6 Hours", 0);
option_timespan(the_time-12*3600, "Last 12 Hours", 0);
option_timespan(the_time-86400, "Last Day", 0);
option_timespan(the_time-2*86400, "Last 2 Days", 0);
option_timespan(the_time-4*86400, "Last 4 Days", 0);
option_timespan(the_time-7*86400, "Last Week", 0);
option_timespan(the_time-30*86400, "Last Month", 0);
option_timespan(the_time-2*30*86400, "Last 2 Months", 0);
option_timespan(the_time-4*30*86400, "Last 4 Months", 0);
option_timespan(the_time-6*30*86400, "Last 6 Months", 0);
option_timespan(the_time-12*30*86400, "Last Year", 0);
sendString("</select>\n");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<input type=hidden name=action value=\"" CONST_ARBITRARY_RRDREQUEST "\">\n"
"<input type=hidden name="CONST_ARBITRARY_IP " value=\"%s\">\n"
"<input type=hidden name=" CONST_ARBITRARY_INTERFACE " value=\"%s\">\n"
"<input type=hidden name=" CONST_ARBITRARY_FILE " value=\"%s\">\n"
"<input type=hidden name=start value=\"%s\">\n"
"<input type=hidden name=end value=\"%s\">\n"
"<input type=hidden name=counter value=\"%s\">\n"
"<input type=hidden name=title value=\"%s\">\n"
"<input type=hidden name=mode value=\"zoom\">\n",
rrdIP, rrdInterface, rrdName, startTime, endTime, buf1, buf2);
sendString(buf);
sendString(" <STRONG>From:</STRONG>\n<INPUT type=\"text\" name=\"date1\" id=\"date1\" size=\"16\" value=\"");
the_time = atol(startTime); the_tm = localtime(&the_time);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M", the_tm); sendString(buf);
sendString("\">\n<INPUT type=\"image\" src=\"/calendar.gif\" alt=\"Start date selector\" border=\"0\" align=\"absmiddle\" onclick=\"return showCalendar('date1');\">\n");
sendString(" <strong>To:</strong>\n<INPUT type=\"text\" name=\"date2\" id=\"date2\" size=\"16\" value=\"");
the_time = atol(endTime); the_tm = localtime(&the_time);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M", the_tm); sendString(buf);
sendString("\">\n<INPUT type=\"image\" src=\"/calendar.gif\" alt=\"End date selector\" border=\"0\" align=\"absmiddle\" onclick=\"return showCalendar('date2');\">\n"
"<INPUT type=\"submit\" value=\"Update Graph\">\n</FORM>\n</TD></TR></TBODY></TABLE>\n</p>\n");
/* *************************************** */
sendString("<SCRIPT type=\"text/javascript\" src=\"/zoom.js\"></SCRIPT>\n"
"<DIV id=\"zoomBox\" style=\"position: absolute; visibility: visible; background-image: initial; background-repeat: initial; "
"background-attachment: initial; background-position-x: initial; background-position-y: initial; background-color: orange; opacity: 0.5;\"></DIV>\n");
sendString("<DIV id=\"zoomSensitiveZone\" style=\"position:absolute; overflow:none; background-repeat: initial; background-attachment: initial; background-position-x: initial; background-position-y: initial; visibility:visible; cursor:crosshair; background:blue; filter:alpha(opacity=0); -moz-opacity:0; -khtml-opacity:0; opacity:0;\" oncontextmenu=\"return false\"></DIV>\n");
/*
NOTE:
If the graph size changes, please update the zoom.js file (search for L.Deri)
*/
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<img id=zoomGraphImage src=\"/" CONST_PLUGINS_HEADER "%s?action=" CONST_ARBITRARY_RRDREQUEST
"&" CONST_ARBITRARY_IP "=%s"
"&" CONST_ARBITRARY_INTERFACE "=%s"
"&" CONST_ARBITRARY_FILE "=%s"
"&start=%s"
"&end=%s"
"&counter=%s"
"&title=%s"
"\" alt=\"graph image\" border=0></center>\n",
rrdPluginInfo->pluginURLname,
rrdIP,
rrdInterface,
rrdName,
startTime,
endTime,
buf1,
buf2);
sendString(buf);
sendString("\n<SCRIPT type=\"text/javascript\">\n\nvar cURLBase = \"/plugins/rrdPlugin?mode=zoom\";\n\n// Global variables\nvar gZoomGraphName = \"zoomGraphImage\";\n"
"var gZoomGraphObj;\nvar gMouseObj;\nvar gUrlObj;\nvar gBrowserObj;\nvar gGraphWidth;\n"
"var gGraphHeight;\n\n\nwindow.onload = initBonsai;\n\n</SCRIPT>\n");
sendString("</center>\n");
printHTMLtrailer();
return;
}
memset(&buf, 0, sizeof(buf));
memset(&rrdKey, 0, sizeof(rrdKey));
/* Security check... it's a file name */
if(fileSanityCheck(rrdName, "arbitrary rrd request", 1) != 0) {
traceEvent(CONST_TRACE_ERROR, "SECURITY: Invalid arbitrary rrd request(filename)... ignored");
return;
}
if(fileSanityCheck(rrdInterface, "arbitrary rrd request", 1) != 0) {
traceEvent(CONST_TRACE_ERROR, "SECURITY: Invalid arbitrary rrd request(interface)... ignored");
return;
}
if(rrdIP[0] == '\0') {
/* Interface level */
safe_snprintf(__FILE__, __LINE__, rrdKey, sizeof(rrdKey), "interfaces/%s/", rrdInterface);
} else {
/* Security check... it's an ip - 0..9 a..f . and : ONLY */
if(ipSanityCheck(rrdIP, "arbitrary rrd request", 1) != 0) {
traceEvent(CONST_TRACE_ERROR, "SECURITY: Invalid arbitrary rrd request(ip)... ignored (sanitized: %s)", rrdIP);
return;
}
len=strlen(rrdIP);
for(i=0; i<len; i++) if(rrdIP[i] == '.') rrdIP[i] = CONST_PATH_SEP;
safe_snprintf(__FILE__, __LINE__, rrdKey, sizeof(rrdKey), "interfaces/%s/hosts/%s/", rrdInterface, rrdIP);
}
if(!validHostCommunity(rrdIP)) {
returnHTTPpageBadCommunity();
return;
}
if(rrdCounter[0] == '\0')
strcpy(rrdCounter, rrdName);
if(_which == CONST_ARBITRARY_RRDREQUEST_SHOWME[0]) {
char buf1[LEN_GENERAL_WORK_BUFFER],
buf2[LEN_GENERAL_WORK_BUFFER];
memset(&buf1, 0, sizeof(buf1));
memset(&buf2, 0, sizeof(buf2));
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("Arbitrary Graph URL", NULL, 0);
escape(buf1, sizeof(buf1), rrdCounter);
escape(buf2, sizeof(buf2), rrdTitle);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<p>/" CONST_PLUGINS_HEADER "%s?action=" CONST_ARBITRARY_RRDREQUEST
"&" CONST_ARBITRARY_IP "=%s"
"&" CONST_ARBITRARY_INTERFACE "=%s"
"&" CONST_ARBITRARY_FILE "=%s"
"&start=%s"
"&end=%s"
"&counter=%s"
"&title=%s</p>\n",
rrdPluginInfo->pluginURLname,
rrdIP,
rrdInterface,
rrdName,
startTime,
endTime,
buf1,
buf2);
sendString(buf);
printHTMLtrailer();
return;
}
if((_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ||
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHMECSV[0])) {
char *argv[32], *argv1[8], rptTime[32], startWorkTime[32], path[128], **ds_namv;
time_t start=0,end=time(NULL)+1, startTimeFound = 0;
unsigned long step=0, ds_cnt, ii;
rrd_value_t *data,*datai, _val;
struct tm workT;
memset(&path, 0, sizeof(path));
memset(&rptTime, 0, sizeof(rptTime));
memset(&startWorkTime, 0, sizeof(startWorkTime));
if(!strcmp(rrdName, "throughput")) {
#ifdef WIN32
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%u/%s%s.rrd", myGlobals.spoolPath, driveSerial, rrdKey, rrdName);
#else
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s%s.rrd", myGlobals.spoolPath, rrdKey, rrdName);
#endif
} else
safe_snprintf(__FILE__, __LINE__, path, sizeof(path), "%s/%s%s.rrd", myGlobals.rrdPath, rrdKey, rrdName);
if(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) {
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("RRD data dump", NULL, 0);
sendString("<h1>For: ");
sendString(path);
sendString("</h1>");
} else {
sendHTTPHeader(FLAG_HTTP_TYPE_TEXT, 0, 1);
sendString("\"file\",\"");
sendString(path);
sendString("\"\n\n");
}
argv[argc++] = "rrd_fetch";
argv[argc++] = path;
argv[argc++] = "AVERAGE";
if((startTime != NULL) && (startTime[0] == '0') && (startTime[1] == '\0')) {
argv1[argc1++] = "rrd_first";
argv1[argc1++] = path;
startTimeFound = rrd_first(argc1, argv1);
if(startTimeFound != ((time_t)-1)) {
safe_snprintf(__FILE__, __LINE__, startWorkTime, sizeof(startWorkTime), "%u", startTimeFound);
argv[argc++] = "--start";
argv[argc++] = startWorkTime;
}
} else if(startTime != NULL) {
argv[argc++] = "--start";
argv[argc++] = startTime;
}
if((endTime != NULL) && (endTime[0] != '\0')) {
argv[argc++] = "--end";
argv[argc++] = endTime;
}
optind=0; /* reset gnu getopt */
opterr=0; /* no error messages */
fillupArgv(argc, sizeof(argv)/sizeof(char*), argv);
rrd_clear_error();
accessMutex(&rrdMutex, "arbitrary rrd_fetch");
rc = rrd_fetch(argc, argv, &start, &end, &step, &ds_cnt, &ds_namv, &data);
releaseMutex(&rrdMutex);
if(rc == -1) {
traceEventRRDebugARGV(3);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"%sError retrieving rrd data, %s%s\n",
rrd_get_error() ? rrd_get_error() : "",
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "<p>" : "",
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "</p>" : "");
sendString(buf);
return;
}
if(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) {
sendString("<center>\n"
"<table border=\"1\""TABLE_DEFAULTS">\n"
"<tr><th align=\"center\" "DARK_BG" colspan=\"2\">Sample date/time</th>"
"<th align=\"center\" "DARK_BG" width=\"150\">Value</th></tr>\n");
}
datai = data;
for(ii = start; ii <= end; ii += step) {
_val = *(datai++);
if(_val > 0) {
countOK++;
strftime(rptTime, sizeof(rptTime), CONST_LOCALE_TIMESPEC, localtime_r((time_t *)&ii, &workT));
if(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) {
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<tr><td>%s</td><td align=\"right\">%u</td><td align=\"right\">%.6g</td></tr>\n",
rptTime, ii, _val);
} else {
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"\"%s\",%u,%.6g\n",
rptTime, ii, _val);
}
sendString(buf);
} else {
countZERO++;
}
}
for(i=0;i<ds_cnt;i++) if(ds_namv[i] != NULL) free(ds_namv[i]);
if(ds_namv != NULL) free(ds_namv);
if(data != NULL) free(data);
if(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) {
sendString("</table>\n"
"</center>\n");
}
/* Closing comments... */
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"\n\n%sNotes%s\n"
"%s%d data points reported, %d skipped%s\n\n",
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "<h2>" : "\"",
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "</h2>\n<ul>" : "\"",
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "<li>" : "\n\"",
countOK, countZERO,
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "</li>" : "\"");
sendString(buf);
if(startTimeFound != ((time_t)-1)) {
strftime(rptTime, sizeof(rptTime), CONST_LOCALE_TIMESPEC, localtime_r(&startTimeFound, &workT));
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"%sFound %s (%u) as the first (detail) data point%s\n",
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "<li>" : "\"",
rptTime, startTimeFound,
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "</li>" : "\"");
} else if(start > 0) {
strftime(rptTime, sizeof(rptTime), CONST_LOCALE_TIMESPEC, localtime_r(&start, &workT));
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"%sFetch found %s (%u) as the first %s data point%s\n",
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "<li>" : "\"",
rptTime, start,
step <= dumpInterval ? "detail" : "summary",
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "</li>" : "\"");
}
sendString(buf);
strftime(rptTime, sizeof(rptTime), CONST_LOCALE_TIMESPEC, localtime_r(&end, &workT));
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"%sFetch found %s (%u) as the last data point%s\n",
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "<li>" : "\"",
rptTime, end,
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "</li>" : "\"");
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"%sStep is %u seconds%s\n",
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "<li>" : "\"",
step,
(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "</li>\n</ul>" : "\"");
sendString(buf);
sendString((_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "<p>" : "\"");
sendString("This request is roughly equivalent to: ");
sendString((_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "<b>" : "");
sendString("rrdtool fetch");
for(i=1; i<argc; i++) {
sendString(" ");
sendString(argv[i]);
}
sendString(" | grep -v nan");
sendString((_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0]) ? "</b></p>" : "\"");
if(_which == CONST_ARBITRARY_RRDREQUEST_FETCHME[0])
printHTMLtrailer();
return;
}
rc = graphCounter(rrdKey, rrdName, rrdTitle, rrdCounter, startTime, endTime, "arbitrary");
return;
}
/* ****************************** */
static void statisticsPage(void) {
char buf[1024];
#ifdef MAX_RRD_PROCESS_BUFFER
float pminDelay=99999.0, pmaxDelay=0.0;
int i;
float /*stddev:*/ pM, pT, pQ, pR, pSD;
#endif
memset(&buf, 0, sizeof(buf));
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("RRD Statistics", NULL, 0);
sendString("<center><table border=\"1\""TABLE_DEFAULTS">\n"
"<tr><th align=\"center\" "DARK_BG">Item</th>"
"<th align=\"center\" "DARK_BG">Count</th></tr>\n");
sendString("<tr><th align=\"left\" "DARK_BG">Cycles</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%lu</td></tr>\n", (unsigned long)numRRDCycles);
sendString(buf);
sendString("<tr><th align=\"left\" "DARK_BG">Files Updated</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%lu</td></tr>\n", (unsigned long)numTotalRRDUpdates);
sendString(buf);
sendString("<tr><th align=\"left\" "DARK_BG">Update Errors</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%lu</td></tr>\n", (unsigned long)numRRDerrors);
sendString(buf);
sendString("<tr><th align=\"left\" "DARK_BG">Graphic Requests</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%lu</td></tr>\n", (unsigned long)rrdGraphicRequests);
sendString(buf);
sendString("</table>\n</center>\n");
#ifdef MAX_RRD_PROCESS_BUFFER
printSectionTitle("Per-RRD Processing times");
sendString("<center><table border=\"0\""TABLE_DEFAULTS">\n<tr><td width=\"500\">"
"<p>These numbers are the elapsed time (in seconds) per RRD update. "
"The computations are based only on the most recent "
xstr(MAX_RRD_PROCESS_BUFFER) " RRDs processed.</p>\n"
"<p>'Processing' time is the elapsed time between starting and finishing "
"updateRRD(). Errors may cause processing to be abandoned and those RRD "
"updates are not counted in the 'processing' averages.</p>\n"
"<p>If the RRD does not already exist, it will be created (along with any "
"necessary directories), so the reported values may include a mix of "
"short and long duration calls.</p>\n"
"<p>Small averages are good, especially if the standard deviation is small "
"(standard deviation is a measurement of the variability of the actual values "
"around the average).</p>\n"
"<p> </p>\n"
"</td></tr></table></center>\n");
if(rrdprocessBufferCount >= MAX_RRD_PROCESS_BUFFER) {
sendString("<center><table border=\"1\""TABLE_DEFAULTS">\n"
"<tr><th align=\"center\" "DARK_BG">Item</th>"
"<th align=\"center\" width=\"75\" "DARK_BG">Time</th></tr>\n");
for(i=0; i<MAX_RRD_PROCESS_BUFFER; i++) {
if(rrdprocessBuffer[i] > pmaxDelay) pmaxDelay = rrdprocessBuffer[i];
if(rrdprocessBuffer[i] < pminDelay) pminDelay = rrdprocessBuffer[i];
if(i==0) {
pM = rrdprocessBuffer[0];
pT = 0.0;
} else {
pQ = rrdprocessBuffer[i] - pM;
pR = pQ / (float)(i+1);
pM += pR;
pT = pT + i * pQ * pR;
}
}
pSD = sqrtf(pT / (MAX_RRD_PROCESS_BUFFER - 1));
pXBAR /*average*/ = pM;
sendString("<tr><th align=\"left\" "DARK_BG">Minimum</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f</td></tr>\n", pminDelay);
sendString(buf);
sendString("<tr><th align=\"left\" "DARK_BG">Average</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f</td></tr>\n", pXBAR);
sendString(buf);
sendString("<tr><th align=\"left\" "DARK_BG">Maximum</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f</td></tr>\n", pmaxDelay);
sendString(buf);
sendString("<tr><th align=\"left\" "DARK_BG">Standard Deviation</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f</td></tr>\n", pSD);
sendString(buf);
sendString("<tr><th align=\"left\" "DARK_BG">Maximum ever</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f</td></tr>\n", rrdpmaxDelay);
sendString(buf);
sendString("</table>\n</center>\n");
} else {
printNoDataYet();
}
#endif /* MAX_RRD_PROCESS_BUFFER */
#ifdef MAX_RRD_CYCLE_BUFFER
printSectionTitle("Per-Cycle Processing times");
sendString("<center><table border=\"0\""TABLE_DEFAULTS">\n<tr><td width=\"500\">"
"<p>These numbers are the elapsed time (in seconds) per RRD update cycle. "
"The computations are based only on the most recent "
xstr(MAX_RRD_CYCLE_BUFFER) " cycles executed.</p>\n"
"<p>'Processing' time is the elapsed time between waking and returning to "
"sleep in rrdMainLoop(). The currently executing cycle (if one) is not "
"included.</p>"
"<p> </p>\n"
"</td></tr></table></center>\n");
if(rrdcycleBufferCount >= MAX_RRD_CYCLE_BUFFER) {
sendString("<center><table border=\"1\""TABLE_DEFAULTS">\n"
"<tr><th align=\"center\" "DARK_BG">Item</th>"
"<th align=\"center\" width=\"75\" "DARK_BG">Time</th></tr>\n");
for(i=0; i<MAX_RRD_CYCLE_BUFFER; i++) {
if(rrdcycleBuffer[i] > pmaxDelay) pmaxDelay = rrdcycleBuffer[i];
if(rrdcycleBuffer[i] < pminDelay) pminDelay = rrdcycleBuffer[i];
if(i==0) {
pM = rrdcycleBuffer[0];
pT = 0.0;
} else {
pQ = rrdcycleBuffer[i] - pM;
pR = pQ / (float)(i+1);
pM += pR;
pT = pT + i * pQ * pR;
}
}
pSD = sqrtf(pT / (MAX_RRD_CYCLE_BUFFER - 1));
pXBAR /*average*/ = pM;
sendString("<tr><th align=\"left\" "DARK_BG">Minimum</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f</td></tr>\n", pminDelay);
sendString(buf);
sendString("<tr><th align=\"left\" "DARK_BG">Average</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f</td></tr>\n", pXBAR);
sendString(buf);
sendString("<tr><th align=\"left\" "DARK_BG">Maximum</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f</td></tr>\n", pmaxDelay);
sendString(buf);
sendString("<tr><th align=\"left\" "DARK_BG">Standard Deviation</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f</td></tr>\n", pSD);
sendString(buf);
sendString("<tr><th align=\"left\" "DARK_BG">Maximum ever</th><td align=\"right\">");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%.6f</td></tr>\n", rrdcmaxLength);
sendString(buf);
sendString("</table>\n</center>\n");
} else {
printNoDataYet();
}
#endif /* MAX_RRD_CYCLE_BUFFER */
}
/* ****************************** */
static void arbitraryActionPage(void) {
int idx, count, rc;
char buf[1024],
dirPath[256],
rrdPath[512],
startTime[32],
endTime[32];
DIR* directoryPointer=NULL;
struct dirent* dp;
struct stat statBuf;
time_t now = time(NULL);
memset(&buf, 0, sizeof(buf));
memset(&dirPath, 0, sizeof(dirPath));
memset(&rrdPath, 0, sizeof(rrdPath));
memset(&startTime, 0, sizeof(startTime));
memset(&endTime, 0, sizeof(endTime));
safe_snprintf(__FILE__, __LINE__, startTime, sizeof(startTime), "%u", now-12*3600);
safe_snprintf(__FILE__, __LINE__, endTime, sizeof(endTime), "%u", now);
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("Arbitrary RRD Actions", NULL, 0);
safe_snprintf(__FILE__, __LINE__, dirPath, sizeof(dirPath), "%s/interfaces", myGlobals.rrdPath);
revertSlashIfWIN32(dirPath, 0);
directoryPointer = opendir(dirPath);
if(directoryPointer == NULL) {
sendString("<p>No rrds found - check configuration.</p>\n");
return;
}
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<center>"
"<p>This allows you to see and/or create a graph of an arbitrary rrd file.</p>\n"
"<form action=\"/" CONST_PLUGINS_HEADER "%s\" method=GET>\n"
"<input type=hidden name=action value=\"" CONST_ARBITRARY_RRDREQUEST "\">\n"
"<table border=\"1\" width=\"80%%\" "TABLE_DEFAULTS">\n"
"<tr><th width=\"250\" align=\"left\" "DARK_BG">Action</th>\n"
"<td align=\"left\">"
"<input type=radio name=\"which\" value=\"" CONST_ARBITRARY_RRDREQUEST_GRAPHME "\" CHECKED>"
" Create the graph - this is returned as a png file and will display ONLY the graph, "
"without any html headings.<br>\n"
"<input type=radio name=\"which\" value=\"" CONST_ARBITRARY_RRDREQUEST_SHOWME "\">"
" Display the url to request the graph<br>\n"
"<input type=radio name=\"which\" value=\"" CONST_ARBITRARY_RRDREQUEST_FETCHME "\">"
" Retrieve rrd data in table form<br>\n"
"<input type=radio name=\"which\" value=\"" CONST_ARBITRARY_RRDREQUEST_FETCHMECSV "\">"
" Retrieve rrd data as CSV"
"</td></tr>\n"
"<tr><th align=\"left\" "DARK_BG">File</th>\n<td align=\"left\">"
"<select name=\"" CONST_ARBITRARY_FILE "\">",
rrdPluginInfo->pluginURLname);
sendString(buf);
for(idx=0; rrdNames[idx] != NULL; idx++) {
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<option value=\"%s\">%s</option>\n",
rrdNames[idx],
rrdNames[idx]);
sendString(buf);
}
if(myGlobals.device[0].ipProtoStats != NULL) {
for(idx=0; idx<myGlobals.numIpProtosToMonitor; idx++) {
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<option value=\"IP_%sSentBytes\">%s Sent Bytes</option>\n"
"<option value=\"IP_%sRcvdBytes\">%s Rcvd Bytes</option>\n"
"<option value=\"IP_%sBytes\">%s Bytes (interface level)</option>\n",
myGlobals.ipTrafficProtosNames[idx],
myGlobals.ipTrafficProtosNames[idx],
myGlobals.ipTrafficProtosNames[idx],
myGlobals.ipTrafficProtosNames[idx],
myGlobals.ipTrafficProtosNames[idx],
myGlobals.ipTrafficProtosNames[idx]);
sendString(buf);
}
}
sendString("</select>"
"<br>\n<p>Note: The drop down list shows all possible files - many (most) (all) "
"of which may not be available for a specific host. Further, the list is "
"based on the -p | --protocols parameter of this ntop run and may not "
"include files created during ntop runs with other -p | --protocols "
"parameter settings.</p>\n</td></tr>\n"
"<tr><th align=\"left\" "DARK_BG">Interface</th>\n<td align=\"left\">");
count = 0;
while((dp = readdir(directoryPointer)) != NULL) {
if(dp->d_name[0] != '.') {
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s", myGlobals.rrdPath, dp->d_name);
rc = stat(rrdPath, &statBuf);
if((rc == 0) && ((statBuf.st_mode & S_IFDIR) == S_IFDIR)) {
count++;
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<input type=radio name=\"" CONST_ARBITRARY_INTERFACE "\" value=\"%s\" %s>%s<br>\n",
dp->d_name,
count == 1 ? "CHECKED" : "",
dp->d_name);
sendString(buf);
}
}
}
if(count == 0) sendString("<b><font color=red>No RRD interface files available.</font></b>");
closedir(directoryPointer);
sendString("</td></tr>\n"
"<tr><th width=\"250\" align=\"left\" "DARK_BG">Host IP address</th>\n<td align=\"left\">"
"<input name=\"" CONST_ARBITRARY_IP "\" size=\"20\" value=\"\">"
" Leave blank to create a per-interface graph.</td></tr>\n"
"<tr><td align=\"left\" colspan=\"2\">\n"
"<p><i>A note about time specification</i>: You may specify time in a number of ways - please "
"see \"AT-STYLE TIME SPECIFICATION\" in the rrdfetch man page for the full details. Here "
"are some examples:</p>\n<ul>\n"
"<li>Specific values: Most common formats are understood, including numerical and character "
"date formats, such as Oct 12 - October 12th of "
"the current year, 10/12/2005, etc.</li>\n"
"<li>Relative time: now-1d (now minus one day) Several time units can be combined together, "
"such as -5mon1w2d</li>\n"
"<li>Seconds since epoch: 1110286800 (this specific value is equivalent to "
"Tue 08 Mar 2005 07:00:00 AM CST</li>\n"
"</ul>\n"
"<p>Don't bother trying to break these - we just pass it through to rrdtool. If you want to "
"play, there are a thousand lines in parsetime.c just waiting for you.</p>\n"
"<p><i>A note about RRD files</i>: You may remember that the rrd file contains data stored "
"at different resolutions - for ntop this is typically every 5 minutes, hourly, and daily. "
"rrdfetch automatically picks the RRA (Round-Robin Archive) which provides the 'best' coverage "
"of the time span you request. Thus, if you request a start time which is before the number "
"of 5 minute samples stored in RRA[0], you will 'magically' see the data from RRA[1], the "
"hourly samples. Other than changing the start/end times, there is no way to force rrdfetch "
"to select a specific RRA.</p>\n"
"<p><i>Two notes for the fetch options</i>:</p>\n"
"<p>Counter values are normalized to per-second rates. To get the (approximate) value of a "
"counter for the entire interval, you need to multipy the per-second rate by the number of "
"seconds in the interval (this is the step, reported at the bottom of the output page).</p>\n"
"<p>If start time is left blank, the default is --start end-1d. To force a dump from the "
"earliest detail point in the rrd, use the special value 0.</tr>\n"
"<tr><th align=\"left\" "DARK_BG">Start</th>\n<td align=\"left\">"
"<input name=\"start\" size=\"20\" value=\"");
sendString(startTime);
sendString("\"><br>\n"
"<tr><th align=\"left\" "DARK_BG">End</th>\n<td align=\"left\">"
"<input name=\"end\" size=\"20\" value=\"");
sendString(endTime);
sendString("\"></td></tr>\n"
"<tr><th align=\"center\" "DARK_BG" colspan=\"2\">For graphs only</th></tr>\n"
"<tr><th align=\"left\" "DARK_BG">Legend</th>\n<td align=\"left\">"
"<input name=\"counter\" size=\"64\" value=\"\"><br>\n"
"This is the 'name' of the counter being displayed, e.g. eth1 Mail bytes. "
"It appears at the bottom left as the legend for the colored bars</td></tr>\n"
"<tr><th align=\"left\" "DARK_BG">(optional) Title to appear above the graph</th>\n"
"<td align=\"left\"><input name=\"title\" size=\"128\" value=\"\"></td></tr>\n"
"<tr><td colspan=\"2\" align=\"center\"> <br>");
if(count > 0)
sendString("<input type=submit value=\"Make Request\">");
sendString("<br> </td></tr>\n</table>\n</form>\n</center>\n");
}
/* ****************************** */
static void printRRDPluginTrailer(void) {
printPluginTrailer(NULL,
"<a href=\"http://www.rrdtool.org/\" title=\"rrd home page\">RRDtool</a> "
"was created by "
"<a href=\"http://ee-staff.ethz.ch/~oetiker/\" title=\"Tobi's home page\">"
"Tobi Oetiker</a>");
printHTMLtrailer();
}
/* ****************************** */
static time_t parse_date(char* value) {
/* 2006-07-11 10:06 */
struct tm _tm;
memset(&_tm, 0, sizeof(_tm));
if(sscanf(value, "%d-%d-%d %d:%d",
&_tm.tm_year, &_tm.tm_mon, &_tm.tm_mday, &_tm.tm_hour, &_tm.tm_min) == 5) {
--_tm.tm_mon, _tm.tm_year -= 1900;
return(mktime(&_tm));
} else
return(0);
}
/* ****************************** */
static void handleRRDHTTPrequest(char* url) {
char buf[1024], *strtokState, *mainState, *urlPiece,
rrdKey[64], rrdName[64], rrdTitle[128], rrdCounter[64], startTime[32], endTime[32],
rrdPrefix[32], rrdIP[32], rrdInterface[64], rrdPath[512], mode[32], cluster[32];
u_char action = FLAG_RRD_ACTION_NONE;
char _which;
int _dumpDomains, _dumpFlows, _dumpHosts, _dumpInterfaces, _dumpASs, _enableAberrant,
_dumpMatrix, _dumpDetail, _dumpInterval, _dumpShortInterval, _dumpHours, _dumpDays, _dumpMonths, graphId;
int i, len, idx;
time_t date1 = 0, date2 = 0;
char * _hostsFilter;
#ifndef WIN32
int _dumpPermissions;
#endif
time_t now = time(NULL);
if(initialized == 0)
commonRRDinit();
/* Specialty pages */
if(strncasecmp(url, CONST_RRD_STATISTICS_HTML, strlen(CONST_RRD_STATISTICS_HTML)) == 0) {
statisticsPage();
printRRDPluginTrailer();
return;
} else if(strncasecmp(url, CONST_RRD_ARBGRAPH_HTML, strlen(CONST_RRD_ARBGRAPH_HTML)) == 0) {
arbitraryActionPage();
printRRDPluginTrailer();
return;
}
/* Initial values - remember, for checkboxes these need to be OFF (there's no html UNCHECKED option) */
_dumpDomains=0;
_dumpFlows=0;
_dumpHosts=0;
_dumpInterfaces=0;
_dumpASs=0;
_enableAberrant=0;
_dumpMatrix=0;
_dumpDetail=CONST_RRD_DETAIL_DEFAULT;
_dumpInterval=DEFAULT_RRD_INTERVAL;
_dumpShortInterval=DEFAULT_RRD_SHORT_INTERVAL;
_dumpHours=DEFAULT_RRD_HOURS;
_dumpDays=DEFAULT_RRD_DAYS;
_dumpMonths=DEFAULT_RRD_MONTHS;
_hostsFilter = NULL;
#ifndef WIN32
_dumpPermissions = DEFAULT_RRD_PERMISSIONS;
#endif
_which=0;
memset(&buf, 0, sizeof(buf));
memset(&rrdKey, 0, sizeof(rrdKey));
memset(&rrdName, 0, sizeof(rrdName));
memset(&rrdTitle, 0, sizeof(rrdTitle));
memset(&rrdCounter, 0, sizeof(rrdCounter));
memset(&startTime, 0, sizeof(startTime));
memset(&endTime, 0, sizeof(endTime));
memset(&rrdPrefix, 0, sizeof(rrdPrefix));
memset(&rrdIP, 0, sizeof(rrdIP));
memset(&rrdInterface, 0, sizeof(rrdInterface));
memset(&rrdPath, 0, sizeof(rrdPath));
memset(&mode, 0, sizeof(mode));
memset(&cluster, 0, sizeof(cluster));
safe_snprintf(__FILE__, __LINE__, startTime, sizeof(startTime), "%u", now-12*3600);
safe_snprintf(__FILE__, __LINE__, endTime, sizeof(endTime), "%u", now);
if((url != NULL) && (url[0] != '\0')) {
unescape_url(url);
/* traceEvent(CONST_TRACE_INFO, "RRD: URL=%s", url); */
urlPiece = strtok_r(url, "&", &mainState);
while(urlPiece != NULL) {
char *key, *value;
key = strtok_r(urlPiece, "=", &strtokState);
if(key != NULL) value = strtok_r(NULL, "=", &strtokState); else value = NULL;
/* traceEvent(CONST_TRACE_INFO, "RRD: key(%s)=%s", key, value); */
if(value && key) {
if(strcmp(key, "action") == 0) {
if(strcmp(value, "graph") == 0) action = FLAG_RRD_ACTION_GRAPH;
else if(strcmp(value, CONST_ARBITRARY_RRDREQUEST) == 0) action = FLAG_RRD_ACTION_ARBITRARY;
else if(strcmp(value, "graphSummary") == 0) action = FLAG_RRD_ACTION_GRAPH_SUMMARY;
else if(strcmp(value, "netflowSummary") == 0) action = FLAG_RRD_ACTION_NF_SUMMARY;
else if(strcmp(value, "interfaceSummary") == 0) action = FLAG_RRD_ACTION_IF_SUMMARY;
else if(strcmp(value, "netflowIfSummary") == 0) action = FLAG_RRD_ACTION_NF_IF_SUMMARY;
else if(strcmp(value, "list") == 0) action = FLAG_RRD_ACTION_LIST;
} else if(strcmp(key, "cluster") == 0) {
safe_snprintf(__FILE__, __LINE__, cluster, sizeof(cluster), "%s", value);
} else if(strcmp(key, "key") == 0) {
safe_snprintf(__FILE__, __LINE__, rrdKey, sizeof(rrdKey), "%s", value);
len = strlen(rrdKey);
for(i=0; i<len; i++) if(rrdKey[i] == '+') rrdKey[i] = ' ';
if(strncmp(value, "hosts/", strlen("hosts/")) == 0) {
int plen, ii;
safe_snprintf(__FILE__, __LINE__, rrdPrefix, sizeof(rrdPrefix), "ip_%s_", &value[6]);
plen=strlen(rrdPrefix);
for (ii=0; ii<plen; ii++)
if( (rrdPrefix[ii] == '.') || (rrdPrefix[ii] == '/') )
rrdPrefix[ii]='_';
} else {
rrdPrefix[0] = '\0';
}
} else if(strcmp(key, CONST_ARBITRARY_IP) == 0) {
safe_snprintf(__FILE__, __LINE__, rrdIP, sizeof(rrdIP), "%s", value);
} else if(strcmp(key, CONST_ARBITRARY_INTERFACE) == 0) {
safe_snprintf(__FILE__, __LINE__, rrdInterface, sizeof(rrdInterface), "%s", value);
} else if(strcmp(key, CONST_ARBITRARY_FILE) == 0) {
safe_snprintf(__FILE__, __LINE__, rrdName, sizeof(rrdName), "%s", value);
} else if(strcmp(key, "mode") == 0) {
safe_snprintf(__FILE__, __LINE__, mode, sizeof(mode), "%s", value);
} else if(strcmp(key, "graphId") == 0) {
graphId = atoi(value);
} else if(strcmp(key, "name") == 0) {
safe_snprintf(__FILE__, __LINE__, rrdName, sizeof(rrdName), "%s", value);
len = strlen(rrdName);
for(i=0; i<len; i++) if(rrdName[i] == '+') rrdName[i] = ' ';
} else if(strcmp(key, "counter") == 0) {
safe_snprintf(__FILE__, __LINE__, rrdCounter, sizeof(rrdCounter), "%s", value);
len = strlen(rrdCounter);
for(i=0; i<len; i++) if(rrdCounter[i] == '+') rrdCounter[i] = ' ';
} else if(strcmp(key, "title") == 0) {
unescape(rrdTitle, sizeof(rrdTitle), value);
} else if(strcmp(key, "start") == 0) {
safe_snprintf(__FILE__, __LINE__, startTime, sizeof(startTime), "%s", value);
} else if(strcmp(key, "end") == 0) {
safe_snprintf(__FILE__, __LINE__, endTime, sizeof(endTime), "%s", value);
} else if(strcmp(key, "interval") == 0) {
_dumpInterval = atoi(value);
if(_dumpInterval < 1) _dumpInterval = 1 /* Min 1 second */;
} else if(strcmp(key, "shortinterval") == 0) {
_dumpShortInterval = atoi(value);
if(_dumpShortInterval < 1) _dumpShortInterval = 1 /* Min 1 second */;
} else if(strcmp(key, "days") == 0) {
_dumpDays = atoi(value);
if(_dumpDays < 0) _dumpDays = 0 /* Min none */;
} else if(strcmp(key, "hours") == 0) {
_dumpHours = atoi(value);
if(_dumpHours < 0) _dumpHours = 0 /* Min none */;
} else if(strcmp(key, "months") == 0) {
_dumpMonths = atoi(value);
if(_dumpMonths < 0) _dumpMonths = 0 /* Min none */;
} else if(strcmp(key, "hostsFilter") == 0) {
_hostsFilter = strdup(value);
} else if(strcmp(key, "rrdPath") == 0) {
int vlen = strlen(value)+1;
idx = 0;
vlen -= idx;
if(myGlobals.rrdPath != NULL) free(myGlobals.rrdPath);
myGlobals.rrdPath = (char*)malloc(vlen);
unescape(myGlobals.rrdPath, vlen, &value[idx]);
revertSlashIfWIN32(myGlobals.rrdPath, 0);
storePrefsValue("rrd.rrdPath", myGlobals.rrdPath);
} else if(strcmp(key, "dumpDomains") == 0) {
_dumpDomains = 1;
} else if(strcmp(key, "dumpFlows") == 0) {
_dumpFlows = 1;
} else if(strcmp(key, "dumpDetail") == 0) {
_dumpDetail = atoi(value);
if(_dumpDetail > FLAG_RRD_DETAIL_HIGH) _dumpDetail = FLAG_RRD_DETAIL_HIGH;
if(_dumpDetail < FLAG_RRD_DETAIL_LOW) _dumpDetail = FLAG_RRD_DETAIL_LOW;
} else if(strcmp(key, "dumpHosts") == 0) {
_dumpHosts = 1;
} else if(strcmp(key, "dumpInterfaces") == 0) {
_dumpInterfaces = 1;
} else if(strcmp(key, "dumpASs") == 0) {
_dumpASs = 1;
} else if(strcmp(key, "enableAberrant") == 0) {
_enableAberrant = atoi(value);
} else if(strcmp(key, "dumpMatrix") == 0) {
_dumpMatrix = 1;
#ifndef WIN32
} else if(strcmp(key, "permissions") == 0) {
_dumpPermissions = atoi(value);
if((_dumpPermissions != CONST_RRD_PERMISSIONS_PRIVATE) &&
(_dumpPermissions != CONST_RRD_PERMISSIONS_GROUP) &&
(_dumpPermissions != CONST_RRD_PERMISSIONS_EVERYONE)) {
_dumpPermissions = DEFAULT_RRD_PERMISSIONS;
}
#endif
} else if(strcmp(key, "which") == 0) {
_which = value[0];
} else if(strcmp(key, "date1") == 0) {
date1 = parse_date(value);
} else if(strcmp(key, "date2") == 0) {
date2 = parse_date(value);
}
}
urlPiece = strtok_r(NULL, "&", &mainState);
}
if(date1 > 0) safe_snprintf(__FILE__, __LINE__, startTime, sizeof(startTime), "%d", date1);
if(date2 > 0) safe_snprintf(__FILE__, __LINE__, endTime, sizeof(endTime), "%d", date2);
if(action == FLAG_RRD_ACTION_NONE) {
dumpInterval = _dumpInterval;
if(dumpShortInterval != _dumpShortInterval) {
int devIdx;
dumpShortInterval = _dumpShortInterval;
for(devIdx=0; devIdx<myGlobals.numDevices; devIdx++) {
if((myGlobals.device[devIdx].virtualDevice && (!myGlobals.device[devIdx].sflowGlobals))
|| (!myGlobals.device[devIdx].activeDevice))
continue;
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath),
"%s/interfaces/%s/", myGlobals.spoolPath,
myGlobals.device[devIdx].uniqueIfName);
deleteRRD(rrdPath, "throughput");
}
}
dumpHours = _dumpHours;
dumpDays = _dumpDays;
dumpMonths = _dumpMonths;
/* traceEvent(CONST_TRACE_INFO, "RRD: dumpFlows=%d", dumpFlows); */
dumpDomains=_dumpDomains;
dumpFlows=_dumpFlows;
dumpHosts=_dumpHosts;
dumpInterfaces=_dumpInterfaces;
dumpASs=_dumpASs;
enableAberrant=_enableAberrant;
dumpMatrix=_dumpMatrix;
dumpDetail = _dumpDetail;
#ifndef WIN32
dumpPermissions = _dumpPermissions;
setGlobalPermissions(_dumpPermissions);
#endif
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", dumpInterval);
storePrefsValue("rrd.dataDumpInterval", buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", dumpShortInterval);
storePrefsValue("rrd.dumpShortInterval", buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", dumpHours);
storePrefsValue("rrd.dataDumpHours", buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", dumpDays);
storePrefsValue("rrd.dataDumpDays", buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", dumpMonths);
storePrefsValue("rrd.dataDumpMonths", buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", dumpDomains);
storePrefsValue("rrd.dataDumpDomains", buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", dumpFlows);
storePrefsValue("rrd.dataDumpFlows", buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", dumpHosts);
storePrefsValue("rrd.dataDumpHosts", buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", dumpInterfaces);
storePrefsValue("rrd.dataDumpInterfaces", buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", dumpASs);
storePrefsValue("rrd.dumpASs", buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", enableAberrant);
storePrefsValue("rrd.enableAberrant", buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", dumpMatrix);
storePrefsValue("rrd.dataDumpMatrix", buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", dumpDetail);
storePrefsValue("rrd.dataDumpDetail", buf);
if(_hostsFilter != NULL) {
if(hostsFilter != NULL) free(hostsFilter);
hostsFilter = _hostsFilter;
_hostsFilter = NULL;
}
storePrefsValue("rrd.hostsFilter", hostsFilter);
#ifndef WIN32
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", dumpPermissions);
storePrefsValue("rrd.permissions", buf);
umask(myGlobals.rrdUmask);
#ifdef RRD_DEBUG
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: Mask for new directories set to %04o",
myGlobals.rrdDirectoryPermissions);
traceEvent(CONST_TRACE_INFO, "RRD_DEBUG: Mask for new files set to %04o",
myGlobals.rrdUmask);
#endif
#endif
shownCreate=0;
}
}
/* traceEvent(CONST_TRACE_INFO, "RRD: action=%d", action); */
if(action == FLAG_RRD_ACTION_GRAPH) {
graphCounter(rrdKey, rrdName, NULL, rrdCounter, startTime, endTime, rrdPrefix);
return;
} else if(action == FLAG_RRD_ACTION_ARBITRARY) {
arbitraryAction(rrdName, rrdInterface, rrdIP, startTime, endTime, rrdCounter, rrdTitle, _which, mode);
return;
} else if(action == FLAG_RRD_ACTION_GRAPH_SUMMARY) {
graphSummary(rrdKey, rrdName, graphId, startTime, endTime, rrdPrefix, mode);
return;
} else if(action == FLAG_RRD_ACTION_NF_SUMMARY) {
netflowSummary(rrdKey, graphId, startTime, endTime, rrdPrefix, mode);
return;
} else if((action == FLAG_RRD_ACTION_NF_IF_SUMMARY) || (action == FLAG_RRD_ACTION_IF_SUMMARY)) {
interfaceSummary(rrdKey, graphId, startTime, endTime, rrdPrefix, mode);
return;
} else if(action == FLAG_RRD_ACTION_LIST) {
listResource(rrdKey, rrdTitle, cluster[0] != '\0' ? cluster : NULL, startTime, endTime);
return;
}
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
printHTMLheader("RRD Preferences", NULL, 0);
if(active == 1)
sendString("<p>You must restart the rrd plugin for changes here to take affect.</p>\n");
else
sendString("<p>Changes here will take effect when the plugin is started.</p>\n");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<center><form action=\"/" CONST_PLUGINS_HEADER "%s\" method=GET>\n"
"<table border=\"1\" width=\"80%%\" "TABLE_DEFAULTS">\n"
"<tr><th align=\"center\" "DARK_BG">Item</th>"
"<th align=\"center\" "DARK_BG">Description and Notes</th></tr>\n"
"<tr><th align=\"left\" "DARK_BG">Dump Interval</th><td>"
"<INPUT NAME=interval SIZE=5 VALUE=",
rrdPluginInfo->pluginURLname);
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", (int)dumpInterval);
sendString(buf);
sendString("> seconds<br>Specifies how often data is stored permanently.</td></tr>\n");
sendString("<tr><th align=\"left\" "DARK_BG">Throughput Granularity</th><td>"
"<INPUT NAME=shortinterval SIZE=5 VALUE=");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", (int)dumpShortInterval);
sendString(buf);
sendString("> seconds<br>Specifies how often <A HREF=/"CONST_SORT_DATA_THPT_STATS_HTML">throughput</A> data is stored permanently.<br>"
"<FONT COLOR=red><b>Note</b></FONT>: if you change this value the throughput stats will be reset "
"and past values will be lost. You've been warned!</td></tr>\n");
sendString("<tr><th align=\"left\" "DARK_BG">Dump Hours</th><td>"
"<INPUT NAME=hours SIZE=5 VALUE=");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", (int)dumpHours);
sendString(buf);
sendString("><br>Specifies how many hours of 'interval' data is stored permanently.</td></tr>\n");
sendString("<tr><th align=\"left\" "DARK_BG">Dump Days</th><td>"
"<INPUT NAME=days SIZE=5 VALUE=");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", (int)dumpDays);
sendString(buf);
sendString("><br>Specifies how many days of hourly data is stored permanently.</td></tr>\n");
sendString("<tr><th align=\"left\" "DARK_BG">Dump Months</th><td>"
"<INPUT NAME=months SIZE=5 VALUE=");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", (int)dumpMonths);
sendString(buf);
sendString("><br>Specifies how many months (30 days) of daily data is stored permanently.</td></tr>\n");
sendString("<tr><td align=\"center\" COLSPAN=2><B>WARNING:</B> "
"Changes to the above values will ONLY affect NEW rrds</td></tr>");
sendString("<tr><th align=\"left\" "DARK_BG">RRD Update Delay</th><td>"
"<INPUT NAME=delay, SIZE=5 VALUE=");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%d", (int)dumpDelay);
sendString(buf);
sendString("><br>Specifies how many ms to wait between two consecutive RRD updates. Increase this value to distribute RRD load on I/O over the time. Note that a combination of large delays and many RRDs to update can slow down the RRD plugin performance</td></tr>\n");
sendString("<tr><th align=\"left\" "DARK_BG">Data to Dump</th><td>");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<INPUT TYPE=checkbox NAME=dumpDomains VALUE=1 %s> Domains<br>\n",
dumpDomains ? "CHECKED" : "" );
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<INPUT TYPE=checkbox NAME=dumpFlows VALUE=1 %s> Flows<br>\n",
dumpFlows ? "CHECKED" : "" );
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<INPUT TYPE=checkbox NAME=dumpHosts VALUE=1 %s> Hosts<br>\n",
dumpHosts ? "CHECKED" : "");
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<INPUT TYPE=checkbox NAME=dumpInterfaces VALUE=1 %s> Interfaces<br>\n",
dumpInterfaces ? "CHECKED" : "");
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<INPUT TYPE=checkbox NAME=dumpASs VALUE=1 %s> ASs<br>\n",
dumpASs ? "CHECKED" : "");
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<INPUT TYPE=checkbox NAME=dumpMatrix VALUE=1 %s> Matrix<br>\n",
dumpMatrix ? "CHECKED" : "");
sendString(buf);
sendString("</td></tr>\n");
if(dumpHosts) {
sendString("<tr><th align=\"left\" "DARK_BG">Hosts Filter</th><td>"
"<INPUT NAME=hostsFilter VALUE=\"");
sendString(hostsFilter);
sendString("\" SIZE=80><br>A list of networks [e.g. 172.22.0.0/255.255.0.0,192.168.5.0/255.255.255.0]<br>"
"separated by commas to which hosts that will be<br>"
"saved must belong to. An empty list means that all the hosts will "
"be stored on disk</td></tr>\n");
}
/* ******************************** */
sendString("<tr><th align=\"left\" "DARK_BG">RRD Detail</th><td>");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<INPUT TYPE=radio NAME=dumpDetail VALUE=%d %s>Low\n",
FLAG_RRD_DETAIL_LOW, (dumpDetail == FLAG_RRD_DETAIL_LOW) ? "CHECKED" : "");
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<INPUT TYPE=radio NAME=dumpDetail VALUE=%d %s>Medium\n",
FLAG_RRD_DETAIL_MEDIUM, (dumpDetail == FLAG_RRD_DETAIL_MEDIUM) ? "CHECKED" : "");
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<INPUT TYPE=radio NAME=dumpDetail VALUE=%d %s>Full\n",
FLAG_RRD_DETAIL_HIGH, (dumpDetail == FLAG_RRD_DETAIL_HIGH) ? "CHECKED" : "");
sendString(buf);
sendString("</td></tr>\n");
/* ******************************** */
sendString("<tr><th align=\"left\" "DARK_BG">Detect Anomalies</th><td>");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<INPUT TYPE=radio NAME=enableAberrant VALUE=1 %s>Yes\n",
(enableAberrant == 1) ? "CHECKED" : "");
sendString(buf);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<INPUT TYPE=radio NAME=enableAberrant VALUE=0 %s>No\n",
(enableAberrant == 0) ? "CHECKED" : "");
sendString(buf);
sendString("<br>Toggle RRD <A HREF=http://cricket.sourceforge.net/aberrant/rrd_hw.htm>Aberrant Behavior</A> support");
sendString("</td></tr>\n");
/* ******************************** */
sendString("<tr><th align=\"left\" "DARK_BG">RRD Files Path</th><td>"
"<INPUT NAME=rrdPath SIZE=50 VALUE=\"");
sendString(myGlobals.rrdPath);
sendString("\">");
sendString("<br>NOTE:<ul><li>The rrd files will be in a subdirectory structure, e.g.\n");
#ifdef WIN32
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"%s\\interfaces\\interface-name\\12\\239\\98\\199\\xxxxx.rrd ",
myGlobals.rrdPath);
#else
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"%s/interfaces/interface-name/12/239/98/199/xxxxx.rrd ",
myGlobals.rrdPath);
#endif
sendString(buf);
sendString("to limit the number of files per subdirectory.");
sendString("<li>Do not use the ':' character in the path as it is forbidded by rrd</ul></td></tr>\n");
#ifndef WIN32
sendString("<tr><th align=\"left\" "DARK_BG">File/Directory Permissions</th><td>");
sendString("<ul>\n");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<li><INPUT TYPE=radio NAME=permissions VALUE=%d %s>Private - ",
CONST_RRD_PERMISSIONS_PRIVATE,
(dumpPermissions == CONST_RRD_PERMISSIONS_PRIVATE) ? "CHECKED" : "");
sendString(buf);
sendString("means that ONLY the ntop userid will be able to view the files</li>\n");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<li><INPUT TYPE=radio NAME=permissions VALUE=%d %s>Group - ",
CONST_RRD_PERMISSIONS_GROUP,
(dumpPermissions == CONST_RRD_PERMISSIONS_GROUP) ? "CHECKED" : "");
sendString(buf);
sendString("means that all users in the same group as the ntop userid will be able to view the rrd files.\n");
sendString("<br><i>(this is a bad choice if ntop's group is 'nobody' along with many other service ids)</i></li>\n");
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "<li><INPUT TYPE=radio NAME=permissions VALUE=%d %s>Everyone - ",
CONST_RRD_PERMISSIONS_EVERYONE,
(dumpPermissions == CONST_RRD_PERMISSIONS_EVERYONE) ? "CHECKED" : "");
sendString(buf);
sendString("means that everyone on the ntop host system will be able to view the rrd files.</li>\n");
sendString("</ul><br>\n<B>WARNING</B>: Changing this setting affects only new files "
"and directories! "
"<i>Unless you go back and fixup existing file and directory permissions:</i><br>\n"
"<ul><li>Users will retain access to any rrd file or directory they currently have "
"access to even if you change to a more restrictive setting.</li>\n"
"<li>Users will not gain access to any rrd file or directory they currently do not "
"have access to even if you change to a less restrictive setting. Further, existing "
"directory permissions may prevent them from reading new files created in existing "
"directories.</li>\n"
"</ul>\n</td></tr>\n");
#endif
sendString("<tr><td colspan=\"2\" align=\"center\"> <br><input type=submit value=\"Save Preferences\"><br> </td></tr>\n"
"</table>\n</form>\n</center>\n");
sendString("<hr>\n<p>Also:</p>\n<ul>");
for(i=0; rrdExtraPages[i].url != NULL; i++) {
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf),
"<li><a href=\"/" CONST_PLUGINS_HEADER "%s/%s\">%s</a></li>\n",
rrdPluginInfo->pluginURLname,
rrdExtraPages[i].url,
rrdExtraPages[i].descr);
sendString(buf);
}
sendString("</ul>\n");
printRRDPluginTrailer();
}
/* ****************************** */
#ifdef MAKE_WITH_RRDSIGTRAP
RETSIGTYPE rrdcleanup(int signo) {
static int msgSent = 0;
int i;
void *array[20];
size_t size;
char **strings;
if(msgSent<10) {
traceEvent(CONST_TRACE_FATALERROR, "RRD: caught signal %d %s", signo,
signo == SIGHUP ? "SIGHUP" :
signo == SIGINT ? "SIGINT" :
signo == SIGQUIT ? "SIGQUIT" :
signo == SIGILL ? "SIGILL" :
signo == SIGABRT ? "SIGABRT" :
signo == SIGFPE ? "SIGFPE" :
signo == SIGKILL ? "SIGKILL" :
signo == SIGSEGV ? "SIGSEGV" :
signo == SIGPIPE ? "SIGPIPE" :
signo == SIGALRM ? "SIGALRM" :
signo == SIGTERM ? "SIGTERM" :
signo == SIGUSR1 ? "SIGUSR1" :
signo == SIGUSR2 ? "SIGUSR2" :
signo == SIGCHLD ? "SIGCHLD" :
#ifdef SIGCONT
signo == SIGCONT ? "SIGCONT" :
#endif
#ifdef SIGSTOP
signo == SIGSTOP ? "SIGSTOP" :
#endif
#ifdef SIGBUS
signo == SIGBUS ? "SIGBUS" :
#endif
#ifdef SIGSYS
signo == SIGSYS ? "SIGSYS"
#endif
: "other");
msgSent++;
}
#ifdef HAVE_BACKTRACE
/* Don't double fault... */
/* signal(signo, SIG_DFL); */
/* Grab the backtrace before we do much else... */
size = backtrace(array, 20);
strings = (char**)backtrace_symbols(array, size);
traceEvent(CONST_TRACE_ERROR, "RRD: BACKTRACE: backtrace is:");
if(size < 2) {
traceEvent(CONST_TRACE_ERROR, "RRD: BACKTRACE: **unavailable!");
} else {
/* Ignore the 0th entry, that's our cleanup() */
for (i=1; i<size; i++) {
traceEvent(CONST_TRACE_ERROR, "RRD: BACKTRACE: %2d. %s", i, strings[i]);
}
}
#endif /* HAVE_BACKTRACE */
traceEvent(CONST_TRACE_FATALERROR, "RRD: ntop shutting down...");
exit(101);
}
#endif /* MAKE_WITH_RRDSIGTRAP */
/* ****************************** */
static void rrdUpdateIPHostStats (HostTraffic *el, int devIdx) {
char value[512 /* leave it big for hosts filter */];
u_int32_t networks[32][4];
u_short numLocalNets;
int idx;
char rrdPath[512];
char *adjHostName;
ProtocolsList *protoList;
char *hostKey;
int j;
if((el == myGlobals.otherHostEntry) || (el == myGlobals.broadcastEntry)
|| broadcastHost(el) || (myGlobals.runningPref.trackOnlyLocalHosts &&
(!subnetPseudoLocalHost(el)))) {
return;
}
/* ********************************************* */
numLocalNets = 0;
/* Avoids strtok to blanks into hostsFilter */
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s", hostsFilter);
handleAddressLists(rrdPath, networks, &numLocalNets, value, sizeof(value), CONST_HANDLEADDRESSLISTS_RRD);
/* ********************************************* */
if((el->bytesSent.value > 0) || (el->bytesRcvd.value > 0)) {
if(el->hostNumIpAddress[0] != '\0') {
hostKey = el->hostNumIpAddress;
if((numLocalNets > 0)
&& (el->hostIpAddress.hostFamily == AF_INET) /* IPv4 ONLY <-- FIX */
&& (!__pseudoLocalAddress(&el->hostIpAddress.Ip4Address, networks, numLocalNets, NULL, NULL))) {
return;
}
if((!myGlobals.runningPref.dontTrustMACaddr)
&& subnetPseudoLocalHost(el)
&& (el->ethAddressString[0] != '\0'))
/*
NOTE:
MAC address is empty even for local hosts if this host has
been learnt on a virtual interface such as the NetFlow interface
*/
hostKey = el->ethAddressString;
} else {
/* For the time being do not save IP-less hosts */
return;
}
adjHostName = dotToSlash(hostKey);
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s/hosts/%s/",
myGlobals.rrdPath, myGlobals.device[devIdx].uniqueIfName,
adjHostName);
mkdir_p("RRD", rrdPath, myGlobals.rrdDirectoryPermissions);
traceEventRRDebug(2, "Updating %s [%s/%s]", hostKey, el->hostNumIpAddress, el->ethAddressString);
updateTrafficCounter(rrdPath, "pktSent", &el->pktSent, 0);
updateTrafficCounter(rrdPath, "pktRcvd", &el->pktRcvd, 0);
updateTrafficCounter(rrdPath, "bytesSent", &el->bytesSent, 0);
updateTrafficCounter(rrdPath, "bytesRcvd", &el->bytesRcvd, 0);
if(dumpDetail >= FLAG_RRD_DETAIL_MEDIUM) {
updateTrafficCounter(rrdPath, "pktDuplicatedAckSent", &el->pktDuplicatedAckSent, 0);
updateTrafficCounter(rrdPath, "pktDuplicatedAckRcvd", &el->pktDuplicatedAckRcvd, 0);
updateTrafficCounter(rrdPath, "pktBroadcastSent", &el->pktBroadcastSent, 0);
updateTrafficCounter(rrdPath, "bytesBroadcastSent", &el->bytesBroadcastSent, 0);
updateTrafficCounter(rrdPath, "pktMulticastSent", &el->pktMulticastSent, 0);
updateTrafficCounter(rrdPath, "bytesMulticastSent", &el->bytesMulticastSent, 0);
updateTrafficCounter(rrdPath, "pktMulticastRcvd", &el->pktMulticastRcvd, 0);
updateTrafficCounter(rrdPath, "bytesMulticastRcvd", &el->bytesMulticastRcvd, 0);
updateTrafficCounter(rrdPath, "bytesLocSent", &el->bytesSentLoc, 0);
updateTrafficCounter(rrdPath, "bytesRemSent", &el->bytesSentRem, 0);
updateTrafficCounter(rrdPath, "bytesLocRcvd", &el->bytesRcvdLoc, 0);
updateTrafficCounter(rrdPath, "bytesFromRemRcvd", &el->bytesRcvdFromRem, 0);
updateTrafficCounter(rrdPath, "ipBytesSent", &el->ipBytesSent, 0);
updateTrafficCounter(rrdPath, "ipBytesRcvd", &el->ipBytesRcvd, 0);
updateTrafficCounter(rrdPath, "tcpLocSent", &el->tcpSentLoc, 0);
updateTrafficCounter(rrdPath, "tcpRemSent", &el->tcpSentRem, 0);
updateTrafficCounter(rrdPath, "udpLocSent", &el->udpSentLoc, 0);
updateTrafficCounter(rrdPath, "udpRemSent", &el->udpSentRem, 0);
updateTrafficCounter(rrdPath, "icmpSent", &el->icmpSent, 0);
updateTrafficCounter(rrdPath, "tcpLocRcvd", &el->tcpRcvdLoc, 0);
updateTrafficCounter(rrdPath, "tcpFromRemRcvd", &el->tcpRcvdFromRem, 0);
updateTrafficCounter(rrdPath, "udpLocRcvd", &el->udpRcvdLoc, 0);
updateTrafficCounter(rrdPath, "udpFromRemRcvd", &el->udpRcvdFromRem, 0);
updateTrafficCounter(rrdPath, "icmpRcvd", &el->icmpRcvd, 0);
updateTrafficCounter(rrdPath, "tcpFragmentsSent", &el->tcpFragmentsSent, 0);
updateTrafficCounter(rrdPath, "tcpFragmentsRcvd", &el->tcpFragmentsRcvd, 0);
updateTrafficCounter(rrdPath, "udpFragmentsSent", &el->udpFragmentsSent, 0);
updateTrafficCounter(rrdPath, "udpFragmentsRcvd", &el->udpFragmentsRcvd, 0);
updateTrafficCounter(rrdPath, "icmpFragmentsSent", &el->icmpFragmentsSent, 0);
updateTrafficCounter(rrdPath, "icmpFragmentsRcvd", &el->icmpFragmentsRcvd, 0);
updateTrafficCounter(rrdPath, "ipv6Sent", &el->ipv6Sent, 0);
updateTrafficCounter(rrdPath, "ipv6Rcvd", &el->ipv6Rcvd, 0);
if(el->nonIPTraffic) {
updateTrafficCounter(rrdPath, "stpSent", &el->nonIPTraffic->stpSent, 0);
updateTrafficCounter(rrdPath, "stpRcvd", &el->nonIPTraffic->stpRcvd, 0);
updateTrafficCounter(rrdPath, "ipxSent", &el->nonIPTraffic->ipxSent, 0);
updateTrafficCounter(rrdPath, "ipxRcvd", &el->nonIPTraffic->ipxRcvd, 0);
updateTrafficCounter(rrdPath, "osiSent", &el->nonIPTraffic->osiSent, 0);
updateTrafficCounter(rrdPath, "osiRcvd", &el->nonIPTraffic->osiRcvd, 0);
updateTrafficCounter(rrdPath, "dlcSent", &el->nonIPTraffic->dlcSent, 0);
updateTrafficCounter(rrdPath, "dlcRcvd", &el->nonIPTraffic->dlcRcvd, 0);
updateTrafficCounter(rrdPath, "arp_rarpSent", &el->nonIPTraffic->arp_rarpSent, 0);
updateTrafficCounter(rrdPath, "arp_rarpRcvd", &el->nonIPTraffic->arp_rarpRcvd, 0);
updateTrafficCounter(rrdPath, "arpReqPktsSent", &el->nonIPTraffic->arpReqPktsSent, 0);
updateTrafficCounter(rrdPath, "arpReplyPktsSent", &el->nonIPTraffic->arpReplyPktsSent, 0);
updateTrafficCounter(rrdPath, "arpReplyPktsRcvd", &el->nonIPTraffic->arpReplyPktsRcvd, 0);
updateTrafficCounter(rrdPath, "decnetSent", &el->nonIPTraffic->decnetSent, 0);
updateTrafficCounter(rrdPath, "decnetRcvd", &el->nonIPTraffic->decnetRcvd, 0);
updateTrafficCounter(rrdPath, "appletalkSent", &el->nonIPTraffic->appletalkSent, 0);
updateTrafficCounter(rrdPath, "appletalkRcvd", &el->nonIPTraffic->appletalkRcvd, 0);
updateTrafficCounter(rrdPath, "netbiosSent", &el->nonIPTraffic->netbiosSent, 0);
updateTrafficCounter(rrdPath, "netbiosRcvd", &el->nonIPTraffic->netbiosRcvd, 0);
updateTrafficCounter(rrdPath, "otherSent", &el->nonIPTraffic->otherSent, 0);
updateTrafficCounter(rrdPath, "otherRcvd", &el->nonIPTraffic->otherRcvd, 0);
}
protoList = myGlobals.ipProtosList, idx=0;
while(protoList != NULL) {
char buf[64];
if(el->ipProtosList[idx] != NULL) {
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%sSent", protoList->protocolName);
updateTrafficCounter(rrdPath, buf, &el->ipProtosList[idx]->sent, 0);
safe_snprintf(__FILE__, __LINE__, buf, sizeof(buf), "%sRcvd", protoList->protocolName);
updateTrafficCounter(rrdPath, buf, &el->ipProtosList[idx]->rcvd, 0);
}
idx++, protoList = protoList->next;
}
}
if(dumpDetail == FLAG_RRD_DETAIL_HIGH) {
updateCounter(rrdPath, "totPeersSent", el->totContactedSentPeers, 0);
updateCounter(rrdPath, "totPeersRcvd", el->totContactedRcvdPeers, 0);
if(el->protoIPTrafficInfos) {
traceEventRRDebug(0, "Updating host %s", hostKey);
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s/hosts/%s/IP_",
myGlobals.rrdPath,
myGlobals.device[devIdx].uniqueIfName,
adjHostName
);
for(j=0; j<myGlobals.numIpProtosToMonitor; j++) {
if(el->protoIPTrafficInfos[j]) {
char key[128];
if(el->protoIPTrafficInfos[j] != NULL) {
safe_snprintf(__FILE__, __LINE__, key, sizeof(key), "%sBytesSent",
myGlobals.ipTrafficProtosNames[j]);
updateCounter(rrdPath, key, el->protoIPTrafficInfos[j]->sentLoc.value+
el->protoIPTrafficInfos[j]->sentRem.value, 0);
safe_snprintf(__FILE__, __LINE__, key, sizeof(key), "%sBytesRcvd",
myGlobals.ipTrafficProtosNames[j]);
updateCounter(rrdPath, key, el->protoIPTrafficInfos[j]->rcvdLoc.value+
el->protoIPTrafficInfos[j]->rcvdFromRem.value, 0);
}
}
}
}
}
if(adjHostName != NULL)
free(adjHostName);
}
ntop_conditional_sched_yield(); /* Allow other threads to run */
return;
}
/* ****************************** */
static void rrdUpdateFcHostStats (HostTraffic *el, int devIdx) {
char rrdPath[512];
char *adjHostName;
char hostKey[128];
lockHostsHashMutex(el, "rrdUpdateFcHostStats");
if((el->bytesSent.value > 0) || (el->bytesRcvd.value > 0)) {
if(el->fcCounters->hostNumFcAddress[0] != '\0') {
safe_snprintf(__FILE__, __LINE__, hostKey, sizeof (hostKey), "%s-%d",
el->fcCounters->hostNumFcAddress,
el->fcCounters->vsanId);
} else {
/* For the time being do not save IP-less hosts */
unlockHostsHashMutex(el);
return;
}
adjHostName = dotToSlash(hostKey);
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s/hosts/%s/",
myGlobals.rrdPath, myGlobals.device[devIdx].uniqueIfName,
adjHostName);
mkdir_p("RRD", rrdPath, myGlobals.rrdDirectoryPermissions);
traceEventRRDebug(2, "Updating %s [%s/%d]", hostKey, el->fcCounters->hostNumFcAddress, el->fcCounters->vsanId);
updateTrafficCounter(rrdPath, "pktSent", &el->pktSent, 0);
updateTrafficCounter(rrdPath, "pktRcvd", &el->pktRcvd, 0);
updateTrafficCounter(rrdPath, "bytesSent", &el->bytesSent, 0);
updateTrafficCounter(rrdPath, "bytesRcvd", &el->bytesRcvd, 0);
if(dumpDetail >= FLAG_RRD_DETAIL_MEDIUM) {
updateTrafficCounter(rrdPath, "fcFcpBytesSent", &el->fcCounters->fcFcpBytesSent, 0);
updateTrafficCounter(rrdPath, "fcFcpBytesRcvd", &el->fcCounters->fcFcpBytesRcvd, 0);
updateTrafficCounter(rrdPath, "fcFiconBytesSent", &el->fcCounters->fcFiconBytesSent, 0);
updateTrafficCounter(rrdPath, "fcFiconBytesRcvd", &el->fcCounters->fcFiconBytesRcvd, 0);
updateTrafficCounter(rrdPath, "fcElsBytesSent", &el->fcCounters->fcElsBytesSent, 0);
updateTrafficCounter(rrdPath, "fcElsBytesRcvd", &el->fcCounters->fcElsBytesRcvd, 0);
updateTrafficCounter(rrdPath, "fcDnsBytesSent", &el->fcCounters->fcDnsBytesSent, 0);
updateTrafficCounter(rrdPath, "fcDnsBytesRcvd", &el->fcCounters->fcDnsBytesRcvd, 0);
updateTrafficCounter(rrdPath, "fcSwilsBytesSent", &el->fcCounters->fcSwilsBytesSent, 0);
updateTrafficCounter(rrdPath, "fcSwilsBytesRcvd", &el->fcCounters->fcSwilsBytesRcvd, 0);
updateTrafficCounter(rrdPath, "fcIpfcBytesSent", &el->fcCounters->fcIpfcBytesSent, 0);
updateTrafficCounter(rrdPath, "fcIpfcBytesRcvd", &el->fcCounters->fcIpfcBytesRcvd, 0);
updateTrafficCounter(rrdPath, "otherFcBytesSent", &el->fcCounters->otherFcBytesSent, 0);
updateTrafficCounter(rrdPath, "otherFcBytesRcvd", &el->fcCounters->otherFcBytesRcvd, 0);
updateTrafficCounter(rrdPath, "fcRscnsRcvd", &el->fcCounters->fcRscnsRcvd, 0);
updateTrafficCounter(rrdPath, "scsiReadBytes", &el->fcCounters->scsiReadBytes, 0);
updateTrafficCounter(rrdPath, "scsiWriteBytes", &el->fcCounters->scsiWriteBytes, 0);
updateTrafficCounter(rrdPath, "scsiOtherBytes", &el->fcCounters->scsiOtherBytes, 0);
updateTrafficCounter(rrdPath, "class2Sent", &el->fcCounters->class2Sent, 0);
updateTrafficCounter(rrdPath, "class2Rcvd", &el->fcCounters->class2Rcvd, 0);
updateTrafficCounter(rrdPath, "class3Sent", &el->fcCounters->class3Sent, 0);
updateTrafficCounter(rrdPath, "class3Rcvd", &el->fcCounters->class3Rcvd, 0);
updateTrafficCounter(rrdPath, "classFSent", &el->fcCounters->classFSent, 0);
updateTrafficCounter(rrdPath, "classFRcvd", &el->fcCounters->classFRcvd, 0);
}
if(dumpDetail == FLAG_RRD_DETAIL_HIGH) {
updateCounter(rrdPath, "totContactedPeersSent", el->totContactedSentPeers, 0);
updateCounter(rrdPath, "totContactedPeersRcvd", el->totContactedRcvdPeers, 0);
}
if(adjHostName != NULL)
free(adjHostName);
}
unlockHostsHashMutex(el);
ntop_conditional_sched_yield(); /* Allow other threads to run */
return;
}
/* ****************************** */
static void* rrdTrafficThreadLoop(void* notUsed _UNUSED_) {
traceEvent(CONST_TRACE_INFO,
"THREADMGMT[t%lu]: RRD: Throughput data collection: Thread starting [p%d]",
pthread_self(), getpid());
ntopSleepUntilStateRUN();
traceEvent(CONST_TRACE_INFO,
"THREADMGMT[t%lu]: RRD: Throughput data collection: Thread running [p%d]",
pthread_self(), getpid());
for(;myGlobals.ntopRunState <= FLAG_NTOPSTATE_RUN;) {
int devIdx;
char rrdPath[512];
ntopSleepWhileSameState(dumpShortInterval);
if(myGlobals.ntopRunState > FLAG_NTOPSTATE_RUN) {
traceEvent(CONST_TRACE_INFO,
"THREADMGMT[t%lu]: RRD: Throughput data collection: Thread stopping [p%d] State>RUN",
pthread_self(), getpid());
break;
}
rrdTime = time(NULL);
for(devIdx=0; devIdx<myGlobals.numDevices; devIdx++) {
if((myGlobals.device[devIdx].virtualDevice && (!myGlobals.device[devIdx].sflowGlobals))
|| (!myGlobals.device[devIdx].activeDevice))
continue;
#ifdef WIN32
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/%u/interfaces/%s/",
myGlobals.spoolPath, driveSerial,
myGlobals.device[devIdx].uniqueIfName);
#else
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s/",
myGlobals.spoolPath,
myGlobals.device[devIdx].uniqueIfName);
#endif
mkdir_p("RRD", rrdPath, myGlobals.rrdDirectoryPermissions);
updateCounter(rrdPath, "throughput", myGlobals.device[devIdx].ethernetBytes.value*8, 1);
/* traceEvent(CONST_TRACE_INFO, "RRD: [idx=%d][%lu]", devIdx, c); */
}
}
rrdTrafficThread = 0;
traceEvent(CONST_TRACE_INFO,
"THREADMGMT[t%lu]: RRD: Throughput data collection: Thread terminated [p%d]",
pthread_self(), getpid());
return(NULL);
}
/* ****************************** */
static void* rrdMainLoop(void* notUsed _UNUSED_) {
char value[512 /* leave it big for hosts filter */],
rrdPath[512],
dname[256],
endTime[32];
int i, j, sleep_tm, devIdx, idx;
u_int32_t networks[32][4];
u_short numLocalNets;
ProtocolsList *protoList;
struct tm workT;
struct timeval rrdStartOfCycle,
rrdEndOfCycle;
float elapsed;
traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: RRD: Data collection thread starting [p%d]",
pthread_self(), getpid());
#ifdef MAKE_WITH_RRDSIGTRAP
signal(SIGSEGV, rrdcleanup);
signal(SIGHUP, rrdcleanup);
signal(SIGINT, rrdcleanup);
signal(SIGQUIT, rrdcleanup);
signal(SIGILL, rrdcleanup);
signal(SIGABRT, rrdcleanup);
signal(SIGFPE, rrdcleanup);
signal(SIGKILL, rrdcleanup);
signal(SIGPIPE, rrdcleanup);
signal(SIGALRM, rrdcleanup);
signal(SIGTERM, rrdcleanup);
signal(SIGUSR1, rrdcleanup);
signal(SIGUSR2, rrdcleanup);
/* signal(SIGCHLD, rrdcleanup); */
#ifdef SIGCONT
signal(SIGCONT, rrdcleanup);
#endif
#ifdef SIGSTOP
signal(SIGSTOP, rrdcleanup);
#endif
#ifdef SIGBUS
signal(SIGBUS, rrdcleanup);
#endif
#ifdef SIGSYS
signal(SIGSYS, rrdcleanup);
#endif
#endif /* MAKE_WITH_RRDSIGTRAP */
/* Wait until the main thread changed privileges */
sleep(10);
active = 1; /* Show we are running */
safe_snprintf(__FILE__, __LINE__, dname, sizeof(dname), "%s", myGlobals.rrdPath);
if(ntop_mkdir(dname, myGlobals.rrdDirectoryPermissions) == -1) {
if(errno != EEXIST) {
traceEvent(CONST_TRACE_ERROR, "RRD: Disabled - unable to create base directory (err %d, %s)",
errno, dname);
setPluginStatus("Disabled - unable to create rrd base directory.");
/* Return w/o creating the rrd thread ... disabled */
return(NULL);
}
} else {
traceEvent(CONST_TRACE_INFO, "RRD: Created base directory (%s)", dname);
}
for (i=0; i<sizeof(rrd_subdirs)/sizeof(rrd_subdirs[0]); i++) {
safe_snprintf(__FILE__, __LINE__, dname, sizeof(dname), "%s/%s", myGlobals.rrdPath, rrd_subdirs[i]);
revertSlashIfWIN32(dname, 0);
if(ntop_mkdir(dname, myGlobals.rrdDirectoryPermissions) == -1) {
if(errno != EEXIST) {
traceEvent(CONST_TRACE_ERROR, "RRD: Disabled - unable to create directory (err %d, %s)", errno, dname);
setPluginStatus("Disabled - unable to create rrd subdirectory.");
/* Return w/o creating the rrd thread ... disabled */
return(NULL);
}
} else {
traceEvent(CONST_TRACE_INFO, "RRD: Created directory (%s)", dname);
}
}
if(initialized == 0)
commonRRDinit();
/* Initialize the "end" of the dummy interval just far enough back in time
so that it expires once everything is up and running. */
end_tm = myGlobals.actTime - dumpInterval + 15;
createThread(&rrdTrafficThread, rrdTrafficThreadLoop, NULL);
traceEvent(CONST_TRACE_INFO,
"THREADMGMT[t%lu]: RRD: Started thread for throughput data collection",
rrdTrafficThread);
ntopSleepUntilStateRUN();
traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: RRD: Data collection thread running [p%d]",
pthread_self(), getpid());
for(;myGlobals.ntopRunState <= FLAG_NTOPSTATE_RUN;) {
numRRDCycles++;
do {
end_tm += dumpInterval;
} while (end_tm < (start_tm = time(NULL)));
sleep_tm = end_tm - start_tm;
strftime(endTime, sizeof(endTime), CONST_LOCALE_TIMESPEC, localtime_r(&end_tm, &workT));
traceEventRRDebug(0, "Sleeping for %d seconds (interval %d, end at %s)",
sleep_tm,
dumpInterval,
endTime);
ntopSleepWhileSameState(sleep_tm);
if(myGlobals.ntopRunState >= FLAG_NTOPSTATE_STOPCAP) {
traceEvent(CONST_TRACE_INFO,
"THREADMGMT[t%lu]: RRD: Data collection thread stopping [p%d] %s",
pthread_self(),
getpid(),
myGlobals.ntopRunState > FLAG_NTOPSTATE_RUN ? "State>RUN" : "Plugin inactive");
break;
}
/* Note, if this is stopcap, we run 1 more cycle and break out at the end so we don't lose data! */
gettimeofday(&rrdStartOfCycle, NULL);
numRRDUpdates = 0;
numRuns++;
rrdTime = time(NULL);
/* ****************************************************** */
numLocalNets = 0;
/* Avoids strtok to blanks into hostsFilter */
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s", hostsFilter);
handleAddressLists(rrdPath, networks, &numLocalNets, value, sizeof(value),
CONST_HANDLEADDRESSLISTS_RRD);
/* ****************************************************** */
if(dumpDomains) {
DomainStats **stats, *tmpStats, *statsEntry;
u_int maxHosts = 0;
Counter totBytesSent = 0;
Counter totBytesRcvd = 0;
HostTraffic *el;
u_short keyValue=0;
for(devIdx=0; devIdx<myGlobals.numDevices; devIdx++) {
u_int numEntries = 0;
if(!strcmp(myGlobals.device[devIdx].name, "pcap-file")) continue;
if(!strcmp(myGlobals.device[devIdx].name, "none")) continue;
/* save this as it may change */
maxHosts = myGlobals.device[devIdx].hostsno;
tmpStats = (DomainStats*)mallocAndInitWithReportWarn(maxHosts*sizeof(DomainStats), "rrdMainLoop");
if (tmpStats == NULL) {
traceEvent(CONST_TRACE_WARNING, "RRD: Out of memory, skipping domain RRD dumps");
continue;
}
stats = (DomainStats**)mallocAndInitWithReportWarn(maxHosts*sizeof(DomainStats*),"rrdMainLoop(2)");
if (stats == NULL) {
traceEvent(CONST_TRACE_WARNING, "RRD: Out of memory, skipping domain RRD dumps");
/* before continuing, also free the block of memory allocated a few lines up */
if (tmpStats != NULL) free(tmpStats);
continue;
}
/* walk through all hosts, getting their domain names and counting stats */
for (el = getFirstHost(devIdx);
el != NULL; el = getNextHost(devIdx, el)) {
if (el->l2Family != FLAG_HOST_TRAFFIC_AF_ETH)
continue;
fillDomainName(el);
/* if we didn't get a domain name, bail out */
if ((el->dnsDomainValue == NULL)
|| (el->dnsDomainValue[0] == '\0')
|| (el->ip2ccValue == NULL)
|| (el->hostResolvedName[0] == '\0')
|| broadcastHost(el)
) {
continue;
}
for(keyValue=0, idx=0; el->dnsDomainValue[idx] != '\0'; idx++)
keyValue += (idx+1)*(u_short)el->dnsDomainValue[idx];
keyValue %= maxHosts;
while((stats[keyValue] != NULL)
&& (strcasecmp(stats[keyValue]->domainHost->dnsDomainValue,
el->dnsDomainValue) != 0))
keyValue = (keyValue+1) % maxHosts;
/* if we just start counting for this domain... */
if(stats[keyValue] != NULL)
statsEntry = stats[keyValue];
else {
statsEntry = &tmpStats[numEntries++];
memset(statsEntry, 0, sizeof(DomainStats));
statsEntry->domainHost = el;
stats[keyValue] = statsEntry;
traceEventRRDebug(2, "[%d] %s/%s", numEntries, el->dnsDomainValue, el->ip2ccValue);
}
/* count this host's stats in the domain stats */
totBytesSent += el->bytesSent.value;
statsEntry->bytesSent.value += el->bytesSent.value;
statsEntry->bytesRcvd.value += el->bytesRcvd.value;
totBytesRcvd += el->bytesRcvd.value;
statsEntry->tcpSent.value += el->tcpSentLoc.value + el->tcpSentRem.value;
statsEntry->udpSent.value += el->udpSentLoc.value + el->udpSentRem.value;
statsEntry->icmpSent.value += el->icmpSent.value;
statsEntry->icmp6Sent.value += el->icmp6Sent.value;
statsEntry->tcpRcvd.value += el->tcpRcvdLoc.value + el->tcpRcvdFromRem.value;
statsEntry->udpRcvd.value += el->udpRcvdLoc.value + el->udpRcvdFromRem.value;
statsEntry->icmpRcvd.value += el->icmpRcvd.value;
statsEntry->icmp6Rcvd.value += el->icmp6Rcvd.value;
if(numEntries >= maxHosts) break;
}
/* if we didn't find a single domain, continue with the next interface */
if (numEntries == 0) {
free(tmpStats); free(stats);
continue;
}
/* insert all domain data for this interface into the RRDs */
for (idx=0; idx < numEntries; idx++) {
if(statsEntry->domainHost->dnsDomainValue != NULL) {
statsEntry = &tmpStats[idx];
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s/domains/%s/",
myGlobals.rrdPath, myGlobals.device[devIdx].uniqueIfName,
statsEntry->domainHost->dnsDomainValue);
mkdir_p("RRD", rrdPath, myGlobals.rrdDirectoryPermissions);
traceEventRRDebug(2, "Updating %s", rrdPath);
updateCounter(rrdPath, "bytesSent", statsEntry->bytesSent.value, 0);
updateCounter(rrdPath, "bytesRcvd", statsEntry->bytesRcvd.value, 0);
updateCounter(rrdPath, "tcpSent", statsEntry->tcpSent.value, 0);
updateCounter(rrdPath, "udpSent", statsEntry->udpSent.value, 0);
updateCounter(rrdPath, "icmpSent", statsEntry->icmpSent.value, 0);
updateCounter(rrdPath, "icmp6Sent", statsEntry->icmp6Sent.value, 0);
updateCounter(rrdPath, "tcpRcvd", statsEntry->tcpRcvd.value, 0);
updateCounter(rrdPath, "udpRcvd", statsEntry->udpRcvd.value, 0);
updateCounter(rrdPath, "icmpRcvd", statsEntry->icmpRcvd.value, 0);
updateCounter(rrdPath, "icmp6Rcvd", statsEntry->icmp6Rcvd.value, 0);
}
} /* for */
free(tmpStats); free(stats);
}
}
/* ****************************************************** */
if(dumpHosts) {
for(devIdx=0; devIdx<myGlobals.numDevices; devIdx++) {
HostTraffic *el;
for (el = getFirstHost(devIdx); el != NULL; el = getNextHost(devIdx, el)) {
if (el->l2Family == FLAG_HOST_TRAFFIC_AF_ETH)
rrdUpdateIPHostStats(el, devIdx);
else if (el->l2Family == FLAG_HOST_TRAFFIC_AF_FC)
rrdUpdateFcHostStats(el, devIdx);
}
}
}
/* ************************** */
if(dumpFlows) {
FlowFilterList *list = myGlobals.flowsList;
while(list != NULL) {
if(list->pluginStatus.activePlugin) {
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/flows/%s/",
myGlobals.rrdPath, list->flowName);
mkdir_p("RRD", rrdPath, myGlobals.rrdDirectoryPermissions);
updateCounter(rrdPath, "packets", list->packets.value, 0);
updateCounter(rrdPath, "bytes", list->bytes.value, 0);
}
list = list->next;
}
}
/* ************************** */
if(dumpInterfaces) {
for(devIdx=0; devIdx<myGlobals.numDevices; devIdx++) {
if((myGlobals.device[devIdx].virtualDevice && (!myGlobals.device[devIdx].sflowGlobals))
|| (!myGlobals.device[devIdx].activeDevice))
continue;
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s/", myGlobals.rrdPath,
myGlobals.device[devIdx].uniqueIfName);
mkdir_p("RRD", rrdPath, myGlobals.rrdDirectoryPermissions);
updateCounter(rrdPath, "ethernetPkts", myGlobals.device[devIdx].ethernetPkts.value, 0);
updateCounter(rrdPath, "broadcastPkts", myGlobals.device[devIdx].broadcastPkts.value, 0);
updateCounter(rrdPath, "multicastPkts", myGlobals.device[devIdx].multicastPkts.value, 0);
updateCounter(rrdPath, "ethernetBytes", myGlobals.device[devIdx].ethernetBytes.value, 0);
updateGauge(rrdPath, "knownHostsNum", myGlobals.device[devIdx].hostsno, 0);
updateGauge(rrdPath, "activeHostSendersNum", numActiveSenders(devIdx), 0);
updateCounter(rrdPath, "ipBytes", myGlobals.device[devIdx].ipBytes.value, 0);
updateCounter(rrdPath, "ipLocalToLocalBytes", myGlobals.device[devIdx].tcpGlobalTrafficStats.local.value +
myGlobals.device[devIdx].udpGlobalTrafficStats.local.value +
myGlobals.device[devIdx].icmpGlobalTrafficStats.local.value, 0);
updateCounter(rrdPath, "ipLocalToRemoteBytes", myGlobals.device[devIdx].tcpGlobalTrafficStats.local2remote.value +
myGlobals.device[devIdx].udpGlobalTrafficStats.local2remote.value +
myGlobals.device[devIdx].icmpGlobalTrafficStats.local2remote.value, 0);
updateCounter(rrdPath, "ipRemoteToLocalBytes", myGlobals.device[devIdx].tcpGlobalTrafficStats.remote2local.value +
myGlobals.device[devIdx].udpGlobalTrafficStats.remote2local.value +
myGlobals.device[devIdx].icmpGlobalTrafficStats.remote2local.value, 0);
updateCounter(rrdPath, "ipRemoteToRemoteBytes", myGlobals.device[devIdx].tcpGlobalTrafficStats.remote.value +
myGlobals.device[devIdx].udpGlobalTrafficStats.remote.value +
myGlobals.device[devIdx].icmpGlobalTrafficStats.remote.value, 0);
if(myGlobals.device[devIdx].netflowGlobals != NULL) {
updateCounter(rrdPath, "NF_numFlowPkts", myGlobals.device[devIdx].netflowGlobals->numNetFlowsPktsRcvd, 0);
updateCounter(rrdPath, "NF_numFlows", myGlobals.device[devIdx].netflowGlobals->numNetFlowsRcvd, 0);
updateCounter(rrdPath, "NF_numDiscardedFlows",
myGlobals.device[devIdx].netflowGlobals->numBadFlowPkts+
myGlobals.device[devIdx].netflowGlobals->numBadFlowBytes+
myGlobals.device[devIdx].netflowGlobals->numBadFlowReality+
myGlobals.device[devIdx].netflowGlobals->numNetFlowsV9UnknTemplRcvd, 0);
if(myGlobals.device[devIdx].netflowGlobals->numNetFlowsTCPRcvd > 0)
updateGauge(rrdPath, "NF_avgTcpNewFlowSize",
myGlobals.device[devIdx].netflowGlobals->totalNetFlowsTCPSize/
myGlobals.device[devIdx].netflowGlobals->numNetFlowsTCPRcvd, 0);
if(myGlobals.device[devIdx].netflowGlobals->numNetFlowsUDPRcvd > 0)
updateGauge(rrdPath, "NF_avgUdpNewFlowSize",
myGlobals.device[devIdx].netflowGlobals->totalNetFlowsUDPSize/
myGlobals.device[devIdx].netflowGlobals->numNetFlowsUDPRcvd, 0);
if(myGlobals.device[devIdx].netflowGlobals->numNetFlowsICMPRcvd > 0)
updateGauge(rrdPath, "NF_avgICMPNewFlowSize",
myGlobals.device[devIdx].netflowGlobals->totalNetFlowsICMPSize/
myGlobals.device[devIdx].netflowGlobals->numNetFlowsICMPRcvd, 0);
if(myGlobals.device[devIdx].netflowGlobals->numNetFlowsOtherRcvd > 0)
updateGauge(rrdPath, "NF_avgOtherFlowSize",
myGlobals.device[devIdx].netflowGlobals->totalNetFlowsOtherSize/
myGlobals.device[devIdx].netflowGlobals->numNetFlowsOtherRcvd, 0);
updateGauge(rrdPath, "NF_newTcpNetFlows",
myGlobals.device[devIdx].netflowGlobals->numNetFlowsTCPRcvd, 0);
updateGauge(rrdPath, "NF_newUdpNetFlows",
myGlobals.device[devIdx].netflowGlobals->numNetFlowsUDPRcvd, 0);
updateGauge(rrdPath, "NF_newIcmpNetFlows",
myGlobals.device[devIdx].netflowGlobals->numNetFlowsICMPRcvd, 0);
updateGauge(rrdPath, "NF_newOtherNetFlows",
myGlobals.device[devIdx].netflowGlobals->numNetFlowsOtherRcvd, 0);
updateGauge(rrdPath, "NF_numNetFlows",
myGlobals.device[devIdx].netflowGlobals->numNetFlowsRcvd-
myGlobals.device[devIdx].netflowGlobals->lastNumNetFlowsRcvd, 0);
/* Update Counters */
myGlobals.device[devIdx].netflowGlobals->lastNumNetFlowsRcvd =
myGlobals.device[devIdx].netflowGlobals->numNetFlowsRcvd;
myGlobals.device[devIdx].netflowGlobals->totalNetFlowsTCPSize = 0;
myGlobals.device[devIdx].netflowGlobals->totalNetFlowsUDPSize = 0;
myGlobals.device[devIdx].netflowGlobals->totalNetFlowsICMPSize = 0;
myGlobals.device[devIdx].netflowGlobals->totalNetFlowsOtherSize = 0;
myGlobals.device[devIdx].netflowGlobals->numNetFlowsTCPRcvd = 0;
myGlobals.device[devIdx].netflowGlobals->numNetFlowsUDPRcvd = 0;
myGlobals.device[devIdx].netflowGlobals->numNetFlowsICMPRcvd = 0;
myGlobals.device[devIdx].netflowGlobals->numNetFlowsOtherRcvd = 0;
}
if(dumpDetail >= FLAG_RRD_DETAIL_MEDIUM) {
updateCounter(rrdPath, "droppedPkts", myGlobals.device[devIdx].droppedPkts.value, 0);
updateCounter(rrdPath, "fragmentedIpBytes", myGlobals.device[devIdx].fragmentedIpBytes.value, 0);
updateCounter(rrdPath, "tcpBytes", myGlobals.device[devIdx].tcpBytes.value, 0);
updateCounter(rrdPath, "udpBytes", myGlobals.device[devIdx].udpBytes.value, 0);
updateCounter(rrdPath, "otherIpBytes", myGlobals.device[devIdx].otherIpBytes.value, 0);
updateCounter(rrdPath, "icmpBytes", myGlobals.device[devIdx].icmpBytes.value, 0);
updateCounter(rrdPath, "dlcBytes", myGlobals.device[devIdx].dlcBytes.value, 0);
updateCounter(rrdPath, "ipxBytes", myGlobals.device[devIdx].ipxBytes.value, 0);
updateCounter(rrdPath, "stpBytes", myGlobals.device[devIdx].stpBytes.value, 0);
updateCounter(rrdPath, "decnetBytes", myGlobals.device[devIdx].decnetBytes.value, 0);
updateCounter(rrdPath, "netbiosBytes", myGlobals.device[devIdx].netbiosBytes.value, 0);
updateCounter(rrdPath, "arpRarpBytes", myGlobals.device[devIdx].arpRarpBytes.value, 0);
updateCounter(rrdPath, "atalkBytes", myGlobals.device[devIdx].atalkBytes.value, 0);
updateCounter(rrdPath, "egpBytes", myGlobals.device[devIdx].egpBytes.value, 0);
updateCounter(rrdPath, "osiBytes", myGlobals.device[devIdx].osiBytes.value, 0);
updateCounter(rrdPath, "ipv6Bytes", myGlobals.device[devIdx].ipv6Bytes.value, 0);
updateCounter(rrdPath, "otherBytes", myGlobals.device[devIdx].otherBytes.value, 0);
updateCounter(rrdPath, "upTo64Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo64.value, 0);
updateCounter(rrdPath, "upTo128Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo128.value, 0);
updateCounter(rrdPath, "upTo256Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo256.value, 0);
updateCounter(rrdPath, "upTo512Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo512.value, 0);
updateCounter(rrdPath, "upTo1024Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo1024.value, 0);
updateCounter(rrdPath, "upTo1518Pkts", myGlobals.device[devIdx].rcvdPktStats.upTo1518.value, 0);
updateCounter(rrdPath, "badChecksumPkts", myGlobals.device[devIdx].rcvdPktStats.badChecksum.value, 0);
updateCounter(rrdPath, "tooLongPkts", myGlobals.device[devIdx].rcvdPktStats.tooLong.value, 0);
if(myGlobals.device[devIdx].ipProtosList != NULL) {
protoList = myGlobals.ipProtosList, idx=0;
while(protoList != NULL) {
Counter c = myGlobals.device[devIdx].ipProtosList[idx].value;
if(c > 0) updateCounter(rrdPath, protoList->protocolName, c, 0);
idx++, protoList = protoList->next;
}
}
}
if(dumpDetail == FLAG_RRD_DETAIL_HIGH) {
if(myGlobals.device[devIdx].ipProtoStats != NULL) {
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath), "%s/interfaces/%s/IP_",
myGlobals.rrdPath, myGlobals.device[devIdx].uniqueIfName);
for(j=0; j<myGlobals.numIpProtosToMonitor; j++) {
TrafficCounter ctr;
char tmpStr[128];
safe_snprintf(__FILE__, __LINE__, tmpStr, sizeof(tmpStr), "%sFlows",
myGlobals.ipTrafficProtosNames[j]);
updateCounter(rrdPath, tmpStr, myGlobals.device[devIdx].
ipProtoStats[j].totalFlows.value, 0);
ctr.value =
myGlobals.device[devIdx].ipProtoStats[j].local.value+
myGlobals.device[devIdx].ipProtoStats[j].local2remote.value+
myGlobals.device[devIdx].ipProtoStats[j].remote2local.value+
myGlobals.device[devIdx].ipProtoStats[j].remote.value;
safe_snprintf(__FILE__, __LINE__, tmpStr, sizeof(tmpStr), "%sBytes",
myGlobals.ipTrafficProtosNames[j]);
updateCounter(rrdPath, tmpStr, ctr.value, 0);
}
}
}
/* ******************************** */
if(myGlobals.device[devIdx].asStats) {
AsStats *asStats;
u_int totAS = 0;
char rrdIfPath[512];
accessMutex(&myGlobals.device[devIdx].asMutex, "rrdPluginAS");
asStats = myGlobals.device[devIdx].asStats;
while(asStats) {
if(dumpASs) {
if(asStats->totPktsSinceLastRRDDump > AS_RRD_DUMP_PKTS_THRESHOLD) {
safe_snprintf(__FILE__, __LINE__, rrdIfPath, sizeof(rrdIfPath),
"%s/interfaces/%s/AS/%d/", myGlobals.rrdPath,
myGlobals.device[devIdx].uniqueIfName,
asStats->as_id);
mkdir_p("RRD", rrdIfPath, myGlobals.rrdDirectoryPermissions);
updateCounter(rrdIfPath, "ifInOctets", asStats->inBytes.value, 0);
updateCounter(rrdIfPath, "ifInPkts", asStats->inPkts.value, 0);
updateCounter(rrdIfPath, "ifOutOctets", asStats->outBytes.value, 0);
updateCounter(rrdIfPath, "ifOutPkts", asStats->outPkts.value, 0);
updateCounter(rrdIfPath, "ifSelfOctets", asStats->selfBytes.value, 0);
updateCounter(rrdIfPath, "ifSelfPkts", asStats->selfPkts.value, 0);
}
}
asStats->totPktsSinceLastRRDDump = 0;
asStats = asStats->next;
totAS++;
}
releaseMutex(&myGlobals.device[devIdx].asMutex);
if(dumpASs) {
safe_snprintf(__FILE__, __LINE__, rrdIfPath, sizeof(rrdIfPath),
"%s/interfaces/%s/AS/", myGlobals.rrdPath,
myGlobals.device[devIdx].uniqueIfName);
mkdir_p("RRD", rrdIfPath, myGlobals.rrdDirectoryPermissions);
updateGauge(rrdIfPath, "numAS", totAS, 0);
// traceEvent(CONST_TRACE_WARNING, "numAS=%d", totAS);
}
}
/* ******************************** */
if(myGlobals.device[devIdx].netflowGlobals) {
InterfaceStats *ifStats;
accessMutex(&myGlobals.device[devIdx].netflowGlobals->ifStatsMutex, "rrdPluginNetflow");
ifStats = myGlobals.device[devIdx].netflowGlobals->ifStats;
while(ifStats != NULL) {
char rrdIfPath[512];
safe_snprintf(__FILE__, __LINE__, rrdIfPath, sizeof(rrdIfPath),
"%s/interfaces/%s/NetFlow/%d/", myGlobals.rrdPath,
myGlobals.device[devIdx].uniqueIfName, ifStats->interface_id);
mkdir_p("RRD", rrdIfPath, myGlobals.rrdDirectoryPermissions);
updateCounter(rrdIfPath, "ifInOctets", ifStats->inBytes.value, 0);
updateCounter(rrdIfPath, "ifInPkts", ifStats->inPkts.value, 0);
updateCounter(rrdIfPath, "ifOutOctets", ifStats->outBytes.value, 0);
updateCounter(rrdIfPath, "ifOutPkts", ifStats->outPkts.value, 0);
updateCounter(rrdIfPath, "ifSelfOctets", ifStats->selfBytes.value, 0);
updateCounter(rrdIfPath, "ifSelfPkts", ifStats->selfPkts.value, 0);
ifStats = ifStats->next;
}
releaseMutex(&myGlobals.device[devIdx].netflowGlobals->ifStatsMutex);
}
/* ******************************** */
if(myGlobals.device[devIdx].sflowGlobals) {
IfCounters *ifName = myGlobals.device[devIdx].sflowGlobals->ifCounters;
while(ifName != NULL) {
char rrdIfPath[512];
safe_snprintf(__FILE__, __LINE__, rrdIfPath, sizeof(rrdIfPath),
"%s/interfaces/%s/sFlow/%u/", myGlobals.rrdPath,
myGlobals.device[devIdx].uniqueIfName, ifName->ifIndex);
mkdir_p("RRD", rrdIfPath, myGlobals.rrdDirectoryPermissions);
updateCounter(rrdIfPath, "ifInOctets", ifName->ifInOctets, 0);
updateCounter(rrdIfPath, "ifInUcastPkts", ifName->ifInUcastPkts, 0);
updateCounter(rrdIfPath, "ifInMulticastPkts", ifName->ifInMulticastPkts, 0);
updateCounter(rrdIfPath, "ifInBroadcastPkts", ifName->ifInBroadcastPkts, 0);
updateCounter(rrdIfPath, "ifInDiscards", ifName->ifInDiscards, 0);
updateCounter(rrdIfPath, "ifInErrors", ifName->ifInErrors, 0);
updateCounter(rrdIfPath, "ifInUnknownProtos", ifName->ifInUnknownProtos, 0);
updateCounter(rrdIfPath, "ifOutOctets", ifName->ifOutOctets, 0);
updateCounter(rrdIfPath, "ifOutUcastPkts", ifName->ifOutUcastPkts, 0);
updateCounter(rrdIfPath, "ifOutMulticastPkts", ifName->ifOutMulticastPkts, 0);
updateCounter(rrdIfPath, "ifOutBroadcastPkts", ifName->ifOutBroadcastPkts, 0);
updateCounter(rrdIfPath, "ifOutDiscards", ifName->ifOutDiscards, 0);
updateCounter(rrdIfPath, "ifOutErrors", ifName->ifOutErrors, 0);
ifName = ifName->next;
}
}
}
}
/* ************************** */
if(dumpMatrix) {
int k;
for(k=0; k<myGlobals.numDevices; k++)
for(i=1; i<myGlobals.device[k].numHosts; i++)
for(j=1; j<myGlobals.device[k].numHosts; j++) {
if(i != j) {
idx = i*myGlobals.device[k].numHosts+j;
if(myGlobals.device[k].ipTrafficMatrix == NULL)
continue;
if(myGlobals.device[k].ipTrafficMatrix[idx] == NULL)
continue;
if(myGlobals.device[k].ipTrafficMatrix[idx]->bytesSent.value > 0) {
safe_snprintf(__FILE__, __LINE__, rrdPath, sizeof(rrdPath),
"%s/interfaces/%s/matrix/%s/%s/",
myGlobals.rrdPath,
myGlobals.device[k].uniqueIfName,
myGlobals.device[k].ipTrafficMatrixHosts[i]->hostNumIpAddress,
myGlobals.device[k].ipTrafficMatrixHosts[j]->hostNumIpAddress);
mkdir_p("RRD", rrdPath, myGlobals.rrdDirectoryPermissions);
updateCounter(rrdPath, "pkts",
myGlobals.device[k].ipTrafficMatrix[idx]->pktsSent.value, 0);
updateCounter(rrdPath, "bytes",
myGlobals.device[k].ipTrafficMatrix[idx]->bytesSent.value, 0);
}
}
}
}
gettimeofday(&rrdEndOfCycle, NULL);
elapsed = timeval_subtract(rrdEndOfCycle, rrdStartOfCycle);
#ifdef MAX_RRD_CYCLE_BUFFER
rrdcycleBuffer[++rrdcycleBufferCount & (MAX_RRD_CYCLE_BUFFER - 1)] = elapsed;
if(elapsed > rrdcmaxLength)
rrdcmaxLength = elapsed;
#endif
traceEvent(CONST_TRACE_NOISY, "RRD: Cycle %lu ended, %llu RRDs updated, %.3f seconds",
numRRDCycles, numRRDUpdates, elapsed);
/*
* If it's FLAG_NTOPSTATE_STOPCAP, and we're still running, then this
* is the 1st pass. We just updated our data to save the counts, now
* we kill the thread...
*/
if(myGlobals.ntopRunState == FLAG_NTOPSTATE_STOPCAP) {
traceEvent(CONST_TRACE_WARNING, "THREADMGMT[t%lu]: RRD: STOPCAP, ending rrd thread", pthread_self());
break;
}
}
termUdp();
rrdThread = 0;
traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: RRD: Data collection thread terminated [p%d]", pthread_self(), getpid());
return(0);
}
/* ****************************** */
static int initRRDfunct(void) {
createMutex(&rrdMutex);
setPluginStatus(NULL);
#if 0
if (myGlobals.runningPref.rFileName != NULL) {
/* Don't start RRD Plugin for capture files as it doesn't work */
traceEvent(CONST_TRACE_INFO, "RRD: plugin disabled on capture files");
active = 0;
return (TRUE); /* 0 indicates success */
}
#endif
traceEvent(CONST_TRACE_INFO, "RRD: Welcome to the RRD plugin");
if(myGlobals.rrdPath == NULL)
commonRRDinit();
createThread(&rrdThread, rrdMainLoop, NULL);
traceEvent(CONST_TRACE_INFO, "THREADMGMT: RRD: Started thread (t%lu) for data collection", rrdThread);
fflush(stdout);
numTotalRRDUpdates = 0;
return(0);
}
/* ****************************** */
static void termRRDfunct(u_char termNtop /* 0=term plugin, 1=term ntop */) {
int count=0, rc;
/* Hold until rrd is finished or 15s elapsed... */
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Shutting down, locking mutex (may block for a little while)");
while ((count++ < 5) && (tryLockMutex(&rrdMutex, "Termination") != 0)) {
sleep(3);
}
if(rrdMutex.isLocked) {
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Locked mutex, continuing shutdown");
} else {
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Unable to lock mutex, continuing shutdown anyway");
}
if(active) {
if(rrdThread) {
rc = killThread(&rrdThread);
if (rc == 0)
traceEvent(CONST_TRACE_INFO,
"THREADMGMT[t%lu]: RRD: killThread(rrdThread) succeeded",
pthread_self());
else
traceEvent(CONST_TRACE_ERROR,
"THREADMGMT[t%lu]: RRD: killThread(rrdThread) failed, rc %s(%d)",
pthread_self(), strerror(rc), rc);
}
if(rrdTrafficThread) {
rc = killThread(&rrdTrafficThread);
if (rc == 0)
traceEvent(CONST_TRACE_INFO,
"THREADMGMT[t%lu]: RRD: killThread(rrdTrafficThread) succeeded",
pthread_self());
else
traceEvent(CONST_TRACE_ERROR,
"THREADMGMT[t%lu]: RRD: killThread(rrdTrafficThread) failed, rc %s(%d)",
pthread_self(), strerror(rc), rc);
}
/*
if((rrdThread != 0) || (rrdTrafficThread != 0)) {
traceEvent(CONST_TRACE_INFO,
"THREADMGMT[t%lu]: RRD: Waiting %d seconds for threads to stop",
pthread_self(), (PARM_SLEEP_LIMIT + 2));
sleep(PARM_SLEEP_LIMIT + 2);
}
*/
traceEvent(CONST_TRACE_INFO, "THREADMGMT[t%lu]: RRD: Plugin shutdown continuing", pthread_self());
}
if(hostsFilter != NULL) free(hostsFilter);
if(myGlobals.rrdPath != NULL) free(myGlobals.rrdPath);
deleteMutex(&rrdMutex);
traceEvent(CONST_TRACE_INFO, "RRD: Thanks for using the rrdPlugin");
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "RRD: Done");
fflush(stdout);
initialized = 0; /* Reinit on restart */
active = 0;
}
/* ****************************** */
/* Plugin entry fctn */
#ifdef MAKE_STATIC_PLUGIN
PluginInfo* rrdPluginEntryFctn(void)
#else
PluginInfo* PluginEntryFctn(void)
#endif
{
traceEvent(CONST_TRACE_ALWAYSDISPLAY,
"RRD: Welcome to %s. (C) 2002-07 by Luca Deri.",
rrdPluginInfo->pluginName);
return(rrdPluginInfo);
}
/* ************************************************ */
/* This must be here so it can access the struct PluginInfo, above */
static void setPluginStatus(char * status) {
if(rrdPluginInfo->pluginStatusMessage != NULL)
free(rrdPluginInfo->pluginStatusMessage);
if(status == NULL) {
rrdPluginInfo->pluginStatusMessage = NULL;
} else {
rrdPluginInfo->pluginStatusMessage = strdup(status);
}
}
syntax highlighted by Code2HTML, v. 0.9.1