[hotfix] plugin: httpinfo: in case of an unrecoverable error ("could not initialize...
[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 "olsr_cfg.h"
59 #include "interfaces.h"
60 #include "olsr_protocol.h"
61 #include "net_olsr.h"
62 #include "link_set.h"
63 #include "ipcalc.h"
64 #include "lq_plugin.h"
65 #include "common/autobuf.h"
66 #ifdef HTTPINFO_PUD
67   #include <pud/src/receiver.h>
68   #include <pud/src/pud.h>
69   #include <nmea/info.h>
70   #include <nmea/sentence.h>
71 #endif /* HTTPINFO_PUD */
72
73 #include "olsrd_httpinfo.h"
74 #include "admin_interface.h"
75 #include "gfx.h"
76
77 #ifdef OS
78 #undef OS
79 #endif /* OS */
80
81 #ifdef _WIN32
82 #define close(x) closesocket(x)
83 #define OS "Windows"
84 #endif /* _WIN32 */
85 #ifdef __linux__
86 #define OS "GNU/Linux"
87 #endif /* __linux__ */
88 #if defined __FreeBSD__ || defined __FreeBSD_kernel__
89 #define OS "FreeBSD"
90 #endif /* defined __FreeBSD__ || defined __FreeBSD_kernel__ */
91
92 #ifndef OS
93 #define OS "Undefined"
94 #endif /* OS */
95
96 static char copyright_string[] __attribute__ ((unused)) =
97   "olsr.org HTTPINFO plugin Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org) All rights reserved.";
98
99 #define MAX_CLIENTS 3
100
101 #define MAX_HTTPREQ_SIZE (1024 * 10)
102
103 #define DEFAULT_TCP_PORT 1978
104
105 #define HTML_BUFSIZE (1024 * 4000)
106
107 #define FRAMEWIDTH (resolve_ip_addresses ? 900 : 800)
108
109 #define FILENREQ_MATCH(req, filename) \
110         !strcmp(req, filename) || \
111         (strlen(req) && !strcmp(&req[1], filename))
112
113 static const char httpinfo_css[] =
114   "#A {text-decoration: none}\n" "TH{text-align: left}\n" "H1, H3, TD, TH {font-family: Helvetica; font-size: 80%}\n"
115   "h2\n {\nfont-family: Helvetica;\n font-size: 14px;text-align: center;\n"
116   "line-height: 16px;\ntext-decoration: none;\nborder: 1px solid #ccc;\n" "margin: 5px;\nbackground: #ececec;\n}\n"
117   "hr\n{\nborder: none;\npadding: 1px;\nbackground: url(grayline.gif) repeat-x bottom;\n}\n"
118   "#maintable\n{\nmargin: 0px;\npadding: 5px;\nborder-left: 1px solid #ccc;\n"
119   "border-right: 1px solid #ccc;\nborder-bottom: 1px solid #ccc;\n}\n"
120   "#footer\n{\nfont-size: 10px;\nline-height: 14px;\ntext-decoration: none;\ncolor: #666;\n}\n"
121   "#hdr\n{\nfont-size: 14px;\ntext-align: center;\nline-height: 16px;\n" "text-decoration: none;\nborder: 1px solid #ccc;\n"
122   "margin: 5px;\nbackground: #ececec;\n}\n"
123   "#container\n{\nwidth: 1000px;\npadding: 30px;\nborder: 1px solid #ccc;\nbackground: #fff;\n}\n"
124   "#tabnav\n{\nheight: 20px;\nmargin: 0;\npadding-left: 10px;\n" "background: url(grayline.gif) repeat-x bottom;\n}\n"
125   "#tabnav li\n{\nmargin: 0;\npadding: 0;\ndisplay: inline;\nlist-style-type: none;\n}\n"
126   "#tabnav a:link, #tabnav a:visited\n{\nfloat: left;\nbackground: #ececec;\n"
127   "font-size: 12px;\nline-height: 14px;\nfont-weight: bold;\npadding: 2px 10px 2px 10px;\n"
128   "margin-right: 4px;\nborder: 1px solid #ccc;\ntext-decoration: none;\ncolor: #777;\n}\n"
129   "#tabnav a:link.active, #tabnav a:visited.active\n{\nborder-bottom: 1px solid #fff;\n" "background: #ffffff;\ncolor: #000;\n}\n"
130   "#tabnav a:hover\n{\nbackground: #777777;\ncolor: #ffffff;\n}\n"
131   ".input_text\n{\nbackground: #E5E5E5;\nmargin-left: 5px; margin-top: 0px;\n"
132   "text-align: left;\n\nwidth: 100px;\npadding: 0px;\ncolor: #000000;\n"
133   "text-decoration: none;\nfont-family: verdana;\nfont-size: 12px;\n" "border: 1px solid #ccc;\n}\n"
134   ".input_button\n{\nbackground: #B5D1EE;\nmargin-left: 5px;\nmargin-top: 0px;\n"
135   "text-align: center;\nwidth: 120px;\npadding: 0px;\ncolor: #000000;\n"
136   "text-decoration: none;\nfont-family: verdana;\nfont-size: 12px;\n" "border: 1px solid #000;\n}\n";
137
138 typedef void (*build_body_callback) (struct autobuf *);
139
140 struct tab_entry {
141   const char *tab_label;
142   const char *filename;
143   build_body_callback build_body_cb;
144   bool display_tab;
145 };
146
147 struct static_bin_file_entry {
148   const char *filename;
149   unsigned char *data;
150   unsigned int data_size;
151 };
152
153 struct static_txt_file_entry {
154   const char *filename;
155   const char *data;
156 };
157
158 struct dynamic_file_entry {
159   const char *filename;
160   int (*process_data_cb) (char *, uint32_t, char *, uint32_t);
161 };
162
163 static int get_http_socket(int);
164
165 static void build_tabs(struct autobuf *, int);
166
167 static void parse_http_request(int fd, void *, unsigned int);
168
169 static int build_http_header(http_header_type, bool, uint32_t, char *, uint32_t);
170
171 static void build_frame(struct autobuf *, const char *, const char *, int, build_body_callback frame_body_cb);
172
173 static void build_routes_body(struct autobuf *);
174
175 static void build_config_body(struct autobuf *);
176
177 static void build_neigh_body(struct autobuf *);
178
179 static void build_topo_body(struct autobuf *);
180
181 static void build_mid_body(struct autobuf *);
182
183 static void build_nodes_body(struct autobuf *);
184
185 static void build_all_body(struct autobuf *);
186
187 #ifdef HTTPINFO_PUD
188 static void build_pud_body(struct autobuf *);
189 #endif /* HTTPINFO_PUD */
190
191 static void build_about_body(struct autobuf *);
192
193 static void build_cfgfile_body(struct autobuf *);
194
195 static int check_allowed_ip(const struct allowed_net *const /*allowed_nets*/, const union olsr_ip_addr *const /*addr*/);
196
197 static void build_ip_txt(struct autobuf *, const bool want_link, const char *const ipaddrstr, const int prefix_len);
198
199 static void build_ipaddr_link(struct autobuf *, const bool want_link, const union olsr_ip_addr *const ipaddr,
200                              const int prefix_len);
201 static void section_title(struct autobuf *, const char *title);
202
203 static void httpinfo_write_data(void *foo);
204
205 static struct timeval start_time;
206 static struct http_stats stats;
207 static int http_socket;
208
209 static char *outbuffer[MAX_CLIENTS];
210 static size_t outbuffer_size[MAX_CLIENTS];
211 static size_t outbuffer_written[MAX_CLIENTS];
212 static int outbuffer_socket[MAX_CLIENTS];
213 static int outbuffer_count;
214
215 static struct timer_entry *writetimer_entry;
216
217 static const struct tab_entry tab_entries[] = {
218   {"Configuration", "config", build_config_body, true},
219   {"Routes", "routes", build_routes_body, true},
220   {"Links/Topology", "nodes", build_nodes_body, true},
221 #ifdef HTTPINFO_PUD
222   {"Position", "position", build_pud_body, true},
223 #endif /* HTTPINFO_PUD */
224   {"All", "all", build_all_body, true},
225 #ifdef ADMIN_INTERFACE
226   {"Admin", "admin", build_admin_body, true},
227 #endif /* ADMIN_INTERFACE */
228   {"About", "about", build_about_body, true},
229   {"FOO", "cfgfile", build_cfgfile_body, false},
230   {NULL, NULL, NULL, false}
231 };
232
233 static const struct static_bin_file_entry static_bin_files[] = {
234   {"favicon.ico", favicon_ico, sizeof(favicon_ico)}
235   ,
236   {"logo.gif", logo_gif, sizeof(logo_gif)}
237   ,
238   {"grayline.gif", grayline_gif, sizeof(grayline_gif)}
239   ,
240   {NULL, NULL, 0}
241 };
242
243 static const struct static_txt_file_entry static_txt_files[] = {
244   {"httpinfo.css", httpinfo_css},
245   {NULL, NULL}
246 };
247
248 #ifdef ADMIN_INTERFACE
249 static const struct dynamic_file_entry dynamic_files[] = {
250   {"set_values", process_set_values},
251   {NULL, NULL}
252 };
253 #endif /* ADMIN_INTERFACE */
254
255 static int
256 get_http_socket(int port)
257 {
258   struct sockaddr_in sock_in;
259   uint32_t yes = 1;
260
261   /* Init ipc socket */
262   int s = socket(AF_INET, SOCK_STREAM, 0);
263   if (s == -1) {
264     olsr_printf(1, "(HTTPINFO)socket %s\n", strerror(errno));
265     return -1;
266   }
267
268   if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
269     olsr_printf(1, "(HTTPINFO)SO_REUSEADDR failed %s\n", strerror(errno));
270     close(s);
271     return -1;
272   }
273
274   /* Bind the socket */
275
276   /* complete the socket structure */
277   memset(&sock_in, 0, sizeof(sock_in));
278   sock_in.sin_family = AF_INET;
279   sock_in.sin_addr.s_addr = httpinfo_listen_ip.v4.s_addr;
280   sock_in.sin_port = htons(port);
281
282   /* bind the socket to the port number */
283   if (bind(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) == -1) {
284     olsr_printf(1, "(HTTPINFO) bind failed %s\n", strerror(errno));
285     close(s);
286     return -1;
287   }
288
289   /* show that we are willing to listen */
290   if (listen(s, 1) == -1) {
291     olsr_printf(1, "(HTTPINFO) listen failed %s\n", strerror(errno));
292     close(s);
293     return -1;
294   }
295
296   return s;
297 }
298
299 /**
300  *Do initialization here
301  *
302  *This function is called by the my_init
303  *function in uolsrd_plugin.c
304  */
305 int
306 olsrd_plugin_init(void)
307 {
308   /* Get start time */
309   gettimeofday(&start_time, NULL);
310
311   /* set up HTTP socket */
312   http_socket = get_http_socket(http_port != 0 ? http_port : DEFAULT_TCP_PORT);
313
314   if (http_socket < 0) {
315     fprintf(stderr, "(HTTPINFO) could not initialize HTTP socket\n");
316     exit(1);
317   }
318
319   /* Register socket */
320   add_olsr_socket(http_socket, &parse_http_request, NULL, NULL, SP_PR_READ);
321
322   return 1;
323 }
324
325 /* Non reentrant - but we are not multithreaded anyway */
326 static void
327 parse_http_request(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
328 {
329   struct sockaddr_in pin;
330   struct autobuf body_abuf = { 0, 0, NULL };
331   socklen_t addrlen;
332   char header_buf[MAX_HTTPREQ_SIZE];
333   char req_type[11];
334   char filename[251];
335   char http_version[11];
336   int client_socket;
337   size_t header_length = 0;
338   size_t c = 0;
339   int r = 1;
340 #ifdef __linux__
341   struct timeval timeout = { 0, 200 };
342 #endif /* __linux__ */
343
344   if (outbuffer_count >= MAX_CLIENTS) {
345     olsr_printf(1, "(HTTPINFO) maximum number of connection reached\n");
346     return;
347   }
348
349   addrlen = sizeof(struct sockaddr_in);
350   client_socket = accept(fd, (struct sockaddr *)&pin, &addrlen);
351   if (client_socket == -1) {
352     olsr_printf(1, "(HTTPINFO) accept: %s\n", strerror(errno));
353     goto close_connection;
354   }
355
356 #ifdef __linux__
357   if (setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
358     olsr_printf(1, "(HTTPINFO)SO_RCVTIMEO failed %s\n", strerror(errno));
359     goto close_connection;
360   }
361
362   if (setsockopt(client_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
363     olsr_printf(1, "(HTTPINFO)SO_SNDTIMEO failed %s\n", strerror(errno));
364     goto close_connection;
365   }
366 #endif /* __linux__ */
367   if (!check_allowed_ip(allowed_nets, (union olsr_ip_addr *)&pin.sin_addr.s_addr)) {
368     struct ipaddr_str strbuf;
369     olsr_printf(0, "HTTP request from non-allowed host %s!\n",
370                 olsr_ip_to_string(&strbuf, (union olsr_ip_addr *)&pin.sin_addr.s_addr));
371     goto close_connection;
372   }
373
374   memset(header_buf, 0, sizeof(header_buf));
375
376   while ((r = recv(client_socket, &header_buf[c], 1, 0)) > 0 && (c < sizeof(header_buf) - 1)) {
377     c++;
378
379     if ((c > 3 && !strcmp(&header_buf[c - 4], "\r\n\r\n")) || (c > 1 && !strcmp(&header_buf[c - 2], "\n\n")))
380       break;
381   }
382
383   if (r < 0) {
384     olsr_printf(1, "(HTTPINFO) Failed to receive data from client!\n");
385     stats.err_hits++;
386     goto close_connection;
387   }
388
389   /* Get the request */
390   if (sscanf(header_buf, "%10s %250s %10s\n", req_type, filename, http_version) != 3) {
391     /* Try without HTTP version */
392     if (sscanf(header_buf, "%10s %250s\n", req_type, filename) != 2) {
393       olsr_printf(1, "(HTTPINFO) Error parsing request %s!\n", header_buf);
394       stats.err_hits++;
395       goto close_connection;
396     }
397   }
398
399   olsr_printf(1, "Request: %s\nfile: %s\nVersion: %s\n\n", req_type, filename, http_version);
400   abuf_init(&body_abuf, 102400);
401
402   if (!strcmp(req_type, "POST")) {
403 #ifdef ADMIN_INTERFACE
404     int i = 0;
405     while (dynamic_files[i].filename) {
406       printf("POST checking %s\n", dynamic_files[i].filename);
407       if (FILENREQ_MATCH(filename, dynamic_files[i].filename)) {
408         uint32_t param_size;
409
410         stats.ok_hits++;
411
412         param_size = recv(client_sockets[curr_clients], header_buf, sizeof(header_buf) - 1, 0);
413
414         header_buf[param_size] = '\0';
415         printf("Dynamic read %d bytes\n", param_size);
416
417         //memcpy(body, dynamic_files[i].data, static_bin_files[i].data_size);
418         body_length += dynamic_files[i].process_data_cb(header_buf, param_size, &body_buf[body_length], sizeof(body_buf) - body_length);
419         header_length = build_http_header(HTTP_OK, true, body_length, header_buf, sizeof(header_buf));
420         goto send_http_data;
421       }
422       i++;
423     }
424 #endif /* ADMIN_INTERFACE */
425     /* We only support GET */
426     abuf_puts(&body_abuf, HTTP_400_MSG);
427     stats.ill_hits++;
428     header_length = build_http_header(HTTP_BAD_REQ, true, body_abuf.len, header_buf, sizeof(header_buf));
429   } else if (!strcmp(req_type, "GET")) {
430     int i = 0;
431
432     for (i = 0; static_bin_files[i].filename; i++) {
433       if (FILENREQ_MATCH(filename, static_bin_files[i].filename)) {
434         break;
435       }
436     }
437
438     if (static_bin_files[i].filename) {
439       stats.ok_hits++;
440       abuf_memcpy(&body_abuf, static_bin_files[i].data, static_bin_files[i].data_size);
441       header_length = build_http_header(HTTP_OK, false, body_abuf.len, header_buf, sizeof(header_buf));
442       goto send_http_data;
443     }
444
445     i = 0;
446     while (static_txt_files[i].filename) {
447       if (FILENREQ_MATCH(filename, static_txt_files[i].filename)) {
448         break;
449       }
450       i++;
451     }
452
453     if (static_txt_files[i].filename) {
454       stats.ok_hits++;
455       abuf_puts(&body_abuf, static_txt_files[i].data);
456       header_length = build_http_header(HTTP_OK, false, body_abuf.len, header_buf, sizeof(header_buf));
457       goto send_http_data;
458     }
459
460     i = 0;
461     if (strlen(filename) > 1) {
462       while (tab_entries[i].filename) {
463         if (FILENREQ_MATCH(filename, tab_entries[i].filename)) {
464           break;
465         }
466         i++;
467       }
468     }
469
470     if (tab_entries[i].filename) {
471 #ifdef NETDIRECT
472       header_length = build_http_header(HTTP_OK, true, body_length, header_buf, sizeof(header_buf));
473       r = send(client_sockets[curr_clients], header_buf, header_length, 0);
474       if (r < 0) {
475         olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
476         goto close_connection;
477       }
478       netsprintf_error = 0;
479       netsprintf_direct = 1;
480 #endif /* NETDIRECT */
481       abuf_appendf(&body_abuf,
482                  "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" "<head>\n"
483                  "<meta http-equiv=\"Content-type\" content=\"text/html; charset=ISO-8859-1\">\n"
484                  "<title>olsr.org httpinfo plugin</title>\n" "<link rel=\"icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
485                  "<link rel=\"shortcut icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
486                  "<link rel=\"stylesheet\" type=\"text/css\" href=\"httpinfo.css\">\n" "</head>\n"
487                  "<body bgcolor=\"#ffffff\" text=\"#000000\">\n"
488                  "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
489                  "<tbody><tr bgcolor=\"#ffffff\">\n" "<td align=\"left\" height=\"69\" valign=\"middle\" width=\"80%%\">\n"
490                  "<font color=\"black\" face=\"timesroman\" size=\"6\">&nbsp;&nbsp;&nbsp;<a href=\"http://www.olsr.org/\">olsr.org OLSR daemon</a></font></td>\n"
491                  "<td height=\"69\" valign=\"middle\" width=\"20%%\">\n"
492                  "<a href=\"http://www.olsr.org/\"><img border=\"0\" src=\"/logo.gif\" alt=\"olsrd logo\"></a></td>\n" "</tr>\n"
493                  "</tbody>\n" "</table>\n", FRAMEWIDTH);
494
495       build_tabs(&body_abuf, i);
496       build_frame(&body_abuf, "Current Routes", "routes", FRAMEWIDTH, tab_entries[i].build_body_cb);
497
498       stats.ok_hits++;
499
500       abuf_appendf(&body_abuf,
501                  "</table>\n" "<div id=\"footer\">\n" "<center>\n" "(C)2005 Andreas T&oslash;nnesen<br/>\n"
502                  "<a href=\"http://www.olsr.org/\">http://www.olsr.org</a>\n" "</center>\n" "</div>\n" "</body>\n" "</html>\n");
503
504 #ifdef NETDIRECT
505       netsprintf_direct = 1;
506       goto close_connection;
507 #else /* NETDIRECT */
508       header_length = build_http_header(HTTP_OK, true, body_abuf.len, header_buf, sizeof(header_buf));
509       goto send_http_data;
510 #endif /* NETDIRECT */
511     }
512
513     stats.ill_hits++;
514     abuf_puts(&body_abuf, HTTP_404_MSG);
515     header_length = build_http_header(HTTP_BAD_FILE, true, body_abuf.len, header_buf, sizeof(header_buf));
516   } else {
517     /* We only support GET */
518     abuf_puts(&body_abuf, HTTP_404_MSG);
519     stats.ill_hits++;
520     header_length = build_http_header(HTTP_BAD_REQ, true, body_abuf.len, header_buf, sizeof(header_buf));
521   }
522
523 send_http_data:
524   if (header_length + body_abuf.len > 0) {
525     outbuffer[outbuffer_count] = olsr_malloc(header_length + body_abuf.len, "http output buffer");
526     outbuffer_size[outbuffer_count] = header_length + body_abuf.len;
527     outbuffer_written[outbuffer_count] = 0;
528     outbuffer_socket[outbuffer_count] = client_socket;
529
530     memcpy(outbuffer[outbuffer_count], header_buf, header_length);
531     if (body_abuf.len > 0) {
532       memcpy((outbuffer[outbuffer_count]) + header_length, body_abuf.buf, body_abuf.len);
533     }
534     outbuffer_count++;
535
536     if (outbuffer_count == 1) {
537       writetimer_entry = olsr_start_timer(100, 0, OLSR_TIMER_PERIODIC, &httpinfo_write_data, NULL, 0);
538     }
539   }
540   abuf_free(&body_abuf);
541   /*
542    * client_socket is stored in outbuffer_socket[outbuffer_count] and closed
543    * by the httpinfo_write_data timer callback, so don't close it here
544    */
545   return;
546
547 close_connection:
548   abuf_free(&body_abuf);
549   if (client_socket >= 0) {
550     close(client_socket);
551   }
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((const void *)ipaddr, olsr_cnf->ipsize,
745                                          olsr_cnf->ip_version) :
746 #endif /* _WIN32 */
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 #ifdef HTTPINFO_PUD
1102   build_pud_body(abuf);
1103 #endif /* HTTPINFO_PUD */
1104 }
1105
1106 #ifdef HTTPINFO_PUD
1107 /**
1108  * Determine if a nmeaINFO structure has a certain field.
1109  * We need this function locally because nmealib might not be loaded.
1110  *
1111  * @param present the presence field
1112  * @param fieldName use a name from nmeaINFO_FIELD
1113  * @return a boolean, true when the structure has the requested field
1114  */
1115 static inline bool nmea_INFO_has_field_local(uint32_t present, nmeaINFO_FIELD fieldName) {
1116         return ((present & fieldName) != 0);
1117 }
1118
1119 static const char * NA_STRING = "N.A.";
1120 static const char * SAT_INUSE_COLOR = "lime";
1121 static const char * SAT_NOTINUSE_COLOR = "red";
1122
1123 static void build_pud_body(struct autobuf *abuf) {
1124         TransmitGpsInformation * txGpsInfo = olsr_cnf->pud_position;
1125         char * nodeId;
1126         char nodeIdString[256];
1127         bool datePresent;
1128         bool timePresent;
1129
1130         abuf_puts(abuf, "<h2>Position</h2>");
1131
1132         if (!txGpsInfo) {
1133                 abuf_puts(abuf, "<p><b>" PUD_PLUGIN_ABBR " plugin not loaded</b></p>\n");
1134                 return;
1135         }
1136
1137         nodeId = (char *) txGpsInfo->nodeId;
1138
1139         if (!nodeId || !strlen(nodeId)) {
1140                 inet_ntop(olsr_cnf->ip_version, &olsr_cnf->main_addr, &nodeIdString[0], sizeof(nodeIdString));
1141                 nodeId = nodeIdString;
1142         }
1143
1144         /* start of table */
1145         abuf_puts(abuf,
1146                 "<p><table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"
1147                 "<tr><th>Parameter</th><th>&nbsp;&nbsp;</th><th>Unit</th><th>&nbsp;&nbsp;</th><th>Value</th></tr>\n"
1148         );
1149
1150         /* nodeId */
1151         abuf_appendf(abuf,
1152                 "<tr><td>Name</td><td></td><td></td><td></td><td id=\"nodeId\">%s</td></tr>\n",
1153                 nodeId
1154         );
1155
1156         /* utc */
1157         abuf_puts(abuf, "<tr><td>Date / Time</td><td></td><td>UTC</td><td></td><td id=\"utc\">");
1158         datePresent = nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, UTCDATE);
1159         timePresent = nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, UTCTIME);
1160         if (datePresent || timePresent) {
1161                 if (datePresent) {
1162                         abuf_appendf(abuf, "%04d%02d%02d",
1163                                 txGpsInfo->txPosition.nmeaInfo.utc.year + 1900,
1164                                 txGpsInfo->txPosition.nmeaInfo.utc.mon,
1165                                 txGpsInfo->txPosition.nmeaInfo.utc.day);
1166                 }
1167                 if (datePresent && timePresent) {
1168                         abuf_puts(abuf, " ");
1169                 }
1170                 if (timePresent) {
1171                         abuf_appendf(abuf, "%02d:%02d:%02d.%02d",
1172                                 txGpsInfo->txPosition.nmeaInfo.utc.hour,
1173                                 txGpsInfo->txPosition.nmeaInfo.utc.min,
1174                                 txGpsInfo->txPosition.nmeaInfo.utc.sec,
1175                                 txGpsInfo->txPosition.nmeaInfo.utc.hsec);
1176                 }
1177         } else {
1178                 abuf_puts(abuf, NA_STRING);
1179         }
1180         abuf_puts(abuf, "</td></tr>\n");
1181
1182         /* smask */
1183         abuf_puts(abuf, "<tr><td>Input Sentences</td><td></td><td></td><td></td><td id=\"smask\">");
1184         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SMASK)
1185                         && (txGpsInfo->txPosition.nmeaInfo.smask != GPNON)) {
1186                 const int id[] = { GPGGA, GPGSA, GPGSV, GPRMC, GPVTG, GPNON };
1187                 const char * ids[] = { "GPGGA", "GPGSA", "GPGSV", "GPRMC", "GPVTG" };
1188                 bool printed = false;
1189                 int i = 0;
1190
1191                 while (id[i] != GPNON) {
1192                         if (txGpsInfo->txPosition.nmeaInfo.smask & id[i]) {
1193                                 if (printed)
1194                                         abuf_puts(abuf, "&nbsp;");
1195                                 abuf_puts(abuf, ids[i]);
1196                                 printed = true;
1197                         }
1198                         i++;
1199                 }
1200         } else {
1201                 abuf_puts(abuf, NA_STRING);
1202         }
1203         abuf_puts(abuf, "</td></tr>\n");
1204
1205         /* sig */
1206         abuf_puts(abuf, "<tr><td>Signal Strength</td><td></td><td></td><td></td><td id=\"sig\">");
1207         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SIG)) {
1208                 const char * s;
1209                 switch (txGpsInfo->txPosition.nmeaInfo.sig) {
1210                         case NMEA_SIG_BAD:
1211                                 s = "Invalid";
1212                                 break;
1213                         case NMEA_SIG_LOW:
1214                                 s = "Fix";
1215                                 break;
1216                         case NMEA_SIG_MID:
1217                                 s = "Differential";
1218                                 break;
1219                         case NMEA_SIG_HIGH:
1220                                 s = "Sensitive";
1221                                 break;
1222                         case NMEA_SIG_RTKIN:
1223                                 s = "Real Time Kinematic";
1224                                 break;
1225                         case NMEA_SIG_FLRTK:
1226                                 s = "Float RTK";
1227                                 break;
1228                         case NMEA_SIG_ESTIM:
1229                                 s = "Estimated (Dead Reckoning)";
1230                                 break;
1231                         case NMEA_SIG_MAN:
1232                                 s = "Manual Input Mode";
1233                                 break;
1234                         case NMEA_SIG_SIM:
1235                                 s = "Simulation Mode";
1236                                 break;
1237                         default:
1238                                 s = "Unknown";
1239                                 break;
1240                 }
1241                 abuf_appendf(abuf, "%s (%d)", s, txGpsInfo->txPosition.nmeaInfo.sig);
1242         } else {
1243                 abuf_puts(abuf, NA_STRING);
1244         }
1245         abuf_puts(abuf, "</td></tr>\n");
1246
1247         /* fix */
1248         abuf_puts(abuf, "<tr><td>Fix</td><td></td><td></td><td></td><td id=\"fix\">");
1249         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, FIX)) {
1250                 const char * s;
1251                 switch (txGpsInfo->txPosition.nmeaInfo.fix) {
1252                         case NMEA_FIX_BAD:
1253                                 s = "BAD";
1254                                 break;
1255                         case NMEA_FIX_2D:
1256                                 s = "2D";
1257                                 break;
1258                         case NMEA_FIX_3D:
1259                                 s = "3D";
1260                                 break;
1261                         default:
1262                                 s = "Unknown";
1263                                 break;
1264                 }
1265                 abuf_appendf(abuf, "%s (%d)", s, txGpsInfo->txPosition.nmeaInfo.fix);
1266         } else {
1267                 abuf_puts(abuf, NA_STRING);
1268         }
1269         abuf_puts(abuf, "</td></tr>\n");
1270
1271         /* PDOP */
1272         abuf_puts(abuf, "<tr><td>PDOP</td><td></td><td></td><td></td><td id=\"pdop\">");
1273         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, PDOP)) {
1274                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.PDOP);
1275         } else {
1276                 abuf_puts(abuf, NA_STRING);
1277         }
1278         abuf_puts(abuf, "</td></tr>\n");
1279
1280         /* HDOP */
1281         abuf_puts(abuf, "<tr><td>HDOP</td><td></td><td></td><td></td><td id=\"hdop\">");
1282         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, HDOP)) {
1283                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.HDOP);
1284         } else {
1285                 abuf_puts(abuf, NA_STRING);
1286         }
1287         abuf_puts(abuf, "</td></tr>\n");
1288
1289         /* VDOP */
1290         abuf_puts(abuf, "<tr><td>VDOP</td><td></td><td></td><td></td><td id=\"vdop\">");
1291         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, VDOP)) {
1292                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.VDOP);
1293         } else {
1294                 abuf_puts(abuf, NA_STRING);
1295         }
1296         abuf_puts(abuf, "</td></tr>\n");
1297
1298         /* lat */
1299         abuf_puts(abuf, "<tr><td>Latitude</td><td></td><td>degrees</td><td></td><td id=\"lat\">");
1300         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, LAT)) {
1301                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.lat);
1302         } else {
1303                 abuf_puts(abuf, NA_STRING);
1304         }
1305         abuf_puts(abuf, "</td></tr>\n");
1306
1307         /* lon */
1308         abuf_puts(abuf, "<tr><td>Longitude</td><td></td><td>degrees</td><td></td><td id=\"lon\">");
1309         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, LON)) {
1310                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.lon);
1311         } else {
1312                 abuf_puts(abuf, NA_STRING);
1313         }
1314         abuf_puts(abuf, "</td></tr>\n");
1315
1316         /* elv */
1317         abuf_puts(abuf, "<tr><td>Elevation</td><td></td><td>m</td><td></td><td id=\"elv\">");
1318         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, ELV)) {
1319                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.elv);
1320         } else {
1321                 abuf_puts(abuf, NA_STRING);
1322         }
1323         abuf_puts(abuf, "</td></tr>\n");
1324
1325         /* speed */
1326         abuf_puts(abuf, "<tr><td>Speed</td><td></td><td>kph</td><td></td><td id=\"speed\">");
1327         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SPEED)) {
1328                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.speed);
1329         } else {
1330                 abuf_puts(abuf, NA_STRING);
1331         }
1332         abuf_puts(abuf, "</td></tr>\n");
1333
1334         /* track */
1335         abuf_puts(abuf, "<tr><td>Track</td><td></td><td>degrees</td><td></td><td id=\"track\">");
1336         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, TRACK)) {
1337                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.track);
1338         } else {
1339                 abuf_puts(abuf, NA_STRING);
1340         }
1341         abuf_puts(abuf, "</td></tr>\n");
1342
1343         /* mtrack */
1344         abuf_puts(abuf, "<tr><td>Magnetic Track</td><td></td><td>degrees</td><td></td><td id=\"mtrack\">");
1345         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, MTRACK)) {
1346                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.mtrack);
1347         } else {
1348                 abuf_puts(abuf, NA_STRING);
1349         }
1350         abuf_puts(abuf, "</td></tr>\n");
1351
1352         /* magvar */
1353         abuf_puts(abuf, "<tr><td>Magnetic Variation</td><td></td><td>degrees</td><td></td><td id=\"magvar\">");
1354         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, MAGVAR)) {
1355                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.magvar);
1356         } else {
1357                 abuf_puts(abuf, NA_STRING);
1358         }
1359         abuf_puts(abuf, "</td></tr>\n");
1360
1361         /* end of table */
1362         abuf_puts(abuf, "</table></p>\n");
1363
1364         /* sats */
1365         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SATINVIEW)) {
1366                 int cnt = 0;
1367
1368                 abuf_puts(abuf, "<p>\n");
1369                 abuf_puts(abuf, "Satellite Infomation:\n");
1370                 abuf_puts(abuf, "<table border=\"1\" cellpadding=\"2\" cellspacing=\"0\" id=\"satinfo\">\n");
1371                 abuf_puts(abuf, "<tbody align=\"center\">\n");
1372                 abuf_puts(abuf,
1373                                 "<tr><th>ID</th><th>In Use</th><th>Elevation (degrees)</th><th>Azimuth (degrees)</th><th>Signal (dB)</th></tr>\n");
1374
1375                 if (txGpsInfo->txPosition.nmeaInfo.satinfo.inview) {
1376                         int satIndex;
1377                         for (satIndex = 0; satIndex < NMEA_MAXSAT; satIndex++) {
1378                                 nmeaSATELLITE * sat = &txGpsInfo->txPosition.nmeaInfo.satinfo.sat[satIndex];
1379                                 if (sat->id) {
1380                                         bool inuse = false;
1381                                         const char * inuseStr;
1382
1383                                         if (!nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SATINUSE)) {
1384                                                 inuseStr = NA_STRING;
1385                                         } else {
1386                                                 int inuseIndex;
1387                                                 for (inuseIndex = 0; inuseIndex < NMEA_MAXSAT; inuseIndex++) {
1388                                                         if (txGpsInfo->txPosition.nmeaInfo.satinfo.in_use[inuseIndex] == sat->id) {
1389                                                                 inuse = true;
1390                                                                 break;
1391                                                         }
1392                                                 }
1393                                                 if (inuse) {
1394                                                         inuseStr = "yes";
1395                                                 } else {
1396                                                         inuseStr = "no";
1397                                                 }
1398                                         }
1399
1400                                         abuf_appendf(abuf, "<tr><td>%02d</td><td bgcolor=\"%s\">%s</td><td>%02d</td><td>%03d</td><td>%02d</td></tr>\n",
1401                                                         sat->id, inuse ? SAT_INUSE_COLOR : SAT_NOTINUSE_COLOR, inuseStr, sat->elv, sat->azimuth, sat->sig);
1402                                         cnt++;
1403                                 }
1404                         }
1405                 }
1406
1407                 if (!cnt) {
1408                         abuf_puts(abuf, "<tr><td colspan=\"5\">none</td></tr>\n");
1409                 }
1410
1411                 abuf_puts(abuf, "</tbody></table>\n");
1412                 abuf_puts(abuf, "</p>\n");
1413         }
1414
1415         /* add Google Maps and OpenStreetMap links when we have both lat and lon */
1416         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, LAT)
1417                         && nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, LON)) {
1418                 const char * c = nodeId;
1419
1420                 abuf_appendf(abuf,
1421                         "<p>\n"
1422                         "<a href=\"http://maps.google.com/maps?q=%f,+%f+%%28",
1423                         txGpsInfo->txPosition.nmeaInfo.lat,
1424                         txGpsInfo->txPosition.nmeaInfo.lon
1425                 );
1426
1427                 while (*c != '\0') {
1428                         if (*c == ' ' || *c == '\t') {
1429                                 abuf_puts(abuf, "+");
1430                         } else {
1431                                 abuf_appendf(abuf, "%c", *c);
1432                         }
1433                         c++;
1434                 }
1435
1436                 abuf_puts(abuf, "%29&amp;iwloc=A\">Show on Google Maps</a></p>\n");
1437
1438                 abuf_appendf(abuf,
1439                         "<p>\n"
1440                         "<a href=\"http://www.openstreetmap.org/index.html?mlat=%f&amp;mlon=%f&amp;zoom=15&amp;layers=M\">Show on OpenStreetMap</a></p>\n",
1441                         txGpsInfo->txPosition.nmeaInfo.lat,
1442                         txGpsInfo->txPosition.nmeaInfo.lon
1443                 );
1444         }
1445 }
1446 #endif /* HTTPINFO_PUD */
1447
1448 static void
1449 build_about_body(struct autobuf *abuf)
1450 {
1451   abuf_appendf(abuf,
1452                   "<strong>" PLUGIN_NAME " version " PLUGIN_VERSION "</strong><br/>\n" "by Andreas T&oslash;nnesen (C)2005.<br/>\n"
1453                   "Compiled "
1454 #ifdef ADMIN_INTERFACE
1455                   "<em>with experimental admin interface</em> "
1456 #endif /* ADMIN_INTERFACE */
1457                   "%s at %s<hr/>\n" "This plugin implements a HTTP server that supplies\n"
1458                   "the client with various dynamic web pages representing\n"
1459                   "the current olsrd status.<br/>The different pages include:\n"
1460                   "<ul>\n<li><strong>Configuration</strong> - This page displays information\n"
1461                   "about the current olsrd configuration. This includes various\n"
1462                   "olsr settings such as IP version, MID/TC redundancy, hysteresis\n"
1463                   "etc. Information about the current status of the interfaces on\n"
1464                   "which olsrd is configured to run is also displayed. Loaded olsrd\n"
1465                   "plugins are shown with their plugin parameters. Finally all local\n"
1466                   "HNA entries are shown. These are the networks that the local host\n"
1467                   "will anounce itself as a gateway to.</li>\n"
1468                   "<li><strong>Routes</strong> - This page displays all routes currently set in\n"
1469                   "the kernel <em>by olsrd</em>. The type of route is also displayed(host\n" "or HNA).</li>\n"
1470                   "<li><strong>Links/Topology</strong> - This page displays all information about\n"
1471                   "links, neighbors, topology, MID and HNA entries.</li>\n"
1472                   "<li><strong>All</strong> - Here all the previous pages are displayed as one.\n"
1473                   "This is to make all information available as easy as possible(for example\n"
1474                   "for a script) and using as few resources as possible.</li>\n"
1475 #ifdef ADMIN_INTERFACE
1476                   "<li><strong>Admin</strong> - This page is highly experimental(and unsecure)!\n"
1477                   "As of now it is not working at all but it provides a impression of\n"
1478                   "the future possibilities of httpinfo. This is to be a interface to\n"
1479                   "changing olsrd settings in realtime. These settings include various\n"
1480                   "\"basic\" settings and local HNA settings.</li>\n"
1481 #endif /* ADMIN_INTERFACE */
1482                   "<li><strong>About</strong> - this help page.</li>\n</ul>" "<hr/>\n" "Send questions or comments to\n"
1483                   "<a href=\"mailto:olsr-users@olsr.org\">olsr-users@olsr.org</a> or\n"
1484                   "<a href=\"mailto:andreto-at-olsr.org\">andreto-at-olsr.org</a><br/>\n"
1485                   "Official olsrd homepage: <a href=\"http://www.olsr.org/\">http://www.olsr.org</a><br/>\n", build_date,
1486                   build_host);
1487 }
1488
1489 static void
1490 build_cfgfile_body(struct autobuf *abuf)
1491 {
1492   abuf_puts(abuf,
1493              "\n\n" "<strong>This is a automatically generated configuration\n"
1494              "file based on the current olsrd configuration of this node.<br/>\n" "<hr/>\n" "<pre>\n");
1495   olsrd_write_cnf_autobuf(abuf, olsr_cnf);
1496
1497   abuf_puts(abuf, "</pre>\n<hr/>\n");
1498 }
1499
1500 static int
1501 check_allowed_ip(const struct allowed_net *const my_allowed_nets, const union olsr_ip_addr *const addr)
1502 {
1503   const struct allowed_net *alln;
1504   for (alln = my_allowed_nets; alln != NULL; alln = alln->next) {
1505     if (ip_in_net(addr, &alln->prefix)) {
1506       return 1;
1507     }
1508   }
1509   return 0;
1510 }
1511
1512 /*
1513  * Local Variables:
1514  * c-basic-offset: 2
1515  * indent-tabs-mode: nil
1516  * End:
1517  */