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