]> git.meshlink.io Git - meshlink/commitdiff
Start of the manynodes example.
authorGuus Sliepen <guus@sliepen.org>
Tue, 29 Jul 2014 16:55:25 +0000 (18:55 +0200)
committerGuus Sliepen <guus@sliepen.org>
Tue, 29 Jul 2014 16:55:25 +0000 (18:55 +0200)
This example program starts many instances of MeshLink in a single
program, and can let them connect to each other. This is mainly usable
for testing scalability.

examples/Makefile.am
examples/manynodes.c [new file with mode: 0644]

index af8f0f45d22cb04319e0f36b4a4f5212c8bf076f..9be95b13a3380f0790d0e3733b30357f1f4c7902 100644 (file)
@@ -1,4 +1,4 @@
-bin_PROGRAMS = meshlinkapp chat chatpp
+bin_PROGRAMS = meshlinkapp chat chatpp manynodes
 
 AM_CPPFLAGS = -I../src
 
@@ -10,3 +10,6 @@ chat_LDADD = ../src/libmeshlink.la
 
 chatpp_SOURCES = chatpp.cc
 chatpp_LDADD = ../src/libmeshlink.la
+
+manynodes_SOURCES = manynodes.cc
+manynodes_LDADD = ../src/libmeshlink.la
diff --git a/examples/manynodes.c b/examples/manynodes.c
new file mode 100644 (file)
index 0000000..86883ea
--- /dev/null
@@ -0,0 +1,260 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <linux/limits.h>
+
+#include "../src/meshlink.h"
+
+static int n = 100;
+static meshlink_handle_t **mesh;
+
+static void log_message(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *text) {
+       const char *levelstr[] = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"};
+       fprintf(stderr, "%s: %s\n", levelstr[level], text);
+}
+
+static void receive(meshlink_handle_t *mesh, meshlink_node_t *source, const void *data, size_t len) {
+       const char *msg = data;
+
+       if(!len || msg[len - 1]) {
+               fprintf(stderr, "Received invalid data from %s\n", source->name);
+               return;
+       }
+
+       printf("%s says: %s\n", source->name, msg);
+}
+
+static void node_status(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
+       if(reachable)
+               printf("%s joined.\n", node->name);
+       else
+               printf("%s left.\n", node->name);
+}
+
+// Make all nodes know about each other by importing each others public keys and addresses.
+static void linkmesh() {
+       for(int i = 0; i < n; i++) {
+               char *datai = meshlink_export(mesh[i]);
+
+               for(int j = i + 1; j < n; j++) {
+                       char *dataj = meshlink_export(mesh[j]);
+                       meshlink_import(mesh[i], dataj);
+                       meshlink_import(mesh[j], datai);
+                       free(dataj);
+               }
+
+               free(datai);
+       }
+}
+
+static void parse_command(char *buf) {
+       char *arg = strchr(buf, ' ');
+       if(arg)
+               *arg++ = 0;
+
+       if(!strcasecmp(buf, "invite")) {
+               char *invitation;
+
+               if(!arg) {
+                       fprintf(stderr, "/invite requires an argument!\n");
+                       return;
+               }
+
+               invitation = meshlink_invite(mesh[0], arg);
+               if(!invitation) {
+                       fprintf(stderr, "Could not invite '%s': %s\n", arg, meshlink_strerror(meshlink_errno));
+                       return;
+               }
+
+               printf("Invitation for %s: %s\n", arg, invitation);
+               free(invitation);
+       } else if(!strcasecmp(buf, "join")) {
+               if(!arg) {
+                       fprintf(stderr, "/join requires an argument!\n");
+                       return;
+               }
+
+               if(!meshlink_join(mesh[0], arg))
+                       fprintf(stderr, "Could not join using invitation: %s\n", meshlink_strerror(meshlink_errno));
+               else
+                       fprintf(stderr, "Invitation accepted!\n");
+       } else if(!strcasecmp(buf, "kick")) {
+               if(!arg) {
+                       fprintf(stderr, "/kick requires an argument!\n");
+                       return;
+               }
+
+               meshlink_node_t *node = meshlink_get_node(mesh[0], arg);
+               if(!node) {
+                       fprintf(stderr, "Unknown node '%s'\n", arg);
+                       return;
+               }
+
+               meshlink_blacklist(mesh[0], node);
+
+               printf("Node '%s' blacklisted.\n", arg);
+       } else if(!strcasecmp(buf, "who")) {
+               if(!arg) {
+                       meshlink_node_t *nodes[100];
+                       size_t n = meshlink_get_all_nodes(mesh[0], nodes, 100);
+                       if(!n) {
+                               fprintf(stderr, "No nodes known!\n");
+                       } else {
+                               printf("Known nodes:");
+                               for(int i = 0; i < n && i < 100; i++)
+                                       printf(" %s", nodes[i]->name);
+                               if(n > 100)
+                                       printf(" (and %zu more)", n - 100);
+                               printf("\n");
+                       }
+               } else {
+                       meshlink_node_t *node = meshlink_get_node(mesh[0], arg);
+                       if(!node) {
+                               fprintf(stderr, "Unknown node '%s'\n", arg);
+                       } else {
+                               printf("Node %s found\n", arg);
+                       }
+               }
+       } else if(!strcasecmp(buf, "link")) {
+               linkmesh();
+       } else if(!strcasecmp(buf, "quit")) {
+               printf("Bye!\n");
+               fclose(stdin);
+       } else if(!strcasecmp(buf, "help")) {
+               printf(
+                       "<name>: <message>     Send a message to the given node.\n"
+                       "                      Subsequent messages don't need the <name>: prefix.\n"
+                       "/invite <name>        Create an invitation for a new node.\n"
+                       "/join <invitation>    Join an existing mesh using an invitation.\n"
+                       "/kick <name>          Blacklist the given node.\n"
+                       "/who [<name>]         List all nodes or show information about the given node.\n"
+                       "/link                 Link all nodes together.\n"
+                       "/quit                 Exit this program.\n"
+                       );
+       } else {
+               fprintf(stderr, "Unknown command '/%s'\n", buf);
+       }
+}
+
+static void parse_input(char *buf) {
+       static meshlink_node_t *destination;
+       size_t len;
+
+       if(!buf)
+               return;
+
+       // Remove newline.
+
+       len = strlen(buf);
+
+       if(len && buf[len - 1] == '\n')
+               buf[--len] = 0;
+
+       if(len && buf[len - 1] == '\r')
+               buf[--len] = 0;
+
+       // Ignore empty lines.
+
+       if(!len)
+               return;
+
+       // Commands start with '/'
+
+       if(*buf == '/')
+               return parse_command(buf + 1);
+
+       // Lines in the form "name: message..." set the destination node.
+
+       char *msg = buf;
+       char *colon = strchr(buf, ':');
+
+       if(colon) {
+               *colon = 0;
+               msg = colon + 1;
+               if(*msg == ' ')
+                       msg++;
+
+               destination = meshlink_get_node(mesh[0], buf);
+               if(!destination) {
+                       fprintf(stderr, "Unknown node '%s'\n", buf);
+                       return;
+               }
+       }
+
+       if(!destination) {
+               fprintf(stderr, "Who are you talking to? Write 'name: message...'\n");
+               return;
+       }
+
+       if(!meshlink_send(mesh[0], destination, msg, strlen(msg) + 1)) {
+               fprintf(stderr, "Could not send message to '%s': %s\n", destination->name, meshlink_strerror(meshlink_errno));
+               return;
+       }
+
+       printf("Message sent to '%s'.\n", destination->name);
+}
+
+int main(int argc, char *argv[]) {
+       const char *basebase = ".manynodes";
+       char buf[1024];
+
+       if(argc > 1)
+               n = atoi(argv[1]);
+
+       if(n < 1) {
+               fprintf(stderr, "Usage: %s [number of local nodes] [confbase]\n", argv[0]);
+               return 1;
+       }
+
+       if(argc > 2)
+               basebase = argv[2];
+
+       mesh = calloc(n, sizeof *mesh);
+
+       mkdir(basebase, 0750);
+
+       char filename[PATH_MAX];
+       char nodename[100];
+       for(int i = 0; i < n; i++) {
+               snprintf(nodename, sizeof nodename, "node%d", i);
+               snprintf(filename, sizeof filename, "%s/%s", basebase, nodename);
+               bool itsnew = access(filename, R_OK);
+               mesh[i] = meshlink_open(filename, nodename);
+               if(itsnew)
+                       meshlink_add_address(mesh[i], "localhost");
+               if(!mesh[i]) {
+                       fprintf(stderr, "errno is: %d\n", meshlink_errno);
+                       fprintf(stderr, "Could not open %s: %s\n", filename, meshlink_strerror(meshlink_errno));
+                       return 1;
+               }
+       }
+
+       int started = 0;
+
+       for(int i = 0; i < n; i++) {
+               if(!meshlink_start(mesh[i]))
+                       fprintf(stderr, "Could not start node %d: %s\n", i, meshlink_strerror(meshlink_errno));
+               else
+                       started++;
+       }
+
+       if(!started) {
+               fprintf(stderr, "Could not start any node!\n");
+               return 1;
+       }
+
+       printf("%d nodes started.\nType /help for a list of commands.\n", started);
+
+       while(fgets(buf, sizeof buf, stdin))
+               parse_input(buf);
+
+       printf("Nodes stopping.\n");
+
+       for(int i = 0; i < n; i++)
+               meshlink_close(mesh[i]);
+
+       return 0;
+}