/* * $Id: hash_spec.c,v 1.4 2002/10/17 20:02:30 ljb Exp $ * originally Id: hash_spec.c,v 1.14 1998/07/20 01:22:03 labovit Exp */ /* routines for handling special indicies in hashes */ #include #include #include "mrt.h" #include "trace.h" #include #include #include "config_file.h" #include #include #include "irrd.h" extern trace_t *default_trace; /* called when indexes are stored in main memory hash */ int irr_spec_hash_store (irr_database_t *database, char *key, char *value) { hash_item_t *hash_item; hash_item = New (hash_item_t); hash_item->key = strdup (key); hash_item->value = value; HASH_Insert (database->hash_spec, hash_item); return (1); } /* put a series of object offsets/lengths from a linked list */ void util_put_ll_objs (LINKED_LIST *ll, char **cp) { maint_objlist_t *maint_obj_p; u_short _type; char *c = *cp; LL_Iterate (ll, maint_obj_p) { UTIL_PUT_NETLONG (maint_obj_p->offset, c); UTIL_PUT_NETLONG (maint_obj_p->len, c); _type = (u_short) maint_obj_p->type; UTIL_PUT_NETSHORT (_type, c); /* type */ } *cp = c; } /* make a string from a linked list, each item is seperated by a ' ' */ void util_put_ll_string (LINKED_LIST *ll, char **cp) { irr_hash_string_t *p; char *c = *cp; LL_Iterate (ll, p) { strcpy (c, p->string); while (*++c); *c++ = ' '; } *c++ = '\0'; /* terminate with a null byte */ *cp = c; /* update pointer past the null */ } /* make a linked list of objects from a string */ void util_get_ll_objs (LINKED_LIST **ll, u_long items, char **cp) { maint_objlist_t *maint_obj_p; u_short _type; char *c = *cp; (*ll) = LL_Create (LL_DestroyFunction, free, 0); while (items > 0) { maint_obj_p = New(maint_objlist_t); UTIL_GET_NETLONG (maint_obj_p->offset, c); UTIL_GET_NETLONG (maint_obj_p->len, c); UTIL_GET_NETSHORT (_type, c); maint_obj_p->type = _type; LL_Add ((*ll), maint_obj_p); items--; } *cp = c; } /* make a linked list from a string, items in the string are seperated by a ' ' */ int util_get_ll_string (LINKED_LIST **ll, u_long items, char **cp) { char *a, *b; irr_hash_string_t tmp; int return_len; a = *cp; (*ll) = LL_Create (LL_Intrusive, True, LL_NextOffset, LL_Offset (&tmp, &tmp.next), LL_PrevOffset, LL_Offset (&tmp, &tmp.prev), LL_DestroyFunction, delete_irr_hash_string, 0); if (items == 0) return (0); while (items > 0) { if ((b = strchr (a, ' ')) == NULL) { /* this should't happen */ trace (ERROR, default_trace, "util_get_ll_string: badly formatted list - %s;\n", *cp); break; } *b = '\0'; LL_Add ((*ll), new_irr_hash_string (a)); *b++ = ' '; a = b; items--; } return_len = a - *cp; /* calculate the length of this string */ /* make cp point to the begining of the next item (skip null) */ *cp = a + 1; return (return_len); } /* Marshal the hash_spec_t struct into a hash_item_t struct. * this means flattening out the linked lists (ie, put both * ll's into a single char string). */ void store_hash_spec (irr_database_t *database, hash_spec_t *hash_sval) { char *cp, *buf; u_short _id; u_int str_size; hash_item_t *hash_x; _id = hash_sval->id; /* compute the size of the packed value string */ /* the lengths should include the '\0' at the end */ if (_id == MNTOBJS ) str_size = NETSHORT_SIZE + NETLONG_SIZE + hash_sval->items1 * (2 * NETLONG_SIZE + NETSHORT_SIZE); else { str_size = NETSHORT_SIZE + NETLONG_SIZE + hash_sval->len1 + 1; if (_id == SET_OBJX) str_size += NETLONG_SIZE + hash_sval->len2 + 1; } /* now pack up the value part */ cp = buf = malloc (str_size); UTIL_PUT_NETSHORT (_id, cp); UTIL_PUT_NETLONG (hash_sval->items1, cp); if (_id == MNTOBJS ) util_put_ll_objs(hash_sval->ll_1, &cp); else { if (hash_sval->items1 > 0) util_put_ll_string(hash_sval->ll_1, &cp); if (_id == SET_OBJX) { UTIL_PUT_NETLONG (hash_sval->items2, cp); if (hash_sval->items2 > 0) util_put_ll_string(hash_sval->ll_2, &cp); } } hash_x = HASH_Lookup (database->hash_spec, hash_sval->key); if (hash_x != NULL) HASH_Remove (database->hash_spec, hash_x); irr_spec_hash_store (database, hash_sval->key, buf); } void remove_hash_spec (irr_database_t *db, char *key) { /* printf("enter remove_hash_spec( key-(%s))\n",key); */ HASH_RemoveByKey (db->hash_spec, key); } hash_spec_t *fetch_hash_spec (irr_database_t *database, char *key, enum FETCH_T mode) { char *cp; u_short _id; hash_item_t *hash_item = NULL; hash_spec_t *hash_sval = NULL; hash_item = HASH_Lookup (database->hash_spec, key); if (hash_item) { cp = hash_item->value; hash_sval = New (hash_spec_t); hash_sval->key = strdup (key); UTIL_GET_NETSHORT (_id, cp); hash_sval->id = _id; UTIL_GET_NETLONG (hash_sval->items1, cp); if (_id == MNTOBJS) util_get_ll_objs (&hash_sval->ll_1, hash_sval->items1, &cp); else { if (mode == UNPACK) { hash_sval->len1 = util_get_ll_string (&hash_sval->ll_1, hash_sval->items1, &cp); if (_id == SET_OBJX) { UTIL_GET_NETLONG (hash_sval->items2, cp); hash_sval->len2 = util_get_ll_string (&hash_sval->ll_2, hash_sval->items2, &cp); } } else {/* FAST mode, just return the unpacked item, ie !gas */ hash_sval->len1 = strlen(cp); hash_sval->gas_answer = cp; /* points to the first string/gas answer */ } } } else hash_sval = NULL; return (hash_sval); } void memory_hash_spec_del (hash_spec_t *hash_value, enum SPEC_KEYS id, void *blob_item) { irr_hash_string_t *irr_hash_str; maint_objlist_t *maint_obj_p; switch (id) { case SET_OBJX: hash_value->len1 = hash_value->len2 = 0; hash_value->items1 = hash_value->items2 = 0; LL_Clear (hash_value->ll_1); LL_Clear (hash_value->ll_2); break; case SET_MBRSX: case GASX: if (blob_item == NULL) return; LL_Iterate (hash_value->ll_1, irr_hash_str) { if (!strcmp ((char *)blob_item, irr_hash_str->string)) { LL_Remove (hash_value->ll_1, irr_hash_str); hash_value->items1--; hash_value->len1 -= strlen ((char *)blob_item) + 1; break; } } break; case MNTOBJS: if (blob_item == NULL) return; LL_Iterate (hash_value->ll_1, maint_obj_p) { if (*((u_long *)blob_item) == maint_obj_p->offset) { LL_Remove (hash_value->ll_1, maint_obj_p); hash_value->items1--; break; } } break; default: trace (ERROR, default_trace, "memory_hash_spec_del() error. Got an unknown index id-type, cannot perform delete operation id-(%d)\n!", id); break; }; } hash_spec_t *memory_hash_spec_create (char *key, enum SPEC_KEYS id) { hash_spec_t *hash_value; irr_hash_string_t hash_str; hash_value = New (hash_spec_t); hash_value->id = id; hash_value->key = strdup (key); if (id == MNTOBJS) { hash_value->ll_1 = LL_Create (LL_DestroyFunction, free, 0); } else { hash_value->ll_1 = LL_Create (LL_Intrusive, True, LL_NextOffset, LL_Offset (&hash_str, &hash_str.next), LL_PrevOffset, LL_Offset (&hash_str, &hash_str.prev), LL_DestroyFunction, delete_irr_hash_string, 0); if (id == SET_OBJX) { hash_value->ll_2 = LL_Create (LL_Intrusive, True, LL_NextOffset, LL_Offset (&hash_str, &hash_str.next), LL_PrevOffset, LL_Offset (&hash_str, &hash_str.prev), LL_DestroyFunction, delete_irr_hash_string, 0); } } return (hash_value); } int memory_hash_spec_remove (irr_database_t *db, char *key, enum SPEC_KEYS id, void *blob_item) { hash_spec_t *hash_sval; convert_toupper(key); hash_sval = HASH_Lookup (db->hash_spec_tmp, key); if (hash_sval == NULL) { /* might be in the mem hash index */ if ((hash_sval = fetch_hash_spec (db, key, UNPACK)) == NULL) return (-1); /* item not found, can't delete */ HASH_Insert (db->hash_spec_tmp, hash_sval); } memory_hash_spec_del (hash_sval, id, blob_item); return (1); } int memory_hash_spec_store (irr_database_t *db, char *key, enum SPEC_KEYS id, irr_object_t *irr_object) { hash_spec_t *hash_sval; LINKED_LIST *ll_1 = NULL; LINKED_LIST *ll_2 = NULL; char *tmpstr; maint_objlist_t *maint_obj_p; int retval = 1; convert_toupper(key); hash_sval = HASH_Lookup (db->hash_spec_tmp, key); if (hash_sval == NULL) { /* might be in the mem hash index */ if ((hash_sval = fetch_hash_spec (db, key, UNPACK)) == NULL) hash_sval = memory_hash_spec_create (key, id); HASH_Insert (db->hash_spec_tmp, hash_sval); } /* if the hash lookup found something and the id's don't match * something is really wrong! */ if (id != hash_sval->id) { trace (ERROR, default_trace, "Attempt to add hash item with different id value-(key(%s),%d,%d)\n!", hash_sval->key, id, hash_sval->id); return (-1); } switch (id) { case SET_OBJX: if ( (ll_1 = irr_object->ll_as) != NULL) { if (hash_sval->items1 > 0) { /* there should be only one unique as-set or route-set object * and therefore we need only one 'members:'/ll_1 list */ trace (ERROR, default_trace, "Append to existing 'members:' list! Object key-(%s)\n", hash_sval->key); LL_Clear (hash_sval->ll_1); hash_sval->items1 = 0; hash_sval->len1 = 0; retval = -1; } LL_Iterate (ll_1, tmpstr) { LL_Add (hash_sval->ll_1, new_irr_hash_string (tmpstr)); hash_sval->len1 += strlen (tmpstr) + 1; hash_sval->items1++; } } if ( (ll_2 = irr_object->ll_mbr_by_ref) != NULL) { if (hash_sval->items2 > 0) { /* ditto above except 'mbrs_by_ref:'/ll_2 */ trace (ERROR, default_trace, "Append to existing 'mbrs_by_ref:' list! Object key-(%s)\n", hash_sval->key); LL_Clear (hash_sval->ll_2); hash_sval->items2 = 0; hash_sval->len2 = 0; retval = -1; } LL_Iterate (ll_2, tmpstr) { LL_Add (hash_sval->ll_2,new_irr_hash_string (tmpstr)); hash_sval->len2 += strlen (tmpstr) + 1; hash_sval->items2++; } } break; case SET_MBRSX: case GASX: if ( (tmpstr = irr_object->name) != NULL) { LL_Add (hash_sval->ll_1, new_irr_hash_string (tmpstr)); hash_sval->len1 += strlen (tmpstr) + 1; hash_sval->items1++; } break; case MNTOBJS: maint_obj_p = New(maint_objlist_t); maint_obj_p->offset = irr_object->offset; maint_obj_p->len = irr_object->len; maint_obj_p->type = irr_object->type; LL_Add (hash_sval->ll_1, maint_obj_p); hash_sval->items1++; break; } return(retval); } /* this delete's the spec temp memory hash */ void Delete_hash_spec (hash_spec_t *hash_sval) { if (hash_sval == NULL) return; if (hash_sval->key) Delete (hash_sval->key); if (hash_sval->ll_1) LL_Destroy (hash_sval->ll_1); if (hash_sval->id == SET_OBJX) { if (hash_sval->ll_2) LL_Destroy (hash_sval->ll_2); } Delete (hash_sval); } /* commit our mem index to our regular index for 2 reasons: * 1. the regular index is suitable for mem and disk storage * ie, there are no linked lists. * 2. it is faster to manipulate mem indexes, so our disk * scan processing will be faster and they need to be * written to disk anyway. */ void commit_spec_hash (irr_database_t *db) { hash_spec_t *hash_tval; HASH_Iterate (db->hash_spec_tmp, hash_tval) { if (hash_tval->items1 == 0 && hash_tval->items2 == 0) remove_hash_spec (db, hash_tval->key); else store_hash_spec (db, hash_tval); } } /* makes the keys for the mbrs-by-ref hash * used in the rpsl !i command */ void make_spec_key (char *new_key, char *maint, char *set_name) { /* some objects may not have a maintainer ;) */ if (maint != NULL) strcpy (new_key, maint); else strcpy (new_key, "ANY"); strcat (new_key, "|"); strcat (new_key, set_name); convert_toupper (new_key); } /* makes the keys for the mbrs objects hash */ void make_mntobj_key (char *new_key, char *maint) { strcpy (new_key, "|"); /* key uniqueness */ strcat (new_key, maint); convert_toupper (new_key); } /* routine expects an origin without the "as", eg "231" */ void make_gas_key (char *gas_key, char *origin) { strcpy (gas_key, "@"); /* key uniqueness */ strcat (gas_key, origin); } void make_setobj_key (char *new_key, char *obj_name) { strcpy (new_key, "@"); /* key uniqueness */ strcat (new_key, obj_name); convert_toupper (new_key); }