made it compile without warnings on Win32
[olsrd.git] / lib / txtinfo / src / olsrd_txtinfo.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas T√łnnesen(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  * $Id: olsrd_txtinfo.c,v 1.6 2007/05/09 17:29:53 bernd67 Exp $
44  */
45
46 /*
47  * Dynamic linked library for the olsr.org olsr daemon
48  */
49
50  
51 #include <sys/types.h>
52 #include <sys/socket.h>
53 #if !defined WIN32
54 #include <sys/select.h>
55 #endif
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
58 #include <sys/time.h>
59 #include <time.h>
60 #include <math.h>
61 #include <stdio.h>
62 #include <string.h>
63 #include <stdlib.h>
64 #include <stdarg.h>
65 #include <unistd.h>
66 #include <errno.h>
67
68 #include "olsr.h"
69 #include "olsr_types.h"
70 #include "neighbor_table.h"
71 #include "two_hop_neighbor_table.h"
72 #include "mpr_selector_set.h"
73 #include "tc_set.h"
74 #include "hna_set.h"
75 #include "mid_set.h"
76 #include "link_set.h"
77 #include "socket_parser.h"
78
79 #include "olsrd_txtinfo.h"
80 #include "olsrd_plugin.h"
81
82
83 #ifdef WIN32
84 #define close(x) closesocket(x)
85 #endif
86
87
88 static int ipc_socket;
89 static int ipc_open;
90 static int ipc_connection;
91 static int ipc_socket_up;
92
93
94 /* IPC initialization function */
95 static int
96 plugin_ipc_init(void);
97
98 static void 
99 send_info(int neighonly);
100
101 static void
102 ipc_action(int);
103
104 static void
105 ipc_print_neigh_link(void);
106
107 static void
108 ipc_print_routes(void);
109
110 static void
111 ipc_print_topology(void);
112
113 static void
114 ipc_print_hna(void);
115
116 static void
117 ipc_print_mid(void);
118
119 #define TXT_IPC_BUFSIZE 256
120 static int 
121 ipc_sendf(const char* format, ...) __attribute__((format(printf, 1, 2)));
122
123 /**
124  *Do initialization here
125  *
126  *This function is called by the my_init
127  *function in uolsrd_plugin.c
128  */
129 int
130 olsrd_plugin_init(void)
131 {
132   /* Initial IPC value */
133   ipc_open = 0;
134   ipc_socket_up = 0;
135
136   plugin_ipc_init();
137   return 1;
138 }
139
140
141 /**
142  * destructor - called at unload
143  */
144 void
145 olsr_plugin_exit(void)
146 {
147   if(ipc_open)
148     close(ipc_socket);
149 }
150
151
152
153 static int
154 plugin_ipc_init(void)
155 {
156   struct sockaddr_in sin;
157   olsr_u32_t yes = 1;
158
159   /* Init ipc socket */
160   if ((ipc_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
161     {
162 #ifndef NODEBUG
163       olsr_printf(1, "(TXTINFO) socket()=%s\n", strerror(errno));
164 #endif
165       return 0;
166     }
167   else
168     {
169       if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) 
170       {
171 #ifndef NODEBUG
172         olsr_printf(1, "(TXTINFO) setsockopt()=%s\n", strerror(errno));
173 #endif
174         return 0;
175       }
176
177 #if defined __FreeBSD__ && defined SO_NOSIGPIPE
178       if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) 
179       {
180         perror("SO_REUSEADDR failed");
181         return 0;
182       }
183 #endif
184
185       /* Bind the socket */
186       
187       /* complete the socket structure */
188       memset(&sin, 0, sizeof(sin));
189       sin.sin_family = AF_INET;
190       sin.sin_addr.s_addr = INADDR_ANY;
191       sin.sin_port = htons(ipc_port);
192       
193       /* bind the socket to the port number */
194       if (bind(ipc_socket, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
195         {
196 #ifndef NODEBUG
197           olsr_printf(1, "(TXTINFO) bind()=%s\n", strerror(errno));
198 #endif
199           return 0;
200         }
201       
202       /* show that we are willing to listen */
203       if (listen(ipc_socket, 1) == -1) 
204         {
205 #ifndef NODEBUG
206           olsr_printf(1, "(TXTINFO) listen()=%s\n", strerror(errno));
207 #endif
208           return 0;
209         }
210         
211       /* Register with olsrd */
212       add_olsr_socket(ipc_socket, &ipc_action);
213
214 #ifndef NODEBUG
215       olsr_printf(2, "(TXTINFO) listening on port %d\n",ipc_port);
216 #endif
217       ipc_socket_up = 1;
218     }
219
220   return 1;
221 }
222
223
224 static void
225 ipc_action(int fd)
226 {
227   struct sockaddr_in pin;
228   socklen_t addrlen;
229   char *addr;  
230
231   addrlen = sizeof(struct sockaddr_in);
232
233   if(ipc_open)
234     return;
235
236   if ((ipc_connection = accept(fd, (struct sockaddr *)  &pin, &addrlen)) == -1)
237     {
238 #ifndef NODEBUG
239       olsr_printf(1, "(TXTINFO) accept()=%s\n", strerror(errno));
240 #endif
241       exit(1);
242     }
243   else
244     {
245       fd_set rfds;
246       struct timeval tv = {0,0};
247       int neighonly = 0;
248
249       addr = inet_ntoa(pin.sin_addr);
250       if(ntohl(pin.sin_addr.s_addr) != ntohl(ipc_accept_ip.s_addr))
251         {
252           olsr_printf(1, "(TXTINFO) From host(%s) not allowed!\n", addr);
253           close(ipc_connection);
254           return;
255         }
256       else
257         {
258       ipc_open = 1;
259 #ifndef NODEBUG
260       olsr_printf(2, "(TXTINFO) Connect from %s\n",addr);
261 #endif
262       
263       /* purge read buffer to prevent blocking on linux*/
264       FD_ZERO(&rfds);
265       FD_SET((unsigned int)ipc_connection, &rfds); /* Win32 needs the cast here */
266       if(select(ipc_connection+1, &rfds, NULL, NULL, &tv)) {
267         char requ[128];
268         ssize_t s = recv(ipc_connection, (void*)&requ, sizeof(requ), 0); /* Win32 needs the cast here */
269         if (0 < s) {
270           requ[s] = 0;
271           /* To print out neighbours only on the Freifunk Status
272            * page the normal output is somewhat lengthy. The
273            * header parsing is sufficient for standard wget.
274            */
275           neighonly = (0 != strstr(requ, "/neighbours"));
276         }
277       }
278
279       send_info(neighonly);
280           
281       close(ipc_connection);
282       ipc_open = 0;
283     }
284   }
285 }
286
287 static void
288 ipc_print_neigh_link(void)
289 {
290   struct neighbor_entry *neigh;
291   struct neighbor_2_list_entry *list_2;
292   struct link_entry *link = NULL;
293   int index, thop_cnt;
294
295         ipc_sendf("Table: Links\nLocal IP\tremote IP\tHysteresis\tLinkQuality\tlost\ttotal\tNLQ\tETX\n");
296
297   /* Link set */
298   link = link_set;
299         while(link)
300         {
301         ipc_sendf( "%s\t%s\t%0.2f\t%0.2f\t%d\t%d\t%0.2f\t%0.2f\t\n",
302                         olsr_ip_to_string(&link->local_iface_addr),
303                         olsr_ip_to_string(&link->neighbor_iface_addr),
304                         link->L_link_quality, 
305                         link->loss_link_quality,
306                         link->lost_packets, 
307                         link->total_packets,
308                         link->neigh_link_quality, 
309                         (link->loss_link_quality * link->neigh_link_quality) ? 1.0 / (link->loss_link_quality * link->neigh_link_quality) : 0.0);
310                 link = link->next;
311       }
312         ipc_sendf("\nTable: Neighbors\nIP address\tSYM\tMPR\tMPRS\tWillingness\t2 Hop Neighbors\n");
313
314   /* Neighbors */
315   for(index=0;index<HASHSIZE;index++)
316     {
317       for(neigh = neighbortable[index].next;
318           neigh != &neighbortable[index];
319           neigh = neigh->next)
320         {
321                 ipc_sendf( 
322                           "%s\t%s\t%s\t%s\t%d\t", 
323                           olsr_ip_to_string(&neigh->neighbor_main_addr),
324                           (neigh->status == SYM) ? "YES" : "NO",
325                           neigh->is_mpr ? "YES" : "NO",
326                           olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO",
327                           neigh->willingness);
328
329           thop_cnt = 0;
330
331           for(list_2 = neigh->neighbor_2_list.next;
332               list_2 != &neigh->neighbor_2_list;
333               list_2 = list_2->next)
334             {
335               //size += sprintf(&buf[size], "<option>%s</option>\n", olsr_ip_to_string(&list_2->neighbor_2->neighbor_2_addr));
336               thop_cnt ++;
337             }
338                 ipc_sendf("%d\n", thop_cnt);
339         }
340     }
341
342         ipc_sendf("\n");
343 }
344
345
346 static void
347 ipc_print_routes(void)
348 {
349   int size = 0, index;
350   struct rt_entry *routes;
351
352         ipc_sendf("Table: Routes\nDestination\tGateway\tMetric\tETX\tInterface\tType\n");
353
354   /* Neighbors */
355   for(index = 0;index < HASHSIZE;index++)
356     {
357       for(routes = routingtable[index].next;
358           routes != &routingtable[index];
359           routes = routes->next)
360         {
361                 size = 0;
362                 ipc_sendf( "%s\t%s\t%d\t%.2f\t%s\tHOST\n",
363                           olsr_ip_to_string(&routes->rt_dst),
364                           olsr_ip_to_string(&routes->rt_router),
365                           routes->rt_metric,
366                           routes->rt_etx,
367                           routes->rt_if->int_name);
368         }
369     }
370
371   /* HNA */
372   for(index = 0;index < HASHSIZE;index++)
373     {
374       for(routes = hna_routes[index].next;
375           routes != &hna_routes[index];
376           routes = routes->next)
377         {
378                 ipc_sendf("%s\t%s\t%d\t%s\t\tHNA\n",
379                           olsr_ip_to_string(&routes->rt_dst),
380                           olsr_ip_to_string(&routes->rt_router),
381                           routes->rt_metric,
382                           routes->rt_if->int_name);
383         }
384     }
385
386         ipc_sendf("\n");
387
388 }
389
390 static void
391 ipc_print_topology(void)
392 {
393   olsr_u8_t index;
394   struct tc_entry *entry;
395   struct topo_dst *dst_entry;
396
397
398   ipc_sendf("Table: Topology\nDestination IP\tLast hop IP\tLQ\tILQ\tETX\n");
399
400   /* Topology */  
401   for(index=0;index<HASHSIZE;index++)
402     {
403       /* For all TC entries */
404       entry = tc_table[index].next;
405       while(entry != &tc_table[index])
406         {
407           /* For all destination entries of that TC entry */
408           dst_entry = entry->destinations.next;
409           while(dst_entry != &entry->destinations)
410             {
411                         ipc_sendf( "%s\t%s\t%0.2f\t%0.2f\t%0.2f\n", 
412                               olsr_ip_to_string(&dst_entry->T_dest_addr),
413                               olsr_ip_to_string(&entry->T_last_addr), 
414                               dst_entry->link_quality,
415                               dst_entry->inverse_link_quality,
416                               (dst_entry->link_quality * dst_entry->inverse_link_quality) ? 1.0 / (dst_entry->link_quality * dst_entry->inverse_link_quality) : 0.0);
417                 
418               dst_entry = dst_entry->next;
419             }
420           entry = entry->next;
421         }
422     }
423
424   ipc_sendf("\n");
425 }
426
427 static void
428 ipc_print_hna(void)
429 {
430   int size;
431   olsr_u8_t index;
432   struct hna_entry *tmp_hna;
433   struct hna_net *tmp_net;
434   struct hna4_entry *hna4;
435   struct hna6_entry *hna6;
436
437   size = 0;
438
439   ipc_sendf("Table: HNA\nNetwork\tNetmask\tGateway\n");
440
441   /* Announced HNA entries */
442         for(hna4 = olsr_cnf->hna4_entries; hna4; hna4 = hna4->next)
443           {
444                         ipc_sendf("%s\t%s\t%s\n",
445                           olsr_ip_to_string(&hna4->net),
446                           olsr_ip_to_string(&hna4->netmask),
447                                 olsr_ip_to_string(&olsr_cnf->main_addr));
448           }
449         for(hna6 = olsr_cnf->hna6_entries; hna6; hna6 = hna6->next)
450           {
451                         ipc_sendf("%s\t%d\t%s\n",
452                           olsr_ip_to_string(&hna6->net),
453                                 hna6->prefix_len,
454                         olsr_ip_to_string(&olsr_cnf->main_addr));
455                 }
456
457   /* HNA entries */
458   for(index=0;index<HASHSIZE;index++)
459     {
460       tmp_hna = hna_set[index].next;
461       /* Check all entrys */
462       while(tmp_hna != &hna_set[index])
463         {
464           /* Check all networks */
465           tmp_net = tmp_hna->networks.next;
466               
467           while(tmp_net != &tmp_hna->networks)
468             {
469                 if (AF_INET == olsr_cnf->ip_version) {
470                         ipc_sendf("%s\t%s\t%s\n",
471                                 olsr_ip_to_string(&tmp_net->A_network_addr),
472                                 olsr_ip_to_string((union olsr_ip_addr *)&tmp_net->A_netmask.v4),
473                                 olsr_ip_to_string(&tmp_hna->A_gateway_addr));
474                 }
475                 else {
476                         ipc_sendf("%s\t%d\t%s\n",
477                                 olsr_ip_to_string(&tmp_net->A_network_addr),
478                                 tmp_net->A_netmask.v6,
479                                 olsr_ip_to_string(&tmp_hna->A_gateway_addr));
480                 }
481               tmp_net = tmp_net->next;
482             }
483               
484           tmp_hna = tmp_hna->next;
485         }
486     }
487
488         ipc_sendf("\n");
489
490 }
491
492 static void
493 ipc_print_mid(void)
494 {
495     olsr_u8_t index;
496     unsigned short is_first;
497     struct mid_entry *entry;
498     struct mid_address *alias;
499
500     ipc_sendf("Table: MID\nIP\tAliases\n");
501
502     /* MID */
503     for( index = 0; index < HASHSIZE; index++ )
504     {
505         entry = mid_set[index].next;
506
507         while( entry != &mid_set[index] )
508         {
509             ipc_sendf( olsr_ip_to_string( &entry->main_addr ) );
510             alias = entry->aliases;
511             is_first = 1;
512
513             while( alias )
514             {
515                 ipc_sendf( "%s%s",
516                     ( is_first ? "\t" : ";" ),
517                     olsr_ip_to_string( &alias->alias )
518                 );
519
520                 alias = alias->next_alias;
521                 is_first = 0;
522             }
523
524             entry = entry->next;
525             ipc_sendf("\n");
526         }
527     }
528
529         ipc_sendf("\n");
530 }
531
532
533 static void 
534 send_info(int neighonly)
535 {
536         
537         /* Print minimal http header */
538         ipc_sendf("HTTP/1.0 200 OK\n");
539         ipc_sendf("Content-type: text/plain\n\n");
540
541         /* Print tables to IPC socket */
542         
543         /* links + Neighbors */
544         ipc_print_neigh_link();
545         
546         /* topology */
547         if (!neighonly) ipc_print_topology();
548         
549         /* hna */
550         if (!neighonly) ipc_print_hna();
551
552         /* mid */
553         if (!neighonly) ipc_print_mid();
554
555         /* routes */
556         if (!neighonly) ipc_print_routes();
557 }
558
559 /*
560  * In a bigger mesh, there are probs with the fixed
561  * bufsize. Because the Content-Length header is
562  * optional, the sprintf() is changed to a more
563  * scalable solution here.
564  */
565  
566 static int 
567 ipc_sendf(const char* format, ...)
568 {
569         char txtnetbuf[TXT_IPC_BUFSIZE];
570
571         va_list arg;
572         int rv;
573 #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __MacOSX__
574         int flags = 0;
575 #else
576         int flags = MSG_NOSIGNAL;
577 #endif
578         va_start(arg, format);
579         rv = vsnprintf(txtnetbuf, sizeof(txtnetbuf), format, arg);
580         va_end(arg);
581         if(ipc_socket_up) {
582                 if (0 > send(ipc_connection, txtnetbuf, rv, flags)) {
583 #ifndef NODEBUG
584                         olsr_printf(1, "(TXTINFO) Failed sending data to client!\n");
585 #endif
586                         close(ipc_connection);
587                         return - 1;
588                 }
589         }
590         return rv;
591 }