]> git.lizzy.rs Git - dragonnet.git/commitdiff
Refactor type hooks
authorHimbeerserverDE <himbeerserverde@gmail.com>
Sat, 9 Oct 2021 15:07:38 +0000 (17:07 +0200)
committerHimbeerserverDE <himbeerserverde@gmail.com>
Sat, 9 Oct 2021 15:07:38 +0000 (17:07 +0200)
listen.c
listen.h
peer.c
peer.h
recv.h
recv_thread.c
typegen/main.c

index a4b19bf94d924168dc4408014f38aea031253487..e040efacfa332788d780f9ee05b36467de9ebb5b 100644 (file)
--- a/listen.c
+++ b/listen.c
@@ -1,12 +1,12 @@
 #include <assert.h>
+#include <dragonnet/recv.h>
+#include <dragonnet/listen.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/socket.h>
 #include <unistd.h>
 
-#include "listen.h"
-
 // ----
 // Peer
 // ----
@@ -45,8 +45,7 @@ static DragonnetPeer *dragonnet_peer_accept(int sock, struct sockaddr_in6 addr,
 // --------
 
 DragonnetListener *dragonnet_listener_new(char *addr,
-               void (*on_connect)(DragonnetPeer *p),
-               void (*on_recv_type)(struct dragonnet_peer *, u16))
+               void (*on_connect)(DragonnetPeer *p))
 {
        DragonnetListener *l = malloc(sizeof *l);
        pthread_rwlock_init(&l->mu, NULL);
@@ -54,7 +53,7 @@ DragonnetListener *dragonnet_listener_new(char *addr,
 
        l->sock = socket(AF_INET6, SOCK_STREAM, 0);
        l->on_connect = on_connect;
-       l->on_recv_type = on_recv_type;
+       l->on_recv_type = calloc(sizeof *l->on_recv_type, dragonnet_num_types);
 
        int so_reuseaddr = 1;
        if (setsockopt(l->sock, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr,
@@ -83,6 +82,21 @@ DragonnetListener *dragonnet_listener_new(char *addr,
        return l;
 }
 
+void dragonnet_listener_set_recv_hook(DragonnetListener *l, u16 type_id,
+               void (*on_recv)(struct dragonnet_peer *, void *))
+{
+       pthread_rwlock_rdlock(&l->mu);
+       DragonnetListenerState state = l->state;
+       pthread_rwlock_unlock(&l->mu);
+
+       if (state >= DRAGONNET_LISTENER_ACTIVE)
+               return;
+
+       pthread_rwlock_wrlock(&l->mu);
+       l->on_recv_type[type_id] = on_recv;
+       pthread_rwlock_unlock(&l->mu);
+}
+
 static void *listener_main(void *g_listener)
 {
        DragonnetListener *l = (DragonnetListener *) g_listener;
index 28c456234939b8239fc488524534db49c92839c3..f1fae8db9bb64d3db46aef4e6d684050de82bcec 100644 (file)
--- a/listen.h
+++ b/listen.h
@@ -18,14 +18,15 @@ typedef struct {
        pthread_t accept_thread;
 
        void (*on_connect)(DragonnetPeer *);
-       void (*on_recv_type)(struct dragonnet_peer *, u16);
+       void (**on_recv_type)(DragonnetPeer *, void *);
 
        pthread_rwlock_t mu;
 } DragonnetListener;
 
 DragonnetListener *dragonnet_listener_new(char *addr,
-               void (*on_connect)(DragonnetPeer *p),
-               void (*on_recv_type)(struct dragonnet_peer *, u16));
+               void (*on_connect)(DragonnetPeer *p));
+void dragonnet_listener_set_recv_hook(DragonnetListener *l, u16 type_id,
+               void (*on_recv)(struct dragonnet_peer *, void *));
 void dragonnet_listener_run(DragonnetListener *l);
 void dragonnet_listener_close(DragonnetListener *l);
 void dragonnet_listener_delete(DragonnetListener *l);
diff --git a/peer.c b/peer.c
index a1bb39d76e861d198698849fabcd0a8c1c47f354..83e91226cbde496a59f2a0157cfde976d1da6765 100644 (file)
--- a/peer.c
+++ b/peer.c
@@ -1,19 +1,19 @@
 #include <assert.h>
+#include <dragonnet/peer.h>
+#include <dragonnet/recv.h>
+#include <dragonnet/recv_thread.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "peer.h"
-#include "recv_thread.h"
-
-static bool dragonnet_peer_init(DragonnetPeer *p, char *addr, void (*on_recv_type)(struct dragonnet_peer *, u16))
+static bool dragonnet_peer_init(DragonnetPeer *p, char *addr)
 {
        pthread_rwlock_init(&p->mu, NULL);
        pthread_rwlock_wrlock(&p->mu);
 
        p->sock = socket(AF_INET6, SOCK_STREAM, 0);
        p->raddr = dragonnet_addr_parse_str(addr);
-       p->on_recv_type = on_recv_type;
+       p->on_recv_type = calloc(sizeof *p->on_recv_type, dragonnet_num_types);
 
        struct sockaddr_in6 sock_addr = dragonnet_addr_sock(p->raddr);
        if (connect(p->sock, (const struct sockaddr *) &sock_addr,
@@ -36,10 +36,10 @@ static bool dragonnet_peer_init(DragonnetPeer *p, char *addr, void (*on_recv_typ
        return true;
 }
 
-DragonnetPeer *dragonnet_connect(char *addr, void (*on_recv_type)(struct dragonnet_peer *, u16))
+DragonnetPeer *dragonnet_connect(char *addr)
 {
        DragonnetPeer *p = malloc(sizeof *p);
-       if (!dragonnet_peer_init(p, addr, on_recv_type)) {
+       if (!dragonnet_peer_init(p, addr)) {
                dragonnet_peer_delete(p);
                return NULL;
        }
@@ -47,6 +47,21 @@ DragonnetPeer *dragonnet_connect(char *addr, void (*on_recv_type)(struct dragonn
        return p;
 }
 
+void dragonnet_peer_set_recv_hook(DragonnetPeer *p, u16 type_id,
+               void (*on_recv)(struct dragonnet_peer *, void *))
+{
+       pthread_rwlock_rdlock(&p->mu);
+       DragonnetPeerState state = p->state;
+       pthread_rwlock_unlock(&p->mu);
+
+       if (state >= DRAGONNET_PEER_ACTIVE)
+               return;
+
+       pthread_rwlock_wrlock(&p->mu);
+       p->on_recv_type[type_id] = on_recv;
+       pthread_rwlock_unlock(&p->mu);
+}
+
 void dragonnet_peer_run(DragonnetPeer *p)
 {
        pthread_rwlock_wrlock(&p->mu);
diff --git a/peer.h b/peer.h
index 16c02f9121e657e4145ff2147f031286040b3aca..5dc06fe5b2e11115ffb555492038ac0908d0671f 100644 (file)
--- a/peer.h
+++ b/peer.h
@@ -3,8 +3,7 @@
 
 #include <pthread.h>
 #include <dragontype/number.h>
-
-#include "addr.h"
+#include <dragonnet/addr.h>
 
 typedef enum {
        DRAGONNET_PEER_CREATED,
@@ -18,12 +17,14 @@ typedef struct dragonnet_peer {
        DragonnetPeerState state;
        pthread_t recv_thread;
 
-       void (*on_recv_type)(struct dragonnet_peer *, u16);
+       void (**on_recv_type)(struct dragonnet_peer *, void *);
 
        pthread_rwlock_t mu;
 } DragonnetPeer;
 
-DragonnetPeer *dragonnet_connect(char *addr, void (*on_recv_type)(struct dragonnet_peer *, u16));
+DragonnetPeer *dragonnet_connect(char *addr);
+void dragonnet_peer_set_recv_hook(DragonnetPeer *p, u16 type_id,
+               void (*on_recv)(struct dragonnet_peer *, void *));
 void dragonnet_peer_run(DragonnetPeer *p);
 void dragonnet_peer_close(DragonnetPeer *p);
 void dragonnet_peer_delete(DragonnetPeer *p);
diff --git a/recv.h b/recv.h
index 22b3b9733d37519257694ed1055d51e37e35dde8..b0938d9b52df78f5e838111589a3ce8f4750d3a1 100644 (file)
--- a/recv.h
+++ b/recv.h
@@ -3,6 +3,14 @@
 
 #include <dragonnet/peer.h>
 
+typedef struct {
+       size_t siz;
+       void (*deserialize)(DragonnetPeer *, void *);
+} DragonnetType;
+
+extern u16 dragonnet_num_types;
+extern DragonnetType dragonnet_types[];
+
 void dragonnet_recv_raw(DragonnetPeer *p, void *buf, size_t n);
 void dragonnet_read_raw(u8 **buf, size_t *n, void *data, size_t len);
 
index b4975fb315f0d799c930526ad73f87ac26d8aabb..437105ee6492d4f5ab2263b4d7e9ec479e2d05f1 100644 (file)
@@ -1,13 +1,13 @@
 #include <assert.h>
+#include <dragonnet/peer.h>
+#include <dragonnet/recv.h>
+#include <dragonnet/recv_thread.h>
 #include <dragontype/number.h>
 #include <pthread.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <unistd.h>
 
-#include "peer.h"
-#include "recv_thread.h"
-
 void *dragonnet_peer_recv_thread(void *g_peer)
 {
        DragonnetPeer *p = (DragonnetPeer *) g_peer;
@@ -18,14 +18,14 @@ void *dragonnet_peer_recv_thread(void *g_peer)
        pthread_rwlock_unlock(&p->mu);
 
        while (true) {
-               u16 type;
+               u16 type_id;
 
                // Copy socket fd so that shutdown doesn't block
                pthread_rwlock_rdlock(&p->mu);
                int sock = p->sock;
                pthread_rwlock_unlock(&p->mu);
 
-               ssize_t len = recv(sock, &type, sizeof type, MSG_WAITALL);
+               ssize_t len = recv(sock, &type_id, sizeof type_id, MSG_WAITALL);
                if (len < 0) {
                        perror("recv");
                        dragonnet_peer_delete(p);
@@ -44,13 +44,16 @@ void *dragonnet_peer_recv_thread(void *g_peer)
                        return NULL;
                }
 
-               type = be16toh(type);
+               type_id = be16toh(type_id);
+               DragonnetType type = dragonnet_types[type_id];
+               u8 buf[type.siz];
+               type.deserialize(p, buf);
 
                pthread_rwlock_rdlock(&p->mu);
-               void (*on_recv_type)(struct dragonnet_peer *, u16) = p->on_recv_type;
+               void (*on_recv_type)(DragonnetPeer *, void *) = p->on_recv_type[type_id];
                pthread_rwlock_unlock(&p->mu);
 
                if (on_recv_type != NULL)
-                       on_recv_type(p, type);
+                       on_recv_type(p, buf);
        }
 }
index 183d7f322cbf8517b8d05cb2f95c634189f494dc..2f045bd15e7a6440722385ecf81344ccee80c5d4 100644 (file)
@@ -1,4 +1,5 @@
 #include <ctype.h>
+#include <dragonport/asprintf.h>
 #include <dragontype/number.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -146,132 +147,60 @@ static void gen_serializers(FILE *c_fp)
 static void gen_deserializers(FILE *c_fp)
 {
        for (u8 bits = 8; bits <= 64; bits *= 2) {
-               char *fmt_u = "__attribute__((unused)) static u%d recv_u%d(DragonnetPeer *p)\n";
-               char *fmt_s = "__attribute__((unused)) static s%d recv_s%d(DragonnetPeer *p)\n";
+               char *fmt = "__attribute__((unused)) static void recv_n%d(DragonnetPeer *p, void *buf)\n";
 
-               fprintf(c_fp, fmt_u, bits, bits);
+               fprintf(c_fp, fmt, bits);
                fprintf(c_fp, "{\n");
                fprintf(c_fp, "\tu%d be;\n", bits);
                fprintf(c_fp, "\tdragonnet_recv_raw(p, &be, sizeof be);\n");
-               fprintf(c_fp, "\treturn be%dtoh(be);\n", bits);
-               fprintf(c_fp, "}\n\n");
-
-               fprintf(c_fp, fmt_s, bits, bits);
-               fprintf(c_fp, "{\n");
-               fprintf(c_fp, "\treturn (s%d) recv_u%d(p);\n", bits, bits);
+               fprintf(c_fp, "\tbe = be%dtoh(be);\n", bits);
+               fprintf(c_fp, "\tmemcpy(buf, &be, sizeof be);\n");
                fprintf(c_fp, "}\n\n");
-
-               if (bits >= 32) {
-                       char *fmt_f = "__attribute__((unused)) static f%d recv_f%d(DragonnetPeer *p)\n";
-
-                       fprintf(c_fp, fmt_f, bits, bits);
-                       fprintf(c_fp, "{\n");
-                       fprintf(c_fp, "\treturn (f%d) recv_u%d(p);\n", bits, bits);
-                       fprintf(c_fp, "}\n\n");
-               }
        }
 
        for (u8 elems = 2; elems <= 4; ++elems) {
                for (u8 bits = 8; bits <= 64; bits *= 2) {
-                       char *fmt_u = "__attribute__((unused)) static v%du%d recv_v%du%d(DragonnetPeer *p)\n";
-                       char *fmt_s = "__attribute__((unused)) static v%ds%d recv_v%ds%d(DragonnetPeer *p)\n";
+                       char *fmt = "__attribute__((unused)) static void recv_v%dn%d(DragonnetPeer *p, void *buf)\n";
 
-                       fprintf(c_fp, fmt_u, elems, bits, elems, bits);
-                       fprintf(c_fp, "{\n");
-                       fprintf(c_fp, "\tv%du%d v = {0};\n", elems, bits);
-                       fprintf(c_fp, "\tu%d *ptr = &v.x;\n\n", bits);
-                       fprintf(c_fp, "\tfor (u8 i = 0; i < %d; ++i) {\n", elems);
-                       fprintf(c_fp, "\t\t*ptr++ = recv_u%d(p);\n", bits);
-                       fprintf(c_fp, "\t}\n\n");
-                       fprintf(c_fp, "\treturn v;\n");
-                       fprintf(c_fp, "}\n\n");
-
-                       fprintf(c_fp, fmt_s, elems, bits, elems, bits);
+                       fprintf(c_fp, fmt, elems, bits);
                        fprintf(c_fp, "{\n");
-                       fprintf(c_fp, "\tv%ds%d v = {0};\n", elems, bits);
-                       fprintf(c_fp, "\ts%d *ptr = &v.x;\n\n", bits);
-                       fprintf(c_fp, "\tfor (u8 i = 0; i < %d; ++i) {\n", elems);
-                       fprintf(c_fp, "\t\t*ptr++ = recv_s%d(p);\n", bits);
-                       fprintf(c_fp, "\t}\n\n");
-                       fprintf(c_fp, "\treturn v;\n");
+                       fprintf(c_fp, "\tfor (u8 i = 0; i < %d; ++i)\n", elems);
+                       fprintf(c_fp, "\t\trecv_n%d(p, buf);\n", bits);
                        fprintf(c_fp, "}\n\n");
-
-                       if (bits >= 32) {
-                               char *fmt_f = "__attribute__((unused)) static v%df%d recv_v%df%d(DragonnetPeer *p)\n";
-
-                               fprintf(c_fp, fmt_f, elems, bits, elems, bits);
-                               fprintf(c_fp, "{\n");
-                               fprintf(c_fp, "\tv%df%d v = {0};\n", elems, bits);
-                               fprintf(c_fp, "\tf%d *ptr = &v.x;\n\n", bits);
-                               fprintf(c_fp, "\tfor (u8 i = 0; i < %d; ++i) {\n", elems);
-                               fprintf(c_fp, "\t\t*ptr++ = recv_f%d(p);\n", bits);
-                               fprintf(c_fp, "\t}\n\n");
-                               fprintf(c_fp, "\treturn v;\n");
-                               fprintf(c_fp, "}\n\n");
-                       }
                }
        }
 
        for (u8 elems = 2; elems <= 4; ++elems) {
                for (u8 bits = 8; bits <= 64; bits *= 2) {
-                       char *fmt_u = "__attribute__((unused)) static aabb%du%d recv_aabb%du%d(DragonnetPeer *p)\n";
-                       char *fmt_s = "__attribute__((unused)) static aabb%ds%d recv_aabb%ds%d(DragonnetPeer *p)\n";
+                       char *fmt = "__attribute__((unused)) static void recv_aabb%dn%d(DragonnetPeer *p, void *buf)\n";
 
-                       fprintf(c_fp, fmt_u, elems, bits, elems, bits);
+                       fprintf(c_fp, fmt, elems, bits);
                        fprintf(c_fp, "{\n");
-                       fprintf(c_fp, "\taabb%du%d v = {0};\n", elems, bits);
-                       fprintf(c_fp, "\tv%du%d *ptr = &v.min;\n\n", elems, bits);
-                       fprintf(c_fp, "\tfor (u8 i = 0; i < 2; ++i) {\n");
-                       fprintf(c_fp, "\t\t*ptr++ = recv_v%du%d(p);\n", elems, bits);
-                       fprintf(c_fp, "\t}\n\n");
-                       fprintf(c_fp, "\treturn v;\n");
+                       fprintf(c_fp, "\tfor (u8 i = 0; i < 2; ++i)\n");
+                       fprintf(c_fp, "\t\trecv_v%dn%d(p, buf);\n", elems, bits);
                        fprintf(c_fp, "}\n\n");
-
-                       fprintf(c_fp, fmt_s, elems, bits, elems, bits);
-                       fprintf(c_fp, "{\n");
-                       fprintf(c_fp, "\taabb%ds%d v = {0};\n", elems, bits);
-                       fprintf(c_fp, "\tv%ds%d *ptr = &v.min;\n\n", elems, bits);
-                       fprintf(c_fp, "\tfor (u8 i = 0; i < 2; ++i) {\n");
-                       fprintf(c_fp, "\t\t*ptr++ = recv_v%ds%d(p);\n", elems, bits);
-                       fprintf(c_fp, "\t}\n\n");
-                       fprintf(c_fp, "\treturn v;\n");
-                       fprintf(c_fp, "}\n\n");
-
-                       if (bits >= 32) {
-                               char *fmt_f = "__attribute__((unused)) static aabb%df%d recv_aabb%df%d(DragonnetPeer *p)\n";
-
-                               fprintf(c_fp, fmt_f, elems, bits, elems, bits);
-                               fprintf(c_fp, "{\n");
-                               fprintf(c_fp, "\taabb%df%d v = {0};\n", elems, bits);
-                               fprintf(c_fp, "\tv%df%d *ptr = &v.min;\n\n", elems, bits);
-                               fprintf(c_fp, "\tfor (u8 i = 0; i < 2; ++i) {\n");
-                               fprintf(c_fp, "\t\t*ptr++ = recv_v%df%d(p);\n", elems, bits);
-                               fprintf(c_fp, "\t}\n\n");
-                               fprintf(c_fp, "\treturn v;\n");
-                               fprintf(c_fp, "}\n\n");
-                       }
                }
        }
 
-       fprintf(c_fp, "__attribute__((unused)) static string recv_string(DragonnetPeer *p)\n");
+       fprintf(c_fp, "__attribute__((unused)) static void recv_string(DragonnetPeer *p, void *buf)\n");
        fprintf(c_fp, "{\n");
-       fprintf(c_fp, "\tstring v = malloc(sizeof(u16));\n\n");
+       fprintf(c_fp, "\tstring v = malloc(1 + (u16) ~0);\n\n");
        fprintf(c_fp, "\tchar ch;\n");
        fprintf(c_fp, "\tfor (u16 i = 0; ch != '\\0'; ++i) {\n");
-       fprintf(c_fp, "\t\tch = recv_s8(p);\n");
+       fprintf(c_fp, "\t\trecv_n8(p, &ch);\n");
        fprintf(c_fp, "\t\tv[i] = ch;\n");
        fprintf(c_fp, "\t}\n\n");
        fprintf(c_fp, "\tv = realloc(v, strlen(v));\n");
-       fprintf(c_fp, "\treturn v;\n");
+       fprintf(c_fp, "\tmemcpy(buf, v, strlen(v));\n");
        fprintf(c_fp, "}\n\n");
 
-       fprintf(c_fp, "__attribute__((unused)) static Blob *recv_Blob(DragonnetPeer *p)\n\n");
+       fprintf(c_fp, "__attribute__((unused)) static void recv_Blob(DragonnetPeer *p, void *buf)\n\n");
        fprintf(c_fp, "{\n");
        fprintf(c_fp, "\tBlob *v = malloc(sizeof *v);\n");
-       fprintf(c_fp, "\tv->siz = recv_u32(p);\n");
+       fprintf(c_fp, "\trecv_n32(p, &v->siz);\n");
        fprintf(c_fp, "\tv->data = malloc(v->siz);\n");
        fprintf(c_fp, "\tdragonnet_recv_raw(p, v->data, v->siz);\n\n");
-       fprintf(c_fp, "\treturn v;\n");
+       fprintf(c_fp, "\tmemcpy(buf, v->data, v->siz);\n");
        fprintf(c_fp, "}\n\n");
 }
 
@@ -587,7 +516,6 @@ int main(__attribute((unused)) int argc, __attribute((unused)) char **argv)
                        size_t tokens_len = split(&tokens, msgs[i], " ");
 
                        fprintf(c_fp, "\tsend_%s(p, false, type.%s);\n", &tokens[0][1], tokens[1]);
-
                        free_split(tokens, tokens_len);
                        tokens = NULL;
                }
@@ -602,8 +530,8 @@ int main(__attribute((unused)) int argc, __attribute((unused)) char **argv)
                                fprintf(c_fp, "}\n\n");
 
                        msg = msgs[i];
-                       fprintf(h_fp, "void dragonnet_peer_send_%s(DragonnetPeer *p, %s type);\n", msg, msg);
-                       fprintf(c_fp, "void dragonnet_peer_send_%s(DragonnetPeer *p, %s type)\n{\n", msg, msg);
+                       fprintf(h_fp, "void dragonnet_peer_send_%s(DragonnetPeer *p, %s *type);\n", msg, msg);
+                       fprintf(c_fp, "void dragonnet_peer_send_%s(DragonnetPeer *p, %s *type)\n{\n", msg, msg);
 
                        char upper[1 + strlen(msgs[i])];
                        char *ptr = upper;
@@ -618,9 +546,9 @@ int main(__attribute((unused)) int argc, __attribute((unused)) char **argv)
                        size_t tokens_len = split(&tokens, msgs[i], " ");
 
                        if (i >= msgs_len-1 || msgs[1+i][0] != '\t')
-                               fprintf(c_fp, "\tsend_%s(p, true, type.%s);\n", &tokens[0][1], tokens[1]);
+                               fprintf(c_fp, "\tsend_%s(p, true, type->%s);\n", &tokens[0][1], tokens[1]);
                        else
-                               fprintf(c_fp, "\tsend_%s(p, false, type.%s);\n", &tokens[0][1], tokens[1]);
+                               fprintf(c_fp, "\tsend_%s(p, false, type->%s);\n", &tokens[0][1], tokens[1]);
 
                        free_split(tokens, tokens_len);
                        tokens = NULL;
@@ -633,26 +561,38 @@ int main(__attribute((unused)) int argc, __attribute((unused)) char **argv)
        for (size_t i = 0; i < msgs_len; ++i) {
                if (msgs[i][0] != '\t') {
                        if (msg != NULL) {
-                               fprintf(c_fp, "\treturn type;\n");
                                fprintf(c_fp, "}\n\n");
                        }
 
                        msg = msgs[i];
-                       fprintf(h_fp, "%s dragonnet_peer_recv_%s(DragonnetPeer *p);\n", msg, msg);
-                       fprintf(c_fp, "%s dragonnet_peer_recv_%s(DragonnetPeer *p)\n{\n", msg, msg);
-                       fprintf(c_fp, "\t%s type = {0};\n", msg);
+                       fprintf(c_fp, "static void dragonnet_peer_recv_%s(DragonnetPeer *p, void *buf)\n{\n", msg);
+                       fprintf(c_fp, "\t%s *type = (%s *) buf;\n", msg, msg);
                } else {
                        char **tokens;
                        size_t tokens_len = split(&tokens, msgs[i], " ");
 
-                       fprintf(c_fp, "\ttype.%s = recv_%s(p);\n", tokens[1], &tokens[0][1]);
+                       char type[strlen(&tokens[0][1])];
+                       strcpy(type, &tokens[0][1]);
+
+                       for (size_t bits = 8; bits <= 64; bits *= 2) {
+                               const char *fmt[] = {"u%d", "s%d", "f%d"};
+                               for (size_t j = 0; j < sizeof fmt / sizeof *fmt; ++j) {
+                                       char *cmp;
+                                       asprintf(&cmp, fmt[j], bits);
+
+                                       if (strcmp(type, cmp) == 0)
+                                               sprintf(type, "n%ld", bits);
+
+                                       free(cmp);
+                               }
+                       }
+
+                       fprintf(c_fp, "\trecv_%s(p, &type->%s);\n", type, tokens[1]);
                        free_split(tokens, tokens_len);
                        tokens = NULL;
                }
        }
 
-       fprintf(h_fp, "\n");
-       fprintf(c_fp, "\treturn type;\n");
        fprintf(c_fp, "}\n");
        msg = NULL;
 
@@ -701,15 +641,10 @@ int main(__attribute((unused)) int argc, __attribute((unused)) char **argv)
 
        fprintf(h_fp, "\n");
        fprintf(c_fp, "\treturn type;\n");
-       fprintf(c_fp, "}\n");
+       fprintf(c_fp, "}\n\n");
        msg = NULL;
 
        // Create type enum
-       size_t last_msg = 0;
-       for (size_t i = 0; i < msgs_len; ++i)
-               if (msgs[i][0] != '\t')
-                       last_msg = i;
-
        fprintf(h_fp, "typedef enum {\n");
        for (size_t i = 0; i < msgs_len; ++i) {
                if (msgs[i][0] == '\t')
@@ -722,13 +657,27 @@ int main(__attribute((unused)) int argc, __attribute((unused)) char **argv)
                while ((*ptr = *ptr ? toupper(*ptr) : '\0'))
                        ++ptr;
 
-               if (i == last_msg)
-                       fprintf(h_fp, "\tDRAGONNET_TYPE_%s\n", upper);
-               else
-                       fprintf(h_fp, "\tDRAGONNET_TYPE_%s,\n", upper);
+               fprintf(h_fp, "\tDRAGONNET_TYPE_%s,\n", upper);
+       }
+
+       fprintf(h_fp, "\tDRAGONNET_NUM_TYPES\n");
+       fprintf(h_fp, "} DragonnetTypeNum;\n");
+
+       // ABI
+       fprintf(c_fp, "u16 dragonnet_num_types = DRAGONNET_NUM_TYPES;\n");
+       fprintf(c_fp, "DragonnetType dragonnet_types[] = {\n");
+
+       for (size_t i = 0; i < msgs_len; ++i) {
+               if (msgs[i][0] == '\t')
+                       continue;
+
+               fprintf(c_fp, "\t{\n");
+               fprintf(c_fp, "\t\t.siz = sizeof(%s),\n", msgs[i]);
+               fprintf(c_fp, "\t\t.deserialize = &dragonnet_peer_recv_%s\n", msgs[i]);
+               fprintf(c_fp, "\t},\n");
        }
 
-       fprintf(h_fp, "} DragonnetType;\n");
+       fprintf(c_fp, "};\n");
 
        free_split(msgs, msgs_len);
        msgs = NULL;