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