Update for txtinfo plugin, new command is "/stats"
[olsrd.git] / lib / txtinfo / src / olsrd_txtinfo.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in
14  *   the documentation and/or other materials provided with the
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
39  */
40
41 /*
42  * Dynamic linked library for the olsr.org olsr daemon
43  */
44 #include "olsrd_txtinfo.h"
45 #include "olsr.h"
46 #include "ipcalc.h"
47 #include "neighbor_table.h"
48 #include "two_hop_neighbor_table.h"
49 #include "mpr_selector_set.h"
50 #include "tc_set.h"
51 #include "hna_set.h"
52 #include "mid_set.h"
53 #include "routing_table.h"
54 #include "log.h"
55 #include "misc.h"
56 #include "olsr_ip_prefix_list.h"
57 #include "parser.h"
58
59 #include "common/autobuf.h"
60
61 #include <unistd.h>
62 #include <errno.h>
63
64 #ifdef WIN32
65 #undef EWOULDBLOCK
66 #undef EAGAIN
67 #define EWOULDBLOCK WSAEWOULDBLOCK
68 #define EAGAIN WSAEWOULDBLOCK
69 #undef errno
70 #define errno WSAGetLastError()
71 #undef SHUT_WR
72 #define SHUT_WR SD_SEND
73 #undef strerror
74 #define strerror(x) StrError(x)
75 #define read(fd,buf,size) recv((fd), (buf), (size), 0)
76 #define write(fd,buf,size) send((fd), (buf), (size), 0)
77 #endif
78
79
80 struct ipc_conn {
81     struct autobuf resp;
82     int respstart;
83     int requlen;
84     char requ[256];
85 };
86
87 static int listen_socket = -1;
88
89
90 static void conn_destroy(struct ipc_conn *);
91
92 static void ipc_action(int, void *, unsigned int);
93
94 static void ipc_http(int, void *, unsigned int);
95
96 static void ipc_http_read(int, struct ipc_conn *);
97
98 static void ipc_http_read_dummy(int, struct ipc_conn *);
99
100 static void ipc_http_write(int, struct ipc_conn *);
101
102 static int send_info(struct ipc_conn *, int);
103
104 static int ipc_print_neigh(struct ipc_conn *);
105
106 static int ipc_print_link(struct ipc_conn *);
107
108 static int ipc_print_routes(struct ipc_conn *);
109
110 static int ipc_print_topology(struct ipc_conn *);
111
112 static int ipc_print_hna_entry(struct autobuf *, const struct olsr_ip_prefix *, const union olsr_ip_addr *);
113 static int ipc_print_hna(struct ipc_conn *);
114
115 static int ipc_print_mid(struct ipc_conn *);
116
117 static int ipc_print_stat(struct ipc_conn *);
118
119 static void update_statistics_ptr(void);
120 static bool olsr_msg_statistics(union olsr_message *msg,
121                struct interface *input_if, union olsr_ip_addr *from_addr);
122 static char *olsr_packet_statistics(char *packet, struct interface *interface,
123                union olsr_ip_addr *, int *length);
124
125 #define isprefix(str, pre) (strncmp((str), (pre), strlen(pre)) == 0)
126
127 #define SIW_NEIGH       (1 << 0)
128 #define SIW_LINK        (1 << 1)
129 #define SIW_ROUTE       (1 << 2)
130 #define SIW_HNA         (1 << 3)
131 #define SIW_MID         (1 << 4)
132 #define SIW_TOPO        (1 << 5)
133 #define SIW_STAT  (1 << 6)
134 #define SIW_ALL         (SIW_NEIGH|SIW_LINK|SIW_ROUTE|SIW_HNA|SIW_MID|SIW_TOPO)
135
136 /* variables for statistics */
137 static uint32_t recv_packets[60], recv_messages[60][6];
138 static clock_t recv_last_now, recv_last_relevantTCs;
139
140 /**
141  * destructor - called at unload
142  */
143 void olsr_plugin_exit(void)
144 {
145     olsr_parser_remove_function(&olsr_msg_statistics, PROMISCUOUS);
146     olsr_preprocessor_remove_function(&olsr_packet_statistics);
147     CLOSESOCKET(listen_socket);
148 }
149 /**
150  *Do initialization here
151  *
152  *This function is called by the my_init
153  *function in uolsrd_plugin.c
154  */
155 int
156 olsrd_plugin_init(void)
157 {
158     struct sockaddr_storage sst;
159     uint32_t yes = 1;
160     socklen_t addrlen;
161
162     /* Init ipc socket */
163     listen_socket = socket(olsr_cnf->ip_version, SOCK_STREAM, 0);
164     if (listen_socket == -1) {
165 #ifndef NODEBUG
166         OLSR_PRINTF(1, "(TXTINFO) socket()=%s\n", strerror(errno));
167 #endif
168         return 0;
169     }
170     if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
171 #ifndef NODEBUG
172         OLSR_PRINTF(1, "(TXTINFO) setsockopt()=%s\n", strerror(errno));
173 #endif
174         CLOSESOCKET(listen_socket);
175         return 0;
176     }
177
178 #if defined __FreeBSD__ && defined SO_NOSIGPIPE
179     if (setsockopt(listen_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) {
180         perror("SO_REUSEADDR failed");
181         CLOSESOCKET(listen_socket);
182         return 0;
183     }
184 #endif
185     /* Bind the socket */
186
187     /* complete the socket structure */
188     memset(&sst, 0, sizeof(sst));
189     if (olsr_cnf->ip_version == AF_INET) {
190         struct sockaddr_in *addr4 = (struct sockaddr_in *)&sst;
191         addr4->sin_family = AF_INET;
192         addrlen = sizeof(*addr4);
193 #ifdef SIN6_LEN
194         addr4->sin_len = addrlen;
195 #endif
196         addr4->sin_addr.s_addr = INADDR_ANY;
197         addr4->sin_port = htons(ipc_port);
198     } else {
199         struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&sst;
200         addr6->sin6_family = AF_INET6;
201         addrlen = sizeof(*addr6);
202 #ifdef SIN6_LEN
203         addr6->sin6_len = addrlen;
204 #endif
205         addr6->sin6_addr = in6addr_any;
206         addr6->sin6_port = htons(ipc_port);
207     }
208
209     /* bind the socket to the port number */
210     if (bind(listen_socket, (struct sockaddr *)&sst, addrlen) == -1) {
211 #ifndef NODEBUG
212         OLSR_PRINTF(1, "(TXTINFO) bind()=%s\n", strerror(errno));
213 #endif
214         CLOSESOCKET(listen_socket);
215         return 0;
216     }
217
218     /* show that we are willing to listen */
219     if (listen(listen_socket, 1) == -1) {
220 #ifndef NODEBUG
221         OLSR_PRINTF(1, "(TXTINFO) listen()=%s\n", strerror(errno));
222 #endif
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 #ifndef NODEBUG
231     OLSR_PRINTF(2, "(TXTINFO) listening on port %d\n",ipc_port);
232 #endif
233
234     memset(recv_packets, 0, sizeof(recv_packets));
235     memset(recv_messages, 0, sizeof(recv_messages));
236
237     recv_last_now = now_times / 100;
238     recv_last_relevantTCs = 0;
239     olsr_parser_add_function(&olsr_msg_statistics, PROMISCUOUS);
240     olsr_preprocessor_add_function(&olsr_packet_statistics);
241     return 1;
242 }
243
244
245 static void update_statistics_ptr(void) {
246   int now = now_times / 100;
247   if (recv_last_now < now) {
248     if (recv_last_now + 60 <= now) {
249       memset(recv_packets, 0, sizeof(recv_packets));
250       memset(recv_messages, 0, sizeof(recv_messages));
251       recv_last_now = now % 60;
252     }
253     else {
254       do {
255         int i;
256         recv_last_now++;
257         recv_packets[recv_last_now % 60] = 0;
258
259         for (i=0; i<6; i++) {
260           recv_messages[recv_last_now % 60][i] = 0;
261         }
262       } while (recv_last_now < now);
263     }
264     while (recv_last_relevantTCs != getRelevantTcCount()) {
265       recv_messages[recv_last_now % 60][5]++;
266       recv_last_relevantTCs++;
267     }
268   }
269 }
270
271 /* update message statistics */
272 static bool
273 olsr_msg_statistics(union olsr_message *msg,
274                struct interface *input_if __attribute__ ((unused)),
275                union olsr_ip_addr *from_addr __attribute__ ((unused))) {
276   int idx, msgtype;
277
278   update_statistics_ptr();
279   if (olsr_cnf->ip_version == AF_INET) {
280     msgtype = msg->v4.olsr_msgtype;
281   }
282   else {
283     msgtype = msg->v6.olsr_msgtype;
284   }
285
286   switch (msgtype) {
287     case HELLO_MESSAGE:
288     case TC_MESSAGE:
289     case MID_MESSAGE:
290     case HNA_MESSAGE:
291       idx = msgtype - 1;
292       break;
293
294     case LQ_HELLO_MESSAGE:
295       idx = 0;
296       break;
297     case LQ_TC_MESSAGE:
298       idx = 1;
299       break;
300     default:
301       idx = 4;
302       break;
303   }
304
305   recv_messages[recv_last_now % 60][idx]++;
306   return false;
307 }
308
309 /* update traffic statistics */
310 static char *olsr_packet_statistics(char *packet __attribute__ ((unused)),
311   struct interface *interface __attribute__ ((unused)),
312   union olsr_ip_addr *ip __attribute__ ((unused)),
313   int *length __attribute__ ((unused))) {
314
315   update_statistics_ptr();
316   recv_packets[recv_last_now % 60] += *length;
317
318   return packet;
319 }
320
321 /* destroy the connection */
322 static void conn_destroy(struct ipc_conn *conn)
323 {
324     abuf_free(&conn->resp);
325     free(conn);
326 }
327
328 static void kill_connection(int fd, struct ipc_conn *conn)
329 {
330     remove_olsr_socket(fd, NULL, &ipc_http);
331     CLOSESOCKET(fd);
332     conn_destroy(conn);
333 }
334
335 static void ipc_action(int fd, void *data __attribute__((unused)), unsigned int flags __attribute__((unused)))
336 {
337     struct ipc_conn *conn;
338     struct sockaddr_storage pin;
339 #ifndef NODEBUG
340     char addr[INET6_ADDRSTRLEN];
341 #endif
342     socklen_t addrlen = sizeof(pin);
343     int http_connection = accept(fd, (struct sockaddr *)&pin, &addrlen);
344     union olsr_ip_addr *ipaddr;
345
346     if (http_connection == -1) {
347         /* this may well happen if the other side immediately closes the connection. */
348 #ifndef NODEBUG
349         OLSR_PRINTF(1, "(TXTINFO) accept()=%s\n", strerror(errno));
350 #endif
351         return;
352     }
353
354     /* check if we want ot speak with it */
355     if(olsr_cnf->ip_version == AF_INET) {
356       struct sockaddr_in *addr4 = (struct sockaddr_in *)&pin;
357       ipaddr = (union olsr_ip_addr *)&addr4->sin_addr;
358     } else {
359       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pin;
360       ipaddr = (union olsr_ip_addr *)&addr6->sin6_addr;
361     }
362
363     if (!ip_acl_acceptable(&allowed_nets, ipaddr, olsr_cnf->ip_version)) {
364       OLSR_PRINTF(1, "(TXTINFO) From host(%s) not allowed!\n", addr);
365       CLOSESOCKET(http_connection);
366       return;
367     }
368 #ifndef NODEBUG
369     OLSR_PRINTF(2, "(TXTINFO) Connect from %s\n",addr);
370 #endif
371
372     /* make the fd non-blocking */
373     if (set_nonblocking(http_connection) < 0) {
374         CLOSESOCKET(http_connection);
375         return;
376     }
377
378     conn = malloc(sizeof(*conn));
379     if (conn == NULL) {
380         OLSR_WARN(LOG_PLUGINS, "(TXTINFO) Out of memory!");
381         CLOSESOCKET(http_connection);
382         return;
383     }
384     conn->requlen = 0;
385     *conn->requ = '\0';
386     conn->respstart = 0;
387     abuf_init(&conn->resp, 1000);
388     add_olsr_socket(http_connection, NULL, &ipc_http, conn, SP_IMM_READ);
389 }
390
391 static void ipc_http_read_dummy(int fd, struct ipc_conn *conn)
392 {
393     /* just read dummy stuff */
394     ssize_t bytes_read;
395     char dummybuf[128];
396     do {
397         bytes_read = read(fd, dummybuf, sizeof(dummybuf));
398     } while (bytes_read > 0);
399     if (bytes_read == 0) {
400         /* EOF */
401         if (conn->respstart < conn->resp.len && conn->resp.len > 0) {
402             disable_olsr_socket(fd, NULL, &ipc_http, SP_IMM_READ);
403             conn->requlen = -1;
404             return;
405         }
406     } else if (errno == EINTR || errno == EAGAIN) {
407         /* ignore interrupted sys-calls */
408         return;
409     }
410     /* we had either an error or EOF and we are completely done */
411     kill_connection(fd, conn);
412 }
413
414 static void ipc_http_read(int fd, struct ipc_conn *conn)
415 {
416     int send_what;
417     const char *p;
418     ssize_t bytes_read = read(fd, conn->requ+conn->requlen, sizeof(conn->requ)-conn->requlen-1); /* leave space for a terminating '\0' */
419     if (bytes_read < 0) {
420         if (errno == EINTR || errno == EAGAIN) {
421             return;
422         }
423         OLSR_WARN(LOG_PLUGINS, "(TXTINFO) read error: %s", strerror(errno));
424         kill_connection(fd, conn);
425         return;
426     }
427     conn->requlen += bytes_read;
428     conn->requ[conn->requlen] = '\0';
429
430     /* look if we have the necessary info. We get here somethign like "GET /path HTTP/1.0" */
431     p = strchr(conn->requ, '/');
432     if (p == NULL) {
433         /* input buffer full ? */
434         if ((sizeof(conn->requ)-conn->requlen-1) == 0) {
435           kill_connection(fd, conn);
436           return;
437         }
438         /* we didn't get all. Wait for more data. */
439         return;
440     }
441     if (isprefix(p, "/neighbours")) send_what=SIW_LINK|SIW_NEIGH;
442     else if (isprefix(p, "/neigh")) send_what=SIW_NEIGH;
443     else if (isprefix(p, "/link")) send_what=SIW_LINK;
444     else if (isprefix(p, "/route")) send_what=SIW_ROUTE;
445     else if (isprefix(p, "/hna")) send_what=SIW_HNA;
446     else if (isprefix(p, "/mid")) send_what=SIW_MID;
447     else if (isprefix(p, "/topo")) send_what=SIW_TOPO;
448     else if (isprefix(p, "/stat")) send_what=SIW_STAT;
449     else send_what = SIW_ALL;
450
451     if (send_info(conn, send_what) < 0) {
452         kill_connection(fd, conn);
453         return;
454     }
455     enable_olsr_socket(fd, NULL, &ipc_http, SP_IMM_WRITE);
456 }
457
458 static void ipc_http_write(int fd, struct ipc_conn *conn)
459 {
460     ssize_t bytes_written = write(fd, conn->resp.buf+conn->respstart,
461       conn->resp.len-conn->respstart);
462     if (bytes_written < 0) {
463         if (errno == EINTR || errno == EAGAIN) {
464             return;
465         }
466         OLSR_WARN(LOG_PLUGINS, "(TXTINFO) write error: %s", strerror(errno));
467         kill_connection(fd, conn);
468         return;
469     }
470     conn->respstart += bytes_written;
471     if (conn->respstart >= conn->resp.len) {
472         /* we are done. */
473         if (conn->requlen < 0) {
474             /* we are completely done. */
475             kill_connection(fd, conn);
476         } else if (shutdown(fd, SHUT_WR) < 0) {
477             kill_connection(fd, conn);
478         } else {
479             disable_olsr_socket(fd, NULL, &ipc_http, SP_IMM_WRITE);
480         }
481     }
482 }
483
484 static void ipc_http(int fd, void *data, unsigned int flags)
485 {
486     struct ipc_conn *conn = data;
487     if ((flags & SP_IMM_READ) != 0) {
488         if (conn->resp.len > 0) {
489             ipc_http_read_dummy(fd, conn);
490         } else {
491             ipc_http_read(fd, conn);
492         }
493     }
494     if ((flags & SP_IMM_WRITE) != 0) {
495         ipc_http_write(fd, conn);
496     }
497 }
498
499
500 static int ipc_print_neigh(struct ipc_conn *conn)
501 {
502     struct neighbor_entry *neigh;
503
504     if (abuf_appendf(&conn->resp, "Table: Neighbors\nIP address\tSYM\tMPR\tMPRS\tWill.\t2 Hop Neighbors\n") < 0) {
505         return -1;
506     }
507
508     /* Neighbors */
509     OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
510         struct neighbor_2_list_entry *list_2;
511         struct ipaddr_str buf1;
512         int thop_cnt = 0;
513         for (list_2 = neigh->neighbor_2_list.next;
514              list_2 != &neigh->neighbor_2_list;
515              list_2 = list_2->next) {
516             thop_cnt++;
517         }
518         if (abuf_appendf(&conn->resp,
519                             "%s\t%s\t%s\t%s\t%d\t%d\n",
520                             olsr_ip_to_string(&buf1, &neigh->neighbor_main_addr),
521                             neigh->status == SYM ? "YES" : "NO",
522                             neigh->is_mpr ? "YES" : "NO",
523                             olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO",
524                             neigh->willingness,
525                             thop_cnt) < 0) {
526             return -1;
527         }
528     } OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
529     if (abuf_appendf(&conn->resp, "\n") < 0) {
530         return -1;
531     }
532     return 0;
533 }
534
535 static int ipc_print_link(struct ipc_conn *conn)
536 {
537     struct link_entry *lnk;
538
539     if (abuf_appendf(&conn->resp, "Table: Links\nLocal IP\tRemote IP\tLQ\tNLQ\tCost\n") < 0) {
540         return -1;
541     }
542
543     /* Link set */
544     OLSR_FOR_ALL_LINK_ENTRIES(lnk) {
545         struct ipaddr_str buf1, buf2;
546         struct lqtextbuffer lqbuffer1, lqbuffer2;
547         if (abuf_appendf(&conn->resp,
548                             "%s\t%s\t%s\t%s\t\n",
549                             olsr_ip_to_string(&buf1, &lnk->local_iface_addr),
550                             olsr_ip_to_string(&buf2, &lnk->neighbor_iface_addr),
551                             get_link_entry_text(lnk, '\t', &lqbuffer1),
552                             get_linkcost_text(lnk->linkcost, false, &lqbuffer2)) < 0) {
553             return -1;
554         }
555     } OLSR_FOR_ALL_LINK_ENTRIES_END(lnk);
556
557     if (abuf_appendf(&conn->resp, "\n") < 0) {
558         return -1;
559     }
560     return 0;
561 }
562
563 static int ipc_print_routes(struct ipc_conn *conn)
564 {
565     struct rt_entry *rt;
566
567     if (abuf_appendf(&conn->resp, "Table: Routes\nDestination\tGateway IP\tMetric\tETX\tInterface\n") < 0) {
568         return -1;
569     }
570
571     /* Walk the route table */
572     OLSR_FOR_ALL_RT_ENTRIES(rt) {
573         struct ipaddr_str buf;
574         struct ipprefix_str prefixstr;
575         struct lqtextbuffer lqbuffer;
576         if (abuf_appendf(&conn->resp,
577                             "%s\t%s\t%u\t%s\t%s\t\n",
578                             olsr_ip_prefix_to_string(&prefixstr, &rt->rt_dst),
579                             olsr_ip_to_string(&buf, &rt->rt_best->rtp_nexthop.gateway),
580                             rt->rt_best->rtp_metric.hops,
581                             get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer),
582                             rt->rt_best->rtp_nexthop.interface ? rt->rt_best->rtp_nexthop.interface->int_name : "[null]") < 0) {
583             return -1;
584         }
585     } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
586
587     if (abuf_appendf(&conn->resp, "\n") < 0) {
588         return -1;
589     }
590     return 0;
591 }
592
593 static int ipc_print_topology(struct ipc_conn *conn)
594 {
595     struct tc_entry *tc;
596
597     if (abuf_appendf(&conn->resp, "Table: Topology\nDest. IP\tLast hop IP\tLQ\tNLQ\tCost\n") < 0) {
598         return -1;
599     }
600
601     /* Topology */
602     OLSR_FOR_ALL_TC_ENTRIES(tc) {
603         struct tc_edge_entry *tc_edge;
604         OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
605             if (tc_edge->edge_inv)  {
606                 struct ipaddr_str dstbuf, addrbuf;
607                 struct lqtextbuffer lqbuffer1, lqbuffer2;
608                 if (abuf_appendf(&conn->resp,
609                                     "%s\t%s\t%s\t%s\n",
610                                     olsr_ip_to_string(&dstbuf, &tc_edge->T_dest_addr),
611                                     olsr_ip_to_string(&addrbuf, &tc->addr),
612                                     get_tc_edge_entry_text(tc_edge, '\t', &lqbuffer1),
613                                     get_linkcost_text(tc_edge->cost, false, &lqbuffer2)) < 0) {
614                     return -1;
615                 }
616             }
617         } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
618     } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
619
620     if (abuf_appendf(&conn->resp, "\n") < 0) {
621         return -1;
622     }
623     return 0;
624 }
625
626 static int ipc_print_hna_entry(struct autobuf *autobuf,
627                                const struct olsr_ip_prefix *hna_prefix,
628                                const union olsr_ip_addr *ipaddr)
629 {
630     struct ipaddr_str mainaddrbuf;
631     struct ipprefix_str addrbuf;
632     return abuf_appendf(autobuf,
633                            "%s\t%s\n",
634                            olsr_ip_prefix_to_string(&addrbuf, hna_prefix),
635                            olsr_ip_to_string(&mainaddrbuf, ipaddr));
636 }
637
638 static int ipc_print_hna(struct ipc_conn *conn)
639 {
640     const struct ip_prefix_entry *hna;
641     struct tc_entry *tc;
642
643     if (abuf_appendf(&conn->resp, "Table: HNA\nDestination\tGateway\n") < 0) {
644         return -1;
645     }
646
647     /* Announced HNA entries */
648     OLSR_FOR_ALL_IPPREFIX_ENTRIES(&olsr_cnf->hna_entries, hna) {
649         if (ipc_print_hna_entry(&conn->resp, &hna->net, &olsr_cnf->router_id) < 0) {
650             return -1;
651         }
652     } OLSR_FOR_ALL_IPPREFIX_ENTRIES_END()
653
654     /* HNA entries */
655     OLSR_FOR_ALL_TC_ENTRIES(tc) {
656         struct hna_net *tmp_net;
657         /* Check all networks */
658         OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, tmp_net) {
659             if (ipc_print_hna_entry(&conn->resp, &tmp_net->hna_prefix, &tc->addr) < 0) {
660                 return -1;
661             }
662         } OLSR_FOR_ALL_TC_HNA_ENTRIES_END(tc, tmp_net);
663     } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
664
665     if (abuf_appendf(&conn->resp, "\n") < 0) {
666         return -1;
667     }
668     return 0;
669 }
670
671 static int ipc_print_mid(struct ipc_conn *conn)
672 {
673     struct tc_entry *tc;
674
675     if (abuf_appendf(&conn->resp, "Table: MID\nIP address\tAliases\n") < 0) {
676         return -1;
677     }
678
679     /* MID root is the TC entry */
680     OLSR_FOR_ALL_TC_ENTRIES(tc) {
681         struct ipaddr_str buf;
682         struct mid_entry *alias;
683         char sep = '\t';
684         if (abuf_puts(&conn->resp,  olsr_ip_to_string(&buf, &tc->addr)) < 0) {
685             return -1;
686         }
687
688         OLSR_FOR_ALL_TC_MID_ENTRIES(tc, alias) {
689             if (abuf_appendf(&conn->resp,
690                                 "%c%s",
691                                 sep,
692                                 olsr_ip_to_string(&buf, &alias->mid_alias_addr)) < 0) {
693                 return -1;
694             }
695             sep = ';';
696         }  OLSR_FOR_ALL_TC_MID_ENTRIES_END(tc, alias);
697         if (abuf_appendf(&conn->resp, "\n") < 0) {
698             return -1;
699         }
700     } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
701     if (abuf_appendf(&conn->resp, "\n") < 0) {
702         return -1;
703     }
704     return 0;
705 }
706
707 static int ipc_print_stat(struct ipc_conn *conn)
708 {
709     static const char *names[] = { "HELLO", "TC", "MID", "HNA", "Other", "Rel.TCs" };
710
711     uint32_t msgs[5], traffic, i, j;
712     clock_t slot = (now_times/100 + 59) % 60;
713
714     if (abuf_appendf(&conn->resp, "Table: Statistics (without duplicates)\nType\tlast seconds\t\t\t\tlast min.\taverage\n") < 0) {
715         return -1;
716     }
717
718     for (j=0; j<5; j++) {
719       msgs[j] = 0;
720       for (i=0; i<60; i++) {
721         msgs[j] += recv_messages[i][j];
722       }
723     }
724
725     traffic = 0;
726     for (i=0; i<60; i++) {
727       traffic += recv_packets[i];
728     }
729
730     for (i=0; i<6; i++) {
731       if (abuf_appendf(&conn->resp, "%s\t%u\t%u\t%u\t%u\t%u\t%u\t\t%u\n", names[i],
732             recv_messages[(slot)%60][i],
733             recv_messages[(slot+59)%60][i],
734             recv_messages[(slot+58)%60][i],
735             recv_messages[(slot+57)%60][i],
736             recv_messages[(slot+56)%60][i],
737             msgs[i],
738             msgs[i]/60) < 0) {
739           return -1;
740       }
741     }
742     if (abuf_appendf(&conn->resp, "\nTraffic: %8u bytes/s\t%u bytes/minute\taverage %u bytes/s\n",
743           recv_packets[(slot)%60],
744           traffic,
745           traffic/60) < 0) {
746         return -1;
747     }
748     return 0;
749 }
750
751 static int send_info(struct ipc_conn *conn, int send_what)
752 {
753     int rv;
754
755     /* Print minimal http header */
756     if (abuf_appendf(&conn->resp,
757                         "HTTP/1.0 200 OK\n"
758                         "Content-type: text/plain\n\n") < 0) {
759         return -1;
760     }
761
762      /* Print tables to IPC socket */
763
764     rv = 0;
765      /* links + Neighbors */
766     if ((send_what & SIW_LINK) != 0 && ipc_print_link(conn) < 0) {
767         rv = -1;
768     }
769     if ((send_what & SIW_NEIGH) != 0 && ipc_print_neigh(conn) < 0) {
770         rv = -1;
771     }
772      /* topology */
773     if ((send_what & SIW_TOPO) != 0) {
774         rv = ipc_print_topology(conn);
775     }
776      /* hna */
777     if ((send_what & SIW_HNA) != 0) {
778         rv = ipc_print_hna(conn);
779     }
780      /* mid */
781     if ((send_what & SIW_MID) != 0) {
782         rv = ipc_print_mid(conn);
783     }
784      /* routes */
785     if ((send_what & SIW_ROUTE) != 0) {
786         rv = ipc_print_routes(conn);
787     }
788     /* statistics */
789     if ((send_what & SIW_STAT) != 0) {
790         rv = ipc_print_stat(conn);
791     }
792     return rv;
793 }
794
795 /*
796  * Local Variables:
797  * mode: c
798  * style: linux
799  * c-basic-offset: 4
800  * indent-tabs-mode: nil
801  * End:
802  */