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