lqnatthresh: maintain an advantage for the current (NAT) inet gw
[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
66 #include "olsrd_httpinfo.h"
67 #include "admin_interface.h"
68 #include "gfx.h"
69
70 #ifdef OS
71 #undef OS
72 #endif
73
74 #ifdef WIN32
75 #define close(x) closesocket(x)
76 #define OS "Windows"
77 #endif
78 #ifdef linux
79 #define OS "GNU/Linux"
80 #endif
81 #ifdef __FreeBSD__
82 #define OS "FreeBSD"
83 #endif
84
85 #ifndef OS
86 #define OS "Undefined"
87 #endif
88
89 static char copyright_string[] __attribute__((unused)) = "olsr.org HTTPINFO plugin Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org) All rights reserved.";
90
91 #define MAX_CLIENTS 3
92
93 #define MAX_HTTPREQ_SIZE (1024 * 10)
94
95 #define DEFAULT_TCP_PORT 1978
96
97 #define HTML_BUFSIZE (1024 * 4000)
98
99 #define FRAMEWIDTH (resolve_ip_addresses ? 900 : 800)
100
101 #define FILENREQ_MATCH(req, filename) \
102         !strcmp(req, filename) || \
103         (strlen(req) && !strcmp(&req[1], filename))
104
105 static const char httpinfo_css[] =
106   "#A {text-decoration: none}\n"
107   "TH{text-align: left}\n"
108   "H1, H3, TD, TH {font-family: Helvetica; font-size: 80%}\n"
109   "h2\n {\nfont-family: Helvetica;\n font-size: 14px;text-align: center;\n"
110   "line-height: 16px;\ntext-decoration: none;\nborder: 1px solid #ccc;\n"
111   "margin: 5px;\nbackground: #ececec;\n}\n"
112   "hr\n{\nborder: none;\npadding: 1px;\nbackground: url(grayline.gif) repeat-x bottom;\n}\n"
113   "#maintable\n{\nmargin: 0px;\npadding: 5px;\nborder-left: 1px solid #ccc;\n"
114   "border-right: 1px solid #ccc;\nborder-bottom: 1px solid #ccc;\n}\n"
115   "#footer\n{\nfont-size: 10px;\nline-height: 14px;\ntext-decoration: none;\ncolor: #666;\n}\n"
116   "#hdr\n{\nfont-size: 14px;\ntext-align: center;\nline-height: 16px;\n"
117   "text-decoration: none;\nborder: 1px solid #ccc;\n"
118   "margin: 5px;\nbackground: #ececec;\n}\n"
119   "#container\n{\nwidth: 1000px;\npadding: 30px;\nborder: 1px solid #ccc;\nbackground: #fff;\n}\n"
120   "#tabnav\n{\nheight: 20px;\nmargin: 0;\npadding-left: 10px;\n"
121   "background: url(grayline.gif) repeat-x bottom;\n}\n"
122   "#tabnav li\n{\nmargin: 0;\npadding: 0;\ndisplay: inline;\nlist-style-type: none;\n}\n"
123   "#tabnav a:link, #tabnav a:visited\n{\nfloat: left;\nbackground: #ececec;\n"
124   "font-size: 12px;\nline-height: 14px;\nfont-weight: bold;\npadding: 2px 10px 2px 10px;\n"
125   "margin-right: 4px;\nborder: 1px solid #ccc;\ntext-decoration: none;\ncolor: #777;\n}\n"
126   "#tabnav a:link.active, #tabnav a:visited.active\n{\nborder-bottom: 1px solid #fff;\n"
127   "background: #ffffff;\ncolor: #000;\n}\n"
128   "#tabnav a:hover\n{\nbackground: #777777;\ncolor: #ffffff;\n}\n"
129   ".input_text\n{\nbackground: #E5E5E5;\nmargin-left: 5px; margin-top: 0px;\n"
130   "text-align: left;\n\nwidth: 100px;\npadding: 0px;\ncolor: #000000;\n"
131   "text-decoration: none;\nfont-family: verdana;\nfont-size: 12px;\n"
132   "border: 1px solid #ccc;\n}\n"
133   ".input_button\n{\nbackground: #B5D1EE;\nmargin-left: 5px;\nmargin-top: 0px;\n"
134   "text-align: center;\nwidth: 120px;\npadding: 0px;\ncolor: #000000;\n"
135   "text-decoration: none;\nfont-family: verdana;\nfont-size: 12px;\n"
136   "border: 1px solid #000;\n}\n";
137
138 typedef int(*build_body_callback)(char *, olsr_u32_t);
139
140 struct tab_entry
141 {
142   const char *tab_label;
143   const char *filename;
144   build_body_callback build_body_cb;
145   olsr_bool display_tab;
146 };
147
148 struct static_bin_file_entry
149 {
150   const char *filename;
151   unsigned char *data;
152   unsigned int data_size;
153 };
154
155 struct static_txt_file_entry
156 {
157   const char *filename;
158   const char *data;
159 };
160
161 struct dynamic_file_entry
162 {
163   const char *filename;
164   int(*process_data_cb)(char *, olsr_u32_t, char *, olsr_u32_t);
165 };
166
167 static int get_http_socket(int);
168
169 static int build_tabs(char *, olsr_u32_t, int);
170
171 static void parse_http_request(int);
172
173 static int build_http_header(http_header_type, olsr_bool, olsr_u32_t, char *, olsr_u32_t);
174
175 static int build_frame(char *, olsr_u32_t, const char *, const char *, int, build_body_callback frame_body_cb);
176
177 static int build_routes_body(char *, olsr_u32_t);
178
179 static int build_config_body(char *, olsr_u32_t);
180
181 static int build_neigh_body(char *, olsr_u32_t);
182
183 static int build_topo_body(char *, olsr_u32_t);
184
185 static int build_mid_body(char *, olsr_u32_t);
186
187 static int build_nodes_body(char *, olsr_u32_t);
188
189 static int build_all_body(char *, olsr_u32_t);
190
191 static int build_about_body(char *, olsr_u32_t);
192
193 static int build_cfgfile_body(char *, olsr_u32_t);
194
195 static int check_allowed_ip(const struct allowed_net * const allowed_nets, const union olsr_ip_addr * const addr);
196
197 static int build_ip_txt(char *buf, const olsr_u32_t bufsize, const olsr_bool want_link,
198                         const char * const ipaddrstr, const int prefix_len);
199
200 static int build_ipaddr_link(char *buf, const olsr_u32_t bufsize, const olsr_bool want_link,
201                              const union olsr_ip_addr * const ipaddr,
202                              const int prefix_len);
203 static int section_title(char *buf, olsr_u32_t bufsize, const char *title);
204
205 static ssize_t writen(int fd, const void *buf, size_t count);
206
207 static struct timeval start_time;
208 static struct http_stats stats;
209 static int client_sockets[MAX_CLIENTS];
210 static int curr_clients;
211 static int http_socket;
212
213 #if 0
214 int netsprintf(char *str, const char* format, ...) __attribute__((format(printf, 2, 3)));
215 static int netsprintf_direct = 0;
216 static int netsprintf_error = 0;
217 #define sprintf netsprintf
218 #define NETDIRECT
219 #endif
220
221 static const struct tab_entry tab_entries[] = {
222     {"Configuration",  "config",  build_config_body,  OLSR_TRUE},
223     {"Routes",         "routes",  build_routes_body,  OLSR_TRUE},
224     {"Links/Topology", "nodes",   build_nodes_body,   OLSR_TRUE},
225     {"All",            "all",     build_all_body,     OLSR_TRUE},
226 #ifdef ADMIN_INTERFACE
227     {"Admin",          "admin",   build_admin_body,   OLSR_TRUE},
228 #endif
229     {"About",          "about",   build_about_body,   OLSR_TRUE},
230     {"FOO",            "cfgfile", build_cfgfile_body, OLSR_FALSE},
231     {NULL,             NULL,      NULL,               OLSR_FALSE}
232 };
233
234 static const struct static_bin_file_entry static_bin_files[] = {
235     {"favicon.ico",  favicon_ico, sizeof(favicon_ico)},
236     {"logo.gif",     logo_gif, sizeof(logo_gif)},
237     {"grayline.gif", grayline_gif, sizeof(grayline_gif)},
238     {NULL, NULL, 0}
239 };
240
241 static const struct static_txt_file_entry static_txt_files[] = {
242     {"httpinfo.css", httpinfo_css},
243     {NULL, NULL}
244 };
245
246
247 static const struct dynamic_file_entry dynamic_files[] =
248   {
249 #ifdef ADMIN_INTERFACE
250     {"set_values", process_set_values},
251 #endif
252     {NULL, NULL}
253   };
254
255
256 static int
257 get_http_socket(int port)
258 {
259   struct sockaddr_in sin;
260   olsr_u32_t yes = 1;
261
262   /* Init ipc socket */
263   int s = socket(AF_INET, SOCK_STREAM, 0);
264   if (s == -1) {
265     olsr_printf(1, "(HTTPINFO)socket %s\n", strerror(errno));
266     return -1;
267   }
268
269   if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
270     olsr_printf(1, "(HTTPINFO)SO_REUSEADDR failed %s\n", strerror(errno));
271     close(s);
272     return -1;
273   }
274
275   /* Bind the socket */
276
277   /* complete the socket structure */
278   memset(&sin, 0, sizeof(sin));
279   sin.sin_family = AF_INET;
280   sin.sin_addr.s_addr = INADDR_ANY;
281   sin.sin_port = htons(port);
282
283   /* bind the socket to the port number */
284   if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
285     olsr_printf(1, "(HTTPINFO) bind failed %s\n", strerror(errno));
286     close(s);
287     return -1;
288   }
289
290   /* show that we are willing to listen */
291   if (listen(s, 1) == -1) {
292     olsr_printf(1, "(HTTPINFO) listen failed %s\n", strerror(errno));
293     close(s);
294     return -1;
295   }
296
297   return s;
298 }
299
300 /**
301  *Do initialization here
302  *
303  *This function is called by the my_init
304  *function in uolsrd_plugin.c
305  */
306 int
307 olsrd_plugin_init(void)
308 {
309   /* Get start time */
310   gettimeofday(&start_time, NULL);
311
312   curr_clients = 0;
313   /* set up HTTP socket */
314   http_socket = get_http_socket(http_port != 0 ? http_port :  DEFAULT_TCP_PORT);
315
316   if (http_socket < 0) {
317     fprintf(stderr, "(HTTPINFO) could not initialize HTTP socket\n");
318     exit(0);
319   }
320
321   /* Register socket */
322   add_olsr_socket(http_socket, &parse_http_request);
323
324   return 1;
325 }
326
327 /* Non reentrant - but we are not multithreaded anyway */
328 void
329 parse_http_request(int fd)
330 {
331   struct sockaddr_in pin;
332   socklen_t addrlen;
333   char *addr;
334   char req[MAX_HTTPREQ_SIZE];
335   static char body[HTML_BUFSIZE];
336   char req_type[11];
337   char filename[251];
338   char http_version[11];
339   unsigned int c = 0;
340   int r = 1, size = 0;
341
342   if (curr_clients >= MAX_CLIENTS) {
343     return;
344   }
345   curr_clients++;
346
347   addrlen = sizeof(struct sockaddr_in);
348   client_sockets[curr_clients] = accept(fd, (struct sockaddr *)  &pin, &addrlen);
349   if (client_sockets[curr_clients] == -1) {
350     olsr_printf(1, "(HTTPINFO) accept: %s\n", strerror(errno));
351     goto close_connection;
352   }
353
354   if (!check_allowed_ip(allowed_nets, (union olsr_ip_addr *)&pin.sin_addr.s_addr)) {
355     struct ipaddr_str strbuf;
356     olsr_printf(0, "HTTP request from non-allowed host %s!\n",
357                 olsr_ip_to_string(&strbuf, (union olsr_ip_addr *)&pin.sin_addr.s_addr));
358     close(client_sockets[curr_clients]);
359   }
360
361   addr = inet_ntoa(pin.sin_addr);
362
363   memset(req, 0, sizeof(req));
364   memset(body, 0, sizeof(body));
365
366   while ((r = recv(client_sockets[curr_clients], &req[c], 1, 0)) > 0 && (c < sizeof(req)-1)) {
367       c++;
368
369       if ((c > 3 && !strcmp(&req[c-4], "\r\n\r\n")) ||
370          (c > 1 && !strcmp(&req[c-2], "\n\n")))
371           break;
372   }
373
374   if (r < 0) {
375     olsr_printf(1, "(HTTPINFO) Failed to recieve data from client!\n");
376     stats.err_hits++;
377     goto close_connection;
378   }
379
380   /* Get the request */
381   if (sscanf(req, "%10s %250s %10s\n", req_type, filename, http_version) != 3) {
382     /* Try without HTTP version */
383     if (sscanf(req, "%10s %250s\n", req_type, filename) != 2) {
384       olsr_printf(1, "(HTTPINFO) Error parsing request %s!\n", req);
385       stats.err_hits++;
386       goto close_connection;
387     }
388   }
389
390   olsr_printf(1, "Request: %s\nfile: %s\nVersion: %s\n\n", req_type, filename, http_version);
391
392   if (!strcmp(req_type, "POST")) {
393 #ifdef ADMIN_INTERFACE
394     int i = 0;
395     while (dynamic_files[i].filename) {
396         printf("POST checking %s\n", dynamic_files[i].filename);
397         if (FILENREQ_MATCH(filename, dynamic_files[i].filename)) {
398             olsr_u32_t param_size;
399
400             stats.ok_hits++;
401
402             param_size = recv(client_sockets[curr_clients], req, sizeof(req)-1, 0);
403
404             req[param_size] = '\0';
405             printf("Dynamic read %d bytes\n", param_size);
406         
407             //memcpy(body, dynamic_files[i].data, static_bin_files[i].data_size);
408             size += dynamic_files[i].process_data_cb(req, param_size, &body[size], sizeof(body)-size);
409             c = build_http_header(HTTP_OK, OLSR_TRUE, size, req, sizeof(req));
410             goto send_http_data;
411         }
412         i++;
413     }
414 #endif
415     /* We only support GET */
416     strcpy(body, HTTP_400_MSG);
417     stats.ill_hits++;
418     c = build_http_header(HTTP_BAD_REQ, OLSR_TRUE, strlen(body), req, sizeof(req));
419   } else if (!strcmp(req_type, "GET")) {
420     int i = 0;
421
422     for (i = 0; static_bin_files[i].filename; i++) {
423         if (FILENREQ_MATCH(filename, static_bin_files[i].filename)) {
424             break;
425         }
426     }
427
428     if (static_bin_files[i].filename) {
429       stats.ok_hits++;
430       memcpy(body, static_bin_files[i].data, static_bin_files[i].data_size);
431       size = static_bin_files[i].data_size;
432       c = build_http_header(HTTP_OK, OLSR_FALSE, size, req, sizeof(req));
433       goto send_http_data;
434     }
435
436     i = 0;
437     while (static_txt_files[i].filename)        {
438       if (FILENREQ_MATCH(filename, static_txt_files[i].filename)) {
439         break;
440       }
441       i++;
442     }
443
444     if (static_txt_files[i].filename) {
445       stats.ok_hits++;
446       size += snprintf(&body[size], sizeof(body)-size, "%s", static_txt_files[i].data);
447       c = build_http_header(HTTP_OK, OLSR_FALSE, size, req, sizeof(req));
448       goto send_http_data;
449     }
450
451     i = 0;
452     if (strlen(filename) > 1) {
453       while (tab_entries[i].filename) {
454         if (FILENREQ_MATCH(filename, tab_entries[i].filename)) {
455           break;
456         }
457         i++;
458       }
459     }
460
461     if (tab_entries[i].filename) {
462 #ifdef NETDIRECT
463       c = build_http_header(HTTP_OK, OLSR_TRUE, size, req, sizeof(req));
464       r = send(client_sockets[curr_clients], req, c, 0);
465       if (r < 0) {
466         olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
467         goto close_connection;
468       }
469       netsprintf_error = 0;
470       netsprintf_direct = 1;
471 #endif
472       size += snprintf(&body[size], sizeof(body)-size,
473                        "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
474                        "<head>\n"
475                        "<meta http-equiv=\"Content-type\" content=\"text/html; charset=ISO-8859-1\">\n"
476                        "<title>olsr.org httpinfo plugin</title>\n"
477                        "<link rel=\"icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
478                        "<link rel=\"shortcut icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
479                        "<link rel=\"stylesheet\" type=\"text/css\" href=\"httpinfo.css\">\n"
480                        "</head>\n"
481                        "<body bgcolor=\"#ffffff\" text=\"#000000\">\n"
482                        "<table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
483                        "<tbody><tr bgcolor=\"#ffffff\">\n"
484                        "<td align=\"left\" height=\"69\" valign=\"middle\" width=\"80%%\">\n"
485                        "<font color=\"black\" face=\"timesroman\" size=\"6\">&nbsp;&nbsp;&nbsp;<a href=\"http://www.olsr.org/\">olsr.org OLSR daemon</a></font></td>\n"
486                        "<td align=\"right\" height=\"69\" valign=\"middle\" width=\"20%%\">\n"
487                        "<a href=\"http://www.olsr.org/\"><img border=\"0\" src=\"/logo.gif\" alt=\"olsrd logo\"></a></td>\n"
488                        "</tr>\n"
489                        "</tbody>\n"
490                        "</table>\n",
491                        FRAMEWIDTH);
492         
493       size += build_tabs(&body[size], sizeof(body)-size, i);
494       size += build_frame(&body[size],
495                           sizeof(body)-size,
496                           "Current Routes",
497                           "routes",
498                           FRAMEWIDTH,
499                           tab_entries[i].build_body_cb);
500         
501       stats.ok_hits++;
502
503       size += snprintf(&body[size], sizeof(body)-size,
504                        "</table>\n"
505                        "<div id=\"footer\">\n"
506                        "<center>\n"
507                        "(C)2005 Andreas T&oslash;nnesen<br/>\n"
508                        "<a href=\"http://www.olsr.org/\">http://www.olsr.org</a>\n"
509                        "</center>\n"
510                        "</div>\n"
511                        "</body>\n"
512                        "</html>\n");
513         
514 #ifdef NETDIRECT
515       netsprintf_direct = 1;
516       goto close_connection;
517 #else
518       c = build_http_header(HTTP_OK, OLSR_TRUE, size, req, sizeof(req));
519       goto send_http_data;
520 #endif
521     }
522
523
524     stats.ill_hits++;
525     strcpy(body, HTTP_404_MSG);
526     c = build_http_header(HTTP_BAD_FILE, OLSR_TRUE, strlen(body), req, sizeof(req));
527   } else {
528     /* We only support GET */
529     strcpy(body, HTTP_400_MSG);
530     stats.ill_hits++;
531     c = build_http_header(HTTP_BAD_REQ, OLSR_TRUE, strlen(body), req, sizeof(req));
532   }
533
534  send_http_data:
535
536   r = writen(client_sockets[curr_clients], req, c);
537   if (r < 0) {
538       olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
539       goto close_connection;
540   }
541
542   r = writen(client_sockets[curr_clients], body, size);
543   if (r < 0) {
544       olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
545       goto close_connection;
546   }
547
548  close_connection:
549   close(client_sockets[curr_clients]);
550   curr_clients--;
551
552 }
553
554
555 int
556 build_http_header(http_header_type type,
557                   olsr_bool is_html,
558                   olsr_u32_t msgsize,
559                   char *buf,
560                   olsr_u32_t bufsize)
561 {
562   time_t currtime;
563   const char *h;
564   int size;
565
566   switch(type) {
567   case HTTP_BAD_REQ:
568       h = HTTP_400;
569       break;
570   case HTTP_BAD_FILE:
571       h = HTTP_404;
572       break;
573   default:
574       /* Defaults to OK */
575       h = HTTP_200;
576       break;
577   }
578   size = snprintf(buf, bufsize, "%s", h);
579
580   /* Date */
581   time(&currtime);
582   size += strftime(&buf[size], bufsize-size, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", localtime(&currtime));
583
584   /* Server version */
585   size += snprintf(&buf[size], bufsize-size, "Server: %s %s %s\r\n", PLUGIN_NAME, PLUGIN_VERSION, HTTP_VERSION);
586
587   /* connection-type */
588   size += snprintf(&buf[size], bufsize-size, "Connection: closed\r\n");
589
590   /* MIME type */
591   size += snprintf(&buf[size], bufsize-size, "Content-type: text/%s\r\n", is_html ? "html" : "plain");
592
593   /* Content length */
594   if (msgsize > 0) {
595       size += snprintf(&buf[size], bufsize-size, "Content-length: %i\r\n", msgsize);
596   }
597
598   /* Cache-control
599    * No caching dynamic pages
600    */
601   size += snprintf(&buf[size], bufsize-size, "Cache-Control: no-cache\r\n");
602
603   if (!is_html) {
604     size += snprintf(&buf[size], bufsize-size, "Accept-Ranges: bytes\r\n");
605   }
606   /* End header */
607   size += snprintf(&buf[size], bufsize-size, "\r\n");
608
609   olsr_printf(1, "HEADER:\n%s", buf);
610
611   return size;
612 }
613
614
615
616 static int build_tabs(char *buf, const olsr_u32_t bufsize, int active)
617 {
618   int size = 0, tabs = 0;
619
620   size += snprintf(&buf[size], bufsize-size,
621                    "<table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
622                    "<tr bgcolor=\"#ffffff\"><td>\n"
623                    "<ul id=\"tabnav\">\n",
624                    FRAMEWIDTH);
625   for (tabs = 0; tab_entries[tabs].tab_label; tabs++) {
626     if (!tab_entries[tabs].display_tab) {
627       continue;
628     }
629     size += snprintf(&buf[size], bufsize-size,
630                      "<li><a href=\"%s\"%s>%s</a></li>\n",
631                      tab_entries[tabs].filename,
632                      tabs == active ? " class=\"active\"" : "",
633                      tab_entries[tabs].tab_label);
634   }
635   size += snprintf(&buf[size], bufsize-size,
636                    "</ul>\n"
637                    "</td></tr>\n"
638                    "<tr><td>\n");
639   return size;
640 }
641
642
643 /*
644  * destructor - called at unload
645  */
646 void
647 olsr_plugin_exit(void)
648 {
649   if (http_socket >= 0) {
650     CLOSE(http_socket);
651   }
652 }
653
654
655 static int section_title(char *buf, olsr_u32_t bufsize, const char *title)
656 {
657   return snprintf(buf, bufsize,
658                   "<h2>%s</h2>\n"
659                   "<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" align=\"center\">\n", title);
660 }
661
662 static int build_frame(char *buf,
663                        olsr_u32_t bufsize,
664                        const char *title __attribute__((unused)),
665                        const char *link __attribute__((unused)),
666                        int width __attribute__((unused)),
667                        build_body_callback frame_body_cb)
668 {
669   int size = 0;
670   size += snprintf(&buf[size], bufsize-size, "<div id=\"maintable\">\n");
671   size += frame_body_cb(&buf[size], bufsize-size);
672   size += snprintf(&buf[size], bufsize-size, "</div>\n");
673   return size;
674 }
675
676 static int fmt_href(char *buf,
677                     const olsr_u32_t bufsize,
678                     const char * const ipaddr)
679 {
680   return snprintf(buf, bufsize, "<a href=\"http://%s:%d/all\">", ipaddr, http_port);
681 }
682
683 static int build_ip_txt(char *buf,
684                         const olsr_u32_t bufsize,
685                         const olsr_bool print_link,
686                         const char * const ipaddrstr,
687                         const int prefix_len)
688 {
689   int size = 0;
690
691   if (print_link) {
692     size += fmt_href(&buf[size], bufsize-size, ipaddrstr);
693   }
694
695   size += snprintf(&buf[size], bufsize-size, "%s", ipaddrstr);
696   /* print ip address or ip prefix ? */
697   if (prefix_len != -1 && prefix_len != olsr_cnf->maxplen) {
698       size += snprintf(&buf[size], bufsize-size, "/%d", prefix_len);
699   }
700
701   if (print_link) { /* Print the link only if there is no prefix_len */
702     size += snprintf(&buf[size], bufsize-size, "</a>");
703   }
704   return size;
705 }
706
707 static int build_ipaddr_link(char *buf, const olsr_u32_t bufsize,
708                              const olsr_bool want_link,
709                              const union olsr_ip_addr * const ipaddr,
710                              const int prefix_len)
711 {
712   int size = 0;
713   struct ipaddr_str ipaddrstr;
714   const struct hostent * const hp =
715 #ifndef WIN32
716       resolve_ip_addresses ? gethostbyaddr(ipaddr, olsr_cnf->ipsize, olsr_cnf->ip_version) :
717 #endif
718       NULL;
719   /* Print the link only if there is no prefix_len */
720   const int print_link = want_link && (prefix_len == -1 || prefix_len == olsr_cnf->maxplen);
721   olsr_ip_to_string(&ipaddrstr, ipaddr);
722
723   size += snprintf(&buf[size], bufsize-size, "<td>");
724   size += build_ip_txt(&buf[size], bufsize-size, print_link, ipaddrstr.buf, prefix_len);
725   size += snprintf(&buf[size], bufsize-size, "</td>");
726
727   if (resolve_ip_addresses) {
728     if (hp) {
729       size += snprintf(&buf[size], bufsize-size, "<td>(");
730       if (print_link) {
731         size += fmt_href(&buf[size], bufsize-size, ipaddrstr.buf);
732       }
733       size += snprintf(&buf[size], bufsize-size, "%s", hp->h_name);
734       if (print_link) {
735         size += snprintf(&buf[size], bufsize-size, "</a>");
736       }
737       size += snprintf(&buf[size], bufsize-size, ")</td>");
738     } else {
739       size += snprintf(&buf[size], bufsize-size, "<td/>");
740     }
741   }
742   return size;
743 }
744
745 #define build_ipaddr_with_link(buf, bufsize, ipaddr, plen) \
746           build_ipaddr_link((buf), (bufsize), OLSR_TRUE, (ipaddr), (plen))
747 #define build_ipaddr_no_link(buf, bufsize, ipaddr, plen) \
748           build_ipaddr_link((buf), (bufsize), OLSR_FALSE, (ipaddr), (plen))
749
750 static int build_route(char *buf, olsr_u32_t bufsize, const struct rt_entry * rt)
751 {
752   int size = 0;
753
754   size += snprintf(&buf[size], bufsize-size, "<tr>");
755   size += build_ipaddr_with_link(&buf[size], bufsize-size,
756                                  &rt->rt_dst.prefix,
757                                  rt->rt_dst.prefix_len);
758   size += build_ipaddr_with_link(&buf[size], bufsize-size,
759                                  &rt->rt_best->rtp_nexthop.gateway,
760                                  -1);
761
762   size += snprintf(&buf[size], bufsize-size,
763                    "<td align=\"center\">%d</td>",
764                    rt->rt_best->rtp_metric.hops);
765   size += snprintf(&buf[size], bufsize-size,
766                    "<td align=\"right\">%.3f</td>",
767                    rt->rt_best->rtp_metric.etx);
768   size += snprintf(&buf[size], bufsize-size,
769                    "<td align=\"center\">%s</td></tr>\n",
770                    if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
771   return size;
772 }
773
774 static int build_routes_body(char *buf, olsr_u32_t bufsize)
775 {
776   int size = 0;
777   struct rt_entry *rt;
778   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
779   size += section_title(&buf[size], bufsize-size, "OLSR Routes in Kernel");
780   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);
781
782   /* Walk the route table */
783   OLSR_FOR_ALL_RT_ENTRIES(rt) {
784       size += build_route(&buf[size], bufsize-size, rt);
785   } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
786
787   size += snprintf(&buf[size], bufsize-size, "</table>\n");
788
789   return size;
790 }
791
792 static int build_config_body(char *buf, olsr_u32_t bufsize)
793 {
794     int size = 0;
795     const struct olsr_if *ifs;
796     const struct plugin_entry *pentry;
797     const struct plugin_param *pparam;
798     struct ipaddr_str mainaddrbuf;
799
800     size += snprintf(&buf[size], bufsize-size, "Version: %s (built on %s on %s)\n<br>", olsrd_version, build_date, build_host);
801     size += snprintf(&buf[size], bufsize-size, "OS: %s\n<br>", OS);
802
803     {
804       const time_t currtime = time(NULL);
805       const int rc = strftime(&buf[size], bufsize-size, "System time: <em>%a, %d %b %Y %H:%M:%S</em><br>", localtime(&currtime));
806       if (rc > 0) {
807         size += rc;
808       }
809     }
810
811     {
812       struct timeval now, uptime;
813       int hours, mins, days;
814       gettimeofday(&now, NULL);
815       timersub(&now, &start_time, &uptime);
816
817       days = uptime.tv_sec/86400;
818       uptime.tv_sec %= 86400;
819       hours = uptime.tv_sec/3600;
820       uptime.tv_sec %= 3600;
821       mins = uptime.tv_sec/60;
822       uptime.tv_sec %= 60;
823
824       size += snprintf(&buf[size], bufsize-size, "Olsrd uptime: <em>");
825       if (days) {
826         size += snprintf(&buf[size], bufsize-size, "%d day(s) ", days);
827       }
828       size += snprintf(&buf[size], bufsize-size, "%02d hours %02d minutes %02d seconds</em><br/>\n", hours, mins, (int)uptime.tv_sec);
829     }
830
831     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);
832
833     size += snprintf(&buf[size], bufsize-size, "Click <a href=\"/cfgfile\">here</a> to <em>generate a configuration file for this node</em>.\n");
834
835     size += snprintf(&buf[size], bufsize-size, "<h2>Variables</h2>\n");
836
837     size += snprintf(&buf[size], bufsize-size, "<table width=\"100%%\" border=\"0\">\n<tr>");
838
839     size += snprintf(&buf[size], bufsize-size, "<td>Main address: <strong>%s</strong></td>\n", olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->main_addr));
840     size += snprintf(&buf[size], bufsize-size, "<td>IP version: %d</td>\n", olsr_cnf->ip_version == AF_INET ? 4 : 6);
841     size += snprintf(&buf[size], bufsize-size, "<td>Debug level: %d</td>\n", olsr_cnf->debug_level);
842     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);
843
844     size += snprintf(&buf[size], bufsize-size, "</tr>\n<tr>\n");
845
846     size += snprintf(&buf[size], bufsize-size, "<td>Pollrate: %0.2f</td>\n", olsr_cnf->pollrate);
847     size += snprintf(&buf[size], bufsize-size, "<td>TC redundancy: %d</td>\n", olsr_cnf->tc_redundancy);
848     size += snprintf(&buf[size], bufsize-size, "<td>MPR coverage: %d</td>\n", olsr_cnf->mpr_coverage);
849     size += snprintf(&buf[size], bufsize-size, "<td>NAT threshold: %f</td>\n", olsr_cnf->lq_nat_thresh);
850
851     size += snprintf(&buf[size], bufsize-size, "</tr>\n<tr>\n");
852
853     size += snprintf(&buf[size], bufsize-size, "<td>Fisheye: %s</td>\n", olsr_cnf->lq_fish ? "Enabled" : "Disabled");
854     size += snprintf(&buf[size], bufsize-size, "<td>TOS: 0x%04x</td>\n", olsr_cnf->tos);
855     size += snprintf(&buf[size], bufsize-size, "<td>RtTable: 0x%04x/%d</td>\n", olsr_cnf->rttable, olsr_cnf->rttable);
856     size += snprintf(&buf[size], bufsize-size, "<td>Willingness: %d %s</td>\n", olsr_cnf->willingness, olsr_cnf->willingness_auto ? "(auto)" : "");
857
858     if (olsr_cnf->lq_level == 0) {
859       size += snprintf(&buf[size], bufsize-size, "</tr>\n<tr>\n"
860                                                   "<td>Hysteresis: %s</td>\n", olsr_cnf->use_hysteresis ? "Enabled" : "Disabled");
861       if (olsr_cnf->use_hysteresis) {
862         size += snprintf(&buf[size], bufsize-size, "<td>Hyst scaling: %0.2f</td>\n", olsr_cnf->hysteresis_param.scaling);
863         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);
864       }
865     }
866
867     size += snprintf(&buf[size], bufsize-size, "</tr>\n<tr>\n"
868                                                "<td>LQ extension: %s</td>\n", olsr_cnf->lq_level ? "Enabled" : "Disabled");
869     if (olsr_cnf->lq_level) {
870       size += snprintf(&buf[size], bufsize-size,
871                        "<td>LQ level: %d</td>\n"
872                        "<td>LQ winsize: %d</td>\n",
873                        olsr_cnf->lq_level,
874                        olsr_cnf->lq_wsize);
875     }
876     size += snprintf(&buf[size], bufsize-size, "</tr></table>\n");
877
878     size += snprintf(&buf[size], bufsize-size, "<h2>Interfaces</h2>\n");
879     size += snprintf(&buf[size], bufsize-size, "<table width=\"100%%\" border=\"0\">\n");
880     for (ifs = olsr_cnf->interfaces; ifs != NULL; ifs = ifs->next) {
881         const struct interface * const rifs = ifs->interf;
882         size += snprintf(&buf[size], bufsize-size, "<tr><th colspan=\"3\">%s</th>\n", ifs->name);
883         if (!rifs) {
884           size += snprintf(&buf[size], bufsize-size, "<tr><td colspan=\"3\">Status: DOWN</td></tr>\n");
885           continue;
886         }
887
888         if (olsr_cnf->ip_version == AF_INET) {
889           struct ipaddr_str addrbuf, maskbuf, bcastbuf;
890           size += snprintf(&buf[size], bufsize-size,
891                            "<tr>\n"
892                            "<td>IP: %s</td>\n"
893                            "<td>MASK: %s</td>\n"
894                            "<td>BCAST: %s</td>\n"
895                            "</tr>\n",
896                            ip4_to_string(&addrbuf, rifs->int_addr.sin_addr),
897                            ip4_to_string(&maskbuf, rifs->int_netmask.sin_addr),
898                            ip4_to_string(&bcastbuf, rifs->int_broadaddr.sin_addr));
899         } else {
900           struct ipaddr_str addrbuf, maskbuf;
901           size += snprintf(&buf[size], bufsize-size,
902                            "<tr>\n"
903                            "<td>IP: %s</td>\n"
904                            "<td>MCAST: %s</td>\n"
905                            "<td></td>\n"
906                            "</tr>\n",
907                            ip6_to_string(&addrbuf, &rifs->int6_addr.sin6_addr),
908                            ip6_to_string(&maskbuf, &rifs->int6_multaddr.sin6_addr));
909         }       
910         size += snprintf(&buf[size], bufsize-size,
911                          "<tr>\n"
912                          "<td>MTU: %d</td>\n"
913                          "<td>WLAN: %s</td>\n"
914                          "<td>STATUS: UP</td>\n"
915                          "</tr>\n",
916                          rifs->int_mtu,
917                          rifs->is_wireless ? "Yes" : "No");
918     }
919     size += snprintf(&buf[size], bufsize-size, "</table>\n");
920
921     size += snprintf(&buf[size], bufsize-size,
922                      "<em>Olsrd is configured to %s if no interfaces are available</em><br>\n",
923                      olsr_cnf->allow_no_interfaces ? "run even" : "halt");
924
925     size += snprintf(&buf[size], bufsize-size, "<h2>Plugins</h2>\n");
926     size += snprintf(&buf[size], bufsize-size, "<table width=\"100%%\" border=\"0\"><tr><th>Name</th><th>Parameters</th></tr>\n");
927     for (pentry = olsr_cnf->plugins; pentry; pentry = pentry->next)
928       {
929         size += snprintf(&buf[size], bufsize-size,
930                          "<tr><td>%s</td>\n"
931                          "<td><select>\n"
932                          "<option>KEY, VALUE</option>\n",
933                          pentry->name);
934
935         for (pparam = pentry->params; pparam; pparam = pparam->next)
936           {
937             size += snprintf(&buf[size], bufsize-size, "<option>\"%s\", \"%s\"</option>\n", pparam->key, pparam->value);
938           }
939         size += snprintf(&buf[size], bufsize-size, "</select></td></tr>\n");
940
941       }
942     size += snprintf(&buf[size], bufsize-size, "</table>\n");
943
944     size += section_title(&buf[size], bufsize-size, "Announced HNA entries");
945     if (olsr_cnf->hna_entries) {
946       struct ip_prefix_list *hna;
947       size += snprintf(&buf[size], bufsize-size, "<tr><th>Network</th></tr>\n");
948       for (hna = olsr_cnf->hna_entries; hna; hna = hna->next) {
949         struct ipaddr_str netbuf;
950         size += snprintf(&buf[size], bufsize-size,
951                          "<tr><td>%s/%d</td></tr>\n",
952                          olsr_ip_to_string(&netbuf, &hna->net.prefix),
953                          hna->net.prefix_len);
954       }
955     } else {
956       size += snprintf(&buf[size], bufsize-size, "<tr><td></td></tr>\n");
957     }
958     size += snprintf(&buf[size], bufsize-size, "</table>\n");
959     return size;
960 }
961
962
963
964 static int build_neigh_body(char *buf, olsr_u32_t bufsize)
965 {
966   struct neighbor_entry *neigh;
967   struct link_entry *link = NULL;
968   int size = 0, idx;
969   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
970
971   size += section_title(&buf[size], bufsize-size, "Links");
972
973   size += snprintf(&buf[size], bufsize-size,
974                    "<tr><th align=\"center\"%s>Local IP</th><th align=\"center\"%s>Remote IP</th><th align=\"right\">Hysteresis</th>", colspan, colspan);
975   if (olsr_cnf->lq_level > 0) {
976     size += snprintf(&buf[size], bufsize-size,
977                      "<th align=\"right\">LinkQuality</th><th>lost</th><th>total</th><th align=\"right\">NLQ</th><th align=\"right\">ETX</th>");
978   }
979   size += snprintf(&buf[size], bufsize-size, "</tr>\n");
980
981   /* Link set */
982   for (link = link_set; link != NULL; link = link->next) {
983     size += snprintf(&buf[size], bufsize-size, "<tr>");
984     size += build_ipaddr_with_link(&buf[size], bufsize, &link->local_iface_addr, -1);
985     size += build_ipaddr_with_link(&buf[size], bufsize, &link->neighbor_iface_addr, -1);
986     size += snprintf(&buf[size], bufsize-size, "<td align=\"right\">%0.2f</td>", link->L_link_quality);
987     if (olsr_cnf->lq_level > 0) {
988       size += snprintf(&buf[size], bufsize-size,
989                        "<td align=\"right\">%0.2f</td>"
990                        "<td>%d</td>"
991                        "<td>%d</td>"
992                        "<td align=\"right\">%0.2f</td>"
993                        "<td align=\"right\">%0.2f</td>\n",
994                        link->loss_link_quality,
995                        link->lost_packets,
996                        link->total_packets,
997                        link->neigh_link_quality,
998                        olsr_calc_link_etx(link));
999     }
1000     size += snprintf(&buf[size], bufsize-size, "</tr>\n");
1001   }
1002
1003   size += snprintf(&buf[size], bufsize-size, "</table>\n");
1004
1005   size += section_title(&buf[size], bufsize-size, "Neighbors");
1006   size += snprintf(&buf[size], bufsize-size,
1007                    "<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);
1008   /* Neighbors */
1009   for (idx = 0; idx < HASHSIZE; idx++) {
1010     for (neigh = neighbortable[idx].next; neigh != &neighbortable[idx]; neigh = neigh->next) {
1011       struct neighbor_2_list_entry *list_2;
1012       int thop_cnt;
1013       size += snprintf(&buf[size], bufsize-size, "<tr>");
1014       size += build_ipaddr_with_link(&buf[size], bufsize, &neigh->neighbor_main_addr, -1);
1015       size += snprintf(&buf[size], bufsize-size,
1016                        "<td align=\"center\">%s</td>"
1017                        "<td align=\"center\">%s</td>"
1018                        "<td align=\"center\">%s</td>"
1019                        "<td align=\"center\">%d</td>",
1020                        (neigh->status == SYM) ? "YES" : "NO",
1021                        neigh->is_mpr ? "YES" : "NO",
1022                        olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO",
1023                        neigh->willingness);
1024
1025       size += snprintf(&buf[size], bufsize-size, "<td><select>\n"
1026                        "<option>IP ADDRESS</option>\n");
1027
1028
1029       for (list_2 = neigh->neighbor_2_list.next, thop_cnt = 0; list_2 != &neigh->neighbor_2_list; list_2 = list_2->next, thop_cnt++) {
1030         struct ipaddr_str strbuf;
1031         size += snprintf(&buf[size], bufsize-size, "<option>%s</option>\n", 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     }
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\">LQ</th><th align=\"right\">ILQ</th><th align=\"right\">ETX</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           size += snprintf(&buf[size], bufsize-size, "<tr>");
1057           size += build_ipaddr_with_link(&buf[size], bufsize, &tc_edge->T_dest_addr, -1);
1058           size += build_ipaddr_with_link(&buf[size], bufsize, &tc->addr, -1);
1059           if (olsr_cnf->lq_level > 0) {
1060               size += snprintf(&buf[size], bufsize-size,
1061                                "<td align=\"right\">%0.2f</td>"
1062                                "<td align=\"right\">%0.2f</td>"
1063                                "<td align=\"right\">%0.2f</td>\n",
1064                                tc_edge->link_quality,
1065                                tc_edge->inverse_link_quality,
1066                                olsr_calc_tc_etx(tc_edge));
1067           }
1068           size += snprintf(&buf[size], bufsize-size, "</tr>\n");
1069
1070       } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
1071   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
1072
1073   size += snprintf(&buf[size], bufsize-size, "</table>\n");
1074
1075   return size;
1076 }
1077
1078 static int build_mid_body(char *buf, olsr_u32_t bufsize)
1079 {
1080   int size = 0;
1081   int idx;
1082   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1083
1084   size += section_title(&buf[size], bufsize-size, "MID Entries");
1085   size += snprintf(&buf[size], bufsize-size,
1086                    "<tr><th align=\"center\"%s>Main Address</th><th>Aliases</th></tr>\n", colspan);
1087
1088   /* MID */
1089   for (idx = 0; idx < HASHSIZE; idx++) {
1090     struct mid_entry *entry;
1091     for (entry = mid_set[idx].next; entry != &mid_set[idx]; entry = entry->next) {
1092       int mid_cnt;
1093       struct mid_address *alias;
1094       size += snprintf(&buf[size], bufsize-size, "<tr>");
1095       size += build_ipaddr_with_link(&buf[size], bufsize, &entry->main_addr, -1);
1096       size += snprintf(&buf[size], bufsize-size, "<td><select>\n<option>IP ADDRESS</option>\n");
1097
1098       for (mid_cnt = 0, alias = entry->aliases; alias != NULL; alias = alias->next_alias, mid_cnt++) {
1099         struct ipaddr_str strbuf;
1100         size += snprintf(&buf[size], bufsize-size, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &alias->alias));
1101       }
1102       size += snprintf(&buf[size], bufsize-size, "</select> (%d)</td></tr>\n", mid_cnt);
1103     }
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 allowed_nets, const union olsr_ip_addr * const addr)
1218 {
1219     const struct allowed_net *alln;
1220     for (alln = allowed_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 }