registry_person.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "daemon/common.h"
  3. #include "registry_internals.h"
  4. // ----------------------------------------------------------------------------
  5. // PERSON_URL INDEX
  6. int person_url_compare(void *a, void *b) {
  7. register uint32_t hash1 = ((REGISTRY_PERSON_URL *)a)->url->hash;
  8. register uint32_t hash2 = ((REGISTRY_PERSON_URL *)b)->url->hash;
  9. if(hash1 < hash2) return -1;
  10. else if(hash1 > hash2) return 1;
  11. else return strcmp(((REGISTRY_PERSON_URL *)a)->url->url, ((REGISTRY_PERSON_URL *)b)->url->url);
  12. }
  13. inline REGISTRY_PERSON_URL *registry_person_url_index_find(REGISTRY_PERSON *p, const char *url) {
  14. debug(D_REGISTRY, "Registry: registry_person_url_index_find('%s', '%s')", p->guid, url);
  15. char buf[sizeof(REGISTRY_URL) + strlen(url)];
  16. REGISTRY_URL *u = (REGISTRY_URL *)&buf;
  17. strcpy(u->url, url);
  18. u->hash = simple_hash(u->url);
  19. REGISTRY_PERSON_URL tpu = { .url = u };
  20. REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)avl_search(&p->person_urls, (void *)&tpu);
  21. return pu;
  22. }
  23. inline REGISTRY_PERSON_URL *registry_person_url_index_add(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
  24. debug(D_REGISTRY, "Registry: registry_person_url_index_add('%s', '%s')", p->guid, pu->url->url);
  25. REGISTRY_PERSON_URL *tpu = (REGISTRY_PERSON_URL *)avl_insert(&(p->person_urls), (avl_t *)(pu));
  26. if(tpu != pu)
  27. error("Registry: registry_person_url_index_add('%s', '%s') already exists as '%s'", p->guid, pu->url->url, tpu->url->url);
  28. return tpu;
  29. }
  30. inline REGISTRY_PERSON_URL *registry_person_url_index_del(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
  31. debug(D_REGISTRY, "Registry: registry_person_url_index_del('%s', '%s')", p->guid, pu->url->url);
  32. REGISTRY_PERSON_URL *tpu = (REGISTRY_PERSON_URL *)avl_remove(&(p->person_urls), (avl_t *)(pu));
  33. if(!tpu)
  34. error("Registry: registry_person_url_index_del('%s', '%s') deleted nothing", p->guid, pu->url->url);
  35. else if(tpu != pu)
  36. error("Registry: registry_person_url_index_del('%s', '%s') deleted wrong URL '%s'", p->guid, pu->url->url, tpu->url->url);
  37. return tpu;
  38. }
  39. // ----------------------------------------------------------------------------
  40. // PERSON_URL
  41. REGISTRY_PERSON_URL *registry_person_url_allocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when) {
  42. debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url, sizeof(REGISTRY_PERSON_URL) + namelen);
  43. // protection from too big names
  44. if(namelen > registry.max_name_length)
  45. namelen = registry.max_name_length;
  46. REGISTRY_PERSON_URL *pu = mallocz(sizeof(REGISTRY_PERSON_URL) + namelen);
  47. // a simple strcpy() should do the job
  48. // but I prefer to be safe, since the caller specified urllen
  49. strncpyz(pu->machine_name, name, namelen);
  50. pu->machine = m;
  51. pu->first_t = pu->last_t = (uint32_t)when;
  52. pu->usages = 1;
  53. pu->url = u;
  54. pu->flags = REGISTRY_URL_FLAGS_DEFAULT;
  55. m->links++;
  56. registry.persons_urls_memory += sizeof(REGISTRY_PERSON_URL) + namelen;
  57. debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, u->url);
  58. REGISTRY_PERSON_URL *tpu = registry_person_url_index_add(p, pu);
  59. if(tpu != pu) {
  60. error("Registry: Attempted to add duplicate person url '%s' with name '%s' to person '%s'", u->url, name, p->guid);
  61. freez(pu);
  62. pu = tpu;
  63. }
  64. else
  65. registry_url_link(u);
  66. return pu;
  67. }
  68. void registry_person_url_free(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
  69. debug(D_REGISTRY, "registry_person_url_free('%s', '%s')", p->guid, pu->url->url);
  70. REGISTRY_PERSON_URL *tpu = registry_person_url_index_del(p, pu);
  71. if(tpu) {
  72. registry_url_unlink(tpu->url);
  73. tpu->machine->links--;
  74. registry.persons_urls_memory -= sizeof(REGISTRY_PERSON_URL) + strlen(tpu->machine_name);
  75. freez(tpu);
  76. }
  77. }
  78. // this function is needed to change the name of a PERSON_URL
  79. REGISTRY_PERSON_URL *registry_person_url_reallocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when, REGISTRY_PERSON_URL *pu) {
  80. debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url, sizeof(REGISTRY_PERSON_URL) + namelen);
  81. // keep a backup
  82. REGISTRY_PERSON_URL pu2 = {
  83. .first_t = pu->first_t,
  84. .last_t = pu->last_t,
  85. .usages = pu->usages,
  86. .flags = pu->flags,
  87. .machine = pu->machine,
  88. .machine_name = ""
  89. };
  90. // remove the existing one from the index
  91. registry_person_url_free(p, pu);
  92. pu = &pu2;
  93. // allocate a new one
  94. REGISTRY_PERSON_URL *tpu = registry_person_url_allocate(p, m, u, name, namelen, when);
  95. tpu->first_t = pu->first_t;
  96. tpu->last_t = pu->last_t;
  97. tpu->usages = pu->usages;
  98. tpu->flags = pu->flags;
  99. return tpu;
  100. }
  101. // ----------------------------------------------------------------------------
  102. // PERSON
  103. REGISTRY_PERSON *registry_person_find(const char *person_guid) {
  104. debug(D_REGISTRY, "Registry: registry_person_find('%s')", person_guid);
  105. return dictionary_get(registry.persons, person_guid);
  106. }
  107. REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when) {
  108. debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(REGISTRY_PERSON));
  109. REGISTRY_PERSON *p = mallocz(sizeof(REGISTRY_PERSON));
  110. if(!person_guid) {
  111. for(;;) {
  112. uuid_t uuid;
  113. uuid_generate(uuid);
  114. uuid_unparse_lower(uuid, p->guid);
  115. debug(D_REGISTRY, "Registry: Checking if the generated person guid '%s' is unique", p->guid);
  116. if (!dictionary_get(registry.persons, p->guid)) {
  117. debug(D_REGISTRY, "Registry: generated person guid '%s' is unique", p->guid);
  118. break;
  119. }
  120. else
  121. info("Registry: generated person guid '%s' found in the registry. Retrying...", p->guid);
  122. }
  123. }
  124. else
  125. strncpyz(p->guid, person_guid, GUID_LEN);
  126. debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): creating dictionary of urls", p->guid);
  127. avl_init(&p->person_urls, person_url_compare);
  128. p->first_t = p->last_t = (uint32_t)when;
  129. p->usages = 0;
  130. registry.persons_memory += sizeof(REGISTRY_PERSON);
  131. registry.persons_count++;
  132. dictionary_set(registry.persons, p->guid, p, sizeof(REGISTRY_PERSON));
  133. return p;
  134. }
  135. // 1. validate person GUID
  136. // 2. if it is valid, find it
  137. // 3. if it is not valid, create a new one
  138. // 4. return it
  139. REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when) {
  140. debug(D_REGISTRY, "Registry: registry_person_get('%s'): creating dictionary of urls", person_guid);
  141. REGISTRY_PERSON *p = NULL;
  142. if(person_guid && *person_guid) {
  143. char buf[GUID_LEN + 1];
  144. // validate it is a GUID
  145. if(unlikely(regenerate_guid(person_guid, buf) == -1))
  146. info("Registry: person guid '%s' is not a valid guid. Ignoring it.", person_guid);
  147. else {
  148. person_guid = buf;
  149. p = registry_person_find(person_guid);
  150. }
  151. }
  152. if(!p) p = registry_person_allocate(NULL, when);
  153. return p;
  154. }
  155. // ----------------------------------------------------------------------------
  156. // LINKING OF OBJECTS
  157. REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when) {
  158. debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): searching for URL in person", p->guid, m->guid, u->url);
  159. REGISTRY_PERSON_URL *pu = registry_person_url_index_find(p, u->url);
  160. if(!pu) {
  161. debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
  162. pu = registry_person_url_allocate(p, m, u, name, namelen, when);
  163. registry.persons_urls_count++;
  164. }
  165. else {
  166. debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url);
  167. pu->usages++;
  168. if(likely(pu->last_t < (uint32_t)when)) pu->last_t = (uint32_t)when;
  169. if(pu->machine != m) {
  170. REGISTRY_MACHINE_URL *mu = dictionary_get(pu->machine->machine_urls, u->url);
  171. if(mu) {
  172. debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - expiring it from previous machine.",
  173. p->guid, m->guid, u->url, pu->machine->guid);
  174. mu->flags |= REGISTRY_URL_FLAGS_EXPIRED;
  175. }
  176. else {
  177. debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - but the URL is not linked to the old machine.",
  178. p->guid, m->guid, u->url, pu->machine->guid);
  179. }
  180. pu->machine->links--;
  181. pu->machine = m;
  182. }
  183. if(strcmp(pu->machine_name, name) != 0) {
  184. // the name of the PERSON_URL has changed !
  185. pu = registry_person_url_reallocate(p, m, u, name, namelen, when, pu);
  186. }
  187. }
  188. p->usages++;
  189. if(likely(p->last_t < (uint32_t)when)) p->last_t = (uint32_t)when;
  190. if(pu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
  191. debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, u->url);
  192. pu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
  193. }
  194. return pu;
  195. }
  196. void registry_person_unlink_from_url(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
  197. registry_person_url_free(p, pu);
  198. }