9cccfc7bf512bed8dc2b416005eebf17bde35306
[olsrd.git] / lib / httpinfo / src / olsrd_httpinfo.c
1 /*
2  * HTTP Info plugin for the olsr.org OLSR daemon
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org)
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  * $Id: olsrd_httpinfo.c,v 1.45 2005/02/17 21:31:52 kattemat Exp $
40  */
41
42 /*
43  * Dynamic linked library for the olsr.org olsr daemon
44  */
45
46 #include "olsrd_httpinfo.h"
47 #include "olsr_cfg.h"
48 #include "link_set.h"
49 #include "gfx.h"
50 #include "html.h"
51 #include "admin_interface.h"
52 #include "interfaces.h"
53 #include <stdio.h>
54 #include <string.h>
55 #include <stdlib.h>
56 #include <unistd.h>
57 #include <errno.h>
58
59 #ifdef OS
60 #undef OS
61 #endif
62
63 #ifdef WIN32
64 #define close(x) closesocket(x)
65 #define OS "Windows"
66 #endif
67 #ifdef linux
68 #define OS "GNU/Linux"
69 #endif
70 #ifdef __FreeBSD__
71 #define OS "FreeBSD"
72 #endif
73
74 #ifndef OS
75 #define OS "Undefined"
76 #endif
77
78 static char copyright_string[] = "olsr.org HTTPINFO plugin Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org) All rights reserved.";
79
80 #define MAX_CLIENTS 3
81
82 #define MAX_HTTPREQ_SIZE 1024 * 10
83
84 #define DEFAULT_TCP_PORT 8080
85
86 #define HTML_BUFSIZE 1024*50
87
88 #define FRAMEWIDTH 800
89
90 #define ACTIVE_TAB "class=\"active\""
91
92 #define FILENREQ_MATCH(req, filename) \
93         !strcmp(req, filename) || \
94         (strlen(req) && !strcmp(&req[1], filename))
95
96 struct tab_entry
97 {
98   char *tab_label;
99   char *filename;
100   int(*build_body_cb)(char *, olsr_u32_t);
101 };
102
103 struct static_bin_file_entry
104 {
105   char *filename;
106   unsigned char *data;
107   unsigned int data_size;
108 };
109
110 struct static_txt_file_entry
111 {
112   char *filename;
113   const char **data;
114 };
115
116 struct dynamic_file_entry
117 {
118   char *filename;
119   int(*process_data_cb)(char *, olsr_u32_t, char *, olsr_u32_t);
120 };
121
122 static int
123 get_http_socket(int);
124
125 int
126 build_tabs(char *, int);
127
128 void
129 parse_http_request(int);
130
131 int
132 build_http_header(http_header_type, olsr_bool, olsr_u32_t, char *, olsr_u32_t);
133
134 static int
135 build_frame(char *, char *, int, char *, olsr_u32_t, int(*frame_body_cb)(char *, olsr_u32_t));
136
137 int
138 build_routes_body(char *, olsr_u32_t);
139
140 int
141 build_config_body(char *, olsr_u32_t);
142
143 int
144 build_neigh_body(char *, olsr_u32_t);
145
146 int
147 build_topo_body(char *, olsr_u32_t);
148
149 int
150 build_hna_body(char *, olsr_u32_t);
151
152 int
153 build_mid_body(char *, olsr_u32_t);
154
155 int
156 build_nodes_body(char *, olsr_u32_t);
157
158 int
159 build_all_body(char *, olsr_u32_t);
160
161 int
162 build_about_body(char *, olsr_u32_t);
163
164
165
166 char *
167 sockaddr_to_string(struct sockaddr *);
168
169 olsr_bool
170 check_allowed_ip(union olsr_ip_addr *);
171
172 static char *
173 get_copyright_string(void);
174
175 static struct timeval start_time;
176 static struct http_stats stats;
177 static int client_sockets[MAX_CLIENTS];
178 static int curr_clients;
179 static int http_socket;
180
181
182
183 struct tab_entry tab_entries[] =
184   {
185     {"Configuration", "config", build_config_body},
186     {"Routes", "routes", build_routes_body},
187     {"Links/Topology", "nodes", build_nodes_body},
188     {"All", "all", build_all_body},
189 #ifdef INCLUDE_SETTINGS
190     {"Admin", "admin", build_admin_body},
191 #endif
192     {"About", "about", build_about_body},
193     {NULL, NULL, NULL}
194   };
195
196 struct static_bin_file_entry static_bin_files[] =
197   {
198     {"favicon.ico", favicon_ico, 1406/*favicon_ico_len*/},
199     {"logo.gif", logo_gif, 2801/*logo_gif_len*/},
200     {"grayline.gif", grayline_gif, 43/*grayline_gif_len*/},
201     {NULL, NULL, 0}
202   };
203
204 struct static_txt_file_entry static_txt_files[] =
205   {
206     {"httpinfo.css", httpinfo_css},
207     {NULL, NULL}
208   };
209
210
211 struct dynamic_file_entry dynamic_files[] =
212   {
213 #ifdef INCLUDE_SETTINGS
214     {"set_values", process_set_values},
215 #endif
216     {NULL, NULL}
217   };
218
219 /**
220  *Do initialization here
221  *
222  *This function is called by the my_init
223  *function in uolsrd_plugin.c
224  */
225 int
226 olsr_plugin_init()
227 {
228   get_copyright_string();
229   /* Get start time */
230   gettimeofday(&start_time, NULL);
231
232   curr_clients = 0;
233   /* set up HTTP socket */
234   http_socket = get_http_socket(http_port != 0 ? http_port :  DEFAULT_TCP_PORT);
235
236   if(http_socket < 0)
237     {
238       fprintf(stderr, "(HTTPINFO) could not initialize HTTP socket\n");
239       exit(0);
240     }
241
242   /* Register socket */
243   add_olsr_socket(http_socket, &parse_http_request);
244
245   return 1;
246 }
247
248 static int
249 get_http_socket(int port)
250 {
251   struct sockaddr_in sin;
252   olsr_u32_t yes = 1;
253   int s;
254
255   /* Init ipc socket */
256   if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
257     {
258       olsr_printf(1, "(HTTPINFO)socket %s\n", strerror(errno));
259       return -1;
260     }
261
262   if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) 
263     {
264       olsr_printf(1, "(HTTPINFO)SO_REUSEADDR failed %s\n", strerror(errno));
265       close(s);
266       return -1;
267     }
268
269
270
271   /* Bind the socket */
272   
273   /* complete the socket structure */
274   memset(&sin, 0, sizeof(sin));
275   sin.sin_family = AF_INET;
276   sin.sin_addr.s_addr = INADDR_ANY;
277   sin.sin_port = htons(port);
278   
279   /* bind the socket to the port number */
280   if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
281     {
282       olsr_printf(1, "(HTTPINFO) bind failed %s\n", strerror(errno));
283       return -1;
284     }
285       
286   /* show that we are willing to listen */
287   if (listen(s, 1) == -1) 
288     {
289       olsr_printf(1, "(HTTPINFO) listen failed %s\n", strerror(errno));
290       return -1;
291     }
292
293   return s;
294 }
295
296
297 /* Non reentrant - but we are not multithreaded anyway */
298 void
299 parse_http_request(int fd)
300 {
301   struct sockaddr_in pin;
302   socklen_t addrlen;
303   char *addr;  
304   char req[MAX_HTTPREQ_SIZE];
305   static char body[HTML_BUFSIZE];
306   char req_type[11];
307   char filename[251];
308   char http_version[11];
309   int c = 0, r = 1, size = 0;
310
311   addrlen = sizeof(struct sockaddr_in);
312
313   if(curr_clients >= MAX_CLIENTS)
314     return;
315
316   curr_clients++;
317
318   if ((client_sockets[curr_clients] = accept(fd, (struct sockaddr *)  &pin, &addrlen)) == -1)
319     {
320       olsr_printf(1, "(HTTPINFO) accept: %s\n", strerror(errno));
321       goto close_connection;
322     }
323
324   if(!check_allowed_ip((union olsr_ip_addr *)&pin.sin_addr.s_addr))
325     {
326       olsr_printf(1, "HTTP request from non-allowed host %s!\n", 
327                   olsr_ip_to_string((union olsr_ip_addr *)&pin.sin_addr.s_addr));
328       close(client_sockets[curr_clients]);
329     }
330
331   addr = inet_ntoa(pin.sin_addr);
332
333
334   memset(req, 0, MAX_HTTPREQ_SIZE);
335   memset(body, 0, 1024*10);
336
337   while((r = recv(client_sockets[curr_clients], &req[c], 1, 0)) > 0 && (c < (MAX_HTTPREQ_SIZE-1)))
338     {
339       c++;
340
341       if((c > 3 && !strcmp(&req[c-4], "\r\n\r\n")) ||
342          (c > 1 && !strcmp(&req[c-2], "\n\n")))
343         break;
344     }
345   
346   if(r < 0)
347     {
348       olsr_printf(1, "(HTTPINFO) Failed to recieve data from client!\n");
349       stats.err_hits++;
350       goto close_connection;
351     }
352   
353   /* Get the request */
354   if(sscanf(req, "%10s %250s %10s\n", req_type, filename, http_version) != 3)
355     {
356       /* Try without HTTP version */
357       if(sscanf(req, "%10s %250s\n", req_type, filename) != 2)
358         {
359           olsr_printf(1, "(HTTPINFO) Error parsing request %s!\n", req);
360           stats.err_hits++;
361           goto close_connection;
362         }
363     }
364   
365   
366   olsr_printf(1, "Request: %s\nfile: %s\nVersion: %s\n\n", req_type, filename, http_version);
367
368   if(!strcmp(req_type, "POST"))
369     {
370 #ifdef INCLUDE_SETTINGS
371       int i = 0;
372       while(dynamic_files[i].filename)
373         {
374           printf("POST checking %s\n", dynamic_files[i].filename);
375           if(FILENREQ_MATCH(filename, dynamic_files[i].filename))
376             {
377               olsr_u32_t param_size;
378
379               stats.ok_hits++;
380
381               param_size = recv(client_sockets[curr_clients], req, MAX_HTTPREQ_SIZE-1, 0);
382
383               req[param_size] = '\0';
384               printf("Dynamic read %d bytes\n", param_size);
385               
386               //memcpy(body, dynamic_files[i].data, static_bin_files[i].data_size);
387               size += dynamic_files[i].process_data_cb(req, param_size, &body[size], HTML_BUFSIZE - size);
388               c = build_http_header(HTTP_OK, OLSR_TRUE, size, req, MAX_HTTPREQ_SIZE);  
389               goto send_http_data;
390             }
391           i++;
392         }
393 #endif
394       /* We only support GET */
395       strcpy(body, HTTP_400_MSG);
396       stats.ill_hits++;
397       c = build_http_header(HTTP_BAD_REQ, OLSR_TRUE, strlen(body), req, MAX_HTTPREQ_SIZE);
398     }
399   else if(!strcmp(req_type, "GET"))
400     {
401       int i = 0;
402       int y = 0;
403
404       while(static_bin_files[i].filename)
405         {
406           if(FILENREQ_MATCH(filename, static_bin_files[i].filename))
407             break;
408           i++;
409         }
410       
411       if(static_bin_files[i].filename)
412         {
413           stats.ok_hits++;
414           memcpy(body, static_bin_files[i].data, static_bin_files[i].data_size);
415           size = static_bin_files[i].data_size;
416           c = build_http_header(HTTP_OK, OLSR_FALSE, size, req, MAX_HTTPREQ_SIZE);  
417           goto send_http_data;
418         }
419
420       i = 0;
421
422       while(static_txt_files[i].filename)
423         {
424           if(FILENREQ_MATCH(filename, static_txt_files[i].filename))
425             break;
426           i++;
427         }
428       
429       if(static_txt_files[i].filename)
430         {
431           stats.ok_hits++;
432           y = 0;
433           while(static_txt_files[i].data[y])
434             {
435               size += sprintf(&body[size], static_txt_files[i].data[y]);
436               y++;
437             }
438
439           c = build_http_header(HTTP_OK, OLSR_FALSE, size, req, MAX_HTTPREQ_SIZE);  
440           goto send_http_data;
441         }
442
443       i = 0;
444
445       if(strlen(filename) > 1)
446         {
447           while(tab_entries[i].filename)
448             {
449               if(FILENREQ_MATCH(filename, tab_entries[i].filename))
450                 break;
451               i++;
452             }
453         }
454
455       if(tab_entries[i].filename)
456         {
457           y = 0;
458           while(http_ok_head[y])
459             {
460               size += sprintf(&body[size], http_ok_head[y]);
461               y++;
462             }
463           
464           size += build_tabs(&body[size], i);
465           size += build_frame("Current Routes", 
466                               "routes", 
467                               FRAMEWIDTH, 
468                               &body[size], 
469                               HTML_BUFSIZE - size, 
470                               tab_entries[i].build_body_cb);
471           
472           stats.ok_hits++;
473           
474           y = 0;
475           while(http_ok_tail[y])
476             {
477               size += sprintf(&body[size], http_ok_tail[y]);
478               y++;
479             }  
480           
481           c = build_http_header(HTTP_OK, OLSR_TRUE, size, req, MAX_HTTPREQ_SIZE);
482           
483           goto send_http_data;
484         }
485       
486       
487       stats.ill_hits++;
488       strcpy(body, HTTP_404_MSG);
489       c = build_http_header(HTTP_BAD_FILE, OLSR_TRUE, strlen(body), req, MAX_HTTPREQ_SIZE);
490     }
491   else
492     {
493       /* We only support GET */
494       strcpy(body, HTTP_400_MSG);
495       stats.ill_hits++;
496       c = build_http_header(HTTP_BAD_REQ, OLSR_TRUE, strlen(body), req, MAX_HTTPREQ_SIZE);
497     }
498
499  send_http_data:
500   
501   r = send(client_sockets[curr_clients], req, c, 0);   
502   if(r < 0)
503     {
504       olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
505       goto close_connection;
506     }
507
508   r = send(client_sockets[curr_clients], body, size, 0);
509   if(r < 0)
510     {
511       olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
512       goto close_connection;
513     }
514
515  close_connection:
516   close(client_sockets[curr_clients]);
517   curr_clients--;
518
519 }
520
521
522 int
523 build_http_header(http_header_type type, 
524                   olsr_bool is_html, 
525                   olsr_u32_t size, 
526                   char *buf, 
527                   olsr_u32_t bufsize)
528 {
529   time_t currtime;
530   char timestr[45];
531   char tmp[30];
532
533   memset(buf, 0, bufsize);
534
535   switch(type)
536     {
537     case(HTTP_BAD_REQ):
538       memcpy(buf, HTTP_400, strlen(HTTP_400));
539       break;
540     case(HTTP_BAD_FILE):
541       memcpy(buf, HTTP_404, strlen(HTTP_404));
542       break;
543     default:
544       /* Defaults to OK */
545       memcpy(buf, HTTP_200, strlen(HTTP_200));
546       break;
547     }
548
549
550   /* Date */
551   if(time(&currtime))
552     {
553       strftime(timestr, 45, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", gmtime(&currtime));
554       strcat(buf, timestr);
555     }
556   
557   /* Server version */
558   strcat(buf, "Server: " PLUGIN_NAME " " PLUGIN_VERSION " " HTTP_VERSION "\r\n");
559
560   /* connection-type */
561   strcat(buf,"Connection: closed\r\n");
562
563   /* MIME type */
564   if(is_html)
565     strcat(buf, "Content-type: text/html\r\n");
566   else
567     strcat(buf, "Content-type: text/plain\r\n");
568
569   /* Content length */
570   if(size > 0)
571     {
572       sprintf(tmp, "Content-length: %i\r\n", size);
573       strcat(buf, tmp);
574     }
575
576
577   /* Cache-control 
578    * No caching dynamic pages
579    */
580   strcat(buf, "Cache-Control: no-cache\r\n");
581
582   if(!is_html)
583     strcat(buf, "Accept-Ranges: bytes\r\n");
584
585   /* End header */
586   strcat(buf, "\r\n");
587   
588   olsr_printf(1, "HEADER:\n%s", buf);
589
590   return strlen(buf);
591
592 }
593
594
595
596 int 
597 build_tabs(char *buf, int active)
598 {
599   int size = 0, i = 0, tabs = 0;
600
601   while(strcmp(html_tabs[i], "<!-- TAB ELEMENTS -->"))
602     {
603       size += sprintf(&buf[size], html_tabs[i]);
604       i++;
605     }
606
607   i++;
608
609   while(tab_entries[tabs].tab_label)
610     {
611       if(tabs == active)
612         size += sprintf(&buf[size], 
613                         html_tabs[i], 
614                         tab_entries[tabs].filename, 
615                         ACTIVE_TAB, 
616                         tab_entries[tabs].tab_label);
617       else
618         size += sprintf(&buf[size], 
619                         html_tabs[i], 
620                         tab_entries[tabs].filename, 
621                         " ", 
622                         tab_entries[tabs].tab_label);
623       tabs++;
624     }
625   
626   i++;      
627   while(html_tabs[i])
628     {
629       size += sprintf(&buf[size], html_tabs[i]);
630       i++;
631     }
632   
633   return size;
634 }
635
636
637 /*
638  * destructor - called at unload
639  */
640 void
641 olsr_plugin_exit()
642 {
643   if(http_socket)
644     close(http_socket);
645 }
646
647
648 /* Mulitpurpose funtion */
649 int
650 plugin_io(int cmd, void *data, size_t size)
651 {
652
653   switch(cmd)
654     {
655     default:
656       return 0;
657     }
658   
659   return 1;
660
661 }
662
663
664 static int
665 build_frame(char *title, 
666             char *link, 
667             int width,
668             char *buf,
669             olsr_u32_t bufsize, 
670             int(*frame_body_cb)(char *, olsr_u32_t))
671 {
672   int i = 0, size = 0;
673
674   while(http_frame[i])
675     {
676       if(!strcmp(http_frame[i], "<!-- BODY -->"))
677         size += frame_body_cb(&buf[size], bufsize - size);
678       else
679         size += sprintf(&buf[size], http_frame[i]);      
680
681       i++;
682     }
683
684   return size;
685 }
686
687
688
689 int
690 build_routes_body(char *buf, olsr_u32_t bufsize)
691 {
692   int size = 0, index;
693   struct rt_entry *routes;
694
695   size += sprintf(&buf[size], "<h2>OLSR routes in kernel</h2>\n");
696
697   size += sprintf(&buf[size], "<table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Destination</th><th>Gateway</th><th>Metric</th><th>Interface</th><th>Type</th></tr>\n");
698
699   /* Neighbors */
700   for(index = 0;index < HASHSIZE;index++)
701     {
702       for(routes = host_routes[index].next;
703           routes != &host_routes[index];
704           routes = routes->next)
705         {
706           size += sprintf(&buf[size], "<tr><td>%s</td><td>%s</td><td>%d</td><td>%s</td><td>HOST</td></tr>\n",
707                           olsr_ip_to_string(&routes->rt_dst),
708                           olsr_ip_to_string(&routes->rt_router),
709                           routes->rt_metric,
710                           routes->rt_if->int_name);
711         }
712     }
713
714   /* HNA */
715   for(index = 0;index < HASHSIZE;index++)
716     {
717       for(routes = hna_routes[index].next;
718           routes != &hna_routes[index];
719           routes = routes->next)
720         {
721           size += sprintf(&buf[size], "<tr><td>%s</td><td>%s</td><td>%d</td><td>%s</td><td>HNA</td></tr>\n",
722                           olsr_ip_to_string(&routes->rt_dst),
723                           olsr_ip_to_string(&routes->rt_router),
724                           routes->rt_metric,
725                           routes->rt_if->int_name);
726         }
727     }
728
729   size += sprintf(&buf[size], "</table>\n");
730
731   return size;
732 }
733
734 int
735 build_config_body(char *buf, olsr_u32_t bufsize)
736 {
737     char systime[100];
738     time_t currtime;
739     int size = 0;
740     struct olsr_if *ifs;
741     struct plugin_entry *pentry;
742     struct plugin_param *pparam;
743     struct timeval now, uptime;
744     int hours, mins, days;
745
746     gettimeofday(&now, NULL);
747     timersub(&now, &start_time, &uptime);
748     days = uptime.tv_sec/86400;
749     uptime.tv_sec -= days*86400;
750     hours = uptime.tv_sec/3600;
751     uptime.tv_sec -= hours*3600;
752     mins = uptime.tv_sec/60;
753     uptime.tv_sec -= mins*60;
754
755     time(&currtime);
756     strftime(systime, 100, "System time: <i>%a, %d %b %Y %H:%M:%S</i><br>", gmtime(&currtime));
757
758
759     size += sprintf(&buf[size], "OS: %s\n<br>", OS);
760
761     size += sprintf(&buf[size], "%s\n", systime);
762
763     if(days)
764       size += sprintf(&buf[size], "Olsrd uptime: <i>%d day(s) %02d hours %02d minutes %02d seconds</i><br>\n", days, hours, mins, (int)uptime.tv_sec);
765     else
766       size += sprintf(&buf[size], "Olsrd uptime: <i>%02d hours %02d minutes %02d seconds</i><br>\n", hours, mins, (int)uptime.tv_sec);
767
768       size += sprintf(&buf[size], "HTTP stats(ok/dyn/error/illegal): <i>%d/%d/%d/%d</i>\n", stats.ok_hits, stats.dyn_hits, stats.err_hits, stats.ill_hits);
769
770     size += sprintf(&buf[size], "<h2>Variables</h2>\n");
771
772     size += sprintf(&buf[size], "<table width=\"100%%\" border=0>\n<tr>");
773
774     size += sprintf(&buf[size], "<td>Main address: <b>%s</b></td>\n", olsr_ip_to_string(main_addr));
775     
776     size += sprintf(&buf[size], "<td>IP version: %d</td>\n", cfg->ip_version == AF_INET ? 4 : 6);
777
778     size += sprintf(&buf[size], "<td>Debug level: %d</td>\n", cfg->debug_level);
779
780     size += sprintf(&buf[size], "</tr>\n<tr>\n");
781
782     size += sprintf(&buf[size], "<td>Pollrate: %0.2f</td>\n", cfg->pollrate);
783     size += sprintf(&buf[size], "<td>TC redundancy: %d</td>\n", cfg->tc_redundancy);
784     size += sprintf(&buf[size], "<td>MPR coverage: %d</td>\n", cfg->mpr_coverage);
785
786
787     size += sprintf(&buf[size], "</tr>\n<tr>\n");
788
789     size += sprintf(&buf[size], "<td>TOS: 0x%04x</td>\n", cfg->tos);
790
791     size += sprintf(&buf[size], "<td>Willingness: %d %s</td>\n", cfg->willingness, cfg->willingness_auto ? "(auto)" : "");
792     
793     size += sprintf(&buf[size], "</tr>\n<tr>\n");
794
795     size += sprintf(&buf[size], "<td>Hysteresis: %s</td>\n", cfg->use_hysteresis ? "Enabled" : "Disabled");
796         
797     size += sprintf(&buf[size], "<td>Hyst scaling: %0.2f</td>\n", cfg->hysteresis_param.scaling);
798     size += sprintf(&buf[size], "<td>Hyst lower/upper: %0.2f/%0.2f</td>\n", cfg->hysteresis_param.thr_low, cfg->hysteresis_param.thr_high);
799
800     size += sprintf(&buf[size], "</tr>\n<tr>\n");
801
802     size += sprintf(&buf[size], "<td>LQ extention: %s</td>\n", cfg->lq_level ? "Enabled" : "Disabled");
803     size += sprintf(&buf[size], "<td>LQ level: %d</td>\n", cfg->lq_level);
804     size += sprintf(&buf[size], "<td>LQ winsize: %d</td>\n", cfg->lq_wsize);
805     size += sprintf(&buf[size], "<td></td>\n");
806
807     size += sprintf(&buf[size], "</tr></table>\n");
808
809     size += sprintf(&buf[size], "<h2>Interfaces</h2>\n");
810
811
812     size += sprintf(&buf[size], "<table width=\"100%%\" border=0>\n");
813
814
815     for(ifs = cfg->interfaces; ifs; ifs = ifs->next)
816       {
817         struct interface *rifs = ifs->interf;
818
819         size += sprintf(&buf[size], "<tr><th colspan=3>%s</th>\n", ifs->name);
820         if(!rifs)
821           {
822             size += sprintf(&buf[size], "<tr><td colspan=3>Status: DOWN</td></tr>\n");
823             continue;
824           }
825         
826         if(cfg->ip_version == AF_INET)
827           {
828             size += sprintf(&buf[size], "<tr><td>IP: %s</td>\n", 
829                             sockaddr_to_string(&rifs->int_addr));
830             size += sprintf(&buf[size], "<td>MASK: %s</td>\n", 
831                             sockaddr_to_string(&rifs->int_netmask));
832             size += sprintf(&buf[size], "<td>BCAST: %s</td></tr>\n",
833                             sockaddr_to_string(&rifs->int_broadaddr));
834             size += sprintf(&buf[size], "<tr><td>MTU: %d</td>\n", rifs->int_mtu);
835             size += sprintf(&buf[size], "<td>WLAN: %s</td>\n", rifs->is_wireless ? "Yes" : "No");
836             size += sprintf(&buf[size], "<td>STATUS: UP</td></tr>\n");
837           }
838         else
839           {
840             size += sprintf(&buf[size], "<tr><td>IP: %s</td>\n", olsr_ip_to_string((union olsr_ip_addr *)&rifs->int6_addr.sin6_addr));
841             size += sprintf(&buf[size], "<td>MCAST: %s</td>\n", olsr_ip_to_string((union olsr_ip_addr *)&rifs->int6_multaddr.sin6_addr));
842             size += sprintf(&buf[size], "<td></td></tr>\n");
843             size += sprintf(&buf[size], "<tr><td>MTU: %d</td>\n", rifs->int_mtu);
844             size += sprintf(&buf[size], "<td>WLAN: %s</td>\n", rifs->is_wireless ? "Yes" : "No");
845             size += sprintf(&buf[size], "<td>STATUS: UP</td></tr>\n");
846           }         
847
848       }
849
850     size += sprintf(&buf[size], "</table>\n");
851
852     if(cfg->allow_no_interfaces)
853       size += sprintf(&buf[size], "<i>Olsrd is configured to run even if no interfaces are available</i><br>\n");
854     else
855       size += sprintf(&buf[size], "<i>Olsrd is configured to halt if no interfaces are available</i><br>\n");
856
857     size += sprintf(&buf[size], "<h2>Plugins</h2>\n");
858
859     size += sprintf(&buf[size], "<table width=\"100%%\" border=0><tr><th>Name</th><th>Parameters</th></tr>\n");
860
861     for(pentry = cfg->plugins; pentry; pentry = pentry->next)
862       {
863         size += sprintf(&buf[size], "<tr><td>%s</td>\n", pentry->name);
864
865         size += sprintf(&buf[size], "<td><select>\n");
866         size += sprintf(&buf[size], "<option>KEY, VALUE</option>\n");
867
868         for(pparam = pentry->params; pparam; pparam = pparam->next)
869           {
870             size += sprintf(&buf[size], "<option>\"%s\", \"%s\"</option>\n",
871                             pparam->key,
872                             pparam->value);
873           }
874         size += sprintf(&buf[size], "</select></td></tr>\n");
875
876       }
877
878     size += sprintf(&buf[size], "</table>\n");
879
880
881     if((cfg->ip_version == AF_INET) && (cfg->hna4_entries))
882       {
883         struct hna4_entry *hna4;
884         
885         size += sprintf(&buf[size], "<h2>Announced HNA entries</h2>\n");
886         size += sprintf(&buf[size], "<table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Network</th><th>Netmask</th></tr>\n");
887         
888         for(hna4 = cfg->hna4_entries; hna4; hna4 = hna4->next)
889           {
890             size += sprintf(&buf[size], "<tr><td>%s</td><td>%s</td></tr>\n", 
891                             olsr_ip_to_string((union olsr_ip_addr *)&hna4->net),
892                             olsr_ip_to_string((union olsr_ip_addr *)&hna4->netmask));
893           }
894         
895         size += sprintf(&buf[size], "</table>\n");
896       }
897     else if((cfg->ip_version == AF_INET6) && (cfg->hna6_entries))
898       {
899         struct hna6_entry *hna6;
900         
901         size += sprintf(&buf[size], "<h2>Announced HNA entries</h2>\n");
902         size += sprintf(&buf[size], "<table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Network</th><th>Prefix length</th></tr>\n");
903         
904         for(hna6 = cfg->hna6_entries; hna6; hna6 = hna6->next)
905           {
906             size += sprintf(&buf[size], "<tr><td>%s</td><td>%d</td></tr>\n", 
907                             olsr_ip_to_string((union olsr_ip_addr *)&hna6->net),
908                             hna6->prefix_len);
909           }
910         
911         size += sprintf(&buf[size], "</table>\n");
912       }
913     
914
915     return size;
916 }
917
918
919
920 int
921 build_neigh_body(char *buf, olsr_u32_t bufsize)
922 {
923   struct neighbor_entry *neigh;
924   struct neighbor_2_list_entry *list_2;
925   struct link_entry *link = NULL;
926   int size = 0, index, thop_cnt;
927
928   size += sprintf(&buf[size], "<h2>Links</h2>\n");
929   size += sprintf(&buf[size], "<table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Local IP</th><th>remote IP</th><th>Hysteresis</th><th>LinkQuality</th><th>lost</th><th>total</th><th>NLQ</th><th>ETX</th></tr>\n");
930
931   /* Link set */
932   if(olsr_plugin_io(GETD__LINK_SET, &link, sizeof(link)) && link)
933   {
934     while(link)
935       {
936         size += sprintf(&buf[size], "<tr><td>%s</td><td>%s</td><td>%0.2f</td><td>%0.2f</td><td>%d</td><td>%d</td><td>%0.2f</td><td>%0.2f</td></tr>\n",
937                         olsr_ip_to_string(&link->local_iface_addr),
938                         olsr_ip_to_string(&link->neighbor_iface_addr),
939                         link->L_link_quality, 
940                         link->loss_link_quality,
941                         link->lost_packets, 
942                         link->total_packets,
943                         link->neigh_link_quality, 
944                         (link->loss_link_quality * link->neigh_link_quality) ? 1.0 / (link->loss_link_quality * link->neigh_link_quality) : 0.0);
945
946         link = link->next;
947       }
948   }
949
950   size += sprintf(&buf[size], "</table>\n");
951
952   size += sprintf(&buf[size], "<h2>Neighbors</h2>\n");
953   size += sprintf(&buf[size], "<table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>IP address</th><th>SYM</th><th>MPR</th><th>MPRS</th><th>Willingness</th><th>2 Hop Neighbors</th></tr>\n");
954   /* Neighbors */
955   for(index=0;index<HASHSIZE;index++)
956     {
957       for(neigh = neighbortable[index].next;
958           neigh != &neighbortable[index];
959           neigh = neigh->next)
960         {
961           size += sprintf(&buf[size], 
962                           "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%d</td>", 
963                           olsr_ip_to_string(&neigh->neighbor_main_addr),
964                           (neigh->status == SYM) ? "YES" : "NO",
965                           neigh->is_mpr ? "YES" : "NO",
966                           olsr_lookup_mprs_set ? 
967                           (olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO") 
968                           : "UNAVAILABLE",
969                           neigh->willingness);
970
971           size += sprintf(&buf[size], "<td><select>\n");
972           size += sprintf(&buf[size], "<option>IP ADDRESS</option>\n");
973
974           thop_cnt = 0;
975
976           for(list_2 = neigh->neighbor_2_list.next;
977               list_2 != &neigh->neighbor_2_list;
978               list_2 = list_2->next)
979             {
980               size += sprintf(&buf[size], "<option>%s</option>\n", olsr_ip_to_string(&list_2->neighbor_2->neighbor_2_addr));
981               thop_cnt ++;
982             }
983           size += sprintf(&buf[size], "</select> (%d)</td></tr>\n", thop_cnt);
984
985         }
986     }
987
988   size += sprintf(&buf[size], "</table>\n");
989
990   return size;
991 }
992
993
994
995 int
996 build_topo_body(char *buf, olsr_u32_t bufsize)
997 {
998   int size = 0;
999   olsr_u8_t index;
1000   struct tc_entry *entry;
1001   struct topo_dst *dst_entry;
1002
1003
1004   size += sprintf(&buf[size], "<h2>Topology entries</h2>\n<table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Destination IP</th><th>Last hop IP</th><th>LQ</th><th>ILQ</th><th>ETX</th></tr>\n");
1005
1006
1007   /* Topology */  
1008   for(index=0;index<HASHSIZE;index++)
1009     {
1010       /* For all TC entries */
1011       entry = tc_table[index].next;
1012       while(entry != &tc_table[index])
1013         {
1014           /* For all destination entries of that TC entry */
1015           dst_entry = entry->destinations.next;
1016           while(dst_entry != &entry->destinations)
1017             {
1018               size += sprintf(&buf[size], "<tr><td>%s</td><td>%s</td><td>%0.2f</td><td>%0.2f</td><td>%0.2f</td></tr>\n", 
1019                               olsr_ip_to_string(&dst_entry->T_dest_addr),
1020                               olsr_ip_to_string(&entry->T_last_addr), 
1021                               dst_entry->link_quality,
1022                               dst_entry->inverse_link_quality,
1023                               (dst_entry->link_quality * dst_entry->inverse_link_quality) ? 1.0 / (dst_entry->link_quality * dst_entry->inverse_link_quality) : 0.0);
1024
1025               dst_entry = dst_entry->next;
1026             }
1027           entry = entry->next;
1028         }
1029     }
1030
1031   size += sprintf(&buf[size], "</table>\n");
1032
1033   return size;
1034 }
1035
1036
1037
1038 int
1039 build_hna_body(char *buf, olsr_u32_t bufsize)
1040 {
1041   int size;
1042   olsr_u8_t index;
1043   struct hna_entry *tmp_hna;
1044   struct hna_net *tmp_net;
1045
1046   size = 0;
1047
1048   size += sprintf(&buf[size], "<h2>HNA entries</h2>\n<table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Network</th><th>Netmask</th><th>Gateway</th></tr>\n");
1049
1050   /* HNA entries */
1051   for(index=0;index<HASHSIZE;index++)
1052     {
1053       tmp_hna = hna_set[index].next;
1054       /* Check all entrys */
1055       while(tmp_hna != &hna_set[index])
1056         {
1057           /* Check all networks */
1058           tmp_net = tmp_hna->networks.next;
1059               
1060           while(tmp_net != &tmp_hna->networks)
1061             {
1062               size += sprintf(&buf[size], "<tr><td>%s</td>", 
1063                               olsr_ip_to_string(&tmp_net->A_network_addr));
1064               size += sprintf(&buf[size], "<td>%s</td>",
1065                               olsr_netmask_to_string(&tmp_net->A_netmask));
1066               size += sprintf(&buf[size], "<td>%s</td></tr>\n",
1067                               olsr_ip_to_string(&tmp_hna->A_gateway_addr));
1068               tmp_net = tmp_net->next;
1069             }
1070               
1071           tmp_hna = tmp_hna->next;
1072         }
1073     }
1074
1075   size += sprintf(&buf[size], "</table>\n");
1076
1077   return size;
1078 }
1079
1080
1081 int
1082 build_mid_body(char *buf, olsr_u32_t bufsize)
1083 {
1084   int size = 0;
1085   olsr_u8_t index;
1086   struct mid_entry *entry;
1087   struct mid_address *alias;
1088
1089   size += sprintf(&buf[size], "<h2>MID entries</h2>\n<table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Main Address</th><th>Aliases</th></tr>\n");
1090   
1091   /* MID */  
1092   for(index=0;index<HASHSIZE;index++)
1093     {
1094       entry = mid_set[index].next;
1095       while(entry != &mid_set[index])
1096         {
1097           size += sprintf(&buf[size], "<tr><td>%s</td>\n", olsr_ip_to_string(&entry->main_addr));
1098           size += sprintf(&buf[size], "<td><select>\n<option>IP ADDRESS</option>\n");
1099
1100           alias = entry->aliases;
1101           while(alias)
1102             {
1103               size += sprintf(&buf[size], "<option>%s</option>\n", olsr_ip_to_string(&alias->alias));
1104               alias = alias->next_alias;
1105             }
1106           size += sprintf(&buf[size], "</select>\n");
1107
1108           size += sprintf(&buf[size], "</tr>\n");
1109           entry = entry->next;
1110         }
1111     }
1112
1113   size += sprintf(&buf[size], "</table>\n");
1114
1115
1116
1117   return size;
1118 }
1119
1120
1121 int
1122 build_nodes_body(char *buf, olsr_u32_t bufsize)
1123 {
1124   int size = 0;
1125
1126   size += build_neigh_body(buf, bufsize);
1127   size += build_topo_body(&buf[size], bufsize - size);
1128   size += build_hna_body(&buf[size], bufsize - size);
1129   size += build_mid_body(&buf[size], bufsize - size);
1130
1131   return size;
1132 }
1133
1134 int
1135 build_all_body(char *buf, olsr_u32_t bufsize)
1136 {
1137   int size = 0;
1138
1139   size += build_config_body(&buf[size], bufsize);
1140   size += build_routes_body(&buf[size], bufsize - size);
1141   size += build_neigh_body(&buf[size], bufsize);
1142   size += build_topo_body(&buf[size], bufsize - size);
1143   size += build_hna_body(&buf[size], bufsize - size);
1144   size += build_mid_body(&buf[size], bufsize - size);
1145
1146   return size;
1147 }
1148
1149
1150 int
1151 build_about_body(char *buf, olsr_u32_t bufsize)
1152 {
1153   int size = 0, i = 0;
1154
1155   while(about_frame[i])
1156     {
1157       size += sprintf(&buf[size], about_frame[i]);
1158       i++;
1159     }
1160   return size;
1161 }
1162
1163
1164 olsr_bool
1165 check_allowed_ip(union olsr_ip_addr *addr)
1166 {
1167   struct allowed_host *allh = allowed_hosts;
1168   struct allowed_net *alln = allowed_nets;
1169
1170   if(addr->v4 == ntohl(INADDR_LOOPBACK))
1171     return OLSR_TRUE;
1172
1173   /* check hosts */
1174   while(allh)
1175     {
1176       if(addr->v4 == allh->host.v4)
1177         return OLSR_TRUE;
1178       allh = allh->next;
1179     }
1180
1181   /* check nets */
1182   while(alln)
1183     {
1184       if((addr->v4 & alln->mask.v4) == (alln->net.v4 & alln->mask.v4))
1185         return OLSR_TRUE;
1186       alln = alln->next;
1187     }
1188
1189   return OLSR_FALSE;
1190 }
1191
1192
1193 /**
1194  *Converts a olsr_ip_addr to a string
1195  *Goes for both IPv4 and IPv6
1196  *
1197  *@param the IP to convert
1198  *@return a pointer to a static string buffer
1199  *representing the address in "dots and numbers"
1200  *
1201  */
1202 char *
1203 olsr_ip_to_string(union olsr_ip_addr *addr)
1204 {
1205   static int index = 0;
1206   static char buff[4][100];
1207   char *ret;
1208   struct in_addr in;
1209  
1210   if(ipversion == AF_INET)
1211     {
1212       in.s_addr=addr->v4;
1213       ret = inet_ntoa(in);
1214     }
1215   else
1216     {
1217       /* IPv6 */
1218       ret = (char *)inet_ntop(AF_INET6, &addr->v6, ipv6_buf, sizeof(ipv6_buf));
1219     }
1220
1221   strncpy(buff[index], ret, 100);
1222
1223   ret = buff[index];
1224
1225   index = (index + 1) & 3;
1226
1227   return ret;
1228 }
1229
1230
1231
1232
1233 /**
1234  *This function is just as bad as the previous one :-(
1235  */
1236 char *
1237 olsr_netmask_to_string(union hna_netmask *mask)
1238 {
1239   char *ret;
1240   struct in_addr in;
1241   static char netmask[5];
1242
1243   if(ipversion == AF_INET)
1244     {
1245       in.s_addr = mask->v4;
1246       ret = inet_ntoa(in);
1247       return ret;
1248
1249     }
1250   else
1251     {
1252       /* IPv6 */
1253       sprintf(netmask, "%d", mask->v6);
1254       return netmask;
1255     }
1256
1257   return ret;
1258 }
1259
1260
1261
1262
1263 char *
1264 sockaddr_to_string(struct sockaddr *address_to_convert)
1265 {
1266   struct sockaddr_in           *address;
1267   
1268   address=(struct sockaddr_in *)address_to_convert; 
1269   return(inet_ntoa(address->sin_addr));
1270   
1271 }
1272
1273
1274 static char *
1275 get_copyright_string()
1276 {
1277   return copyright_string;
1278 }