1 /* Copyright (c) 2003-2004, Roger Dingledine
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
8 * @brief Mappings between identifiers and 16-bit ints.
12 #include "lib/container/smartlist.h"
13 #include "lib/container/namemap.h"
14 #include "lib/container/namemap_st.h"
15 #include "lib/log/util_bug.h"
16 #include "lib/malloc/malloc.h"
17 #include "lib/string/printf.h"
19 #include "ext/siphash.h"
23 /** Helper for namemap hashtable implementation: compare two entries. */
25 mapped_name_eq(const mapped_name_t
*a
, const mapped_name_t
*b
)
27 return !strcmp(a
->name
, b
->name
);
30 /** Helper for namemap hashtable implementation: hash an entry. */
31 static inline unsigned
32 mapped_name_hash(const mapped_name_t
*a
)
34 return (unsigned) siphash24g(a
->name
, strlen(a
->name
));
37 HT_PROTOTYPE(namemap_ht
, mapped_name_t
, node
, mapped_name_hash
,
39 HT_GENERATE2(namemap_ht
, mapped_name_t
, node
, mapped_name_hash
,
40 mapped_name_eq
, 0.6, tor_reallocarray_
, tor_free_
);
42 /** Set up an uninitialized <b>map</b>. */
44 namemap_init(namemap_t
*map
)
46 memset(map
, 0, sizeof(*map
));
47 HT_INIT(namemap_ht
, &map
->ht
);
48 map
->names
= smartlist_new();
51 /** Return the name that <b>map</b> associates with a given <b>id</b>, or
52 * NULL if there is no such name. */
54 namemap_get_name(const namemap_t
*map
, unsigned id
)
56 if (map
->names
&& id
< (unsigned)smartlist_len(map
->names
)) {
57 mapped_name_t
*name
= smartlist_get(map
->names
, (int)id
);
65 * Return the name that <b>map</b> associates with a given <b>id</b>, or a
66 * pointer to a statically allocated string describing the value of <b>id</b>
67 * if no such name exists.
70 namemap_fmt_name(const namemap_t
*map
, unsigned id
)
74 const char *name
= namemap_get_name(map
, id
);
78 tor_snprintf(buf
, sizeof(buf
), "{%u}", id
);
84 * Helper: As namemap_get_id(), but requires that <b>name</b> is
85 * <b>namelen</b> characters long, and that <b>namelen</b> is no more than
86 * MAX_NAMEMAP_NAME_LEN.
89 namemap_get_id_unchecked(const namemap_t
*map
,
95 char storage
[MAX_NAMEMAP_NAME_LEN
+ sizeof(mapped_name_t
) + 1];
97 memcpy(u
.n
.name
, name
, namelen
);
98 u
.n
.name
[namelen
] = 0;
99 const mapped_name_t
*found
= HT_FIND(namemap_ht
, &map
->ht
, &u
.n
);
101 tor_assert(map
->names
);
102 tor_assert(smartlist_get(map
->names
, found
->intval
) == found
);
103 return found
->intval
;
110 * Return the identifier currently associated by <b>map</b> with the name
111 * <b>name</b>, or NAMEMAP_ERR if no such identifier exists.
114 namemap_get_id(const namemap_t
*map
,
117 size_t namelen
= strlen(name
);
118 if (namelen
> MAX_NAMEMAP_NAME_LEN
) {
122 return namemap_get_id_unchecked(map
, name
, namelen
);
126 * Return the identifier associated by <b>map</b> with the name
127 * <b>name</b>, allocating a new identifier in <b>map</b> if none exists.
129 * Return NAMEMAP_ERR if <b>name</b> is too long, or if there are no more
130 * identifiers we can allocate.
133 namemap_get_or_create_id(namemap_t
*map
,
136 size_t namelen
= strlen(name
);
137 if (namelen
> MAX_NAMEMAP_NAME_LEN
) {
141 if (PREDICT_UNLIKELY(map
->names
== NULL
))
142 map
->names
= smartlist_new();
144 unsigned found
= namemap_get_id_unchecked(map
, name
, namelen
);
145 if (found
!= NAMEMAP_ERR
)
148 unsigned new_id
= (unsigned)smartlist_len(map
->names
);
149 if (new_id
== NAMEMAP_ERR
)
150 return NAMEMAP_ERR
; /* Can't allocate any more. */
152 mapped_name_t
*insert
= tor_malloc_zero(
153 offsetof(mapped_name_t
, name
) + namelen
+ 1);
154 memcpy(insert
->name
, name
, namelen
+1);
155 insert
->intval
= new_id
;
157 HT_INSERT(namemap_ht
, &map
->ht
, insert
);
158 smartlist_add(map
->names
, insert
);
163 /** Return the number of entries in 'names' */
165 namemap_get_size(const namemap_t
*map
)
167 if (PREDICT_UNLIKELY(map
->names
== NULL
))
170 return smartlist_len(map
->names
);
174 * Release all storage held in <b>map</b>.
177 namemap_clear(namemap_t
*map
)
182 HT_CLEAR(namemap_ht
, &map
->ht
);
184 SMARTLIST_FOREACH(map
->names
, mapped_name_t
*, n
,
186 smartlist_free(map
->names
);
188 memset(map
, 0, sizeof(*map
));