Win32 fixes: use CLOSESOCKET to close sockets
[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 read(fd,buf,size) recv((fd), (buf), (size), 0)
78 #define write(fd,buf,size) send((fd), (buf), (size), 0)
79 #endif
80
81
82 struct ipc_conn {
83     struct autobuf resp;
84     int respstart;
85     int requlen;
86     char requ[256];
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 *);
115 static int ipc_print_hna(struct ipc_conn *);
116
117 static int ipc_print_mid(struct ipc_conn *);
118
119 #define isprefix(str, pre) (strncmp((str), (pre), strlen(pre)) == 0)
120
121 #define SIW_NEIGH       (1 << 0)
122 #define SIW_LINK        (1 << 1)
123 #define SIW_ROUTE       (1 << 2)
124 #define SIW_HNA         (1 << 3)
125 #define SIW_MID         (1 << 4)
126 #define SIW_TOPO        (1 << 5)
127 #define SIW_ALL         (SIW_NEIGH|SIW_LINK|SIW_ROUTE|SIW_HNA|SIW_MID|SIW_TOPO)
128
129 /**
130  * destructor - called at unload
131  */
132 void olsr_plugin_exit(void)
133 {
134     CLOSESOCKET(listen_socket);
135 }
136
137 /**
138  *Do initialization here
139  *
140  *This function is called by the my_init
141  *function in uolsrd_plugin.c
142  */
143 int
144 olsrd_plugin_init(void)
145 {
146     struct sockaddr_storage sst;
147     uint32_t yes = 1;
148     socklen_t addrlen;
149
150     /* Init ipc socket */
151     listen_socket = socket(olsr_cnf->ip_version, SOCK_STREAM, 0);
152     if (listen_socket == -1) {
153 #ifndef NODEBUG
154         olsr_printf(1, "(TXTINFO) socket()=%s\n", strerror(errno));
155 #endif
156         return 0;
157     }
158     if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
159 #ifndef NODEBUG
160         olsr_printf(1, "(TXTINFO) setsockopt()=%s\n", strerror(errno));
161 #endif
162         CLOSESOCKET(listen_socket);
163         return 0;
164     }
165
166 #if defined __FreeBSD__ && defined SO_NOSIGPIPE
167     if (setsockopt(listen_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) {
168         perror("SO_REUSEADDR failed");
169         CLOSESOCKET(listen_socket);
170         return 0;
171     }
172 #endif
173     /* Bind the socket */
174
175     /* complete the socket structure */
176     memset(&sst, 0, sizeof(sst));
177     if (olsr_cnf->ip_version == AF_INET) {
178         struct sockaddr_in *addr4 = (struct sockaddr_in *)&sst;
179         addr4->sin_family = AF_INET;
180         addrlen = sizeof(*addr4);
181 #ifdef SIN6_LEN
182         addr4->sin_len = addrlen;
183 #endif
184         addr4->sin_addr.s_addr = INADDR_ANY;
185         addr4->sin_port = htons(ipc_port);
186     } else {
187         struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&sst;
188         addr6->sin6_family = AF_INET6;
189         addrlen = sizeof(*addr6);
190 #ifdef SIN6_LEN
191         addr6->sin6_len = addrlen;
192 #endif
193         addr6->sin6_addr = in6addr_any;
194         addr6->sin6_port = htons(ipc_port);
195     }
196
197     /* bind the socket to the port number */
198     if (bind(listen_socket, (struct sockaddr *)&sst, addrlen) == -1) {
199 #ifndef NODEBUG
200         olsr_printf(1, "(TXTINFO) bind()=%s\n", strerror(errno));
201 #endif
202         CLOSESOCKET(listen_socket);
203         return 0;
204     }
205
206     /* show that we are willing to listen */
207     if (listen(listen_socket, 1) == -1) {
208 #ifndef NODEBUG
209         olsr_printf(1, "(TXTINFO) listen()=%s\n", strerror(errno));
210 #endif
211         CLOSESOCKET(listen_socket);
212         return 0;
213     }
214
215     /* Register with olsrd */
216     add_olsr_socket(listen_socket, NULL, &ipc_action, NULL, SP_IMM_READ);
217
218 #ifndef NODEBUG
219     olsr_printf(2, "(TXTINFO) listening on port %d\n",ipc_port);
220 #endif
221     return 1;
222 }
223
224 /* destroy the connection */
225 static void conn_destroy(struct ipc_conn *conn)
226 {
227     abuf_free(&conn->resp);
228     free(conn);
229 }
230
231 static void kill_connection(int fd, struct ipc_conn *conn)
232 {
233     remove_olsr_socket(fd, NULL, &ipc_http);
234     CLOSESOCKET(fd);
235     conn_destroy(conn);
236 }
237
238 static void ipc_action(int fd, void *data __attribute__((unused)), unsigned int flags __attribute__((unused)))
239 {
240     struct ipc_conn *conn;
241     struct sockaddr_storage pin;
242     char addr[INET6_ADDRSTRLEN];
243     socklen_t addrlen = sizeof(pin);
244     int http_connection = accept(fd, (struct sockaddr *)&pin, &addrlen);
245
246     if (http_connection == -1) {
247         /* this may well happen if the other side immediately closes the connection. */
248 #ifndef NODEBUG
249         olsr_printf(1, "(TXTINFO) accept()=%s\n", strerror(errno));
250 #endif
251         return;
252     }
253     /* check if we want ot speak with it */
254     if (olsr_cnf->ip_version == AF_INET) {
255         const struct sockaddr_in *addr4 = (struct sockaddr_in *)&pin;
256         if (inet_ntop(olsr_cnf->ip_version, &addr4->sin_addr, addr, sizeof(addr)) == NULL) {
257              addr[0] = '\0';
258         }
259         if (!ip4equal(&addr4->sin_addr, &ipc_accept_ip.v4)) {
260             olsr_printf(1, "(TXTINFO) From host(%s) not allowed!\n", addr);
261             CLOSESOCKET(http_connection);
262             return;
263         }
264     } else {
265         const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pin;
266         if (inet_ntop(olsr_cnf->ip_version, &addr6->sin6_addr, addr, sizeof(addr)) == NULL) {
267              addr[0] = '\0';
268         }
269        /* Use in6addr_any (::) in olsr.conf to allow anybody. */
270         if (!ip6equal(&in6addr_any, &ipc_accept_ip.v6) &&
271            !ip6equal(&addr6->sin6_addr, &ipc_accept_ip.v6)) {
272             olsr_printf(1, "(TXTINFO) From host(%s) not allowed!\n", addr);
273             CLOSESOCKET(http_connection);
274             return;
275         }
276     }
277 #ifndef NODEBUG
278     olsr_printf(2, "(TXTINFO) Connect from %s\n",addr);
279 #endif
280
281     /* make the fd non-blocking */
282     if (set_nonblocking(http_connection) < 0) {
283         CLOSESOCKET(http_connection);
284         return;
285     }
286
287     conn = malloc(sizeof(*conn));
288     if (conn == NULL) {
289         olsr_syslog(OLSR_LOG_ERR, "(TXTINFO) Out of memory!");
290         CLOSESOCKET(http_connection);
291         return;
292     }
293     conn->requlen = 0;
294     *conn->requ = '\0';
295     conn->respstart = 0;
296     abuf_init(&conn->resp, 1000);
297     add_olsr_socket(http_connection, NULL, &ipc_http, conn, SP_IMM_READ);
298 }
299
300 static void ipc_http_read_dummy(int fd, struct ipc_conn *conn)
301 {
302     /* just read dummy stuff */
303     ssize_t bytes_read;
304     char dummybuf[128];
305     do {
306         bytes_read = read(fd, dummybuf, sizeof(dummybuf));
307     } while (bytes_read > 0);
308     if (bytes_read == 0) {
309         /* EOF */
310         if (conn->respstart < conn->resp.len && conn->resp.len > 0) {
311             disable_olsr_socket(fd, NULL, &ipc_http, SP_IMM_READ);
312             conn->requlen = -1;
313             return;
314         }
315     } else if (errno == EINTR || errno == EAGAIN) {
316         /* ignore interrupted sys-calls */
317         return;
318     }
319     /* we had either an error or EOF and we are completely done */
320     kill_connection(fd, conn);
321 }
322
323 static void ipc_http_read(int fd, struct ipc_conn *conn)
324 {
325     int send_what;
326     const char *p;
327     ssize_t bytes_read = read(fd, conn->requ+conn->requlen, sizeof(conn->requ)-conn->requlen-1); /* leave space for a terminating '\0' */
328     if (bytes_read < 0) {
329         if (errno == EINTR || errno == EAGAIN) {
330             return;
331         }
332         olsr_syslog(OLSR_LOG_ERR, "(TXTINFO) read error: %s", strerror(errno));
333         kill_connection(fd, conn);
334         return;
335     }
336     conn->requlen += bytes_read;
337     conn->requ[conn->requlen] = '\0';
338
339     /* look if we have the necessary info. We get here somethign like "GET /path HTTP/1.0" */
340     p = strchr(conn->requ, '/');
341     if (p == NULL) {
342         /* we didn't get all. Wait for more data. */
343         return;
344     }
345     if (isprefix(p, "/neighbours")) send_what=SIW_LINK|SIW_NEIGH;
346     else if (isprefix(p, "/neigh")) send_what=SIW_NEIGH;
347     else if (isprefix(p, "/link")) send_what=SIW_LINK;
348     else if (isprefix(p, "/route")) send_what=SIW_ROUTE;
349     else if (isprefix(p, "/hna")) send_what=SIW_HNA;
350     else if (isprefix(p, "/mid")) send_what=SIW_MID;
351     else if (isprefix(p, "/topo")) send_what=SIW_TOPO;
352     else send_what = SIW_ALL;
353
354     if (send_info(conn, send_what) < 0) {
355         kill_connection(fd, conn);
356         return;
357     }
358     enable_olsr_socket(fd, NULL, &ipc_http, SP_IMM_WRITE);
359 }
360
361 static void ipc_http_write(int fd, struct ipc_conn *conn)
362 {
363     ssize_t bytes_written = write(fd, conn->resp.buf+conn->respstart,
364       conn->resp.len-conn->respstart);
365     if (bytes_written < 0) {
366         if (errno == EINTR || errno == EAGAIN) {
367             return;
368         }
369         olsr_syslog(OLSR_LOG_ERR, "(TXTINFO) write error: %s", strerror(errno));
370         kill_connection(fd, conn);
371         return;
372     }
373     conn->respstart += bytes_written;
374     if (conn->respstart >= conn->resp.len) {
375         /* we are done. */
376         if (conn->requlen < 0) {
377             /* we are completely done. */
378             kill_connection(fd, conn);
379         } else if (shutdown(fd, SHUT_WR) < 0) {
380             kill_connection(fd, conn);
381         } else {
382             disable_olsr_socket(fd, NULL, &ipc_http, SP_IMM_WRITE);
383         }
384     }
385 }
386
387 static void ipc_http(int fd, void *data, unsigned int flags)
388 {
389     struct ipc_conn *conn = data;
390     if ((flags & SP_IMM_READ) != 0) {
391         if (conn->resp.len > 0) {
392             ipc_http_read_dummy(fd, conn);
393         } else {
394             ipc_http_read(fd, conn);
395         }
396     }
397     if ((flags & SP_IMM_WRITE) != 0) {
398         ipc_http_write(fd, conn);
399     }
400 }
401
402
403 static int ipc_print_neigh(struct ipc_conn *conn)
404 {
405     struct neighbor_entry *neigh;
406
407     if (abuf_appendf(&conn->resp, "Table: Neighbors\nIP address\tSYM\tMPR\tMPRS\tWill.\t2 Hop Neighbors\n") < 0) {
408         return -1;
409     }
410
411     /* Neighbors */
412     OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
413         struct neighbor_2_list_entry *list_2;
414         struct ipaddr_str buf1;
415         int thop_cnt = 0;
416         for (list_2 = neigh->neighbor_2_list.next;
417              list_2 != &neigh->neighbor_2_list;
418              list_2 = list_2->next) {
419             thop_cnt++;
420         }
421         if (abuf_appendf(&conn->resp,
422                             "%s\t%s\t%s\t%s\t%d\t%d\n",
423                             olsr_ip_to_string(&buf1, &neigh->neighbor_main_addr),
424                             neigh->status == SYM ? "YES" : "NO",
425                             neigh->is_mpr ? "YES" : "NO",
426                             olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO",
427                             neigh->willingness,
428                             thop_cnt) < 0) {
429             return -1;
430         }
431     } OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
432     if (abuf_appendf(&conn->resp, "\n") < 0) {
433         return -1;
434     }
435     return 0;
436 }
437
438 static int ipc_print_link(struct ipc_conn *conn)
439 {
440     struct link_entry *lnk;
441
442     if (abuf_appendf(&conn->resp, "Table: Links\nLocal IP\tRemote IP\tHyst.\tLQ\tNLQ\tCost\n") < 0) {
443         return -1;
444     }
445
446     /* Link set */
447     OLSR_FOR_ALL_LINK_ENTRIES(lnk) {
448         struct ipaddr_str buf1, buf2;
449         struct lqtextbuffer lqbuffer1, lqbuffer2;
450         if (abuf_appendf(&conn->resp,
451                             "%s\t%s\t%0.2f\t%s\t%s\t\n",
452                             olsr_ip_to_string(&buf1, &lnk->local_iface_addr),
453                             olsr_ip_to_string(&buf2, &lnk->neighbor_iface_addr),
454                             lnk->L_link_quality,
455                             get_link_entry_text(lnk, '\t', &lqbuffer1),
456                             get_linkcost_text(lnk->linkcost, false, &lqbuffer2)) < 0) {
457             return -1;
458         }
459     } OLSR_FOR_ALL_LINK_ENTRIES_END(lnk);
460
461     if (abuf_appendf(&conn->resp, "\n") < 0) {
462         return -1;
463     }
464     return 0;
465 }
466
467 static int ipc_print_routes(struct ipc_conn *conn)
468 {
469     struct rt_entry *rt;
470
471     if (abuf_appendf(&conn->resp, "Table: Routes\nDestination\tGateway IP\tMetric\tETX\tInterface\n") < 0) {
472         return -1;
473     }
474
475     /* Walk the route table */
476     OLSR_FOR_ALL_RT_ENTRIES(rt) {
477         struct ipaddr_str buf;
478         struct ipprefix_str prefixstr;
479         struct lqtextbuffer lqbuffer;
480         if (abuf_appendf(&conn->resp,
481                             "%s\t%s\t%u\t%s\t%s\t\n",
482                             olsr_ip_prefix_to_string(&prefixstr, &rt->rt_dst),
483                             olsr_ip_to_string(&buf, &rt->rt_best->rtp_nexthop.gateway),
484                             rt->rt_best->rtp_metric.hops,
485                             get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer),
486                             if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index)) < 0) {
487             return -1;
488         }
489     } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
490
491     if (abuf_appendf(&conn->resp, "\n") < 0) {
492         return -1;
493     }
494     return 0;
495 }
496
497 static int ipc_print_topology(struct ipc_conn *conn)
498 {
499     struct tc_entry *tc;
500
501     if (abuf_appendf(&conn->resp, "Table: Topology\nDest. IP\tLast hop IP\tLQ\tNLQ\tCost\n") < 0) {
502         return -1;
503     }
504
505     /* Topology */
506     OLSR_FOR_ALL_TC_ENTRIES(tc) {
507         struct tc_edge_entry *tc_edge;
508         OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
509             if (tc_edge->edge_inv)  {
510                 struct ipaddr_str dstbuf, addrbuf;
511                 struct lqtextbuffer lqbuffer1, lqbuffer2;
512                 if (abuf_appendf(&conn->resp,
513                                     "%s\t%s\t%s\t%s\n",
514                                     olsr_ip_to_string(&dstbuf, &tc_edge->T_dest_addr),
515                                     olsr_ip_to_string(&addrbuf, &tc->addr),
516                                     get_tc_edge_entry_text(tc_edge, '\t', &lqbuffer1),
517                                     get_linkcost_text(tc_edge->cost, false, &lqbuffer2)) < 0) {
518                     return -1;
519                 }
520             }
521         } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
522     } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
523
524     if (abuf_appendf(&conn->resp, "\n") < 0) {
525         return -1;
526     }
527     return 0;
528 }
529
530 static int ipc_print_hna_entry(struct autobuf *autobuf,
531                                const struct olsr_ip_prefix *hna_prefix,
532                                const union olsr_ip_addr *ipaddr)
533 {
534     struct ipaddr_str mainaddrbuf;
535     struct ipprefix_str addrbuf;
536     return abuf_appendf(autobuf,
537                            "%s\t%s\n",
538                            olsr_ip_prefix_to_string(&addrbuf, hna_prefix),
539                            olsr_ip_to_string(&mainaddrbuf, ipaddr));
540 }
541
542 static int ipc_print_hna(struct ipc_conn *conn)
543 {
544     const struct ip_prefix_list *hna;
545     struct tc_entry *tc;
546
547     if (abuf_appendf(&conn->resp, "Table: HNA\nDestination\tGateway\n") < 0) {
548         return -1;
549     }
550
551     /* Announced HNA entries */
552     for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next) {
553         if (ipc_print_hna_entry(&conn->resp, &hna->net, &olsr_cnf->main_addr) < 0) {
554             return -1;
555         }
556     }
557
558     /* HNA entries */
559     OLSR_FOR_ALL_TC_ENTRIES(tc) {
560         struct hna_net *tmp_net;
561         /* Check all networks */
562         OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, tmp_net) {
563             if (ipc_print_hna_entry(&conn->resp, &tmp_net->hna_prefix, &tc->addr) < 0) {
564                 return -1;
565             }
566         } OLSR_FOR_ALL_TC_HNA_ENTRIES_END(tc, tmp_net);
567     } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
568
569     if (abuf_appendf(&conn->resp, "\n") < 0) {
570         return -1;
571     }
572     return 0;
573 }
574
575 static int ipc_print_mid(struct ipc_conn *conn)
576 {
577     struct tc_entry *tc;
578
579     if (abuf_appendf(&conn->resp, "Table: MID\nIP address\tAliases\n") < 0) {
580         return -1;
581     }
582
583     /* MID root is the TC entry */
584     OLSR_FOR_ALL_TC_ENTRIES(tc) {
585         struct ipaddr_str buf;
586         struct mid_entry *alias;
587         char sep = '\t';
588         if (abuf_puts(&conn->resp,  olsr_ip_to_string(&buf, &tc->addr)) < 0) {
589             return -1;
590         }
591
592         OLSR_FOR_ALL_TC_MID_ENTRIES(tc, alias) {
593             if (abuf_appendf(&conn->resp,
594                                 "%c%s",
595                                 sep,
596                                 olsr_ip_to_string(&buf, &alias->mid_alias_addr)) < 0) {
597                 return -1;
598             }
599             sep = ';';
600         }  OLSR_FOR_ALL_TC_MID_ENTRIES_END(tc, alias);
601         if (abuf_appendf(&conn->resp, "\n") < 0) {
602             return -1;
603         }
604     } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
605     if (abuf_appendf(&conn->resp, "\n") < 0) {
606         return -1;
607     }
608     return 0;
609 }
610
611 static int send_info(struct ipc_conn *conn, int send_what)
612 {
613     int rv;
614
615     /* Print minimal http header */
616     if (abuf_appendf(&conn->resp,
617                         "HTTP/1.0 200 OK\n"
618                         "Content-type: text/plain\n\n") < 0) {
619         return -1;
620     }
621
622      /* Print tables to IPC socket */
623
624     rv = 0;
625      /* links + Neighbors */
626     if ((send_what & SIW_LINK) != 0 && ipc_print_link(conn) < 0) {
627         rv = -1;
628     }
629     if ((send_what & SIW_NEIGH) != 0 && ipc_print_neigh(conn) < 0) {
630         rv = -1;
631     }
632      /* topology */
633     if ((send_what & SIW_TOPO) != 0) {
634         rv = ipc_print_topology(conn);
635     }
636      /* hna */
637     if ((send_what & SIW_HNA) != 0) {
638         rv = ipc_print_hna(conn);
639     }
640      /* mid */
641     if ((send_what & SIW_MID) != 0) {
642         rv = ipc_print_mid(conn);
643     }
644      /* routes */
645     if ((send_what & SIW_ROUTE) != 0) {
646         rv = ipc_print_routes(conn);
647     }
648     return rv;
649 }
650
651 /*
652  * Local Variables:
653  * mode: c
654  * style: linux
655  * c-basic-offset: 4
656  * indent-tabs-mode: nil
657  * End:
658  */