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