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