SearchRunner_admin.c 5.7 KB

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