]> git.meshlink.io Git - meshlink/blob - examples/manynodes.c
json export of node and edge structure
[meshlink] / examples / manynodes.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <strings.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <linux/limits.h>
8
9 #include "../src/meshlink.h"
10 #include "../src/devtools.h"
11
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <errno.h>
15
16 static int n = 10;
17 static meshlink_handle_t **mesh;
18
19 static meshlink_node_t **nodes;
20 static size_t nnodes;
21
22 static void log_message(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *text) {
23         const char *levelstr[] = {
24                 [MESHLINK_DEBUG] = "\x1b[34mDEBUG",
25                 [MESHLINK_INFO] = "\x1b[32mINFO",
26                 [MESHLINK_WARNING] = "\x1b[33mWARNING",
27                 [MESHLINK_ERROR] = "\x1b[31mERROR",
28                 [MESHLINK_CRITICAL] = "\x1b[31mCRITICAL",
29         };
30         fprintf(stderr, "%s\t%s:\x1b[0m %s\n", mesh ? mesh->name : "global",levelstr[level], text);
31 }
32
33 //Test mesh sending data
34 static void testmesh () {
35
36         for(int nindex = 0; nindex < n; nindex++) {
37
38                         nodes = meshlink_get_all_nodes(mesh[nindex], nodes, &nnodes);
39                         if(!nodes) {
40                                 fprintf(stderr, "Could not get list of nodes: %s\n", meshlink_strerror(meshlink_errno));
41                         } else {
42                                 printf("%zu known nodes:\n", nnodes);
43                                 for(int i = 0; i < nnodes; i++) {
44                                         //printf(" %s\n", nodes[i]->name);
45                                                 if(!meshlink_send(mesh[nindex], nodes[i], "magic", strlen("magic") + 1)) {
46                 fprintf(stderr, "Could not send message to '%s': %s\n", nodes[i]->name, meshlink_strerror(meshlink_errno));
47                                                 }
48                                 }
49
50                         }
51
52         }
53 }
54 // Make all nodes know about each other by importing each others public keys and addresses.
55 static void linkmesh() {
56         for(int i = 0; i < n; i++) {
57                 char *datai = meshlink_export(mesh[i]);
58
59                 for(int j = i + 1; j < n; j++) {
60                         char *dataj = meshlink_export(mesh[j]);
61                         meshlink_import(mesh[i], dataj);
62                         meshlink_import(mesh[j], datai);
63                         free(dataj);
64                 }
65
66                 free(datai);
67         }
68 }
69
70 static bool exportmeshgraph(const char* path)
71 {
72         struct stat ps;
73         int psr = stat(path, &ps);
74
75         if(psr == 0 || errno != ENOENT)
76         {
77                 if(psr == -1)
78                         { perror("stat"); }
79                 else
80                         { fprintf(stderr, "%s exists already\n", path); }
81
82                 return false;
83         }
84
85         FILE* stream = fopen(path, "w");
86
87         if(!stream)
88         {
89                 perror("stream");
90                 return false;
91         }
92
93         if(!devtool_export_json_all_edges_state(mesh[0], stream))
94         {
95                 fclose(stream);
96                 fprintf(stderr, "could not export graph\n");
97                 return false;
98         }
99
100         fclose(stream);
101         return true;
102 }
103
104 static void parse_command(char *buf) {
105         char *arg = strchr(buf, ' ');
106         if(arg)
107                 *arg++ = 0;
108
109         if(!strcasecmp(buf, "invite")) {
110                 char *invitation;
111
112                 if(!arg) {
113                         fprintf(stderr, "/invite requires an argument!\n");
114                         return;
115                 }
116
117                 invitation = meshlink_invite(mesh[0], arg);
118                 if(!invitation) {
119                         fprintf(stderr, "Could not invite '%s': %s\n", arg, meshlink_strerror(meshlink_errno));
120                         return;
121                 }
122
123                 printf("Invitation for %s: %s\n", arg, invitation);
124                 free(invitation);
125         } else if(!strcasecmp(buf, "join")) {
126                 if(!arg) {
127                         fprintf(stderr, "/join requires an argument!\n");
128                         return;
129                 }
130                 meshlink_stop(mesh[0]);
131                 if(!meshlink_join(mesh[0], arg))
132                         fprintf(stderr, "Could not join using invitation: %s\n", meshlink_strerror(meshlink_errno));
133                 else {
134                         fprintf(stderr, "Invitation accepted!\n");
135                         meshlink_start(mesh[0]);
136                 }
137         } else if(!strcasecmp(buf, "kick")) {
138                 if(!arg) {
139                         fprintf(stderr, "/kick requires an argument!\n");
140                         return;
141                 }
142
143                 meshlink_node_t *node = meshlink_get_node(mesh[0], arg);
144                 if(!node) {
145                         fprintf(stderr, "Unknown node '%s'\n", arg);
146                         return;
147                 }
148
149                 meshlink_blacklist(mesh[0], node);
150
151                 printf("Node '%s' blacklisted.\n", arg);
152         } else if(!strcasecmp(buf, "who")) {
153                 if(!arg) {
154                         nodes = meshlink_get_all_nodes(mesh[0], nodes, &nnodes);
155                         if(!nodes) {
156                                 fprintf(stderr, "Could not get list of nodes: %s\n", meshlink_strerror(meshlink_errno));
157                         } else {
158                                 printf("%zu known nodes:", nnodes);
159                                 for(int i = 0; i < nnodes; i++)
160                                         printf(" %s", nodes[i]->name);
161                                 printf("\n");
162                         }
163                 } else {
164                         meshlink_node_t *node = meshlink_get_node(mesh[0], arg);
165                         if(!node) {
166                                 fprintf(stderr, "Unknown node '%s'\n", arg);
167                         } else {
168                                 printf("Node %s found, pmtu %zd\n", arg, meshlink_get_pmtu(mesh[0], node));
169                         }
170                 }
171         } else if(!strcasecmp(buf, "link")) {
172                 linkmesh();
173         } else if(!strcasecmp(buf, "eg")) {
174                 exportmeshgraph(arg);
175         } else if(!strcasecmp(buf, "test")) {
176                 testmesh();
177         } else if(!strcasecmp(buf, "quit")) {
178                 printf("Bye!\n");
179                 fclose(stdin);
180         } else if(!strcasecmp(buf, "help")) {
181                 printf(
182                         "<name>: <message>     Send a message to the given node.\n"
183                         "                      Subsequent messages don't need the <name>: prefix.\n"
184                         "/invite <name>        Create an invitation for a new node.\n"
185                         "/join <invitation>    Join an existing mesh using an invitation.\n"
186                         "/kick <name>          Blacklist the given node.\n"
187                         "/who [<name>]         List all nodes or show information about the given node.\n"
188                         "/link                 Link all nodes together.\n"
189                         "/eg <path>            Export graph as json file.\n"
190                         "/test                 Test functionality sending some data to all nodes\n"
191                         "/quit                 Exit this program.\n"
192                         );
193         } else {
194                 fprintf(stderr, "Unknown command '/%s'\n", buf);
195         }
196 }
197
198 static void parse_input(char *buf) {
199         static meshlink_node_t *destination;
200         size_t len;
201
202         if(!buf)
203                 return;
204
205         // Remove newline.
206
207         len = strlen(buf);
208
209         if(len && buf[len - 1] == '\n')
210                 buf[--len] = 0;
211
212         if(len && buf[len - 1] == '\r')
213                 buf[--len] = 0;
214
215         // Ignore empty lines.
216
217         if(!len)
218                 return;
219
220         // Commands start with '/'
221
222         if(*buf == '/')
223                 return parse_command(buf + 1);
224
225         // Lines in the form "name: message..." set the destination node.
226
227         char *msg = buf;
228         char *colon = strchr(buf, ':');
229
230         if(colon) {
231                 *colon = 0;
232                 msg = colon + 1;
233                 if(*msg == ' ')
234                         msg++;
235
236                 destination = meshlink_get_node(mesh[0], buf);
237                 if(!destination) {
238                         fprintf(stderr, "Unknown node '%s'\n", buf);
239                         return;
240                 }
241         }
242
243         if(!destination) {
244                 fprintf(stderr, "Who are you talking to? Write 'name: message...'\n");
245                 return;
246         }
247
248         if(!meshlink_send(mesh[0], destination, msg, strlen(msg) + 1)) {
249                 fprintf(stderr, "Could not send message to '%s': %s\n", destination->name, meshlink_strerror(meshlink_errno));
250                 return;
251         }
252
253         printf("Message sent to '%s'.\n", destination->name);
254 }
255
256 int main(int argc, char *argv[]) {
257         const char *basebase = ".manynodes";
258         const char *namesprefix = "machine1";
259         char buf[1024];
260
261         if(argc > 1)
262                 n = atoi(argv[1]);
263
264         if(n < 1) {
265                 fprintf(stderr, "Usage: %s [number of local nodes] [confbase] [prefixnodenames]\n", argv[0]);
266                 return 1;
267         }
268
269         if(argc > 2)
270                 basebase = argv[2];
271
272         if(argc > 3)
273                 namesprefix = argv[3];
274
275         mesh = calloc(n, sizeof *mesh);
276
277         meshlink_set_log_cb(NULL, MESHLINK_INFO, log_message);
278         mkdir(basebase, 0750);
279
280         char filename[PATH_MAX];
281         char nodename[100];
282         for(int i = 0; i < n; i++) {
283                 snprintf(nodename, sizeof nodename, "%snode%d", namesprefix,i);
284                 snprintf(filename, sizeof filename, "%s/%s", basebase, nodename);
285                 bool itsnew = access(filename, R_OK);
286                 mesh[i] = meshlink_open(filename, nodename, "manynodes", i%_DEV_CLASS_MAX);
287                 meshlink_set_log_cb(mesh[i], MESHLINK_INFO, log_message);
288                 if(itsnew)
289                         meshlink_add_address(mesh[i], "localhost");
290                 if(!mesh[i]) {
291                         fprintf(stderr, "errno is: %d\n", meshlink_errno);
292                         fprintf(stderr, "Could not open %s: %s\n", filename, meshlink_strerror(meshlink_errno));
293                         return 1;
294                 }
295         }
296
297         int started = 0;
298
299         for(int i = 0; i < n; i++) {
300                 if(!meshlink_start(mesh[i]))
301                         fprintf(stderr, "Could not start node %d: %s\n", i, meshlink_strerror(meshlink_errno));
302                 else
303                         started++;
304         }
305
306         if(!started) {
307                 fprintf(stderr, "Could not start any node!\n");
308                 return 1;
309         }
310
311         printf("%d nodes started.\nType /help for a list of commands.\n", started);
312
313         while(fgets(buf, sizeof buf, stdin))
314                 parse_input(buf);
315
316         printf("Nodes stopping.\n");
317
318         for(int i = 0; i < n; i++)
319                 meshlink_close(mesh[i]);
320
321         return 0;
322 }