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