1
0

SearchRunner_admin.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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 <https://www.gnu.org/licenses/>.
  14. */
  15. #include "admin/Admin.h"
  16. #include "benc/Dict.h"
  17. #include "benc/String.h"
  18. #include "dht/Address.h"
  19. #include "dht/dhtcore/SearchRunner_admin.h"
  20. #include "dht/dhtcore/SearchRunner.h"
  21. #include "dht/dhtcore/ReplySerializer.h"
  22. #include "dht/Address.h"
  23. #include "memory/Allocator.h"
  24. #include "util/AddrTools.h"
  25. struct Context {
  26. struct Admin* admin;
  27. struct Allocator* allocator;
  28. struct SearchRunner* runner;
  29. Identity
  30. };
  31. static void showActiveSearch(Dict* args, void* vctx, String* txid, struct Allocator* alloc)
  32. {
  33. struct Context* ctx = Identity_check((struct Context*) vctx);
  34. int number = *(Dict_getIntC(args, "number"));
  35. struct SearchRunner_SearchData* search =
  36. SearchRunner_showActiveSearch(ctx->runner, number, alloc);
  37. Dict* dict = Dict_new(alloc);
  38. // Nothing is an error
  39. Dict_putString(dict, String_new("error", alloc), String_new("none", alloc), alloc);
  40. if (number < search->activeSearches) {
  41. uint8_t target[40];
  42. AddrTools_printIp(target, search->target);
  43. Dict_putString(dict, String_new("target", alloc), String_new((char*)target, alloc), alloc);
  44. uint8_t lastNodeAsked[60];
  45. Address_print(lastNodeAsked, &search->lastNodeAsked);
  46. Dict_putString(dict,
  47. String_new("lastNodeAsked", alloc),
  48. String_new((char*)lastNodeAsked, alloc),
  49. alloc);
  50. Dict_putInt(dict, String_new("totalRequests", alloc), search->totalRequests, alloc);
  51. }
  52. Dict_putInt(dict, String_new("activeSearches", alloc), search->activeSearches, alloc);
  53. Admin_sendMessage(dict, txid, ctx->admin);
  54. }
  55. struct Search
  56. {
  57. String* txid;
  58. struct RouterModule_Promise* promise;
  59. struct Context* ctx;
  60. struct Allocator* alloc;
  61. Identity
  62. };
  63. static void searchResponse(struct RouterModule_Promise* promise,
  64. uint32_t lag,
  65. struct Address* from,
  66. Dict* responseDict)
  67. {
  68. struct Search* search = Identity_check((struct Search*) promise->userData);
  69. struct Allocator* alloc = Allocator_child(search->alloc);
  70. Dict* resp = Dict_new(alloc);
  71. if (!from) {
  72. Dict_putStringCC(resp, "error", "none", alloc);
  73. Dict_putIntC(resp, "complete", 1, alloc);
  74. Admin_sendMessage(resp, search->txid, search->ctx->admin);
  75. Allocator_free(alloc);
  76. return;
  77. }
  78. String* fromStr = Address_toStringKey(from, alloc);
  79. Dict_putStringC(resp, "from", fromStr, alloc);
  80. Dict_putIntC(resp, "ms", lag, alloc);
  81. struct Address_List* addrs = ReplySerializer_parse(from, responseDict, NULL, true, alloc);
  82. List* nodes = List_new(alloc);
  83. for (int i = 0; addrs && i < addrs->length; i++) {
  84. String* addr = Address_toStringKey(&addrs->elems[i], alloc);
  85. List_addString(nodes, addr, alloc);
  86. }
  87. Dict_putListC(resp, "nodes", nodes, alloc);
  88. Admin_sendMessage(resp, search->txid, search->ctx->admin);
  89. }
  90. static void search(Dict* args, void* vctx, String* txid, struct Allocator* reqAlloc)
  91. {
  92. struct Context* ctx = Identity_check((struct Context*) vctx);
  93. String* addrStr = Dict_getStringC(args, "ipv6");
  94. int maxRequests = -1;
  95. uint64_t* maxRequestsPtr = Dict_getIntC(args, "maxRequests");
  96. if (maxRequestsPtr) { maxRequests = *maxRequestsPtr; }
  97. uint8_t addr[16];
  98. if (AddrTools_parseIp(addr, (uint8_t*) addrStr->bytes)) {
  99. Dict* resp = Dict_new(reqAlloc);
  100. Dict_putStringCC(resp, "error", "ipv6 invalid", reqAlloc);
  101. Admin_sendMessage(resp, txid, ctx->admin);
  102. } else {
  103. struct Allocator* alloc = Allocator_child(ctx->allocator);
  104. struct Search* s = Allocator_calloc(alloc, sizeof(struct Search), 1);
  105. s->promise = SearchRunner_search(addr, maxRequests, maxRequests, ctx->runner, alloc);
  106. s->ctx = ctx;
  107. s->txid = String_clone(txid, alloc);
  108. s->alloc = alloc;
  109. Identity_set(s);
  110. if (!s->promise) {
  111. Dict* resp = Dict_new(reqAlloc);
  112. Dict_putStringCC(resp, "error", "creating search", reqAlloc);
  113. Admin_sendMessage(resp, txid, ctx->admin);
  114. Allocator_free(alloc);
  115. return;
  116. }
  117. s->promise->userData = s;
  118. s->promise->callback = searchResponse;
  119. }
  120. }
  121. void SearchRunner_admin_register(struct SearchRunner* runner,
  122. struct Admin* admin,
  123. struct Allocator* alloc)
  124. {
  125. struct Context* ctx = Allocator_clone(alloc, (&(struct Context) {
  126. .admin = admin,
  127. .allocator = alloc,
  128. .runner = runner
  129. }));
  130. Identity_set(ctx);
  131. Admin_registerFunction("SearchRunner_showActiveSearch", showActiveSearch, ctx, true,
  132. ((struct Admin_FunctionArg[]) {
  133. { .name = "number", .required = 1, .type = "Int" }
  134. }), admin);
  135. Admin_registerFunction("SearchRunner_search", search, ctx, true,
  136. ((struct Admin_FunctionArg[]) {
  137. { .name = "ipv6", .required = 1, .type = "String" },
  138. { .name = "maxRequests", .required = 0, .type = "Int" }
  139. }), admin);
  140. }