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