NodeCollector.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #ifndef NodeCollector_H
  16. #define NodeCollector_H
  17. #include "dht/Address.h"
  18. #include "dht/dhtcore/Node.h"
  19. #include "dht/dhtcore/NodeHeader.h"
  20. #include "util/log/Log.h"
  21. #include "memory/Allocator.h"
  22. #include "util/platform/libc/string.h"
  23. #include <stdbool.h>
  24. struct NodeCollector_Element
  25. {
  26. struct NodeHeader* node;
  27. struct Node* body;
  28. uint64_t value;
  29. uint32_t distance;
  30. };
  31. /** Collects the nodes with the lowest distance:reach from the target. */
  32. struct NodeCollector
  33. {
  34. /** Maximum size which the collector can grow to. */
  35. uint32_t capacity;
  36. /** The prefix of the address we are looking for. */
  37. uint32_t targetPrefix;
  38. struct Address* targetAddress;
  39. /**
  40. * The distance between this node and the address we are looking for
  41. * set to UINT32_MAX if allowNodesFartherThanUs is true.
  42. */
  43. uint32_t thisNodeDistance;
  44. /** The array of collected nodes, capacity long. */
  45. struct NodeCollector_Element* nodes;
  46. struct Log* logger;
  47. };
  48. /**
  49. * Create a new NodeCollector.
  50. * This will create a collector which sifts through nodes and finds the best nodes to serve a
  51. * request. Nodes which have the lowest distance:reach ratio will be collected.
  52. *
  53. * @param targetAddress the address we are searching for.
  54. * @param capacity the number of nodes to collect, if less than this number are added, some of
  55. * the nodes will remain NULL pointers.
  56. * @param thisNodeAddress this node's address.
  57. * @param allowNodesFartherThanUs if true then return nodes which are farther than the target
  58. * then we are. this is required for searches but unallowable
  59. * for answering queries.
  60. * @param logger
  61. * @param allocator the means of getting memory to store the collector.
  62. * @return a new collector.
  63. */
  64. static struct NodeCollector* NodeCollector_new(struct Address* targetAddress,
  65. const uint32_t capacity,
  66. struct Address* thisNodeAddress,
  67. const bool allowNodesFartherThanUs,
  68. struct Log* logger,
  69. struct Allocator* allocator)
  70. {
  71. struct NodeCollector* out = Allocator_malloc(allocator, sizeof(struct NodeCollector));
  72. out->nodes = Allocator_malloc(allocator, capacity * sizeof(struct NodeCollector_Element));
  73. for (uint32_t i = 0; i < capacity; i++) {
  74. out->nodes[i].value = 0;
  75. out->nodes[i].distance = UINT32_MAX;
  76. out->nodes[i].node = NULL;
  77. out->nodes[i].body = NULL;
  78. }
  79. out->capacity = capacity;
  80. out->targetAddress = targetAddress;
  81. out->targetPrefix = Address_getPrefix(targetAddress);
  82. out->logger = logger;
  83. if (allowNodesFartherThanUs) {
  84. out->thisNodeDistance = UINT32_MAX;
  85. } else {
  86. out->thisNodeDistance = Address_getPrefix(thisNodeAddress) ^ out->targetPrefix;
  87. }
  88. return out;
  89. }
  90. /**
  91. * Filter a node through the collector.
  92. * If this node is better than all of the ones known to the collector, it will be collected.
  93. *
  94. * @param header the header of the node to add.
  95. * @param body the node which is used in case the prefix is an exact match and it needs to
  96. * look at more bits.
  97. * @param collector the collector to filter the node through.
  98. */
  99. static inline void NodeCollector_addNode(struct NodeHeader* header,
  100. struct Node* body,
  101. struct NodeCollector* collector)
  102. {
  103. uint32_t nodeDistance = header->addressPrefix ^ collector->targetPrefix;
  104. // This is a hack because we don't really care about
  105. // beyond the first 4 bytes unless it's a match.
  106. if (nodeDistance == 0
  107. && Bits_memcmp(body->address.ip6.bytes,
  108. collector->targetAddress,
  109. Address_SEARCH_TARGET_SIZE) != 0)
  110. {
  111. Log_debug(collector->logger, "Increasing distance because addr is not exact match.\n");
  112. nodeDistance++;
  113. }
  114. struct NodeCollector_Element* nodes = collector->nodes;
  115. // Check that it's not farther from the target than we are...
  116. if (nodeDistance < collector->thisNodeDistance) {
  117. uint64_t value = 0;
  118. #define NodeCollector_getValue(value, header, body, nodeDistance) \
  119. if (value == 0) { \
  120. value = 64 - Bits_log2x64(body->address.path); \
  121. value |= (uint64_t) (UINT32_MAX - nodeDistance) * header->reach * value; \
  122. }
  123. // 0 distance (match) always wins,
  124. // If both have 0 distance, highest reach wins.
  125. // If both have 0 reach (likely) smallest distance wins.
  126. // Otherwise highest value wins.
  127. uint32_t i;
  128. uint32_t match = 0;
  129. for (i = 0; i < collector->capacity; i++) {
  130. if ((nodes[i].distance == 0) == (nodeDistance == 0)) {
  131. NodeCollector_getValue(value, header, body, nodeDistance);
  132. if (value <= nodes[i].value) {
  133. break;
  134. }
  135. if (i > 0
  136. && nodes[i].body
  137. && Bits_memcmp(body->address.ip6.bytes,
  138. nodes[i].body->address.ip6.bytes,
  139. 16) == 0)
  140. {
  141. match = i + 1;
  142. }
  143. } else if (nodeDistance != 0) {
  144. break;
  145. }
  146. }
  147. if (i > 0) {
  148. if (match > 0) {
  149. i = match;
  150. } else if (i > 1) {
  151. Bits_memmove(nodes, &nodes[1], (i - 1) * sizeof(struct NodeCollector_Element));
  152. }
  153. nodes[i - 1].node = header;
  154. nodes[i - 1].body = body;
  155. NodeCollector_getValue(value, header, body, nodeDistance);
  156. nodes[i - 1].value = value;
  157. nodes[i - 1].distance = nodeDistance;
  158. }
  159. #undef NodeCollector_getValue
  160. }
  161. }
  162. #endif