EncodingSchemeModule.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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. #include "dht/EncodingSchemeModule.h"
  16. #include "dht/Address.h"
  17. #include "dht/CJDHTConstants.h"
  18. #include "dht/DHTMessage.h"
  19. #include "dht/DHTModule.h"
  20. #include "dht/DHTModuleRegistry.h"
  21. #include "benc/String.h"
  22. #include "util/Identity.h"
  23. #include "switch/NumberCompress.h"
  24. #include "switch/EncodingScheme.h"
  25. #include "util/version/Version.h"
  26. #include "dht/dhtcore/NodeStore.h"
  27. #include "dht/dhtcore/ReplySerializer.h"
  28. /**
  29. * The encoding scheme module tags each message with our encoding scheme
  30. * representation as well as the number of the smallest encoding form which
  31. * can represent the return path to the querying node.
  32. *
  33. * On incoming messages, it informs NodeStore of the encoding scheme used by
  34. * the node sending the message and if the node is pre-version-6, it converts
  35. * the query responses from the pre-version-6 representation to the version-6
  36. * representation.
  37. */
  38. struct EncodingSchemeModule_pvt
  39. {
  40. struct DHTModule module;
  41. /** Our scheme. */
  42. String* schemeDefinition;
  43. struct EncodingScheme* scheme;
  44. struct EncodingScheme* legacyV3x5x8;
  45. struct Log* logger;
  46. struct Allocator* alloc;
  47. Identity
  48. };
  49. static int handleIncoming(struct DHTMessage* message, void* vcontext)
  50. {
  51. struct EncodingSchemeModule_pvt* ctx =
  52. Identity_check((struct EncodingSchemeModule_pvt*) vcontext);
  53. struct EncodingScheme* scheme = NULL;
  54. String* schemeDefinition = Dict_getString(message->asDict, CJDHTConstants_ENC_SCHEME);
  55. if (schemeDefinition) {
  56. scheme = EncodingScheme_deserialize(schemeDefinition, message->allocator);
  57. } else {
  58. scheme = ctx->legacyV3x5x8;
  59. }
  60. if (!scheme) {
  61. Log_debug(ctx->logger, "Failed to parse encoding scheme");
  62. Assert_ifTesting(0);
  63. return -1;
  64. }
  65. message->encodingScheme = scheme;
  66. int64_t* version = Dict_getInt(message->asDict, CJDHTConstants_PROTOCOL);
  67. if (!version || !Version_isCompatible(Version_CURRENT_PROTOCOL, *version)) {
  68. Log_debug(ctx->logger, "Incompatible version");
  69. Assert_ifTesting(0);
  70. return -1;
  71. }
  72. message->address->protocolVersion = *version;
  73. int64_t* encIdx = Dict_getInt(message->asDict, CJDHTConstants_ENC_INDEX);
  74. if (!encIdx) {
  75. Log_debug(ctx->logger, "Missing encoding index, version [%d]", (int) (*version));
  76. return -1;
  77. }
  78. if (*encIdx < 0 || *encIdx >= scheme->count) {
  79. Log_debug(ctx->logger, "Invalid encoding index [%lld], version [%d]",
  80. (long long int) (*encIdx),
  81. (int) (*version));
  82. Assert_ifTesting(0);
  83. return -1;
  84. }
  85. message->encIndex = *encIdx;
  86. struct Allocator* alloc = Allocator_child(ctx->alloc);
  87. ReplySerializer_parse(message->address, scheme, *encIdx, message->asDict, ctx->logger, alloc);
  88. Allocator_free(alloc);
  89. return 0;
  90. }
  91. static int handleOutgoing(struct DHTMessage* dmesg, void* vcontext)
  92. {
  93. struct EncodingSchemeModule_pvt* ctx =
  94. Identity_check((struct EncodingSchemeModule_pvt*) vcontext);
  95. // Send our encoding scheme definition
  96. Dict_putString(dmesg->asDict,
  97. CJDHTConstants_ENC_SCHEME,
  98. ctx->schemeDefinition,
  99. dmesg->allocator);
  100. #ifdef TESTING
  101. // sanity check
  102. Assert_true(dmesg->address->path ==
  103. EncodingScheme_convertLabel(ctx->scheme,
  104. dmesg->address->path,
  105. EncodingScheme_convertLabel_convertTo_CANNONICAL));
  106. #endif
  107. // And tell the asker which interface the message came from
  108. int encIdx = EncodingScheme_getFormNum(ctx->scheme, dmesg->address->path);
  109. Assert_true(encIdx != EncodingScheme_getFormNum_INVALID);
  110. Dict_putInt(dmesg->asDict, CJDHTConstants_ENC_INDEX, encIdx, dmesg->allocator);
  111. return 0;
  112. }
  113. void EncodingSchemeModule_register(struct DHTModuleRegistry* reg,
  114. struct Log* logger,
  115. struct Allocator* alloc)
  116. {
  117. struct EncodingScheme* scheme = NumberCompress_defineScheme(alloc);
  118. String* schemeDefinition = EncodingScheme_serialize(scheme, alloc);
  119. struct EncodingSchemeModule_pvt* ctx =
  120. Allocator_clone(alloc, (&(struct EncodingSchemeModule_pvt) {
  121. .module = {
  122. .name = "EncodingSchemeModule",
  123. .handleIncoming = handleIncoming,
  124. .handleOutgoing = handleOutgoing
  125. },
  126. .logger = logger,
  127. .scheme = scheme,
  128. .schemeDefinition = schemeDefinition,
  129. .alloc = alloc
  130. }));
  131. Identity_set(ctx);
  132. ctx->module.context = ctx;
  133. ctx->legacyV3x5x8 = NumberCompress_v3x5x8_defineScheme(alloc);
  134. DHTModuleRegistry_register(&ctx->module, reg);
  135. }