0
0
mirror of https://github.com/cjdelisle/cjdns synced 2025-10-05 16:22:54 +02:00

Deleted sybilsim and FakeNetwork which are nolonger being meaningfully maintained

This commit is contained in:
Caleb James DeLisle
2023-02-21 14:58:07 +01:00
parent 4728027c43
commit ef3d9fd92d
15 changed files with 3 additions and 781 deletions

1
.gitignore vendored
View File

@@ -17,7 +17,6 @@
/cleanconfig*
/privatetopublic*
/publictoip6*
/sybilsim*
/makekeys*
/mkpasswd*
/node_build/node_modules/jshint

View File

@@ -143,51 +143,4 @@ You can do this on Linux using the `perf` utility.
<ctrl+c>
sudo perf script | ../FlameGraph/stackcollapse-perf.pl > ./cjdns-stackcollapse.out
../FlameGraph/flamegraph.pl < ./cjdns-stackcollapse.out > ./cjdns-stackcollapse.svg
chromium ./cjdns-stackcollapse.svg
Simulating
----------
Cjdns comes with it's own simulator, it will create *n* nodes and link them together
however you wish. It's like having many cjdns processes all running together but they're
all in the same process so it is much more efficient. You can set admin credentials on
one node and then use the admin tools to access it as you would an ordinary router.
You will however need private keys whose public keys hash to ip addresses beginning with
fc. To make these keys, use the `makekeys` utility.
./makekeys | head -n 32 > keys.txt
To convert the list of keys into a simulator configuration, use `makesim.js`, note there
are interesting constants inside of `makesim.js` which you might want to alter.
node ./tools/lib/makesim.js keys.txt > ~/my-cjdns-simulation.json
Once you have a simulation setup, you may want to add your admin credentials to one of
the nodes so you can inspect it, dump the table, etc...
Example simulation config entry with added admin block:
```javascript
"fc5c:0537:606a:3d7e:c9f0:2103:4dcd:6bc8": {
"privateKey": "0dc3d33bbffc2d16c175df463110c6d164714a40d23db2f83539664b7365a5b6",
"peers": [
"fc1c:84bf:9557:1ce4:4862:fd82:5105:9984",
"fc1c:90e4:2953:938b:47cc:65c3:6540:dff6",
"fc1b:7ea7:911f:f2d5:7685:ac22:6c4f:8b15"
],
"admin":
{
"bind": "127.0.0.1:11234",
"password": "the_password_you_will_use_to_connect"
}
},
```
And to start it up (in the debugger):
gdb ./sybilsim -ex 'r < ~/my-cjdns-simulation.json'
BUG: Sometimes the simulator doesn't really start up correctly! If you could figure out
what is going wrong, your help would be most appreciated, if not, you can just quit and
then restart it again and it should start up ok.
chromium ./cjdns-stackcollapse.svg

View File

@@ -335,7 +335,6 @@ void Core_init(struct Allocator* alloc,
struct Admin* admin,
struct Random* rand,
struct Except* eh,
struct FakeNetwork* fakeNet,
bool noSec)
{
struct Security* sec = NULL;
@@ -376,7 +375,7 @@ void Core_init(struct Allocator* alloc,
InterfaceController_admin_register(nc->ifController, admin, alloc);
SwitchPinger_admin_register(nc->sp, admin, alloc);
UDPInterface_admin_register(
eventBase, alloc, logger, admin, nc->ifController, fakeNet, globalConf);
eventBase, alloc, logger, admin, nc->ifController, globalConf);
#ifdef HAS_ETH_INTERFACE
ETHInterface_admin_register(eventBase, alloc, logger, admin, nc->ifController);
#endif
@@ -535,7 +534,7 @@ int Core_main(int argc, char** argv)
Allocator_free(tempAlloc);
Core_init(alloc, logger, eventBase, privateKey, admin, rand, eh, NULL, false);
Core_init(alloc, logger, eventBase, privateKey, admin, rand, eh, false);
EventBase_beginLoop(eventBase);
return 0;
}

