Kaynağa Gözat

Merge branch 'fakenet-sybilsim' into crashey

Caleb James DeLisle 8 yıl önce
ebeveyn
işleme
d65af9a6ff

+ 2 - 5
admin/Admin.c

@@ -63,16 +63,13 @@ struct MapValue
 #define Map_KEY_TYPE struct Sockaddr*
 #define Map_VALUE_TYPE struct MapValue*
 #include "util/Map.h"
-
 static inline uint32_t Map_LastMessageTimeByAddr_hash(struct Sockaddr** key)
 {
-    uint32_t* k = (uint32_t*) *key;
-    return k[ ((*key)->addrLen / 4)-1 ];
+    return Sockaddr_hash(*key);
 }
-
 static inline int Map_LastMessageTimeByAddr_compare(struct Sockaddr** keyA, struct Sockaddr** keyB)
 {
-    return Bits_memcmp(*keyA, *keyB, (*keyA)->addrLen);
+    return Sockaddr_compare(*keyA, *keyB);
 }
 
 /////// end map

+ 12 - 5
admin/angel/Core.c

@@ -179,9 +179,14 @@ void Core_init(struct Allocator* alloc,
                uint8_t privateKey[32],
                struct Admin* admin,
                struct Random* rand,
-               struct Except* eh)
+               struct Except* eh,
+               struct FakeNetwork* fakeNet,
+               bool noSec)
 {
-    struct Security* sec = Security_new(alloc, logger, eventBase);
+    struct Security* sec = NULL;
+    if (!noSec) {
+        Security_new(alloc, logger, eventBase);
+    }
     struct NetCore* nc = NetCore_new(privateKey, alloc, eventBase, rand, logger);
 
     struct IpTunnel* ipTunnel = IpTunnel_new(logger, eventBase, alloc, rand);
@@ -197,14 +202,16 @@ void Core_init(struct Allocator* alloc,
     // ------------------- Register RPC functions ----------------------- //
     InterfaceController_admin_register(nc->ifController, admin, alloc);
     SwitchPinger_admin_register(nc->sp, admin, alloc);
-    UDPInterface_admin_register(eventBase, alloc, logger, admin, nc->ifController);
+    UDPInterface_admin_register(eventBase, alloc, logger, admin, nc->ifController, fakeNet);
 #ifdef HAS_ETH_INTERFACE
     ETHInterface_admin_register(eventBase, alloc, logger, admin, nc->ifController);
 #endif
 
     AuthorizedPasswords_init(admin, nc->ca, alloc);
     Admin_registerFunction("ping", adminPing, admin, false, NULL, admin);
-    Security_admin_register(alloc, logger, sec, admin);
+    if (!noSec) {
+        Security_admin_register(alloc, logger, sec, admin);
+    }
     IpTunnel_admin_register(ipTunnel, admin, alloc);
     SessionManager_admin_register(nc->sm, admin, alloc);
     Allocator_admin_register(alloc, admin);
@@ -322,7 +329,7 @@ int Core_main(int argc, char** argv)
     Allocator_free(tempAlloc);
 
 
-    Core_init(alloc, logger, eventBase, privateKey, admin, rand, eh);
+    Core_init(alloc, logger, eventBase, privateKey, admin, rand, eh, NULL, false);
     EventBase_beginLoop(eventBase);
     return 0;
 }

+ 4 - 1
admin/angel/Core.h

@@ -20,6 +20,7 @@
 #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")
 
@@ -38,7 +39,9 @@ void Core_init(struct Allocator* alloc,
                uint8_t privateKey[32],
                struct Admin* admin,
                struct Random* rand,
-               struct Except* eh);
+               struct Except* eh,
+               struct FakeNetwork* fakeNet,
+               bool noSec);
 
 int Core_main(int argc, char** argv);
 

+ 1 - 0
client/cjdroute2.c

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

+ 61 - 26
contrib/c/sybilsim.c

@@ -36,6 +36,8 @@
 #include "io/FileReader.h"
 #include "io/ArrayWriter.h"
 #include "util/Hex.h"
+#include "util/events/FakeNetwork.h"
+#include "util/Hash.h"
 
 #include "crypto_scalarmult_curve25519.h"
 
@@ -65,6 +67,8 @@ struct NodeContext {
     struct Log nodeLog;
     struct Log* parentLogger;
 
+    List* peers;
+
     Identity
 };
 
@@ -80,6 +84,21 @@ struct RPCCall
     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;
@@ -92,9 +111,8 @@ struct Context
     struct Log* logger;
     struct Allocator* alloc;
 
