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