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