netsukuku/src/bmap.c
Alexander von Gluck IV e264723db2 all: Automatic style cleanup, KnR. No functional change.
* Style varied wildly between files and within files.
* find . -name "*.c" -exec indent {} -ut -ts4 -kr -psl \;
* find . -name "*.h" -exec indent {} -ut -ts4 -kr -psl \;
2014-09-17 07:41:24 -05:00

486 lines
12 KiB
C

/* This file is part of Netsukuku
* (c) Copyright 2005 Andrea Lo Pumo aka AlpT <alpt@freaknet.org>
*
* This source code 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 source code 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.
* Please refer to the GNU Public License for more details.
*
* You should have received a copy of the GNU Public License along with
* this source code; if not, write to:
* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* --
* bmap.c:
* Border node map code.
*/
#include "includes.h"
#include "common.h"
#include "inet.h"
#include "endianness.h"
#include "map.h"
#include "gmap.h"
#include "bmap.h"
void
bmap_levels_init(u_char levels, map_bnode *** bmap, u_int ** bmap_nodes)
{
*bmap = xmalloc(sizeof(map_bnode *) * levels);
*bmap_nodes = (u_int *) xmalloc(sizeof(u_int) * levels);
setzero(*bmap, sizeof(map_bnode *) * levels);
bmap_counter_reset(levels, *bmap_nodes);
}
void
bmap_levels_free(map_bnode ** bmap, u_int * bmap_nodes)
{
xfree(bmap);
xfree(bmap_nodes);
}
void
bmap_counter_init(u_char levels, u_int ** bnodes_closed,
u_int ** bnodes_opened)
{
*bnodes_closed = (u_int *) xmalloc(sizeof(u_int) * levels);
*bnodes_opened = (u_int *) xmalloc(sizeof(u_int) * levels);
bmap_counter_reset(levels, *bnodes_closed);
bmap_counter_reset(levels, *bnodes_opened);
}
void
bmap_counter_free(u_int * bnodes_closed, u_int * bnodes_opened)
{
xfree(bnodes_closed);
xfree(bnodes_opened);
}
void
bmap_counter_reset(u_char levels, u_int * counter)
{
setzero(counter, sizeof(u_int) * levels);
}
/*
* map_add_bnode: It adds a new bnode in the `bmap' and then returns its position
* in the bmap. It also increments the `*bmap_nodes' counter. The bnode_ptr is set
* to `bnode' and the links to `links'.
* Note that the `bmap' argument must be an adress of a pointer.
*/
int
map_add_bnode(map_bnode ** bmap, u_int * bmap_nodes, u_int bnode,
u_int links)
{
map_bnode *bnode_map;
u_int bm;
bm = *bmap_nodes;
(*bmap_nodes)++;
if (!bm)
*bmap = xmalloc(sizeof(map_bnode));
else
*bmap = xrealloc(*bmap, sizeof(map_bnode) * *bmap_nodes);
bnode_map = *bmap;
setzero(bnode_map, sizeof(map_bnode));
bnode_map[bm].bnode_ptr = bnode;
bnode_map[bm].links = links;
return bm;
}
/*
* map_bnode_del: It deletes the `bnode' in the `bmap' which has `bmap_nodes'.
* It returns the newly rescaled `bmap'.
* It returns 0 if the `bmap' doesn't exist anymore.*/
map_bnode *
map_bnode_del(map_bnode * bmap, u_int * bmap_nodes, map_bnode * bnode)
{
map_node_del((map_node *) bnode);
if (((char *) bnode - (char *) bmap) / sizeof(map_bnode) !=
(*bmap_nodes) - 1)
memcpy(bnode, &bmap[*bmap_nodes - 1], sizeof(map_bnode));
(*bmap_nodes)--;
if (*bmap_nodes)
return xrealloc(bmap, (*bmap_nodes) * sizeof(map_bnode));
else {
*bmap_nodes = 0;
xfree(bmap);
return 0;
}
}
/*
* bmap_del_rnode_by_level: it is pretty specific, it deletes all the rnodes
* of `bnode' which point to a gnode located in a level not equal to `level'.
* The number of rnode deleted is returned.
* `total_levels' must be equal to the maximum levels
* available (use FAMILY_LVLS).
*/
int
bmap_del_rnode_by_level(map_bnode * bnode, int level, map_gnode ** ext_map,
int total_levels)
{
map_gnode *gn;
int i, ret = 0, lvl;
for (i = 0; i < bnode->links; i++) {
gn = (map_gnode *) bnode->r_node[i].r_node;
lvl = extmap_find_level(ext_map, gn, total_levels);
if (lvl != level) {
rnode_del(bnode, i);
ret++;
}
}
return ret;
}
/*
* map_find_bnode: Find the given `node' (in the pos_from_node() format) in the
* given map_bnode `bmap'.
*/
int
map_find_bnode(map_bnode * bmap, int bmap_nodes, int node)
{
int e;
for (e = 0; e < bmap_nodes; e++)
if (bmap[e].bnode_ptr == node)
return e;
return -1;
}
/*
* map_find_bnode_rnode: Find the first bnode in the `bmap' which has a rnode
* which points to `n'. If it is found the pos of the bnode in the `bmap' is
* returned, otherwise -1 is the return value.
*/
int
map_find_bnode_rnode(map_bnode * bmap, int bmap_nodes, void *n)
{
int e;
for (e = 0; e < bmap_nodes; e++)
if (rnode_find((map_node *) & bmap[e], (map_node *) n) != -1)
return e;
return -1;
}
/*
* map_count_bnode_rnode: counts how many bnode which have a rnode which
* points to `n' there are in `bmap'.
*/
int
map_count_bnode_rnode(map_bnode * bmap, int bmap_nodes, void *n)
{
int e, i;
for (i = 0, e = 0; i < bmap_nodes; i++)
if (rnode_find((map_node *) & bmap[i], (map_node *) n) != -1)
e++;
return e;
}
/*
* bmaps_count_bnode_rnode: applies map_count_bnode_rnode() to each level of
* `bmap' and returns the sum of the results.
* `levels' are the total levels of `bmap'.
*/
int
bmaps_count_bnode_rnode(map_bnode ** bmap, int *bmap_nodes, int levels,
void *n)
{
int i, e;
for (i = 0, e = 0; i < levels; i++)
e += map_count_bnode_rnode(bmap[i], bmap_nodes[i], n);
return e;
}
/*
* map_del_bnode_rnode: deletes all the rnodes of the bnode, present in `bmap',
* which points to `n' and deletes the bnodes remained empty.
* `bmap' is the address of the pointer to the bmap.
* It returns the number of rnodes deleted.
*/
int
map_del_bnode_rnode(map_bnode ** bmap, int *bmap_nodes, void *n)
{
map_bnode *bm;
int e, p, ret = 0;
bm = *bmap;
for (e = 0; e < *bmap_nodes; e++) {
if ((p = rnode_find((map_node *) & bm[e], (map_node *) n)) != -1) {
rnode_del(&bm[e], p);
if (!bm[e].links) {
*bmap = map_bnode_del(*bmap, (u_int *) bmap_nodes, &bm[e]);
bm = *bmap;
}
ret++;
}
}
return ret;
}
/*
* bmaps_del_bnode_rnode: applies map_del_bnode_rnode() to each level of
* `bmap'.
* `levels' are the total levels of `bmap'.
* It returns the total number of rnodes deleted
*/
int
bmaps_del_bnode_rnode(map_bnode ** bmap, int *bmap_nodes, int levels,
void *n)
{
int i, e;
for (i = 0, e = 0; i < levels; i++)
e += map_del_bnode_rnode(&bmap[i], &bmap_nodes[i], n);
return e;
}
/*
* map_set_bnode_flag: sets the `flags' to all the `bmap_nodes'# present in
* `bmap'.
*/
void
map_set_bnode_flag(map_bnode * bmap, int bmap_nodes, int flags)
{
int e;
for (e = 0; e < bmap_nodes; e++)
bmap[e].flags |= flags;
}
/*
* bmaps_set_bnode_flag: sets the `flags' to all the bnodes present in the
* `levels'# `bmap'.
*/
void
bmaps_set_bnode_flag(map_bnode ** bmap, int *bmap_nodes, int levels,
int flags)
{
int i;
for (i = 0; i < levels; i++)
map_set_bnode_flag(bmap[i], bmap_nodes[i], flags);
}
/*
* pack_all_bmaps: It creates the block of all the `bmaps' which have
* `bmap_nodes' nodes. `ext_map' and `quadg' are the structs referring
* to the external map. In `pack_sz' is stored the size of the block.
* The address pointing to the block is returned otherwise 0 is given.
* The package will be in network order.
*/
char *
pack_all_bmaps(map_bnode ** bmaps, u_int * bmap_nodes,
map_gnode ** ext_map, quadro_group quadg, size_t * pack_sz)
{
struct bnode_maps_hdr bmaps_hdr;
size_t sz, tmp_sz[BMAP_LEVELS(quadg.levels)];
char *pack[BMAP_LEVELS(quadg.levels)], *final_pack, *buf;
u_char level;
*pack_sz = 0;
for (level = 0; level < BMAP_LEVELS(quadg.levels); level++) {
pack[level] =
pack_map((map_node *) bmaps[level],
(int *) ext_map[_EL(level + 1)], bmap_nodes[level], 0,
&sz);
tmp_sz[level] = sz;
(*pack_sz) += sz;
}
bmaps_hdr.levels = BMAP_LEVELS(quadg.levels);
bmaps_hdr.bmaps_block_sz = *pack_sz;
(*pack_sz) += sizeof(struct bnode_maps_hdr);
final_pack = xmalloc((*pack_sz));
memcpy(final_pack, &bmaps_hdr, sizeof(struct bnode_maps_hdr));
ints_host_to_network(final_pack, bnode_maps_hdr_iinfo);
buf = final_pack + sizeof(struct bnode_maps_hdr);
for (level = 0; level < BMAP_LEVELS(quadg.levels); level++) {
memcpy(buf, pack[level], tmp_sz[level]);
buf += tmp_sz[level];
xfree(pack[level]);
}
return final_pack;
}
/*
* unpack_all_bmaps: Given a block `pack' of size `pack_sz' containing `levels'
* it unpacks each bnode map it finds in it.
* `ext_map' is the external map used by the new bmaps.
* In `bmap_nodes' unpack_all_bmaps stores the address of the newly xmallocated
* array of u_int. Each bmap_nodes[x] contains the number of nodes of the bmap
* of level x.
* `maxbnodes' is the maximum number of nodes each bmap can contain,
* while `maxbnode_rnodeblock' is the maximum number of rnodes each node can
* contain.
* On error 0 is returned.
* Note: `pack' will be modified during the unpacking.
*/
map_bnode **
unpack_all_bmaps(char *pack, u_char max_levels, map_gnode ** ext_map,
u_int ** bmap_nodes, int maxbnodes,
int maxbnode_rnodeblock)
{
struct bnode_maps_hdr *bmaps_hdr;
struct bnode_map_hdr *bmap_hdr;
map_bnode **bmap, *unpacked_bmap;
size_t bblock_sz, pack_sz;
int i, e = 0;
char *bblock, *buf;
u_char levels;
bmaps_hdr = (struct bnode_maps_hdr *) pack;
ints_network_to_host(bmaps_hdr, bnode_maps_hdr_iinfo);
levels = bmaps_hdr->levels;
pack_sz = bmaps_hdr->bmaps_block_sz;
if (levels > max_levels || pack_sz < sizeof(struct bnode_maps_hdr))
return 0;
bmap_levels_init(levels, &bmap, bmap_nodes);
buf = pack + sizeof(struct bnode_maps_hdr);
for (i = 0; i < levels; i++) {
bmap_hdr = (struct bnode_map_hdr *) buf;
if (!bmap_hdr->bnode_map_sz) {
buf += sizeof(struct bnode_map_hdr);
continue;
}
/*Extracting the map... */
bblock = (char *) bmap_hdr;
unpacked_bmap = unpack_map(bblock, (int *) ext_map[_EL(i + 1)], 0,
maxbnodes, maxbnode_rnodeblock);
if (!unpacked_bmap) {
error("Cannot unpack the bnode_map at level %d ! Skipping...",
i);
e++;
continue;
}
(*bmap_nodes)[i] = bmap_hdr->bnode_map_sz / MAP_BNODE_PACK_SZ;
bblock_sz =
INT_MAP_BLOCK_SZ(bmap_hdr->bnode_map_sz, bmap_hdr->rblock_sz);
bmap[i] = unpacked_bmap;
buf += bblock_sz;
}
if (e == levels)
/* Not a single map was restored */
return 0;
return bmap;
}
/* * * save/load bnode_map * * */
/*
* save_bmap: It saves the bnode maps `bmaps' in `file'. The each `bmaps[x]' has
* `bmap_nodes[x]' nodes. `ext_map' is the pointer to the external map the bmap is
* referring to.
*/
int
save_bmap(map_bnode ** bmaps, u_int * bmap_nodes, map_gnode ** ext_map,
quadro_group quadg, char *file)
{
FILE *fd;
char *pack;
size_t pack_sz;
pack = pack_all_bmaps(bmaps, bmap_nodes, ext_map, quadg, &pack_sz);
if (!pack_sz || !pack)
return 0;
if ((fd = fopen(file, "w")) == NULL) {
error("Cannot save the bnode_map in %s: %s", file,
strerror(errno));
return -1;
}
fwrite(pack, pack_sz, 1, fd);
xfree(pack);
fclose(fd);
return 0;
}
/*
* load_bmap: It loads all the bnode maps from `file' and returns the address
* of the array of pointer to the loaded bmaps. `ext_map' is the external maps
* the bmap shall refer to. In `bmap_nodes' the address of the u_int array, used
* to count the nodes in each bmaps, is stored. On error 0 is returned.
*/
map_bnode **
load_bmap(char *file, map_gnode ** ext_map, u_char max_levels,
u_int ** bmap_nodes)
{
map_bnode **bmap = 0;
FILE *fd;
struct bnode_maps_hdr bmaps_hdr;
size_t pack_sz;
u_char levels;
char *pack = 0;
if ((fd = fopen(file, "r")) == NULL) {
error("Cannot load the bmap from %s: %s", file, strerror(errno));
return 0;
}
if (!fread(&bmaps_hdr, sizeof(struct bnode_maps_hdr), 1, fd))
goto finish;
ints_network_to_host(&bmaps_hdr, bnode_maps_hdr_iinfo);
levels = bmaps_hdr.levels;
pack_sz = bmaps_hdr.bmaps_block_sz;
if (levels > max_levels || pack_sz < sizeof(struct bnode_maps_hdr))
goto finish;
/* Extracting the map... */
rewind(fd);
pack = xmalloc(pack_sz);
if (!fread(pack, pack_sz, 1, fd))
goto finish;
bmap = unpack_all_bmaps(pack, max_levels, ext_map, bmap_nodes,
MAXGROUPNODE, MAXBNODE_RNODEBLOCK);
finish:
fclose(fd);
if (pack)
xfree(pack);
if (!bmap)
error("Malformed bmap file. Cannot load the bnode maps.");
return bmap;
}