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