View File

@@ -20,7 +20,6 @@
#include "exception/Except.h"
#include "memory/Allocator.h"
#include "tunnel/IpTunnel.h"
#include "util/events/FakeNetwork.h"
#include "util/Linker.h"
Linker_require("admin/angel/Core.c")
@@ -40,7 +39,6 @@ void Core_init(struct Allocator* alloc,
struct Admin* admin,
struct Random* rand,
struct Except* eh,
struct FakeNetwork* fakeNet,
bool noSec);
int Core_main(int argc, char** argv);

View File

@@ -48,7 +48,6 @@
#include "util/events/EventBase.h"
#include "util/events/Pipe.h"
#include "util/events/Process.h"
#include "util/events/FakeNetwork.h"
#include "util/events/libuv/Glock.h"
#include "util/Hex.h"
#include "util/log/Log.h"

View File

@@ -1,457 +0,0 @@
/* 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 "benc/serialization/standard/BencMessageReader.h"
#include "benc/serialization/standard/BencMessageWriter.h"
#include "benc/serialization/json/JsonBencSerializer.h"
#include "benc/serialization/BencSerializer.h"
#include "benc/List.h"
#include "io/ArrayReader.h"
#include "admin/angel/Core.h"
#include "client/AdminClient.h"
#include "interface/ASynchronizer.h"
#include "interface/addressable/AddrIfaceAdapter.h"
#include "memory/Allocator.h"
#include "util/log/FileWriterLog.h"
#include "wire/Message.h"
#include "util/events/EventBase.h"
#include "crypto/random/Random.h"
#include "crypto/random/nanotime/NanotimeEntropyProvider.h"
#include "exception/Except.h"
#include "util/events/Timeout.h"
#include "crypto/Key.h"
#include "util/log/Log_impl.h"
#include "io/FileReader.h"
#include "io/ArrayWriter.h"
#include "util/Hex.h"
#include "util/events/FakeNetwork.h"
#include "util/Hash.h"
#include <sodium/crypto_scalarmult_curve25519.h>
#include <unistd.h> // isatty()
struct NodeContext {
struct Sockaddr* boundAddr;
struct Allocator* alloc;
struct EventBase* base;
uint8_t privateKey[32];
String* publicKey;
struct AdminClient* adminClient;
struct Admin* admin;
char* nodeName;
/** Admin socket to bind */
String* bind;
/** Admin password */
String* pass;
/** UDPInterface */
int ifNum;
struct Sockaddr* udpAddr;
struct Log nodeLog;
struct Log* parentLogger;
List* peers;
Identity
};
struct RPCCall;
typedef void (* RPCCallback)(struct RPCCall* call, struct AdminClient_Result* res);
struct RPCCall
{
String* func;
Dict* args;
struct NodeContext* node;
RPCCallback callback;
};
#define Map_KEY_TYPE String*
#define Map_VALUE_TYPE struct NodeContext*
#define Map_NAME OfNodes
#define Map_USE_COMPARATOR
#define Map_USE_HASH
#include "util/Map.h"
static inline int Map_OfNodes_compare(String** a, String** b)
{
return String_compare(*a, *b);
}
static inline uint32_t Map_OfNodes_hash(String** a)
{
return Hash_compute(a[0]->bytes, a[0]->len);
}
struct Context
{
struct RPCCall* rpcCalls;
int rpcCallCount;
int nextCall;
struct Allocator* rpcAlloc;
struct Random* rand;
struct EventBase* base;
struct Log* logger;
struct Allocator* alloc;
struct Map_OfNodes nodeMap;
Dict* confNodes;
Identity
};
static String* pubKeyForPriv(uint8_t* privateKey, struct Allocator* alloc)
{
uint8_t publicKey[32];
crypto_scalarmult_curve25519_base(publicKey, privateKey);
return Key_stringify(publicKey, alloc);
}
static void printLog(struct Log* log,
enum Log_Level logLevel,
const char* file,
int line,
const char* format,
va_list args)
{
struct NodeContext* ctx = Identity_check(
(struct NodeContext*) (((char*)log) - offsetof(struct NodeContext, nodeLog))
);
struct Allocator* alloc = Allocator_child(ctx->alloc);
String* str = String_printf(alloc, "[%s] %s", ctx->nodeName, file);
ctx->parentLogger->print(ctx->parentLogger, logLevel, str->bytes, line, format, args);
Allocator_free(alloc);
}
static struct RPCCall* pushCall(struct Context* ctx)
{
ctx->rpcCalls = Allocator_realloc(ctx->rpcAlloc,
ctx->rpcCalls,
sizeof(struct RPCCall) * (ctx->rpcCallCount+1));
Bits_memset(&ctx->rpcCalls[ctx->rpcCallCount], 0, sizeof(struct RPCCall));
return &ctx->rpcCalls[ctx->rpcCallCount++];
}
static void bindUDPCallback(struct RPCCall* call, struct AdminClient_Result* res)
{
Assert_true(!res->err);
// Indirection to shutup clang warning
struct Log* logger = &call->node->nodeLog;
Log_debug(logger, "UDPInterface_new() -> [%s]", res->messageBytes);
String* addr = Dict_getStringC(res->responseDict, "bindAddress");
int64_t* ifNum = Dict_getIntC(res->responseDict, "interfaceNumber");
struct Sockaddr_storage ss;
Assert_true(!Sockaddr_parse(addr->bytes, &ss));
call->node->ifNum = *ifNum;
call->node->udpAddr = Sockaddr_clone(&ss.addr, call->node->alloc);
}
static void bindUDP(struct Context* ctx, struct NodeContext* node)
{
struct RPCCall* call = pushCall(ctx);
call->func = String_new("UDPInterface_new", ctx->rpcAlloc);
call->args = Dict_new(ctx->rpcAlloc);
call->node = node;
call->callback = bindUDPCallback;
}
static void securitySetupComplete(struct Context* ctx, struct NodeContext* node)
{
struct RPCCall* call = pushCall(ctx);
call->func = String_new("Security_setupComplete", ctx->rpcAlloc);
call->args = Dict_new(ctx->rpcAlloc);
call->node = node;
}
static struct NodeContext* startNode(char* nodeName,
char* privateKeyHex,
Dict* admin,
struct Context* ctx,
struct Except* eh,
struct FakeNetwork* fakeNet)
{
struct Allocator* alloc = Allocator_child(ctx->alloc);
struct NodeContext* node = Allocator_clone(alloc, (&(struct NodeContext) {
.alloc = alloc,
.base = ctx->base,
.nodeLog = {
.print = printLog
},
.parentLogger = ctx->logger,
.nodeName = nodeName
}));
Identity_set(node);
node->bind = Dict_getStringC(admin, "bind");
if (!node->bind) {
node->bind = String_new("127.0.0.1:0", alloc);
}
node->pass = Dict_getStringC(admin, "password");
if (!node->pass) {
node->pass = String_new("x", alloc);
}
Assert_true(Hex_decode(node->privateKey, 32, privateKeyHex, 64) == 32);
struct AddrIfaceAdapter* adminClientIface = AddrIfaceAdapter_new(node->alloc);
struct AddrIfaceAdapter* adminIface = AddrIfaceAdapter_new(node->alloc);
struct ASynchronizer* asyncer = ASynchronizer_new(node->alloc, ctx->base, ctx->logger);
Iface_plumb(&asyncer->ifA, &adminClientIface->inputIf);
Iface_plumb(&asyncer->ifB, &adminIface->inputIf);
String* pass = String_new("12345", node->alloc);
node->adminClient = AdminClient_new(&adminClientIface->generic,
Sockaddr_clone(Sockaddr_LOOPBACK, node->alloc),
pass,
ctx->base,
&node->nodeLog,
node->alloc);
node->admin = Admin_new(&adminIface->generic, &node->nodeLog, ctx->base, pass);
Core_init(node->alloc,
&node->nodeLog,
ctx->base,
node->privateKey,
node->admin,
ctx->rand,
eh,
fakeNet,
true);
securitySetupComplete(ctx, node);
bindUDP(ctx, node);
node->publicKey = pubKeyForPriv(node->privateKey, node->alloc);
return node;
}
static void beginConnectionCallback(struct RPCCall* call, struct AdminClient_Result* res)
{
Assert_true(!res->err);
// Indirection to shutup clang warning
struct Log* logger = &call->node->nodeLog;
Log_debug(logger, "UDPInterface_beginConnection() -> [%s]", res->messageBytes);
}
static void linkNodes(struct Context* ctx, struct NodeContext* client, struct NodeContext* server)
{
Dict* addPasswordArgs = Dict_new(ctx->rpcAlloc);
String* clientStr = String_printf(ctx->rpcAlloc, "%ld", (long) (uintptr_t) client);
Dict_putString(addPasswordArgs,
String_new("password", ctx->rpcAlloc),
clientStr,
ctx->rpcAlloc);
Dict_putString(addPasswordArgs,
String_new("user", ctx->rpcAlloc),
clientStr,
ctx->rpcAlloc);
struct RPCCall* addPasswordCall = pushCall(ctx);
addPasswordCall->func = String_new("AuthorizedPasswords_add", ctx->rpcAlloc);
addPasswordCall->args = addPasswordArgs;
addPasswordCall->node = server;
// client
Dict* beginConnectionArgs = Dict_new(ctx->rpcAlloc);
Dict_putInt(beginConnectionArgs,
String_new("interfaceNumber", ctx->rpcAlloc),
client->ifNum,
ctx->rpcAlloc);
Dict_putString(beginConnectionArgs,
String_new("password", ctx->rpcAlloc),
clientStr,
ctx->rpcAlloc);
Dict_putString(beginConnectionArgs,
String_new("publicKey", ctx->rpcAlloc),
server->publicKey,
ctx->rpcAlloc);
char* udpAddr = Sockaddr_print(server->udpAddr, ctx->rpcAlloc);
Dict_putString(beginConnectionArgs,
String_new("address", ctx->rpcAlloc),
String_new(udpAddr, ctx->rpcAlloc),
ctx->rpcAlloc);
Log_info(ctx->logger, "Linking [%s] with [%s/%s]",
client->nodeName, server->nodeName, udpAddr);
struct RPCCall* connectCall = pushCall(ctx);
connectCall->func = String_new("UDPInterface_beginConnection", ctx->rpcAlloc);
connectCall->args = beginConnectionArgs;
connectCall->node = client;
connectCall->callback = beginConnectionCallback;
}
static void linkAllNodes(struct Context* ctx)
{
int i = 0;
String* key = NULL;
Dict_forEach(ctx->confNodes, key) {
int nodeIdx = Map_OfNodes_indexForKey(&key, &ctx->nodeMap);
Assert_true(nodeIdx >= 0);
struct NodeContext* nc = ctx->nodeMap.values[nodeIdx];
List* connectTo = nc->peers;
for (int j = 0; j < List_size(connectTo); j++) {
String* server = List_getString(connectTo, j);
Assert_true(server);
int nodeIdxB = Map_OfNodes_indexForKey(&server, &ctx->nodeMap);
Assert_true(nodeIdxB >= 0);
struct NodeContext* ncB = ctx->nodeMap.values[nodeIdxB];
linkNodes(ctx, nc, ncB);
}
i++;
}
ctx->confNodes = NULL;
}
static void startRpc(void* vcontext);
static void rpcCallback(struct AdminClient_Promise* promise, struct AdminClient_Result* res)
{
struct Context* ctx = promise->userData;
Identity_check(ctx);
struct RPCCall* thisCall = &ctx->rpcCalls[ctx->nextCall];
if (thisCall->callback) {
thisCall->callback(thisCall, res);
}
ctx->nextCall++;
startRpc(ctx);
}
static void startRpc(void* vcontext)
{
struct Context* ctx = vcontext;
Identity_check(ctx);
if (ctx->nextCall >= ctx->rpcCallCount) {
if (ctx->confNodes) {
linkAllNodes(ctx);
}
}
if (ctx->nextCall >= ctx->rpcCallCount) {
Log_info(ctx->logger, "\n\nCompleted setting up simulation\n\n");
Allocator_free(ctx->rpcAlloc);
ctx->rpcAlloc = NULL;
ctx->rpcCalls = NULL;
ctx->rpcCallCount = 0;
return;
}
struct RPCCall* nextCall = &ctx->rpcCalls[ctx->nextCall];
struct AdminClient_Promise* promise = AdminClient_rpcCall(nextCall->func,
nextCall->args,
nextCall->node->adminClient,
ctx->rpcAlloc);
promise->callback = rpcCallback;
promise->userData = ctx;
}
static void letErRip(Dict* config, struct Allocator* alloc)
{
struct Except* eh = NULL;
struct Log* logger = FileWriterLog_new(stdout, alloc);
struct EventBase* base = EventBase_new(alloc);
struct Random* rand = NanotimeEntropyProvider_newDefaultRandom(base, logger, eh, alloc);
Allocator_setCanary(alloc, (uintptr_t)Random_uint64(rand));
struct Context sctx = {
.rpcAlloc = Allocator_child(alloc),
.logger = logger,
.base = base,
.rand = rand,
.alloc = alloc,
.nodeMap = {
.allocator = alloc
}
};
struct Context* ctx = &sctx;
Identity_set(ctx);
ctx->confNodes = Dict_getDictC(config, "nodes");
struct FakeNetwork* fakeNet = FakeNetwork_new(base, alloc, logger);
String* key = NULL;
Dict_forEach(ctx->confNodes, key) {
Dict* val = Dict_getDict(ctx->confNodes, key);
String* privateKeyHex = Dict_getStringC(val, "privateKey");
Dict* admin = Dict_getDictC(val, "admin");
struct NodeContext* nc =
startNode(key->bytes, privateKeyHex->bytes, admin, ctx, eh, fakeNet);
nc->peers = Dict_getListC(val, "peers");
Map_OfNodes_put(&key, &nc, &ctx->nodeMap);
}
Log_info(ctx->logger, "\n\nAll nodes initialized\n\n");
// begin the chain of RPC calls which sets up the net
Timeout_setTimeout(startRpc, ctx, 0, base, ctx->rpcAlloc);
EventBase_beginLoop(base);
Allocator_free(alloc);
}
static int usage(char* appName)
{
printf("Example usage: %s < config.json\n"
"Example config:\n"
"{\n"
" \"nodes\": {\n"
" \"alice\": {\n"
" \"privateKey\": "
"\"5e2295679394e5e1db67c238abbc10292ad9b127904394c52cc5fff39383e920\",\n"
" \"peers\": []\n"
" },\n"
" \"bob\": {\n"
" \"privateKey\": "
"\"6569bf3f0d168faa6dfb2912f8ee5ee9b938319e97618fdf06caed73b1aad1cc\",\n"
" \"peers\": [\n"
" \"alice\"\n"
" ]\n"
" }\n"
" }\n"
"}\n", appName);
return 0;
}
// This is invoked from sybilsim.rs
int sybilsim_main(int argc, char** argv);
int sybilsim_main(int argc, char** argv)
{
Assert_true(argc > 0);
if (isatty(STDIN_FILENO)) {
return usage(argv[0]);
}
struct Allocator* alloc = Allocator_new(1LL<<31);
struct Reader* stdinReader = FileReader_new(stdin, alloc);
Dict config;
if (JsonBencSerializer_get()->parseDictionary(stdinReader, alloc, &config)) {
fprintf(stderr, "Failed to parse configuration.\n");
return -1;
}
letErRip(&config, alloc);
return 0;
}

