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