3 * The olsr.org Optimized Link-State Routing daemon(olsrd)
4 * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
5 * includes code by Bruno Randolf
6 * includes code by Andreas Lopatic
7 * includes code by Sven-Ola Tuecke
8 * includes code by Lorenz Schori
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
15 * * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * * Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
21 * * Neither the name of olsr.org, olsrd nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
38 * Visit http://www.olsr.org for more information.
40 * If you find this software useful feel free to make a donation
41 * to the project. For more information see the website or contact
42 * the copyright holders.
47 * Dynamic linked library for the olsr.org olsr daemon
50 #include <sys/types.h>
51 #include <sys/socket.h>
53 #include <sys/select.h>
55 #include <netinet/in.h>
56 #include <arpa/inet.h>
68 #include "olsr_types.h"
69 #include "neighbor_table.h"
70 #include "two_hop_neighbor_table.h"
71 #include "mpr_selector_set.h"
76 #include "socket_parser.h"
78 #include "lq_plugin.h"
79 #include "common/autobuf.h"
81 #include "olsrd_txtinfo.h"
82 #include "olsrd_plugin.h"
85 #define close(x) closesocket(x)
88 static int ipc_socket;
90 /* IPC initialization function */
91 static int plugin_ipc_init(void);
93 static void send_info(int send_what, int socket);
95 static void ipc_action(int);
97 static void ipc_print_neigh(struct autobuf *);
99 static void ipc_print_link(struct autobuf *);
101 static void ipc_print_routes(struct autobuf *);
103 static void ipc_print_topology(struct autobuf *);
105 static void ipc_print_hna(struct autobuf *);
107 static void ipc_print_mid(struct autobuf *);
109 #define TXT_IPC_BUFSIZE 256
118 #define SIW_NEIGHLINK 7
120 #define MAX_CLIENTS 3
122 static char *outbuffer[MAX_CLIENTS];
123 static size_t outbuffer_size[MAX_CLIENTS];
124 static size_t outbuffer_written[MAX_CLIENTS];
125 static int outbuffer_socket[MAX_CLIENTS];
126 static int outbuffer_count;
128 static struct timer_entry *writetimer_entry;
131 *Do initialization here
133 *This function is called by the my_init
134 *function in uolsrd_plugin.c
137 olsrd_plugin_init(void)
139 /* Initial IPC value */
147 * destructor - called at unload
150 olsr_plugin_exit(void)
152 if (ipc_socket != -1)
157 plugin_ipc_init(void)
159 struct sockaddr_storage sst;
160 struct sockaddr_in *sin;
161 struct sockaddr_in6 *sin6;
165 /* Init ipc socket */
166 if ((ipc_socket = socket(olsr_cnf->ip_version, SOCK_STREAM, 0)) == -1) {
168 olsr_printf(1, "(TXTINFO) socket()=%s\n", strerror(errno));
172 if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
174 olsr_printf(1, "(TXTINFO) setsockopt()=%s\n", strerror(errno));
178 #if defined __FreeBSD__ && defined SO_NOSIGPIPE
179 if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) {
180 perror("SO_REUSEADDR failed");
184 /* Bind the socket */
186 /* complete the socket structure */
187 memset(&sst, 0, sizeof(sst));
188 if (olsr_cnf->ip_version == AF_INET) {
189 sin = (struct sockaddr_in *)&sst;
190 sin->sin_family = AF_INET;
191 addrlen = sizeof(struct sockaddr_in);
193 sin->sin_len = addrlen;
195 sin->sin_addr.s_addr = INADDR_ANY;
196 sin->sin_port = htons(ipc_port);
198 sin6 = (struct sockaddr_in6 *)&sst;
199 sin6->sin6_family = AF_INET6;
200 addrlen = sizeof(struct sockaddr_in6);
202 sin6->sin6_len = addrlen;
204 sin6->sin6_addr = in6addr_any;
205 sin6->sin6_port = htons(ipc_port);
208 /* bind the socket to the port number */
209 if (bind(ipc_socket, (struct sockaddr *)&sst, addrlen) == -1) {
211 olsr_printf(1, "(TXTINFO) bind()=%s\n", strerror(errno));
216 /* show that we are willing to listen */
217 if (listen(ipc_socket, 1) == -1) {
219 olsr_printf(1, "(TXTINFO) listen()=%s\n", strerror(errno));
224 /* Register with olsrd */
225 add_olsr_socket(ipc_socket, &ipc_action);
228 olsr_printf(2, "(TXTINFO) listening on port %d\n", ipc_port);
237 struct sockaddr_storage pin;
238 struct sockaddr_in *sin4;
239 struct sockaddr_in6 *sin6;
240 char addr[INET6_ADDRSTRLEN];
246 socklen_t addrlen = sizeof(struct sockaddr_storage);
248 if ((ipc_connection = accept(fd, (struct sockaddr *)&pin, &addrlen)) == -1) {
250 olsr_printf(1, "(TXTINFO) accept()=%s\n", strerror(errno));
255 tv.tv_sec = tv.tv_usec = 0;
256 if (olsr_cnf->ip_version == AF_INET) {
257 sin4 = (struct sockaddr_in *)&pin;
258 if (inet_ntop(olsr_cnf->ip_version, &sin4->sin_addr, addr, INET6_ADDRSTRLEN) == NULL)
260 if (!ip4equal(&sin4->sin_addr, &ipc_accept_ip.v4)) {
261 olsr_printf(1, "(TXTINFO) From host(%s) not allowed!\n", addr);
262 close(ipc_connection);
266 sin6 = (struct sockaddr_in6 *)&pin;
267 if (inet_ntop(olsr_cnf->ip_version, &sin6->sin6_addr, addr, INET6_ADDRSTRLEN) == NULL)
269 /* Use in6addr_any (::) in olsr.conf to allow anybody. */
270 if (!ip6equal(&in6addr_any, &ipc_accept_ip.v6) && !ip6equal(&sin6->sin6_addr, &ipc_accept_ip.v6)) {
271 olsr_printf(1, "(TXTINFO) From host(%s) not allowed!\n", addr);
272 close(ipc_connection);
278 olsr_printf(2, "(TXTINFO) Connect from %s\n", addr);
281 /* purge read buffer to prevent blocking on linux */
283 FD_SET((unsigned int)ipc_connection, &rfds); /* Win32 needs the cast here */
284 if (0 <= select(ipc_connection + 1, &rfds, NULL, NULL, &tv)) {
286 ssize_t s = recv(ipc_connection, (void *)&requ, sizeof(requ), 0); /* Win32 needs the cast here */
289 /* To print out neighbours only on the Freifunk Status
290 * page the normal output is somewhat lengthy. The
291 * header parsing is sufficient for standard wget.
293 if (0 != strstr(requ, "/neighbours"))
294 send_what = SIW_NEIGHLINK;
295 else if (0 != strstr(requ, "/neigh"))
296 send_what = SIW_NEIGH;
297 else if (0 != strstr(requ, "/link"))
298 send_what = SIW_LINK;
299 else if (0 != strstr(requ, "/route"))
300 send_what = SIW_ROUTE;
301 else if (0 != strstr(requ, "/hna"))
303 else if (0 != strstr(requ, "/mid"))
305 else if (0 != strstr(requ, "/topo"))
306 send_what = SIW_TOPO;
310 send_info(send_what, ipc_connection);
314 ipc_print_neigh(struct autobuf *abuf)
316 struct ipaddr_str buf1;
317 struct neighbor_entry *neigh;
318 struct neighbor_2_list_entry *list_2;
321 abuf_puts(abuf, "Table: Neighbors\nIP address\tSYM\tMPR\tMPRS\tWill.\t2 Hop Neighbors\n");
324 OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
325 abuf_appendf(abuf, "%s\t%s\t%s\t%s\t%d\t", olsr_ip_to_string(&buf1, &neigh->neighbor_main_addr), (neigh->status == SYM) ? "YES" : "NO",
326 neigh->is_mpr ? "YES" : "NO", olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO", neigh->willingness);
329 for (list_2 = neigh->neighbor_2_list.next; list_2 != &neigh->neighbor_2_list; list_2 = list_2->next) {
330 //size += sprintf(&buf[size], "<option>%s</option>\n", olsr_ip_to_string(&buf1, &list_2->neighbor_2->neighbor_2_addr));
333 abuf_appendf(abuf, "%d\n", thop_cnt);
335 OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
336 abuf_puts(abuf, "\n");
340 ipc_print_link(struct autobuf *abuf)
342 struct ipaddr_str buf1, buf2;
343 struct lqtextbuffer lqbuffer1, lqbuffer2;
345 struct link_entry *link = NULL;
347 abuf_puts(abuf, "Table: Links\nLocal IP\tRemote IP\tHyst.\tLQ\tNLQ\tCost\n");
350 OLSR_FOR_ALL_LINK_ENTRIES(link) {
351 abuf_appendf(abuf, "%s\t%s\t%0.2f\t%s\t%s\t\n", olsr_ip_to_string(&buf1, &link->local_iface_addr),
352 olsr_ip_to_string(&buf2, &link->neighbor_iface_addr), link->L_link_quality, get_link_entry_text(link, '\t',
354 get_linkcost_text(link->linkcost, false, &lqbuffer2));
355 } OLSR_FOR_ALL_LINK_ENTRIES_END(link);
357 abuf_puts(abuf, "\n");
361 ipc_print_routes(struct autobuf *abuf)
363 struct ipaddr_str buf1, buf2;
365 struct lqtextbuffer lqbuffer;
367 abuf_puts(abuf, "Table: Routes\nDestination\tGateway IP\tMetric\tETX\tInterface\n");
369 /* Walk the route table */
370 OLSR_FOR_ALL_RT_ENTRIES(rt) {
371 abuf_appendf(abuf, "%s/%d\t%s\t%d\t%s\t%s\t\n", olsr_ip_to_string(&buf1, &rt->rt_dst.prefix), rt->rt_dst.prefix_len,
372 olsr_ip_to_string(&buf2, &rt->rt_best->rtp_nexthop.gateway), rt->rt_best->rtp_metric.hops,
373 get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer),
374 if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
375 } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
377 abuf_puts(abuf, "\n");
382 ipc_print_topology(struct autobuf *abuf)
386 abuf_puts(abuf, "Table: Topology\nDest. IP\tLast hop IP\tLQ\tNLQ\tCost\n");
389 OLSR_FOR_ALL_TC_ENTRIES(tc) {
390 struct tc_edge_entry *tc_edge;
391 OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
392 if (tc_edge->edge_inv) {
393 struct ipaddr_str dstbuf, addrbuf;
394 struct lqtextbuffer lqbuffer1, lqbuffer2;
395 abuf_appendf(abuf, "%s\t%s\t%s\t%s\n", olsr_ip_to_string(&dstbuf, &tc_edge->T_dest_addr), olsr_ip_to_string(&addrbuf, &tc->addr),
396 get_tc_edge_entry_text(tc_edge, '\t', &lqbuffer1), get_linkcost_text(tc_edge->cost, false, &lqbuffer2));
398 } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
399 } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
401 abuf_puts(abuf, "\n");
405 ipc_print_hna(struct autobuf *abuf)
408 struct ip_prefix_list *hna;
409 struct hna_entry *tmp_hna;
410 struct hna_net *tmp_net;
411 struct ipaddr_str addrbuf, mainaddrbuf;
415 abuf_puts(abuf, "Table: HNA\nDestination\tGateway\n");
417 /* Announced HNA entries */
418 if (olsr_cnf->ip_version == AF_INET) {
419 for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next) {
420 struct ipaddr_str addrbuf, mainaddrbuf;
421 abuf_appendf(abuf, "%s/%d\t%s\n", olsr_ip_to_string(&addrbuf, &hna->net.prefix), hna->net.prefix_len,
422 olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->main_addr));
425 for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next) {
426 struct ipaddr_str addrbuf, mainaddrbuf;
427 abuf_appendf(abuf, "%s/%d\t%s\n", olsr_ip_to_string(&addrbuf, &hna->net.prefix), hna->net.prefix_len,
428 olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->main_addr));
433 OLSR_FOR_ALL_HNA_ENTRIES(tmp_hna) {
435 /* Check all networks */
436 for (tmp_net = tmp_hna->networks.next; tmp_net != &tmp_hna->networks; tmp_net = tmp_net->next) {
438 abuf_appendf(abuf, "%s/%d\t%s\n", olsr_ip_to_string(&addrbuf, &tmp_net->A_network_addr), tmp_net->prefixlen,
439 olsr_ip_to_string(&mainaddrbuf, &tmp_hna->A_gateway_addr));
442 OLSR_FOR_ALL_HNA_ENTRIES_END(tmp_hna);
444 abuf_puts(abuf, "\n");
448 ipc_print_mid(struct autobuf *abuf)
451 unsigned short is_first;
452 struct mid_entry *entry;
453 struct mid_address *alias;
455 abuf_puts(abuf, "Table: MID\nIP address\tAliases\n");
458 for (index = 0; index < HASHSIZE; index++) {
459 entry = mid_set[index].next;
461 while (entry != &mid_set[index]) {
462 struct ipaddr_str buf;
463 abuf_puts(abuf, olsr_ip_to_string(&buf, &entry->main_addr));
464 alias = entry->aliases;
468 abuf_appendf(abuf, "%s%s", (is_first ? "\t" : ";"), olsr_ip_to_string(&buf, &alias->alias));
470 alias = alias->next_alias;
474 abuf_puts(abuf,"\n");
477 abuf_puts(abuf, "\n");
481 txtinfo_write_data(void *foo __attribute__ ((unused))) {
483 int result, i, j, max;
488 for (i=0; i<outbuffer_count; i++) {
489 FD_SET(outbuffer_socket[i], &set);
490 if (outbuffer_socket[i] > max) {
491 max = outbuffer_socket[i];
498 result = select(max + 1, NULL, &set, NULL, &tv);
503 for (i=0; i<outbuffer_count; i++) {
504 if (FD_ISSET(outbuffer_socket[i], &set)) {
505 result = write(outbuffer_socket[i], outbuffer[i] + outbuffer_written[i], outbuffer_size[i] - outbuffer_written[i]);
507 outbuffer_written[i] += result;
510 if (result <= 0 || outbuffer_written[i] == outbuffer_size[i]) {
511 /* close this socket and cleanup*/
512 close(outbuffer_socket[i]);
515 for (j=i+1; j<outbuffer_count; j++) {
516 outbuffer[j-1] = outbuffer[j];
517 outbuffer_size[j-1] = outbuffer_size[j];
518 outbuffer_socket[j-1] = outbuffer_socket[j];
519 outbuffer_written[j-1] = outbuffer_written[j];
525 if (outbuffer_count == 0) {
526 olsr_stop_timer(writetimer_entry);
531 send_info(int send_what, int socket)
535 abuf_init(&abuf, 4096);
537 /* Print minimal http header */
538 abuf_puts(&abuf, "HTTP/1.0 200 OK\n");
539 abuf_puts(&abuf, "Content-type: text/plain\n\n");
541 /* Print tables to IPC socket */
543 /* links + Neighbors */
544 if ((send_what == SIW_ALL) || (send_what == SIW_NEIGHLINK) || (send_what == SIW_LINK))
545 ipc_print_link(&abuf);
547 if ((send_what == SIW_ALL) || (send_what == SIW_NEIGHLINK) || (send_what == SIW_NEIGH))
548 ipc_print_neigh(&abuf);
551 if ((send_what == SIW_ALL) || (send_what == SIW_TOPO))
552 ipc_print_topology(&abuf);
555 if ((send_what == SIW_ALL) || (send_what == SIW_HNA))
556 ipc_print_hna(&abuf);
559 if ((send_what == SIW_ALL) || (send_what == SIW_MID))
560 ipc_print_mid(&abuf);
563 if ((send_what == SIW_ALL) || (send_what == SIW_ROUTE))
564 ipc_print_routes(&abuf);
566 outbuffer[outbuffer_count] = olsr_malloc(abuf.len, "txt output buffer");
567 outbuffer_size[outbuffer_count] = abuf.len;
568 outbuffer_written[outbuffer_count] = 0;
569 outbuffer_socket[outbuffer_count] = socket;
571 memcpy(outbuffer[outbuffer_count], abuf.buf, abuf.len);
574 if (outbuffer_count == 1) {
575 writetimer_entry = olsr_start_timer(100, 0, OLSR_TIMER_PERIODIC, &txtinfo_write_data, NULL, 0);
586 * indent-tabs-mode: nil