mirror of
https://github.com/ChronosX88/netsukuku.git
synced 2024-12-23 09:21:47 +00:00
455 lines
12 KiB
C
455 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;
|
||
|
}
|