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