View File

@@ -1,43 +0,0 @@
sybilsim(8) -- Cjdns packet switch
=============================================
## SYNOPSIS
`/usr/libexec/cjdns/sybilsim < config.json`
## DESCRIPTION
Sybilsim reads a list of nodes and peers from stdin and simulates the
corresponding mesh without any actual networking using the same code
as cjdroute. This is useful for testing and optimizing cjdroute.
Every node must have a valid cjdns private key. The makekeys(1) utility can be
useful for scripts that generate the config.
## USAGE
Example config:
{
"nodes": {
"alice": {
"privateKey":
"5e2295679394e5e1db67c238abbc10292ad9b127904394c52cc5fff39383e920",
"peers": []
},
"bob": {
"privateKey":
"6569bf3f0d168faa6dfb2912f8ee5ee9b938319e97618fdf06caed73b1aad1cc",
"peers": [ "alice" ]
}
}
}
Example use:
makekeys | head -20 >keys.txt
node /usr/libexec/cjdns/tools/lib/makesim.js keys.txt |
/usr/libexec/cjdns/sybilsim
## SEE ALSO
makekeys(1), cjdroute(1)

View File

@@ -11,12 +11,6 @@ RUN adduser -D -h /etc/cjdns -u 1000 cjdns \
&& rm -rf build_* && ./do \
&& cp cjdroute /usr/bin \
&& cp -r tools/* /usr/bin \
&& cp makekeys \
mkpasswd \
privatetopublic \
publictoip6 \
randombytes \
sybilsim /usr/bin \
&& cp contrib/docker/entrypoint.sh / \
&& rm -rf /src /var/cache/apk/* \
&& apk del --purge python build-base linux-headers

View File

@@ -121,8 +121,6 @@ ln contrib/selinux/cjdns.{te,fc} . # for doc dir
# install c and nodejs tools
mkdir -p %{buildroot}%{_prefix}/lib/cjdns/{node_build,contrib}
cp -p publictoip6 privatetopublic makekeys randombytes sybilsim \
$RPM_BUILD_ROOT%{_prefix}/lib/cjdns
cp -pr tools $RPM_BUILD_ROOT%{_prefix}/lib/cjdns
cp -p node_build/Semaphore.js $RPM_BUILD_ROOT%{_prefix}/lib/cjdns/node_build
cp -pr contrib/nodejs $RPM_BUILD_ROOT%{_prefix}/lib/cjdns/contrib

View File

@@ -5,7 +5,6 @@ cp mkpasswd /usr/bin/
cp privatetopublic /usr/bin/
cp publictoip6 /usr/bin/
cp randombytes /usr/bin/
cp sybilsim /usr/bin/
cp contrib/systemd/cjdns.service /etc/systemd/system/
cp contrib/systemd/cjdns-resume.service /etc/systemd/system
systemctl enable --now cjdns.service

View File

@@ -17,7 +17,6 @@
#include "memory/Allocator.h"
#include "net/InterfaceController.h"
#include "util/events/EventBase.h"
#include "util/events/FakeNetwork.h"
#include "util/platform/Sockaddr.h"
#include "crypto/Key.h"
#include "interface/UDPInterface_admin.h"
@@ -36,7 +35,6 @@ struct Context
struct Admin* admin;
struct ArrayList_UDPInterface* ifaces;
struct InterfaceController* ic;
struct FakeNetwork* fakeNet;
struct GlobalConfig* globalConf;
Identity
};
@@ -333,7 +331,6 @@ void UDPInterface_admin_register(struct EventBase* base,
struct Log* logger,
struct Admin* admin,
struct InterfaceController* ic,
struct FakeNetwork* fakeNet,
struct GlobalConfig* globalConf)
{
struct Context* ctx = Allocator_clone(alloc, (&(struct Context) {
@@ -342,7 +339,6 @@ void UDPInterface_admin_register(struct EventBase* base,
.logger = logger,
.admin = admin,
.ic = ic,
.fakeNet = fakeNet,
.globalConf = globalConf
}));
Identity_set(ctx);

View File

@@ -20,7 +20,6 @@
#include "net/InterfaceController.h"
#include "util/log/Log.h"
#include "util/events/EventBase.h"
#include "util/events/FakeNetwork.h"
#include "util/GlobalConfig.h"
#include "util/Linker.h"
Linker_require("interface/UDPInterface_admin.c")
@@ -30,7 +29,6 @@ void UDPInterface_admin_register(struct EventBase* base,
struct Log* logger,
struct Admin* admin,
struct InterfaceController* ic,
struct FakeNetwork* fakeNet,
struct GlobalConfig* globalConf);
#endif

View File

@@ -294,7 +294,6 @@ Builder.configure({
builder.buildLibrary('contrib/c/publictoip6.c');
builder.buildLibrary('contrib/c/privatetopublic.c');
builder.buildLibrary('contrib/c/sybilsim.c');
builder.buildLibrary('contrib/c/makekeys.c');
builder.buildLibrary('contrib/c/mkpasswd.c');
builder.buildLibrary('crypto/random/randombytes.c');

View File

@@ -1,44 +0,0 @@
/* 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/>.
*/
#ifndef FakeNetwork_H
#define FakeNetwork_H
#include "exception/Except.h"
#include "interface/Iface.h"
#include "interface/addressable/AddrIface.h"
#include "memory/Allocator.h"
#include "util/events/EventBase.h"
#include "util/log/Log.h"
#include "util/Linker.h"
Linker_require("util/events/libuv/FakeNetwork.c")
struct FakeNetwork
{
int unused;
};
struct FakeNetwork_UDPIface
{
struct AddrIface generic;
};
struct FakeNetwork* FakeNetwork_new(struct EventBase* base,
struct Allocator* allocator,
struct Log* logger);
struct FakeNetwork_UDPIface* FakeNetwork_iface(struct FakeNetwork* net,
struct Sockaddr* bindAddress,
struct Allocator* alloc);
#endif

