Browse Source

Iface_DEFUN return an error type

Caleb James DeLisle 3 years ago
parent
commit
3cf79da359
46 changed files with 328 additions and 320 deletions
  1. 12 9
      admin/Admin.c
  2. 2 2
      admin/angel/InterfaceWaiter.c
  3. 6 5
      client/AdminClient.c
  4. 14 14
      dht/Pathfinder.c
  5. 2 2
      interface/ASynchronizer.c
  6. 1 2
      interface/ETHInterface_darwin.c
  7. 1 1
      interface/ETHInterface_linux.c
  8. 6 6
      interface/FramingIface.c
  9. 29 61
      interface/Iface.h
  10. 7 7
      interface/UDPInterface.c
  11. 2 2
      interface/addressable/AddrIfaceMuxer.c
  12. 3 3
      interface/addressable/PacketHeaderToUDPAddrIface.c
  13. 1 1
      interface/test/FramingIface_fuzz_test.c
  14. 3 3
      interface/tuntap/AndroidWrapper.c
  15. 2 2
      interface/tuntap/BSDMessageTypeWrapper.c
  16. 3 3
      interface/tuntap/SocketWrapper.c
  17. 3 3
      interface/tuntap/TAPWrapper.c
  18. 1 1
      interface/tuntap/test/BSDMessageTypeWrapper_test.c
  19. 1 1
      interface/tuntap/test/TUNInterface_ipv4_root_test.c
  20. 3 3
      interface/tuntap/test/TUNTools.c
  21. 2 2
      interface/tuntap/windows/TAPInterface.c
  22. 1 1
      net/Benchmark.c
  23. 19 18
      net/ControlHandler.c
  24. 10 10
      net/EventEmitter.c
  25. 21 21
      net/InterfaceController.c
  26. 17 17
      net/SessionManager.c
  27. 13 13
      net/SwitchPinger.c
  28. 6 5
      net/TUNAdapter.c
  29. 20 6
      net/UpperDistributor.c
  30. 10 10
      subnode/MsgCore.c
  31. 4 4
      subnode/MsgCore.h
  32. 7 6
      subnode/PingResponder.c
  33. 10 10
      subnode/SubnodePathfinder.c
  34. 4 4
      switch/SwitchCore.c
  35. 2 2
      test/Beacon_test.c
  36. 1 1
      test/Main_fuzz_test.c
  37. 1 2
      test/TestFramework.c
  38. 23 21
      tunnel/IpTunnel.c
  39. 2 2
      tunnel/test/IpTunnel_test.c
  40. 1 1
      util/events/libuv/FakeNetwork.c
  41. 2 2
      util/events/libuv/Pipe.c
  42. 1 1
      util/events/libuv/PipeServer.c
  43. 4 4
      util/events/libuv/UDPAddrIface.c
  44. 2 2
      util/test/Process_test.c
  45. 1 1
      util/test/Seccomp_test.c
  46. 42 23
      wire/Error.h

+ 12 - 9
admin/Admin.c

@@ -113,26 +113,27 @@ struct Admin_pvt
     Identity
 };
 
-static void sendMessage(struct Message* message, struct Sockaddr* dest, struct Admin_pvt* admin)
+static struct Error_s sendMessage(
+    struct Message* message, struct Sockaddr* dest, struct Admin_pvt* admin)
 {
     // stack overflow when used with admin logger.
     //Log_keys(admin->logger, "sending message to angel [%s]", message->bytes);
     Er_assert(Message_epush(message, dest, dest->addrLen));
-    Iface_send(&admin->iface, message);
+    return Iface_send(&admin->iface, message);
 }
 
-static void sendBenc(Dict* message,
-                     struct Sockaddr* dest,
-                     struct Allocator* alloc,
-                     struct Admin_pvt* admin,
-                     int fd)
+static struct Error_s sendBenc(Dict* message,
+                               struct Sockaddr* dest,
+                               struct Allocator* alloc,
+                               struct Admin_pvt* admin,
+                               int fd)
 {
     Message_reset(admin->tempSendMsg);
     Er_assert(BencMessageWriter_write(message, admin->tempSendMsg));
     struct Message* msg = Message_new(0, admin->tempSendMsg->length + 32, alloc);
     Er_assert(Message_epush(msg, admin->tempSendMsg->bytes, admin->tempSendMsg->length));
     Message_setAssociatedFd(msg, fd);
-    sendMessage(msg, dest, admin);
+    return sendMessage(msg, dest, admin);
 }
 
 /**
@@ -473,7 +474,9 @@ static Iface_DEFUN receiveMessage(struct Message* message, struct Iface* iface)
 
     admin->currentRequest = NULL;
     Allocator_free(alloc);
-    return NULL;
+    // We don't return errors here because the caller can't make use of them
+    // instead we reply with anything which went wrong.
+    return Error(NONE);
 }
 
 void Admin_registerFunctionWithArgCount(char* name,

+ 2 - 2
admin/angel/InterfaceWaiter.c

@@ -44,13 +44,13 @@ static void timeout(void* vcontext)
 static Iface_DEFUN receiveMessage(struct Message* message, struct Iface* iface)
 {
     struct Context* ctx = Identity_check((struct Context*) iface);
-    if (ctx->messageReceived) { return 0; }
+    if (ctx->messageReceived) { return Error(NONE); }
     ctx->message = Message_clone(message, ctx->alloc);
 
     Timeout_clearTimeout(ctx->timeout);
     EventBase_endLoop(ctx->eventBase);
 
-    return 0;
+    return Error(NONE);
 }
 
 struct Message* InterfaceWaiter_waitForData(struct Iface* iface,

+ 6 - 5
client/AdminClient.c

@@ -123,7 +123,8 @@ static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* addrIface)
         Log_info(ctx->logger, "Got spurious message from [%s], expecting messages from [%s]",
                  Sockaddr_print(&source.addr, msg->alloc),
                  Sockaddr_print(ctx->targetAddr, msg->alloc));
-        return NULL;
+        // The UDP interface can't make use of an error but we'll inform anyway
+        return Error(INVALID);
     }
 
     // we don't yet know with which message this data belongs,
@@ -133,17 +134,17 @@ static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* addrIface)
     int origLen = msg->length;
     Dict* d = NULL;
     const char* err = BencMessageReader_readNoExcept(msg, alloc, &d);
-    if (err) { return NULL; }
+    if (err) { return Error(INVALID); }
     Er_assert(Message_eshift(msg, origLen));
 
     String* txid = Dict_getStringC(d, "txid");
-    if (!txid || txid->len != 8) { return NULL; }
+    if (!txid || txid->len != 8) { return Error(INVALID); }
 
     // look up the result
     uint32_t handle = ~0u;
     Hex_decode((uint8_t*)&handle, 4, txid->bytes, 8);
     int idx = Map_OfRequestByHandle_indexForHandle(handle, &ctx->outstandingRequests);
-    if (idx < 0) { return NULL; }
+    if (idx < 0) { return Error(INVALID); }
 
     struct Request* req = ctx->outstandingRequests.values[idx];
 
@@ -157,7 +158,7 @@ static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* addrIface)
     Bits_memset(req->res.messageBytes, 0, AdminClient_MAX_MESSAGE_SIZE);
     Bits_memcpy(req->res.messageBytes, msg->bytes, len);
     done(req, AdminClient_Error_NONE);
-    return NULL;
+    return Error(NONE);
 }
 
 static int requestOnFree(struct Allocator_OnFreeJob* job)

+ 14 - 14
dht/Pathfinder.c

@@ -237,7 +237,7 @@ static Iface_DEFUN connected(struct Pathfinder_pvt* pf, struct Message* msg)
 
     pf->state = Pathfinder_pvt_state_RUNNING;
 
-    return NULL;
+    return Error(NONE);
 }
 
 static void addressForNode(struct Address* addrOut, struct Message* msg)
@@ -277,7 +277,7 @@ static Iface_DEFUN switchErr(struct Message* msg, struct Pathfinder_pvt* pf)
         SearchRunner_search(nodeAddr, 20, 3, pf->searchRunner, pf->alloc);
     }
 
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN searchReq(struct Message* msg, struct Pathfinder_pvt* pf)
@@ -286,7 +286,7 @@ static Iface_DEFUN searchReq(struct Message* msg, struct Pathfinder_pvt* pf)
     Er_assert(Message_epop(msg, addr, 16));
     Er_assert(Message_epop32be(msg));
     uint32_t version = Er_assert(Message_epop32be(msg));
-    if (version && version >= 20) { return NULL; }
+    if (version && version >= 20) { return Error(NONE); }
     Assert_true(!msg->length);
     uint8_t printedAddr[40];
     AddrTools_printIp(printedAddr, addr);
@@ -298,7 +298,7 @@ static Iface_DEFUN searchReq(struct Message* msg, struct Pathfinder_pvt* pf)
     } else {
         SearchRunner_search(addr, 20, 3, pf->searchRunner, pf->alloc);
     }
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN peer(struct Message* msg, struct Pathfinder_pvt* pf)
@@ -315,7 +315,7 @@ static Iface_DEFUN peer(struct Message* msg, struct Pathfinder_pvt* pf)
         && Node_getBestParent(link->child)->parent->address.path == 1
         && Node_getBestParent(link->child)->cannonicalLabel == addr.path)
     {
-        return NULL;
+        return Error(NONE);
     }
     //RumorMill_addNode(pf->rumorMill, &addr);
     Router_sendGetPeers(pf->router, &addr, 0, 0, pf->alloc);
@@ -349,7 +349,7 @@ static Iface_DEFUN session(struct Message* msg, struct Pathfinder_pvt* pf)
         SearchRunner_search(addr.ip6.bytes, 20, 3, pf->searchRunner, pf->alloc);
     }*/
 
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN sessionEnded(struct Message* msg, struct Pathfinder_pvt* pf)
@@ -358,7 +358,7 @@ static Iface_DEFUN sessionEnded(struct Message* msg, struct Pathfinder_pvt* pf)
     addressForNode(&addr, msg);
     String* str = Address_toString(&addr, msg->alloc);
     Log_debug(pf->log, "Session ended [%s]", str->bytes);
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN discoveredPath(struct Message* msg, struct Pathfinder_pvt* pf)
@@ -367,22 +367,22 @@ static Iface_DEFUN discoveredPath(struct Message* msg, struct Pathfinder_pvt* pf
     addressForNode(&addr, msg);
 
     // We're somehow aware of this path (even if it's unused)
-    if (NodeStore_linkForPath(pf->nodeStore, addr.path)) { return NULL; }
+    if (NodeStore_linkForPath(pf->nodeStore, addr.path)) { return Error(NONE); }
 
     // If we don't already care about the destination, then don't do anything.
     struct Node_Two* nn = NodeStore_nodeForAddr(pf->nodeStore, addr.ip6.bytes);
-    if (!nn) { return NULL; }
+    if (!nn) { return Error(NONE); }
 
     // Our best path is "shorter" (label bits which is somewhat representitive of hop count)
     // basically this is just to dampen the flood to the RM because otherwise it prevents Janitor
     // from getting any actual work done.
-    if (nn->address.path < addr.path) { return NULL; }
+    if (nn->address.path < addr.path) { return Error(NONE); }
 
     addr.protocolVersion = nn->address.protocolVersion;
 
     Log_debug(pf->log, "Discovered path [%s]", Address_toString(&addr, msg->alloc)->bytes);
     RumorMill_addNode(pf->rumorMill, &addr);
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN handlePing(struct Message* msg, struct Pathfinder_pvt* pf)
@@ -395,7 +395,7 @@ static Iface_DEFUN handlePing(struct Message* msg, struct Pathfinder_pvt* pf)
 static Iface_DEFUN handlePong(struct Message* msg, struct Pathfinder_pvt* pf)
 {
     Log_debug(pf->log, "Received pong");
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN incomingMsg(struct Message* msg, struct Pathfinder_pvt* pf)
@@ -427,7 +427,7 @@ static Iface_DEFUN incomingMsg(struct Message* msg, struct Pathfinder_pvt* pf)
         return Iface_next(&pf->pub.eventIf, msg);
     }
 
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN incomingFromEventIf(struct Message* msg, struct Iface* eventIf)
@@ -453,7 +453,7 @@ static Iface_DEFUN incomingFromEventIf(struct Message* msg, struct Iface* eventI
         case PFChan_Core_PONG: return handlePong(msg, pf);
         case PFChan_Core_UNSETUP_SESSION:
         case PFChan_Core_LINK_STATE:
-        case PFChan_Core_CTRL_MSG: return NULL;
+        case PFChan_Core_CTRL_MSG: return Error(NONE);
         default:;
     }
     Assert_failure("unexpected event [%d]", ev);

+ 2 - 2
interface/ASynchronizer.c

@@ -101,7 +101,7 @@ static Iface_DEFUN fromA(struct Message* msg, struct Iface* ifA)
     Allocator_adopt(as->cycleAlloc, msg->alloc);
     ArrayList_Messages_add(as->msgsToB, msg);
     checkTimeout(as);
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN fromB(struct Message* msg, struct Iface* ifB)
@@ -112,7 +112,7 @@ static Iface_DEFUN fromB(struct Message* msg, struct Iface* ifB)
     Allocator_adopt(as->cycleAlloc, msg->alloc);
     ArrayList_Messages_add(as->msgsToA, msg);
     checkTimeout(as);
-    return NULL;
+    return Error(NONE);
 }
 
 struct ASynchronizer* ASynchronizer_new(struct Allocator* alloc,

+ 1 - 2
interface/ETHInterface_darwin.c

@@ -109,8 +109,7 @@ static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* iface)
     if (msg->length != write(ctx->socket, msg->bytes, msg->length)) {
         Log_debug(ctx->logger, "Error writing to eth device [%s]", strerror(errno));
     }
