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