76671c7cacaf4d7d828a62db2e18b384eef00b11
[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(0);
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   return;
542
543 close_connection:
544   abuf_free(&body_abuf);
545   close(client_socket);
546 }
547
548 static void
549 httpinfo_write_data(void *foo __attribute__ ((unused))) {
550   fd_set set;
551   int result, i, j, max;
552   struct timeval tv;
553
554   FD_ZERO(&set);
555   max = 0;
556   for (i=0; i<outbuffer_count; i++) {
557     /* prevent warning in win32 */
558     FD_SET((unsigned int)outbuffer_socket[i], &set);
559     if (outbuffer_socket[i] > max) {
560       max = outbuffer_socket[i];
561     }
562   }
563
564   tv.tv_sec = 0;
565   tv.tv_usec = 0;
566
567   result = select(max + 1, NULL, &set, NULL, &tv);
568   if (result <= 0) {
569     return;
570   }
571
572   for (i=0; i<outbuffer_count; i++) {
573     if (FD_ISSET(outbuffer_socket[i], &set)) {
574       result = write(outbuffer_socket[i], outbuffer[i] + outbuffer_written[i], outbuffer_size[i] - outbuffer_written[i]);
575       if (result > 0) {
576         outbuffer_written[i] += result;
577       }
578
579       if (result <= 0 || outbuffer_written[i] == outbuffer_size[i]) {
580         /* close this socket and cleanup*/
581         close(outbuffer_socket[i]);
582         free (outbuffer[i]);
583
584         for (j=i+1; j<outbuffer_count; j++) {
585           outbuffer[j-1] = outbuffer[j];
586           outbuffer_size[j-1] = outbuffer_size[j];
587           outbuffer_socket[j-1] = outbuffer_socket[j];
588           outbuffer_written[j-1] = outbuffer_written[j];
589         }
590         outbuffer_count--;
591       }
592     }
593   }
594   if (outbuffer_count == 0) {
595     olsr_stop_timer(writetimer_entry);
596   }
597 }
598
599 int
600 build_http_header(http_header_type type, bool is_html, uint32_t msgsize, char *buf, uint32_t bufsize)
601 {
602   time_t currtime;
603   const char *h;
604   int size;
605
606   switch (type) {
607   case HTTP_BAD_REQ:
608     h = HTTP_400;
609     break;
610   case HTTP_BAD_FILE:
611     h = HTTP_404;
612     break;
613   default:
614     /* Defaults to OK */
615     h = HTTP_200;
616     break;
617   }
618   size = snprintf(buf, bufsize, "%s", h);
619
620   /* Date */
621   time(&currtime);
622   size += strftime(&buf[size], bufsize - size, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", localtime(&currtime));
623
624   /* Server version */
625   size += snprintf(&buf[size], bufsize - size, "Server: %s %s %s\r\n", PLUGIN_NAME, PLUGIN_VERSION, HTTP_VERSION);
626
627   /* connection-type */
628   size += snprintf(&buf[size], bufsize - size, "Connection: closed\r\n");
629
630   /* MIME type */
631   size += snprintf(&buf[size], bufsize - size, "Content-type: text/%s\r\n", is_html ? "html" : "plain");
632
633   /* Content length */
634   if (msgsize > 0) {
635     size += snprintf(&buf[size], bufsize - size, "Content-length: %i\r\n", msgsize);
636   }
637
638   /* Cache-control
639    * No caching dynamic pages
640    */
641   size += snprintf(&buf[size], bufsize - size, "Cache-Control: no-cache\r\n");
642
643   if (!is_html) {
644     size += snprintf(&buf[size], bufsize - size, "Accept-Ranges: bytes\r\n");
645   }
646   /* End header */
647   size += snprintf(&buf[size], bufsize - size, "\r\n");
648
649   olsr_printf(1, "HEADER:\n%s", buf);
650
651   return size;
652 }
653
654 static void
655 build_tabs(struct autobuf *abuf, int active)
656 {
657   int tabs = 0;
658
659   abuf_appendf(abuf,
660       "<table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
661       "<tr bgcolor=\"#ffffff\"><td>\n" "<ul id=\"tabnav\">\n", FRAMEWIDTH);
662   for (tabs = 0; tab_entries[tabs].tab_label; tabs++) {
663     if (!tab_entries[tabs].display_tab) {
664       continue;
665     }
666     abuf_appendf(abuf, "<li><a href=\"%s\"%s>%s</a></li>\n", tab_entries[tabs].filename,
667                tabs == active ? " class=\"active\"" : "", tab_entries[tabs].tab_label);
668   }
669   abuf_appendf(abuf, "</ul>\n" "</td></tr>\n" "<tr><td>\n");
670 }
671
672 /*
673  * destructor - called at unload
674  */
675 void
676 olsr_plugin_exit(void)
677 {
678   struct allowed_net *a, *next;
679   if (http_socket >= 0) {
680     CLOSE(http_socket);
681   }
682
683   for (a = allowed_nets; a != NULL; a = next) {
684     next = a->next;
685
686     free(a);
687   }
688 }
689
690 static void
691 section_title(struct autobuf *abuf, const char *title)
692 {
693   abuf_appendf(abuf,
694                   "<h2>%s</h2>\n" "<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" align=\"center\">\n",
695                   title);
696 }
697
698 static void
699 build_frame(struct autobuf *abuf, const char *title __attribute__ ((unused)), const char *the_link
700             __attribute__ ((unused)), int width __attribute__ ((unused)), build_body_callback frame_body_cb)
701 {
702   abuf_puts(abuf, "<div id=\"maintable\">\n");
703   frame_body_cb(abuf);
704   abuf_puts(abuf, "</div>\n");
705 }
706
707 static void
708 fmt_href(struct autobuf *abuf, const char *const ipaddr)
709 {
710   abuf_appendf(abuf, "<a href=\"http://%s:%d/all\">", ipaddr, http_port);
711 }
712
713 static void
714 build_ip_txt(struct autobuf *abuf, const bool print_link, const char *const ipaddrstr, const int prefix_len)
715 {
716   if (print_link) {
717     fmt_href(abuf, ipaddrstr);
718   }
719
720   abuf_puts(abuf, ipaddrstr);
721   /* print ip address or ip prefix ? */
722   if (prefix_len != -1 && prefix_len != olsr_cnf->maxplen) {
723     abuf_appendf(abuf, "/%d", prefix_len);
724   }
725
726   if (print_link) {             /* Print the link only if there is no prefix_len */
727     abuf_puts(abuf, "</a>");
728   }
729 }
730
731 static void
732 build_ipaddr_link(struct autobuf *abuf, const bool want_link, const union olsr_ip_addr *const ipaddr,
733                   const int prefix_len)
734 {
735   struct ipaddr_str ipaddrstr;
736   const struct hostent *const hp =
737 #ifndef _WIN32
738     resolve_ip_addresses ? gethostbyaddr((const void *)ipaddr, olsr_cnf->ipsize,
739                                          olsr_cnf->ip_version) :
740 #endif /* _WIN32 */
741     NULL;
742   /* Print the link only if there is no prefix_len and ip_version is AF_INET */
743   const int print_link = want_link && (prefix_len == -1 || prefix_len == olsr_cnf->maxplen) && (olsr_cnf->ip_version == AF_INET);
744   olsr_ip_to_string(&ipaddrstr, ipaddr);
745
746   abuf_puts(abuf, "<td>");
747   build_ip_txt(abuf, print_link, ipaddrstr.buf, prefix_len);
748   abuf_puts(abuf, "</td>");
749
750   if (resolve_ip_addresses) {
751     if (hp) {
752       abuf_puts(abuf, "<td>(");
753       if (print_link) {
754         fmt_href(abuf, ipaddrstr.buf);
755       }
756       abuf_puts(abuf, hp->h_name);
757       if (print_link) {
758         abuf_puts(abuf, "</a>");
759       }
760       abuf_puts(abuf, ")</td>");
761     } else {
762       abuf_puts(abuf, "<td/>");
763     }
764   }
765 }
766
767 #define build_ipaddr_with_link(buf, ipaddr, plen) \
768           build_ipaddr_link((buf), true, (ipaddr), (plen))
769 #define build_ipaddr_no_link(buf, ipaddr, plen) \
770           build_ipaddr_link((buf), false, (ipaddr), (plen))
771
772 static void
773 build_route(struct autobuf *abuf, const struct rt_entry *rt)
774 {
775   struct lqtextbuffer lqbuffer;
776
777   abuf_puts(abuf, "<tr>");
778   build_ipaddr_with_link(abuf, &rt->rt_dst.prefix, rt->rt_dst.prefix_len);
779   build_ipaddr_with_link(abuf, &rt->rt_best->rtp_nexthop.gateway, -1);
780
781   abuf_appendf(abuf, "<td>%d</td>", rt->rt_best->rtp_metric.hops);
782   abuf_appendf(abuf, "<td>%s</td>",
783              get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer));
784   abuf_appendf(abuf, "<td>%s</td></tr>\n",
785              if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
786 }
787
788 static void
789 build_routes_body(struct autobuf *abuf)
790 {
791   struct rt_entry *rt;
792   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
793   section_title(abuf, "OLSR Routes in Kernel");
794   abuf_appendf(abuf,
795              "<tr><th%s>Destination</th><th%s>Gateway</th><th>Metric</th><th>ETX</th><th>Interface</th></tr>\n",
796              colspan, colspan);
797
798   /* Walk the route table */
799   OLSR_FOR_ALL_RT_ENTRIES(rt) {
800     build_route(abuf, rt);
801   } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
802
803   abuf_puts(abuf, "</table>\n");
804 }
805
806 static void
807 build_config_body(struct autobuf *abuf)
808 {
809   const struct olsr_if *ifs;
810   const struct plugin_entry *pentry;
811   const struct plugin_param *pparam;
812   struct ipaddr_str mainaddrbuf;
813
814   abuf_appendf(abuf, "Version: %s (built on %s on %s)\n<br>", olsrd_version, build_date, build_host);
815   abuf_appendf(abuf, "OS: %s\n<br>", OS);
816
817   {
818     const time_t currtime = time(NULL);
819
820     abuf_strftime(abuf, "System time: <em>%a, %d %b %Y %H:%M:%S</em><br>",
821                             localtime(&currtime));
822   }
823
824   {
825     struct timeval now, uptime;
826     int hours, mins, days;
827     gettimeofday(&now, NULL);
828     timersub(&now, &start_time, &uptime);
829
830     days = uptime.tv_sec / 86400;
831     uptime.tv_sec %= 86400;
832     hours = uptime.tv_sec / 3600;
833     uptime.tv_sec %= 3600;
834     mins = uptime.tv_sec / 60;
835     uptime.tv_sec %= 60;
836
837     abuf_puts(abuf, "Olsrd uptime: <em>");
838     if (days) {
839       abuf_appendf(abuf, "%d day(s) ", days);
840     }
841     abuf_appendf(abuf, "%02d hours %02d minutes %02d seconds</em><br/>\n", hours, mins, (int)uptime.tv_sec);
842   }
843
844   abuf_appendf(abuf, "HTTP stats(ok/dyn/error/illegal): <em>%d/%d/%d/%d</em><br>\n", stats.ok_hits,
845              stats.dyn_hits, stats.err_hits, stats.ill_hits);
846
847   abuf_puts(abuf,
848              "Click <a href=\"/cfgfile\">here</a> to <em>generate a configuration file for this node</em>.\n");
849
850   abuf_puts(abuf, "<h2>Variables</h2>\n");
851
852   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n<tr>");
853
854   abuf_appendf(abuf, "<td>Main address: <strong>%s</strong></td>\n",
855              olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->main_addr));
856   abuf_appendf(abuf, "<td>IP version: %d</td>\n", olsr_cnf->ip_version == AF_INET ? 4 : 6);
857   abuf_appendf(abuf, "<td>Debug level: %d</td>\n", olsr_cnf->debug_level);
858   abuf_appendf(abuf, "<td>FIB Metrics: %s</td>\n", FIB_METRIC_TXT[olsr_cnf->fib_metric]);
859
860   abuf_puts(abuf, "</tr>\n<tr>\n");
861
862   abuf_appendf(abuf, "<td>Pollrate: %0.2f</td>\n", (double)olsr_cnf->pollrate);
863   abuf_appendf(abuf, "<td>TC redundancy: %d</td>\n", olsr_cnf->tc_redundancy);
864   abuf_appendf(abuf, "<td>MPR coverage: %d</td>\n", olsr_cnf->mpr_coverage);
865   abuf_appendf(abuf, "<td>NAT threshold: %f</td>\n", (double)olsr_cnf->lq_nat_thresh);
866
867   abuf_puts(abuf, "</tr>\n<tr>\n");
868
869   abuf_appendf(abuf, "<td>Fisheye: %s</td>\n", olsr_cnf->lq_fish ? "Enabled" : "Disabled");
870   abuf_appendf(abuf, "<td>TOS: 0x%04x</td>\n", olsr_cnf->tos);
871   abuf_appendf(abuf, "<td>RtTable: 0x%04x/%d</td>\n", olsr_cnf->rt_table, olsr_cnf->rt_table);
872   abuf_appendf(abuf, "<td>RtTableDefault: 0x%04x/%d</td>\n", olsr_cnf->rt_table_default,
873              olsr_cnf->rt_table_default);
874   abuf_appendf(abuf, "<td>RtTableTunnel: 0x%04x/%d</td>\n", olsr_cnf->rt_table_tunnel,
875              olsr_cnf->rt_table_tunnel);
876   abuf_appendf(abuf, "<td>Willingness: %d %s</td>\n", olsr_cnf->willingness,
877              olsr_cnf->willingness_auto ? "(auto)" : "");
878
879   if (olsr_cnf->lq_level == 0) {
880     abuf_appendf(abuf, "</tr>\n<tr>\n" "<td>Hysteresis: %s</td>\n",
881                olsr_cnf->use_hysteresis ? "Enabled" : "Disabled");
882     if (olsr_cnf->use_hysteresis) {
883       abuf_appendf(abuf, "<td>Hyst scaling: %0.2f</td>\n", (double)olsr_cnf->hysteresis_param.scaling);
884       abuf_appendf(abuf, "<td>Hyst lower/upper: %0.2f/%0.2f</td>\n", (double)olsr_cnf->hysteresis_param.thr_low,
885                   (double)olsr_cnf->hysteresis_param.thr_high);
886     }
887   }
888
889   abuf_appendf(abuf, "</tr>\n<tr>\n" "<td>LQ extension: %s</td>\n",
890              olsr_cnf->lq_level ? "Enabled" : "Disabled");
891   if (olsr_cnf->lq_level) {
892     abuf_appendf(abuf, "<td>LQ level: %d</td>\n" "<td>LQ aging: %f</td>\n", olsr_cnf->lq_level,
893                 (double)olsr_cnf->lq_aging);
894   }
895   abuf_puts(abuf, "</tr></table>\n");
896
897   abuf_puts(abuf, "<h2>Interfaces</h2>\n");
898   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n");
899   for (ifs = olsr_cnf->interfaces; ifs != NULL; ifs = ifs->next) {
900     const struct interface *const rifs = ifs->interf;
901     abuf_appendf(abuf, "<tr><th colspan=\"3\">%s</th>\n", ifs->name);
902     if (!rifs) {
903       abuf_puts(abuf, "<tr><td colspan=\"3\">Status: DOWN</td></tr>\n");
904       continue;
905     }
906
907     if (olsr_cnf->ip_version == AF_INET) {
908       struct ipaddr_str addrbuf, maskbuf, bcastbuf;
909       abuf_appendf(abuf, "<tr>\n" "<td>IP: %s</td>\n" "<td>MASK: %s</td>\n" "<td>BCAST: %s</td>\n" "</tr>\n",
910                  ip4_to_string(&addrbuf, rifs->int_addr.sin_addr), ip4_to_string(&maskbuf, rifs->int_netmask.sin_addr),
911                  ip4_to_string(&bcastbuf, rifs->int_broadaddr.sin_addr));
912     } else {
913       struct ipaddr_str addrbuf, maskbuf;
914       abuf_appendf(abuf, "<tr>\n" "<td>IP: %s</td>\n" "<td>MCAST: %s</td>\n" "<td></td>\n" "</tr>\n",
915                  ip6_to_string(&addrbuf, &rifs->int6_addr.sin6_addr), ip6_to_string(&maskbuf, &rifs->int6_multaddr.sin6_addr));
916     }
917     abuf_appendf(abuf, "<tr>\n" "<td>MTU: %d</td>\n" "<td>WLAN: %s</td>\n" "<td>STATUS: UP</td>\n" "</tr>\n",
918                rifs->int_mtu, rifs->is_wireless ? "Yes" : "No");
919   }
920   abuf_puts(abuf, "</table>\n");
921
922   abuf_appendf(abuf, "<em>Olsrd is configured to %s if no interfaces are available</em><br>\n",
923              olsr_cnf->allow_no_interfaces ? "run even" : "halt");
924
925   abuf_puts(abuf, "<h2>Plugins</h2>\n");
926   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\"><tr><th>Name</th><th>Parameters</th></tr>\n");
927   for (pentry = olsr_cnf->plugins; pentry; pentry = pentry->next) {
928     abuf_appendf(abuf, "<tr><td>%s</td>\n" "<td><select>\n" "<option>KEY, VALUE</option>\n", pentry->name);
929
930     for (pparam = pentry->params; pparam; pparam = pparam->next) {
931       abuf_appendf(abuf, "<option>\"%s\", \"%s\"</option>\n", pparam->key, pparam->value);
932     }
933     abuf_puts(abuf, "</select></td></tr>\n");
934
935   }
936   abuf_puts(abuf, "</table>\n");
937
938   section_title(abuf, "Announced HNA entries");
939   if (olsr_cnf->hna_entries) {
940     struct ip_prefix_list *hna;
941     abuf_puts(abuf, "<tr><th>Network</th></tr>\n");
942     for (hna = olsr_cnf->hna_entries; hna; hna = hna->next) {
943       struct ipaddr_str netbuf;
944       abuf_appendf(abuf, "<tr><td>%s/%d</td></tr>\n", olsr_ip_to_string(&netbuf, &hna->net.prefix),
945                  hna->net.prefix_len);
946     }
947   } else {
948     abuf_puts(abuf, "<tr><td></td></tr>\n");
949   }
950   abuf_puts(abuf, "</table>\n");
951 }
952
953 static void
954 build_neigh_body(struct autobuf *abuf)
955 {
956   struct neighbor_entry *neigh;
957   struct link_entry *the_link = NULL;
958   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
959
960   section_title(abuf, "Links");
961
962   abuf_appendf(abuf,
963              "<tr><th%s>Local IP</th><th%s>Remote IP</th><th>Hysteresis</th>",
964              colspan, colspan);
965   if (olsr_cnf->lq_level > 0) {
966     abuf_puts(abuf, "<th>LinkCost</th>");
967   }
968   abuf_puts(abuf, "</tr>\n");
969
970   /* Link set */
971   OLSR_FOR_ALL_LINK_ENTRIES(the_link) {
972     abuf_puts(abuf, "<tr>");
973     build_ipaddr_with_link(abuf, &the_link->local_iface_addr, -1);
974     build_ipaddr_with_link(abuf, &the_link->neighbor_iface_addr, -1);
975     abuf_appendf(abuf, "<td>%0.2f</td>", (double)the_link->L_link_quality);
976     if (olsr_cnf->lq_level > 0) {
977       struct lqtextbuffer lqbuffer1, lqbuffer2;
978       abuf_appendf(abuf, "<td>(%s) %s</td>", get_link_entry_text(the_link, '/', &lqbuffer1),
979                  get_linkcost_text(the_link->linkcost, false, &lqbuffer2));
980     }
981     abuf_puts(abuf, "</tr>\n");
982   } OLSR_FOR_ALL_LINK_ENTRIES_END(the_link);
983
984   abuf_puts(abuf, "</table>\n");
985
986   section_title(abuf, "Neighbors");
987   abuf_appendf(abuf,
988              "<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",
989              colspan);
990   /* Neighbors */
991   OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
992
993     struct neighbor_2_list_entry *list_2;
994     int thop_cnt;
995     abuf_puts(abuf, "<tr>");
996     build_ipaddr_with_link(abuf, &neigh->neighbor_main_addr, -1);
997     abuf_appendf(abuf,
998                "<td>%s</td>" "<td>%s</td>" "<td>%s</td>"
999                "<td>%d</td>", (neigh->status == SYM) ? "YES" : "NO", neigh->is_mpr ? "YES" : "NO",
1000                olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO", neigh->willingness);
1001
1002     abuf_puts(abuf, "<td><select>\n" "<option>IP ADDRESS</option>\n");
1003
1004     for (list_2 = neigh->neighbor_2_list.next, thop_cnt = 0; list_2 != &neigh->neighbor_2_list; list_2 = list_2->next, thop_cnt++) {
1005       struct ipaddr_str strbuf;
1006       abuf_appendf(abuf, "<option>%s</option>\n",
1007                  olsr_ip_to_string(&strbuf, &list_2->neighbor_2->neighbor_2_addr));
1008     }
1009     abuf_appendf(abuf, "</select> (%d)</td></tr>\n", thop_cnt);
1010   } OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
1011
1012   abuf_puts(abuf, "</table>\n");
1013 }
1014
1015 static void
1016 build_topo_body(struct autobuf *abuf)
1017 {
1018   struct tc_entry *tc;
1019   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1020
1021   section_title(abuf, "Topology Entries");
1022   abuf_appendf(abuf, "<tr><th%s>Destination IP</th><th%s>Last Hop IP</th>",
1023              colspan, colspan);
1024   if (olsr_cnf->lq_level > 0) {
1025     abuf_puts(abuf, "<th>Linkcost</th>");
1026   }
1027   abuf_puts(abuf, "</tr>\n");
1028
1029   OLSR_FOR_ALL_TC_ENTRIES(tc) {
1030     struct tc_edge_entry *tc_edge;
1031     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
1032       if (tc_edge->edge_inv) {
1033         abuf_puts(abuf, "<tr>");
1034         build_ipaddr_with_link(abuf, &tc_edge->T_dest_addr, -1);
1035         build_ipaddr_with_link(abuf, &tc->addr, -1);
1036         if (olsr_cnf->lq_level > 0) {
1037           struct lqtextbuffer lqbuffer1, lqbuffer2;
1038           abuf_appendf(abuf, "<td>(%s) %s</td>\n",
1039                      get_tc_edge_entry_text(tc_edge, '/', &lqbuffer1), get_linkcost_text(tc_edge->cost, false, &lqbuffer2));
1040         }
1041         abuf_puts(abuf, "</tr>\n");
1042       }
1043     } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
1044   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
1045
1046   abuf_puts(abuf, "</table>\n");
1047 }
1048
1049 static void
1050 build_mid_body(struct autobuf *abuf)
1051 {
1052   int idx;
1053   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1054
1055   section_title(abuf, "MID Entries");
1056   abuf_appendf(abuf, "<tr><th%s>Main Address</th><th>Aliases</th></tr>\n", colspan);
1057
1058   /* MID */
1059   for (idx = 0; idx < HASHSIZE; idx++) {
1060     struct mid_entry *entry;
1061     for (entry = mid_set[idx].next; entry != &mid_set[idx]; entry = entry->next) {
1062       int mid_cnt;
1063       struct mid_address *alias;
1064       abuf_puts(abuf, "<tr>");
1065       build_ipaddr_with_link(abuf, &entry->main_addr, -1);
1066       abuf_puts(abuf, "<td><select>\n<option>IP ADDRESS</option>\n");
1067
1068       for (mid_cnt = 0, alias = entry->aliases; alias != NULL; alias = alias->next_alias, mid_cnt++) {
1069         struct ipaddr_str strbuf;
1070         abuf_appendf(abuf, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &alias->alias));
1071       }
1072       abuf_appendf(abuf, "</select> (%d)</td></tr>\n", mid_cnt);
1073     }
1074   }
1075
1076   abuf_puts(abuf, "</table>\n");
1077 }
1078
1079 static void
1080 build_nodes_body(struct autobuf *abuf)
1081 {
1082   build_neigh_body(abuf);
1083   build_topo_body(abuf);
1084   build_mid_body(abuf);
1085 }
1086
1087 static void
1088 build_all_body(struct autobuf *abuf)
1089 {
1090   build_config_body(abuf);
1091   build_routes_body(abuf);
1092   build_neigh_body(abuf);
1093   build_topo_body(abuf);
1094   build_mid_body(abuf);
1095 #ifdef HTTPINFO_PUD
1096   build_pud_body(abuf);
1097 #endif /* HTTPINFO_PUD */
1098 }
1099
1100 #ifdef HTTPINFO_PUD
1101 /**
1102  * Determine if a nmeaINFO structure has a certain field.
1103  * We need this function locally because nmealib might not be loaded.
1104  *
1105  * @param present the presence field
1106  * @param fieldName use a name from nmeaINFO_FIELD
1107  * @return a boolean, true when the structure has the requested field
1108  */
1109 static inline bool nmea_INFO_has_field_local(uint32_t present, nmeaINFO_FIELD fieldName) {
1110         return ((present & fieldName) != 0);
1111 }
1112
1113 static const char * NA_STRING = "N.A.";
1114 static const char * SAT_INUSE_COLOR = "lime";
1115 static const char * SAT_NOTINUSE_COLOR = "red";
1116
1117 static void build_pud_body(struct autobuf *abuf) {
1118         TransmitGpsInformation * txGpsInfo = olsr_cnf->pud_position;
1119         char * nodeId;
1120         char nodeIdString[256];
1121         bool datePresent;
1122         bool timePresent;
1123
1124         abuf_puts(abuf, "<h2>Position</h2>");
1125
1126         if (!txGpsInfo) {
1127                 abuf_puts(abuf, "<p><b>" PUD_PLUGIN_ABBR " plugin not loaded</b></p>\n");
1128                 return;
1129         }
1130
1131         nodeId = (char *) txGpsInfo->nodeId;
1132
1133         if (!nodeId || !strlen(nodeId)) {
1134                 inet_ntop(olsr_cnf->ip_version, &olsr_cnf->main_addr, &nodeIdString[0], sizeof(nodeIdString));
1135                 nodeId = nodeIdString;
1136         }
1137
1138         /* start of table */
1139         abuf_puts(abuf,
1140                 "<p><table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"
1141                 "<tr><th>Parameter</th><th>&nbsp;&nbsp;</th><th>Unit</th><th>&nbsp;&nbsp;</th><th>Value</th></tr>\n"
1142         );
1143
1144         /* nodeId */
1145         abuf_appendf(abuf,
1146                 "<tr><td>Name</td><td></td><td></td><td></td><td id=\"nodeId\">%s</td></tr>\n",
1147                 nodeId
1148         );
1149
1150         /* utc */
1151         abuf_puts(abuf, "<tr><td>Date / Time</td><td></td><td>UTC</td><td></td><td id=\"utc\">");
1152         datePresent = nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, UTCDATE);
1153         timePresent = nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, UTCTIME);
1154         if (datePresent || timePresent) {
1155                 if (datePresent) {
1156                         abuf_appendf(abuf, "%04d%02d%02d",
1157                                 txGpsInfo->txPosition.nmeaInfo.utc.year + 1900,
1158                                 txGpsInfo->txPosition.nmeaInfo.utc.mon,
1159                                 txGpsInfo->txPosition.nmeaInfo.utc.day);
1160                 }
1161                 if (datePresent && timePresent) {
1162                         abuf_puts(abuf, " ");
1163                 }
1164                 if (timePresent) {
1165                         abuf_appendf(abuf, "%02d:%02d:%02d.%02d",
1166                                 txGpsInfo->txPosition.nmeaInfo.utc.hour,
1167                                 txGpsInfo->txPosition.nmeaInfo.utc.min,
1168                                 txGpsInfo->txPosition.nmeaInfo.utc.sec,
1169                                 txGpsInfo->txPosition.nmeaInfo.utc.hsec);
1170                 }
1171         } else {
1172                 abuf_puts(abuf, NA_STRING);
1173         }
1174         abuf_puts(abuf, "</td></tr>\n");
1175
1176         /* smask */
1177         abuf_puts(abuf, "<tr><td>Input Sentences</td><td></td><td></td><td></td><td id=\"smask\">");
1178         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SMASK)
1179                         && (txGpsInfo->txPosition.nmeaInfo.smask != GPNON)) {
1180                 const int id[] = { GPGGA, GPGSA, GPGSV, GPRMC, GPVTG, GPNON };
1181                 const char * ids[] = { "GPGGA", "GPGSA", "GPGSV", "GPRMC", "GPVTG" };
1182                 bool printed = false;
1183                 int i = 0;
1184
1185                 while (id[i] != GPNON) {
1186                         if (txGpsInfo->txPosition.nmeaInfo.smask & id[i]) {
1187                                 if (printed)
1188                                         abuf_puts(abuf, "&nbsp;");
1189                                 abuf_puts(abuf, ids[i]);
1190                                 printed = true;
1191                         }
1192                         i++;
1193                 }
1194         } else {
1195                 abuf_puts(abuf, NA_STRING);
1196         }
1197         abuf_puts(abuf, "</td></tr>\n");
1198
1199         /* sig */
1200         abuf_puts(abuf, "<tr><td>Signal Strength</td><td></td><td></td><td></td><td id=\"sig\">");
1201         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SIG)) {
1202                 const char * s;
1203                 switch (txGpsInfo->txPosition.nmeaInfo.sig) {
1204                         case NMEA_SIG_BAD:
1205                                 s = "Invalid";
1206                                 break;
1207                         case NMEA_SIG_LOW:
1208                                 s = "Fix";
1209                                 break;
1210                         case NMEA_SIG_MID:
1211                                 s = "Differential";
1212                                 break;
1213                         case NMEA_SIG_HIGH:
1214                                 s = "Sensitive";
1215                                 break;
1216                         case NMEA_SIG_RTKIN:
1217                                 s = "Real Time Kinematic";
1218                                 break;
1219                         case NMEA_SIG_FLRTK:
1220                                 s = "Float RTK";
1221                                 break;
1222                         case NMEA_SIG_ESTIM:
1223                                 s = "Estimated (Dead Reckoning)";
1224                                 break;
1225                         case NMEA_SIG_MAN:
1226                                 s = "Manual Input Mode";
1227                                 break;
1228                         case NMEA_SIG_SIM:
1229                                 s = "Simulation Mode";
1230                                 break;
1231                         default:
1232                                 s = "Unknown";
1233                                 break;
1234                 }
1235                 abuf_appendf(abuf, "%s (%d)", s, txGpsInfo->txPosition.nmeaInfo.sig);
1236         } else {
1237                 abuf_puts(abuf, NA_STRING);
1238         }
1239         abuf_puts(abuf, "</td></tr>\n");
1240
1241         /* fix */
1242         abuf_puts(abuf, "<tr><td>Fix</td><td></td><td></td><td></td><td id=\"fix\">");
1243         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, FIX)) {
1244                 const char * s;
1245                 switch (txGpsInfo->txPosition.nmeaInfo.fix) {
1246                         case NMEA_FIX_BAD:
1247                                 s = "BAD";
1248                                 break;
1249                         case NMEA_FIX_2D:
1250                                 s = "2D";
1251                                 break;
1252                         case NMEA_FIX_3D:
1253                                 s = "3D";
1254                                 break;
1255                         default:
1256                                 s = "Unknown";
1257                                 break;
1258                 }
1259                 abuf_appendf(abuf, "%s (%d)", s, txGpsInfo->txPosition.nmeaInfo.fix);
1260         } else {
1261                 abuf_puts(abuf, NA_STRING);
1262         }
1263         abuf_puts(abuf, "</td></tr>\n");
1264
1265         /* PDOP */
1266         abuf_puts(abuf, "<tr><td>PDOP</td><td></td><td></td><td></td><td id=\"pdop\">");
1267         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, PDOP)) {
1268                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.PDOP);
1269         } else {
1270                 abuf_puts(abuf, NA_STRING);
1271         }
1272         abuf_puts(abuf, "</td></tr>\n");
1273
1274         /* HDOP */
1275         abuf_puts(abuf, "<tr><td>HDOP</td><td></td><td></td><td></td><td id=\"hdop\">");
1276         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, HDOP)) {
1277                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.HDOP);
1278         } else {
1279                 abuf_puts(abuf, NA_STRING);
1280         }
1281         abuf_puts(abuf, "</td></tr>\n");
1282
1283         /* VDOP */
1284         abuf_puts(abuf, "<tr><td>VDOP</td><td></td><td></td><td></td><td id=\"vdop\">");
1285         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, VDOP)) {
1286                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.VDOP);
1287         } else {
1288                 abuf_puts(abuf, NA_STRING);
1289         }
1290         abuf_puts(abuf, "</td></tr>\n");
1291
1292         /* lat */
1293         abuf_puts(abuf, "<tr><td>Latitude</td><td></td><td>degrees</td><td></td><td id=\"lat\">");
1294         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, LAT)) {
1295                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.lat);
1296         } else {
1297                 abuf_puts(abuf, NA_STRING);
1298         }
1299         abuf_puts(abuf, "</td></tr>\n");
1300
1301         /* lon */
1302         abuf_puts(abuf, "<tr><td>Longitude</td><td></td><td>degrees</td><td></td><td id=\"lon\">");
1303         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, LON)) {
1304                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.lon);
1305         } else {
1306                 abuf_puts(abuf, NA_STRING);
1307         }
1308         abuf_puts(abuf, "</td></tr>\n");
1309
1310         /* elv */
1311         abuf_puts(abuf, "<tr><td>Elevation</td><td></td><td>m</td><td></td><td id=\"elv\">");
1312         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, ELV)) {
1313                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.elv);
1314         } else {
1315                 abuf_puts(abuf, NA_STRING);
1316         }
1317         abuf_puts(abuf, "</td></tr>\n");
1318
1319         /* speed */
1320         abuf_puts(abuf, "<tr><td>Speed</td><td></td><td>kph</td><td></td><td id=\"speed\">");
1321         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SPEED)) {
1322                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.speed);
1323         } else {
1324                 abuf_puts(abuf, NA_STRING);
1325         }
1326         abuf_puts(abuf, "</td></tr>\n");
1327
1328         /* track */
1329         abuf_puts(abuf, "<tr><td>Track</td><td></td><td>degrees</td><td></td><td id=\"track\">");
1330         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, TRACK)) {
1331                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.track);
1332         } else {
1333                 abuf_puts(abuf, NA_STRING);
1334         }
1335         abuf_puts(abuf, "</td></tr>\n");
1336
1337         /* mtrack */
1338         abuf_puts(abuf, "<tr><td>Magnetic Track</td><td></td><td>degrees</td><td></td><td id=\"mtrack\">");
1339         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, MTRACK)) {
1340                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.mtrack);
1341         } else {
1342                 abuf_puts(abuf, NA_STRING);
1343         }
1344         abuf_puts(abuf, "</td></tr>\n");
1345
1346         /* magvar */
1347         abuf_puts(abuf, "<tr><td>Magnetic Variation</td><td></td><td>degrees</td><td></td><td id=\"magvar\">");
1348         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, MAGVAR)) {
1349                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.magvar);
1350         } else {
1351                 abuf_puts(abuf, NA_STRING);
1352         }
1353         abuf_puts(abuf, "</td></tr>\n");
1354
1355         /* end of table */
1356         abuf_puts(abuf, "</table></p>\n");
1357
1358         /* sats */
1359         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SATINVIEW)) {
1360                 int cnt = 0;
1361
1362                 abuf_puts(abuf, "<p>\n");
1363                 abuf_puts(abuf, "Satellite Infomation:\n");
1364                 abuf_puts(abuf, "<table border=\"1\" cellpadding=\"2\" cellspacing=\"0\" id=\"satinfo\">\n");
1365                 abuf_puts(abuf, "<tbody align=\"center\">\n");
1366                 abuf_puts(abuf,
1367                                 "<tr><th>ID</th><th>In Use</th><th>Elevation (degrees)</th><th>Azimuth (degrees)</th><th>Signal (dB)</th></tr>\n");
1368
1369                 if (txGpsInfo->txPosition.nmeaInfo.satinfo.inview) {
1370                         int satIndex;
1371                         for (satIndex = 0; satIndex < NMEA_MAXSAT; satIndex++) {
1372                                 nmeaSATELLITE * sat = &txGpsInfo->txPosition.nmeaInfo.satinfo.sat[satIndex];
1373                                 if (sat->id) {
1374                                         bool inuse = false;
1375                                         const char * inuseStr;
1376
1377                                         if (!nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SATINUSE)) {
1378                                                 inuseStr = NA_STRING;
1379                                         } else {
1380                                                 int inuseIndex;
1381                                                 for (inuseIndex = 0; inuseIndex < NMEA_MAXSAT; inuseIndex++) {
1382                                                         if (txGpsInfo->txPosition.nmeaInfo.satinfo.in_use[inuseIndex] == sat->id) {
1383                                                                 inuse = true;
1384                                                                 break;
1385                                                         }
1386                                                 }
1387                                                 if (inuse) {
1388                                                         inuseStr = "yes";
1389                                                 } else {
1390                                                         inuseStr = "no";
1391                                                 }
1392                                         }
1393
1394                                         abuf_appendf(abuf, "<tr><td>%02d</td><td bgcolor=\"%s\">%s</td><td>%02d</td><td>%03d</td><td>%02d</td></tr>\n",
1395                                                         sat->id, inuse ? SAT_INUSE_COLOR : SAT_NOTINUSE_COLOR, inuseStr, sat->elv, sat->azimuth, sat->sig);
1396                                         cnt++;
1397                                 }
1398                         }
1399                 }
1400
1401                 if (!cnt) {
1402                         abuf_puts(abuf, "<tr><td colspan=\"5\">none</td></tr>\n");
1403                 }
1404
1405                 abuf_puts(abuf, "</tbody></table>\n");
1406                 abuf_puts(abuf, "</p>\n");
1407         }
1408
1409         /* add Google Maps and OpenStreetMap links when we have both lat and lon */
1410         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, LAT)
1411                         && nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, LON)) {
1412                 const char * c = nodeId;
1413
1414                 abuf_appendf(abuf,
1415                         "<p>\n"
1416                         "<a href=\"http://maps.google.com/maps?q=%f,+%f+%%28",
1417                         txGpsInfo->txPosition.nmeaInfo.lat,
1418                         txGpsInfo->txPosition.nmeaInfo.lon
1419                 );
1420
1421                 while (*c != '\0') {
1422                         if (*c == ' ' || *c == '\t') {
1423                                 abuf_puts(abuf, "+");
1424                         } else {
1425                                 abuf_appendf(abuf, "%c", *c);
1426                         }
1427                         c++;
1428                 }
1429
1430                 abuf_puts(abuf, "%29&amp;iwloc=A\">Show on Google Maps</a></p>\n");
1431
1432                 abuf_appendf(abuf,
1433                         "<p>\n"
1434                         "<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",
1435                         txGpsInfo->txPosition.nmeaInfo.lat,
1436                         txGpsInfo->txPosition.nmeaInfo.lon
1437                 );
1438         }
1439 }
1440 #endif /* HTTPINFO_PUD */
1441
1442 static void
1443 build_about_body(struct autobuf *abuf)
1444 {
1445   abuf_appendf(abuf,
1446                   "<strong>" PLUGIN_NAME " version " PLUGIN_VERSION "</strong><br/>\n" "by Andreas T&oslash;nnesen (C)2005.<br/>\n"
1447                   "Compiled "
1448 #ifdef ADMIN_INTERFACE
1449                   "<em>with experimental admin interface</em> "
1450 #endif /* ADMIN_INTERFACE */
1451                   "%s at %s<hr/>\n" "This plugin implements a HTTP server that supplies\n"
1452                   "the client with various dynamic web pages representing\n"
1453                   "the current olsrd status.<br/>The different pages include:\n"
1454                   "<ul>\n<li><strong>Configuration</strong> - This page displays information\n"
1455                   "about the current olsrd configuration. This includes various\n"
1456                   "olsr settings such as IP version, MID/TC redundancy, hysteresis\n"
1457                   "etc. Information about the current status of the interfaces on\n"
1458                   "which olsrd is configured to run is also displayed. Loaded olsrd\n"
1459                   "plugins are shown with their plugin parameters. Finally all local\n"
1460                   "HNA entries are shown. These are the networks that the local host\n"
1461                   "will anounce itself as a gateway to.</li>\n"
1462                   "<li><strong>Routes</strong> - This page displays all routes currently set in\n"
1463                   "the kernel <em>by olsrd</em>. The type of route is also displayed(host\n" "or HNA).</li>\n"
1464                   "<li><strong>Links/Topology</strong> - This page displays all information about\n"
1465                   "links, neighbors, topology, MID and HNA entries.</li>\n"
1466                   "<li><strong>All</strong> - Here all the previous pages are displayed as one.\n"
1467                   "This is to make all information available as easy as possible(for example\n"
1468                   "for a script) and using as few resources as possible.</li>\n"
1469 #ifdef ADMIN_INTERFACE
1470                   "<li><strong>Admin</strong> - This page is highly experimental(and unsecure)!\n"
1471                   "As of now it is not working at all but it provides a impression of\n"
1472                   "the future possibilities of httpinfo. This is to be a interface to\n"
1473                   "changing olsrd settings in realtime. These settings include various\n"
1474                   "\"basic\" settings and local HNA settings.</li>\n"
1475 #endif /* ADMIN_INTERFACE */
1476                   "<li><strong>About</strong> - this help page.</li>\n</ul>" "<hr/>\n" "Send questions or comments to\n"
1477                   "<a href=\"mailto:olsr-users@olsr.org\">olsr-users@olsr.org</a> or\n"
1478                   "<a href=\"mailto:andreto-at-olsr.org\">andreto-at-olsr.org</a><br/>\n"
1479                   "Official olsrd homepage: <a href=\"http://www.olsr.org/\">http://www.olsr.org</a><br/>\n", build_date,
1480                   build_host);
1481 }
1482
1483 static void
1484 build_cfgfile_body(struct autobuf *abuf)
1485 {
1486   abuf_puts(abuf,
1487              "\n\n" "<strong>This is a automatically generated configuration\n"
1488              "file based on the current olsrd configuration of this node.<br/>\n" "<hr/>\n" "<pre>\n");
1489   olsrd_write_cnf_autobuf(abuf, olsr_cnf);
1490
1491   abuf_puts(abuf, "</pre>\n<hr/>\n");
1492 }
1493
1494 static int
1495 check_allowed_ip(const struct allowed_net *const my_allowed_nets, const union olsr_ip_addr *const addr)
1496 {
1497   const struct allowed_net *alln;
1498   for (alln = my_allowed_nets; alln != NULL; alln = alln->next) {
1499     if (ip_in_net(addr, &alln->prefix)) {
1500       return 1;
1501     }
1502   }
1503   return 0;
1504 }
1505
1506 /*
1507  * Local Variables:
1508  * c-basic-offset: 2
1509  * indent-tabs-mode: nil
1510  * End:
1511  */