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