Debuginfo allows access to current logging output through telnet.
[olsrd.git] / lib / debuginfo / src / olsrd_debuginfo.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
42 /*
43  * Dynamic linked library for the olsr.org olsr daemon
44  */
45
46 #include <stdlib.h>
47
48 #include "olsr.h"
49 #include "ipcalc.h"
50 #include "neighbor_table.h"
51 #include "tc_set.h"
52 #include "hna_set.h"
53 #include "mid_set.h"
54 #include "routing_table.h"
55 #include "olsr_logging.h"
56 #include "olsr_ip_prefix_list.h"
57 #include "parser.h"
58 #include "olsr_comport_txt.h"
59 #include "olsrd_debuginfo.h"
60 #include "olsr_types.h"
61 #include "defs.h"
62
63 #include "common/autobuf.h"
64
65 #define PLUGIN_DESCR    "OLSRD debuginfo plugin"
66 #define PLUGIN_AUTHOR   "Henning Rogge"
67
68 struct debuginfo_cmd {
69   const char *name;
70   const char *help;
71   olsr_txthandler handler;
72   struct olsr_txtcommand *cmd, *cmdhelp;
73 };
74
75 static int debuginfo_init(void);
76 static int debuginfo_enable(void);
77 static int debuginfo_disable(void);
78
79 static enum olsr_txtcommand_result debuginfo_msgstat(struct comport_connection *con,
80     const char *cmd, const char *param);
81 static enum olsr_txtcommand_result debuginfo_pktstat(struct comport_connection *con,
82     const char *cmd, const char *param);
83 static enum olsr_txtcommand_result debuginfo_cookies(struct comport_connection *con,
84     const char *cmd, const char *param);
85 static enum olsr_txtcommand_result debuginfo_log(struct comport_connection *con,
86     const char *cmd, const char *param);
87 static enum olsr_txtcommand_result olsr_debuginfo_displayhelp(struct comport_connection *con,
88     const char *cmd, const char *param);
89
90 static void update_statistics_ptr(void *);
91 static void olsr_msg_statistics(struct olsr_message *,
92     struct interface *, union olsr_ip_addr *, enum duplicate_status);
93 static uint8_t *olsr_packet_statistics(uint8_t *binary,
94     struct interface *interface, union olsr_ip_addr *ip, int *length);
95
96 static void update_statistics_ptr(void *data __attribute__ ((unused)));
97
98 /* plugin configuration */
99 static struct ip_acl allowed_nets;
100 static uint32_t traffic_interval, traffic_slots, current_slot;
101
102 /* plugin parameters */
103 static const struct olsrd_plugin_parameters plugin_parameters[] = {
104   {.name = IP_ACL_ACCEPT_PARAP,.set_plugin_parameter = &ip_acl_add_plugin_accept,.data = &allowed_nets},
105   {.name = IP_ACL_REJECT_PARAM,.set_plugin_parameter = &ip_acl_add_plugin_reject,.data = &allowed_nets},
106   {.name = IP_ACL_CHECKFIRST_PARAM,.set_plugin_parameter = &ip_acl_add_plugin_checkFirst,.data = &allowed_nets},
107   {.name = IP_ACL_DEFAULTPOLICY_PARAM,.set_plugin_parameter = &ip_acl_add_plugin_defaultPolicy,.data = &allowed_nets},
108   {.name = "stat_interval", .set_plugin_parameter = &set_plugin_int, .data = &traffic_interval},
109   {.name = "stat_slots", .set_plugin_parameter = &set_plugin_int, .data = &traffic_slots},
110 };
111
112 OLSR_PLUGIN6(plugin_parameters) {
113   .descr = PLUGIN_DESCR,
114   .author = PLUGIN_AUTHOR,
115   .init = debuginfo_init,
116   .enable = debuginfo_enable,
117   .disable = debuginfo_disable,
118   .deactivate = false
119 };
120
121 /* command callbacks and names */
122 static struct debuginfo_cmd commands[] = {
123     {"msgstat", "Displays statistics about the incoming OLSR messages\n", &debuginfo_msgstat, NULL, NULL},
124     {"pktstat", "Displays statistics about the incoming OLSR packets\n", &debuginfo_pktstat, NULL, NULL},
125     {"cookies", "Displays statistics about memory and timer cookies\n", &debuginfo_cookies, NULL, NULL},
126     {"log",     "\"log\":      continuous output of logging to this console\n"
127                 "\"log show\": show configured logging option for debuginfo output\n"
128                 "\"log add <severity> <source1> <source2> ...\": Add one or more sources of a defined severity for logging\n"
129                 "\"log remove <severity> <source1> <source2> ...\": Remove one or more sources of a defined severity for logging\n",
130         &debuginfo_log, NULL, NULL}
131 };
132
133 /* variables for statistics */
134 static struct avl_tree stat_msg_tree, stat_pkt_tree;
135
136 static struct debug_msgtraffic_count total_msg_traffic;
137 static struct debug_pkttraffic_count total_pkt_traffic;
138
139 static struct olsr_memcookie_info *statistics_msg_mem = NULL;
140 static struct olsr_memcookie_info *statistics_pkt_mem = NULL;
141
142 static struct olsr_timer_info *statistics_timer = NULL;
143
144 static union olsr_ip_addr total_ip_addr;
145
146 /* variables for log access */
147 static bool log_debuginfo_mask[LOG_SEVERITY_COUNT][LOG_SOURCE_COUNT];
148 static int log_source_maxlen, log_severity_maxlen;
149 static struct comport_connection *log_connection;
150 static struct log_handler_entry *log_handler;
151 /**
152  *Constructor
153  */
154 static int
155 debuginfo_init(void)
156 {
157   int i;
158   ip_acl_init(&allowed_nets);
159
160   traffic_interval = 5; /* seconds */
161   traffic_slots = 12;      /* number of 5000 second slots */
162   current_slot = 0;
163
164   memset(&total_ip_addr, 255, sizeof(total_ip_addr));
165
166   /* calculate maximum length of log source names */
167   log_source_maxlen = 0;
168   for (i=1; i<LOG_SOURCE_COUNT; i++) {
169     int len = strlen(LOG_SOURCE_NAMES[i]);
170
171     if (len > log_source_maxlen) {
172       log_source_maxlen = len;
173     }
174   }
175
176   /* calculate maximum length of log severity names */
177   log_severity_maxlen = 0;
178   for (i=1; i<LOG_SEVERITY_COUNT; i++) {
179     int len = strlen(LOG_SEVERITY_NAMES[i]);
180
181     if (len > log_severity_maxlen) {
182       log_severity_maxlen = len;
183     }
184   }
185
186   memcpy(log_debuginfo_mask, log_global_mask, sizeof(log_global_mask));
187   log_connection = NULL;
188   return 0;
189 }
190
191 /**
192  *Destructor
193  */
194 static int
195 debuginfo_disable(void)
196 {
197   size_t i;
198
199   for (i=0; i<ARRAYSIZE(commands); i++) {
200     olsr_com_remove_normal_txtcommand(commands[i].cmd);
201     olsr_com_remove_help_txtcommand(commands[i].cmdhelp);
202   }
203   olsr_parser_remove_function(&olsr_msg_statistics);
204   olsr_preprocessor_remove_function(&olsr_packet_statistics);
205   ip_acl_flush(&allowed_nets);
206   return 0;
207 }
208
209 static int
210 debuginfo_enable(void)
211 {
212   size_t i;
213
214   /* always allow localhost */
215   if (olsr_cnf->ip_version == AF_INET) {
216     union olsr_ip_addr ip;
217
218     ip.v4.s_addr = ntohl(INADDR_LOOPBACK);
219     ip_acl_add(&allowed_nets, &ip, 32, false);
220   } else {
221     ip_acl_add(&allowed_nets, (const union olsr_ip_addr *)&in6addr_loopback, 128, false);
222     ip_acl_add(&allowed_nets, (const union olsr_ip_addr *)&in6addr_v4mapped_loopback, 128, false);
223   }
224
225   for (i=0; i<ARRAYSIZE(commands); i++) {
226     commands[i].cmd = olsr_com_add_normal_txtcommand(commands[i].name, commands[i].handler);
227     commands[i].cmdhelp = olsr_com_add_help_txtcommand(commands[i].name, olsr_debuginfo_displayhelp);
228     commands[i].cmd->acl = &allowed_nets;
229   }
230
231   statistics_timer = olsr_timer_add("debuginfo timer", &update_statistics_ptr, true);
232   olsr_timer_start(traffic_interval * 1000, 0, NULL, statistics_timer);
233
234   statistics_msg_mem = olsr_memcookie_add("debuginfo msgstat",
235       sizeof(struct debug_msgtraffic) + sizeof(struct debug_msgtraffic_count) * traffic_slots);
236
237   statistics_pkt_mem = olsr_memcookie_add("debuginfo pktstat",
238       sizeof(struct debug_pkttraffic) + sizeof(struct debug_pkttraffic_count) * traffic_slots);
239
240   memset(&total_msg_traffic, 0, sizeof(total_msg_traffic));
241   memset(&total_pkt_traffic, 0, sizeof(total_pkt_traffic));
242   avl_init(&stat_msg_tree, avl_comp_default, false, NULL);
243   avl_init(&stat_pkt_tree, avl_comp_default, false, NULL);
244
245   olsr_parser_add_function(&olsr_msg_statistics, PROMISCUOUS);
246   olsr_preprocessor_add_function(&olsr_packet_statistics);
247   return 0;
248 }
249
250 static struct debug_msgtraffic *get_msgtraffic_entry(union olsr_ip_addr *ip) {
251   struct debug_msgtraffic *tr;
252   tr = (struct debug_msgtraffic *) avl_find(&stat_msg_tree, ip);
253   if (tr == NULL) {
254     tr = olsr_memcookie_malloc(statistics_msg_mem);
255
256     memcpy(&tr->ip, ip, sizeof(union olsr_ip_addr));
257     tr->node.key = &tr->ip;
258
259     avl_insert(&stat_msg_tree, &tr->node);
260   }
261   return tr;
262 }
263
264 static struct debug_pkttraffic *get_pkttraffic_entry(union olsr_ip_addr *ip, struct interface *in) {
265   struct debug_pkttraffic *tr;
266   tr = (struct debug_pkttraffic *) avl_find(&stat_pkt_tree, ip);
267   if (tr == NULL) {
268     tr = olsr_memcookie_malloc(statistics_pkt_mem);
269
270     memcpy(&tr->ip, ip, sizeof(union olsr_ip_addr));
271     tr->node.key = &tr->ip;
272
273     tr->int_name = strdup(in ? in->int_name : "---");
274
275     avl_insert(&stat_pkt_tree, &tr->node);
276   }
277   return tr;
278 }
279
280 static void
281 update_statistics_ptr(void *data __attribute__ ((unused)))
282 {
283   struct debug_msgtraffic *msg, *msg_iterator;
284   struct debug_pkttraffic *pkt, *pkt_iterator;
285   uint32_t last_slot, i;
286
287   last_slot = current_slot;
288   current_slot++;
289   if (current_slot == traffic_slots) {
290     current_slot = 0;
291   }
292
293   /* move data from "current" template to slot array */
294   OLSR_FOR_ALL_MSGTRAFFIC_ENTRIES(msg, msg_iterator) {
295     /* subtract old values from node count and total count */
296     for (i=0; i<DTR_MSG_COUNT; i++) {
297       msg->total.data[i] -= msg->traffic[current_slot].data[i];
298     }
299
300     /* copy new traffic into slot */
301     msg->traffic[current_slot] = msg->current;
302
303     /* add new values to node count and total count */
304     for (i=0; i<DTR_MSG_COUNT; i++) {
305       msg->total.data[i] += msg->current.data[i];
306     }
307
308     /* erase new traffic */
309     memset(&msg->current, 0, sizeof(msg->current));
310
311     if (msg->total.data[DTR_MESSAGES] == 0) {
312       /* no traffic left, cleanup ! */
313
314       avl_delete(&stat_msg_tree, &msg->node);
315       olsr_memcookie_free(statistics_msg_mem, msg);
316     }
317   }
318
319   OLSR_FOR_ALL_PKTTRAFFIC_ENTRIES(pkt, pkt_iterator) {
320     /* subtract old values from node count and total count */
321     for (i=0; i<DTR_PKT_COUNT; i++) {
322       pkt->total.data[i] -= pkt->traffic[current_slot].data[i];
323     }
324
325     /* copy new traffic into slot */
326     pkt->traffic[current_slot] = pkt->current;
327
328     /* add new values to node count and total count */
329     for (i=0; i<DTR_PKT_COUNT; i++) {
330       pkt->total.data[i] += pkt->current.data[i];
331     }
332
333     /* erase new traffic */
334     memset(&pkt->current, 0, sizeof(pkt->current));
335
336     if (pkt->total.data[DTR_PACKETS] == 0) {
337       /* no traffic left, cleanup ! */
338
339       avl_delete(&stat_pkt_tree, &pkt->node);
340       free(pkt->int_name);
341       olsr_memcookie_free(statistics_pkt_mem, pkt);
342     }
343   }
344 }
345
346 /* update message statistics */
347 static void
348 olsr_msg_statistics(struct olsr_message *msg,
349     struct interface *input_if __attribute__ ((unused)),
350     union olsr_ip_addr *from_addr __attribute__ ((unused)), enum duplicate_status status  __attribute__ ((unused)))
351 {
352   enum debug_msgtraffic_type type;
353   struct debug_msgtraffic *tr;
354 #if !defined REMOVE_LOG_DEBUG
355   struct ipaddr_str buf;
356 #endif
357
358   switch (msg->type) {
359   case HELLO_MESSAGE:
360     type = DTR_HELLO;
361     break;
362   case TC_MESSAGE:
363     type = DTR_TC;
364     break;
365   case MID_MESSAGE:
366     type = DTR_MID;
367     break;
368   case HNA_MESSAGE:
369     type = DTR_HNA;
370     break;
371   case LQ_HELLO_MESSAGE:
372     type = DTR_HELLO;
373     break;
374   case LQ_TC_MESSAGE:
375     type = DTR_TC;
376     break;
377   default:
378     type = DTR_OTHER;
379     break;
380   }
381
382   /* input data for specific node */
383   tr = get_msgtraffic_entry(&msg->originator);
384   tr->current.data[type]++;
385   tr->current.data[DTR_MESSAGES]++;
386   tr->current.data[DTR_MSG_TRAFFIC] += msg->size;
387
388   OLSR_DEBUG(LOG_PLUGINS, "Added message type %d to statistics of %s: %d\n",
389       type, olsr_ip_to_string(&buf, &tr->ip), tr->current.data[type]);
390
391   /* input data for total traffic handling */
392   tr = get_msgtraffic_entry(&total_ip_addr);
393   tr->current.data[type]++;
394   tr->current.data[DTR_MESSAGES]++;
395   tr->current.data[DTR_MSG_TRAFFIC] += msg->size;
396 }
397
398 /* update traffic statistics */
399 static uint8_t *
400 olsr_packet_statistics(uint8_t *binary, struct interface *interface, union olsr_ip_addr *ip, int *length)
401 {
402   struct debug_pkttraffic *tr;
403   tr = get_pkttraffic_entry(ip, interface);
404   tr->current.data[DTR_PACK_TRAFFIC] += *length;
405   tr->current.data[DTR_PACKETS] ++;
406
407   tr = get_pkttraffic_entry(&total_ip_addr, NULL);
408   tr->current.data[DTR_PACK_TRAFFIC] += *length;
409   tr->current.data[DTR_PACKETS] ++;
410   return binary;
411 }
412
413 static const char *debuginfo_print_trafficip(struct ipaddr_str *buf, union olsr_ip_addr *ip) {
414   static const char *total = "Total";
415   if (olsr_ipcmp(ip, &total_ip_addr) == 0) {
416     return total;
417   }
418   return olsr_ip_to_string(buf, ip);
419 }
420
421 static bool debuginfo_print_msgstat(struct autobuf *buf, union olsr_ip_addr *ip, struct debug_msgtraffic_count *cnt) {
422   struct ipaddr_str strbuf;
423   return abuf_appendf(buf, "%-*s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t\n",
424       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, debuginfo_print_trafficip(&strbuf, ip),
425       cnt->data[DTR_HELLO],
426       cnt->data[DTR_TC],
427       cnt->data[DTR_MID],
428       cnt->data[DTR_HNA],
429       cnt->data[DTR_OTHER],
430       cnt->data[DTR_MESSAGES],
431       cnt->data[DTR_MSG_TRAFFIC]) < 0;
432 }
433
434 static enum olsr_txtcommand_result
435 debuginfo_msgstat(struct comport_connection *con,
436     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
437 {
438   struct debug_msgtraffic *tr, *iterator;
439
440   if (abuf_appendf(&con->out, "Slot size: %d seconds\tSlot count: %d\n", traffic_interval, traffic_slots) < 0) {
441     return ABUF_ERROR;
442   }
443   if (abuf_appendf(&con->out,
444       "Table: Statistics (without duplicates)\n%-*s\tHello\tTC\tMID\tHNA\tOther\tTotal\tBytes\n",
445       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, "IP"
446       ) < 0) {
447     return ABUF_ERROR;
448   }
449
450   if (param == NULL || strcasecmp(param, "node") == 0) {
451     OLSR_FOR_ALL_MSGTRAFFIC_ENTRIES(tr, iterator) {
452       if (debuginfo_print_msgstat(&con->out, &tr->ip, &tr->traffic[current_slot])) {
453         return ABUF_ERROR;
454       }
455     }
456   }
457   else {
458     uint32_t mult = 1, divisor = 1;
459     struct debug_msgtraffic_count cnt;
460     int i;
461
462     if (strcasecmp(param, "total") == 0) {
463       divisor = 1;
464     }
465     else if (strcasecmp(param, "average") == 0) {
466       divisor = traffic_slots;
467     }
468     else if (strcasecmp(param, "avgsec") == 0) {
469       divisor = traffic_slots * traffic_interval;
470       mult = 1;
471     }
472     else if (strcasecmp(param, "avgmin") == 0) {
473       divisor = traffic_slots * traffic_interval;
474       mult = 60;
475     }
476     else if (strcasecmp(param, "avghour") == 0) {
477       divisor = traffic_slots * traffic_interval;
478       mult = 3600;
479     }
480     else {
481       abuf_appendf(&con->out, "Error, unknown parameter %s for msgstat\n", param);
482       return CONTINUE;
483     }
484
485     OLSR_FOR_ALL_MSGTRAFFIC_ENTRIES(tr, iterator) {
486       for (i=0; i<DTR_MSG_COUNT; i++) {
487         cnt.data[i] = (tr->total.data[i] * mult) / divisor;
488       }
489       if (debuginfo_print_msgstat(&con->out, &tr->ip, &cnt)) {
490         return ABUF_ERROR;
491       }
492     }
493   }
494
495   return CONTINUE;
496 }
497
498 static bool debuginfo_print_pktstat(struct autobuf *buf, union olsr_ip_addr *ip, char *int_name, struct debug_pkttraffic_count *cnt) {
499   struct ipaddr_str strbuf;
500   return abuf_appendf(buf, "%-*s\t%s\t%d\t%d\n",
501       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, debuginfo_print_trafficip(&strbuf, ip),
502       int_name,
503       cnt->data[DTR_PACKETS],
504       cnt->data[DTR_PACK_TRAFFIC]) < 0;
505 }
506
507 static enum olsr_txtcommand_result
508 debuginfo_pktstat(struct comport_connection *con,
509     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
510 {
511   struct debug_pkttraffic *tr, *iterator;
512
513   if (abuf_appendf(&con->out, "Slot size: %d seconds\tSlot count: %d\n", traffic_interval, traffic_slots) < 0) {
514     return ABUF_ERROR;
515   }
516   if (abuf_appendf(&con->out,
517       "Table: Statistics (without duplicates)\n%-*s\tInterf.\tPackets\tBytes\n",
518       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, "IP"
519       ) < 0) {
520     return ABUF_ERROR;
521   }
522
523   if (param == NULL || strcasecmp(param, "node") == 0) {
524     OLSR_FOR_ALL_PKTTRAFFIC_ENTRIES(tr, iterator) {
525       if (debuginfo_print_pktstat(&con->out, &tr->ip, tr->int_name, &tr->traffic[current_slot])) {
526         return ABUF_ERROR;
527       }
528     }
529   }
530   else {
531     uint32_t mult = 1, divisor = 1;
532     struct debug_pkttraffic_count cnt;
533     int i;
534
535     if (strcasecmp(param, "total") == 0) {
536       divisor = 1;
537     }
538     else if (strcasecmp(param, "average") == 0) {
539       divisor = traffic_slots;
540     }
541     else if (strcasecmp(param, "avgsec") == 0) {
542       divisor = traffic_slots * traffic_interval;
543       mult = 1;
544     }
545     else if (strcasecmp(param, "avgmin") == 0) {
546       divisor = traffic_slots * traffic_interval;
547       mult = 60;
548     }
549     else if (strcasecmp(param, "avghour") == 0) {
550       divisor = traffic_slots * traffic_interval;
551       mult = 3600;
552     }
553     else {
554       abuf_appendf(&con->out, "Error, unknown parameter %s for msgstat\n", param);
555       return CONTINUE;
556     }
557
558     OLSR_FOR_ALL_PKTTRAFFIC_ENTRIES(tr, iterator) {
559       for (i=0; i<DTR_PKT_COUNT; i++) {
560         cnt.data[i] = (tr->total.data[i] * mult) / divisor;
561       }
562       if (debuginfo_print_pktstat(&con->out, &tr->ip, tr->int_name, &cnt)) {
563         return ABUF_ERROR;
564       }
565     }
566   }
567
568   return CONTINUE;
569 }
570
571 static INLINE bool debuginfo_print_cookies_mem(struct autobuf *buf) {
572   struct olsr_memcookie_info *c, *iterator;
573
574   OLSR_FOR_ALL_COOKIES(c, iterator) {
575     if (abuf_appendf(buf, "%-25s (MEMORY) size: %lu usage: %u freelist: %u\n",
576         c->ci_name, (unsigned long)c->ci_size, c->ci_usage, c->ci_free_list_usage) < 0) {
577       return true;
578     }
579   }
580   return false;
581 }
582
583 static INLINE bool debuginfo_print_cookies_timer(struct autobuf *buf) {
584   struct olsr_timer_info *t, *iterator;
585
586   OLSR_FOR_ALL_TIMERS(t, iterator) {
587     if (abuf_appendf(buf, "%-25s (TIMER) usage: %u changes: %u\n",
588         t->name, t->usage, t->changes) < 0) {
589       return true;
590     }
591   }
592   return false;
593 }
594
595 static enum olsr_txtcommand_result
596 debuginfo_cookies(struct comport_connection *con,
597     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
598 {
599   if (abuf_puts(&con->out, "Memory cookies:\n") < 0) {
600     return ABUF_ERROR;
601   }
602
603   if (debuginfo_print_cookies_mem(&con->out)) {
604     return ABUF_ERROR;
605   }
606
607   if (abuf_puts(&con->out, "\nTimer cookies:\n") < 0) {
608     return ABUF_ERROR;
609   }
610
611   if (debuginfo_print_cookies_timer(&con->out)) {
612     return ABUF_ERROR;
613   }
614   return CONTINUE;
615 }
616
617 static enum olsr_txtcommand_result
618 debuginfo_update_logfilter(struct comport_connection *con,
619     const char *cmd, const char *param, const char *current, bool value) {
620   const char *next;
621   int src, sev;
622
623   for (sev = 0; sev < LOG_SEVERITY_COUNT; sev++) {
624     if ((next = str_hasnextword(current, LOG_SEVERITY_NAMES[sev])) != NULL) {
625       break;
626     }
627   }
628   if (sev == LOG_SEVERITY_COUNT) {
629     abuf_appendf(&con->out, "Error, unknown severity in command: %s %s\n", cmd, param);
630     return CONTINUE;
631   }
632
633   current = next;
634   while (current && *current) {
635     for (src = 0; src < LOG_SOURCE_COUNT; src++) {
636       if ((next = str_hasnextword(current, LOG_SOURCE_NAMES[src])) != NULL) {
637         log_debuginfo_mask[sev][src] = value;
638         break;
639       }
640     }
641     if (src == LOG_SOURCE_COUNT) {
642       abuf_appendf(&con->out, "Error, unknown source in command: %s %s\n", cmd, param);
643       return CONTINUE;
644     }
645     current = next;
646   }
647   return CONTINUE;
648 }
649
650 static void
651 debuginfo_print_log(enum log_severity severity __attribute__ ((unused)),
652               enum log_source source __attribute__ ((unused)),
653               bool no_header __attribute__ ((unused)),
654               const char *file __attribute__ ((unused)),
655               int line __attribute__ ((unused)),
656               char *buffer,
657               int timeLength __attribute__ ((unused)),
658               int prefixLength __attribute__ ((unused)))
659 {
660   abuf_puts(&log_connection->out, buffer);
661   abuf_puts(&log_connection->out, "\n");
662
663   olsr_com_activate_output(log_connection);
664 }
665
666 static void
667 debuginfo_stop_logging(struct comport_connection *con) {
668   con->stop_handler = NULL;
669   log_connection = NULL;
670   olsr_log_removehandler(log_handler);
671 }
672
673 static enum olsr_txtcommand_result
674 debuginfo_log(struct comport_connection *con, const char *cmd, const char *param) {
675   const char *next;
676   int src;
677
678   if (param == NULL) {
679     if (con->stop_handler) {
680       abuf_puts(&con->out, "Error, you cannot stack continous output commands\n");
681       return CONTINUE;
682     }
683     if (log_connection != NULL) {
684       abuf_puts(&con->out, "Error, debuginfo cannot handle concurrent logging\n");
685       return CONTINUE;
686     }
687
688     log_connection = con;
689     con->stop_handler = debuginfo_stop_logging;
690
691     log_handler = olsr_log_addhandler(debuginfo_print_log, &log_debuginfo_mask);
692     return CONTINOUS;
693   }
694
695   if (strcasecmp(param, "show") == 0) {
696     abuf_appendf(&con->out, "%*s %6s %6s %6s %6s\n",
697         log_source_maxlen, "",
698         LOG_SEVERITY_NAMES[SEVERITY_DEBUG],
699         LOG_SEVERITY_NAMES[SEVERITY_INFO],
700         LOG_SEVERITY_NAMES[SEVERITY_WARN],
701         LOG_SEVERITY_NAMES[SEVERITY_ERR]);
702
703     for (src=0; src<LOG_SOURCE_COUNT; src++) {
704       abuf_appendf(&con->out, "%*s %*s %*s %*s %*s\n",
705         log_source_maxlen, LOG_SOURCE_NAMES[src],
706         log_severity_maxlen, log_debuginfo_mask[SEVERITY_DEBUG][src] ? "*" : "",
707         log_severity_maxlen, log_debuginfo_mask[SEVERITY_INFO][src] ? "*" : "",
708         log_severity_maxlen, log_debuginfo_mask[SEVERITY_WARN][src] ? "*" : "",
709         log_severity_maxlen, log_debuginfo_mask[SEVERITY_ERR][src] ? "*" : "");
710     }
711     return CONTINUE;
712   }
713
714   if ((next = str_hasnextword(param, "add")) != NULL) {
715     return debuginfo_update_logfilter(con, cmd, param, next, true);
716   }
717
718   if ((next = str_hasnextword(param, "remove")) != NULL) {
719     return debuginfo_update_logfilter(con, cmd, param, next, false);
720   }
721
722   return UNKNOWN;
723 }
724
725 static enum olsr_txtcommand_result
726 olsr_debuginfo_displayhelp(struct comport_connection *con,
727     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused))) {
728   size_t i;
729
730   for (i=0; i<ARRAYSIZE(commands); i++) {
731     if (strcasecmp(commands[i].name, cmd) == 0) {
732       abuf_puts(&con->out, commands[i].help);
733       return CONTINUE;
734     }
735   }
736   return UNKNOWN;
737 }
738
739 /*
740  * Local Variables:
741  * mode: c
742  * style: linux
743  * c-basic-offset: 4
744  * indent-tabs-mode: nil
745  * End:
746  */