mirror of
https://github.com/cjdelisle/cjdns
synced 2025-10-06 00:32:50 +02:00
154 lines
5.2 KiB
C
154 lines
5.2 KiB
C
/* vim: set expandtab ts=4 sw=4: */
|
|
/*
|
|
* You may redistribute this program and/or modify it under the terms of
|
|
* the GNU General Public License as published by the Free Software Foundation,
|
|
* either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "dht/EncodingSchemeModule.h"
|
|
#include "dht/Address.h"
|
|
#include "dht/CJDHTConstants.h"
|
|
#include "dht/DHTMessage.h"
|
|
#include "dht/DHTModule.h"
|
|
#include "dht/DHTModuleRegistry.h"
|
|
#include "benc/String.h"
|
|
#include "util/Identity.h"
|
|
#include "switch/NumberCompress.h"
|
|
#include "switch/EncodingScheme.h"
|
|
#include "util/version/Version.h"
|
|
#include "dht/dhtcore/NodeStore.h"
|
|
|
|
/**
|
|
* The encoding scheme module tags each message with our encoding scheme
|
|
* representation as well as the number of the smallest encoding form which
|
|
* can represent the return path to the querying node.
|
|
*
|
|
* On incoming messages, it informs NodeStore of the encoding scheme used by
|
|
* the node sending the message and if the node is pre-version-6, it converts
|
|
* the query responses from the pre-version-6 representation to the version-6
|
|
* representation.
|
|
*/
|
|
|
|
struct EncodingSchemeModule_pvt
|
|
{
|
|
struct DHTModule module;
|
|
|
|
/** Our scheme. */
|
|
String* schemeDefinition;
|
|
struct EncodingScheme* scheme;
|
|
|
|
struct EncodingScheme* legacyV3x5x8;
|
|
|
|
struct Log* logger;
|
|
|
|
Identity
|
|
};
|
|
|
|
static int handleIncoming(struct DHTMessage* message, void* vcontext)
|
|
{
|
|
struct EncodingSchemeModule_pvt* ctx =
|
|
Identity_check((struct EncodingSchemeModule_pvt*) vcontext);
|
|
|
|
struct EncodingScheme* scheme = NULL;
|
|
|
|
String* schemeDefinition = Dict_getString(message->asDict, CJDHTConstants_ENC_SCHEME);
|
|
if (schemeDefinition) {
|
|
scheme = EncodingScheme_deserialize(schemeDefinition, message->allocator);
|
|
} else {
|
|
scheme = ctx->legacyV3x5x8;
|
|
}
|
|
|
|
if (!scheme) {
|
|
Log_debug(ctx->logger, "Failed to parse encoding scheme");
|
|
Assert_ifTesting(0);
|
|
return -1;
|
|
}
|
|
message->encodingScheme = scheme;
|
|
|
|
int64_t* version = Dict_getInt(message->asDict, CJDHTConstants_PROTOCOL);
|
|
if (!version) {
|
|
Log_debug(ctx->logger, "Protocol version missing");
|
|
Assert_ifTesting(0);
|
|
return -1;
|
|
}
|
|
if (!Version_compatibleWithCurrent(*version)) {
|
|
Log_debug(ctx->logger, "Incompatible version");
|
|
Assert_ifTesting(0);
|
|
return -1;
|
|
}
|
|
message->address->protocolVersion = *version;
|
|
|
|
int64_t* encIdx = Dict_getInt(message->asDict, CJDHTConstants_ENC_INDEX);
|
|
if (!encIdx) {
|
|
Log_debug(ctx->logger, "Missing encoding index, version [%d]", (int) (*version));
|
|
return -1;
|
|
}
|
|
if (*encIdx < 0 || *encIdx >= scheme->count) {
|
|
Log_debug(ctx->logger, "Invalid encoding index [%lld], version [%d]",
|
|
(long long int) (*encIdx),
|
|
(int) (*version));
|
|
Assert_ifTesting(0);
|
|
return -1;
|
|
}
|
|
message->encIndex = *encIdx;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int handleOutgoing(struct DHTMessage* dmesg, void* vcontext)
|
|
{
|
|
struct EncodingSchemeModule_pvt* ctx =
|
|
Identity_check((struct EncodingSchemeModule_pvt*) vcontext);
|
|
|
|
// Send our encoding scheme definition
|
|
Dict_putString(dmesg->asDict,
|
|
CJDHTConstants_ENC_SCHEME,
|
|
ctx->schemeDefinition,
|
|
dmesg->allocator);
|
|
|
|
// sanity check if in sym, real world broken nodes will trigger this.
|
|
Assert_ifTesting(dmesg->address->path ==
|
|
EncodingScheme_convertLabel(ctx->scheme,
|
|
dmesg->address->path,
|
|
EncodingScheme_convertLabel_convertTo_CANNONICAL));
|
|
|
|
// And tell the asker which interface the message came from
|
|
int encIdx = EncodingScheme_getFormNum(ctx->scheme, dmesg->address->path);
|
|
Assert_ifParanoid(encIdx != EncodingScheme_getFormNum_INVALID);
|
|
Dict_putInt(dmesg->asDict, CJDHTConstants_ENC_INDEX, encIdx, dmesg->allocator);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void EncodingSchemeModule_register(struct DHTModuleRegistry* reg,
|
|
struct Log* logger,
|
|
struct Allocator* alloc)
|
|
{
|
|
struct EncodingScheme* scheme = NumberCompress_defineScheme(alloc);
|
|
String* schemeDefinition = EncodingScheme_serialize(scheme, alloc);
|
|
|
|
struct EncodingSchemeModule_pvt* ctx =
|
|
Allocator_clone(alloc, (&(struct EncodingSchemeModule_pvt) {
|
|
.module = {
|
|
.name = "EncodingSchemeModule",
|
|
.handleIncoming = handleIncoming,
|
|
.handleOutgoing = handleOutgoing
|
|
},
|
|
.logger = logger,
|
|
.scheme = scheme,
|
|
.schemeDefinition = schemeDefinition,
|
|
}));
|
|
Identity_set(ctx);
|
|
ctx->module.context = ctx;
|
|
ctx->legacyV3x5x8 = NumberCompress_v3x5x8_defineScheme(alloc);
|
|
|
|
DHTModuleRegistry_register(&ctx->module, reg);
|
|
}
|