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