-Log_debug(ctx->logger, "message sent");
-    return NULL;
+    return Error(NONE);
 }
 
 static void handleEvent2(struct ETHInterface_pvt* context,

+ 1 - 1
interface/ETHInterface_linux.c

@@ -129,7 +129,7 @@ static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* iface)
     };
     Er_assert(Message_epush(msg, &hdr, ETHInterface_Header_SIZE));
     sendMessageInternal(msg, &addr, ctx);
-    return NULL;
+    return Error(NONE);
 }
 
 static void handleEvent2(struct ETHInterface_pvt* context, struct Allocator* messageAlloc)

+ 6 - 6
interface/FramingIface.c

@@ -79,7 +79,7 @@ static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* streamIf)
     if (fi->bytesRemaining > fi->maxMessageSize) {
         // Oversize message
         Assert_ifTesting(0);
-        return NULL;
+        return Error(OVERSIZE_MESSAGE);
     }
 
     if (fi->frameParts) {
@@ -93,7 +93,7 @@ static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* streamIf)
             // Run the message through again since it's almost certainly not perfect size.
             Iface_CALL(receiveMessage, wholeMessage, streamIf);
             Allocator_free(frameAlloc);
-            return NULL;
+            return Error(NONE);
         }
         fi->bytesRemaining -= msg->length;
         Allocator_adopt(fi->frameAlloc, msg->alloc);
@@ -101,13 +101,13 @@ static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* streamIf)
         parts->msg = msg;
         parts->next = fi->frameParts;
         fi->frameParts = parts;
-        return NULL;
+        return Error(NONE);
     }
 
     for (;;) {
         while (fi->headerIndex < 4) {
             if (!msg->length) {
-                return NULL;
+                return Error(NONE);
             }
             fi->header.bytes[fi->headerIndex] = msg->bytes[0];
             Er_assert(Message_eshift(msg, -1));
@@ -119,7 +119,7 @@ static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* streamIf)
         if (fi->bytesRemaining > fi->maxMessageSize) {
             // oversize
             Assert_ifTesting(0);
-            return NULL;
+            return Error(OVERSIZE_MESSAGE);
         }
 
         if (fi->bytesRemaining == (uint32_t)msg->length) {
@@ -153,7 +153,7 @@ static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* streamIf)
             fi->frameParts->msg = m;
             fi->frameParts->next = NULL;
         }
-        return NULL;
+        return Error(NONE);
     }
 }
 

+ 29 - 61
interface/Iface.h

@@ -17,6 +17,7 @@
 
 #include <stdint.h>
 
+#include "wire/Error.h"
 #include "wire/Message.h"
 #include "util/Defined.h"
 
@@ -26,9 +27,9 @@ struct Iface;
  * @param thisInterface the interface which contains the sendMessage function pointer.
  * @param message the message
  */
-typedef struct Iface* (* Iface_Callback)(struct Message* message, struct Iface* thisInterface);
+typedef struct Error_s (* Iface_Callback)(struct Message* message, struct Iface* thisInterface);
 
-#define Iface_DEFUN __attribute__ ((warn_unused_result)) struct Iface*
+#define Iface_DEFUN __attribute__ ((warn_unused_result)) struct Error_s
 
 struct Iface
 {
@@ -52,51 +53,31 @@ struct Iface
  * assertion error, in order to forward the message which you received, you must use Iface_next()
  * and it must be a tail-call.
  */
-static inline void Iface_send(struct Iface* iface, struct Message* msg)
+static inline struct Error_s Iface_send(struct Iface* iface, struct Message* msg)
 {
-    do {
-        struct Iface* conn = iface->connectedIf;
+    struct Iface* conn = iface->connectedIf;
+
+    #ifdef PARANOIA
+        Assert_true(conn);
+        Assert_true(conn->send);
+        Assert_true(msg);
+        struct Message* currentMsg = conn->currentMsg;
+        msg->currentIface = conn;
+        conn->currentMsg = msg;
+    #endif
 
-        #ifdef PARANOIA
-            Assert_true(conn);
-            Assert_true(conn->send);
-            Assert_true(msg);
-            struct Message* currentMsg = conn->currentMsg;
-            msg->currentIface = conn;
-            conn->currentMsg = msg;
-        #endif
-
-        iface = conn->send(msg, conn);
-
-        #ifdef PARANOIA
-            msg->currentIface = NULL;
-            conn->currentMsg = currentMsg;
-        #endif
-
-        if (!Defined(Iface_OPTIMIZE)) {
-            Assert_true(!iface);
-        }
-    } while (iface);
+    struct Error_s ret = conn->send(msg, conn);
+
+    #ifdef PARANOIA
+        msg->currentIface = NULL;
+        conn->currentMsg = currentMsg;
+    #endif
+
+    return ret;
 }
 
 /**
  * Forward a message from inside of an Iface_Callback function.
- * This function must be a tail-call, you must return the value returned to you.
- * If you do anything between the call to this function and your return of it's return value,
- * the order in which that thing happens is undefined.
- *
- * Consider the following (bad) code:
- *     struct Iface* retVal = Iface_next(iface, msg);
- *     x++;
- *     return retVal;
- *
- * If Iface_OPTIMIZE is enabled, it becomes equivilant to:
- *     x++;
- *     struct Iface* retVal = Iface_next(iface, msg);
- *     return retVal;
- *
- * So simplify your life and follow the basic rule of always returning directly the value
- * from this function, IE: return Iface_next(iface, msg);
  */
 static inline Iface_DEFUN Iface_next(struct Iface* iface, struct Message* msg)
 {
@@ -108,27 +89,19 @@ static inline Iface_DEFUN Iface_next(struct Iface* iface, struct Message* msg)
         msg->currentIface->currentMsg = NULL;
     #endif
 
-    if (Defined(Iface_OPTIMIZE)) {
-        #ifdef PARANOIA
-            msg->currentIface = conn;
-            conn->currentMsg = msg;
-        #endif
-        return iface;
-    }
-
     #ifdef PARANOIA
         // done inside of Iface_send()
         msg->currentIface = NULL;
         conn->currentMsg = NULL;
     #endif
 
-    Iface_send(iface, msg);
+    struct Error_s ret = Iface_send(iface, msg);
 
     #ifdef PARANOIA
         conn->currentMsg = currentMsg;
     #endif
 
-    return NULL;
+    return ret;
 }
 
 /**
@@ -146,22 +119,17 @@ static inline Iface_DEFUN Iface_next(struct Iface* iface, struct Message* msg)
  */
 #ifdef PARANOIA
     #define Iface_CALL(func, msg, ...) \
-        do {                                                \
+        (__extension__ ({                                    \
             Assert_true(!msg->currentIface);                \
             struct Iface Iface_y = { .currentMsg = msg };   \
             msg->currentIface = &Iface_y;                   \
-            struct Iface* Iface_x = func(msg, __VA_ARGS__); \
+            struct Error_s ret = func(msg, __VA_ARGS__); \
             msg->currentIface = NULL;                       \
-            if (Iface_x) { Iface_send(Iface_x, msg); }      \
-        } while (0)
+            ret; \
+        }))
     // CHECKFILES_IGNORE missing ;
 #else
-    #define Iface_CALL(func, msg, ...) \
-        do {                                                 \
-            struct Iface* Iface_x = func(msg, __VA_ARGS__);  \
-            if (Iface_x) { Iface_send(Iface_x, msg); }       \
-        } while (0)
-    // CHECKFILES_IGNORE missing ;
+    #define Iface_CALL(func, msg, ...) func(msg, __VA_ARGS__)
 #endif
 
 static inline void Iface_plumb(struct Iface* a, struct Iface* b)

+ 7 - 7
interface/UDPInterface.c

@@ -124,7 +124,7 @@ static Iface_DEFUN sendPacket(struct Message* m, struct Iface* iface)
     if (!(sa->flags & Sockaddr_flags_BCAST)) { return Iface_next(&ctx->commSock, m); }
 
     if (updateBcastAddrs(ctx)) {
-        return NULL;
+        return Error(INTERNAL);
     }
 
     // bcast
@@ -146,7 +146,7 @@ static Iface_DEFUN sendPacket(struct Message* m, struct Iface* iface)
         Allocator_free(tmpAlloc);
     }
 
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN fromCommSock(struct Message* m, struct Iface* iface)
@@ -163,14 +163,14 @@ static Iface_DEFUN fromBcastSock(struct Message* m, struct Iface* iface)
 
     if (m->length < UDPInterface_BroadcastHeader_SIZE + Sockaddr_OVERHEAD) {
         Log_debug(ctx->log, "DROP runt bcast");
-        return NULL;
+        return Error(RUNT);
     }
 
     struct Sockaddr_storage ss;
     Er_assert(Message_epop(m, &ss, Sockaddr_OVERHEAD));
     if (m->length < UDPInterface_BroadcastHeader_SIZE + ss.addr.addrLen - Sockaddr_OVERHEAD) {
         Log_debug(ctx->log, "DROP runt bcast");
-        return NULL;
+        return Error(RUNT);
     }
     Er_assert(Message_epop(m, &ss.nativeAddr, ss.addr.addrLen - Sockaddr_OVERHEAD));
 
@@ -180,17 +180,17 @@ static Iface_DEFUN fromBcastSock(struct Message* m, struct Iface* iface)
     if (hdr.fffffffc_be != Endian_hostToBigEndian32(0xfffffffc)) {
         Log_debug(ctx->log, "DROP bcast bad magic, expected 0xfffffffc got [%08x]",
             Endian_bigEndianToHost32(hdr.fffffffc_be));
-        return NULL;
+        return Error(INVALID);
     }
 
     if (hdr.version != UDPInterface_CURRENT_VERSION) {
         Log_debug(ctx->log, "DROP bcast bad version [%u]", hdr.version);
-        return NULL;
+        return Error(INVALID);
     }
 
     if (hdr.zero) {
         Log_debug(ctx->log, "DROP bcast malformed (zero not zero)");
-        return NULL;
+        return Error(INVALID);
     }
 
     uint16_t commPort = Endian_bigEndianToHost16(hdr.commPort_be);

+ 2 - 2
interface/addressable/AddrIfaceMuxer.c

@@ -61,7 +61,7 @@ static Iface_DEFUN incomingFromAddrIf(struct Message* msg, struct Iface* addrIf)
     int idx = Map_Ifaces_indexForHandle(handle, &ctx->ifaces);
     if (idx < 0) {
         Log_info(ctx->log, "DROP message to nonexistant iface [0x%x]", handle);
-        return NULL;
+        return Error(UNHANDLED);
     }
     return Iface_next(&ctx->ifaces.values[idx]->iface, msg);
 }
