61f74e1810b22ba7c30d2b26264409db0f32a735
[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
796   abuf_appendf(abuf, "Version: %s (built on %s on %s)\n<br>OS: %s\n<br>", olsrd_version, build_date, build_host, OS);
797   {
798     const time_t currtime = time(NULL);
799     abuf_strftime(abuf, "System time: <em>%a, %d %b %Y %H:%M:%S</em><br>", localtime(&currtime));
800   }
801
802   {
803     struct timeval now, uptime;
804     int hours, mins, days;
805     gettimeofday(&now, NULL);
806     timersub(&now, &start_time, &uptime);
807
808     days = uptime.tv_sec / 86400;
809     uptime.tv_sec %= 86400;
810     hours = uptime.tv_sec / 3600;
811     uptime.tv_sec %= 3600;
812     mins = uptime.tv_sec / 60;
813     uptime.tv_sec %= 60;
814
815     abuf_puts(abuf, "Olsrd uptime: <em>");
816     if (days) {
817       abuf_appendf(abuf, "%d day(s) ", days);
818     }
819     abuf_appendf(abuf, "%02d hours %02d minutes %02d seconds</em><br/>\n", hours, mins, (int)uptime.tv_sec);
820   }
821
822   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,
823                stats.ill_hits);
824
825   abuf_appendf(abuf, "Click <a href=\"/cfgfile\">here</a> to <em>generate a configuration file for this node</em>.\n");
826
827   abuf_puts(abuf, "<h2>Variables</h2>\n");
828
829   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n<tr>");
830
831   abuf_appendf(abuf, "<td>Main address: <strong>%s</strong></td>\n", olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->router_id));
832   abuf_appendf(abuf, "<td>IP version: %d</td>\n", olsr_cnf->ip_version == AF_INET ? 4 : 6);
833
834   // TODO: add logging information into http info ?
835   abuf_appendf(abuf, "<td></td>\n");
836   abuf_appendf(abuf, "<td>FIB Metrics: %s</td>\n",
837                FIBM_FLAT == olsr_cnf->fib_metric ? CFG_FIBM_FLAT : FIBM_CORRECT ==
838                olsr_cnf->fib_metric ? CFG_FIBM_CORRECT : CFG_FIBM_APPROX);
839
840   abuf_puts(abuf, "</tr>\n<tr>\n");
841
842   abuf_appendf(abuf, "<td>Pollrate: %0.2f</td>\n", conv_pollrate_to_secs(olsr_cnf->pollrate));
843   abuf_appendf(abuf, "<td>TC redundancy: %d</td>\n", olsr_cnf->tc_redundancy);
844   abuf_appendf(abuf, "<td>MPR coverage: %d</td>\n", olsr_cnf->mpr_coverage);
845   abuf_appendf(abuf, "<td>NAT threshold: %f</td>\n", olsr_cnf->lq_nat_thresh);
846
847   abuf_puts(abuf, "</tr>\n<tr>\n");
848
849   abuf_appendf(abuf, "<td>Fisheye: %s</td>\n", olsr_cnf->lq_fish ? "Enabled" : "Disabled");
850   abuf_appendf(abuf, "<td>TOS: 0x%04x</td>\n", olsr_cnf->tos);
851   abuf_appendf(abuf, "<td>RtTable: 0x%04x/%d</td>\n", olsr_cnf->rttable, olsr_cnf->rttable);
852   abuf_appendf(abuf, "<td>RtTableDefault: 0x%04x/%d</td>\n", olsr_cnf->rttable_default, olsr_cnf->rttable_default);
853   abuf_appendf(abuf, "<td>Willingness: %d %s</td>\n", olsr_cnf->willingness, olsr_cnf->willingness_auto ? "(auto)" : "");
854
855   abuf_puts(abuf, "</tr></table>\n");
856
857   abuf_puts(abuf, "<h2>Interfaces</h2>\n");
858   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n");
859   for (ifs = olsr_cnf->if_configs; ifs != NULL; ifs = ifs->next) {
860     const struct interface *const rifs = ifs->interf;
861     abuf_appendf(abuf, "<tr><th colspan=\"3\">%s</th>\n", ifs->name);
862     if (!rifs) {
863       abuf_puts(abuf, "<tr><td colspan=\"3\">Status: DOWN</td></tr>\n");
864       continue;
865     }
866
867     if (olsr_cnf->ip_version == AF_INET) {
868       struct ipaddr_str addrbuf, maskbuf, bcastbuf;
869       abuf_appendf(abuf,
870                    "<tr>\n"
871                    "<td>IP: %s</td>\n"
872                    "<td>MASK: %s</td>\n"
873                    "<td>BCAST: %s</td>\n"
874                    "</tr>\n",
875                    ip4_to_string(&addrbuf, rifs->int_addr.sin_addr),
876                    ip4_to_string(&maskbuf, rifs->int_netmask.sin_addr), ip4_to_string(&bcastbuf, rifs->int_broadaddr.sin_addr));
877     } else {
878       struct ipaddr_str addrbuf, maskbuf;
879       abuf_appendf(abuf,
880                    "<tr>\n"
881                    "<td>IP: %s</td>\n"
882                    "<td>MCAST: %s</td>\n"
883                    "<td></td>\n"
884                    "</tr>\n",
885                    ip6_to_string(&addrbuf, &rifs->int6_addr.sin6_addr), ip6_to_string(&maskbuf, &rifs->int6_multaddr.sin6_addr));
886     }
887     abuf_appendf(abuf,
888                  "<tr>\n"
889                  "<td>MTU: %d</td>\n"
890                  "<td>WLAN: %s</td>\n" "<td>STATUS: UP</td>\n" "</tr>\n", rifs->int_mtu, rifs->is_wireless ? "Yes" : "No");
891   }
892   abuf_puts(abuf, "</table>\n");
893
894   abuf_appendf(abuf,
895                "<em>Olsrd is configured to %s if no interfaces are available</em><br>\n",
896                olsr_cnf->allow_no_interfaces ? "run even" : "halt");
897
898   abuf_puts(abuf, "<h2>Plugins</h2>\n");
899   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\"><tr><th>Name</th><th>Parameters</th></tr>\n");
900   for (pentry = olsr_cnf->plugins; pentry; pentry = pentry->next) {
901     abuf_appendf(abuf, "<tr><td>%s</td>\n" "<td><select>\n" "<option>KEY, VALUE</option>\n", pentry->name);
902
903     for (pparam = pentry->params; pparam; pparam = pparam->next) {
904       abuf_appendf(abuf, "<option>\"%s\", \"%s\"</option>\n", pparam->key, pparam->value);
905     }
906     abuf_puts(abuf, "</select></td></tr>\n");
907
908   }
909   abuf_puts(abuf, "</table>\n");
910
911   section_title(abuf, "Announced HNA entries");
912   if (list_is_empty(&olsr_cnf->hna_entries)) {
913     struct ip_prefix_entry *hna;
914     abuf_puts(abuf, "<tr><th>Network</th></tr>\n");
915     OLSR_FOR_ALL_IPPREFIX_ENTRIES(&olsr_cnf->hna_entries, hna) {
916       struct ipprefix_str netbuf;
917       abuf_appendf(abuf, "<tr><td>%s</td></tr>\n", olsr_ip_prefix_to_string(&netbuf, &hna->net));
918     } OLSR_FOR_ALL_IPPREFIX_ENTRIES_END()
919   } else {
920     abuf_puts(abuf, "<tr><td></td></tr>\n");
921   }
922   abuf_puts(abuf, "</table>\n");
923 }
924
925 static void
926 build_neigh_body(struct autobuf *abuf)
927 {
928   struct nbr_entry *neigh;
929   struct link_entry *lnk;
930   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
931
932   section_title(abuf, "Links");
933
934   abuf_appendf(abuf, "<tr><th%s>Local IP</th><th%s>Remote IP</th>", colspan, colspan);
935   abuf_puts(abuf, "<th>LinkCost</th>");
936   abuf_puts(abuf, "</tr>\n");
937
938   /* Link set */
939   OLSR_FOR_ALL_LINK_ENTRIES(lnk) {
940     struct lqtextbuffer lqbuffer1, lqbuffer2;
941     abuf_puts(abuf, "<tr>");
942     build_ipaddr_with_link(abuf, &lnk->local_iface_addr, -1);
943     build_ipaddr_with_link(abuf, &lnk->neighbor_iface_addr, -1);
944     abuf_appendf(abuf,
945                  "<td>(%s) %s</td>",
946                  get_link_entry_text(lnk, '/', &lqbuffer1), get_linkcost_text(lnk->linkcost, false, &lqbuffer2));
947     abuf_puts(abuf, "</tr>\n");
948   } OLSR_FOR_ALL_LINK_ENTRIES_END(lnk);
949
950   abuf_puts(abuf, "</table>\n");
951
952   section_title(abuf, "Neighbors");
953   abuf_appendf(abuf,
954                "<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",
955                colspan);
956   /* Neighbors */
957   OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
958     struct nbr_con *connector;
959     int thop_cnt;
960     abuf_puts(abuf, "<tr>");
961     build_ipaddr_with_link(abuf, &neigh->nbr_addr, -1);
962     abuf_appendf(abuf,
963                  "<td>%s</td>"
964                  "<td>%s</td>"
965                  "<td>%s</td>"
966                  "<td>%d</td>",
967                  neigh->is_sym ? "YES" : "NO",
968                  neigh->is_mpr ? "YES" : "NO", olsr_lookup_mprs_set(&neigh->nbr_addr) ? "YES" : "NO", neigh->willingness);
969
970     abuf_puts(abuf, "<td><select>\n" "<option>IP ADDRESS</option>\n");
971
972     thop_cnt = 0;
973     OLSR_FOR_ALL_NBR_CON_ENTRIES(neigh, connector) {
974       struct ipaddr_str strbuf;
975       abuf_appendf(abuf, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &connector->nbr2->nbr2_addr));
976       thop_cnt++;
977     } OLSR_FOR_ALL_NBR_CON_ENTRIES_END(neigh, connector);
978     abuf_appendf(abuf, "</select> (%d)</td></tr>\n", thop_cnt);
979   } OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
980
981   abuf_puts(abuf, "</table>\n");
982 }
983
984 static void
985 build_topo_body(struct autobuf *abuf)
986 {
987   struct tc_entry *tc;
988   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
989
990   section_title(abuf, "Topology Entries");
991   abuf_appendf(abuf, "<tr><th%s>Destination IP</th><th%s>Last Hop IP</th>", colspan, colspan);
992   abuf_puts(abuf, "<th colspan=\"3\">Linkcost</th>");
993   abuf_puts(abuf, "</tr>\n");
994
995   OLSR_FOR_ALL_TC_ENTRIES(tc) {
996     struct tc_edge_entry *tc_edge;
997     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
998       if (tc_edge->edge_inv) {
999         struct lqtextbuffer lqbuffer1, lqbuffer2;
1000         abuf_puts(abuf, "<tr>");
1001         build_ipaddr_with_link(abuf, &tc_edge->T_dest_addr, -1);
1002         build_ipaddr_with_link(abuf, &tc->addr, -1);
1003         abuf_appendf(abuf,
1004                      "<td>(%s)</td><td>&nbsp;</td><td>%s</td>\n",
1005                      get_tc_edge_entry_text(tc_edge, '/', &lqbuffer1), get_linkcost_text(tc_edge->cost, false, &lqbuffer2));
1006         abuf_puts(abuf, "</tr>\n");
1007       }
1008     } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
1009   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
1010
1011   abuf_puts(abuf, "</table>\n");
1012 }
1013
1014 static void
1015 build_mid_body(struct autobuf *abuf)
1016 {
1017   struct tc_entry *tc;
1018   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1019
1020   section_title(abuf, "MID Entries");
1021   abuf_appendf(abuf, "<tr><th%s>Main Address</th><th>Aliases</th></tr>\n", colspan);
1022
1023   /* MID */
1024   OLSR_FOR_ALL_TC_ENTRIES(tc) {
1025     struct mid_entry *alias;
1026     abuf_puts(abuf, "<tr>");
1027     build_ipaddr_with_link(abuf, &tc->addr, -1);
1028     abuf_puts(abuf, "<td><select>\n<option>IP ADDRESS</option>\n");
1029
1030     OLSR_FOR_ALL_TC_MID_ENTRIES(tc, alias) {
1031       struct ipaddr_str strbuf;
1032       abuf_appendf(abuf, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &alias->mid_alias_addr));
1033     } OLSR_FOR_ALL_TC_MID_ENTRIES_END(tc, alias);
1034     abuf_appendf(abuf, "</select> (%u)</td></tr>\n", tc->mid_tree.count);
1035   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
1036
1037   abuf_puts(abuf, "</table>\n");
1038 }
1039
1040
1041 static void
1042 build_nodes_body(struct autobuf *abuf)
1043 {
1044   build_neigh_body(abuf);
1045   build_topo_body(abuf);
1046   build_mid_body(abuf);
1047 }
1048
1049 static void
1050 build_all_body(struct autobuf *abuf)
1051 {
1052   build_config_body(abuf);
1053   build_routes_body(abuf);
1054   build_nodes_body(abuf);
1055 }
1056
1057
1058 static void
1059 build_about_body(struct autobuf *abuf)
1060 {
1061   abuf_appendf(abuf,
1062                "<strong>" PLUGIN_NAME " version " PLUGIN_VERSION "</strong><br/>\n"
1063                "by Andreas T&oslash;nnesen (C)2005.<br/>\n" "Compiled "
1064 #if ADMIN_INTERFACE
1065                "<em>with experimental admin interface</em> "
1066 #endif
1067                "%s at %s<hr/>\n"
1068                "This plugin implements a HTTP server that supplies\n"
1069                "the client with various dynamic web pages representing\n"
1070                "the current olsrd status.<br/>The different pages include:\n"
1071                "<ul>\n<li><strong>Configuration</strong> - This page displays information\n"
1072                "about the current olsrd configuration. This includes various\n"
1073                "olsr settings such as IP version, MID/TC redundancy, hysteresis\n"
1074                "etc. Information about the current status of the interfaces on\n"
1075                "which olsrd is configured to run is also displayed. Loaded olsrd\n"
1076                "plugins are shown with their plugin parameters. Finally all local\n"
1077                "HNA entries are shown. These are the networks that the local host\n"
1078                "will anounce itself as a gateway to.</li>\n"
1079                "<li><strong>Routes</strong> - This page displays all routes currently set in\n"
1080                "the kernel <em>by olsrd</em>. The type of route is also displayed(host\n"
1081                "or HNA).</li>\n"
1082                "<li><strong>Links/Topology</strong> - This page displays all information about\n"
1083                "links, neighbors, topology, MID and HNA entries.</li>\n"
1084                "<li><strong>All</strong> - Here all the previous pages are displayed as one.\n"
1085                "This is to make all information available as easy as possible(for example\n"
1086                "for a script) and using as few resources as possible.</li>\n"
1087 #if ADMIN_INTERFACE
1088                "<li><strong>Admin</strong> - This page is highly experimental(and unsecure)!\n"
1089                "As of now it is not working at all but it provides a impression of\n"
1090                "the future possibilities of httpinfo. This is to be a interface to\n"
1091                "changing olsrd settings in realtime. These settings include various\n"
1092                "\"basic\" settings and local HNA settings.</li>\n"
1093 #endif
1094                "<li><strong>About</strong> - this help page.</li>\n</ul>"
1095                "<hr/>\n"
1096                "Send questions or comments to\n"
1097                "<a href=\"mailto:olsr-users@olsr.org\">olsr-users@olsr.org</a> or\n"
1098                "<a href=\"mailto:andreto-at-olsr.org\">andreto-at-olsr.org</a><br/>\n"
1099                "Official olsrd homepage: <a href=\"http://www.olsr.org/\">http://www.olsr.org</a><br/>\n", build_date, build_host);
1100 }
1101
1102 static void
1103 build_cfgfile_body(struct autobuf *abuf)
1104 {
1105   abuf_puts(abuf,
1106             "\n\n"
1107             "<strong>This is an automatically generated configuration\n"
1108             "file based on the current olsrd configuration of this node.</strong><br/>\n" "<hr/>\n" "<pre>\n");
1109
1110 #ifdef NETDIRECT
1111   {
1112     /* Hack to make netdirect stuff work with
1113        olsr_write_cnf_buf
1114      */
1115     char tmpBuf[10000];
1116     size = olsr_write_cnf_buf(olsr_cnf, true, tmpBuf, 10000);
1117     snprintf(&buf[size], bufsize - size, tmpBuf);
1118   }
1119 #else
1120   olsr_write_cnf_buf(abuf, olsr_cnf, true);
1121 #endif
1122
1123   abuf_puts(abuf, "</pre>\n<hr/>\n");
1124 }
1125
1126 #if 0
1127
1128 /*
1129  * In a bigger mesh, there are probs with the fixed
1130  * bufsize. Because the Content-Length header is
1131  * optional, the sprintf() is changed to a more
1132  * scalable solution here.
1133  */
1134
1135 int
1136 netsprintf(char *str, const char *format, ...)
1137 {
1138   va_list arg;
1139   int rv;
1140   va_start(arg, format);
1141   rv = vsprintf(str, format, arg);
1142   va_end(arg);
1143   if (0 != netsprintf_direct) {
1144     if (0 == netsprintf_error) {
1145       if (0 > send(client_sockets[curr_clients], str, rv, 0)) {
1146         OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Failed sending data to client!\n");
1147         netsprintf_error = 1;
1148       }
1149     }
1150     return 0;
1151   }
1152   return rv;
1153 }
1154 #endif
1155
1156 static ssize_t
1157 writen(int fd, const void *buf, size_t count)
1158 {
1159   size_t bytes_left = count;
1160   const char *p = buf;
1161   while (bytes_left > 0) {
1162     const ssize_t written = write(fd, p, bytes_left);
1163     if (written == -1) {        /* error */
1164       if (errno == EINTR) {
1165         continue;
1166       }
1167       return -1;
1168     }
1169     /* We wrote something */
1170     bytes_left -= written;
1171     p += written;
1172   }
1173   return count;
1174 }
1175
1176 /*
1177  * Local Variables:
1178  * c-basic-offset: 2
1179  * indent-tabs-mode: nil
1180  * End:
1181  */