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