/*
This file is part of GNUnet.
(C) 2001, 2002, 2004 Christian Grothoff (and other contributing authors)
GNUnet 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, or (at your
option) any later version.
GNUnet 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 GNUnet; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/**
* @file util/statistics.c
* @brief keeping statistics of GNUnet activities
* @author Christian Grothoff
*
* This module keeps a mapping of strings to (unsigned long long)
* values. Every entry in the mapping can be accessed with a handle
* (int) which can be obtained from the string. The module can be used
* to keep track of certain statistical information, such as the
* number of bytes received, messages sent, kilobytes stored, and so
* on.
*
* When used within gnunetd, the gnunet-stats tool can be used to
* print the statistical information stored in this module.
*/
#include "gnunet_util.h"
#include "platform.h"
/* ***************** global statistics ***************** */
/**
* When did the module start?
*/
static cron_t startTime;
/**
* How many values do we keep statistics for?
*/
static unsigned int statCounters = 0;
/**
* What are these values (value)
*/
static unsigned long long * values = NULL;
/**
* A description for each of the values
*/
static char ** descriptions = NULL;
/**
* lock for the stat module
*/
static Mutex statLock;
/**
* Initialize the statistics module.
*/
void initStatistics() {
cronTime(&startTime);
MUTEX_CREATE_RECURSIVE(&statLock);
}
/**
* Shutdown the statistics module.
*/
void doneStatistics() {
int i;
MUTEX_DESTROY(&statLock);
for (i=0;i= statCounters) ) {
BREAK();
MUTEX_UNLOCK(&statLock);
return;
}
values[handle] = value;
MUTEX_UNLOCK(&statLock);
}
/**
* Manipulate statistics. Changes the statistics associated with the
* value by delta.
*
* @param handle the handle for the value to change
* @param delta by how much should the value be changed
*/
void statChange(const int handle,
const int delta) {
MUTEX_LOCK(&statLock);
if ( (handle < 0) ||
(handle >= statCounters) ) {
BREAK();
MUTEX_UNLOCK(&statLock);
return;
}
values[handle] += delta;
MUTEX_UNLOCK(&statLock);
}
/**
* Send statistics to a TCP socket. May send multiple messages if the
* overall size would be too big otherwise.
*
* @param originalRequestMessage ignored at this point.
*/
int sendStatistics(ClientHandle sock,
const CS_HEADER * originalRequestMessage,
SendToClientCallback callback) {
STATS_CS_MESSAGE * statMsg;
int pos; /* position in the values-descriptions */
int start;
int end;
int mpos; /* postion in the message */
statMsg = (STATS_CS_MESSAGE*)MALLOC(MAX_BUFFER_SIZE);
statMsg->header.tcpType
= htons(STATS_CS_PROTO_STATISTICS);
statMsg->totalCounters
= htonl(statCounters);
statMsg->statCounters
= htons(0);
statMsg->startTime
= htonll(startTime);
start = 0;
while (start < statCounters) {
pos = start;
/* first pass: gauge how many statistic numbers
and their descriptions we can send in one message */
mpos = 0;
while ( (pos < statCounters) &&
(mpos + sizeof(unsigned long long)
+ strlen(descriptions[pos]) + 1
< MAX_BUFFER_SIZE - sizeof(STATS_CS_MESSAGE)) ) {
mpos += sizeof(unsigned long long); /* value */
mpos += strlen(descriptions[pos])+1;
pos++;
}
end = pos;
/* second pass: copy values and messages to message */
for (pos=start;posvalues[pos-start] = htonll(values[pos]);
mpos = sizeof(unsigned long long) * (end - start);
for (pos=start;posvalues)[mpos],
descriptions[pos]);
mpos += strlen(descriptions[pos])+1;
}
statMsg->statCounters = htonl(end - start);
statMsg->header.size = htons(mpos + sizeof(STATS_CS_MESSAGE));
/* printf("writing message of size %d with stats %d to %d out of %d to socket\n",
ntohs(statMsg->header.size),
start, end, statCounters);*/
if (SYSERR == callback(sock,
&statMsg->header))
break; /* abort, socket error! */
start = end;
}
FREE(statMsg);
return OK;
}
/* end of statistics.c */