SwitchPinger_admin.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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/String.h"
  17. #include "benc/Dict.h"
  18. #include "dht/Address.h"
  19. #include "net/SwitchPinger.h"
  20. #include "net/SwitchPinger_admin.h"
  21. #include "util/Bits.h"
  22. #include "util/Endian.h"
  23. #include "util/AddrTools.h"
  24. #include "crypto/Key.h"
  25. #include "util/Hex.h"
  26. #include "util/platform/Sockaddr.h"
  27. #define DEFAULT_TIMEOUT 2000
  28. struct Context
  29. {
  30. struct SwitchPinger* switchPinger;
  31. struct Admin* admin;
  32. struct Allocator* alloc;
  33. };
  34. struct Ping
  35. {
  36. struct Context* context;
  37. String* txid;
  38. String* path;
  39. };
  40. static void adminPingOnResponse(struct SwitchPinger_Response* resp, void* vping)
  41. {
  42. struct Allocator* pingAlloc = resp->ping->pingAlloc;
  43. struct Ping* ping = vping;
  44. Dict* rd = Dict_new(pingAlloc);
  45. if (resp->res == SwitchPinger_Result_LABEL_MISMATCH) {
  46. uint8_t path[20] = {0};
  47. AddrTools_printPath(path, resp->label);
  48. String* pathStr = String_new(path, pingAlloc);
  49. Dict_putStringC(rd, "responsePath", pathStr, pingAlloc);
  50. }
  51. if (resp->version) {
  52. Dict_putIntC(rd, "version", resp->version, pingAlloc);
  53. }
  54. Dict_putIntC(rd, "ms", resp->milliseconds, pingAlloc);
  55. Dict_putStringC(rd, "result", SwitchPinger_resultString(resp->res), pingAlloc);
  56. Dict_putStringC(rd, "path", ping->path, pingAlloc);
  57. if (resp->data) {
  58. Dict_putStringC(rd, "data", resp->data, pingAlloc);
  59. }
  60. if (!Bits_isZero(resp->key, 32)) {
  61. Dict_putStringC(rd, "key", Key_stringify(resp->key, pingAlloc), pingAlloc);
  62. }
  63. if (!Bits_isZero(&resp->snode, sizeof resp->snode)) {
  64. Dict_putStringC(rd, "snode", Address_toString(&resp->snode, pingAlloc), pingAlloc);
  65. }
  66. if (resp->rpath) {
  67. uint8_t path[20] = {0};
  68. AddrTools_printPath(path, resp->rpath);
  69. String* pathStr = String_new(path, pingAlloc);
  70. Dict_putStringC(rd, "rpath", pathStr, pingAlloc);
  71. }
  72. if (!Bits_isZero(&resp->lladdr, sizeof resp->lladdr)) {
  73. struct Sockaddr_storage ss;
  74. if (resp->lladdr.addr.udp4.type == Control_LlAddr_Udp4_TYPE) {
  75. Sockaddr_t* sa = Sockaddr_initFromBytes(
  76. &ss, resp->lladdr.addr.udp4.addr, Sockaddr_AF_INET);
  77. Sockaddr_setPort(sa, Endian_bigEndianToHost16(resp->lladdr.addr.udp4.port_be));
  78. Dict_putStringCC(
  79. rd, "lladdr", Sockaddr_print(sa, pingAlloc), pingAlloc);
  80. } else if (resp->lladdr.addr.udp4.type == Control_LlAddr_Udp6_TYPE) {
  81. Sockaddr_t* sa = Sockaddr_initFromBytes(
  82. &ss, resp->lladdr.addr.udp6.addr, Sockaddr_AF_INET6);
  83. Sockaddr_setPort(sa, Endian_bigEndianToHost16(resp->lladdr.addr.udp6.port_be));
  84. Dict_putStringCC(
  85. rd, "lladdr", Sockaddr_print(sa, pingAlloc), pingAlloc);
  86. } else {
  87. Dict_putStringCC(
  88. rd,
  89. "lladdrUnknown",
  90. Hex_print(&resp->lladdr, sizeof resp->lladdr, pingAlloc),
  91. pingAlloc
  92. );
  93. }
  94. }
  95. Admin_sendMessage(rd, ping->txid, ping->context->admin);
  96. }
  97. static void adminPing(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
  98. {
  99. struct Context* context = vcontext;
  100. String* pathStr = Dict_getStringC(args, "path");
  101. int64_t* timeoutPtr = Dict_getIntC(args, "timeout");
  102. String* data = Dict_getStringC(args, "data");
  103. int64_t* keyPing = Dict_getIntC(args, "keyPing");
  104. int64_t* lladdr = Dict_getIntC(args, "lladdr");
  105. int64_t* snode = Dict_getIntC(args, "snode");
  106. int64_t* rpath = Dict_getIntC(args, "rpath");
  107. uint32_t timeout = (timeoutPtr) ? *timeoutPtr : DEFAULT_TIMEOUT;
  108. uint64_t path;
  109. char* err = NULL;
  110. if ((keyPing && *keyPing != 0) + (lladdr && *lladdr != 0) + (snode && *snode != 0) > 1) {
  111. err = "Can only be one of keyPing, lladdr, OR snode";
  112. } else if (pathStr->len != 19 || AddrTools_parsePath(&path, (uint8_t*) pathStr->bytes)) {
  113. err = "path was not parsable.";
  114. } else {
  115. struct SwitchPinger_Ping* ping = SwitchPinger_newPing(path,
  116. data,
  117. timeout,
  118. adminPingOnResponse,
  119. context->alloc,
  120. context->switchPinger);
  121. if (!ping) {
  122. err = "no open slots to store ping, try later.";
  123. } else {
  124. if (keyPing && *keyPing) {
  125. ping->type = SwitchPinger_Type_KEYPING;
  126. } else if (lladdr && *lladdr) {
  127. ping->type = SwitchPinger_Type_LLADDR;
  128. } else if (snode && *snode) {
  129. ping->type = SwitchPinger_Type_GETSNODE;
  130. } else if (rpath && *rpath) {
  131. ping->type = SwitchPinger_Type_RPATH;
  132. }
  133. ping->onResponseContext = Allocator_clone(ping->pingAlloc, (&(struct Ping) {
  134. .context = context,
  135. .txid = String_clone(txid, ping->pingAlloc),
  136. .path = String_clone(pathStr, ping->pingAlloc)
  137. }));
  138. }
  139. }
  140. if (err) {
  141. Dict d = Dict_CONST(String_CONST("error"), String_OBJ(String_CONST(err)), NULL);
  142. Admin_sendMessage(&d, txid, context->admin);
  143. }
  144. }
  145. void SwitchPinger_admin_register(struct SwitchPinger* sp,
  146. struct Admin* admin,
  147. struct Allocator* allocator)
  148. {
  149. struct Allocator* alloc = Allocator_child(allocator);
  150. struct Context* ctx = Allocator_clone(alloc, (&(struct Context) {
  151. .switchPinger = sp,
  152. .alloc = alloc,
  153. .admin = admin
  154. }));
  155. Admin_registerFunction("SwitchPinger_ping", adminPing, ctx, true,
  156. ((struct Admin_FunctionArg[]) {
  157. { .name = "path", .required = 1, .type = "String" },
  158. { .name = "timeout", .required = 0, .type = "Int" },
  159. { .name = "data", .required = 0, .type = "String" },
  160. { .name = "keyPing", .required = 0, .type = "Int" },
  161. { .name = "lladdr", .required = 0, .type = "Int" },
  162. { .name = "snode", .required = 0, .type = "Int" },
  163. { .name = "rpath", .required = 0, .type = "Int" },
  164. }), admin);
  165. }