serialized LQ data is not always 4 bytes long, so we need a function to precalculate...
[olsrd.git] / src / olsr_comport_txt.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
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 #include <string.h>
42
43 #include "olsr_cfg.h"
44 #include "olsr_logging.h"
45 #include "olsr_cookie.h"
46 #include "olsr_ip_acl.h"
47 #include "olsr.h"
48 #include "scheduler.h"
49 #include "olsr_comport.h"
50 #include "olsr_comport_txt.h"
51 #include "plugin_loader.h"
52
53 struct txt_repeat_data {
54   struct timer_entry *timer;
55   struct autobuf *buf;
56   char *cmd;
57   char *param;
58   bool csv;
59 };
60
61 static struct avl_tree txt_normal_tree, txt_csv_tree, txt_help_tree;
62 static struct olsr_cookie_info *txtcommand_cookie, *txt_repeattimer_cookie;
63
64 static enum olsr_txtcommand_result olsr_txtcmd_quit(
65     struct comport_connection *con, char *cmd, char *param);
66 static enum olsr_txtcommand_result olsr_txtcmd_help(
67     struct comport_connection *con, char *cmd, char *param);
68 static enum olsr_txtcommand_result olsr_txtcmd_csv(
69     struct comport_connection *con, char *cmd, char *param);
70 static enum olsr_txtcommand_result olsr_txtcmd_csvoff(
71     struct comport_connection *con, char *cmd, char *param);
72 static enum olsr_txtcommand_result olsr_txtcmd_repeat(
73     struct comport_connection *con, char *cmd, char *param);
74 static enum olsr_txtcommand_result olsr_txtcmd_timeout(
75     struct comport_connection *con, char *cmd, char *param);
76 static enum olsr_txtcommand_result olsr_txtcmd_version(
77     struct comport_connection *con, char *cmd, char *param);
78 static enum olsr_txtcommand_result olsr_txtcmd_plugin(
79     struct comport_connection *con, char *cmd, char *param);
80 static enum olsr_txtcommand_result olsr_txtcmd_displayhelp(
81     struct comport_connection *con, char *cmd, char *param);
82
83
84 static const char *txt_internal_names[] = {
85   "quit",
86   "exit",
87   "help",
88   "csv",
89   "csvoff",
90   "repeat",
91   "timeout",
92   "version",
93   "plugin"
94 };
95
96 static const char *txt_internal_help[] = {
97   "shuts down the terminal connection\n",
98   "shuts down the terminal connection\n",
99   "display the online help text\n",
100   "activates the csv (comma separated value) flag\n",
101   "deactivates the csv (comma separated value) flag\n",
102   "repeat <interval> <command>: repeats a command every <interval> seconds\n",
103   "timeout <interval>: set the timeout interval to <interval> seconds, 0 means no timeout\n"
104   "displays the version of the olsrd\n"
105   "control olsr plugins dynamically, parameters are 'list', 'activate <plugin>', 'deactivate <plugin>', "
106     "'load <plugin>' and 'unload <plugin>'"
107 };
108
109 static olsr_txthandler txt_internal_handlers[] = {
110   olsr_txtcmd_quit,
111   olsr_txtcmd_quit,
112   olsr_txtcmd_help,
113   olsr_txtcmd_csv,
114   olsr_txtcmd_csvoff,
115   olsr_txtcmd_repeat,
116   olsr_txtcmd_timeout,
117   olsr_txtcmd_version,
118   olsr_txtcmd_plugin
119 };
120
121 void olsr_com_init_txt(void) {
122   size_t i;
123
124   avl_init(&txt_normal_tree, &avl_comp_strcasecmp);
125   avl_init(&txt_csv_tree, &avl_comp_strcasecmp);
126   avl_init(&txt_help_tree, &avl_comp_strcasecmp);
127
128   txtcommand_cookie = olsr_alloc_cookie("comport txt commands", OLSR_COOKIE_TYPE_MEMORY);
129   olsr_cookie_set_memory_size(txtcommand_cookie, sizeof(struct olsr_txtcommand));
130
131   txt_repeattimer_cookie = olsr_alloc_cookie("txt repeat timer", OLSR_COOKIE_TYPE_TIMER);
132
133   for (i=0; i < ARRAYSIZE(txt_internal_names); i++) {
134     olsr_com_add_normal_txtcommand(txt_internal_names[i], txt_internal_handlers[i]);
135     olsr_com_add_csv_txtcommand(txt_internal_names[i], txt_internal_handlers[i]);
136     olsr_com_add_help_txtcommand(txt_internal_names[i], olsr_txtcmd_displayhelp);
137   }
138 }
139
140 struct olsr_txtcommand *
141 olsr_com_add_normal_txtcommand (const char *command, olsr_txthandler handler) {
142   struct olsr_txtcommand *txt;
143
144   txt = olsr_cookie_malloc(txtcommand_cookie);
145   txt->node.key = strdup(command);
146   txt->handler = handler;
147
148   avl_insert(&txt_normal_tree, &txt->node, AVL_DUP_NO);
149   return txt;
150 }
151
152 struct olsr_txtcommand *
153 olsr_com_add_csv_txtcommand (const char *command, olsr_txthandler handler) {
154   struct olsr_txtcommand *txt;
155
156   txt = olsr_cookie_malloc(txtcommand_cookie);
157   txt->node.key = strdup(command);
158   txt->handler = handler;
159
160   avl_insert(&txt_csv_tree, &txt->node, AVL_DUP_NO);
161   return txt;
162 }
163
164 struct olsr_txtcommand *
165 olsr_com_add_help_txtcommand (const char *command, olsr_txthandler handler) {
166   struct olsr_txtcommand *txt;
167
168   txt = olsr_cookie_malloc(txtcommand_cookie);
169   txt->node.key = strdup(command);
170   txt->handler = handler;
171
172   avl_insert(&txt_help_tree, &txt->node, AVL_DUP_NO);
173   return txt;
174 }
175
176 void olsr_com_remove_normal_txtcommand (struct olsr_txtcommand *cmd) {
177   avl_delete(&txt_normal_tree, &cmd->node);
178   free(cmd->node.key);
179   olsr_cookie_free(txtcommand_cookie, cmd);
180 }
181
182 void olsr_com_remove_csv_txtcommand (struct olsr_txtcommand *cmd) {
183   avl_delete(&txt_csv_tree, &cmd->node);
184   free(cmd->node.key);
185   olsr_cookie_free(txtcommand_cookie, cmd);
186 }
187
188 void olsr_com_remove_help_txtcommand (struct olsr_txtcommand *cmd) {
189   avl_delete(&txt_help_tree, &cmd->node);
190   free(cmd->node.key);
191   olsr_cookie_free(txtcommand_cookie, cmd);
192 }
193
194 enum olsr_txtcommand_result
195 olsr_com_handle_txtcommand(struct comport_connection *con, char *cmd, char *param) {
196   struct olsr_txtcommand *ptr;
197
198   ptr = (struct olsr_txtcommand *) avl_find(con->is_csv ? (&txt_csv_tree) : (&txt_normal_tree), cmd);
199
200   OLSR_DEBUG(LOG_COMPORT, "Looking for command '%s' (%s): %s\n",
201     cmd, con->is_csv ? "csv" : "normal", ptr ? "unknown" : "available");
202   if (ptr == NULL) {
203     return UNKNOWN;
204   }
205
206   if (ptr->acl) {
207     if (!ip_acl_acceptable(ptr->acl, &con->addr, olsr_cnf->ip_version)) {
208       return UNKNOWN;
209     }
210   }
211
212   return ptr->handler(con, cmd, param);
213 }
214
215 static enum olsr_txtcommand_result
216 olsr_txtcmd_quit(struct comport_connection *con __attribute__ ((unused)),
217     char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused))) {
218   return QUIT;
219 }
220
221 static enum olsr_txtcommand_result
222 olsr_txtcmd_displayhelp(struct comport_connection *con,
223     char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused))) {
224   size_t i;
225
226   for (i=0; i<ARRAYSIZE(txt_internal_names); i++) {
227     if (strcasecmp(txt_internal_names[i], cmd) == 0) {
228       abuf_puts(&con->out, txt_internal_help[i]);
229       return CONTINUE;
230     }
231   }
232   return UNKNOWN;
233 }
234
235 static enum olsr_txtcommand_result
236 olsr_txtcmd_help(struct comport_connection *con,
237     char *cmd __attribute__ ((unused)), char *param) {
238   struct olsr_txtcommand *ptr;
239
240   if (param != NULL) {
241     ptr = (struct olsr_txtcommand *)avl_find(&txt_help_tree, cmd);
242     if (ptr != NULL) {
243       return ptr->handler(con, param, NULL);
244     }
245     return UNKNOWN;
246   }
247
248   if (!con->is_csv) {
249     abuf_puts(&con->out, "Known commands:\n");
250   }
251
252   ptr = (struct olsr_txtcommand *)avl_walk_first(con->is_csv ? (&txt_csv_tree) : (&txt_normal_tree));
253   while (ptr) {
254     abuf_appendf(&con->out, con->is_csv ? ",%s" : "  %s\n", (char *)ptr->node.key);
255     ptr = (struct olsr_txtcommand *)avl_walk_next(&ptr->node);
256   }
257
258   abuf_puts(&con->out, con->is_csv ? "\n" : "Use 'help <command> to see a help text for a certain command\n");
259   return CONTINUE;
260 }
261
262 static enum olsr_txtcommand_result
263 olsr_txtcmd_csv(struct comport_connection *con,
264     char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused))) {
265   con->is_csv = true;
266   return CONTINUE;
267 }
268
269 static enum olsr_txtcommand_result
270 olsr_txtcmd_csvoff(struct comport_connection *con,
271     char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused))) {
272   con->is_csv = false;
273   return CONTINUE;
274 }
275
276 static enum olsr_txtcommand_result
277 olsr_txtcmd_timeout(struct comport_connection *con,
278     char *cmd __attribute__ ((unused)), char *param) {
279   con->timeout_value = (uint32_t)strtoul(param, NULL, 10);
280   return CONTINUE;
281 }
282
283 static void olsr_txt_repeat_stophandler(struct comport_connection *con) {
284   olsr_stop_timer((struct timer_entry *)con->stop_data[0]);
285   free(con->stop_data[1]);
286
287   con->stop_handler = NULL;
288   con->stop_data[0] = NULL;
289   con->stop_data[1] = NULL;
290   con->stop_data[2] = NULL;
291 }
292
293 static void olsr_txt_repeat_timer(void *data) {
294   struct comport_connection *con = data;
295
296   if (olsr_com_handle_txtcommand(con, con->stop_data[1], con->stop_data[2]) != CONTINUE) {
297     con->stop_handler(con);
298   }
299   olsr_com_activate_output(con);
300 }
301
302 static enum olsr_txtcommand_result
303 olsr_txtcmd_repeat(struct comport_connection *con, char *cmd __attribute__ ((unused)), char *param) {
304   int interval = 0;
305   char *ptr;
306   struct timer_entry *timer;
307
308   if (con->stop_handler) {
309     abuf_puts(&con->out, "Error, you cannot stack continous output commands\n");
310     return CONTINUE;
311   }
312
313   if (param == NULL || (ptr = strchr(param, ' ')) == NULL) {
314     abuf_puts(&con->out, "Missing parameters for repeat\n");
315     return CONTINUE;
316   }
317
318   ptr++;
319
320   interval = atoi(param);
321
322   timer = olsr_start_timer(interval * 1000, 0, true, &olsr_txt_repeat_timer, con, txt_repeattimer_cookie);
323   con->stop_handler = olsr_txt_repeat_stophandler;
324   con->stop_data[0] = timer;
325   con->stop_data[1] = strdup(ptr);
326   con->stop_data[2] = NULL;
327
328   /* split command/parameter and remember it */
329   ptr = strchr(con->stop_data[1], ' ');
330   if (ptr != NULL) {
331     /* found a parameter */
332     *ptr++ = 0;
333     con->stop_data[2] = ptr;
334   }
335
336   /* start command the first time */
337   if (olsr_com_handle_txtcommand(con, con->stop_data[1], con->stop_data[2]) != CONTINUE) {
338     con->stop_handler(con);
339   }
340   return CONTINOUS;
341 }
342
343 static enum olsr_txtcommand_result
344 olsr_txtcmd_version(struct comport_connection *con, char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused))) {
345   abuf_appendf(&con->out,
346       con->is_csv ? "version,%s,%s,%s\n" : " *** %s ***\n Build date: %s on %s\n http://www.olsr.org\n\n",
347       olsrd_version, build_date, build_host);
348   return CONTINUE;
349 }
350
351 static enum olsr_txtcommand_result
352 olsr_txtcmd_plugin(struct comport_connection *con, char *cmd, char *param) {
353   struct olsr_plugin *plugin;
354   char *para2 = NULL;
355   if (param == NULL || strcasecmp(param, "list") == 0) {
356     if (!con->is_csv && abuf_puts(&con->out, "Table:\n") < 0) {
357       return ABUF_ERROR;
358     }
359     OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin) {
360       if (abuf_appendf(&con->out, con->is_csv ? "%s,%s,%s": " %-30s\t%s\t%s\n",
361           plugin->p_name, plugin->active ? "active" : "", plugin->dlhandle == NULL ? "static" : "") < 0) {
362         return ABUF_ERROR;
363       }
364     } OLSR_FOR_ALL_PLUGIN_ENTRIES_END(plugin)
365     return CONTINUE;
366   }
367
368   para2 = strchr(param, ' ');
369   if (para2 == NULL) {
370     if (con->is_csv) {
371       abuf_appendf(&con->out, "Error, missing or unknown parameter\n");
372     }
373     return CONTINUE;
374   }
375   *para2++ = 0;
376
377   plugin = olsr_get_plugin(para2);
378   if (strcasecmp(param, "load") == 0) {
379     if (plugin != NULL) {
380       abuf_appendf(&con->out, "Plugin %s already loaded\n", para2);
381       return CONTINUE;
382     }
383     plugin = olsr_load_plugin(para2);
384     if (plugin != NULL) {
385       abuf_appendf(&con->out, "Plugin %s successfully loaded\n", para2);
386     }
387     else {
388       abuf_appendf(&con->out, "Could not load plugin %s\n", para2);
389     }
390     return CONTINUE;
391   }
392
393   if (plugin == NULL) {
394     if (con->is_csv) {
395       abuf_appendf(&con->out, "Error, could not find plugin '%s'.\n", para2);
396     }
397     return CONTINUE;
398   }
399   if (strcasecmp(param, "activate") == 0) {
400     if (plugin->active) {
401       abuf_appendf(&con->out, "Plugin %s already active\n", para2);
402     }
403     else if (olsr_activate_plugin(plugin)) {
404       abuf_appendf(&con->out, "Could not activate plugin %s\n", para2);
405     }
406     else {
407       abuf_appendf(&con->out, "Plugin %s successfully activated\n", para2);
408     }
409   }
410   else if (strcasecmp(param, "deactivate") == 0) {
411     if (!plugin->active) {
412       abuf_appendf(&con->out, "Plugin %s is not active\n", para2);
413     }
414     else if (olsr_deactivate_plugin(plugin)) {
415       abuf_appendf(&con->out, "Could not deactivate plugin %s\n", para2);
416     }
417     else {
418       abuf_appendf(&con->out, "Plugin %s successfully deactivated\n", para2);
419     }
420   }
421   else if (strcasecmp(param, "unload") == 0) {
422     if (plugin->dlhandle == NULL) {
423       abuf_appendf(&con->out, "Plugin %s is static and cannot be unloaded\n", para2);
424     }
425     else if (olsr_unload_plugin(plugin)) {
426       abuf_appendf(&con->out, "Could not unload plugin %s\n", para2);
427     }
428     else {
429       abuf_appendf(&con->out, "Plugin %s successfully unloaded\n", para2);
430     }
431   }
432   else {
433     abuf_appendf(&con->out, "Unknown command '%s %s %s'.\n", cmd, param, para2);
434   }
435   return CONTINUE;
436 }