@@ -73,7 +73,7 @@ static Iface_DEFUN incomingFromInputIf(struct Message* msg, struct Iface* inputI
     struct AddrIfaceMuxer_pvt* ctx = Identity_check(cli->muxer);
     if (msg->length < (int)sizeof(struct Sockaddr)) {
         Log_info(ctx->log, "DROP runt");
-        return NULL;
+        return Error(RUNT);
     }
 
     uint16_t addrLen = Bits_get16(msg->bytes);

+ 3 - 3
interface/addressable/PacketHeaderToUDPAddrIface.c

@@ -72,14 +72,14 @@ static Iface_DEFUN incomingFromHeaderIf(struct Message* message, struct Iface* i
 
     if (message->length < Headers_IP6Header_SIZE + Headers_UDPHeader_SIZE) {
         // runt
-        return NULL;
+        return Error(RUNT);
     }
 
     struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes;
 
     // udp
     if (ip->nextHeader != 17) {
-        return NULL;
+        return Error(INVALID);
     }
 
     struct Allocator* alloc = Allocator_child(message->alloc);
@@ -93,7 +93,7 @@ static Iface_DEFUN incomingFromHeaderIf(struct Message* message, struct Iface* i
 
     if (Sockaddr_getPort(context->pub.udpIf.addr) != Endian_bigEndianToHost16(udp->destPort_be)) {
         // not the right port
-        return NULL;
+        return Error(INVALID);
     }
 
     Er_assert(Message_eshift(message, -(Headers_IP6Header_SIZE + Headers_UDPHeader_SIZE)));

+ 1 - 1
interface/test/FramingIface_fuzz_test.c

@@ -40,7 +40,7 @@ static Iface_DEFUN ifaceRecvMsg(struct Message* message, struct Iface* thisInter
     Assert_true(ctx->buf->length == 0);
     Assert_true(!Bits_memcmp(ctx->bufPtr, message->bytes, ctx->messageLen));
     ctx->success = 1;
-    return NULL;
+    return Error(NONE);
 }
 
 void CJDNS_FUZZ_MAIN(void* vctx, struct Message* fuzz)

+ 3 - 3
interface/tuntap/AndroidWrapper.c

@@ -43,7 +43,7 @@ static Iface_DEFUN incomingFromWire(struct Message* msg, struct Iface* externalI
 
     if (!ctx->pub.internalIf.connectedIf) {
         Log_debug(ctx->logger, "DROP message for android tun not inited");
-        return NULL;
+        return Error(UNHANDLED);
     }
 
     int version = Headers_getIpVersion(msg->bytes);
@@ -54,7 +54,7 @@ static Iface_DEFUN incomingFromWire(struct Message* msg, struct Iface* externalI
         ethertype = Ethernet_TYPE_IP6;
     } else {
         Log_debug(ctx->logger, "Message is not IP/IPv6, dropped.");
-        return NULL;
+        return Error(INVALID);
     }
 
     Er_assert(Message_eshift(msg, 4));
@@ -71,7 +71,7 @@ static Iface_DEFUN incomingFromUs(struct Message* msg, struct Iface* internalIf)
 
     if (!ctx->pub.externalIf.connectedIf) {
         Log_debug(ctx->logger, "DROP message for android tun not inited");
-        return NULL;
+        return Error(UNHANDLED);
     }
 
     Er_assert(Message_eshift(msg, -4));

+ 2 - 2
interface/tuntap/BSDMessageTypeWrapper.c

@@ -42,7 +42,7 @@ static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* wireSide)
     struct BSDMessageTypeWrapper_pvt* ctx =
         Identity_containerOf(wireSide, struct BSDMessageTypeWrapper_pvt, pub.wireSide);
 
-    if (msg->length < 4) { return NULL; }
+    if (msg->length < 4) { return Error(RUNT); }
 
     uint16_t afType_be = ((uint16_t*) msg->bytes)[1];
     uint16_t ethertype = 0;
@@ -53,7 +53,7 @@ static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* wireSide)
     } else {
         Log_debug(ctx->logger, "Message of unhandled aftype [0x%04x]",
                   Endian_bigEndianToHost16(afType_be));
-        return NULL;
+        return Error(INVALID);
     }
     ((uint16_t*) msg->bytes)[0] = 0;
     ((uint16_t*) msg->bytes)[1] = ethertype;

+ 3 - 3
interface/tuntap/SocketWrapper.c

@@ -37,7 +37,7 @@ static Iface_DEFUN incomingFromSocket(struct Message* msg, struct Iface* externa
 
     if (!ctx->pub.internalIf.connectedIf) {
         Log_debug(ctx->logger, "DROP message for socket not inited");
-        return NULL;
+        return Error(INVALID);
     }
 
     // get ess packet type
@@ -51,7 +51,7 @@ static Iface_DEFUN incomingFromSocket(struct Message* msg, struct Iface* externa
     }
 
     // skip all other types
-    return NULL;
+    return Error(INVALID);
 }
 
 static Iface_DEFUN incomingFromUs(struct Message* msg, struct Iface* internalIf)
@@ -61,7 +61,7 @@ static Iface_DEFUN incomingFromUs(struct Message* msg, struct Iface* internalIf)
 
     if (!ctx->pub.externalIf.connectedIf) {
         Log_debug(ctx->logger, "DROP message for socket not inited");
-        return NULL;
+        return Error(INVALID);
     }
 
     // send payload length

+ 3 - 3
interface/tuntap/TAPWrapper.c

@@ -36,7 +36,7 @@ static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* external)
 
     if (msg->length < Ethernet_SIZE-2) {
         Log_debug(tw->log, "runt");
-        return 0;
+        return Error(RUNT);
     }
 
     // wacky 14 byte headers, back off into outer-space to create the padding...
@@ -66,7 +66,7 @@ static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* external)
                 AddrTools_printMac(printedMac, eth.srcAddr);
                 Log_debug(tw->log, "DROP Packet with unexpected source MAC [%s]", printedMac);
             #endif
-            return 0;
+            return Error(INVALID);
         }
     }
     Er_assert(TUNMessageType_push(msg, eth.ethertype));
@@ -83,7 +83,7 @@ static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* internal)
     Bits_memcpy(eth.destAddr, tw->pub.peerAddress, Ethernet_ADDRLEN);
     if (Bits_isZero(tw->pub.peerAddress, Ethernet_ADDRLEN)) {
         Log_debug(tw->log, "DROP Packet because peers MAC is not yet known");
-        return NULL;
+        return Error(INVALID);
     }
 
     Er_assert(Message_epush(msg, &eth, sizeof(struct Ethernet)));

+ 1 - 1
interface/tuntap/test/BSDMessageTypeWrapper_test.c

@@ -34,7 +34,7 @@ static Iface_DEFUN sendInside(struct Message* msg, struct Iface* inside)
     Assert_true(top == 0x00000800);
     Assert_true(!(ctx->received & 1));
     ctx->received |= 1;
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN sendOutside(struct Message* msg, struct Iface* outside)

+ 1 - 1
interface/tuntap/test/TUNInterface_ipv4_root_test.c

@@ -36,7 +36,7 @@ static Iface_DEFUN receiveMessageTUN(struct Message* msg, struct TUNTools* tt)
     if (ethertype != Ethernet_TYPE_IP4) {
         Log_debug(tt->log, "Spurious packet with ethertype [%u]\n",
                   Endian_bigEndianToHost16(ethertype));
-        return 0;
+        return Error(INVALID);
     }
 
     struct Headers_IP4Header* header = (struct Headers_IP4Header*) msg->bytes;

+ 3 - 3
interface/tuntap/test/TUNTools.c

@@ -83,7 +83,7 @@ Iface_DEFUN TUNTools_genericIP6Echo(struct Message* msg, struct TUNTools* tt)
     if (ethertype != Ethernet_TYPE_IP6) {
         Log_debug(tt->log, "Spurious packet with ethertype [%04x]\n",
                   Endian_bigEndianToHost16(ethertype));
-        return 0;
+        return Error(INVALID);
     }
 
     struct Headers_IP6Header* header = (struct Headers_IP6Header*) msg->bytes;
@@ -92,7 +92,7 @@ Iface_DEFUN TUNTools_genericIP6Echo(struct Message* msg, struct TUNTools* tt)
         int type = (msg->length >= Headers_IP6Header_SIZE) ? header->nextHeader : -1;
         Log_debug(tt->log, "Message of unexpected length [%u] ip6->nextHeader: [%d]\n",
                   msg->length, type);
-        return 0;
+        return Error(INVALID);
     }
     uint8_t* address;
     Sockaddr_getAddress(tt->tunDestAddr, &address);
@@ -127,7 +127,7 @@ static Iface_DEFUN receiveMessageUDP(struct Message* msg, struct Iface* udpIface
         EventBase_endLoop(ctx->pub.base);
     }
 
-    return NULL;
+    return Error(NONE);
 }
 
 static void fail(void* ignored)

+ 2 - 2
interface/tuntap/windows/TAPInterface.c

@@ -229,7 +229,7 @@ static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* iface)
     struct TAPInterface_pvt* tap = Identity_check((struct TAPInterface_pvt*) iface);
     if (tap->writeMessageCount >= WRITE_MESSAGE_SLOTS) {
         Log_info(tap->log, "DROP message because the tap is lagging");
-        return 0;
+        return Error(OVERFLOW);
     }
     if (!tap->pendingWritesAlloc) {
         tap->pendingWritesAlloc = Allocator_child(tap->alloc);
@@ -239,7 +239,7 @@ static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* iface)
     if (tap->writeMessageCount == 1) {
         postWrite(tap);
     }
