info: java: update workspace
[olsrd.git] / src / olsr_switch / ohs_cmd.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45
46 #include "common/string_handling.h"
47 #include "olsr_host_switch.h"
48 #include "olsr_types.h"
49 #include "commands.h"
50 #include "link_rules.h"
51 #include "ipcalc.h"
52
53 #include <string.h>
54 #include <stdlib.h>
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #include <unistd.h>
61 #include <errno.h>
62
63 #define TOK_BUF_SIZE 500
64 static char tok_buf[TOK_BUF_SIZE];
65
66 #define MAX_OLSRD_ARGS 10
67 static char olsrd_path[FILENAME_MAX];
68
69 static int
70 get_next_token(const char *src, char *dst, size_t buflen)
71 {
72   int i = 0, j = 0;
73
74   dst[0] = 0;
75   /* Skip leading spaces */
76   while (src[j] == ' ' && src[j] != 0) {
77     j++;
78   }
79
80   src += j;
81   i = 0;
82   while ((src[i] != ' ') && (src[i] != 0) && (i < ((int)buflen - 1))) {
83     dst[i] = src[i];
84     i++;
85   }
86   dst[i] = 0;
87
88   //if(strlen(dst))
89   //printf("Extracted token: %s\n", dst);
90   return i + j;
91 }
92
93 int
94 ohs_set_olsrd_path(const char *path)
95 {
96   strscpy(olsrd_path, path, sizeof(olsrd_path));
97   return 0;
98 }
99
100 #ifdef _WIN32
101 int
102 ohs_cmd_olsrd(const char *args __attribute__ ((unused)))
103 {
104   printf("olsrd command not available in windows version\nStart instances manually\n");
105   return 0;
106 }
107 #else /* _WIN32 */
108 int
109 ohs_cmd_olsrd(const char *args)
110 {
111   const char *olsrd_args[MAX_OLSRD_ARGS];
112   struct in_addr iaddr;
113
114   args += get_next_token(args, tok_buf, TOK_BUF_SIZE);
115
116   if (!strlen(tok_buf))
117     goto print_usage;
118
119   /* Start olsrd instance */
120   if (!strncmp(tok_buf, "start", strlen("start"))) {
121     int argc = 0, i = 0;
122
123     args += get_next_token(args, tok_buf, TOK_BUF_SIZE);
124
125     if (!strlen(tok_buf))
126       goto print_usage;
127
128     if (!inet_pton(AF_INET, tok_buf, &iaddr)) {
129       printf("Invalid IP %s\n", tok_buf);
130       goto print_usage;
131     }
132
133     olsrd_args[argc++] = olsrd_path;
134
135     if (1) {                    /* config file is set */
136       olsrd_args[argc++] = "-f";
137       olsrd_args[argc++] = "./olsrd.emu.conf";
138     }
139     olsrd_args[argc++] = "-hemu";
140     olsrd_args[argc++] = tok_buf;
141
142     olsrd_args[argc++] = "-d";
143     olsrd_args[argc++] = "0";
144     olsrd_args[argc++] = "-nofork";
145     olsrd_args[argc] = NULL;
146
147     printf("Executing: %s", olsrd_path);
148     for (i = 0; i < argc; i++)
149       printf(" %s", olsrd_args[i]);
150     printf("\n");
151
152     if (fork())
153       return 1;
154
155     if (execve(olsrd_path, (char *const *)olsrd_args, NULL) < 0) {
156       printf("Error executing olsrd: %s\n", strerror(errno));
157       exit(EXIT_FAILURE);
158     }
159   }
160   /* Stop olsrd instance */
161   else if (!strncmp(tok_buf, "stop", strlen("stop"))) {
162     struct ohs_connection *oc;
163
164     args += get_next_token(args, tok_buf, TOK_BUF_SIZE);
165
166     if (!strlen(tok_buf))
167       goto print_usage;
168
169     if (!inet_pton(AF_INET, tok_buf, &iaddr)) {
170       printf("Invalid IP %s\n", tok_buf);
171       goto print_usage;
172     }
173
174     oc = get_client_by_addr((union olsr_ip_addr *)&iaddr.s_addr);
175
176     if (!oc) {
177       printf("No such client: %s\n", tok_buf);
178       return -1;
179     }
180     ohs_delete_connection(oc);
181
182     return 1;
183   }
184   /* Set olsrd binary path */
185   else if (!strncmp(tok_buf, "setb", strlen("setb"))) {
186     struct stat sbuf;
187
188     args += get_next_token(args, tok_buf, TOK_BUF_SIZE);
189
190     if (!strlen(tok_buf))
191       goto print_usage;
192
193     if (stat(tok_buf, &sbuf) < 0) {
194       printf("Error setting binary \"%s\": %s\n", tok_buf, strerror(errno));
195       return -1;
196     }
197
198     if ((sbuf.st_mode & S_IFDIR) || !(sbuf.st_mode & S_IXUSR)) {
199       printf("Error setting binary \"%s\": Not a regular execuatble file!\n", tok_buf);
200       return -1;
201     }
202
203     printf("New olsrd binary path:\"%s\"\n", tok_buf);
204     ohs_set_olsrd_path(tok_buf);
205
206     return 1;
207
208   }
209   /* Set arguments */
210   else if (!strncmp(tok_buf, "seta", strlen("seta"))) {
211     printf("Error - NOT IMPLEMENTED YET\n");
212     return 1;
213   }
214   /* Show settings */
215   else if (!strncmp(tok_buf, "show", strlen("show"))) {
216     printf("olsrd command settings:\n\tBinary path: %s\n\tArguments  : \n", olsrd_path);
217     return 1;
218   }
219
220 print_usage:
221   printf("Usage: olsrd [start|stop|show|setb|seta] [IP|path|args]\n");
222   return 0;
223 }
224 #endif /* _WIN32 */
225
226 int
227 ohs_cmd_link(const char *args)
228 {
229   uint8_t bi = 0, wildc_src = 0, wildc_dst = 0;
230   struct ohs_connection *src, *dst;
231   struct in_addr iaddr;
232   int qual;
233   struct ohs_ip_link *my_link, *inv_link;
234
235   args += get_next_token(args, tok_buf, TOK_BUF_SIZE);
236
237   if (!strlen(tok_buf)) {
238     goto print_usage;
239   }
240   if (!strncmp(tok_buf, "bi", strlen("bi"))) {
241     bi = 1;
242     args += get_next_token(args, tok_buf, TOK_BUF_SIZE);
243
244     if (!strlen(tok_buf)) {
245       goto print_usage;
246     }
247   }
248
249   if (tok_buf[0] == '*') {
250     wildc_src = 1;
251     src = ohs_conns;
252   } else {
253     if (!inet_pton(AF_INET, tok_buf, &iaddr)) {
254       printf("Invalid src IP %s\n", tok_buf);
255       return -1;
256     }
257
258     src = get_client_by_addr((union olsr_ip_addr *)&iaddr.s_addr);
259
260     if (!src) {
261       printf("No such client: %s!\n", tok_buf);
262       return -1;
263     }
264   }
265
266   args += get_next_token(args, tok_buf, TOK_BUF_SIZE);
267
268   if (!strlen(tok_buf)) {
269     goto print_usage;
270   }
271
272   if (tok_buf[0] == '*') {
273     wildc_dst = 1;
274     dst = ohs_conns;
275   } else {
276     if (!inet_pton(AF_INET, tok_buf, &iaddr)) {
277       printf("Invalid src IP %s\n", tok_buf);
278       return -1;
279     }
280
281     dst = get_client_by_addr((union olsr_ip_addr *)&iaddr.s_addr);
282     if (!dst) {
283       printf("No such client: %s!\n", tok_buf);
284       return -1;
285     }
286   }
287
288   args += get_next_token(args, tok_buf, TOK_BUF_SIZE);
289
290   if (!strlen(tok_buf)) {
291     goto print_usage;
292   }
293
294   /* No use for bi if both src and dst are widcards */
295   if (wildc_src && wildc_dst) {
296     bi = 0;
297   }
298
299   qual = atoi(tok_buf);
300
301   if (qual < 0 || qual > 100) {
302     printf("Link quality out of range(0-100)\n");
303     return -1;
304   }
305
306   while (src) {
307     while (dst) {
308       struct ipaddr_str srcaddrstr, dstaddrstr;
309
310       if (src != dst) {
311         my_link = get_link(src, &dst->ip_addr);
312         inv_link = bi ? get_link(dst, &src->ip_addr) : NULL;
313         if (qual == 100) {
314           /* Remove link entry */
315           if (my_link) {
316             remove_link(src, my_link);
317           }
318           if (inv_link) {
319             remove_link(dst, inv_link);
320           }
321         } else {
322           if (!my_link) {
323             /* Create new link */
324             my_link = add_link(src, dst);
325           }
326
327           my_link->quality = qual;
328
329           if (bi) {
330             if (!inv_link) {
331               /* Create new link */
332               inv_link = add_link(dst, src);
333             }
334             inv_link->quality = qual;
335           }
336         }
337         printf("%s %sdirectional link(s) %s %c=> %s quality %d\n", (qual == 100) ? "Removing" : "Setting", bi ? "bi" : "uni",
338                olsr_ip_to_string(&srcaddrstr, &src->ip_addr), bi ? '<' : '=', olsr_ip_to_string(&dstaddrstr, &dst->ip_addr), qual);
339       }
340       if (wildc_dst) {
341         dst = dst->next;
342       } else {
343         break;
344       }
345     }
346     dst = wildc_dst ? ohs_conns : dst;
347     src = wildc_src ? src->next : NULL;
348   }
349
350   return 1;
351 print_usage:
352   printf("link <bi> srcIP dstIP [0-100]");
353   return -1;
354 }
355
356 int
357 ohs_cmd_list(const char *args)
358 {
359   struct ohs_connection *oc = ohs_conns;
360
361   args += get_next_token(args, tok_buf, TOK_BUF_SIZE);
362
363   if (!strlen(tok_buf) || !strncmp(tok_buf, "clients", strlen("clients"))) {
364     printf("All connected clients:\n");
365
366     while (oc) {
367       struct ipaddr_str addrstr;
368       printf("\t%s - Rx: %d Tx: %d LinkCnt: %d\n", olsr_ip_to_string(&addrstr, &oc->ip_addr), oc->rx, oc->tx, oc->linkcnt);
369       oc = oc->next;
370     }
371   } else if (!strncmp(tok_buf, "links", strlen("links"))) {
372     printf("All configured links:\n");
373     while (oc) {
374       struct ohs_ip_link *links = oc->links;
375       while (links) {
376         struct ipaddr_str addrstr, dststr;
377         printf("\t%s => %s Quality: %d\n", olsr_ip_to_string(&addrstr, &oc->ip_addr), olsr_ip_to_string(&dststr, &links->dst),
378                links->quality);
379
380         links = links->next;
381       }
382       oc = oc->next;
383     }
384   } else {
385     printf("list [clients|links]");
386     return -1;
387   }
388   return 1;
389 }
390
391 int
392 ohs_cmd_help(const char *args)
393 {
394   int i;
395
396   args += get_next_token(args, tok_buf, TOK_BUF_SIZE);
397
398   if (!strlen(tok_buf)) {
399     printf("Olsrd host switch version %s\n", OHS_VERSION);
400     printf("Available commands:\n");
401
402     for (i = 0; ohs_commands[i].cmd; i++) {
403       if (ohs_commands[i].helptext_brief)
404         printf("\t%s - %s\n", ohs_commands[i].cmd, ohs_commands[i].helptext_brief);
405     }
406     printf("\nType 'help cmd' for help on a specific command\n");
407   } else {
408     for (i = 0; ohs_commands[i].cmd; i++) {
409       if (!strncmp(tok_buf, ohs_commands[i].cmd, strlen(ohs_commands[i].cmd))) {
410         printf("Usage: %s\nDescription:\n%s\n", ohs_commands[i].syntax, ohs_commands[i].helptext_long);
411         return 1;
412       }
413     }
414
415     printf("Usage: help <command>\n");
416   }
417
418   return i;
419 }
420
421 int
422 ohs_cmd_log(const char *args)
423 {
424   uint8_t set = 0;
425
426   args += get_next_token(args, tok_buf, TOK_BUF_SIZE);
427
428   if (strlen(tok_buf) && ((set = !strncmp(tok_buf, "set", strlen("set"))) || !strncmp(tok_buf, "unset", strlen("unset")))) {
429     uint32_t new_bit = 0;
430
431     args += get_next_token(args, tok_buf, TOK_BUF_SIZE);
432
433     if (!strlen(tok_buf))
434       goto print_usage;
435
436     if (!strncmp(tok_buf, "CON", strlen("CON")))
437       new_bit = LOG_CONNECT;
438     else if (!strncmp(tok_buf, "FOR", strlen("FOR")))
439       new_bit = LOG_FORWARD;
440     else if (!strncmp(tok_buf, "LIN", strlen("LIN")))
441       new_bit = LOG_LINK;
442
443     if (!new_bit)
444       goto print_usage;
445
446     if (set)
447       logbits |= new_bit;
448     else
449       logbits &= ~new_bit;
450
451     printf("%s log bit: 0x%08x, new log: 0x%08x\n", set ? "Setting" : "Removing", new_bit, logbits);
452
453   } else {
454     if (strlen(tok_buf))
455       goto print_usage;
456
457     printf("Log: (0x%08x) ", logbits);
458     if (logbits & LOG_CONNECT)
459       printf("CONNECT ");
460     if (logbits & LOG_FORWARD)
461       printf("FORWARD ");
462     if (logbits & LOG_LINK)
463       printf("LINK ");
464
465     printf("\n");
466   }
467   return 1;
468
469 print_usage:
470   printf("Usage: log <[set|unset] [CONNECT|FORWARD|LINK]>\n");
471   return 0;
472
473 }
474
475 int
476 ohs_cmd_exit(const char *args __attribute__ ((unused)))
477 {
478
479   printf("Exitting... bye-bye!\n");
480
481   ohs_close(0);
482 }
483
484 void
485 ohs_parse_command(void)
486 {
487   static char cmd_line[500];
488   static int cmd_len = 0;
489   char *args;
490   char cmd_token[20];
491   int i;
492 #if defined _WIN32
493   char c;
494   unsigned long Read;
495   INPUT_RECORD InRec;
496   KEY_EVENT_RECORD *KeyEventRec;
497 #endif /* defined _WIN32 */
498
499 #if defined _WIN32
500   if (!ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &InRec, sizeof(InRec), &Read)) {
501     fprintf(stderr, "ReadConsoleInput failed: %s\n", strerror(GetLastError()));
502     return;
503   }
504
505   if (InRec.EventType != KEY_EVENT)
506     return;
507
508   KeyEventRec = &InRec.Event.KeyEvent;
509
510   if (!KeyEventRec->bKeyDown)
511     return;
512
513   c = KeyEventRec->uChar.AsciiChar;
514
515   if (c == 8) {
516     if (cmd_len == 0)
517       return;
518
519     cmd_len--;
520
521     fputc(8, stdout);
522     fputc(32, stdout);
523     fputc(8, stdout);
524
525     fflush(stdout);
526
527     return;
528   }
529
530   fputc(c, stdout);
531   fflush(stdout);
532
533   if (c != '\n' && c != '\r' && cmd_len < (int)sizeof(cmd_line) - 1)
534     cmd_line[cmd_len++] = (char)c;
535
536   else
537 #else /* defined _WIN32 */
538   if (fgets(cmd_line, sizeof(cmd_line), stdin) == NULL) {
539     ohs_cmd_exit(NULL);
540   }
541
542   for (cmd_len = 0; cmd_line[cmd_len] != 0 && cmd_line[cmd_len] != '\n'; cmd_len++) {
543     // Avoid: error: this ‘for’ clause does not guard... [-Werror=misleading-indentation]
544   }
545 #endif /* defined _WIN32 */
546
547   {
548     cmd_line[cmd_len] = 0;
549     cmd_len = 0;
550
551     args = cmd_line + get_next_token(cmd_line, cmd_token, sizeof(cmd_token));
552
553     for (i = 0; ohs_commands[i].cmd != NULL; i++) {
554       if (strcmp(cmd_token, ohs_commands[i].cmd) == 0) {
555         if (ohs_commands[i].cmd_cb != NULL)
556           ohs_commands[i].cmd_cb(args);
557
558         else
559           printf("No action registered on cmd %s!\n", cmd_token);
560
561         break;
562       }
563     }
564
565     if (ohs_commands[i].cmd == NULL)
566       printf("%s: no such cmd!\n", cmd_token);
567
568     printf("\n> ");
569     fflush(stdout);
570   }
571 }
572
573 /*
574  * Local Variables:
575  * c-basic-offset: 2
576  * indent-tabs-mode: nil
577  * End:
578  */