View File

@@ -1,166 +0,0 @@
/* 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 "util/events/FakeNetwork.h"
#include "exception/Except.h"
#include "interface/Iface.h"
#include "interface/addressable/AddrIface.h"
#include "memory/Allocator.h"
#include "util/events/EventBase.h"
#include "util/log/Log.h"
#include "interface/ASynchronizer.h"
#include "wire/Error.h"
#define Map_USE_HASH
#define Map_USE_COMPARATOR
#define Map_NAME OfIfaces
#define Map_KEY_TYPE struct Sockaddr*
#define Map_VALUE_TYPE struct FakeNetwork_UDPIface_pvt*
#include "util/Map.h"
static inline uint32_t Map_OfIfaces_hash(struct Sockaddr** key)
{
return Sockaddr_hash(*key);
}
static inline int Map_OfIfaces_compare(struct Sockaddr** keyA, struct Sockaddr** keyB)
{
return Sockaddr_compare(*keyA, *keyB);
}
struct FakeNetwork_pvt
{
struct FakeNetwork pub;
struct Allocator* alloc;
struct Log* log;
struct EventBase* base;
struct ASynchronizer* async;
struct Iface fromAsync;
struct Iface toAsync;
uint16_t lastPort;
struct Map_OfIfaces map;
Identity
};
struct FakeNetwork_UDPIface_pvt
{
struct FakeNetwork_UDPIface pub;
struct FakeNetwork_pvt* fnp;
Identity
};
static void popSockaddr(struct Message* msg, struct Sockaddr_storage* ss)
{
uint64_t length = 0;
Er_assert(Message_epop(msg, &length, 8));
Er_assert(Message_eshift(msg, 8));
Assert_true(length >= Sockaddr_OVERHEAD);
Assert_true(length <= sizeof(struct Sockaddr_storage));
Er_assert(Message_epop(msg, ss, length));
}
static void pushSockaddr(struct Message* msg, struct Sockaddr* sa)
{
Er_assert(Message_epush(msg, sa, sa->addrLen));
}
static Iface_DEFUN fromAsync(struct Message* msg, struct Iface* fnpFromAsync)
{
struct FakeNetwork_pvt* fnp =
Identity_containerOf(fnpFromAsync, struct FakeNetwork_pvt, fromAsync);
struct Sockaddr_storage dest;
struct Sockaddr* dp = &dest.addr;
popSockaddr(msg, &dest);
int idx = Map_OfIfaces_indexForKey(&dp, &fnp->map);
if (idx == -1) {
char* destAddr = Sockaddr_print(dp, Message_getAlloc(msg));
// hack, the 'dest' becomes the source.
popSockaddr(msg, &dest);
char* srcAddr = Sockaddr_print(dp, Message_getAlloc(msg));
Log_debug(fnp->log, "Message with unknown dest address [%s] from [%s]", destAddr, srcAddr);
return Error(msg, "INVALID");
}
struct FakeNetwork_UDPIface_pvt* fnip = Identity_check(fnp->map.values[idx]);
return Iface_next(&fnip->pub.generic.iface, msg);
}
static Iface_DEFUN incoming(struct Message* msg, struct Iface* iface)
{
struct FakeNetwork_UDPIface_pvt* fnip =
Identity_check((struct FakeNetwork_UDPIface_pvt*) iface);
struct FakeNetwork_pvt* fnp = Identity_check(fnip->fnp);
// Swap so that the message contains [dest][src][content]
struct Sockaddr_storage dest;
popSockaddr(msg, &dest);
pushSockaddr(msg, fnip->pub.generic.addr);
pushSockaddr(msg, &dest.addr);
return Iface_next(&fnp->toAsync, msg);
}
struct FakeNetwork_UDPIface* FakeNetwork_iface(struct FakeNetwork* net,
struct Sockaddr* bindAddress,
struct Allocator* allocator)
{
struct FakeNetwork_pvt* fnp = Identity_check((struct FakeNetwork_pvt*) net);
struct Allocator* alloc = Allocator_child(allocator);
struct Sockaddr* addr = Sockaddr_clone(bindAddress, alloc);
uint8_t* addrBytes;
int addrLen = Sockaddr_getAddress(addr, &addrBytes);
if (Sockaddr_getPort(addr) == 0) {
Sockaddr_setPort(addr, ++fnp->lastPort);
// Check for wrapping.
Assert_true(fnp->lastPort != 0);
Assert_true(addrLen == 4);
Bits_memcpy(addrBytes, ((uint8_t[]){127, 0, 0, 1}), 4);
} else if (addrLen == 4 && !Bits_memcmp(addrBytes, "\0\0\0\0", 4)) {
Assert_failure("Address 0 with port specified is not allowed");
}
if (Map_OfIfaces_indexForKey(&addr, &fnp->map) != -1) {
return NULL;
}
struct FakeNetwork_UDPIface_pvt* fnip =
Allocator_calloc(alloc, sizeof(struct FakeNetwork_UDPIface_pvt), 1);
Map_OfIfaces_put(&addr, &fnip, &fnp->map);
fnip->fnp = fnp;
fnip->pub.generic.alloc = alloc;
fnip->pub.generic.addr = addr;
fnip->pub.generic.iface.send = incoming;
Identity_set(fnip);
return &fnip->pub;
}
struct FakeNetwork* FakeNetwork_new(struct EventBase* base,
struct Allocator* allocator,
struct Log* logger)
{
struct Allocator* alloc = Allocator_child(allocator);
struct FakeNetwork_pvt* fnp = Allocator_calloc(alloc, sizeof(struct FakeNetwork_pvt), 1);
fnp->alloc = alloc;
fnp->log = logger;
fnp->base = base;
fnp->map.allocator = alloc;
fnp->async = ASynchronizer_new(alloc, base, logger);
fnp->fromAsync.send = fromAsync;
Iface_plumb(&fnp->fromAsync, &fnp->async->ifB);
Iface_plumb(&fnp->toAsync, &fnp->async->ifA);
Identity_set(fnp);
return &fnp->pub;
}