www.pudn.com > hipl.1.0.1.rar > hit_db.c
/*
HIP Agent
License: GNU/GPL
Authors: Antti Partanen
*/
/******************************************************************************/
/* INCLUDES */
/* STANDARD */
#include
#include
#include
/* THIS */
#include "hit_db.h"
/******************************************************************************/
/* DEFINES */
/**
Define minimum amount of allocated space for database items and amount
of memory allocated more, when not enough space for new items.
*/
#define HIT_DB_ITEMS_REALLOC 8
#define HIT_DB_LOCK() { while (hit_db_lock); hit_db_lock = 1; }
#define HIT_DB_UNLOCK() { hit_db_lock = 0; }
/******************************************************************************/
/* VARIABLES */
/** All HIT-data in the database is stored in here. */
HIT_Remote *remote_db = NULL, *remote_db_last = NULL;
/** All groups in database are stored in here. */
HIT_Group *group_db = NULL, *group_db_last = NULL;
/** All local HITs in database are stored in here. */
HIT_Local *local_db = NULL, *local_db_last = NULL;
/** Counts items in database. */
int remote_db_n = 0;
/** Count groups in database. */
int group_db_n = 0;
/** Count local HITs in database. */
int local_db_n = 0;
/** Almost atomic lock. */
int hit_db_lock = 1;
/******************************************************************************/
/* FUNCTIONS */
/******************************************************************************/
/**
Initialize HIP agent HIT database. This function must be called before
using database at all.
@param file If not NULL, database is initialized from here.
@return 0 on success, -1 on errors.
*/
int hit_db_init(char *file)
{
/* Variables. */
int err = 0;
hit_db_lock = 0;
hit_db_clear();
if (file) HIP_IFE(hit_db_load_from_file(file), -1);
out_err:
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Deinitialize HIP agent HIT database. This function must be called when
closing application and stopping using database.
@param file If not NULL, database saved to here.
*/
void hit_db_quit(char *file)
{
if (file) hit_db_save_to_file(file);
hit_db_clear();
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Clear HIT database.
@return 0 on success, -1 on errors.
*/
void hit_db_clear(void)
{
/* Variables. */
HIT_Remote *r1, *r2;
HIT_Group *g1, *g2;
HIT_Local *l1, *l2;
HIT_DB_LOCK();
/* Free remote. */
r1 = remote_db;
remote_db = NULL;
remote_db_n = 0;
while (r1)
{
r2 = r1->next;
free(r1);
r1 = r2;
}
/* Free groups. */
g1 = group_db;
group_db = NULL;
group_db_n = 0;
while (g1)
{
g2 = g1->next;
free(g1);
g1 = g2;
}
/* Free locals. */
l1 = local_db;
local_db = NULL;
local_db_n = 0;
while (l1)
{
l2 = l1->next;
free(l1);
l1 = l2;
}
HIT_DB_UNLOCK();
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Adds new HIT to database.
*/
HIT_Remote *hit_db_add_hit(HIT_Remote *hit, int nolock)
{
return (hit_db_add(hit->name, &hit->hit, hit->url, hit->port, hit->g, nolock));
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Adds new HIT to database.
@param name 'Human' identifier for this item: it's name.
@param hit HIT of this item.
@param url URL, which is connected to this item, can be NULL.
@param port Port, which is connected to this item, can be 0 if not needed.
@param type HIT type, accept or deny.
@param nolock Set to one if no database lock is needed.
@return Pointer to new remote HIT on success, NULL on errors.
*/
HIT_Remote *hit_db_add(char *name, struct in6_addr *hit, char *url,
char *port, HIT_Group *group, int nolock)
{
/* Variables. */
HIT_Remote *r, *err = NULL;
char hitb[128];
struct in6_addr lhit;
if (!nolock) HIT_DB_LOCK();
/* Check group name length. */
HIP_IFEL(strlen(name) < 1, NULL, "Remote HIT name too short.\n");
/* Check database for group already with same name. */
r = hit_db_find(name, NULL);
HIP_IFEL(r != NULL, r, "Remote HIT already found from database with same"
" name, returning it, could not add new.\n");
r = hit_db_find(NULL, hit);
HIP_IFEL(r != NULL, r, "Remote HIT already found from database, returning it.\n");
/* Allocate new remote HIT. */
r = (HIT_Remote *)malloc(sizeof(HIT_Remote));
HIP_IFEL(r == NULL, NULL, "Failed to allocate new remote HIT.\n");
/* Copy info. */
memset(r, 0, sizeof(HIT_Remote));
NAMECPY(r->name, name);
memcpy(&r->hit, hit, sizeof(struct in6_addr));
URLCPY(r->port, port);
URLCPY(r->url, url);
/* Check that group is not NULL and set group. */
if (group == NULL)
{
if (group_db_n < 1)
{
//HIP_DEBUG("Group database emty, adding default group.\n");
//hit_db_add_rgroup("default", local_db, HIT_DB_TYPE_ACCEPT, 0);
}
group = group_db;
}
r->g = group;
r->g->remotec++;
/* Add remote group item to database. */
if (remote_db == NULL) remote_db = r;
else remote_db_last->next = (void *)r;
remote_db_last = r;
remote_db_n++;
/* Then call GUI to show new HIT. */
HIP_DEBUG("Calling GUI to show new HIT %s...\n", r->name);
gui_add_remote_hit(r->name, group->name);
HIP_DEBUG("%d items in database.\n", remote_db_n);
err = r;
out_err:
if (!nolock) HIT_DB_UNLOCK();
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Delete hit with given index.
@param name Name of remote HIT to be removed.
@return 0 if hit removed, -1 on errors.
*/
int hit_db_del(char *n)
{
/* Variables. */
HIT_Remote *r1, *r2;
char name[MAX_NAME_LEN + 1];
int err = 0;
/* Check that database is not empty. */
HIP_IFEL(remote_db_n < 1, -1, "Remote database is empty, should not happen!\n");
NAMECPY(name, n);
HIP_DEBUG("Deleting remote HIT: %s\n", name);
/* Check whether this HIT is the first. */
if (strncmp(remote_db->name, name, MAX_NAME_LEN) == 0)
{
r1 = remote_db;
r1->g->remotec--;
remote_db = (HIT_Remote *)remote_db->next;
free(r1);
remote_db_n--;
if (remote_db_n < 1)
{
remote_db = NULL;
remote_db_last = NULL;
}
}
else
{
/* Find previous HIT first. */
r1 = remote_db;
while (r1 != NULL)
{
r2 = (HIT_Remote *)r1->next;
if (r2 == NULL) break;
if (strncmp(r2->name, name, MAX_NAME_LEN) == 0) break;
r1 = r2;
}
/* Then delete, if found. */
if (r2 != NULL)
{
r1->next = r2->next;
r2->g->remotec--;
if (remote_db_last == r2) remote_db_last = r1;
free(r2);
}
else err = -1;
}
out_err:
if (err) HIP_DEBUG("Deleting remote HIT failed: %s\n", name);
else gui_delete_remote_hit(name);
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Find a remote HIT from database.
@param name Name of HIT to be searched.
@param hit HIT to be searched.
@return Pointer to HIT found, or NULL if none found.
*/
HIT_Remote *hit_db_find(char *name, struct in6_addr *hit)
{
/* Variables. */
HIT_Remote *r;
int err;
r = remote_db;
while (r != NULL)
{
err = 0;
if (name == NULL) err++;
else if (strncmp(r->name, name, MAX_NAME_LEN) == 0) err++;
if (hit == NULL) err++;
else if (memcmp(&r->hit, hit, sizeof(struct in6_addr)) == 0) err++;
if (err == 2) break;
r = (HIT_Remote *)r->next;
}
return (r);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Enumerate all remote HITs in database. This function locks the database.
@param f Function to call for every remote HIT in database. This function
should return 0 if continue enumeration and something else, if
enumeration should be stopped.
@param p Pointer to user data.
@return Number of HITs enumerated.
*/
int hit_db_enum(int (*f)(HIT_Remote *, void *), void *p)
{
/* Variables. */
HIT_Remote *r;
int err = 0, n = 0;
r = remote_db;
while (r != NULL && err == 0)
{
err = f(r, p);
n++;
r = (HIT_Remote *)r->next;
}
HIP_DEBUG("Enumerated %d remote HITs.\n", n);
return (n);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Save database to file.
@param file Filename for saving database.
@return 0 on success, -1 on errors.
*/
int hit_db_save_to_file(char *file)
{
/* Variables. */
HIT_Remote *items = NULL;
FILE *f = NULL;
int err = 0, i;
char hit[128];
HIT_DB_LOCK();
HIP_DEBUG("Saving HIT database to %s.\n", file);
f = fopen(file, "w");
HIP_IFEL(f == NULL, -1, "Failed to save database.\n");
/* Write all local HITs to file. */
hit_db_enum_locals(hit_db_save_local_to_file, f);
/* Write all remote groups to file. */
hit_db_enum_rgroups(hit_db_save_rgroup_to_file, f);
/* Write all remote HITs to file. */
hit_db_enum(hit_db_save_remote_to_file, f);
out_err:
if (f) fclose(f);
HIT_DB_UNLOCK();
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Write remote group to agent database -file.
This is a enumeration callback function used by hit_db_enum_rgroups().
*/
int hit_db_save_rgroup_to_file(HIT_Group *g, void *p)
{
/* Variables. */
FILE *f = (FILE *)p;
char hit[128];
fprintf(f, "g \"%s\" \"%s\" %d %d\n", g->name, g->l->name, g->type, g->lightweight);
return (0);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Write local HIT to agent database -file.
This is a enumeration callback function used by hit_db_enum_locals().
*/
int hit_db_save_local_to_file(HIT_Local *local, void *p)
{
/* Variables. */
FILE *f = (FILE *)p;
char hit[128];
print_hit_to_buffer(hit, &local->lhit);
fprintf(f, "l \"%s\" %s\n", local->name, hit);
return (0);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Write remote HIT to agent database -file.
This is a enumeration callback function used by hit_db_enum_locals().
*/
int hit_db_save_remote_to_file(HIT_Remote *r, void *p)
{
/* Variables. */
FILE *f = (FILE *)p;
char hit[128];
print_hit_to_buffer(hit, &r->hit);
fprintf(f, "r %s \"%s\" \"%s\" \"%s\" \"%s\"\n", hit, r->name,
r->url, r->port, r->g->name);
return (0);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Load database from file.
@param file Filename for saving database.
@return 0 on success, -1 on errors.
*/
int hit_db_load_from_file(char *file)
{
/* Variables. */
FILE *f = NULL;
char buf[2048], ch;
int err = 0, i, n;
struct in6_addr hit;
hit_db_clear();
HIT_DB_LOCK();
HIP_DEBUG("Loading HIT database from %s.\n", file);
f = fopen(file, "r");
HIP_IFEL(!f, 0, "Failed to open HIT database file \"%s\" for reading.\n", file);
/* Start parsing. */
memset(buf, '\0', sizeof(buf)); i = 0; n = -1;
for (ch = fgetc(f); ch != EOF; ch = fgetc(f))
{
/* Remove whitespaces from line start. */
if (i == 0 && (ch == ' ' || ch == '\t')) continue;
/* Find end of line. */
if (ch != '\n')
{
buf[i] = ch;
i++;
continue;
}
/*
Check whether there is carriage return
in the stream and remove it.
*/
ch = fgetc(f);
if (ch != '\r') ungetc(ch, f);
/* Check for empty lines and for commented lines. */
if (strlen(buf) < 3) goto loop_end;
if (buf[0] == '#') goto loop_end;
if (buf[0] == 'r') hit_db_parse_hit(&buf[2]);
else if (buf[0] == 'l') hit_db_parse_local(&buf[2]);
else if (buf[0] == 'g') hit_db_parse_rgroup(&buf[2]);
loop_end:
/* Clear buffer. */
memset(buf, '\0', sizeof(buf)); i = 0;
}
out_err:
if (f) fclose(f);
HIT_DB_UNLOCK();
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Load one HIT from given string.
@param buf String containing HIT information.
@return 0 on success, -1 on errors.
*/
int hit_db_parse_hit(char *buf)
{
/* Variables. */
HIT_Remote item;
struct in6_addr slhit, srhit;
int err = 0, n;
char type[128], lhit[128], group[320];
/* Parse values from current line. */
n = sscanf(buf, "%s \"%64[^\"]\" \"%1024[^\"]\" \"%1024[^\"]\" \"%64[^\"]\"",
lhit, item.name, item.url, item.port, group);
HIP_IFEL(n != 5, -1, "Broken line in database file: %s\n", buf);
HIP_DEBUG("Scanned HIT line with values: %s %s %s %s %s\n",
lhit, item.name, item.url, item.port, group);
read_hit_from_buffer(&item.hit, lhit);
item.g = hit_db_find_rgroup(group);
HIP_IFEL(item.g == NULL, -1, "Invalid group for HIT in database file!\n");
hit_db_add_hit(&item, 1);
out_err:
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Load one remote group from given string.
@param buf String containing remote group information.
@return 0 on success, -1 on errors.
*/
int hit_db_parse_rgroup(char *buf)
{
/* Variables. */
HIT_Local *l;
HIT_Group *g;
int err = 0, n;
char name[MAX_NAME_LEN + 1], hit[128];
int type, lightweight;
/* Parse values from current line. */
n = sscanf(buf, "\"%64[^\"]\" \"%64[^\"]\" %d %d",
name, hit, &type, &lightweight);
HIP_IFEL(n != 4, -1, "Broken line in database file: %s\n", buf);
HIP_DEBUG("Scanned remote group line with values: %s %s %d %d\n",
name, hit, type, lightweight);
l = hit_db_find_local(hit, NULL);
HIP_IFEL(!l, -1, "Failed to find local HIT for remote group!\n");
g = hit_db_add_rgroup(name, l, type, lightweight);
if (g && strncmp("default", name, MAX_NAME_LEN) == 0)
{
g->l = l;
g->type = type;
g->lightweight = lightweight;
}
out_err:
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Load one local HIT from given string.
@param buf String containing local HIT information.
@return 0 on success, -1 on errors.
*/
int hit_db_parse_local(char *buf)
{
/* Variables. */
int err = 0, n;
char name[MAX_NAME_LEN + 1], hit[128];
struct in6_addr lhit;
/* Parse values from current line. */
n = sscanf(buf, "\"%64[^\"]\" %s", name, hit);
HIP_IFEL(n != 2, -1, "Broken line in database file: %s\n", buf);
HIP_DEBUG("Scanned local HIT line with values: %s %s\n", name, hit);
read_hit_from_buffer(&lhit, hit);
hit_db_add_local(name, &lhit);
out_err:
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Add new remote group to HIT group database. Notice that this function don't
lock the database!
@return Returns pointer to new group or if group already existed, pointer
to old one. Returns NULL on errors.
*/
HIT_Group *hit_db_add_rgroup(char *name, HIT_Local *lhit,
int type, int lightweight)
{
/* Variables. */
HIT_Group *g, *err = NULL;
/* Check group name length. */
HIP_IFEL(strlen(name) < 1, NULL, "Remote group name too short.\n");
/* Check database for group already with same name. */
g = hit_db_find_rgroup(name);
HIP_IFEL(g != NULL, g, "Group already found from database, returning it."
" (This is not an actual error)\n");
/* Allocate new remote group item. */
g = (HIT_Group *)malloc(sizeof(HIT_Group));
HIP_IFEL(g == NULL, NULL, "Failed to allocate new remote group item.\n");
/* Setup remote group item. */
memset(g, 0, sizeof(HIT_Group));
NAMECPY(g->name, name);
g->l = lhit;
g->type = type;
g->lightweight = lightweight;
g->remotec = 0;
/* Add remote group item to database. */
if (group_db == NULL) group_db = g;
else group_db_last->next = (void *)g;
group_db_last = g;
group_db_n++;
HIP_DEBUG("New group added with name \"%s\", calling GUI to show it.\n", name);
/* Tell GUI to show new group item. */
gui_add_rgroup(g);
err = g;
out_err:
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Delete remote group from HIT group database.
@return 0 on success, -1 on errors.
*/
int hit_db_del_rgroup(char *name)
{
/* Variables. */
HIT_Group *g, *g2;
int err = 0;
/* Find group from database first. */
g = hit_db_find_rgroup(name);
HIP_IFEL(!g, -1, "Tried to delete unexisting group \"%s\" from database", name);
/* If group is first group.. */
if (g == group_db)
{
group_db = (HIT_Group *)g->next;
if (g == group_db_last) group_db_last = NULL;
}
else
{
/* Find previous group from database. */
g2 = group_db;
while (g2->next != (void *)g && g2) g2 = (HIT_Group *)g2->next;
HIP_IFEL(!g2, -1, "Could not find previous group for group \"%s\"!\n", name);
g2->next = g->next;
if (g == group_db_last) group_db_last = g2;
}
gui_delete_rgroup(name);
free(g);
group_db_n--;
/* If this was last group, re-create default group. */
if (group_db_n < 1) hit_db_add_rgroup("default", local_db, HIT_DB_TYPE_ACCEPT, 0);
out_err:
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Find a group from remote group database.
@param group Name of remote group to be searched.
@return Pointer to group found, or NULL if none found.
*/
HIT_Group *hit_db_find_rgroup(char *name)
{
/* Variables. */
HIT_Group *g;
g = group_db;
while (g != NULL)
{
if (strncmp(g->name, name, MAX_NAME_LEN) == 0) break;
g = (HIT_Group *)g->next;
}
return (g);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Enumerate all remote groups in database. This function does not lock the
database!
@param f Function to call for every group in database. This function should
return 0 if continue enumeration and something else, if enumeration
should be stopped.
@param p Pointer to user data.
@return Number of groups enumerated.
*/
int hit_db_enum_rgroups(int (*f)(HIT_Group *, void *), void *p)
{
/* Variables. */
HIT_Group *g;
int err = 0, n = 0;
g = group_db;
while (g != NULL && err == 0)
{
err = f(g, p);
n++;
g = (HIT_Group *)g->next;
}
HIP_DEBUG("Enumerated %d groups.\n", n);
return (n);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Add new local HIT database. Notice that this function don't
lock the database!
@return Returns pointer to new HIT or if HIT already existed, pointer
to old one. Returns NULL on errors.
*/
HIT_Local *hit_db_add_local(char *name, struct in6_addr *hit)
{
/* Variables. */
HIT_Local *h, *err = NULL;
/* Check HIT name length. */
HIP_IFEL(strlen(name) < 1, NULL, "Local HIT name too short.\n");
/* Check database for HIT already with same name. */
h = hit_db_find_local(name, NULL);
HIP_IFEL(h != NULL, h, "Local HIT already found from database, returning it."
" (This is not an actual error)\n");
h = hit_db_find_local(NULL, hit);
HIP_IFEL(h != NULL, h, "Local HIT already found from database, returning it."
" (This is not an actual error)\n");
/* Allocate new remote group item. */
h = (HIT_Local *)malloc(sizeof(HIT_Local));
HIP_IFEL(h == NULL, NULL, "Failed to allocate new local HIT.\n");
/* Setup local HIT. */
memset(h, 0, sizeof(HIT_Local));
NAMECPY(h->name, name);
memcpy(&h->lhit, hit, sizeof(struct in6_addr));
/* Add local HIT to database. */
if (local_db == NULL) local_db = h;
else local_db_last->next = (void *)h;
local_db_last = h;
local_db_n++;
if (group_db_n < 1)
{
HIP_DEBUG("Group database emty, adding default group.\n");
hit_db_add_rgroup(lang_get("default-group-name"), h, HIT_DB_TYPE_ACCEPT, 0);
}
HIP_DEBUG("New local HIT added with name \"%s\", calling GUI to show it.\n", name);
/* Tell GUI to show local HIT. */
gui_add_local_hit(h);
err = h;
out_err:
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Delete local HIT from database.
@return 0 on success, -1 on errors.
*/
int hit_db_del_local(char *name)
{
/* Variables. */
int err = -1;
/*! \todo Implement! */
HIP_DEBUG("Local HIT delete not implemented yet!!!\n");
out_err:
return (err);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Find a local HIT from database.
@param name Name of HIT to be searched.
@param hit HIT to be searched.
@return Pointer to HIT found, or NULL if none found.
*/
HIT_Local *hit_db_find_local(char *name, struct in6_addr *hit)
{
/* Variables. */
HIT_Local *h;
int err;
h = local_db;
while (h != NULL)
{
err = 0;
if (name == NULL) err++;
else if (strncmp(h->name, name, MAX_NAME_LEN) == 0) err++;
if (hit == NULL) err++;
else if (memcmp(&h->lhit, hit, sizeof(struct in6_addr)) == 0) err++;
if (err == 2) break;
h = (HIT_Local *)h->next;
}
return (h);
}
/* END OF FUNCTION */
/******************************************************************************/
/**
Enumerate all local HITs in database. This function locks the database.
@param f Function to call for every local HIT in database. This function
should return 0 if continue enumeration and something else, if
enumeration should be stopped.
@param p Pointer to user data.
@return Number of HITs enumerated.
*/
int hit_db_enum_locals(int (*f)(HIT_Local *, void *), void *p)
{
/* Variables. */
HIT_Local *h;
int err = 0, n = 0;
h = local_db;
while (h != NULL && err == 0)
{
err = f(h, p);
n++;
h = (HIT_Local *)h->next;
}
HIP_DEBUG("Enumerated %d local HITs.\n", n);
return (n);
}
/* END OF FUNCTION */
/******************************************************************************/
/** Return number of local HITs in database. */
int hit_db_count_locals(void)
{
return (local_db_n);
}
/* END OF FUNCTION */
/******************************************************************************/
/** Return default local HIT. */
HIT_Local *hit_db_default_local(void)
{
return (local_db);
}
/* END OF FUNCTION */
/* END OF SOURCE FILE */
/******************************************************************************/