rttable-default: (from otti) configures a new policy routing table for the default...
[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>RtTableDefault: 0x%04x/%d</td>\n", olsr_cnf->rttable_default, olsr_cnf->rttable_default);
857     size += snprintf(&buf[size], bufsize-size, "<td>Willingness: %d %s</td>\n", olsr_cnf->willingness, olsr_cnf->willingness_auto ? "(auto)" : "");
858
859     if (olsr_cnf->lq_level == 0) {
860       size += snprintf(&buf[size], bufsize-size, "</tr>\n<tr>\n"
861                                                   "<td>Hysteresis: %s</td>\n", olsr_cnf->use_hysteresis ? "Enabled" : "Disabled");
862       if (olsr_cnf->use_hysteresis) {
863         size += snprintf(&buf[size], bufsize-size, "<td>Hyst scaling: %0.2f</td>\n", olsr_cnf->hysteresis_param.scaling);
864         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);
865       }
866     }
867
868     size += snprintf(&buf[size], bufsize-size, "</tr>\n<tr>\n"
869                                                "<td>LQ extension: %s</td>\n", olsr_cnf->lq_level ? "Enabled" : "Disabled");
870     if (olsr_cnf->lq_level) {
871       size += snprintf(&buf[size], bufsize-size,
872                        "<td>LQ level: %d</td>\n"
873                        "<td>LQ winsize: %d</td>\n",
874                        olsr_cnf->lq_level,
875                        olsr_cnf->lq_wsize);
876     }
877     size += snprintf(&buf[size], bufsize-size, "</tr></table>\n");
878
879     size += snprintf(&buf[size], bufsize-size, "<h2>Interfaces</h2>\n");
880     size += snprintf(&buf[size], bufsize-size, "<table width=\"100%%\" border=\"0\">\n");
881     for (ifs = olsr_cnf->interfaces; ifs != NULL; ifs = ifs->next) {
882         const struct interface * const rifs = ifs->interf;
883         size += snprintf(&buf[size], bufsize-size, "<tr><th colspan=\"3\">%s</th>\n", ifs->name);
884         if (!rifs) {
885           size += snprintf(&buf[size], bufsize-size, "<tr><td colspan=\"3\">Status: DOWN</td></tr>\n");
886           continue;
887         }
888
889         if (olsr_cnf->ip_version == AF_INET) {
890           struct ipaddr_str addrbuf, maskbuf, bcastbuf;
891           size += snprintf(&buf[size], bufsize-size,
892                            "<tr>\n"
893                            "<td>IP: %s</td>\n"
894                            "<td>MASK: %s</td>\n"
895                            "<td>BCAST: %s</td>\n"
896                            "</tr>\n",
897                            ip4_to_string(&addrbuf, rifs->int_addr.sin_addr),
898                            ip4_to_string(&maskbuf, rifs->int_netmask.sin_addr),
899                            ip4_to_string(&bcastbuf, rifs->int_broadaddr.sin_addr));
900         } else {
901           struct ipaddr_str addrbuf, maskbuf;
902           size += snprintf(&buf[size], bufsize-size,
903                            "<tr>\n"
904                            "<td>IP: %s</td>\n"
905                            "<td>MCAST: %s</td>\n"
906                            "<td></td>\n"
907                            "</tr>\n",
908                            ip6_to_string(&addrbuf, &rifs->int6_addr.sin6_addr),
909                            ip6_to_string(&maskbuf, &rifs->int6_multaddr.sin6_addr));
910         }       
911         size += snprintf(&buf[size], bufsize-size,
912                          "<tr>\n"
913                          "<td>MTU: %d</td>\n"
914                          "<td>WLAN: %s</td>\n"
915                          "<td>STATUS: UP</td>\n"
916                          "</tr>\n",
917                          rifs->int_mtu,
918                          rifs->is_wireless ? "Yes" : "No");
919     }
920     size += snprintf(&buf[size], bufsize-size, "</table>\n");
921
922     size += snprintf(&buf[size], bufsize-size,
923                      "<em>Olsrd is configured to %s if no interfaces are available</em><br>\n",
924                      olsr_cnf->allow_no_interfaces ? "run even" : "halt");
925
926     size += snprintf(&buf[size], bufsize-size, "<h2>Plugins</h2>\n");
927     size += snprintf(&buf[size], bufsize-size, "<table width=\"100%%\" border=\"0\"><tr><th>Name</th><th>Parameters</th></tr>\n");
928     for (pentry = olsr_cnf->plugins; pentry; pentry = pentry->next)
929       {
930         size += snprintf(&buf[size], bufsize-size,
931                          "<tr><td>%s</td>\n"
932                          "<td><select>\n"
933                          "<option>KEY, VALUE</option>\n",
934                          pentry->name);
935
936         for (pparam = pentry->params; pparam; pparam = pparam->next)
937           {
938             size += snprintf(&buf[size], bufsize-size, "<option>\"%s\", \"%s\"</option>\n", pparam->key, pparam->value);
939           }
940         size += snprintf(&buf[size], bufsize-size, "</select></td></tr>\n");
941
942       }
943     size += snprintf(&buf[size], bufsize-size, "</table>\n");
944
945     size += section_title(&buf[size], bufsize-size, "Announced HNA entries");
946     if (olsr_cnf->hna_entries) {
947       struct ip_prefix_list *hna;
948       size += snprintf(&buf[size], bufsize-size, "<tr><th>Network</th></tr>\n");
949       for (hna = olsr_cnf->hna_entries; hna; hna = hna->next) {
950         struct ipaddr_str netbuf;
951         size += snprintf(&buf[size], bufsize-size,
952                          "<tr><td>%s/%d</td></tr>\n",
953                          olsr_ip_to_string(&netbuf, &hna->net.prefix),
954                          hna->net.prefix_len);
955       }
956     } else {
957       size += snprintf(&buf[size], bufsize-size, "<tr><td></td></tr>\n");
958     }
959     size += snprintf(&buf[size], bufsize-size, "</table>\n");
960     return size;
961 }
962
963
964
965 static int build_neigh_body(char *buf, olsr_u32_t bufsize)
966 {
967   struct neighbor_entry *neigh;
968   struct link_entry *link = NULL;
969   int size = 0, idx;
970   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
971
972   size += section_title(&buf[size], bufsize-size, "Links");
973
974   size += snprintf(&buf[size], bufsize-size,
975                    "<tr><th align=\"center\"%s>Local IP</th><th align=\"center\"%s>Remote IP</th><th align=\"right\">Hysteresis</th>", colspan, colspan);
976   if (olsr_cnf->lq_level > 0) {
977     size += snprintf(&buf[size], bufsize-size,
978                      "<th align=\"right\">LinkQuality</th><th>lost</th><th>total</th><th align=\"right\">NLQ</th><th align=\"right\">ETX</th>");
979   }
980   size += snprintf(&buf[size], bufsize-size, "</tr>\n");
981
982   /* Link set */
983   for (link = link_set; link != NULL; link = link->next) {
984     size += snprintf(&buf[size], bufsize-size, "<tr>");
985     size += build_ipaddr_with_link(&buf[size], bufsize, &link->local_iface_addr, -1);
986     size += build_ipaddr_with_link(&buf[size], bufsize, &link->neighbor_iface_addr, -1);
987     size += snprintf(&buf[size], bufsize-size, "<td align=\"right\">%0.2f</td>", link->L_link_quality);
988     if (olsr_cnf->lq_level > 0) {
989       size += snprintf(&buf[size], bufsize-size,
990                        "<td align=\"right\">%0.2f</td>"
991                        "<td>%d</td>"
992                        "<td>%d</td>"
993                        "<td align=\"right\">%0.2f</td>"
994                        "<td align=\"right\">%0.2f</td>\n",
995                        link->loss_link_quality,
996                        link->lost_packets,
997                        link->total_packets,
998                        link->neigh_link_quality,
999                        olsr_calc_link_etx(link));
1000     }
1001     size += snprintf(&buf[size], bufsize-size, "</tr>\n");
1002   }
1003
1004   size += snprintf(&buf[size], bufsize-size, "</table>\n");
1005
1006   size += section_title(&buf[size], bufsize-size, "Neighbors");
1007   size += snprintf(&buf[size], bufsize-size,
1008                    "<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);
1009   /* Neighbors */
1010   for (idx = 0; idx < HASHSIZE; idx++) {
1011     for (neigh = neighbortable[idx].next; neigh != &neighbortable[idx]; neigh = neigh->next) {
1012       struct neighbor_2_list_entry *list_2;
1013       int thop_cnt;
1014       size += snprintf(&buf[size], bufsize-size, "<tr>");
1015       size += build_ipaddr_with_link(&buf[size], bufsize, &neigh->neighbor_main_addr, -1);
1016       size += snprintf(&buf[size], bufsize-size,
1017                        "<td align=\"center\">%s</td>"
1018                        "<td align=\"center\">%s</td>"
1019                        "<td align=\"center\">%s</td>"
1020                        "<td align=\"center\">%d</td>",
1021                        (neigh->status == SYM) ? "YES" : "NO",
1022                        neigh->is_mpr ? "YES" : "NO",
1023                        olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO",
1024                        neigh->willingness);
1025
1026       size += snprintf(&buf[size], bufsize-size, "<td><select>\n"
1027                        "<option>IP ADDRESS</option>\n");
1028
1029
1030       for (list_2 = neigh->neighbor_2_list.next, thop_cnt = 0; list_2 != &neigh->neighbor_2_list; list_2 = list_2->next, thop_cnt++) {
1031         struct ipaddr_str strbuf;
1032         size += snprintf(&buf[size], bufsize-size, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &list_2->neighbor_2->neighbor_2_addr));
1033       }
1034       size += snprintf(&buf[size], bufsize-size, "</select> (%d)</td></tr>\n", thop_cnt);
1035     }
1036   }
1037   size += snprintf(&buf[size], bufsize-size, "</table>\n");
1038   return size;
1039 }
1040
1041 static int build_topo_body(char *buf, olsr_u32_t bufsize)
1042 {
1043   int size = 0;
1044   struct tc_entry *tc;
1045   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1046
1047   size += section_title(&buf[size], bufsize-size, "Topology Entries");
1048   size += snprintf(&buf[size], bufsize-size, "<tr><th align=\"center\"%s>Destination IP</th><th align=\"center\"%s>Last Hop IP</th>", colspan, colspan);
1049   if (olsr_cnf->lq_level > 0) {
1050     size += snprintf(&buf[size], bufsize-size, "<th align=\"right\">LQ</th><th align=\"right\">ILQ</th><th align=\"right\">ETX</th>");
1051   }
1052   size += snprintf(&buf[size], bufsize-size, "</tr>\n");
1053
1054   OLSR_FOR_ALL_TC_ENTRIES(tc) {
1055       struct tc_edge_entry *tc_edge;
1056       OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
1057           size += snprintf(&buf[size], bufsize-size, "<tr>");
1058           size += build_ipaddr_with_link(&buf[size], bufsize, &tc_edge->T_dest_addr, -1);
1059           size += build_ipaddr_with_link(&buf[size], bufsize, &tc->addr, -1);
1060           if (olsr_cnf->lq_level > 0) {
1061               size += snprintf(&buf[size], bufsize-size,
1062                                "<td align=\"right\">%0.2f</td>"
1063                                "<td align=\"right\">%0.2f</td>"
1064                                "<td align=\"right\">%0.2f</td>\n",
1065                                tc_edge->link_quality,
1066                                tc_edge->inverse_link_quality,
1067                                olsr_calc_tc_etx(tc_edge));
1068           }
1069           size += snprintf(&buf[size], bufsize-size, "</tr>\n");
1070
1071       } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
1072   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
1073
1074   size += snprintf(&buf[size], bufsize-size, "</table>\n");
1075
1076   return size;
1077 }
1078
1079 static int build_mid_body(char *buf, olsr_u32_t bufsize)
1080 {
1081   int size = 0;
1082   int idx;
1083   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1084
1085   size += section_title(&buf[size], bufsize-size, "MID Entries");
1086   size += snprintf(&buf[size], bufsize-size,
1087                    "<tr><th align=\"center\"%s>Main Address</th><th>Aliases</th></tr>\n", colspan);
1088
1089   /* MID */
1090   for (idx = 0; idx < HASHSIZE; idx++) {
1091     struct mid_entry *entry;
1092     for (entry = mid_set[idx].next; entry != &mid_set[idx]; entry = entry->next) {
1093       int mid_cnt;
1094       struct mid_address *alias;
1095       size += snprintf(&buf[size], bufsize-size, "<tr>");
1096       size += build_ipaddr_with_link(&buf[size], bufsize, &entry->main_addr, -1);
1097       size += snprintf(&buf[size], bufsize-size, "<td><select>\n<option>IP ADDRESS</option>\n");
1098
1099       for (mid_cnt = 0, alias = entry->aliases; alias != NULL; alias = alias->next_alias, mid_cnt++) {
1100         struct ipaddr_str strbuf;
1101         size += snprintf(&buf[size], bufsize-size, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &alias->alias));
1102       }
1103       size += snprintf(&buf[size], bufsize-size, "</select> (%d)</td></tr>\n", mid_cnt);
1104     }
1105   }
1106
1107   size += snprintf(&buf[size], bufsize-size, "</table>\n");
1108   return size;
1109 }
1110
1111
1112 static int build_nodes_body(char *buf, olsr_u32_t bufsize)
1113 {
1114   int size = 0;
1115
1116   size += build_neigh_body(&buf[size], bufsize-size);
1117   size += build_topo_body(&buf[size], bufsize-size);
1118   size += build_mid_body(&buf[size], bufsize-size);
1119
1120   return size;
1121 }
1122
1123 static int build_all_body(char *buf, olsr_u32_t bufsize)
1124 {
1125   int size = 0;
1126
1127   size += build_config_body(&buf[size], bufsize-size);
1128   size += build_routes_body(&buf[size], bufsize-size);
1129   size += build_neigh_body(&buf[size], bufsize-size);
1130   size += build_topo_body(&buf[size], bufsize-size);
1131   size += build_mid_body(&buf[size], bufsize-size);
1132
1133   return size;
1134 }
1135
1136
1137 static int build_about_body(char *buf, olsr_u32_t bufsize)
1138 {
1139   return snprintf(buf, bufsize,
1140                   "<strong>" PLUGIN_NAME " version " PLUGIN_VERSION "</strong><br/>\n"
1141                   "by Andreas T&oslash;nnesen (C)2005.<br/>\n"
1142                   "Compiled "
1143 #ifdef ADMIN_INTERFACE
1144                            "<em>with experimental admin interface</em> "
1145 #endif
1146                                                                       "%s at %s<hr/>\n"
1147                   "This plugin implements a HTTP server that supplies\n"
1148                   "the client with various dynamic web pages representing\n"
1149                   "the current olsrd status.<br/>The different pages include:\n"
1150                   "<ul>\n<li><strong>Configuration</strong> - This page displays information\n"
1151                   "about the current olsrd configuration. This includes various\n"
1152                   "olsr settings such as IP version, MID/TC redundancy, hysteresis\n"
1153                   "etc. Information about the current status of the interfaces on\n"
1154                   "which olsrd is configured to run is also displayed. Loaded olsrd\n"
1155                   "plugins are shown with their plugin parameters. Finally all local\n"
1156                   "HNA entries are shown. These are the networks that the local host\n"
1157                   "will anounce itself as a gateway to.</li>\n"
1158                   "<li><strong>Routes</strong> - This page displays all routes currently set in\n"
1159                   "the kernel <em>by olsrd</em>. The type of route is also displayed(host\n"
1160                   "or HNA).</li>\n"
1161                   "<li><strong>Links/Topology</strong> - This page displays all information about\n"
1162                   "links, neighbors, topology, MID and HNA entries.</li>\n"
1163                   "<li><strong>All</strong> - Here all the previous pages are displayed as one.\n"
1164                   "This is to make all information available as easy as possible(for example\n"
1165                   "for a script) and using as few resources as possible.</li>\n"
1166 #ifdef ADMIN_INTERFACE
1167                   "<li><strong>Admin</strong> - This page is highly experimental(and unsecure)!\n"
1168                   "As of now it is not working at all but it provides a impression of\n"
1169                   "the future possibilities of httpinfo. This is to be a interface to\n"
1170                   "changing olsrd settings in realtime. These settings include various\n"
1171                   "\"basic\" settings and local HNA settings.</li>\n"
1172 #endif
1173                   "<li><strong>About</strong> - this help page.</li>\n</ul>"
1174                   "<hr/>\n"
1175                   "Send questions or comments to\n"
1176                   "<a href=\"mailto:olsr-users@olsr.org\">olsr-users@olsr.org</a> or\n"
1177                   "<a href=\"mailto:andreto-at-olsr.org\">andreto-at-olsr.org</a><br/>\n"
1178                   "Official olsrd homepage: <a href=\"http://www.olsr.org/\">http://www.olsr.org</a><br/>\n",
1179                   build_date, build_host);
1180 }
1181
1182 static int build_cfgfile_body(char *buf, olsr_u32_t bufsize)
1183 {
1184   int size = 0;
1185
1186   size += snprintf(&buf[size], bufsize-size,
1187                    "\n\n"
1188                    "<strong>This is a automatically generated configuration\n"
1189                    "file based on the current olsrd configuration of this node.<br/>\n"
1190                    "<hr/>\n"
1191                    "<pre>\n");
1192
1193 #ifdef NETDIRECT
1194   {
1195         /* Hack to make netdirect stuff work with
1196            olsrd_write_cnf_buf
1197         */
1198         char tmpBuf[10000];
1199         size = olsrd_write_cnf_buf(olsr_cnf, tmpBuf, 10000);
1200         snprintf(&buf[size], bufsize-size, tmpBuf);
1201   }
1202 #else
1203   size += olsrd_write_cnf_buf(olsr_cnf, &buf[size], bufsize-size);
1204 #endif
1205
1206   if (size < 0) {
1207     size = snprintf(buf, size, "ERROR GENERATING CONFIGFILE!\n");
1208   }
1209
1210   size += snprintf(&buf[size], bufsize-size, "</pre>\n<hr/>\n");
1211
1212 #if 0
1213   printf("RETURNING %d\n", size);
1214 #endif
1215   return size;
1216 }
1217
1218 static int check_allowed_ip(const struct allowed_net * const allowed_nets, const union olsr_ip_addr * const addr)
1219 {
1220     const struct allowed_net *alln;
1221     for (alln = allowed_nets; alln != NULL; alln = alln->next) {
1222         if ((addr->v4.s_addr & alln->mask.v4.s_addr) == (alln->net.v4.s_addr & alln->mask.v4.s_addr)) {
1223             return 1;
1224         }
1225     }
1226     return 0;
1227 }
1228
1229
1230
1231 #if 0
1232 /*
1233  * In a bigger mesh, there are probs with the fixed
1234  * bufsize. Because the Content-Length header is
1235  * optional, the sprintf() is changed to a more
1236  * scalable solution here.
1237  */
1238
1239 int netsprintf(char *str, const char* format, ...)
1240 {
1241         va_list arg;
1242         int rv;
1243         va_start(arg, format);
1244         rv = vsprintf(str, format, arg);
1245         va_end(arg);
1246         if (0 != netsprintf_direct) {
1247                 if (0 == netsprintf_error) {
1248                         if (0 > send(client_sockets[curr_clients], str, rv, 0)) {
1249                                 olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
1250                                 netsprintf_error = 1;
1251                         }
1252                 }
1253                 return 0;
1254         }
1255         return rv;
1256 }
1257 #endif
1258
1259 static ssize_t writen(int fd, const void *buf, size_t count)
1260 {
1261     size_t bytes_left = count;
1262     const char *p = buf;
1263     while (bytes_left > 0) {
1264         const ssize_t written = write(fd, p, bytes_left);
1265         if (written == -1)  { /* error */
1266             if (errno == EINTR ) {
1267                 continue;
1268             }
1269             return -1;
1270         }
1271         /* We wrote something */
1272         bytes_left -= written;
1273         p += written;
1274     }
1275     return count;
1276 }