-    return 0;
+    return Error(NONE);
 }
 
 Er_DEFUN(struct TAPInterface* TAPInterface_new(const char* preferredName,

+ 1 - 1
net/Benchmark.c

@@ -134,7 +134,7 @@ static Iface_DEFUN aliceCtrlRecv(struct Message* msg, struct Iface* aliceCtrlIf)
         Identity_containerOf(aliceCtrlIf, struct SwitchingContext, aliceCtrlIf);
     //Log_debug(sc->benchmarkCtx->log, "pong!");
     sc->msgCount++;
-    return NULL;
+    return Error(NONE);
 }
 
 static void switching(struct Context* ctx)

+ 19 - 18
net/ControlHandler.c

@@ -45,7 +45,7 @@ static Iface_DEFUN handleError(struct Message* msg,
 {
     if (msg->length < handleError_MIN_SIZE) {
         Log_info(ch->log, "DROP runt error packet from [%s]", labelStr);
-        return NULL;
+        return Error(RUNT);
     }
     msg->length = handleError_MIN_SIZE;
     Er_assert(Message_epush(msg, &rh->sh, SwitchHeader_SIZE));
@@ -66,7 +66,7 @@ static Iface_DEFUN handlePing(struct Message* msg,
 {
     if (msg->length < handlePing_MIN_SIZE) {
         Log_info(ch->log, "DROP runt ping");
-        return NULL;
+        return Error(RUNT);
     }
 
     struct Control* ctrl = (struct Control*) msg->bytes;
@@ -77,7 +77,7 @@ static Iface_DEFUN handlePing(struct Message* msg,
     uint32_t herVersion = Endian_bigEndianToHost32(ping->version_be);
     if (!Version_isCompatible(Version_CURRENT_PROTOCOL, herVersion)) {
         Log_debug(ch->log, "DROP ping from incompatible version [%d]", herVersion);
-        return NULL;
+        return Error(INVALID);
     }
 
     if (messageType_be == Control_KEYPING_be) {
@@ -85,15 +85,15 @@ static Iface_DEFUN handlePing(struct Message* msg,
         if (msg->length < Control_KeyPing_HEADER_SIZE) {
             // min keyPing size is longer
             Log_debug(ch->log, "DROP runt keyPing");
-            return NULL;
+            return Error(RUNT);
         }
         if (msg->length > Control_KeyPing_MAX_SIZE) {
             Log_debug(ch->log, "DROP long keyPing");
-            return NULL;
+            return Error(INVALID);
         }
         if (ping->magic != Control_KeyPing_MAGIC) {
             Log_debug(ch->log, "DROP keyPing (bad magic)");
-            return NULL;
+            return Error(INVALID);
         }
 
         struct Control_KeyPing* keyPing = (struct Control_KeyPing*) msg->bytes;
@@ -106,7 +106,7 @@ static Iface_DEFUN handlePing(struct Message* msg,
         //Log_debug(ch->log, "got switch ping from [%s]", labelStr);
         if (ping->magic != Control_Ping_MAGIC) {
             Log_debug(ch->log, "DROP ping (bad magic)");
-            return NULL;
+            return Error(INVALID);
         }
         ping->magic = Control_Pong_MAGIC;
         ctrl->header.type_be = Control_PONG_be;
@@ -145,7 +145,7 @@ static Iface_DEFUN handleRPathQuery(struct Message* msg,
     Log_debug(ch->log, "Incoming RPATH query");
     if (msg->length < handleRPathQuery_MIN_SIZE) {
         Log_info(ch->log, "DROP runt RPATH query");
-        return NULL;
+        return Error(RUNT);
     }
 
     struct Control* ctrl = (struct Control*) msg->bytes;
@@ -153,7 +153,7 @@ static Iface_DEFUN handleRPathQuery(struct Message* msg,
 
     if (rpa->magic != Control_RPATH_QUERY_MAGIC) {
         Log_debug(ch->log, "DROP RPATH query (bad magic)");
-        return NULL;
+        return Error(INVALID);
     }
 
     ctrl->header.type_be = Control_RPATH_REPLY_be;
@@ -186,7 +186,7 @@ static Iface_DEFUN handleGetSnodeQuery(struct Message* msg,
     Log_debug(ch->log, "incoming getSupernode query");
     if (msg->length < handleGetSnodeQuery_MIN_SIZE) {
         Log_info(ch->log, "DROP runt getSupernode query");
-        return NULL;
+        return Error(RUNT);
     }
 
     struct Control* ctrl = (struct Control*) msg->bytes;
@@ -194,13 +194,14 @@ static Iface_DEFUN handleGetSnodeQuery(struct Message* msg,
 
     if (snq->magic != Control_GETSNODE_QUERY_MAGIC) {
         Log_debug(ch->log, "DROP getSupernode query (bad magic)");
-        return NULL;
+        return Error(INVALID);
     }
 
     uint32_t herVersion = Endian_bigEndianToHost32(snq->version_be);
     if (!Version_isCompatible(Version_CURRENT_PROTOCOL, herVersion)) {
         Log_debug(ch->log, "DROP getSupernode query from incompatible version [%d]", herVersion);
-        return NULL;
+        // Nothing wrong with the query but we're just not going to answer it
+        return Error(NONE);
     }
 
     ctrl->header.type_be = Control_GETSNODE_REPLY_be;
@@ -262,14 +263,14 @@ static Iface_DEFUN incomingFromCore(struct Message* msg, struct Iface* coreIf)
 
     if (msg->length < 4 + Control_Header_SIZE) {
         Log_info(ch->log, "DROP runt ctrl packet from [%s]", labelStr);
-        return NULL;
+        return Error(RUNT);
     }
 
     Assert_true(routeHdr.flags & RouteHeader_flags_CTRLMSG);
 
     if (Checksum_engine_be(msg->bytes, msg->length)) {
         Log_info(ch->log, "DROP ctrl packet from [%s] with invalid checksum", labelStr);
-        return NULL;
+        return Error(INVALID);
     }
 
     struct Control* ctrl = (struct Control*) msg->bytes;
@@ -310,7 +311,7 @@ static Iface_DEFUN incomingFromCore(struct Message* msg, struct Iface* coreIf)
     Log_info(ch->log, "DROP control packet of unknown type from [%s], type [%d]",
              labelStr, Endian_bigEndianToHost16(ctrl->header.type_be));
 
-    return NULL;
+    return Error(INVALID);
 }
 
 // Forward from switch pinger directly to core.
@@ -342,7 +343,7 @@ static Iface_DEFUN changeSnode(struct Message* msg, struct Iface* eventIf)
             log = "Found snode";
         } else {
             // didn't know the snode before, still don't
-            return NULL;
+            return Error(NONE);
         }
     } else if (!node.path_be) {
         // We had one, now we don't
@@ -356,7 +357,7 @@ static Iface_DEFUN changeSnode(struct Message* msg, struct Iface* eventIf)
             log = "Changing snode protocolVersion";
         } else {
             // Nothing has changed
-            return NULL;
+            return Error(NONE);
         }
     }
 
@@ -377,7 +378,7 @@ static Iface_DEFUN changeSnode(struct Message* msg, struct Iface* eventIf)
         Address_toStringKey(&old, msg->alloc)->bytes,
         Address_toStringKey(&addr, msg->alloc)->bytes);
 
-    return NULL;
+    return Error(NONE);
 }
 
 struct ControlHandler* ControlHandler_new(struct Allocator* allocator,

+ 10 - 10
net/EventEmitter.c

@@ -85,7 +85,7 @@ static struct ArrayList_Ifaces* getHandlers(struct EventEmitter_pvt* ee,
 
 static Iface_DEFUN sendToPathfinder(struct Message* msg, struct Pathfinder* pf)
 {
-    if (!pf || pf->state != Pathfinder_state_CONNECTED) { return NULL; }
+    if (!pf || pf->state != Pathfinder_state_CONNECTED) { return Error(NONE); }
     if (pf->bytesSinceLastPing < 8192 && pf->bytesSinceLastPing + msg->length >= 8192) {
         struct Message* ping = Message_new(0, 512, msg->alloc);
         Er_assert(Message_epush32be(ping, pf->bytesSinceLastPing));
@@ -192,7 +192,7 @@ static Iface_DEFUN incomingFromCore(struct Message* msg, struct Iface* trickIf)
             Iface_CALL(sendToPathfinder, messageClone, pf);
         }
     }
-    return NULL;
+    return Error(NONE);
 }
 
 static struct Message* pathfinderMsg(enum PFChan_Core ev,
@@ -283,34 +283,34 @@ static Iface_DEFUN incomingFromPathfinder(struct Message* msg, struct Iface* ifa
     struct EventEmitter_pvt* ee = Identity_check((struct EventEmitter_pvt*) pf->ee);
     if (msg->length < 4) {
         Log_debug(ee->log, "DROPPF runt");
-        return NULL;
+        return Error(RUNT);
     }
     enum PFChan_Pathfinder ev = Er_assert(Message_epop32be(msg));
     Er_assert(Message_epush32be(msg, pf->pathfinderId));
     Er_assert(Message_epush32be(msg, ev));
     if (ev <= PFChan_Pathfinder__TOO_LOW || ev >= PFChan_Pathfinder__TOO_HIGH) {
         Log_debug(ee->log, "DROPPF invalid type [%d]", ev);
-        return NULL;
+        return Error(INVALID);
     }
     if (!PFChan_Pathfinder_sizeOk(ev, msg->length)) {
         Log_debug(ee->log, "DROPPF incorrect length[%d] for type [%d]", msg->length, ev);
-        return NULL;
+        return Error(INVALID);
     }
 
     if (pf->state == Pathfinder_state_DISCONNECTED) {
         if (ev != PFChan_Pathfinder_CONNECT) {
             Log_debug(ee->log, "DROPPF disconnected and event != CONNECT event:[%d]", ev);
-            return NULL;
+            return Error(INVALID);
         }
     } else if (pf->state != Pathfinder_state_CONNECTED) {
         Log_debug(ee->log, "DROPPF error state");
-        return NULL;
+        return Error(INVALID);
     }
 
-    if (handleFromPathfinder(ev, msg, ee, pf)) { return NULL; }
+    if (handleFromPathfinder(ev, msg, ee, pf)) { return Error(NONE); }
 
     struct ArrayList_Ifaces* handlers = getHandlers(ee, ev, false);
-    if (!handlers) { return NULL; }
+    if (!handlers) { return Error(NONE); }
     for (int i = 0; i < handlers->length; i++) {
         struct Message* messageClone = Message_clone(msg, msg->alloc);
         struct Iface* iface = ArrayList_Ifaces_get(handlers, i);
@@ -320,7 +320,7 @@ static Iface_DEFUN incomingFromPathfinder(struct Message* msg, struct Iface* ifa
         Assert_true(iface->send);
         Iface_CALL(iface->send, messageClone, iface);
     }
-    return NULL;
+    return Error(NONE);
 }
 
 void EventEmitter_regCore(struct EventEmitter* eventEmitter,

+ 21 - 21
net/InterfaceController.c

@@ -507,7 +507,7 @@ static Iface_DEFUN receivedPostCryptoAuth(struct Message* msg,
             // directs it to *this* router.
             if (msg->length < 8 || msg->bytes[7] != 1) {
                 Log_info(ic->logger, "DROP message because CA is not established.");
-                return 0;
+                return Error(UNHANDLED);
             } else {
                 // When a "server" gets a new connection from a "client" the router doesn't
                 // know about that client so if the client sends a packet to the server, the
@@ -553,7 +553,7 @@ static Iface_DEFUN sendFromSwitch(struct Message* msg, struct Iface* switchIf)
             Log_debug(ep->ici->ic->logger, "[%s] DROP msg to node with incompat version [%d] ",
                 Address_toString(&ep->addr, msg->alloc)->bytes, ep->addr.protocolVersion);
         }
-        return NULL;
+        return Error(UNHANDLED);
     }
 
     ep->bytesOut += msg->length;
@@ -578,7 +578,7 @@ static Iface_DEFUN sendFromSwitch(struct Message* msg, struct Iface* switchIf)
 
         Iface_send(&ep->ici->pub.addrIf, msg);
     }
-    return NULL;
+    return Error(NONE);
 }
 
 static int closeInterface(struct Allocator_OnFreeJob* job)
@@ -606,19 +606,19 @@ static Iface_DEFUN handleBeacon(struct Message* msg, struct InterfaceController_
         // accepting beacons disabled.
         Log_debug(ic->logger, "[%s] Dropping beacon because beaconing is disabled",
                   ici->pub.name->bytes);
-        return NULL;
+        return Error(NONE);
     }
 
     if (msg->length < Sockaddr_OVERHEAD) {
         Log_debug(ic->logger, "[%s] Dropping runt beacon", ici->pub.name->bytes);
-        return NULL;
+        return Error(RUNT);
     }
 
     struct Sockaddr* lladdrInmsg = (struct Sockaddr*) msg->bytes;
 
     if (msg->length < lladdrInmsg->addrLen + Headers_Beacon_SIZE) {
         Log_debug(ic->logger, "[%s] Dropping runt beacon", ici->pub.name->bytes);
-        return NULL;
+        return Error(RUNT);
     }
 
     // clear the bcast flag
@@ -647,10 +647,10 @@ static Iface_DEFUN handleBeacon(struct Message* msg, struct InterfaceController_
 
     if (!AddressCalc_validAddress(addr.ip6.bytes)) {
         Log_debug(ic->logger, "handleBeacon invalid key [%s]", printedAddr->bytes);
-        return NULL;
+        return Error(INVALID);
     } else if (!Bits_memcmp(ic->ca->publicKey, addr.key, 32)) {
         // receive beacon from self, drop silent
-        return NULL;
+        return Error(NONE);
     }
 
     if (!Version_isCompatible(addr.protocolVersion, Version_CURRENT_PROTOCOL)) {
@@ -659,14 +659,14 @@ static Iface_DEFUN handleBeacon(struct Message* msg, struct InterfaceController_
                       "our version is [%d] making them incompatable", ici->pub.name->bytes,
                       printedAddr->bytes, addr.protocolVersion, Version_CURRENT_PROTOCOL);
         }
-        return NULL;
+        return Error(UNHANDLED);
     } else if (Defined(SUBNODE) && addr.protocolVersion < 21) {
         if (Defined(Log_DEBUG)) {
             Log_debug(ic->logger, "[%s] DROP beacon from [%s] which was version [%d] "
                       "which is incompatible with SUBNODE", ici->pub.name->bytes,
                       printedAddr->bytes, addr.protocolVersion);
         }
-        return NULL;
+        return Error(UNHANDLED);
     }
 
     String* beaconPass = String_newBinary(beacon.password, Headers_Beacon_PASSWORD_LEN, msg->alloc);
@@ -675,7 +675,7 @@ static Iface_DEFUN handleBeacon(struct Message* msg, struct InterfaceController_
         // The password might have changed!
         struct Peer* ep = ici->peerMap.values[epIndex];
         CryptoAuth_setAuth(beaconPass, NULL, ep->caSession);
-        return NULL;
+        return Error(NONE);
     }
 
     struct Allocator* epAlloc = Allocator_child(ici->alloc);
@@ -700,7 +700,7 @@ static Iface_DEFUN handleBeacon(struct Message* msg, struct InterfaceController_
     if (SwitchCore_addInterface(ic->switchCore, &ep->switchIf, epAlloc, &ep->addr.path)) {
         Log_debug(ic->logger, "handleBeacon() SwitchCore out of space");
         Allocator_free(epAlloc);
-        return NULL;
+        return Error(UNHANDLED);
     }
 
     // We want the node to immedietly be pinged but we don't want it to appear unresponsive because
@@ -713,7 +713,7 @@ static Iface_DEFUN handleBeacon(struct Message* msg, struct InterfaceController_
         Address_toString(&ep->addr, msg->alloc)->bytes);
 
     sendPeer(0xffffffff, PFChan_Core_PEER, ep, 0xffff);
-    return NULL;
+    return Error(NONE);
 }
 
 /**
@@ -728,7 +728,7 @@ static Iface_DEFUN handleUnexpectedIncoming(struct Message* msg,
     struct Sockaddr* lladdr = (struct Sockaddr*) msg->bytes;
     Er_assert(Message_eshift(msg, -lladdr->addrLen));
     if (msg->length < CryptoHeader_SIZE) {
-        return NULL;
+        return Error(RUNT);
     }
 
     Assert_true(!((uintptr_t)msg->bytes % 4) && "alignment fault");
@@ -737,7 +737,7 @@ static Iface_DEFUN handleUnexpectedIncoming(struct Message* msg,
     if (ch->nonce & Endian_bigEndianToHost32(~1)) {
         // This cuts down on processing and logger noise because any packet
         // which is not a setup packet will be summarily dropped.
-        return NULL;
+        return Error(INVALID);
     }
 
     struct Allocator* epAlloc = Allocator_child(ici->alloc);
@@ -755,7 +755,7 @@ static Iface_DEFUN handleUnexpectedIncoming(struct Message* msg,
         // If the first message is a dud, drop all state for this peer.
         // probably some random crap that wandered in the socket.
         Allocator_free(epAlloc);
-        return NULL;
+        return Error(AUTHENTICATION);
     }
     Assert_true(!Bits_isZero(ep->caSession->herPublicKey, 32));
     Assert_true(Map_EndpointsBySockaddr_indexForKey(&lladdr, &ici->peerMap) == -1);
@@ -770,7 +770,7 @@ static Iface_DEFUN handleUnexpectedIncoming(struct Message* msg,
     if (SwitchCore_addInterface(ic->switchCore, &ep->switchIf, epAlloc, &ep->addr.path)) {
         Log_debug(ic->logger, "handleUnexpectedIncoming() SwitchCore out of space");
         Allocator_free(epAlloc);
-        return NULL;
+        return Error(UNHANDLED);
     }
 
     // We want the node to immedietly be pinged but we don't want it to appear unresponsive because
@@ -795,7 +795,7 @@ static Iface_DEFUN handleIncomingFromWire(struct Message* msg, struct Iface* add
     struct Sockaddr* lladdr = (struct Sockaddr*) msg->bytes;
     if (msg->length < Sockaddr_OVERHEAD || msg->length < lladdr->addrLen) {
         Log_debug(ici->ic->logger, "DROP runt");
-        return NULL;
+        return Error(RUNT);
     }
 
     Assert_true(!((uintptr_t)msg->bytes % 4) && "alignment fault");
@@ -829,13 +829,13 @@ static Iface_DEFUN handleIncomingFromWire(struct Message* msg, struct Iface* add
             Log_debug(ici->ic->logger, "[%s] DROP msg from node with incompat version [%d] ",
                 Address_toString(&ep->addr, msg->alloc)->bytes, ep->addr.protocolVersion);
         }
-        return NULL;
+        return Error(NONE);
     }
 
     CryptoAuth_resetIfTimeout(ep->caSession);
     uint32_t nonce = Endian_bigEndianToHost32( ((uint32_t*)msg->bytes)[0] );
     if (CryptoAuth_decrypt(ep->caSession, msg)) {
-        return NULL;
+        return Error(AUTHENTICATION);
     }
 
     if (ici->ic->pub.timestampPackets) {
@@ -1168,7 +1168,7 @@ static Iface_DEFUN incomingFromEventEmitterIf(struct Message* msg, struct Iface*
             sendPeer(pathfinderId, PFChan_Core_PEER, peer, 0xffff);
         }
     }
-    return NULL;
+    return Error(NONE);
 }
 
 struct InterfaceController* InterfaceController_new(struct CryptoAuth* ca,

+ 17 - 17
net/SessionManager.c

@@ -389,7 +389,7 @@ static Iface_DEFUN incomingFromSwitchIf(struct Message* msg, struct Iface* iface
     // SwitchHeader, handle, 0 or more bytes of control frame
     if (msg->length < SwitchHeader_SIZE + 4) {
         Log_debug(sm->log, "DROP runt");
-        return NULL;
+        return Error(RUNT);
     }
 
     struct SwitchHeader* switchHeader = (struct SwitchHeader*) msg->bytes;
@@ -410,7 +410,7 @@ static Iface_DEFUN incomingFromSwitchIf(struct Message* msg, struct Iface* iface
     // handle, small cryptoAuth header
     if (msg->length < 4 + 20) {
         Log_debug(sm->log, "DROP runt");
-        return NULL;
+        return Error(RUNT);
     }
 
     // This is for handling error situations and being able to send back some kind of a message.
@@ -424,32 +424,32 @@ static Iface_DEFUN incomingFromSwitchIf(struct Message* msg, struct Iface* iface
         session = sessionForHandle(nonceOrHandle, sm);
         if (!session) {
             Log_debug(sm->log, "DROP message with unrecognized handle [%u]", nonceOrHandle);
-            return NULL;
+            return Error(INVALID);
         }
         Er_assert(Message_eshift(msg, -4));
         uint32_t nonce = Endian_bigEndianToHost32(((uint32_t*)msg->bytes)[0]);
         if (nonce < 4) {
             Log_debug(sm->log, "DROP setup message [%u] with specified handle [%u]",
                 nonce, nonceOrHandle);
-            return NULL;
+            return Error(INVALID);
         }
     } else {
         // handle + big cryptoauth header
         if (msg->length < CryptoHeader_SIZE + 4) {
             Log_debug(sm->log, "DROP runt");
-            return NULL;
+            return Error(RUNT);
         }
         struct CryptoHeader* caHeader = (struct CryptoHeader*) msg->bytes;
         uint8_t ip6[16];
         // a packet which claims to be "from us" causes problems
         if (!AddressCalc_addressForPublicKey(ip6, caHeader->publicKey)) {
             Log_debug(sm->log, "DROP Handshake with non-fc key");
-            return NULL;
+            return Error(INVALID);
         }
 
         if (!Bits_memcmp(caHeader->publicKey, sm->cryptoAuth->publicKey, 32)) {
             Log_debug(sm->log, "DROP Handshake from 'ourselves'");
-            return NULL;
+            return Error(INVALID);
         }
 
         uint64_t label = Endian_bigEndianToHost64(switchHeader->label_be);
@@ -731,11 +731,11 @@ static Iface_DEFUN outgoingCtrlFrame(struct Message* msg, struct SessionManager_
     struct RouteHeader* header = (struct RouteHeader*) msg->bytes;
     if (!Bits_isZero(header->publicKey, 32) || !Bits_isZero(header->ip6, 16)) {
         Log_debug(sm->log, "DROP Ctrl frame with non-zero destination key or IP");
-        return NULL;
+        return Error(INVALID);
     }
     if (!(header->flags & RouteHeader_flags_CTRLMSG)) {
         Log_debug(sm->log, "DROP Ctrl frame w/o RouteHeader_flags_CTRLMSG flag");
-        return NULL;
+        return Error(INVALID);
     }
     struct SwitchHeader sh;
     Bits_memcpy(&sh, &header->sh, SwitchHeader_SIZE);
@@ -768,7 +768,7 @@ static Iface_DEFUN incomingFromInsideIf(struct Message* msg, struct Iface* iface
                               ((header->sh.label_be) ? Metric_SM_SEND : Metric_DEAD_LINK));
         } else {
             needsLookup(sm, msg);
-            return NULL;
+            return Error(NONE);
         }
     }
 
@@ -781,7 +781,7 @@ static Iface_DEFUN incomingFromInsideIf(struct Message* msg, struct Iface* iface
 
     if (!sess->pub.version) {
         needsLookup(sm, msg);
-        return NULL;
+        return Error(NONE);
     }
 
     if (header->sh.label_be) {
@@ -792,7 +792,7 @@ static Iface_DEFUN incomingFromInsideIf(struct Message* msg, struct Iface* iface
         SwitchHeader_setVersion(&header->sh, SwitchHeader_CURRENT_VERSION);
     } else {
         needsLookup(sm, msg);
-        return NULL;
+        return Error(NONE);
     }
 
     // Forward secrecy, only send dht messages until the session is setup.
@@ -809,7 +809,7 @@ static Iface_DEFUN incomingFromInsideIf(struct Message* msg, struct Iface* iface
                 Endian_bigEndianToHost64(header->sh.label_be), "user traffic, unsetupSession");
             bufferPacket(sm, msg);
             unsetupSession(sm, sess);
-            return NULL;
+            return Error(NONE);
         }
     }
 
@@ -824,7 +824,7 @@ static Iface_DEFUN sessions(struct SessionManager_pvt* sm,
         struct SessionManager_Session_pvt* sess = sm->ifaceMap.values[i];
         sendSession(sess, &sess->pub.paths[0], sourcePf, PFChan_Core_SESSION);
     }
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN incomingFromEventIf(struct Message* msg, struct Iface* iface)
@@ -845,9 +845,9 @@ static Iface_DEFUN incomingFromEventIf(struct Message* msg, struct Iface* iface)
     struct SessionManager_Session_pvt* sess = sessionForIp6(node.ip6, sm);
     if (!sess) {
         // Node we don't care about.
-        if (index == -1) { return NULL; }
+        if (index == -1) { return Error(NONE); }
         // Broken path to a node we don't have a session for...
-        if (node.metric_be == Metric_DEAD_LINK) { return NULL; }
+        if (node.metric_be == Metric_DEAD_LINK) { return Error(NONE); }
     }
     sess = getSession(sm,
                       node.ip6,
@@ -863,7 +863,7 @@ static Iface_DEFUN incomingFromEventIf(struct Message* msg, struct Iface* iface)
         Map_BufferedMessages_remove(index, &sm->bufMap);
         Allocator_free(bm->alloc);
     }
-    return NULL;
+    return Error(NONE);
 }
 
 struct SessionManager* SessionManager_new(struct Allocator* allocator,

+ 13 - 13
net/SwitchPinger.c

@@ -103,12 +103,12 @@ static Iface_DEFUN messageFromControlHandler(struct Message* msg, struct Iface*
             ctx->incomingVersion = Endian_bigEndianToHost32(pongHeader->version_be);
             if (pongHeader->magic != Control_Pong_MAGIC) {
                 Log_debug(ctx->logger, "dropped invalid switch pong");
-                return NULL;
+                return Error(INVALID);
             }
             Er_assert(Message_eshift(msg, -Control_Pong_HEADER_SIZE));
         } else {
             Log_debug(ctx->logger, "got runt pong message, length: [%d]", msg->length);
-            return NULL;
+            return Error(RUNT);
         }
 
     } else if (ctrl->header.type_be == Control_KEYPONG_be) {
@@ -119,16 +119,16 @@ static Iface_DEFUN messageFromControlHandler(struct Message* msg, struct Iface*
             ctx->incomingVersion = Endian_bigEndianToHost32(pongHeader->version_be);
             if (pongHeader->magic != Control_KeyPong_MAGIC) {
                 Log_debug(ctx->logger, "dropped invalid switch key-pong");
-                return NULL;
+                return Error(INVALID);
             }
             Bits_memcpy(ctx->incomingKey, pongHeader->key, 32);
             Er_assert(Message_eshift(msg, -Control_KeyPong_HEADER_SIZE));
         } else if (msg->length > Control_KeyPong_MAX_SIZE) {
             Log_debug(ctx->logger, "got overlong key-pong message, length: [%d]", msg->length);
-            return NULL;
+            return Error(INVALID);
         } else {
             Log_debug(ctx->logger, "got runt key-pong message, length: [%d]", msg->length);
-            return NULL;
+            return Error(RUNT);
         }
 
     } else if (ctrl->header.type_be == Control_GETSNODE_REPLY_be) {
@@ -136,20 +136,20 @@ static Iface_DEFUN messageFromControlHandler(struct Message* msg, struct Iface*
         ctx->error = Error_NONE;
         if (msg->length < Control_GetSnode_HEADER_SIZE) {
             Log_debug(ctx->logger, "got runt GetSnode message, length: [%d]", msg->length);
-            return NULL;
+            return Error(RUNT);
         }
         struct Control_GetSnode* hdr = (struct Control_GetSnode*) msg->bytes;
         if (hdr->magic != Control_GETSNODE_REPLY_MAGIC) {
             Log_debug(ctx->logger, "dropped invalid GetSnode");
-            return NULL;
+            return Error(INVALID);
         }
         if (Bits_isZero(hdr->snodeKey, 32)) {
             Log_debug(ctx->logger, "Peer doesn't have an snode");
-            return NULL;
+            return Error(NONE);
         }
         if (!AddressCalc_addressForPublicKey(ctx->incomingSnodeAddr.ip6.bytes, hdr->snodeKey)) {
             Log_debug(ctx->logger, "dropped invalid GetSnode key");
-            return NULL;
+            return Error(INVALID);
         }
         ctx->incomingVersion = Endian_hostToBigEndian32(hdr->version_be);
         Bits_memcpy(ctx->incomingSnodeAddr.key, hdr->snodeKey, 32);
@@ -165,12 +165,12 @@ static Iface_DEFUN messageFromControlHandler(struct Message* msg, struct Iface*
         ctx->error = Error_NONE;
         if (msg->length < Control_RPath_HEADER_SIZE) {
             Log_debug(ctx->logger, "got runt RPath message, length: [%d]", msg->length);
-            return NULL;
+            return Error(RUNT);
         }
         struct Control_RPath* hdr = (struct Control_RPath*) msg->bytes;
         if (hdr->magic != Control_RPATH_REPLY_MAGIC) {
             Log_debug(ctx->logger, "dropped invalid RPATH (bad magic)");
-            return NULL;
+            return Error(INVALID);
         }
         ctx->incomingVersion = Endian_hostToBigEndian32(hdr->version_be);
         uint64_t rpath_be;
@@ -183,7 +183,7 @@ static Iface_DEFUN messageFromControlHandler(struct Message* msg, struct Iface*
         Assert_true((uint8_t*)&ctrl->content.error.errorType_be == msg->bytes);
         if (msg->length < (Control_Error_HEADER_SIZE + SwitchHeader_SIZE + Control_Header_SIZE)) {
             Log_debug(ctx->logger, "runt error packet");
-            return NULL;
+            return Error(RUNT);
         }
 
         ctx->error = Er_assert(Message_epop32be(msg));
@@ -218,7 +218,7 @@ static Iface_DEFUN messageFromControlHandler(struct Message* msg, struct Iface*
     String* msgStr = &(String) { .bytes = (char*) msg->bytes, .len = msg->length };
     Pinger_pongReceived(msgStr, ctx->pinger);
     Bits_memset(ctx->incomingKey, 0, 32);
-    return NULL;
+    return Error(NONE);
 }
 
 static void onPingResponse(String* data, uint32_t milliseconds, void* vping)

+ 6 - 5
net/TUNAdapter.c

@@ -45,7 +45,7 @@ static Iface_DEFUN incomingFromTunIf(struct Message* msg, struct Iface* tunIf)
     {
         Log_debug(ud->log, "DROP packet because ip version [%d] "
                   "doesn't match ethertype [%u].", version, Endian_bigEndianToHost16(ethertype));
-        return NULL;
+        return Error(INVALID);
     }
 
     if (ethertype == Ethernet_TYPE_IP4) {
@@ -54,12 +54,12 @@ static Iface_DEFUN incomingFromTunIf(struct Message* msg, struct Iface* tunIf)
     if (ethertype != Ethernet_TYPE_IP6) {
         Log_debug(ud->log, "DROP packet unknown ethertype [%u]",
                   Endian_bigEndianToHost16(ethertype));
-        return NULL;
+        return Error(INVALID);
     }
 
     if (msg->length < Headers_IP6Header_SIZE) {
         Log_debug(ud->log, "DROP runt");
-        return NULL;
+        return Error(RUNT);
     }
 
     struct Headers_IP6Header* header = (struct Headers_IP6Header*) msg->bytes;
@@ -76,7 +76,7 @@ static Iface_DEFUN incomingFromTunIf(struct Message* msg, struct Iface* tunIf)
                       "DROP packet from [%s] because all messages must have source address [%s]",
                       packetSource, expectedSource);
         }
-        return NULL;
+        return Error(INVALID);
     }
     if (!Bits_memcmp(header->destinationAddr, ud->myIp6, 16)) {
         // I'm Gonna Sit Right Down and Write Myself a Letter
@@ -105,7 +105,8 @@ static Iface_DEFUN sendToTunIf(struct Message* msg, struct TUNAdapter_pvt* ud)
 {
     if (!ud->pub.tunIf.connectedIf) {
         Log_debug(ud->log, "DROP message for tun because no device is defined");
-        return NULL;
+        // Nothing inherently wrong with this message
+        return Error(NONE);
     }
     return Iface_next(&ud->pub.tunIf, msg);
 }

+ 20 - 6
net/UpperDistributor.c

@@ -62,11 +62,11 @@ static Iface_DEFUN fromHandler(struct Message* msg, struct UpperDistributor_pvt*
     enum ContentType type = DataHeader_getContentType(&dh);
     if (type != ContentType_IP6_UDP) {
         Log_debug(ud->log, "DROP Message from handler with invalid type [%d]", type);
-        return NULL;
+        return Error(INVALID);
     }
     if (msg->length < Headers_UDPHeader_SIZE + RouteHeader_SIZE + DataHeader_SIZE) {
         Log_debug(ud->log, "DROP runt");
-        return NULL;
+        return Error(RUNT);
     }
     uint8_t srcAndDest[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
     AddressCalc_makeValidAddress(&srcAndDest[16]);
@@ -74,18 +74,18 @@ static Iface_DEFUN fromHandler(struct Message* msg, struct UpperDistributor_pvt*
     struct Headers_UDPHeader* udp = (struct Headers_UDPHeader*) msg->bytes;
     if (Checksum_udpIp6_be(srcAndDest, msg->bytes, msg->length)) {
         Log_debug(ud->log, "DROP Bad checksum");
-        return NULL;
+        return Error(INVALID);
     }
     if (udp->destPort_be != Endian_bigEndianToHost16(MAGIC_PORT)) {
         Log_debug(ud->log, "DROP Message to unknown port [%d]",
             Endian_bigEndianToHost16(udp->destPort_be));
-        return NULL;
+        return Error(INVALID);
     }
     int udpPort = Endian_bigEndianToHost16(udp->srcPort_be);
     int index = Map_OfHandlers_indexForKey(&udpPort, ud->handlers);
     if (index < 0) {
         Log_debug(ud->log, "DROP Message from unregistered port [%d]", udpPort);
-        return NULL;
+        return Error(INVALID);
     }
     Er_assert(Message_epop(msg, NULL, Headers_UDPHeader_SIZE));
 
@@ -97,6 +97,20 @@ static Iface_DEFUN fromHandler(struct Message* msg, struct UpperDistributor_pvt*
         return incomingFromSessionManagerIf(msg, &ud->pub.sessionManagerIf);
     }
 
+    struct DataHeader* dataHeader = (struct DataHeader*) &hdr[1];
+    if (DataHeader_getContentType(dataHeader) == ContentType_CJDHT) {
+        if (Bits_isZero(hdr->publicKey, 32)) {
+            Log_debug(ud->log, "DROP message with no pubkey");
+            return Error(INVALID);
+        } else if (hdr->sh.label_be == 0) {
+            Log_debug(ud->log, "DROP message with no label");
+            return Error(INVALID);
+        } else if (hdr->version_be == 0) {
+            Log_debug(ud->log, "DROP message with no version");
+            return Error(INVALID);
+        }
+    }
+
     return Iface_next(&ud->pub.sessionManagerIf, msg);
 }
 
@@ -227,7 +241,7 @@ static Iface_DEFUN incomingFromSessionManagerIf(struct Message* msg, struct Ifac
         return Iface_next(&ud->pub.ipTunnelIf, msg);
     }
     Log_debug(ud->log, "DROP message with unknown type [%d]", type);
-    return NULL;
+    return Error(INVALID);
 }
 
 int UpperDistributor_unregisterHandler(struct UpperDistributor* upper, int udpPort)

+ 10 - 10
subnode/MsgCore.c

@@ -83,7 +83,7 @@ static Iface_DEFUN replyMsg(struct MsgCore_pvt* mcp,
     String* txid = Dict_getStringC(content, "txid");
     if (!txid) {
         Log_debug(mcp->log, "DROP Message with no txid");
-        return NULL;
+        return Error(INVALID);
     }
 
     struct ReplyContext* rc = Allocator_calloc(msg->alloc, sizeof(struct ReplyContext), 1);
@@ -96,7 +96,7 @@ static Iface_DEFUN replyMsg(struct MsgCore_pvt* mcp,
     // Pops out in pingerOnResponse() if the reply is indeed valid...
     Pinger_pongReceived(txid, mcp->pinger);
     mcp->currentReply = NULL;
-    return NULL;
+    return Error(NONE);
 }
 
 static void pingerOnResponse(String* data, uint32_t milliseconds, void* context)
@@ -241,9 +241,9 @@ static Iface_DEFUN queryMsg(struct MsgCore_pvt* mcp,
     } else if (!qh->pub.cb) {
         Log_info(mcp->log, "Query handler for [%s] not setup", q->bytes);
     } else {
-        qh->pub.cb(content, src, msg->alloc, &qh->pub);
+        return qh->pub.cb(content, src, msg->alloc, &qh->pub);
     }
-    return NULL;
+    return Error(INVALID);
 }
 
 static int qhOnFree(struct Allocator_OnFreeJob* job)
@@ -300,18 +300,18 @@ static Iface_DEFUN incoming(struct Message* msg, struct Iface* interRouterIf)
     if (!content) {
         char* esc = Escape_getEscaped(msgBytes, length, msg->alloc);
         Log_debug(mcp->log, "DROP Malformed message [%s]", esc);
-        return NULL;
+        return Error(INVALID);
     }
 
     int64_t* verP = Dict_getIntC(content, "p");
     if (!verP) {
         Log_debug(mcp->log, "DROP Message without version");
-        return NULL;
+        return Error(INVALID);
     }
     addr.protocolVersion = *verP;
     if (!addr.protocolVersion) {
         Log_debug(mcp->log, "DROP Message with zero version");
-        return NULL;
+        return Error(INVALID);
     }
 
     String* q = Dict_getStringC(content, "q");
@@ -319,7 +319,7 @@ static Iface_DEFUN incoming(struct Message* msg, struct Iface* interRouterIf)
     String* txid = Dict_getStringC(content, "txid");
     if (!txid || !txid->len) {
         Log_debug(mcp->log, "Message with no txid [%s]", q ? (q->bytes) : "(no query)");
-        return NULL;
+        return Error(INVALID);
     }
 
     if (q) {
@@ -327,14 +327,14 @@ static Iface_DEFUN incoming(struct Message* msg, struct Iface* interRouterIf)
             return queryMsg(mcp, content, &addr, msg);
         } else {
             // Let the old pathfinder handle every query if it is present
-            return NULL;
+            return Error(NONE);
         }
     } else if (txid->len >= 2 && txid->bytes[0] == '0' && txid->bytes[1] == '1') {
         txid->bytes = &txid->bytes[2];
         txid->len -= 2;
         return replyMsg(mcp, content, &addr, msg);
     }
-    return NULL;
+    return Error(INVALID);
 }
 
 struct MsgCore* MsgCore_new(struct EventBase* base,

+ 4 - 4
subnode/MsgCore.h

@@ -29,10 +29,10 @@ Linker_require("subnode/MsgCore.c")
 struct MsgCore_Handler;
 struct MsgCore;
 
-typedef void (* MsgCore_HandlerCb)(Dict* msg,
-                                   struct Address* src,
-                                   struct Allocator* tmpAlloc,
-                                   struct MsgCore_Handler* handler);
+typedef struct Error_s (* MsgCore_HandlerCb)(Dict* msg,
+                                             struct Address* src,
+                                             struct Allocator* tmpAlloc,
+                                             struct MsgCore_Handler* handler);
 
 struct MsgCore_Handler
 {

+ 7 - 6
subnode/PingResponder.c

@@ -29,10 +29,10 @@ struct PingResponder_pvt
     Identity
 };
 
-static void onPing(Dict* msg,
-                   struct Address* src,
-                   struct Allocator* tmpAlloc,
-                   struct MsgCore_Handler* handler)
+static struct Error_s onPing(Dict* msg,
+                             struct Address* src,
+                             struct Allocator* tmpAlloc,
+                             struct MsgCore_Handler* handler)
 {
     struct PingResponder_pvt* prp = Identity_check((struct PingResponder_pvt*) handler->userData);
     Log_debug(prp->log, "Received ping req from [%s]", Address_toString(src, tmpAlloc)->bytes);
@@ -40,7 +40,7 @@ static void onPing(Dict* msg,
     String* txid = Dict_getStringC(msg, "txid");
     if (!txid) {
         Log_debug(prp->log, "ping missing txid");
-        return;
+        return Error(INVALID);
     }
 
     Dict* responseDict = Dict_new(tmpAlloc);
@@ -59,13 +59,14 @@ static void onPing(Dict* msg,
             "respect do-not-disturb",
             Address_toString(src, tmpAlloc)->bytes,
             src->protocolVersion);
-        return;
+        return Error(UNHANDLED);
     }
 
     Dict_putStringC(responseDict, "txid", txid, tmpAlloc);
     Dict_putIntC(msg, "dnd", 1, tmpAlloc); // do not disturb
     BoilerplateResponder_addBoilerplate(prp->br, responseDict, src, tmpAlloc);
     MsgCore_sendResponse(prp->msgCore, responseDict, src, tmpAlloc);
+    return Error(NONE);
 }
 
 struct PingResponder* PingResponder_new(struct Allocator* allocator,

+ 10 - 10
subnode/SubnodePathfinder.c

@@ -118,7 +118,7 @@ static Iface_DEFUN connected(struct SubnodePathfinder_pvt* pf, struct Message* m
 {
     Log_debug(pf->log, "INIT");
     pf->state = SubnodePathfinder_pvt_state_RUNNING;
-    return NULL;
+    return Error(NONE);
 }
 
 static uint32_t addressForNode(struct Address* addrOut, struct Message* msg)
@@ -159,7 +159,7 @@ static Iface_DEFUN switchErr(struct Message* msg, struct SubnodePathfinder_pvt*
     // we only really have the ability to report a node with known IPv6 address
     // so we will need to add a new event type to PFChan.
 
-    return NULL;
+    return Error(NONE);
 }
 
 struct SnodeQuery {
@@ -243,7 +243,7 @@ static Iface_DEFUN searchReq(struct Message* msg, struct SubnodePathfinder_pvt*
     Er_assert(Message_epop(msg, addr, 16));
     Er_assert(Message_epop32be(msg));
     uint32_t version = Er_assert(Message_epop32be(msg));
-    if (version && version < 20) { return NULL; }
+    if (version && version < 20) { return Error(UNHANDLED); }
     Assert_true(!msg->length);
     uint8_t printedAddr[40];
     AddrTools_printIp(printedAddr, addr);
@@ -268,7 +268,7 @@ static Iface_DEFUN searchReq(struct Message* msg, struct SubnodePathfinder_pvt*
     }
 
     queryRs(pf, addr, printedAddr);
-    return NULL;
+    return Error(NONE);
 }
 
 static void rcChange(struct ReachabilityCollector* rc,
@@ -385,7 +385,7 @@ static Iface_DEFUN session(struct Message* msg, struct SubnodePathfinder_pvt* pf
     String* str = Address_toString(&addr, msg->alloc);
     Log_debug(pf->log, "Session [%s]", str->bytes);
     //if (addr.protocolVersion) { NodeCache_discoverNode(pf->nc, &addr); }
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN sessionEnded(struct Message* msg, struct SubnodePathfinder_pvt* pf)
@@ -395,7 +395,7 @@ static Iface_DEFUN sessionEnded(struct Message* msg, struct SubnodePathfinder_pv
     String* str = Address_toString(&addr, msg->alloc);
     Log_debug(pf->log, "Session ended [%s]", str->bytes);
     //NodeCache_forgetNode(pf->nc, &addr);
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN discoveredPath(struct Message* msg, struct SubnodePathfinder_pvt* pf)
@@ -404,7 +404,7 @@ static Iface_DEFUN discoveredPath(struct Message* msg, struct SubnodePathfinder_
     //addressForNode(&addr, msg);
     //Log_debug(pf->log, "discoveredPath(%s)", Address_toString(&addr, msg->alloc)->bytes);
     //if (addr.protocolVersion) { NodeCache_discoverNode(pf->nc, &addr); }
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN handlePing(struct Message* msg, struct SubnodePathfinder_pvt* pf)
@@ -417,7 +417,7 @@ static Iface_DEFUN handlePing(struct Message* msg, struct SubnodePathfinder_pvt*
 static Iface_DEFUN handlePong(struct Message* msg, struct SubnodePathfinder_pvt* pf)
 {
     //Log_debug(pf->log, "Received pong");
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN ctrlMsgFromSwitchPinger(struct Message* msg, struct Iface* iface)
@@ -445,7 +445,7 @@ static Iface_DEFUN unsetupSession(struct Message* msg, struct SubnodePathfinder_
     Bits_memcpy(addr.ip6.bytes, node.ip6, 16);
     Bits_memcpy(addr.key, node.publicKey, 32);
     pingNode(pf, &addr);
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN incomingMsg(struct Message* msg, struct SubnodePathfinder_pvt* pf)
@@ -465,7 +465,7 @@ static Iface_DEFUN linkState(struct Message* msg, struct SubnodePathfinder_pvt*
             lse.sumOfDrops,
             lse.sumOfKb);
     }
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN incomingFromMsgCore(struct Message* msg, struct Iface* iface)

+ 4 - 4
switch/SwitchCore.c

@@ -73,14 +73,14 @@ static inline Iface_DEFUN sendError(struct SwitchInterface* iface,
 {
     if (cause->length < SwitchHeader_SIZE + 4) {
         Log_debug(logger, "runt");
-        return NULL;
+        return Error(RUNT);
     }
 
     struct SwitchHeader* causeHeader = (struct SwitchHeader*) cause->bytes;
 
     if (SwitchHeader_getSuppressErrors(causeHeader)) {
         // don't send errors if they're asking us to suppress them!
-        return NULL;
+        return Error(NONE);
     }
 
     // limit of 256 bytes
@@ -121,7 +121,7 @@ static Iface_DEFUN receiveMessage(struct Message* message, struct Iface* iface)
 
     if (message->length < SwitchHeader_SIZE) {
         Log_debug(core->logger, "DROP runt");
-        return NULL;
+        return Error(RUNT);
     }
 
     struct SwitchHeader* header = (struct SwitchHeader*) message->bytes;
@@ -222,7 +222,7 @@ static Iface_DEFUN receiveMessage(struct Message* message, struct Iface* iface)
     if (labelShift > 63) {
         // TODO(cjd): hmm should we return an error packet?
         Log_debug(core->logger, "Label rolled over");
-        return NULL;
+        return Error(UNDELIVERABLE);
     }
     SwitchHeader_setLabelShift(header, labelShift);
     SwitchHeader_setTrafficClass(header, 0xffff);

+ 2 - 2
test/Beacon_test.c

@@ -76,7 +76,7 @@ static Iface_DEFUN incomingTunB(struct Message* msg, struct Iface* tunB)
     Er_assert(Message_eshift(msg, -Headers_IP6Header_SIZE));
     printf("Message from TUN in node B [%s]\n", msg->bytes);
     tn->messageFrom = TUNB;
-    return 0;
+    return Error(NONE);
 }
 
 static Iface_DEFUN incomingTunA(struct Message* msg, struct Iface* tunA)
@@ -89,7 +89,7 @@ static Iface_DEFUN incomingTunA(struct Message* msg, struct Iface* tunA)
     Hex_encode(buff, 1024, msg->bytes, msg->length);
     printf("Message from TUN in node A [%s] [%d] [%s]\n", msg->bytes, msg->length, buff);
     tn->messageFrom = TUNA;
-    return 0;
+    return Error(NONE);
 }
 
 static void notLinkedYet(struct TwoNodes* ctx)

+ 1 - 1
test/Main_fuzz_test.c

@@ -54,7 +54,7 @@ struct Context
 
 static Iface_DEFUN incomingTun(struct Message* msg, struct Iface* tunB)
 {
-    return 0;
+    return Error(NONE);
 }
 
 static void notLinkedYet(struct Context* ctx)

+ 1 - 2
test/TestFramework.c

@@ -80,8 +80,7 @@ static Iface_DEFUN sendTo(struct Message* msg,
     // Copy the original and send that to the other end.
     // Can't use Iface_next() when not sending the original msg.
     struct Message* sendMsg = Message_clone(msg, destTf->alloc);
-    Iface_send(dest, sendMsg);
-    return 0;
+    return Iface_send(dest, sendMsg);
 }
 
 static Iface_DEFUN sendClient(struct Message* msg, struct Iface* clientIf)

+ 23 - 21
tunnel/IpTunnel.c

@@ -361,7 +361,7 @@ static Iface_DEFUN requestForAddresses(Dict* request,
 
     if (conn->isOutgoing) {
         Log_warn(context->logger, "got request for addresses from outgoing connection");
-        return 0;
+        return Error(INVALID);
     }
     Dict* addresses = Dict_new(requestAlloc);
     bool noAddresses = true;
@@ -395,7 +395,8 @@ static Iface_DEFUN requestForAddresses(Dict* request,
     }
     if (noAddresses) {
         Log_warn(context->logger, "no addresses to provide");
-        return 0;
+        // The message is ok, this one is our fault
+        return Error(NONE);
     }
 
     Dict* msg = Dict_new(requestAlloc);
@@ -407,7 +408,7 @@ static Iface_DEFUN requestForAddresses(Dict* request,
     }
 
     sendControlMessage(msg, conn, requestAlloc, context);
-    return 0;
+    return Error(NONE);
 }
 
 static void addAddress(char* printedAddr, uint8_t prefixLen,
@@ -455,20 +456,20 @@ static Iface_DEFUN incomingAddresses(Dict* d,
 {
     if (!conn->isOutgoing) {
         Log_warn(context->logger, "got offer of addresses from incoming connection");
-        return 0;
+        return Error(INVALID);
     }
 
     String* txid = Dict_getStringC(d, "txid");
     if (!txid || txid->len != 4) {
         Log_info(context->logger, "missing or wrong length txid");
-        return 0;
+        return Error(INVALID);
     }
 
     int number;
     Bits_memcpy(&number, txid->bytes, 4);
     if (number < 0 || number >= (int)context->nextConnectionNumber) {
         Log_info(context->logger, "txid out of range");
-        return 0;
+        return Error(INVALID);
     }
 
     if (number != conn->number) {
@@ -479,7 +480,7 @@ static Iface_DEFUN incomingAddresses(Dict* d,
                                 32))
                 {
                     Log_info(context->logger, "txid doesn't match origin");
-                    return 0;
+                    return Error(INVALID);
                 } else {
                     conn = &context->pub.connectionList.connections[i];
                 }
@@ -556,16 +557,16 @@ static Iface_DEFUN incomingAddresses(Dict* d,
         String* tunName = GlobalConfig_getTunName(context->globalConf);
         if (!tunName) {
             Log_error(context->logger, "Failed to set routes because TUN interface is not setup");
-            return 0;
+            return Error(INVALID);
         }
         struct Er_Ret* er = NULL;
         Er_check(&er, RouteGen_commit(context->rg, tunName->bytes, alloc));
         if (er) {
             Log_error(context->logger, "Error setting routes for TUN [%s]", er->message);
-            return 0;
+            return Error(INVALID);
         }
     }
-    return 0;
+    return Error(NONE);
 }
 
 static Iface_DEFUN incomingControlMessage(struct Message* message,
@@ -580,7 +581,7 @@ static Iface_DEFUN incomingControlMessage(struct Message* message,
 
     // This aligns the message on the content.
     if (isControlMessageInvalid(message, context)) {
-        return 0;
+        return Error(INVALID);
     }
 
     Log_debug(context->logger, "Message content [%s]",
@@ -592,7 +593,7 @@ static Iface_DEFUN incomingControlMessage(struct Message* message,
     const char* err = BencMessageReader_readNoExcept(message, alloc, &d);
     if (err) {
         Log_info(context->logger, "Failed to parse message [%s]", err);
-        return 0;
+        return Error(INVALID);
     }
 
     if (Dict_getDictC(d, "addresses")) {
@@ -604,7 +605,7 @@ static Iface_DEFUN incomingControlMessage(struct Message* message,
         return requestForAddresses(d, conn, alloc, context);
     }
     Log_warn(context->logger, "Message which is unhandled");
-    return 0;
+    return Error(INVALID);
 }
 
 #define GET64(buffer) \
@@ -698,6 +699,7 @@ static Iface_DEFUN incomingFromTun(struct Message* message, struct Iface* tunIf)
 
     if (message->length < 20) {
         Log_debug(context->logger, "DROP runt");
+        return Error(RUNT);
     }
 
     struct IpTunnel_Connection* conn = NULL;
@@ -711,12 +713,12 @@ static Iface_DEFUN incomingFromTun(struct Message* message, struct Iface* tunIf)
         conn = findConnection(NULL, header->sourceAddr, true, context);
     } else {
         Log_debug(context->logger, "Message of unknown type from TUN");
-        return 0;
+        return Error(INVALID);
     }
 
     if (!conn) {
         Log_debug(context->logger, "Message with unrecognized address from TUN");
-        return 0;
+        return Error(INVALID);
     }
 
     return sendToNode(message, conn, context);
@@ -732,13 +734,13 @@ static Iface_DEFUN ip6FromNode(struct Message* message,
             return incomingControlMessage(message, conn, context);
         }
         Log_debug(context->logger, "Got message with zero address");
-        return 0;
+        return Error(INVALID);
     }
     if (!isValidAddress6(header->sourceAddr, false, conn)) {
         uint8_t addr[40];
         AddrTools_printIp(addr, header->sourceAddr);
         Log_debug(context->logger, "Got message with wrong address for connection [%s]", addr);
-        return 0;
+        return Error(INVALID);
     }
 
     Er_assert(TUNMessageType_push(message, Ethernet_TYPE_IP6));
@@ -752,7 +754,7 @@ static Iface_DEFUN ip4FromNode(struct Message* message,
     struct Headers_IP4Header* header = (struct Headers_IP4Header*) message->bytes;
     if (Bits_isZero(header->sourceAddr, 4) || Bits_isZero(header->destAddr, 4)) {
         Log_debug(context->logger, "Got message with zero address");
-        return 0;
+        return Error(INVALID);
     } else if (!isValidAddress4(header->sourceAddr, false, conn)) {
         Log_debug(context->logger, "Got message with wrong address [%d.%d.%d.%d] for connection "
                                    "[%d.%d.%d.%d/%d:%d]",
@@ -761,7 +763,7 @@ static Iface_DEFUN ip4FromNode(struct Message* message,
                   conn->connectionIp4[0], conn->connectionIp4[1],
                   conn->connectionIp4[2], conn->connectionIp4[3],
                   conn->connectionIp4Alloc, conn->connectionIp4Prefix);
-        return 0;
+        return Error(INVALID);
     }
 
     Er_assert(TUNMessageType_push(message, Ethernet_TYPE_IP4));
@@ -786,7 +788,7 @@ static Iface_DEFUN incomingFromNode(struct Message* message, struct Iface* nodeI
             AddrTools_printIp(addr, rh->ip6);
             Log_debug(context->logger, "Got message from unrecognized node [%s]", addr);
         }
-        return 0;
+        return Error(NONE);
     }
 
     Er_assert(Message_eshift(message, -(RouteHeader_SIZE + DataHeader_SIZE)));
@@ -807,7 +809,7 @@ static Iface_DEFUN incomingFromNode(struct Message* message, struct Iface* nodeI
                   (message->length > 1) ? Headers_getIpVersion(message->bytes) : 0,
                   addr);
     }
-    return 0;
+    return Error(INVALID);
 }
 
 static void timeout(void* vcontext)

+ 2 - 2
tunnel/test/IpTunnel_test.c

@@ -97,7 +97,7 @@ static Iface_DEFUN responseWithIpCallback(struct Message* message, struct Iface*
     Assert_true(!Bits_memcmp(message->bytes, ctx->expectedResponse->bytes, message->length));
     ctx->called |= 2;
 
-    return NULL;
+    return Error(NONE);
 }
 
 static Iface_DEFUN messageToTun(struct Message* msg, struct Iface* iface)
@@ -120,7 +120,7 @@ static Iface_DEFUN messageToTun(struct Message* msg, struct Iface* iface)
         Assert_failure("unrecognized message type %u", (unsigned int)type);
     }
     Assert_true(msg->length == 12 && CString_strcmp(msg->bytes, "hello world") == 0);
-    return 0;
+    return Error(NONE);
 }
 
 static void pushRouteDataHeaders(struct Context* ctx, struct Message* message)

+ 1 - 1
util/events/libuv/FakeNetwork.c

@@ -90,7 +90,7 @@ static Iface_DEFUN fromAsync(struct Message* msg, struct Iface* fnpFromAsync)
         char* srcAddr = Sockaddr_print(dp, msg->alloc);
 
         Log_debug(fnp->log, "Message with unknown dest address [%s] from [%s]", destAddr, srcAddr);
-        return NULL;
+        return Error(INVALID);
     }
 
     struct FakeNetwork_UDPIface_pvt* fnip = Identity_check(fnp->map.values[idx]);

+ 2 - 2
util/events/libuv/Pipe.c

@@ -130,7 +130,7 @@ static Iface_DEFUN sendMessage(struct Message* m, struct Iface* iface)
     struct Pipe_pvt* pipe = Identity_check((struct Pipe_pvt*) iface);
 
     if (pipe->queueLen > 50000) {
-        return 0;
+        return Error(OVERFLOW);
     }
 
     // This allocator will hold the message allocator in existance after it is freed.
@@ -171,7 +171,7 @@ static Iface_DEFUN sendMessage(struct Message* m, struct Iface* iface)
             pipe->bufferedRequest = req;
         }
     }
-    return NULL;
+    return Error(NONE);
 }
 
 /** Asynchronous allocator freeing. */

+ 1 - 1
util/events/libuv/PipeServer.c

@@ -79,7 +79,7 @@ static Iface_DEFUN sendMessage(struct Message* m, struct Iface* iface)
     int idx = Map_Clients_indexForHandle(handle, &psp->clients);
     if (idx < 0) {
         Log_warn(psp->log, "Attempted to send a message to client [0x%x] which is gone", handle);
-        return NULL;
+        return Error(UNHANDLED);
     }
     struct Client* cli = psp->clients.values[idx];
     return Iface_next(&cli->iface, m);

+ 4 - 4
util/events/libuv/UDPAddrIface.c

@@ -86,13 +86,13 @@ static Iface_DEFUN incomingFromIface(struct Message* m, struct Iface* iface)
     if (((struct Sockaddr*)m->bytes)->flags & Sockaddr_flags_BCAST) {
         Log_debug(context->logger, "Attempted bcast, bcast unsupported");
         // bcast not supported.
-        return NULL;
+        return Error(UNHANDLED);
     }
 
     if (context->queueLen > UDPAddrIface_MAX_QUEUE) {
         Log_warn(context->logger, "DROP msg length [%d] to [%s] maximum queue length reached",
             m->length, Sockaddr_print(context->pub.generic.addr, m->alloc));
-        return NULL;
+        return Error(OVERFLOW);
     }
 
     // This allocator will hold the message allocator in existance after it is freed.
@@ -128,11 +128,11 @@ static Iface_DEFUN incomingFromIface(struct Message* m, struct Iface* iface)
         Log_info(context->logger, "DROP Failed writing to UDPAddrIface [%s]",
                  uv_strerror(ret));
         Allocator_free(req->alloc);
-        return NULL;
+        return Error(UNHANDLED);
     }
     context->queueLen += m->length;
 
-    return NULL;
+    return Error(NONE);
 }
 
 #if UDPAddrIface_PADDING_AMOUNT < 8

+ 2 - 2
util/test/Process_test.c

@@ -74,7 +74,7 @@ static Iface_DEFUN receiveMessageParent(struct Message* msg, struct Iface* iface
     Assert_true(msg->length == (int)CString_strlen(MESSAGEB)+1);
     Assert_true(!Bits_memcmp(msg->bytes, MESSAGEB, CString_strlen(MESSAGEB)+1));
     Allocator_free(c->alloc);
-    return NULL;
+    return Error(NONE);
 }
 
 static void timeout(void* vNULL)
@@ -122,7 +122,7 @@ static Iface_DEFUN receiveMessageChild(struct Message* msg, struct Iface* iface)
     // shutdown
     Allocator_free(c->alloc);
 
-    return NULL;
+    return Error(NONE);
 }
 
 static void child(char* name, struct Context* ctx)

+ 1 - 1
util/test/Seccomp_test.c

@@ -102,7 +102,7 @@ static Iface_DEFUN receiveMessageParent(struct Message* msg, struct Iface* iface
     Assert_true(msg->length == 3);
     Assert_true(!Bits_memcmp(msg->bytes, "OK", 3));
     EventBase_endLoop(ctx->eventBase);
-    return 0;
+    return Error(NONE);
 }
 
 int main(int argc, char** argv)

+ 42 - 23
wire/Error.h

@@ -15,38 +15,55 @@
 #ifndef Error_H
 #define Error_H
 
-/** No error, everything is ok. */
-#define Error_NONE                 0
+enum Error_e {
+    /** No error, everything is ok. */
+    Error_NONE =                0,
 
-/** The switch label was malformed. */
-#define Error_MALFORMED_ADDRESS    1
+    /** The switch label was malformed. */
+    Error_MALFORMED_ADDRESS =   1,
 
-/** Packet dropped because link is congested. */
-#define Error_FLOOD                2
+    /** Packet dropped because link is congested. */
+    Error_FLOOD =               2,
 
-/** Packet dropped because node has oversent its limit. */
-#define Error_LINK_LIMIT_EXCEEDED  3
+    /** Packet dropped because node has oversent its limit. */
+    Error_LINK_LIMIT_EXCEEDED = 3,
 
-/** Message too big to send. */
-#define Error_OVERSIZE_MESSAGE     4
+    /** Message too big to send. */
+    Error_OVERSIZE_MESSAGE =    4,
 
-/** Message smaller than expected headers. */
-#define Error_UNDERSIZE_MESSAGE    5
+    /** Message smaller than expected headers. */
+    Error_RUNT =                5,
 
-/** Authentication failed. */
-#define Error_AUTHENTICATION       6
+    /** Authentication failed. */
+    Error_AUTHENTICATION =      6,
 
-/** Header is invalid or checksum failed. */
-#define Error_INVALID              7
+    /** Header is invalid or checksum failed. */
+    Error_INVALID =             7,
 
-/** Message could not be sent to its destination through no fault of the sender. */
-#define Error_UNDELIVERABLE        8
+    /** Message could not be sent to its destination through no fault of the sender. */
+    Error_UNDELIVERABLE =       8,
 
-/** The route enters and leaves through the same interface in one switch. */
-#define Error_LOOP_ROUTE           9
+    /** The route enters and leaves through the same interface in one switch. */
+    Error_LOOP_ROUTE =          9,
 
-/** The switch is unable to represent the return path. */
-#define Error_RETURN_PATH_INVALID 10
+    /** The switch is unable to represent the return path. */
+    Error_RETURN_PATH_INVALID = 10,
+
+    /** Not invalid, but not something the code is able to handle. */
+    Error_UNHANDLED =           11,
+
+    /** Too many messages, cannot handle. */
+    Error_OVERFLOW =            12,
+
+    /** Something went wrong, it should not have happened. */
+    Error_INTERNAL =            13,
+};
+
+struct Error_s {
+    enum Error_e e;
+};
+
+#define Error(x) ((struct Error_s){ .e = Error_ ## x })
 
 static inline char* Error_strerror(int err)
 {
@@ -56,12 +73,14 @@ static inline char* Error_strerror(int err)
         case Error_FLOOD:               return "Error_FLOOD";
         case Error_LINK_LIMIT_EXCEEDED: return "Error_LINK_LIMIT_EXCEEDED";
         case Error_OVERSIZE_MESSAGE:    return "Error_OVERSIZE_MESSAGE";
-        case Error_UNDERSIZE_MESSAGE:   return "Error_UNDERSIZE_MESSAGE";
+        case Error_RUNT:                return "Error_RUNT";
         case Error_AUTHENTICATION:      return "Error_AUTHENTICATION";
         case Error_INVALID:             return "Error_INVALID";
         case Error_UNDELIVERABLE:       return "Error_UNDELIVERABLE";
         case Error_LOOP_ROUTE:          return "Error_LOOP_ROUTE";
         case Error_RETURN_PATH_INVALID: return "Error_RETURN_PATH_INVALID";
+        case Error_UNHANDLED:           return "Error_UNHANDLED";
+        case Error_INTERNAL:            return "Error_INTERNAL";
         default: return "UNKNOWN";
     }
 }