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