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