namemap.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /* Copyright (c) 2003-2004, Roger Dingledine
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2018, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. #include "orconfig.h"
  6. #include "lib/container/smartlist.h"
  7. #include "lib/container/namemap.h"
  8. #include "lib/container/namemap_st.h"
  9. #include "lib/log/util_bug.h"
  10. #include "lib/malloc/malloc.h"
  11. #include "lib/string/printf.h"
  12. #include "ext/siphash.h"
  13. #include <string.h>
  14. /** Helper for namemap hashtable implementation: compare two entries. */
  15. static inline int
  16. mapped_name_eq(const mapped_name_t *a, const mapped_name_t *b)
  17. {
  18. return !strcmp(a->name, b->name);
  19. }
  20. /** Helper for namemap hashtable implementation: hash an entry. */
  21. static inline unsigned
  22. mapped_name_hash(const mapped_name_t *a)
  23. {
  24. return (unsigned) siphash24g(a->name, strlen(a->name));
  25. }
  26. HT_PROTOTYPE(namemap_ht, mapped_name_t, node, mapped_name_hash,
  27. mapped_name_eq)
  28. HT_GENERATE2(namemap_ht, mapped_name_t, node, mapped_name_hash,
  29. mapped_name_eq, 0.6, tor_reallocarray_, tor_free_)
  30. /** Set up an uninitialized <b>map</b>. */
  31. void
  32. namemap_init(namemap_t *map)
  33. {
  34. memset(map, 0, sizeof(*map));
  35. HT_INIT(namemap_ht, &map->ht);
  36. map->names = smartlist_new();
  37. }
  38. /** Return the name that <b>map</b> associates with a given <b>id</b>, or
  39. * NULL if there is no such name. */
  40. const char *
  41. namemap_get_name(const namemap_t *map, unsigned id)
  42. {
  43. if (map->names && id < (unsigned)smartlist_len(map->names)) {
  44. mapped_name_t *name = smartlist_get(map->names, (int)id);
  45. return name->name;
  46. } else {
  47. return NULL;
  48. }
  49. }
  50. /**
  51. * Return the name that <b>map</b> associates with a given <b>id</b>, or a
  52. * pointer to a statically allocated string describing the value of <b>id</b>
  53. * if no such name exists.
  54. **/
  55. const char *
  56. namemap_fmt_name(const namemap_t *map, unsigned id)
  57. {
  58. static char buf[32];
  59. const char *name = namemap_get_name(map, id);
  60. if (name)
  61. return name;
  62. tor_snprintf(buf, sizeof(buf), "{%u}", id);
  63. return buf;
  64. }
  65. /**
  66. * Helper: As namemap_get_id(), but requires that <b>name</b> is
  67. * <b>namelen</b> charaters long, and that <b>namelen</b> is no more than
  68. * MAX_NAMEMAP_NAME_LEN.
  69. */
  70. static unsigned
  71. namemap_get_id_unchecked(const namemap_t *map,
  72. const char *name,
  73. size_t namelen)
  74. {
  75. union {
  76. mapped_name_t n;
  77. char storage[MAX_NAMEMAP_NAME_LEN + sizeof(mapped_name_t) + 1];
  78. } u;
  79. memcpy(u.n.name, name, namelen);
  80. u.n.name[namelen] = 0;
  81. const mapped_name_t *found = HT_FIND(namemap_ht, &map->ht, &u.n);
  82. if (found) {
  83. tor_assert(map->names);
  84. tor_assert(smartlist_get(map->names, found->intval) == found);
  85. return found->intval;
  86. }
  87. return NAMEMAP_ERR;
  88. }
  89. /**
  90. * Return the identifier currently associated by <b>map</b> with the name
  91. * <b>name</b>, or NAMEMAP_ERR if no such identifier exists.
  92. **/
  93. unsigned
  94. namemap_get_id(const namemap_t *map,
  95. const char *name)
  96. {
  97. size_t namelen = strlen(name);
  98. if (namelen > MAX_NAMEMAP_NAME_LEN) {
  99. return NAMEMAP_ERR;
  100. }
  101. return namemap_get_id_unchecked(map, name, namelen);
  102. }
  103. /**
  104. * Return the identifier associated by <b>map</b> with the name
  105. * <b>name</b>, allocating a new identifier in <b>map</b> if none exists.
  106. *
  107. * Return NAMEMAP_ERR if <b>name</b> is too long, or if there are no more
  108. * identifiers we can allocate.
  109. **/
  110. unsigned
  111. namemap_get_or_create_id(namemap_t *map,
  112. const char *name)
  113. {
  114. size_t namelen = strlen(name);
  115. if (namelen > MAX_NAMEMAP_NAME_LEN) {
  116. return NAMEMAP_ERR;
  117. }
  118. if (PREDICT_UNLIKELY(map->names == NULL))
  119. map->names = smartlist_new();
  120. unsigned found = namemap_get_id_unchecked(map, name, namelen);
  121. if (found != NAMEMAP_ERR)
  122. return found;
  123. unsigned new_id = (unsigned)smartlist_len(map->names);
  124. if (new_id == NAMEMAP_ERR)
  125. return NAMEMAP_ERR; /* Can't allocate any more. */
  126. mapped_name_t *insert = tor_malloc_zero(
  127. offsetof(mapped_name_t, name) + namelen + 1);
  128. memcpy(insert->name, name, namelen+1);
  129. insert->intval = new_id;
  130. HT_INSERT(namemap_ht, &map->ht, insert);
  131. smartlist_add(map->names, insert);
  132. return new_id;
  133. }
  134. /** Return the number of entries in 'names' */
  135. size_t
  136. namemap_get_size(const namemap_t *map)
  137. {
  138. if (PREDICT_UNLIKELY(map->names == NULL))
  139. return 0;
  140. return smartlist_len(map->names);
  141. }
  142. /**
  143. * Release all storage held in <b>map</b>.
  144. */
  145. void
  146. namemap_clear(namemap_t *map)
  147. {
  148. if (!map)
  149. return;
  150. HT_CLEAR(namemap_ht, &map->ht);
  151. if (map->names) {
  152. SMARTLIST_FOREACH(map->names, mapped_name_t *, n,
  153. tor_free(n));
  154. smartlist_free(map->names);
  155. }
  156. memset(map, 0, sizeof(*map));
  157. }