Convert some plugins to new logger
[olsrd.git] / lib / txtinfo / src / olsrd_txtinfo.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 #include "olsrd_txtinfo.h"
46 #include "olsr.h"
47 #include "ipcalc.h"
48 #include "neighbor_table.h"
49 #include "two_hop_neighbor_table.h"
50 #include "mpr_selector_set.h"
51 #include "tc_set.h"
52 #include "hna_set.h"
53 #include "mid_set.h"
54 #include "routing_table.h"
55 #include "log.h"
56 #include "misc.h"
57 #include "olsr_ip_prefix_list.h"
58 #include "parser.h"
59
60 #include "common/autobuf.h"
61
62 #include <unistd.h>
63 #include <errno.h>
64
65 #ifdef WIN32
66 #undef EWOULDBLOCK
67 #undef EAGAIN
68 #define EWOULDBLOCK WSAEWOULDBLOCK
69 #define EAGAIN WSAEWOULDBLOCK
70 #undef errno
71 #define errno WSAGetLastError()
72 #undef SHUT_WR
73 #define SHUT_WR SD_SEND
74 #undef strerror
75 #define strerror(x) StrError(x)
76 #define read(fd,buf,size) recv((fd), (buf), (size), 0)
77 #define write(fd,buf,size) send((fd), (buf), (size), 0)
78 #endif
79
80
81 struct ipc_conn {
82   struct autobuf resp;
83   int respstart;
84   int requlen;
85   char requ[256];
86   char csv;
87 };
88
89 static int listen_socket = -1;
90
91
92 static void conn_destroy(struct ipc_conn *);
93
94 static void ipc_action(int, void *, unsigned int);
95
96 static void ipc_http(int, void *, unsigned int);
97
98 static void ipc_http_read(int, struct ipc_conn *);
99
100 static void ipc_http_read_dummy(int, struct ipc_conn *);
101
102 static void ipc_http_write(int, struct ipc_conn *);
103
104 static int send_info(struct ipc_conn *, int);
105
106 static int ipc_print_neigh(struct ipc_conn *);
107
108 static int ipc_print_link(struct ipc_conn *);
109
110 static int ipc_print_routes(struct ipc_conn *);
111
112 static int ipc_print_topology(struct ipc_conn *);
113
114 static int ipc_print_hna_entry(struct autobuf *, const struct olsr_ip_prefix *, const union olsr_ip_addr *, char csv);
115 static int ipc_print_hna(struct ipc_conn *);
116
117 static int ipc_print_mid(struct ipc_conn *);
118
119 static int ipc_print_stat(struct ipc_conn *);
120
121 static void update_statistics_ptr(void *);
122 static bool olsr_msg_statistics(union olsr_message *msg, struct interface *input_if, union olsr_ip_addr *from_addr);
123 static char *olsr_packet_statistics(char *packet, struct interface *interface, union olsr_ip_addr *, int *length);
124 static void update_statistics_ptr(void *data __attribute__ ((unused)));
125
126 #define isprefix(str, pre) (strncmp((str), (pre), strlen(pre)) == 0)
127
128 #define SIW_NEIGH         (1 << 0)
129 #define SIW_LINK          (1 << 1)
130 #define SIW_ROUTE         (1 << 2)
131 #define SIW_HNA           (1 << 3)
132 #define SIW_MID           (1 << 4)
133 #define SIW_TOPO          (1 << 5)
134 #define SIW_STAT          (1 << 6)
135 #define SIW_COOKIES       (1 << 7)
136 #define SIW_CSV           (1 << 8)
137 #define SIW_ALL           (SIW_NEIGH|SIW_LINK|SIW_ROUTE|SIW_HNA|SIW_MID|SIW_TOPO)
138
139 /* variables for statistics */
140 static uint32_t recv_packets[60], recv_messages[60][6];
141 static uint32_t recv_last_relevantTCs;
142 struct olsr_cookie_info *statistics_timer = NULL;
143
144 /**
145  * destructor - called at unload
146  */
147 void
148 olsr_plugin_exit(void)
149 {
150   olsr_parser_remove_function(&olsr_msg_statistics, PROMISCUOUS);
151   olsr_preprocessor_remove_function(&olsr_packet_statistics);
152   CLOSESOCKET(listen_socket);
153 }
154
155 /**
156  *Do initialization here
157  *
158  *This function is called by the my_init
159  *function in uolsrd_plugin.c
160  */
161 int
162 olsrd_plugin_init(void)
163 {
164   struct sockaddr_storage sst;
165   uint32_t yes = 1;
166   socklen_t addrlen;
167
168   statistics_timer = olsr_alloc_cookie("Txtinfo statistics timer", OLSR_COOKIE_TYPE_TIMER);
169   olsr_start_timer(1000, 0, true, &update_statistics_ptr, NULL, statistics_timer->ci_id);
170
171   /* Init ipc socket */
172   listen_socket = socket(olsr_cnf->ip_version, SOCK_STREAM, 0);
173   if (listen_socket == -1) {
174     OLSR_WARN(LOG_PLUGINS, "(TXTINFO) socket()=%s\n", strerror(errno));
175     return 0;
176   }
177   if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
178     OLSR_WARN(LOG_PLUGINS, "(TXTINFO) setsockopt()=%s\n", strerror(errno));
179     CLOSESOCKET(listen_socket);
180     return 0;
181   }
182 #if defined __FreeBSD__ && defined SO_NOSIGPIPE
183   if (setsockopt(listen_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) {
184     OLSR_WARN(LOG_PLUGINS, "(TXTINFO) reusing address failed: %s", strerror(errno));
185     CLOSESOCKET(listen_socket);
186     return 0;
187   }
188 #endif
189   /* Bind the socket */
190
191   /* complete the socket structure */
192   memset(&sst, 0, sizeof(sst));
193   if (olsr_cnf->ip_version == AF_INET) {
194     struct sockaddr_in *addr4 = (struct sockaddr_in *)&sst;
195     addr4->sin_family = AF_INET;
196     addrlen = sizeof(*addr4);
197 #ifdef SIN6_LEN
198     addr4->sin_len = addrlen;
199 #endif
200     addr4->sin_addr.s_addr = INADDR_ANY;
201     addr4->sin_port = htons(ipc_port);
202   } else {
203     struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&sst;
204     addr6->sin6_family = AF_INET6;
205     addrlen = sizeof(*addr6);
206 #ifdef SIN6_LEN
207     addr6->sin6_len = addrlen;
208 #endif
209     addr6->sin6_addr = in6addr_any;
210     addr6->sin6_port = htons(ipc_port);
211   }
212
213   /* bind the socket to the port number */
214   if (bind(listen_socket, (struct sockaddr *)&sst, addrlen) == -1) {
215     OLSR_WARN(LOG_PLUGINS, "(TXTINFO) bind()=%s\n", strerror(errno));
216     CLOSESOCKET(listen_socket);
217     return 0;
218   }
219
220   /* show that we are willing to listen */
221   if (listen(listen_socket, 1) == -1) {
222     OLSR_WARN(LOG_PLUGINS, "(TXTINFO) listen()=%s\n", strerror(errno));
223     CLOSESOCKET(listen_socket);
224     return 0;
225   }
226
227   /* Register with olsrd */
228   add_olsr_socket(listen_socket, NULL, &ipc_action, NULL, SP_IMM_READ);
229
230   OLSR_INFO(LOG_PLUGINS, "(TXTINFO) listening on port %d\n", ipc_port);
231
232   memset(recv_packets, 0, sizeof(recv_packets));
233   memset(recv_messages, 0, sizeof(recv_messages));
234
235   recv_last_relevantTCs = 0;
236   olsr_parser_add_function(&olsr_msg_statistics, PROMISCUOUS);
237   olsr_preprocessor_add_function(&olsr_packet_statistics);
238   return 1;
239 }
240
241
242 static void
243 update_statistics_ptr(void *data __attribute__ ((unused)))
244 {
245   uint32_t now = now_times / 1000;
246   int i;
247
248   recv_packets[now % 60] = 0;
249   for (i = 0; i < 6; i++) {
250     recv_messages[now % 60][i] = 0;
251   }
252 }
253
254 /* update message statistics */
255 static bool
256 olsr_msg_statistics(union olsr_message *msg,
257                     struct interface *input_if __attribute__ ((unused)), union olsr_ip_addr *from_addr __attribute__ ((unused)))
258 {
259   uint32_t now = now_times / 1000;
260   int idx, msgtype;
261
262   if (olsr_cnf->ip_version == AF_INET) {
263     msgtype = msg->v4.olsr_msgtype;
264   } else {
265     msgtype = msg->v6.olsr_msgtype;
266   }
267
268   switch (msgtype) {
269   case HELLO_MESSAGE:
270   case TC_MESSAGE:
271   case MID_MESSAGE:
272   case HNA_MESSAGE:
273     idx = msgtype - 1;
274     break;
275
276   case LQ_HELLO_MESSAGE:
277     idx = 0;
278     break;
279   case LQ_TC_MESSAGE:
280     idx = 1;
281     break;
282   default:
283     idx = 4;
284     break;
285   }
286
287   recv_messages[now % 60][idx]++;
288   if (recv_last_relevantTCs != getRelevantTcCount()) {
289     recv_messages[now % 60][5]++;
290     recv_last_relevantTCs ++;
291   }
292   return true;
293 }
294
295 /* update traffic statistics */
296 static char *
297 olsr_packet_statistics(char *packet __attribute__ ((unused)),
298                        struct interface *interface __attribute__ ((unused)),
299                        union olsr_ip_addr *ip __attribute__ ((unused)), int *length __attribute__ ((unused)))
300 {
301   uint32_t now = now_times / 1000;
302   recv_packets[now % 60] += *length;
303
304   return packet;
305 }
306
307 /* destroy the connection */
308 static void
309 conn_destroy(struct ipc_conn *conn)
310 {
311   abuf_free(&conn->resp);
312   free(conn);
313 }
314
315 static void
316 kill_connection(int fd, struct ipc_conn *conn)
317 {
318   remove_olsr_socket(fd, NULL, &ipc_http);
319   CLOSESOCKET(fd);
320   conn_destroy(conn);
321 }
322
323 static void
324 ipc_action(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
325 {
326   struct ipc_conn *conn;
327   struct sockaddr_storage pin;
328 #ifndef NODEBUG
329   char addr[INET6_ADDRSTRLEN];
330 #endif
331   socklen_t addrlen = sizeof(pin);
332   int http_connection = accept(fd, (struct sockaddr *)&pin, &addrlen);
333   union olsr_ip_addr *ipaddr;
334
335   if (http_connection == -1) {
336     /* this may well happen if the other side immediately closes the connection. */
337     OLSR_WARN(LOG_PLUGINS, "(TXTINFO) accept()=%s\n", strerror(errno));
338     return;
339   }
340
341   /* check if we want ot speak with it */
342   if (olsr_cnf->ip_version == AF_INET) {
343     struct sockaddr_in *addr4 = (struct sockaddr_in *)&pin;
344     ipaddr = (union olsr_ip_addr *)&addr4->sin_addr;
345   } else {
346     struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pin;
347     ipaddr = (union olsr_ip_addr *)&addr6->sin6_addr;
348   }
349
350   if (!ip_acl_acceptable(&allowed_nets, ipaddr, olsr_cnf->ip_version)) {
351     OLSR_WARN(LOG_PLUGINS, "(TXTINFO) From host(%s) not allowed!\n", addr);
352     CLOSESOCKET(http_connection);
353     return;
354   }
355   OLSR_WARN(LOG_PLUGINS, "(TXTINFO) Connect from %s\n", addr);
356
357   /* make the fd non-blocking */
358   if (set_nonblocking(http_connection) < 0) {
359     CLOSESOCKET(http_connection);
360     return;
361   }
362
363   conn = malloc(sizeof(*conn));
364   if (conn == NULL) {
365     OLSR_WARN(LOG_PLUGINS, "(TXTINFO) Out of memory!");
366     CLOSESOCKET(http_connection);
367     return;
368   }
369   conn->requlen = 0;
370   *conn->requ = '\0';
371   conn->respstart = 0;
372   abuf_init(&conn->resp, 1000);
373   add_olsr_socket(http_connection, NULL, &ipc_http, conn, SP_IMM_READ);
374 }
375
376 static void
377 ipc_http_read_dummy(int fd, struct ipc_conn *conn)
378 {
379   /* just read dummy stuff */
380   ssize_t bytes_read;
381   char dummybuf[128];
382   do {
383     bytes_read = read(fd, dummybuf, sizeof(dummybuf));
384   } while (bytes_read > 0);
385   if (bytes_read == 0) {
386     /* EOF */
387     if (conn->respstart < conn->resp.len && conn->resp.len > 0) {
388       disable_olsr_socket(fd, NULL, &ipc_http, SP_IMM_READ);
389       conn->requlen = -1;
390       return;
391     }
392   } else if (errno == EINTR || errno == EAGAIN) {
393     /* ignore interrupted sys-calls */
394     return;
395   }
396   /* we had either an error or EOF and we are completely done */
397   kill_connection(fd, conn);
398 }
399
400 static void
401 ipc_http_read(int fd, struct ipc_conn *conn)
402 {
403   int send_what = 0;
404   const char *p;
405   ssize_t bytes_read = read(fd, conn->requ + conn->requlen, sizeof(conn->requ) - conn->requlen - 1);    /* leave space for a terminating '\0' */
406   if (bytes_read < 0) {
407     if (errno == EINTR || errno == EAGAIN) {
408       return;
409     }
410     OLSR_WARN(LOG_PLUGINS, "(TXTINFO) read error: %s", strerror(errno));
411     kill_connection(fd, conn);
412     return;
413   }
414   conn->requlen += bytes_read;
415   conn->requ[conn->requlen] = '\0';
416   conn->csv = 0;
417
418   /* look if we have the necessary info. We get here somethign like "GET /path HTTP/1.0" */
419   p = strchr(conn->requ, '/');
420   if (p == NULL) {
421     /* input buffer full ? */
422     if ((sizeof(conn->requ) - conn->requlen - 1) == 0) {
423       kill_connection(fd, conn);
424       return;
425     }
426     /* we didn't get all. Wait for more data. */
427     return;
428   }
429   while (p != NULL) {
430     if (isprefix(p, "/neighbours"))
431       send_what = send_what | SIW_LINK | SIW_NEIGH;
432     else if (isprefix(p, "/neigh"))
433       send_what = send_what | SIW_NEIGH;
434     else if (isprefix(p, "/link"))
435       send_what = send_what | SIW_LINK;
436     else if (isprefix(p, "/route"))
437       send_what = send_what | SIW_ROUTE;
438     else if (isprefix(p, "/hna"))
439       send_what = send_what | SIW_HNA;
440     else if (isprefix(p, "/mid"))
441       send_what = send_what | SIW_MID;
442     else if (isprefix(p, "/topo"))
443       send_what = send_what | SIW_TOPO;
444     else if (isprefix(p, "/stat"))
445       send_what = send_what | SIW_STAT;
446     else if (isprefix(p, "/cookies"))
447       send_what = send_what | SIW_COOKIES;
448     else if (isprefix(p, "/csv"))
449       send_what = send_what | SIW_CSV;
450     p = strchr(++p, '/');
451   }
452   if (send_what == 0) {
453     send_what = SIW_ALL;
454   } else if (send_what == SIW_CSV) {
455     send_what = SIW_ALL | SIW_CSV;
456   }
457
458   if (send_info(conn, send_what) < 0) {
459     kill_connection(fd, conn);
460     return;
461   }
462   enable_olsr_socket(fd, NULL, &ipc_http, SP_IMM_WRITE);
463 }
464
465 static void
466 ipc_http_write(int fd, struct ipc_conn *conn)
467 {
468   ssize_t bytes_written = write(fd, conn->resp.buf + conn->respstart,
469                                 conn->resp.len - conn->respstart);
470   if (bytes_written < 0) {
471     if (errno == EINTR || errno == EAGAIN) {
472       return;
473     }
474     OLSR_WARN(LOG_PLUGINS, "(TXTINFO) write error: %s", strerror(errno));
475     kill_connection(fd, conn);
476     return;
477   }
478   conn->respstart += bytes_written;
479   if (conn->respstart >= conn->resp.len) {
480     /* we are done. */
481     if (conn->requlen < 0) {
482       /* we are completely done. */
483       kill_connection(fd, conn);
484     } else if (shutdown(fd, SHUT_WR) < 0) {
485       kill_connection(fd, conn);
486     } else {
487       disable_olsr_socket(fd, NULL, &ipc_http, SP_IMM_WRITE);
488     }
489   }
490 }
491
492 static void
493 ipc_http(int fd, void *data, unsigned int flags)
494 {
495   struct ipc_conn *conn = data;
496   if ((flags & SP_IMM_READ) != 0) {
497     if (conn->resp.len > 0) {
498       ipc_http_read_dummy(fd, conn);
499     } else {
500       ipc_http_read(fd, conn);
501     }
502   }
503   if ((flags & SP_IMM_WRITE) != 0) {
504     ipc_http_write(fd, conn);
505   }
506 }
507
508
509 static int
510 ipc_print_neigh(struct ipc_conn *conn)
511 {
512   struct neighbor_entry *neigh;
513
514   if (!conn->csv) {
515     if (abuf_appendf(&conn->resp, "Table: Neighbors\nIP address\tSYM\tMPR\tMPRS\tWill.\t2 Hop Neighbors\n") < 0) {
516       return -1;
517     }
518   }
519
520   /* Neighbors */
521   OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
522     struct neighbor_2_list_entry *list_2;
523     struct ipaddr_str buf1;
524     int thop_cnt = 0;
525     for (list_2 = neigh->neighbor_2_list.next; list_2 != &neigh->neighbor_2_list; list_2 = list_2->next) {
526       thop_cnt++;
527     }
528     if (!conn->csv) {
529       if (abuf_appendf(&conn->resp,
530                        "%s\t%s\t%s\t%s\t%d\t%d\n",
531                        olsr_ip_to_string(&buf1, &neigh->neighbor_main_addr),
532                        neigh->status == SYM ? "YES" : "NO",
533                        neigh->is_mpr ? "YES" : "NO",
534                        olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO", neigh->willingness, thop_cnt) < 0) {
535         return -1;
536       }
537     } else {
538       if (abuf_appendf(&conn->resp,
539                        "neigh,%s,%s,%s,%s,%d,%d\n",
540                        olsr_ip_to_string(&buf1, &neigh->neighbor_main_addr),
541                        neigh->status == SYM ? "YES" : "NO",
542                        neigh->is_mpr ? "YES" : "NO",
543                        olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO", neigh->willingness, thop_cnt) < 0) {
544         return -1;
545       }
546     }
547   }
548   OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
549
550   if (!conn->csv) {
551     if (abuf_appendf(&conn->resp, "\n") < 0) {
552       return -1;
553     }
554   }
555   return 0;
556 }
557
558 static int
559 ipc_print_link(struct ipc_conn *conn)
560 {
561   struct link_entry *lnk;
562
563   if (!conn->csv) {
564     if (abuf_appendf(&conn->resp, "Table: Links\nLocal IP\tRemote IP\tLQ\tNLQ\tCost\n") < 0) {
565       return -1;
566     }
567   }
568
569   /* Link set */
570   OLSR_FOR_ALL_LINK_ENTRIES(lnk) {
571     struct ipaddr_str buf1, buf2;
572     struct lqtextbuffer lqbuffer1, lqbuffer2;
573     if (!conn->csv) {
574       if (abuf_appendf(&conn->resp,
575                        "%s\t%s\t%s\t%s\t\n",
576                        olsr_ip_to_string(&buf1, &lnk->local_iface_addr),
577                        olsr_ip_to_string(&buf2, &lnk->neighbor_iface_addr),
578                        get_link_entry_text(lnk, '\t', &lqbuffer1), get_linkcost_text(lnk->linkcost, false, &lqbuffer2)) < 0) {
579         return -1;
580       }
581     } else {
582       if (abuf_appendf(&conn->resp,
583                        "link,%s,%s,%s,%s\n",
584                        olsr_ip_to_string(&buf1, &lnk->local_iface_addr),
585                        olsr_ip_to_string(&buf2, &lnk->neighbor_iface_addr),
586                        get_link_entry_text(lnk, ',', &lqbuffer1), get_linkcost_text(lnk->linkcost, false, &lqbuffer2)) < 0) {
587         return -1;
588       }
589     }
590   }
591   OLSR_FOR_ALL_LINK_ENTRIES_END(lnk);
592
593   if (!conn->csv) {
594     if (abuf_appendf(&conn->resp, "\n") < 0) {
595       return -1;
596     }
597   }
598   return 0;
599 }
600
601 static int
602 ipc_print_routes(struct ipc_conn *conn)
603 {
604   struct rt_entry *rt;
605
606   if (!conn->csv) {
607     if (abuf_appendf(&conn->resp, "Table: Routes\nDestination\tGateway IP\tMetric\tETX\tInterface\n") < 0) {
608       return -1;
609     }
610   }
611
612   /* Walk the route table */
613   OLSR_FOR_ALL_RT_ENTRIES(rt) {
614     struct ipaddr_str buf;
615     struct ipprefix_str prefixstr;
616     struct lqtextbuffer lqbuffer;
617     if (!conn->csv) {
618       if (abuf_appendf(&conn->resp,
619                        "%s\t%s\t%u\t%s\t%s\t\n",
620                        olsr_ip_prefix_to_string(&prefixstr, &rt->rt_dst),
621                        olsr_ip_to_string(&buf, &rt->rt_best->rtp_nexthop.gateway),
622                        rt->rt_best->rtp_metric.hops,
623                        get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer),
624                        rt->rt_best->rtp_nexthop.interface ? rt->rt_best->rtp_nexthop.interface->int_name : "[null]") < 0) {
625         return -1;
626       }
627     } else {
628       if (abuf_appendf(&conn->resp,
629                        "route,%s,%s,%u,%s,%s\n",
630                        olsr_ip_prefix_to_string(&prefixstr, &rt->rt_dst),
631                        olsr_ip_to_string(&buf, &rt->rt_best->rtp_nexthop.gateway),
632                        rt->rt_best->rtp_metric.hops,
633                        get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer),
634                        rt->rt_best->rtp_nexthop.interface ? rt->rt_best->rtp_nexthop.interface->int_name : "[null]") < 0) {
635         return -1;
636       }
637     }
638   }
639   OLSR_FOR_ALL_RT_ENTRIES_END(rt);
640
641   if (!conn->csv) {
642     if (abuf_appendf(&conn->resp, "\n") < 0) {
643       return -1;
644     }
645   }
646   return 0;
647 }
648
649 static int
650 ipc_print_topology(struct ipc_conn *conn)
651 {
652   struct tc_entry *tc;
653
654   if (!conn->csv) {
655     if (abuf_appendf(&conn->resp, "Table: Topology\nDest. IP\tLast hop IP\tLQ\tNLQ\tCost\n") < 0) {
656       return -1;
657     }
658   }
659
660   /* Topology */
661   OLSR_FOR_ALL_TC_ENTRIES(tc) {
662     struct tc_edge_entry *tc_edge;
663     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
664       if (tc_edge->edge_inv) {
665         struct ipaddr_str dstbuf, addrbuf;
666         struct lqtextbuffer lqbuffer1, lqbuffer2;
667         if (!conn->csv) {
668           if (abuf_appendf(&conn->resp,
669                            "%s\t%s\t%s\t%s\n",
670                            olsr_ip_to_string(&dstbuf, &tc_edge->T_dest_addr),
671                            olsr_ip_to_string(&addrbuf, &tc->addr),
672                            get_tc_edge_entry_text(tc_edge, '\t', &lqbuffer1),
673                            get_linkcost_text(tc_edge->cost, false, &lqbuffer2)) < 0) {
674             return -1;
675           }
676         } else {
677           if (abuf_appendf(&conn->resp,
678                            "topo,%s,%s,%s,%s\n",
679                            olsr_ip_to_string(&dstbuf, &tc_edge->T_dest_addr),
680                            olsr_ip_to_string(&addrbuf, &tc->addr),
681                            get_tc_edge_entry_text(tc_edge, ',', &lqbuffer1),
682                            get_linkcost_text(tc_edge->cost, false, &lqbuffer2)) < 0) {
683             return -1;
684           }
685         }
686       }
687     }
688     OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
689   }
690   OLSR_FOR_ALL_TC_ENTRIES_END(tc);
691
692   if (!conn->csv) {
693     if (abuf_appendf(&conn->resp, "\n") < 0) {
694       return -1;
695     }
696   }
697   return 0;
698 }
699
700 static int
701 ipc_print_hna_entry(struct autobuf *autobuf, const struct olsr_ip_prefix *hna_prefix, const union olsr_ip_addr *ipaddr, char csv)
702 {
703   struct ipaddr_str mainaddrbuf;
704   struct ipprefix_str addrbuf;
705   if (!csv) {
706     return abuf_appendf(autobuf,
707                         "%s\t%s\n", olsr_ip_prefix_to_string(&addrbuf, hna_prefix), olsr_ip_to_string(&mainaddrbuf, ipaddr));
708   } else {
709     return abuf_appendf(autobuf,
710                         "hna,%s,%s\n", olsr_ip_prefix_to_string(&addrbuf, hna_prefix), olsr_ip_to_string(&mainaddrbuf, ipaddr));
711   }
712 }
713
714 static int
715 ipc_print_hna(struct ipc_conn *conn)
716 {
717   const struct ip_prefix_entry *hna;
718   struct tc_entry *tc;
719
720   if (!conn->csv) {
721     if (abuf_appendf(&conn->resp, "Table: HNA\nDestination\tGateway\n") < 0) {
722       return -1;
723     }
724   }
725
726   /* Announced HNA entries */
727   OLSR_FOR_ALL_IPPREFIX_ENTRIES(&olsr_cnf->hna_entries, hna) {
728     if (ipc_print_hna_entry(&conn->resp, &hna->net, &olsr_cnf->router_id, conn->csv) < 0) {
729       return -1;
730     }
731   }
732   OLSR_FOR_ALL_IPPREFIX_ENTRIES_END()
733
734     /* HNA entries */
735     OLSR_FOR_ALL_TC_ENTRIES(tc) {
736     struct hna_net *tmp_net;
737     /* Check all networks */
738     OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, tmp_net) {
739       if (ipc_print_hna_entry(&conn->resp, &tmp_net->hna_prefix, &tc->addr, conn->csv) < 0) {
740         return -1;
741       }
742     }
743     OLSR_FOR_ALL_TC_HNA_ENTRIES_END(tc, tmp_net);
744   }
745   OLSR_FOR_ALL_TC_ENTRIES_END(tc);
746
747   if (!conn->csv) {
748     if (abuf_appendf(&conn->resp, "\n") < 0) {
749       return -1;
750     }
751   }
752   return 0;
753 }
754
755 static int
756 ipc_print_mid(struct ipc_conn *conn)
757 {
758   struct tc_entry *tc;
759
760   if (!conn->csv) {
761     if (abuf_appendf(&conn->resp, "Table: MID\nIP address\tAliases\n") < 0) {
762       return -1;
763     }
764   }
765
766   /* MID root is the TC entry */
767   OLSR_FOR_ALL_TC_ENTRIES(tc) {
768     struct ipaddr_str buf;
769     struct mid_entry *alias;
770     char sep = '\t';
771     if (conn->csv) {
772       sep = ',';
773     }
774
775     if (!conn->csv) {
776       if (abuf_puts(&conn->resp, olsr_ip_to_string(&buf, &tc->addr)) < 0) {
777         return -1;
778       }
779     } else {
780       if (abuf_appendf(&conn->resp, "mid,%s", olsr_ip_to_string(&buf, &tc->addr)) < 0) {
781         return -1;
782       }
783     }
784
785     OLSR_FOR_ALL_TC_MID_ENTRIES(tc, alias) {
786       if (abuf_appendf(&conn->resp, "%c%s", sep, olsr_ip_to_string(&buf, &alias->mid_alias_addr)) < 0) {
787         return -1;
788       }
789       if (!conn->csv) {
790         sep = ';';
791       } else {
792         sep = ',';
793       }
794     }
795     OLSR_FOR_ALL_TC_MID_ENTRIES_END(tc, alias);
796     if (abuf_appendf(&conn->resp, "\n") < 0) {
797       return -1;
798     }
799   }
800   OLSR_FOR_ALL_TC_ENTRIES_END(tc);
801   if (!conn->csv) {
802     if (abuf_appendf(&conn->resp, "\n") < 0) {
803       return -1;
804     }
805   }
806   return 0;
807 }
808
809 static int
810 ipc_print_stat(struct ipc_conn *conn)
811 {
812   static const char *names[] = { "HELLO", "TC", "MID", "HNA", "Other", "Rel.TCs" };
813
814   uint32_t msgs[6], traffic, i, j;
815   uint32_t slot = (now_times / 1000 + 59) % 60;
816
817   if (!conn->csv) {
818     if (abuf_appendf(&conn->resp, "Table: Statistics (without duplicates)\nType\tlast seconds\t\t\t\tlast min.\taverage\n") < 0) {
819       return -1;
820     }
821   }
822
823   for (j = 0; j < 6; j++) {
824     msgs[j] = 0;
825     for (i = 0; i < 60; i++) {
826       msgs[j] += recv_messages[i][j];
827     }
828   }
829
830   traffic = 0;
831   for (i = 0; i < 60; i++) {
832     traffic += recv_packets[i];
833   }
834
835   for (i = 0; i < 6; i++) {
836     if (!conn->csv) {
837       if (abuf_appendf(&conn->resp, "%s\t%u\t%u\t%u\t%u\t%u\t%u\t\t%u\n", names[i],
838                        recv_messages[(slot) % 60][i],
839                        recv_messages[(slot + 59) % 60][i],
840                        recv_messages[(slot + 58) % 60][i],
841                        recv_messages[(slot + 57) % 60][i], recv_messages[(slot + 56) % 60][i], msgs[i], msgs[i] / 60) < 0) {
842         return -1;
843       }
844     } else {
845       if (abuf_appendf(&conn->resp, "stat,%s,%u,%u,%u,%u,%u,%u,%u\n", names[i],
846                        recv_messages[(slot) % 60][i],
847                        recv_messages[(slot + 59) % 60][i],
848                        recv_messages[(slot + 58) % 60][i],
849                        recv_messages[(slot + 57) % 60][i], recv_messages[(slot + 56) % 60][i], msgs[i], msgs[i] / 60) < 0) {
850         return -1;
851       }
852     }
853   }
854   if (!conn->csv) {
855     if (abuf_appendf(&conn->resp, "\nTraffic: %8u bytes/s\t%u bytes/minute\taverage %u bytes/s\n",
856                      recv_packets[(slot) % 60], traffic, traffic / 60) < 0) {
857       return -1;
858     }
859   } else {
860     if (abuf_appendf(&conn->resp, "stat,Traffic,%u,%u,%u\n", recv_packets[(slot) % 60], traffic, traffic / 60) < 0) {
861       return -1;
862     }
863   }
864
865   if (!conn->csv) {
866     if (abuf_appendf(&conn->resp, "\n") < 0) {
867       return -1;
868     }
869   }
870   return 0;
871 }
872
873 static int
874 ipc_print_cookies(struct ipc_conn *conn)
875 {
876   int i;
877
878   if (!conn->csv) {
879     if (abuf_appendf(&conn->resp, "Memory cookies:\n") < 0) {
880       return -1;
881     }
882   }
883
884   for (i = 1; i < COOKIE_ID_MAX; i++) {
885     struct olsr_cookie_info *c = olsr_cookie_get(i);
886     if (c == NULL || c->ci_type != OLSR_COOKIE_TYPE_MEMORY) {
887       continue;
888     }
889     if (!conn->csv) {
890       if (abuf_appendf(&conn->resp, "%-25s ", c->ci_name == NULL ? "Unknown" : c->ci_name) < 0) {
891         return -1;
892       }
893       if (abuf_appendf(&conn->resp, "(MEMORY) size: %lu usage: %u freelist: %u\n",
894                        (unsigned long)c->ci_size, c->ci_usage, c->ci_free_list_usage) < 0) {
895         return -1;
896       }
897     } else {
898       if (abuf_appendf(&conn->resp, "mem_cookie,%s,%lu,%u,%u\n", c->ci_name == NULL ? "Unknown" : c->ci_name,
899                        (unsigned long)c->ci_size, c->ci_usage, c->ci_free_list_usage) < 0) {
900         return -1;
901       }
902     }
903   }
904
905   if (!conn->csv) {
906     if (abuf_appendf(&conn->resp, "\nTimer cookies:\n") < 0) {
907       return -1;
908     }
909   }
910
911   for (i = 1; i < COOKIE_ID_MAX; i++) {
912     struct olsr_cookie_info *c = olsr_cookie_get(i);
913     if (c == NULL || c->ci_type != OLSR_COOKIE_TYPE_TIMER) {
914       continue;
915     }
916     if (!conn->csv) {
917       if (abuf_appendf(&conn->resp, "%-25s ", c->ci_name == NULL ? "Unknown" : c->ci_name) < 0) {
918         return -1;
919       }
920       if (abuf_appendf(&conn->resp, "(TIMER) usage: %u changes: %u\n", c->ci_usage, c->ci_changes) < 0) {
921         return -1;
922       }
923     } else {
924       if (abuf_appendf(&conn->resp, "tmr_cookie,%s,%u,%u\n", c->ci_name == NULL ? "Unknown" : c->ci_name,
925                        c->ci_usage, c->ci_changes) < 0) {
926         return -1;
927       }
928     }
929   }
930
931   if (!conn->csv) {
932     if (abuf_appendf(&conn->resp, "\n") < 0) {
933       return -1;
934     }
935   }
936   return 0;
937 }
938
939 static int
940 send_info(struct ipc_conn *conn, int send_what)
941 {
942   int rv;
943
944   /* comma separated values output format */
945   if ((send_what & SIW_CSV) != 0) {
946     conn->csv = 1;
947   }
948
949   /* Print minimal http header */
950   if (!conn->csv) {
951     if (abuf_appendf(&conn->resp, "HTTP/1.0 200 OK\n" "Content-type: text/plain\n\n") < 0) {
952       return -1;
953     }
954   }
955
956   /* Print tables to IPC socket */
957
958   rv = 0;
959   /* links + Neighbors */
960   if ((send_what & SIW_LINK) != 0 && ipc_print_link(conn) < 0) {
961     rv = -1;
962   }
963   if ((send_what & SIW_NEIGH) != 0 && ipc_print_neigh(conn) < 0) {
964     rv = -1;
965   }
966   /* topology */
967   if ((send_what & SIW_TOPO) != 0) {
968     rv = ipc_print_topology(conn);
969   }
970   /* hna */
971   if ((send_what & SIW_HNA) != 0) {
972     rv = ipc_print_hna(conn);
973   }
974   /* mid */
975   if ((send_what & SIW_MID) != 0) {
976     rv = ipc_print_mid(conn);
977   }
978   /* routes */
979   if ((send_what & SIW_ROUTE) != 0) {
980     rv = ipc_print_routes(conn);
981   }
982   /* statistics */
983   if ((send_what & SIW_STAT) != 0) {
984     rv = ipc_print_stat(conn);
985   }
986   /* cookies */
987   if ((send_what & SIW_COOKIES) != 0) {
988     rv = ipc_print_cookies(conn);
989   }
990   return rv;
991 }
992
993 /*
994  * Local Variables:
995  * mode: c
996  * style: linux
997  * c-basic-offset: 4
998  * indent-tabs-mode: nil
999  * End:
1000  */