-    struct NodeContext** nodes;
+    struct Map_OfNodes nodeMap;
     Dict* confNodes;
-    String** names;
 
     Identity
 };
@@ -134,7 +152,9 @@ static struct RPCCall* pushCall(struct Context* ctx)
 static void bindUDPCallback(struct RPCCall* call, struct AdminClient_Result* res)
 {
     Assert_true(!res->err);
-    Log_debug(&call->node->nodeLog, "UDPInterface_new() -> [%s]", res->messageBytes);
+    // Indirection to shutup clang warning
+    struct Log* logger = &call->node->nodeLog;
+    Log_debug(logger, "UDPInterface_new() -> [%s]", res->messageBytes);
     String* addr = Dict_getString(res->responseDict, String_CONST("bindAddress"));
     int64_t* ifNum = Dict_getInt(res->responseDict, String_CONST("interfaceNumber"));
     struct Sockaddr_storage ss;
@@ -164,10 +184,12 @@ static struct NodeContext* startNode(char* nodeName,
                                      char* privateKeyHex,
                                      Dict* admin,
                                      struct Context* ctx,
-                                     struct Except* eh)
+                                     struct Except* eh,
+                                     struct FakeNetwork* fakeNet)
 {
-    struct NodeContext* node = Allocator_clone(ctx->alloc, (&(struct NodeContext) {
-        .alloc = ctx->alloc,
+    struct Allocator* alloc = Allocator_child(ctx->alloc);
+    struct NodeContext* node = Allocator_clone(alloc, (&(struct NodeContext) {
+        .alloc = alloc,
         .base = ctx->base,
         .nodeLog = {
             .print = printLog
@@ -179,11 +201,11 @@ static struct NodeContext* startNode(char* nodeName,
 
     node->bind = Dict_getString(admin, String_CONST("bind"));
     if (!node->bind) {
-        node->bind = String_new("127.0.0.1:0", ctx->alloc);
+        node->bind = String_new("127.0.0.1:0", alloc);
     }
     node->pass = Dict_getString(admin, String_CONST("password"));
     if (!node->pass) {
-        node->pass = String_new("x", ctx->alloc);
+        node->pass = String_new("x", alloc);
     }
 
     Assert_true(Hex_decode(node->privateKey, 32, privateKeyHex, 64) == 32);
@@ -204,7 +226,15 @@ static struct NodeContext* startNode(char* nodeName,
 
     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);
+    Core_init(node->alloc,
+              &node->nodeLog,
+              ctx->base,
+              node->privateKey,
+              node->admin,
+              ctx->rand,
+              eh,
+              fakeNet,
+              true);
 
     securitySetupComplete(ctx, node);
     bindUDP(ctx, node);
@@ -216,7 +246,9 @@ static struct NodeContext* startNode(char* nodeName,
 static void beginConnectionCallback(struct RPCCall* call, struct AdminClient_Result* res)
 {
     Assert_true(!res->err);
-    Log_debug(&call->node->nodeLog, "UDPInterface_beginConnection() -> [%s]", res->messageBytes);
+    // 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)
@@ -271,17 +303,17 @@ static void linkAllNodes(struct Context* ctx)
     int i = 0;
     String* key = NULL;
     Dict_forEach(ctx->confNodes, key) {
-        Dict* val = Dict_getDict(ctx->confNodes, key);
-        List* connectTo = Dict_getList(val, String_CONST("peers"));
+        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);
-            for (int k = 0; k < Dict_size(ctx->confNodes); k++) {
-                if (String_equals(server, ctx->names[k])) {
-                    linkNodes(ctx, ctx->nodes[i], ctx->nodes[k]);
-                    break;
-                }
-            }
+            int nodeIdxB = Map_OfNodes_indexForKey(&server, &ctx->nodeMap);
+            Assert_true(nodeIdxB >= 0);
+            struct NodeContext* ncB = ctx->nodeMap.values[nodeIdxB];
+            linkNodes(ctx, nc, ncB);
         }
         i++;
     }
@@ -347,26 +379,29 @@ static void letErRip(Dict* config, struct Allocator* alloc)
         .base = base,
         .rand = rand,
         .alloc = alloc,
+        .nodeMap = {
+            .allocator = alloc
+        }
     };
     struct Context* ctx = &sctx;
     Identity_set(ctx);
 
     ctx->confNodes = Dict_getDict(config, String_CONST("nodes"));
-    ctx->nodes = Allocator_calloc(alloc, sizeof(char*), Dict_size(ctx->confNodes));
-    ctx->names = Allocator_calloc(alloc, sizeof(String*), Dict_size(ctx->confNodes));
+
+    struct FakeNetwork* fakeNet = FakeNetwork_new(base, alloc, logger);
 
     String* key = NULL;
-    int i = 0;
     Dict_forEach(ctx->confNodes, key) {
         Dict* val = Dict_getDict(ctx->confNodes, key);
         String* privateKeyHex = Dict_getString(val, String_CONST("privateKey"));
         Dict* admin = Dict_getDict(val, String_CONST("admin"));
-        ctx->names[i] = key;
-        ctx->nodes[i] = startNode(key->bytes, privateKeyHex->bytes, admin, ctx, eh);
-        i++;
+        struct NodeContext* nc =
+            startNode(key->bytes, privateKeyHex->bytes, admin, ctx, eh, fakeNet);
+        nc->peers = Dict_getList(val, String_CONST("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);
@@ -407,7 +442,7 @@ int main(int argc, char** argv)
         return usage(argv[0]);
     }
 
-    struct Allocator* alloc = MallocAllocator_new(1<<30);
+    struct Allocator* alloc = MallocAllocator_new(1LL<<31);
 
     struct Reader* stdinReader = FileReader_new(stdin, alloc);
     Dict config;

+ 35 - 9
interface/UDPInterface_admin.c

@@ -19,6 +19,7 @@
 #include "net/InterfaceController.h"
 #include "util/events/UDPAddrIface.h"
 #include "util/events/EventBase.h"
+#include "util/events/FakeNetwork.h"
 #include "util/platform/Sockaddr.h"
 #include "crypto/Key.h"
 
@@ -30,6 +31,7 @@ struct Context
     struct Admin* admin;
     struct AddrIface* udpIf;
     struct InterfaceController* ic;
+    struct FakeNetwork* fakeNet;
 };
 
 static void beginConnection(Dict* args,
@@ -116,12 +118,11 @@ static void beginConnection(Dict* args,
     Admin_sendMessage(&out, txid, ctx->admin);
 }
 
-static void newInterface2(struct Context* ctx,
-                          struct Sockaddr* addr,
-                          String* txid,
-                          struct Allocator* requestAlloc)
+static struct AddrIface* setupLibuvUDP(struct Context* ctx,
+                                       struct Sockaddr* addr,
+                                       String* txid,
+                                       struct Allocator* alloc)
 {
-    struct Allocator* const alloc = Allocator_child(ctx->alloc);
     struct UDPAddrIface* udpIf = NULL;
     struct Jmp jmp;
     Jmp_try(jmp) {
@@ -131,10 +132,33 @@ static void newInterface2(struct Context* ctx,
         Dict out = Dict_CONST(String_CONST("error"), String_OBJ(errStr), NULL);
         Admin_sendMessage(&out, txid, ctx->admin);
         Allocator_free(alloc);
-        return;
+        return NULL;
     }
+    return &udpIf->generic;
+}
+
+static struct AddrIface* setupFakeUDP(struct FakeNetwork* fakeNet,
+                                      struct Sockaddr* addr,
+                                      struct Allocator* alloc)
+{
+    struct FakeNetwork_UDPIface* fni = FakeNetwork_iface(fakeNet, addr, alloc);
+    return &fni->generic;
+}
 
-    struct AddrIface* ai = ctx->udpIf = &udpIf->generic;
+static void newInterface2(struct Context* ctx,
+                          struct Sockaddr* addr,
+                          String* txid,
+                          struct Allocator* requestAlloc)
+{
+    struct Allocator* const alloc = Allocator_child(ctx->alloc);
+    struct AddrIface* ai;
+    if (ctx->fakeNet) {
+        ai = setupFakeUDP(ctx->fakeNet, addr, alloc);
+    } else {
+        ai = setupLibuvUDP(ctx, addr, txid, alloc);
+    }
+    if (!ai) { return; }
+    ctx->udpIf = ai;
     struct InterfaceController_Iface* ici =
         InterfaceController_newIface(ctx->ic, String_CONST("UDP"), alloc);
     Iface_plumb(&ici->addrIf, &ai->iface);
@@ -170,14 +194,16 @@ void UDPInterface_admin_register(struct EventBase* base,
                                  struct Allocator* alloc,
                                  struct Log* logger,
                                  struct Admin* admin,
-                                 struct InterfaceController* ic)
+                                 struct InterfaceController* ic,
+                                 struct FakeNetwork* fakeNet)
 {
     struct Context* ctx = Allocator_clone(alloc, (&(struct Context) {
         .eventBase = base,
         .alloc = alloc,
         .logger = logger,
         .admin = admin,
-        .ic = ic
+        .ic = ic,
+        .fakeNet = fakeNet
     }));
 
     Admin_registerFunction("UDPInterface_new", newInterface, ctx, true,

+ 3 - 1
interface/UDPInterface_admin.h

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

+ 2 - 2
net/InterfaceController.c

@@ -70,11 +70,11 @@
 #include "util/Map.h"
 static inline uint32_t Map_EndpointsBySockaddr_hash(struct Sockaddr** key)
 {
-    return Checksum_engine((uint8_t*) &(key[0][1]), key[0]->addrLen - Sockaddr_OVERHEAD);
+    return Sockaddr_hash(*key);
 }
 static inline int Map_EndpointsBySockaddr_compare(struct Sockaddr** keyA, struct Sockaddr** keyB)
 {
-    return Bits_memcmp((uint8_t*) *keyA, (uint8_t*) *keyB, keyA[0]->addrLen);
+    return Sockaddr_compare(*keyA, *keyB);
 }
 // ---------------- EndMap ----------------
 

+ 30 - 0
util/Hash.h

@@ -0,0 +1,30 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+#ifndef Hash_H
+#define Hash_H
+
+#include <stdint.h>
+
+/** The DJB2a hash (equivilant to DJB2 but using XOR instead of +) */
+static uint32_t Hash_compute(uint8_t* str, int length)
+{
+    uint32_t hash = 5381;
+    for (int i = 0; i < length; i++) {
+        hash = ((hash << 5) + hash) ^ str[i];
+    }
+    return hash;
+}
+
+#endif

+ 4 - 1
util/Map.h

@@ -18,6 +18,7 @@
 
 #include "util/Bits.h"
 
+
 #if defined(Map_KEY_TYPE)
     Assert_compileTime(!(sizeof(Map_KEY_TYPE) % 4));
     #define Map_ENABLE_KEYS
@@ -40,10 +41,11 @@
     // Hashcode calculator.
     static inline uint32_t Map_FUNCTION(hash)(Map_KEY_TYPE* key);
     #ifndef Map_USE_HASH
+        #include "util/Hash.h"
         // Get the last 4 bytes of the key by default.
         static inline uint32_t Map_FUNCTION(hash)(Map_KEY_TYPE* key)
         {
-            return ((uint32_t*)key)[(sizeof(Map_KEY_TYPE) / 4) - 1];
+            return Hash_compute((uint8_t*)key, sizeof(Map_KEY_TYPE));
         }
     #endif
 
@@ -229,3 +231,4 @@ static inline int Map_FUNCTION(put)(Map_VALUE_TYPE* value,
 #undef Map_ENABLE_HANDLES
 #undef Map_KEY_TYPE
 #undef Map_ENABLE_KEYS
+#undef Map_USE_COMPARATOR

+ 44 - 0
util/events/FakeNetwork.h

@@ -0,0 +1,44 @@
+/* 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 <http://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

+ 165 - 0
util/events/libuv/FakeNetwork.c

@@ -0,0 +1,165 @@
+/* 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 <http://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"
+
+#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;
+    Message_pop(msg, &length, 8, NULL);
+    Message_shift(msg, 8, NULL);
+    Assert_true(length >= Sockaddr_OVERHEAD);
+    Assert_true(length <= sizeof(struct Sockaddr_storage));
+    Message_pop(msg, ss, length, NULL);
+}
+
+static void pushSockaddr(struct Message* msg, struct Sockaddr* sa)
+{
+    Message_push(msg, sa, sa->addrLen, NULL);
+}
+
+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, msg->alloc);
+
+        // hack, the 'dest' becomes the source.
+        popSockaddr(msg, &dest);
+        char* srcAddr = Sockaddr_print(dp, msg->alloc);
+
+        Log_debug(fnp->log, "Message with unknown dest address [%s] from [%s]", destAddr, srcAddr);
+        return NULL;
+    }
+
+    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_memcpyConst(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;
+}

+ 20 - 45
util/log/Log.h

@@ -70,58 +70,33 @@ void Log_print(struct Log* log,
 
 #define Log_printf(log, level, ...) \
     do {                                                                   \
-        if (log) {                                                         \
+        if (log && level >= Log_MIN_LEVEL) {                               \
             Log_print(log, level, Gcc_SHORT_FILE, Gcc_LINE, __VA_ARGS__);  \
         }                                                                  \
     } while (0)
 // CHECKFILES_IGNORE missing ;
 
-#ifdef Log_KEYS
-    #define Log_keys(log, ...) \
-        Log_printf(log, Log_Level_KEYS, __VA_ARGS__)
-#else
-    #define Log_keys(log, ...) \
-        Log_printf(0, Log_Level_KEYS, __VA_ARGS__)
-#endif
-
-#ifdef Log_DEBUG
-    #define Log_debug(log, ...) \
-        Log_printf(log, Log_Level_DEBUG, __VA_ARGS__)
+#if defined(Log_KEYS)
+    #define Log_MIN_LEVEL Log_Level_KEYS
+#elif defined(Log_DEBUG)
+    #define Log_MIN_LEVEL Log_Level_DEBUG
+#elif defined(Log_INFO)
+    #define Log_MIN_LEVEL Log_Level_INFO
+#elif defined(Log_WARN)
+    #define Log_MIN_LEVEL Log_Level_WARN
+#elif defined(Log_ERROR)
+    #define Log_MIN_LEVEL Log_Level_ERROR
+#elif defined(Log_CRITICAL)
+    #define Log_MIN_LEVEL Log_Level_CRITICAL
 #else
-    #define Log_debug(log, ...) \
-        Log_printf(0, Log_Level_DEBUG, __VA_ARGS__)
+    #error
 #endif
 
-#ifdef Log_INFO
-    #define Log_info(log, ...) \
-        Log_printf(log, Log_Level_INFO, __VA_ARGS__)
-#else
-    #define Log_info(log, ...) \
-        Log_printf(0, Log_Level_INFO, __VA_ARGS__)
-#endif
-
-#ifdef Log_WARN
-    #define Log_warn(log, ...) \
-        Log_printf(log, Log_Level_WARN, __VA_ARGS__)
-#else
-    #define Log_warn(log, ...) \
-        Log_printf(0, Log_Level_WARN, __VA_ARGS__)
-#endif
-
-#ifdef Log_ERROR
-    #define Log_error(log, ...) \
-        Log_printf(log, Log_Level_ERROR, __VA_ARGS__)
-#else
-    #define Log_error(log, ...) \
-        Log_printf(0, Log_Level_ERROR, __VA_ARGS__)
-#endif
-
-#ifdef Log_CRITICAL
-    #define Log_critical(log, ...) \
-        Log_printf(log, Log_Level_CRITICAL, __VA_ARGS__)
-#else
-    #define Log_critical(log, ...) \
-        Log_printf(0, Log_Level_CRITICAL, __VA_ARGS__)
-#endif
+#define Log_keys(log, ...)  Log_printf(log, Log_Level_KEYS, __VA_ARGS__)
+#define Log_debug(log, ...) Log_printf(log, Log_Level_DEBUG, __VA_ARGS__)
+#define Log_info(log, ...)  Log_printf(log, Log_Level_INFO, __VA_ARGS__)
+#define Log_warn(log, ...)  Log_printf(log, Log_Level_WARN, __VA_ARGS__)
+#define Log_error(log, ...) Log_printf(log, Log_Level_ERROR, __VA_ARGS__)
+#define Log_critical(log, ...) Log_printf(log, Log_Level_CRITICAL, __VA_ARGS__)
 
 #endif

+ 11 - 0
util/platform/Sockaddr.c

@@ -19,6 +19,7 @@
 #include "util/CString.h"
 #include "util/Bits.h"
 #include "util/Hex.h"
+#include "util/Hash.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -309,3 +310,13 @@ struct Sockaddr* Sockaddr_fromName(char* name, struct Allocator* alloc)
     }
     return NULL;
 }
+
+uint32_t Sockaddr_hash(const struct Sockaddr* addr)
+{
+    return Hash_compute((uint8_t*)addr, addr->addrLen);
+}
+
+int Sockaddr_compare(const struct Sockaddr* a, const struct Sockaddr* b)
+{
+    return Bits_memcmp(a, b, a->addrLen);
+}

+ 10 - 0
util/platform/Sockaddr.h

@@ -136,4 +136,14 @@ struct Sockaddr* Sockaddr_clone(const struct Sockaddr* addr, struct Allocator* a
  */
 void Sockaddr_normalizeNative(void* nativeSockaddr);
 
+/**
+ * Get a hash for hashtable lookup.
+ */
+uint32_t Sockaddr_hash(const struct Sockaddr* addr);
+
+/**
+ * Compare two sockaddrs for sorting, comparison does not put them in any specific order.
+ */
+int Sockaddr_compare(const struct Sockaddr* a, const struct Sockaddr* b);
+
 #endif