FIX: floatingpoint-text to uint32 conversion
[olsrd.git] / lib / httpinfo / src / olsrd_httpinfo.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
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 "olsrd_httpinfo.h"
47 #include "admin_interface.h"
48 #include "gfx.h"
49
50 #include "olsr.h"
51 #include "olsr_cfg.h"
52 #include "interfaces.h"
53 #include "olsr_protocol.h"
54 #include "net_olsr.h"
55 #include "link_set.h"
56 #include "ipcalc.h"
57 #include "lq_plugin.h"
58 #include "olsr_cfg_gen.h"
59 #include "common/string.h"
60 #include "olsr_ip_prefix_list.h"
61 #include "olsr_logging.h"
62
63 #include <stdio.h>
64 #include <string.h>
65 #include <stdlib.h>
66 #include <stdarg.h>
67 #include <unistd.h>
68 #include <errno.h>
69 #ifdef WIN32
70 #include <io.h>
71 #else
72 #include <netdb.h>
73 #endif
74
75 #ifdef OS
76 #undef OS
77 #endif
78
79 #ifdef WIN32
80 #define OS "Windows"
81 #endif
82 #ifdef linux
83 #define OS "GNU/Linux"
84 #endif
85 #ifdef __FreeBSD__
86 #define OS "FreeBSD"
87 #endif
88
89 #ifndef OS
90 #define OS "Undefined"
91 #endif
92
93 static char copyright_string[] __attribute__ ((unused)) =
94   "olsr.org HTTPINFO plugin Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org) All rights reserved.";
95
96 #define MAX_CLIENTS 3
97
98 #define MAX_HTTPREQ_SIZE (1024 * 10)
99
100 #define DEFAULT_TCP_PORT 1978
101
102 #define HTML_BUFSIZE (1024 * 4000)
103
104 #define FRAMEWIDTH (resolve_ip_addresses ? 900 : 800)
105
106 #define FILENREQ_MATCH(req, filename) \
107         !strcmp(req, filename) || \
108         (strlen(req) && !strcmp(&req[1], filename))
109
110 static const char httpinfo_css[] =
111   "#A{text-decoration:none}\n"
112   "TH{text-align:left}\n"
113   "H1,H3,TD,TH{font-family:Helvetica;font-size:80%}\n"
114   "h2{font-family:Helvetica; font-size:14px;text-align:center;line-height:16px;"
115   "text-decoration:none;border:1px solid #ccc;margin:5px;background:#ececec;}\n"
116   "hr{border:none;padding:1px;background:url(grayline.gif) repeat-x bottom;}\n"
117   "#maintable{margin:0px;padding:5px;border-left:1px solid #ccc;"
118   "border-right:1px solid #ccc;border-bottom:1px solid #ccc;}\n"
119   "#footer{font-size:10px;line-height:14px;text-decoration:none;color:#666;}\n"
120   "#hdr{font-size:14px;text-align:center;line-height:16px;text-decoration:none;"
121   "border:1px solid #ccc;margin:5px;background:#ececec;}\n"
122   "#container{width:1000px;padding:30px;border:1px solid #ccc;background:#fff;}\n"
123   "#tabnav{height:20px;margin:0;padding-left:10px;"
124   "background:url(grayline.gif) repeat-x bottom;}\n"
125   "#tabnav li{margin:0;padding:0;display:inline;list-style-type:none;}\n"
126   "#tabnav a:link,#tabnav a:visited{float:left;background:#ececec;font-size:12px;"
127   "line-height:14px;font-weight:bold;padding:2px 10px 2px 10px;margin-right:4px;"
128   "border:1px solid #ccc;text-decoration:none;color:#777;}\n"
129   "#tabnav a:link.active,#tabnav a:visited.active{border-bottom:1px solid #fff;"
130   "background:#ffffff;color:#000;}\n"
131   "#tabnav a:hover{background:#777777;color:#ffffff;}\n"
132   ".input_text{background:#E5E5E5;margin-left:5px; margin-top:0px;text-align:left;"
133   "width:100px;padding:0px;color:#000;text-decoration:none;font-family:verdana;"
134   "font-size:12px;border:1px solid #ccc;}\n"
135   ".input_button{background:#B5D1EE;margin-left:5px;margin-top:0px;text-align:center;"
136   "width:120px;padding:0px;color:#000;text-decoration:none;font-family:verdana;" "font-size:12px;border:1px solid #000;}\n";
137
138 typedef void (*build_body_callback) (struct autobuf * abuf);
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 #if ADMIN_INTERFACE
159 struct dynamic_file_entry {
160   const char *filename;
161   process_data_func process_data_cb;
162 };
163 #endif
164
165 static int get_http_socket(int);
166
167 static void build_tabs(struct autobuf *abuf, int);
168
169 static void parse_http_request(int, void *, unsigned int flags);
170
171 static void build_http_header(struct autobuf *abuf, http_header_type, bool, uint32_t);
172
173 static void build_frame(struct autobuf *abuf, build_body_callback frame_body_cb);
174
175 static void build_routes_body(struct autobuf *abuf);
176
177 static void build_config_body(struct autobuf *abuf);
178
179 static void build_neigh_body(struct autobuf *abuf);
180
181 static void build_topo_body(struct autobuf *abuf);
182
183 static void build_mid_body(struct autobuf *abuf);
184
185 static void build_nodes_body(struct autobuf *abuf);
186
187 static void build_all_body(struct autobuf *abuf);
188
189 static void build_about_body(struct autobuf *abuf);
190
191 static void build_cfgfile_body(struct autobuf *abuf);
192
193 static void build_ip_txt(struct autobuf *abuf, const bool want_link, const char *const ipaddrstr, const int prefix_len);
194
195 static void build_ipaddr_link(struct autobuf *abuf, const bool want_link,
196                               const union olsr_ip_addr *const ipaddr, const int prefix_len);
197 static void section_title(struct autobuf *abuf, const char *title);
198
199 static ssize_t writen(int fd, const void *buf, size_t count);
200
201 static struct timeval start_time;
202 static struct http_stats stats;
203 static int client_sockets[MAX_CLIENTS];
204 static int curr_clients;
205 static int http_socket;
206
207 #if 0
208 int netsprintf(char *str, const char *format, ...) __attribute__ ((format(printf, 2, 3)));
209 static int netsprintf_direct = 0;
210 static int netsprintf_error = 0;
211 #define sprintf netsprintf
212 #define NETDIRECT
213 #endif
214
215 static const struct tab_entry tab_entries[] = {
216   {"Configuration", "config", build_config_body, true},
217   {"Routes", "routes", build_routes_body, true},
218   {"Links/Topology", "nodes", build_nodes_body, true},
219   {"All", "all", build_all_body, true},
220 #if ADMIN_INTERFACE
221   {"Admin", "admin", build_admin_body, true},
222 #endif
223   {"About", "about", build_about_body, true},
224   {"FOO", "cfgfile", build_cfgfile_body, false},
225   {NULL, NULL, NULL, false}
226 };
227
228 static const struct static_bin_file_entry static_bin_files[] = {
229   {"favicon.ico", favicon_ico, sizeof(favicon_ico)}
230   ,
231   {"logo.gif", logo_gif, sizeof(logo_gif)}
232   ,
233   {"grayline.gif", grayline_gif, sizeof(grayline_gif)}
234   ,
235   {NULL, NULL, 0}
236 };
237
238 static const struct static_txt_file_entry static_txt_files[] = {
239   {"httpinfo.css", httpinfo_css},
240   {NULL, NULL}
241 };
242
243
244 #if ADMIN_INTERFACE
245 static const struct dynamic_file_entry dynamic_files[] = {
246   {"set_values", process_set_values},
247   {NULL, NULL}
248 };
249 #endif
250
251
252 static int
253 get_http_socket(int port)
254 {
255   struct sockaddr_storage sst;
256   uint32_t yes = 1;
257   socklen_t addrlen;
258
259   /* Init ipc socket */
260   int s = socket(olsr_cnf->ip_version, SOCK_STREAM, 0);
261   if (s == -1) {
262     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO)socket %s\n", strerror(errno));
263     return -1;
264   }
265
266   if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
267     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO)SO_REUSEADDR failed %s\n", strerror(errno));
268     CLOSESOCKET(s);
269     return -1;
270   }
271
272   /* Bind the socket */
273
274   /* complete the socket structure */
275   memset(&sst, 0, sizeof(sst));
276   if (olsr_cnf->ip_version == AF_INET) {
277     struct sockaddr_in *addr4 = (struct sockaddr_in *)&sst;
278     addr4->sin_family = AF_INET;
279     addrlen = sizeof(*addr4);
280 #ifdef SIN6_LEN
281     addr4->sin_len = addrlen;
282 #endif
283     addr4->sin_addr.s_addr = INADDR_ANY;
284     addr4->sin_port = htons(port);
285   } else {
286     struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&sst;
287     addr6->sin6_family = AF_INET6;
288     addrlen = sizeof(*addr6);
289 #ifdef SIN6_LEN
290     addr6->sin6_len = addrlen;
291 #endif
292     addr6->sin6_addr = in6addr_any;
293     addr6->sin6_port = htons(port);
294   }
295
296   /* bind the socket to the port number */
297   if (bind(s, (struct sockaddr *)&sst, addrlen) == -1) {
298     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) bind failed %s\n", strerror(errno));
299     CLOSESOCKET(s);
300     return -1;
301   }
302
303   /* show that we are willing to listen */
304   if (listen(s, 1) == -1) {
305     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) listen failed %s\n", strerror(errno));
306     CLOSESOCKET(s);
307     return -1;
308   }
309
310   return s;
311 }
312
313 /**
314  *Do initialization here
315  *
316  *This function is called by the my_init
317  *function in olsrd_plugin.c
318  */
319 int
320 olsrd_plugin_init(void)
321 {
322   /* Get start time */
323   gettimeofday(&start_time, NULL);
324
325   curr_clients = 0;
326   /* set up HTTP socket */
327   http_socket = get_http_socket(http_port != 0 ? http_port : DEFAULT_TCP_PORT);
328
329   if (http_socket < 0) {
330     OLSR_ERROR(LOG_PLUGINS, "(HTTPINFO) could not initialize HTTP socket\n");
331     olsr_exit(0);
332   }
333
334   /* always allow localhost */
335   if (olsr_cnf->ip_version == AF_INET) {
336     union olsr_ip_addr ip;
337
338     ip.v4.s_addr = ntohl(INADDR_LOOPBACK);
339     ip_acl_add(&allowed_nets, &ip, 32, false);
340   } else {
341     ip_acl_add(&allowed_nets, (const union olsr_ip_addr *)&in6addr_loopback, 128, false);
342     ip_acl_add(&allowed_nets, (const union olsr_ip_addr *)&in6addr_v4mapped_loopback, 128, false);
343   }
344
345   /* Register socket */
346   add_olsr_socket(http_socket, &parse_http_request, NULL, NULL, SP_PR_READ);
347
348   return 1;
349 }
350
351 /* Non reentrant - but we are not multithreaded anyway */
352 static void
353 parse_http_request(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
354 {
355   struct sockaddr_storage pin;
356   socklen_t addrlen;
357   union olsr_ip_addr *ipaddr;
358   char req[MAX_HTTPREQ_SIZE];
359   //static char body[HTML_BUFSIZE];
360   struct autobuf body, header;
361   char req_type[11];
362   char filename[251];
363   char http_version[11];
364   unsigned int c = 0;
365   int r = 1 /*, size = 0 */ ;
366
367   abuf_init(&body, 0);
368   abuf_init(&header, 0);
369
370   if (curr_clients >= MAX_CLIENTS) {
371     return;
372   }
373   curr_clients++;
374
375   addrlen = sizeof(pin);
376   client_sockets[curr_clients] = accept(fd, (struct sockaddr *)&pin, &addrlen);
377   if (client_sockets[curr_clients] == -1) {
378     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) accept: %s\n", strerror(errno));
379     goto close_connection;
380   }
381
382   if (((struct sockaddr *)&pin)->sa_family != olsr_cnf->ip_version) {
383     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Connection with wrong IP version?!\n");
384     goto close_connection;
385   }
386
387   if (olsr_cnf->ip_version == AF_INET) {
388     struct sockaddr_in *addr4 = (struct sockaddr_in *)&pin;
389     ipaddr = (union olsr_ip_addr *)&addr4->sin_addr;
390   } else {
391     struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pin;
392     ipaddr = (union olsr_ip_addr *)&addr6->sin6_addr;
393   }
394
395   if (!ip_acl_acceptable(&allowed_nets, ipaddr, olsr_cnf->ip_version)) {
396 #if !defined REMOVE_LOG_WARN
397     struct ipaddr_str strbuf;
398 #endif
399     OLSR_WARN(LOG_PLUGINS, "HTTP request from non-allowed host %s!\n", olsr_ip_to_string(&strbuf, ipaddr));
400     goto close_connection;
401   }
402
403   memset(req, 0, sizeof(req));
404   //memset(body, 0, sizeof(body));
405
406   while ((r = recv(client_sockets[curr_clients], &req[c], 1, 0)) > 0 && (c < sizeof(req) - 1)) {
407     c++;
408
409     if ((c > 3 && !strcmp(&req[c - 4], "\r\n\r\n")) || (c > 1 && !strcmp(&req[c - 2], "\n\n")))
410       break;
411   }
412
413   if (r < 0) {
414     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Failed to recieve data from client!\n");
415     stats.err_hits++;
416     goto close_connection;
417   }
418
419   /* Get the request */
420   if (sscanf(req, "%10s %250s %10s\n", req_type, filename, http_version) != 3) {
421     /* Try without HTTP version */
422     if (sscanf(req, "%10s %250s\n", req_type, filename) != 2) {
423       OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Error parsing request %s!\n", req);
424       stats.err_hits++;
425       goto close_connection;
426     }
427   }
428
429   OLSR_DEBUG(LOG_PLUGINS, "Request: %s\nfile: %s\nVersion: %s\n\n", req_type, filename, http_version);
430
431   if (!strcmp(req_type, "POST")) {
432 #if ADMIN_INTERFACE
433     int i = 0;
434     while (dynamic_files[i].filename) {
435       OLSR_DEBUG(LOG_PLUGINS, "POST checking %s\n", dynamic_files[i].filename);
436       if (FILENREQ_MATCH(filename, dynamic_files[i].filename)) {
437         uint32_t param_size;
438
439         stats.ok_hits++;
440
441         param_size = recv(client_sockets[curr_clients], req, sizeof(req) - 1, 0);
442
443         req[param_size] = '\0';
444         OLSR_DEBUG(LOG_PLUGINS, "Dynamic read %d bytes\n", param_size);
445
446         //memcpy(body, dynamic_files[i].data, static_bin_files[i].data_size);
447         //size += dynamic_files[i].process_data_cb(req, param_size, &body[size], sizeof(body)-size);
448         dynamic_files[i].process_data_cb(req, param_size, &body);
449
450         build_http_header(&header, HTTP_OK, true, body.len);
451         goto send_http_data;
452       }
453       i++;
454     }
455 #endif
456     /* We only support GET */
457     abuf_puts(&body, HTTP_400_MSG);
458     stats.ill_hits++;
459     build_http_header(&header, HTTP_BAD_REQ, true, body.len);
460   } else if (!strcmp(req_type, "GET")) {
461     int i = 0;
462
463     for (i = 0; static_bin_files[i].filename; i++) {
464       if (FILENREQ_MATCH(filename, static_bin_files[i].filename)) {
465         break;
466       }
467     }
468
469     if (static_bin_files[i].filename) {
470       stats.ok_hits++;
471       //memcpy(body, static_bin_files[i].data, static_bin_files[i].data_size);
472       abuf_memcpy(&body, static_bin_files[i].data, static_bin_files[i].data_size);
473       //size = static_bin_files[i].data_size;
474       build_http_header(&header, HTTP_OK, false, body.len);
475       goto send_http_data;
476     }
477
478     i = 0;
479     while (static_txt_files[i].filename) {
480       if (FILENREQ_MATCH(filename, static_txt_files[i].filename)) {
481         break;
482       }
483       i++;
484     }
485
486     if (static_txt_files[i].filename) {
487       stats.ok_hits++;
488
489       //size += snprintf(&body[size], sizeof(body)-size, "%s", static_txt_files[i].data);
490       abuf_puts(&body, static_txt_files[i].data);
491
492       build_http_header(&header, HTTP_OK, false, body.len);
493       goto send_http_data;
494     }
495
496     i = 0;
497     if (strlen(filename) > 1) {
498       while (tab_entries[i].filename) {
499         if (FILENREQ_MATCH(filename, tab_entries[i].filename)) {
500           break;
501         }
502         i++;
503       }
504     }
505
506     if (tab_entries[i].filename) {
507 #ifdef NETDIRECT
508       build_http_header(&header, HTTP_OK, true);
509       r = send(client_sockets[curr_clients], req, c, 0);
510       if (r < 0) {
511         OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Failed sending data to client!\n");
512         goto close_connection;
513       }
514       netsprintf_error = 0;
515       netsprintf_direct = 1;
516 #endif
517       abuf_appendf(&body,
518                    "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
519                    "<head>\n"
520                    "<meta http-equiv=\"Content-type\" content=\"text/html; charset=ISO-8859-1\">\n"
521                    "<title>olsr.org httpinfo plugin</title>\n"
522                    "<link rel=\"icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
523                    "<link rel=\"shortcut icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
524                    "<link rel=\"stylesheet\" type=\"text/css\" href=\"httpinfo.css\">\n"
525                    "</head>\n"
526                    "<body bgcolor=\"#ffffff\" text=\"#000000\">\n"
527                    "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
528                    "<tbody><tr bgcolor=\"#ffffff\">\n"
529                    "<td height=\"69\" valign=\"middle\" width=\"80%%\">\n"
530                    "<font color=\"black\" face=\"timesroman\" size=\"6\">&nbsp;&nbsp;&nbsp;<a href=\"http://www.olsr.org/\">olsr.org OLSR daemon</a></font></td>\n"
531                    "<td height=\"69\" valign=\"middle\" width=\"20%%\">\n"
532                    "<a href=\"http://www.olsr.org/\"><img border=\"0\" src=\"/logo.gif\" alt=\"olsrd logo\"></a></td>\n"
533                    "</tr>\n" "</tbody>\n" "</table>\n", FRAMEWIDTH);
534
535       build_tabs(&body, i);
536       build_frame(&body, tab_entries[i].build_body_cb);
537
538       stats.ok_hits++;
539
540       abuf_appendf(&body,
541                    "</table>\n"
542                    "<div id=\"footer\">\n"
543                    "<center>\n"
544                    "(C)2005 Andreas T&oslash;nnesen<br/>\n"
545                    "<a href=\"http://www.olsr.org/\">http://www.olsr.org</a>\n" "</center>\n" "</div>\n" "</body>\n" "</html>\n");
546
547 #ifdef NETDIRECT
548       netsprintf_direct = 1;
549       goto close_connection;
550 #else
551       build_http_header(&header, HTTP_OK, true, body.len);
552       goto send_http_data;
553 #endif
554     }
555
556
557     stats.ill_hits++;
558     abuf_puts(&body, HTTP_404_MSG);
559     build_http_header(&header, HTTP_BAD_FILE, true, body.len);
560   } else {
561     /* We only support GET */
562     abuf_puts(&body, HTTP_400_MSG);
563     stats.ill_hits++;
564     build_http_header(&header, HTTP_BAD_REQ, true, body.len);
565   }
566
567 send_http_data:
568
569   r = writen(client_sockets[curr_clients], header.buf, header.len);
570   if (r < 0) {
571     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Failed sending data to client!\n");
572     goto close_connection;
573   }
574
575   r = writen(client_sockets[curr_clients], body.buf, body.len);
576   if (r < 0) {
577     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Failed sending data to client!\n");
578     goto close_connection;
579   }
580
581 close_connection:
582   abuf_free(&body);
583   abuf_free(&header);
584   CLOSESOCKET(client_sockets[curr_clients]);
585   curr_clients--;
586 }
587
588
589 void
590 build_http_header(struct autobuf *abuf, http_header_type type, bool is_html, uint32_t msgsize)
591 {
592   time_t currtime;
593   const char *h;
594
595   switch (type) {
596   case HTTP_BAD_REQ:
597     h = HTTP_400;
598     break;
599   case HTTP_BAD_FILE:
600     h = HTTP_404;
601     break;
602   default:
603     /* Defaults to OK */
604     h = HTTP_200;
605     break;
606   }
607   abuf_puts(abuf, h);
608
609   /* Date */
610   time(&currtime);
611   abuf_strftime(abuf, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", localtime(&currtime));
612
613   /* Server version */
614   abuf_appendf(abuf, "Server: %s %s %s\r\n", PLUGIN_NAME, PLUGIN_VERSION, HTTP_VERSION);
615
616   /* connection-type */
617   abuf_puts(abuf, "Connection: closed\r\n");
618
619   /* MIME type */
620   abuf_appendf(abuf, "Content-type: text/%s\r\n", is_html ? "html" : "plain");
621
622   /* Content length */
623   if (msgsize > 0) {
624     abuf_appendf(abuf, "Content-length: %u\r\n", msgsize);
625   }
626
627   /* Cache-control
628    * No caching dynamic pages
629    */
630   abuf_puts(abuf, "Cache-Control: no-cache\r\n");
631
632   if (!is_html) {
633     abuf_puts(abuf, "Accept-Ranges: bytes\r\n");
634   }
635   /* End header */
636   abuf_puts(abuf, "\r\n");
637
638   OLSR_DEBUG(LOG_PLUGINS, "HEADER:\n%s", abuf->buf);
639 }
640
641
642 static void
643 build_tabs(struct autobuf *abuf, int active)
644 {
645   int tabs;
646
647   abuf_appendf(abuf,
648                "<table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
649                "<tr bgcolor=\"#ffffff\"><td>\n" "<ul id=\"tabnav\">\n", FRAMEWIDTH);
650   for (tabs = 0; tab_entries[tabs].tab_label; tabs++) {
651     if (!tab_entries[tabs].display_tab) {
652       continue;
653     }
654     abuf_appendf(abuf,
655                  "<li><a href=\"%s\"%s>%s</a></li>\n",
656                  tab_entries[tabs].filename, tabs == active ? " class=\"active\"" : "", tab_entries[tabs].tab_label);
657   }
658   abuf_appendf(abuf, "</ul>\n" "</td></tr>\n" "<tr><td>\n");
659 }
660
661
662 /*
663  * destructor - called at unload
664  */
665 void
666 olsr_plugin_exit(void)
667 {
668   ip_acl_flush(&allowed_nets);
669
670   if (http_socket >= 0) {
671     CLOSESOCKET(http_socket);
672   }
673 }
674
675
676 static void
677 section_title(struct autobuf *abuf, const char *title)
678 {
679   abuf_appendf(abuf,
680                "<h2>%s</h2>\n"
681                "<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" align=\"center\">\n", title);
682 }
683
684 static void
685 build_frame(struct autobuf *abuf, build_body_callback frame_body_cb)
686 {
687   abuf_puts(abuf, "<div id=\"maintable\">\n");
688   frame_body_cb(abuf);
689   abuf_puts(abuf, "</div>\n");
690 }
691
692 static void
693 fmt_href(struct autobuf *abuf, const char *const ipaddr)
694 {
695   abuf_appendf(abuf, "<a href=\"http://%s:%d/all\">", ipaddr, http_port);
696 }
697
698 static void
699 build_ip_txt(struct autobuf *abuf, const bool print_link, const char *const ipaddrstr, const int prefix_len)
700 {
701   if (print_link) {
702     fmt_href(abuf, ipaddrstr);
703   }
704
705   abuf_puts(abuf, ipaddrstr);
706   /* print ip address or ip prefix ? */
707   if (prefix_len != -1 && prefix_len != 8 * (int)olsr_cnf->ipsize) {
708     abuf_appendf(abuf, "/%d", prefix_len);
709   }
710
711   if (print_link) {             /* Print the link only if there is no prefix_len */
712     abuf_puts(abuf, "</a>");
713   }
714 }
715
716 static void
717 build_ipaddr_link(struct autobuf *abuf, const bool want_link, const union olsr_ip_addr *const ipaddr, const int prefix_len)
718 {
719   struct ipaddr_str ipaddrstr;
720   const struct hostent *const hp =
721 #ifndef WIN32
722     resolve_ip_addresses ? gethostbyaddr(ipaddr, olsr_cnf->ipsize, olsr_cnf->ip_version) :
723 #endif
724     NULL;
725   /* Print the link only if there is no prefix_len */
726   const int print_link = want_link && (prefix_len == -1 || prefix_len == 8 * (int)olsr_cnf->ipsize);
727   olsr_ip_to_string(&ipaddrstr, ipaddr);
728
729   abuf_puts(abuf, "<td>");
730   build_ip_txt(abuf, print_link, ipaddrstr.buf, prefix_len);
731   abuf_puts(abuf, "</td>");
732
733   if (resolve_ip_addresses) {
734     if (hp) {
735       abuf_puts(abuf, "<td>(");
736       if (print_link) {
737         fmt_href(abuf, ipaddrstr.buf);
738       }
739       abuf_puts(abuf, hp->h_name);
740       if (print_link) {
741         abuf_puts(abuf, "</a>");
742       }
743       abuf_puts(abuf, ")</td>");
744     } else {
745       abuf_puts(abuf, "<td/>");
746     }
747   }
748 }
749
750 #define build_ipaddr_with_link(abuf, ipaddr, plen) \
751           build_ipaddr_link((abuf), true, (ipaddr), (plen))
752 #define build_ipaddr_no_link(abuf, ipaddr, plen) \
753           build_ipaddr_link((abuf), false, (ipaddr), (plen))
754
755 static void
756 build_route(struct autobuf *abuf, const struct rt_entry *rt)
757 {
758   struct lqtextbuffer lqbuffer;
759
760   abuf_puts(abuf, "<tr>");
761   build_ipaddr_with_link(abuf, &rt->rt_dst.prefix, rt->rt_dst.prefix_len);
762   build_ipaddr_with_link(abuf, &rt->rt_best->rtp_nexthop.gateway, -1);
763
764   abuf_appendf(abuf, "<td>%u</td>", rt->rt_best->rtp_metric.hops);
765   abuf_appendf(abuf, "<td>%s</td>", get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer));
766   abuf_appendf(abuf,
767                "<td>%s</td></tr>\n", rt->rt_best->rtp_nexthop.interface ? rt->rt_best->rtp_nexthop.interface->int_name : "[null]");
768 }
769
770 static void
771 build_routes_body(struct autobuf *abuf)
772 {
773   struct rt_entry *rt;
774   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
775   section_title(abuf, "OLSR Routes in Kernel");
776   abuf_appendf(abuf,
777                "<tr><th%s>Destination</th><th%s>Gateway</th><th>Metric</th><th>ETX</th><th>Interface</th></tr>\n",
778                colspan, colspan);
779
780   /* Walk the route table */
781   OLSR_FOR_ALL_RT_ENTRIES(rt) {
782     build_route(abuf, rt);
783   } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
784
785   abuf_puts(abuf, "</table>\n");
786 }
787
788 static void
789 build_config_body(struct autobuf *abuf)
790 {
791   const struct olsr_if_config *ifs;
792   const struct plugin_entry *pentry;
793   const struct plugin_param *pparam;
794   struct ipaddr_str mainaddrbuf;
795   struct millitxt_buf tbuf;
796
797   abuf_appendf(abuf, "Version: %s (built on %s on %s)\n<br>OS: %s\n<br>", olsrd_version, build_date, build_host, OS);
798   {
799     const time_t currtime = time(NULL);
800     abuf_strftime(abuf, "System time: <em>%a, %d %b %Y %H:%M:%S</em><br>", localtime(&currtime));
801   }
802
803   {
804     struct timeval now, uptime;
805     int hours, mins, days;
806     gettimeofday(&now, NULL);
807     timersub(&now, &start_time, &uptime);
808
809     days = uptime.tv_sec / 86400;
810     uptime.tv_sec %= 86400;
811     hours = uptime.tv_sec / 3600;
812     uptime.tv_sec %= 3600;
813     mins = uptime.tv_sec / 60;
814     uptime.tv_sec %= 60;
815
816     abuf_puts(abuf, "Olsrd uptime: <em>");
817     if (days) {
818       abuf_appendf(abuf, "%d day(s) ", days);
819     }
820     abuf_appendf(abuf, "%02d hours %02d minutes %02d seconds</em><br/>\n", hours, mins, (int)uptime.tv_sec);
821   }
822
823   abuf_appendf(abuf, "HTTP stats(ok/dyn/error/illegal): <em>%u/%u/%u/%u</em><br>\n", stats.ok_hits, stats.dyn_hits, stats.err_hits,
824                stats.ill_hits);
825
826   abuf_appendf(abuf, "Click <a href=\"/cfgfile\">here</a> to <em>generate a configuration file for this node</em>.\n");
827
828   abuf_puts(abuf, "<h2>Variables</h2>\n");
829
830   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n<tr>");
831
832   abuf_appendf(abuf, "<td>Main address: <strong>%s</strong></td>\n", olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->router_id));
833   abuf_appendf(abuf, "<td>IP version: %d</td>\n", olsr_cnf->ip_version == AF_INET ? 4 : 6);
834
835   // TODO: add logging information into http info ?
836   abuf_appendf(abuf, "<td></td>\n");
837   abuf_appendf(abuf, "<td>FIB Metrics: %s</td>\n",
838                FIBM_FLAT == olsr_cnf->fib_metric ? CFG_FIBM_FLAT : FIBM_CORRECT ==
839                olsr_cnf->fib_metric ? CFG_FIBM_CORRECT : CFG_FIBM_APPROX);
840
841   abuf_puts(abuf, "</tr>\n<tr>\n");
842
843   abuf_appendf(abuf, "<td>Pollrate: %s</td>\n", olsr_milli_to_txt(&tbuf, olsr_cnf->pollrate));
844   abuf_appendf(abuf, "<td>TC redundancy: %d</td>\n", olsr_cnf->tc_redundancy);
845   abuf_appendf(abuf, "<td>MPR coverage: %d</td>\n", olsr_cnf->mpr_coverage);
846   abuf_appendf(abuf, "<td>NAT threshold: %s</td>\n", olsr_milli_to_txt(&tbuf, olsr_cnf->lq_nat_thresh));
847
848   abuf_puts(abuf, "</tr>\n<tr>\n");
849
850   abuf_appendf(abuf, "<td>Fisheye: %s</td>\n", olsr_cnf->lq_fish ? "Enabled" : "Disabled");
851   abuf_appendf(abuf, "<td>TOS: 0x%04x</td>\n", olsr_cnf->tos);
852   abuf_appendf(abuf, "<td>RtTable: 0x%04x/%d</td>\n", olsr_cnf->rttable, olsr_cnf->rttable);
853   abuf_appendf(abuf, "<td>RtTableDefault: 0x%04x/%d</td>\n", olsr_cnf->rttable_default, olsr_cnf->rttable_default);
854   abuf_appendf(abuf, "<td>Willingness: %d %s</td>\n", olsr_cnf->willingness, olsr_cnf->willingness_auto ? "(auto)" : "");
855
856   abuf_puts(abuf, "</tr></table>\n");
857
858   abuf_puts(abuf, "<h2>Interfaces</h2>\n");
859   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n");
860   for (ifs = olsr_cnf->if_configs; ifs != NULL; ifs = ifs->next) {
861     const struct interface *const rifs = ifs->interf;
862     abuf_appendf(abuf, "<tr><th colspan=\"3\">%s</th>\n", ifs->name);
863     if (!rifs) {
864       abuf_puts(abuf, "<tr><td colspan=\"3\">Status: DOWN</td></tr>\n");
865       continue;
866     }
867
868     if (olsr_cnf->ip_version == AF_INET) {
869       struct ipaddr_str addrbuf, maskbuf, bcastbuf;
870       abuf_appendf(abuf,
871                    "<tr>\n"
872                    "<td>IP: %s</td>\n"
873                    "<td>MASK: %s</td>\n"
874                    "<td>BCAST: %s</td>\n"
875                    "</tr>\n",
876                    ip4_to_string(&addrbuf, rifs->int_addr.sin_addr),
877                    ip4_to_string(&maskbuf, rifs->int_netmask.sin_addr), ip4_to_string(&bcastbuf, rifs->int_broadaddr.sin_addr));
878     } else {
879       struct ipaddr_str addrbuf, maskbuf;
880       abuf_appendf(abuf,
881                    "<tr>\n"
882                    "<td>IP: %s</td>\n"
883                    "<td>MCAST: %s</td>\n"
884                    "<td></td>\n"
885                    "</tr>\n",
886                    ip6_to_string(&addrbuf, &rifs->int6_addr.sin6_addr), ip6_to_string(&maskbuf, &rifs->int6_multaddr.sin6_addr));
887     }
888     abuf_appendf(abuf,
889                  "<tr>\n"
890                  "<td>MTU: %d</td>\n"
891                  "<td>WLAN: %s</td>\n" "<td>STATUS: UP</td>\n" "</tr>\n", rifs->int_mtu, rifs->is_wireless ? "Yes" : "No");
892   }
893   abuf_puts(abuf, "</table>\n");
894
895   abuf_appendf(abuf,
896                "<em>Olsrd is configured to %s if no interfaces are available</em><br>\n",
897                olsr_cnf->allow_no_interfaces ? "run even" : "halt");
898
899   abuf_puts(abuf, "<h2>Plugins</h2>\n");
900   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\"><tr><th>Name</th><th>Parameters</th></tr>\n");
901   for (pentry = olsr_cnf->plugins; pentry; pentry = pentry->next) {
902     abuf_appendf(abuf, "<tr><td>%s</td>\n" "<td><select>\n" "<option>KEY, VALUE</option>\n", pentry->name);
903
904     for (pparam = pentry->params; pparam; pparam = pparam->next) {
905       abuf_appendf(abuf, "<option>\"%s\", \"%s\"</option>\n", pparam->key, pparam->value);
906     }
907     abuf_puts(abuf, "</select></td></tr>\n");
908
909   }
910   abuf_puts(abuf, "</table>\n");
911
912   section_title(abuf, "Announced HNA entries");
913   if (list_is_empty(&olsr_cnf->hna_entries)) {
914     struct ip_prefix_entry *hna;
915     abuf_puts(abuf, "<tr><th>Network</th></tr>\n");
916     OLSR_FOR_ALL_IPPREFIX_ENTRIES(&olsr_cnf->hna_entries, hna) {
917       struct ipprefix_str netbuf;
918       abuf_appendf(abuf, "<tr><td>%s</td></tr>\n", olsr_ip_prefix_to_string(&netbuf, &hna->net));
919     } OLSR_FOR_ALL_IPPREFIX_ENTRIES_END()
920   } else {
921     abuf_puts(abuf, "<tr><td></td></tr>\n");
922   }
923   abuf_puts(abuf, "</table>\n");
924 }
925
926 static void
927 build_neigh_body(struct autobuf *abuf)
928 {
929   struct nbr_entry *neigh;
930   struct link_entry *lnk;
931   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
932
933   section_title(abuf, "Links");
934
935   abuf_appendf(abuf, "<tr><th%s>Local IP</th><th%s>Remote IP</th>", colspan, colspan);
936   abuf_puts(abuf, "<th>LinkCost</th>");
937   abuf_puts(abuf, "</tr>\n");
938
939   /* Link set */
940   OLSR_FOR_ALL_LINK_ENTRIES(lnk) {
941     struct lqtextbuffer lqbuffer1, lqbuffer2;
942     abuf_puts(abuf, "<tr>");
943     build_ipaddr_with_link(abuf, &lnk->local_iface_addr, -1);
944     build_ipaddr_with_link(abuf, &lnk->neighbor_iface_addr, -1);
945     abuf_appendf(abuf,
946                  "<td>(%s) %s</td>",
947                  get_link_entry_text(lnk, '/', &lqbuffer1), get_linkcost_text(lnk->linkcost, false, &lqbuffer2));
948     abuf_puts(abuf, "</tr>\n");
949   } OLSR_FOR_ALL_LINK_ENTRIES_END(lnk);
950
951   abuf_puts(abuf, "</table>\n");
952
953   section_title(abuf, "Neighbors");
954   abuf_appendf(abuf,
955                "<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",
956                colspan);
957   /* Neighbors */
958   OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
959     struct nbr_con *connector;
960     int thop_cnt;
961     abuf_puts(abuf, "<tr>");
962     build_ipaddr_with_link(abuf, &neigh->nbr_addr, -1);
963     abuf_appendf(abuf,
964                  "<td>%s</td>"
965                  "<td>%s</td>"
966                  "<td>%s</td>"
967                  "<td>%d</td>",
968                  neigh->is_sym ? "YES" : "NO",
969                  neigh->is_mpr ? "YES" : "NO",
970                  neigh->mprs_count > 0 ? "YES" : "NO",
971                  neigh->willingness);
972
973     abuf_puts(abuf, "<td><select>\n" "<option>IP ADDRESS</option>\n");
974
975     thop_cnt = 0;
976     OLSR_FOR_ALL_NBR_CON_ENTRIES(neigh, connector) {
977       struct ipaddr_str strbuf;
978       abuf_appendf(abuf, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &connector->nbr2->nbr2_addr));
979       thop_cnt++;
980     } OLSR_FOR_ALL_NBR_CON_ENTRIES_END(neigh, connector);
981     abuf_appendf(abuf, "</select> (%d)</td></tr>\n", thop_cnt);
982   } OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
983
984   abuf_puts(abuf, "</table>\n");
985 }
986
987 static void
988 build_topo_body(struct autobuf *abuf)
989 {
990   struct tc_entry *tc;
991   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
992
993   section_title(abuf, "Topology Entries");
994   abuf_appendf(abuf, "<tr><th%s>Destination IP</th><th%s>Last Hop IP</th>", colspan, colspan);
995   abuf_puts(abuf, "<th colspan=\"3\">Linkcost</th>");
996   abuf_puts(abuf, "</tr>\n");
997
998   OLSR_FOR_ALL_TC_ENTRIES(tc) {
999     struct tc_edge_entry *tc_edge;
1000     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
1001       if (tc_edge->edge_inv) {
1002         struct lqtextbuffer lqbuffer1, lqbuffer2;
1003         abuf_puts(abuf, "<tr>");
1004         build_ipaddr_with_link(abuf, &tc_edge->T_dest_addr, -1);
1005         build_ipaddr_with_link(abuf, &tc->addr, -1);
1006         abuf_appendf(abuf,
1007                      "<td>(%s)</td><td>&nbsp;</td><td>%s</td>\n",
1008                      get_tc_edge_entry_text(tc_edge, '/', &lqbuffer1), get_linkcost_text(tc_edge->cost, false, &lqbuffer2));
1009         abuf_puts(abuf, "</tr>\n");
1010       }
1011     } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
1012   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
1013
1014   abuf_puts(abuf, "</table>\n");
1015 }
1016
1017 static void
1018 build_mid_body(struct autobuf *abuf)
1019 {
1020   struct tc_entry *tc;
1021   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1022
1023   section_title(abuf, "MID Entries");
1024   abuf_appendf(abuf, "<tr><th%s>Main Address</th><th>Aliases</th></tr>\n", colspan);
1025
1026   /* MID */
1027   OLSR_FOR_ALL_TC_ENTRIES(tc) {
1028     struct mid_entry *alias;
1029     abuf_puts(abuf, "<tr>");
1030     build_ipaddr_with_link(abuf, &tc->addr, -1);
1031     abuf_puts(abuf, "<td><select>\n<option>IP ADDRESS</option>\n");
1032
1033     OLSR_FOR_ALL_TC_MID_ENTRIES(tc, alias) {
1034       struct ipaddr_str strbuf;
1035       abuf_appendf(abuf, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &alias->mid_alias_addr));
1036     } OLSR_FOR_ALL_TC_MID_ENTRIES_END(tc, alias);
1037     abuf_appendf(abuf, "</select> (%u)</td></tr>\n", tc->mid_tree.count);
1038   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
1039
1040   abuf_puts(abuf, "</table>\n");
1041 }
1042
1043
1044 static void
1045 build_nodes_body(struct autobuf *abuf)
1046 {
1047   build_neigh_body(abuf);
1048   build_topo_body(abuf);
1049   build_mid_body(abuf);
1050 }
1051
1052 static void
1053 build_all_body(struct autobuf *abuf)
1054 {
1055   build_config_body(abuf);
1056   build_routes_body(abuf);
1057   build_nodes_body(abuf);
1058 }
1059
1060
1061 static void
1062 build_about_body(struct autobuf *abuf)
1063 {
1064   abuf_appendf(abuf,
1065                "<strong>" PLUGIN_NAME " version " PLUGIN_VERSION "</strong><br/>\n"
1066                "by Andreas T&oslash;nnesen (C)2005.<br/>\n" "Compiled "
1067 #if ADMIN_INTERFACE
1068                "<em>with experimental admin interface</em> "
1069 #endif
1070                "%s at %s<hr/>\n"
1071                "This plugin implements a HTTP server that supplies\n"
1072                "the client with various dynamic web pages representing\n"
1073                "the current olsrd status.<br/>The different pages include:\n"
1074                "<ul>\n<li><strong>Configuration</strong> - This page displays information\n"
1075                "about the current olsrd configuration. This includes various\n"
1076                "olsr settings such as IP version, MID/TC redundancy, hysteresis\n"
1077                "etc. Information about the current status of the interfaces on\n"
1078                "which olsrd is configured to run is also displayed. Loaded olsrd\n"
1079                "plugins are shown with their plugin parameters. Finally all local\n"
1080                "HNA entries are shown. These are the networks that the local host\n"
1081                "will anounce itself as a gateway to.</li>\n"
1082                "<li><strong>Routes</strong> - This page displays all routes currently set in\n"
1083                "the kernel <em>by olsrd</em>. The type of route is also displayed(host\n"
1084                "or HNA).</li>\n"
1085                "<li><strong>Links/Topology</strong> - This page displays all information about\n"
1086                "links, neighbors, topology, MID and HNA entries.</li>\n"
1087                "<li><strong>All</strong> - Here all the previous pages are displayed as one.\n"
1088                "This is to make all information available as easy as possible(for example\n"
1089                "for a script) and using as few resources as possible.</li>\n"
1090 #if ADMIN_INTERFACE
1091                "<li><strong>Admin</strong> - This page is highly experimental(and unsecure)!\n"
1092                "As of now it is not working at all but it provides a impression of\n"
1093                "the future possibilities of httpinfo. This is to be a interface to\n"
1094                "changing olsrd settings in realtime. These settings include various\n"
1095                "\"basic\" settings and local HNA settings.</li>\n"
1096 #endif
1097                "<li><strong>About</strong> - this help page.</li>\n</ul>"
1098                "<hr/>\n"
1099                "Send questions or comments to\n"
1100                "<a href=\"mailto:olsr-users@olsr.org\">olsr-users@olsr.org</a> or\n"
1101                "<a href=\"mailto:andreto-at-olsr.org\">andreto-at-olsr.org</a><br/>\n"
1102                "Official olsrd homepage: <a href=\"http://www.olsr.org/\">http://www.olsr.org</a><br/>\n", build_date, build_host);
1103 }
1104
1105 static void
1106 build_cfgfile_body(struct autobuf *abuf)
1107 {
1108   abuf_puts(abuf,
1109             "\n\n"
1110             "<strong>This is an automatically generated configuration\n"
1111             "file based on the current olsrd configuration of this node.</strong><br/>\n" "<hr/>\n" "<pre>\n");
1112
1113 #ifdef NETDIRECT
1114   {
1115     /* Hack to make netdirect stuff work with
1116        olsr_write_cnf_buf
1117      */
1118     char tmpBuf[10000];
1119     size = olsr_write_cnf_buf(olsr_cnf, true, tmpBuf, 10000);
1120     snprintf(&buf[size], bufsize - size, tmpBuf);
1121   }
1122 #else
1123   olsr_write_cnf_buf(abuf, olsr_cnf, true);
1124 #endif
1125
1126   abuf_puts(abuf, "</pre>\n<hr/>\n");
1127 }
1128
1129 #if 0
1130
1131 /*
1132  * In a bigger mesh, there are probs with the fixed
1133  * bufsize. Because the Content-Length header is
1134  * optional, the sprintf() is changed to a more
1135  * scalable solution here.
1136  */
1137
1138 int
1139 netsprintf(char *str, const char *format, ...)
1140 {
1141   va_list arg;
1142   int rv;
1143   va_start(arg, format);
1144   rv = vsprintf(str, format, arg);
1145   va_end(arg);
1146   if (0 != netsprintf_direct) {
1147     if (0 == netsprintf_error) {
1148       if (0 > send(client_sockets[curr_clients], str, rv, 0)) {
1149         OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Failed sending data to client!\n");
1150         netsprintf_error = 1;
1151       }
1152     }
1153     return 0;
1154   }
1155   return rv;
1156 }
1157 #endif
1158
1159 static ssize_t
1160 writen(int fd, const void *buf, size_t count)
1161 {
1162   size_t bytes_left = count;
1163   const char *p = buf;
1164   while (bytes_left > 0) {
1165     const ssize_t written = write(fd, p, bytes_left);
1166     if (written == -1) {        /* error */
1167       if (errno == EINTR) {
1168         continue;
1169       }
1170       return -1;
1171     }
1172     /* We wrote something */
1173     bytes_left -= written;
1174     p += written;
1175   }
1176   return count;
1177 }
1178
1179 /*
1180  * Local Variables:
1181  * c-basic-offset: 2
1182  * indent-tabs-mode: nil
1183  * End:
1184  */