123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- /* Copyright (c) 2003-2004, Roger Dingledine
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2018, The Tor Project, Inc. */
- /* See LICENSE for licensing information */
- #include "orconfig.h"
- #include "lib/container/smartlist.h"
- #include "lib/container/namemap.h"
- #include "lib/container/namemap_st.h"
- #include "lib/log/util_bug.h"
- #include "lib/malloc/malloc.h"
- #include "lib/string/printf.h"
- #include "ext/siphash.h"
- #include <string.h>
- /** Helper for namemap hashtable implementation: compare two entries. */
- static inline int
- mapped_name_eq(const mapped_name_t *a, const mapped_name_t *b)
- {
- return !strcmp(a->name, b->name);
- }
- /** Helper for namemap hashtable implementation: hash an entry. */
- static inline unsigned
- mapped_name_hash(const mapped_name_t *a)
- {
- return (unsigned) siphash24g(a->name, strlen(a->name));
- }
- HT_PROTOTYPE(namemap_ht, mapped_name_t, node, mapped_name_hash,
- mapped_name_eq)
- HT_GENERATE2(namemap_ht, mapped_name_t, node, mapped_name_hash,
- mapped_name_eq, 0.6, tor_reallocarray_, tor_free_)
- /** Set up an uninitialized <b>map</b>. */
- void
- namemap_init(namemap_t *map)
- {
- memset(map, 0, sizeof(*map));
- HT_INIT(namemap_ht, &map->ht);
- map->names = smartlist_new();
- }
- /** Return the name that <b>map</b> associates with a given <b>id</b>, or
- * NULL if there is no such name. */
- const char *
- namemap_get_name(const namemap_t *map, unsigned id)
- {
- if (map->names && id < (unsigned)smartlist_len(map->names)) {
- mapped_name_t *name = smartlist_get(map->names, (int)id);
- return name->name;
- } else {
- return NULL;
- }
- }
- /**
- * Return the name that <b>map</b> associates with a given <b>id</b>, or a
- * pointer to a statically allocated string describing the value of <b>id</b>
- * if no such name exists.
- **/
- const char *
- namemap_fmt_name(const namemap_t *map, unsigned id)
- {
- static char buf[32];
- const char *name = namemap_get_name(map, id);
- if (name)
- return name;
- tor_snprintf(buf, sizeof(buf), "{%u}", id);
- return buf;
- }
- /**
- * Helper: As namemap_get_id(), but requires that <b>name</b> is
- * <b>namelen</b> charaters long, and that <b>namelen</b> is no more than
- * MAX_NAMEMAP_NAME_LEN.
- */
- static unsigned
- namemap_get_id_unchecked(const namemap_t *map,
- const char *name,
- size_t namelen)
- {
- union {
- mapped_name_t n;
- char storage[MAX_NAMEMAP_NAME_LEN + sizeof(mapped_name_t) + 1];
- } u;
- memcpy(u.n.name, name, namelen);
- u.n.name[namelen] = 0;
- const mapped_name_t *found = HT_FIND(namemap_ht, &map->ht, &u.n);
- if (found) {
- tor_assert(map->names);
- tor_assert(smartlist_get(map->names, found->intval) == found);
- return found->intval;
- }
- return NAMEMAP_ERR;
- }
- /**
- * Return the identifier currently associated by <b>map</b> with the name
- * <b>name</b>, or NAMEMAP_ERR if no such identifier exists.
- **/
- unsigned
- namemap_get_id(const namemap_t *map,
- const char *name)
- {
- size_t namelen = strlen(name);
- if (namelen > MAX_NAMEMAP_NAME_LEN) {
- return NAMEMAP_ERR;
- }
- return namemap_get_id_unchecked(map, name, namelen);
- }
- /**
- * Return the identifier associated by <b>map</b> with the name
- * <b>name</b>, allocating a new identifier in <b>map</b> if none exists.
- *
- * Return NAMEMAP_ERR if <b>name</b> is too long, or if there are no more
- * identifiers we can allocate.
- **/
- unsigned
- namemap_get_or_create_id(namemap_t *map,
- const char *name)
- {
- size_t namelen = strlen(name);
- if (namelen > MAX_NAMEMAP_NAME_LEN) {
- return NAMEMAP_ERR;
- }
- if (PREDICT_UNLIKELY(map->names == NULL))
- map->names = smartlist_new();
- unsigned found = namemap_get_id_unchecked(map, name, namelen);
- if (found != NAMEMAP_ERR)
- return found;
- unsigned new_id = (unsigned)smartlist_len(map->names);
- if (new_id == NAMEMAP_ERR)
- return NAMEMAP_ERR; /* Can't allocate any more. */
- mapped_name_t *insert = tor_malloc_zero(
- offsetof(mapped_name_t, name) + namelen + 1);
- memcpy(insert->name, name, namelen+1);
- insert->intval = new_id;
- HT_INSERT(namemap_ht, &map->ht, insert);
- smartlist_add(map->names, insert);
- return new_id;
- }
- /** Return the number of entries in 'names' */
- size_t
- namemap_get_size(const namemap_t *map)
- {
- if (PREDICT_UNLIKELY(map->names == NULL))
- return 0;
- return smartlist_len(map->names);
- }
- /**
- * Release all storage held in <b>map</b>.
- */
- void
- namemap_clear(namemap_t *map)
- {
- if (!map)
- return;
- HT_CLEAR(namemap_ht, &map->ht);
- if (map->names) {
- SMARTLIST_FOREACH(map->names, mapped_name_t *, n,
- tor_free(n));
- smartlist_free(map->names);
- }
- memset(map, 0, sizeof(*map));
- }
|