/****************************************************************************
Program: $Id: rtghash.c,v 1.9 2003/10/02 15:59:07 rbeverly Exp $
Author: $Author: rbeverly $
Date: $Date: 2003/10/02 15:59:07 $
Description: RTG target hash table routines
****************************************************************************/
#include "common.h"
#include "rtg.h"
/* Initialize hash table */
void init_hash() {
int i;
for(i=0;i<HASHSIZE;i++)
hash.table[i] = NULL;
if (set.verbose >= LOW) {
printf("Initialize hash table pointers: %d bytes.\n",
HASHSIZE * sizeof(target_t *));
}
}
void init_hash_walk() {
hash.bucket = 0;
hash.target = hash.table[hash.bucket];
}
target_t *getNext() {
target_t *next = NULL;
while (!(hash.target)) {
(hash.bucket)++;
if (hash.bucket >= HASHSIZE)
return NULL;
hash.target = hash.table[hash.bucket];
}
next = hash.target;
hash.target = (hash.target)->next;
return next;
}
/* Free hash table memory */
void free_hash() {
target_t *ptr = NULL;
target_t *f = NULL;
int i;
for(i=0;i<HASHSIZE;i++) {
ptr = hash.table[i];
while (ptr) {
f = ptr;
ptr = ptr->next;
free(f);
}
}
}
/* Hash the target */
unsigned long make_key(const void *entry) {
const target_t *t = (const target_t *) entry;
const char *h = (const char *) t->host;
const char *o = (const char *) t->objoid;
unsigned long hashval;
if (!h) return 0;
for (hashval = 0; *o != '\0'; o++)
hashval = (((unsigned int) *o) | 0x20) + 31 * hashval;
for (;*h != '\0'; h++)
hashval = (((unsigned int) *h) | 0x20) + 31 * hashval;
return (hashval % HASHSIZE);
}
/* Set state of all targets to state - used on init, update targets, etc */
void mark_targets(int state) {
target_t *p = NULL;
int i = 0;
for (i=0;i<HASHSIZE;i++) {
p = hash.table[i];
while (p) {
p->init = state;
p = p->next;
}
}
}
/* Delete targets marked with state = state */
int delete_targets(int state) {
target_t *p = NULL;
target_t *d = NULL;
int i = 0;
int entries = 0;
for (i=0;i<HASHSIZE;i++) {
p = hash.table[i];
while (p) {
d = p;
p = p->next;
if (d->init == state) {
del_hash_entry(d);
entries++;
}
}
}
return entries;
}
/* Dump the entire target hash [sequential num/bucket number] */
void walk_target_hash() {
target_t *p = NULL;
int targets = 0;
int i = 0;
printf("Dumping Target List:\n");
for (i=0;i<HASHSIZE;i++) {
p = hash.table[i];
while (p) {
printf("[%d/%d]: %s %s %d %s %s %d\n", targets, i, p->host,
p->objoid, p->bits, p->community, p->table,
p->iid);
targets++;
p = p->next;
}
}
printf("Total of %u targets [%u bytes of memory].\n",
targets, targets * sizeof(target_t));
}
/* return ptr to target if the entry exists in the named list */
void *in_hash(target_t *entry, target_t *list) {
while (list) {
if (compare_targets(entry, list)) {
if (set.verbose >= HIGH) {
printf("Found existing %s %s %s %d\n", list->host,
list->objoid, list->table, list->iid);
}
return list;
}
list = list->next;
}
return NULL;
}
/* TRUE if target 1 == target 2 */
int compare_targets(target_t *t1, target_t *t2) {
if (!strcmp(t1->host, t2->host) &&
!strcmp(t1->objoid, t2->objoid) &&
!strcmp(t1->table, t2->table) &&
!strcmp(t1->community, t2->community) &&
(t1->iid == t2->iid))
return TRUE;
return FALSE;
}
/* Remove an item from the list. Returns TRUE if successful. */
int del_hash_entry(target_t *new) {
target_t *p = NULL;
target_t *prev = NULL;
unsigned int key;
key = make_key(new);
if (!in_hash(new, hash.table[key]))
return FALSE;
p = hash.table[key];
/* assert(p != NULL) */
while (p) {
if (compare_targets(p, new)) {
/* if successor, we need to point predecessor to it (if exists) */
if (p->next) {
/* there is a predecessor */
if (prev)
prev->next = p->next;
/* there is no predecessor */
else
hash.table[key] = p->next;
}
/* no successor, delete just this target */
else {
if (prev)
prev->next = NULL;
else
hash.table[key] = NULL;
}
free (p);
return TRUE;
}
prev = p;
p = p->next;
}
return FALSE;
}
/* Add an entry to hash if it is unique, otherwise free() it */
int add_hash_entry(target_t *new) {
target_t *p = NULL;
unsigned int key;
key = make_key(new);
p = hash.table[key];
p = in_hash(new, hash.table[key]);
if (p) {
p->init = LIVE;
free(new);
return FALSE;
}
if (!hash.table[key]) {
hash.table[key] = new;
} else {
p = hash.table[key];
while (p->next) p = p->next;
p->next = new;
}
return TRUE;
}
/* Read a target file into a target_t hash table. Our hash algorithm
roughly randomizes targets, easing SNMP load on end devices during
polling. hash_target_file() can be called again to update the target
hash. If hash_target_file() finds new target entries in the file, it
adds them to the hash. If hash_target_file() finds entries in hash
but not in file, it removes said entries from hash. */
int hash_target_file(char *file) {
FILE *fp;
target_t *new = NULL;
char buffer[BUFSIZE];
char maxspeed[30];
int entries = 0;
int removed = 0;
/* Open the target file */
if ((fp = fopen(file, "r")) == NULL) {
fprintf(stderr, "\nCould not open file for reading '%s'.\n", file);
return (-1);
}
if (set.verbose >= LOW)
printf("\nReading RTG target list [%s].\n", file);
mark_targets(STALE);
/* Read each unique target into hash table */
while (!feof(fp)) {
fgets(buffer, BUFSIZE, fp);
if (!feof(fp) && buffer[0] != '#' && buffer[0] != ' ' && buffer[0] != '\n') {
new = (target_t *) malloc(sizeof(target_t));
if (!new) {
printf("Fatal target malloc error!\n");
exit(-1);
}
sscanf(buffer, "%64s %128s %hu %64s %64s %d %30s",
new->host, new->objoid, &(new->bits),
new->community, new->table,
&(new->iid), maxspeed);
if (alldigits(maxspeed)) {
#ifdef HAVE_STRTOLL
new->maxspeed = strtoll(maxspeed, NULL, 0);
#else
new->maxspeed = strtol(maxspeed, NULL, 0);
#endif
} else {
new->maxspeed = set.out_of_range;
}
if (set.verbose > DEBUG)
printf("Host[OID][OutOfRange]:%s[%s][%lld]\n",
new->host, new->objoid, new->maxspeed);
new->init = NEW;
new->last_value = 0;
new->next = NULL;
entries += add_hash_entry(new);
}
}
fclose(fp);
removed = delete_targets(STALE);
if (set.verbose >= LOW) {
printf("Successfully hashed [%d] new targets, (%d bytes).\n",
entries, entries * sizeof(target_t));
if (removed > 0)
printf("Removed [%d] stale targets from hash.\n", removed);
}
return (entries);
}
syntax highlighted by Code2HTML, v. 0.9.1