Namespace cleanup of scheduler, remove "polling" sockets
[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(0);
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   olsr_socket_add(http_socket, &parse_http_request, NULL, OLSR_SOCKET_READ);
348
349   return 1;
350 }
351
352 /* Non reentrant - but we are not multithreaded anyway */
353 static void
354 parse_http_request(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
355 {
356   struct sockaddr_storage pin;
357   socklen_t addrlen;
358   union olsr_ip_addr *ipaddr;
359   char req[MAX_HTTPREQ_SIZE];
360   //static char body[HTML_BUFSIZE];
361   struct autobuf body, header;
362   char req_type[11];
363   char filename[251];
364   char http_version[11];
365   unsigned int c = 0;
366   int r = 1 /*, size = 0 */ ;
367
368   abuf_init(&body, 0);
369   abuf_init(&header, 0);
370
371   if (curr_clients >= MAX_CLIENTS) {
372     return;
373   }
374   curr_clients++;
375
376   addrlen = sizeof(pin);
377   client_sockets[curr_clients] = accept(fd, (struct sockaddr *)&pin, &addrlen);
378   if (client_sockets[curr_clients] == -1) {
379     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) accept: %s\n", strerror(errno));
380     goto close_connection;
381   }
382
383   if (((struct sockaddr *)&pin)->sa_family != olsr_cnf->ip_version) {
384     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Connection with wrong IP version?!\n");
385     goto close_connection;
386   }
387
388   if (olsr_cnf->ip_version == AF_INET) {
389     struct sockaddr_in *addr4 = (struct sockaddr_in *)&pin;
390     ipaddr = (union olsr_ip_addr *)&addr4->sin_addr;
391   } else {
392     struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pin;
393     ipaddr = (union olsr_ip_addr *)&addr6->sin6_addr;
394   }
395
396   if (!ip_acl_acceptable(&allowed_nets, ipaddr, olsr_cnf->ip_version)) {
397 #if !defined REMOVE_LOG_WARN
398     struct ipaddr_str strbuf;
399 #endif
400     OLSR_WARN(LOG_PLUGINS, "HTTP request from non-allowed host %s!\n", olsr_ip_to_string(&strbuf, ipaddr));
401     goto close_connection;
402   }
403
404   memset(req, 0, sizeof(req));
405   //memset(body, 0, sizeof(body));
406
407   while ((r = recv(client_sockets[curr_clients], &req[c], 1, 0)) > 0 && (c < sizeof(req) - 1)) {
408     c++;
409
410     if ((c > 3 && !strcmp(&req[c - 4], "\r\n\r\n")) || (c > 1 && !strcmp(&req[c - 2], "\n\n")))
411       break;
412   }
413
414   if (r < 0) {
415     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Failed to recieve data from client!\n");
416     stats.err_hits++;
417     goto close_connection;
418   }
419
420   /* Get the request */
421   if (sscanf(req, "%10s %250s %10s\n", req_type, filename, http_version) != 3) {
422     /* Try without HTTP version */
423     if (sscanf(req, "%10s %250s\n", req_type, filename) != 2) {
424       OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Error parsing request %s!\n", req);
425       stats.err_hits++;
426       goto close_connection;
427     }
428   }
429
430   OLSR_DEBUG(LOG_PLUGINS, "Request: %s\nfile: %s\nVersion: %s\n\n", req_type, filename, http_version);
431
432   if (!strcmp(req_type, "POST")) {
433 #if ADMIN_INTERFACE
434     int i = 0;
435     while (dynamic_files[i].filename) {
436       OLSR_DEBUG(LOG_PLUGINS, "POST checking %s\n", dynamic_files[i].filename);
437       if (FILENREQ_MATCH(filename, dynamic_files[i].filename)) {
438         uint32_t param_size;
439
440         stats.ok_hits++;
441
442         param_size = recv(client_sockets[curr_clients], req, sizeof(req) - 1, 0);
443
444         req[param_size] = '\0';
445         OLSR_DEBUG(LOG_PLUGINS, "Dynamic read %d bytes\n", param_size);
446
447         //memcpy(body, dynamic_files[i].data, static_bin_files[i].data_size);
448         //size += dynamic_files[i].process_data_cb(req, param_size, &body[size], sizeof(body)-size);
449         dynamic_files[i].process_data_cb(req, param_size, &body);
450
451         build_http_header(&header, HTTP_OK, true, body.len);
452         goto send_http_data;
453       }
454       i++;
455     }
456 #endif
457     /* We only support GET */
458     abuf_puts(&body, HTTP_400_MSG);
459     stats.ill_hits++;
460     build_http_header(&header, HTTP_BAD_REQ, true, body.len);
461   } else if (!strcmp(req_type, "GET")) {
462     int i = 0;
463
464     for (i = 0; static_bin_files[i].filename; i++) {
465       if (FILENREQ_MATCH(filename, static_bin_files[i].filename)) {
466         break;
467       }
468     }
469
470     if (static_bin_files[i].filename) {
471       stats.ok_hits++;
472       //memcpy(body, static_bin_files[i].data, static_bin_files[i].data_size);
473       abuf_memcpy(&body, static_bin_files[i].data, static_bin_files[i].data_size);
474       //size = static_bin_files[i].data_size;
475       build_http_header(&header, HTTP_OK, false, body.len);
476       goto send_http_data;
477     }
478
479     i = 0;
480     while (static_txt_files[i].filename) {
481       if (FILENREQ_MATCH(filename, static_txt_files[i].filename)) {
482         break;
483       }
484       i++;
485     }
486
487     if (static_txt_files[i].filename) {
488       stats.ok_hits++;
489
490       //size += snprintf(&body[size], sizeof(body)-size, "%s", static_txt_files[i].data);
491       abuf_puts(&body, static_txt_files[i].data);
492
493       build_http_header(&header, HTTP_OK, false, body.len);
494       goto send_http_data;
495     }
496
497     i = 0;
498     if (strlen(filename) > 1) {
499       while (tab_entries[i].filename) {
500         if (FILENREQ_MATCH(filename, tab_entries[i].filename)) {
501           break;
502         }
503         i++;
504       }
505     }
506
507     if (tab_entries[i].filename) {
508 #ifdef NETDIRECT
509       build_http_header(&header, HTTP_OK, true);
510       r = send(client_sockets[curr_clients], req, c, 0);
511       if (r < 0) {
512         OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Failed sending data to client!\n");
513         goto close_connection;
514       }
515       netsprintf_error = 0;
516       netsprintf_direct = 1;
517 #endif
518       abuf_appendf(&body,
519                    "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
520                    "<head>\n"
521                    "<meta http-equiv=\"Content-type\" content=\"text/html; charset=ISO-8859-1\">\n"
522                    "<title>olsr.org httpinfo plugin</title>\n"
523                    "<link rel=\"icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
524                    "<link rel=\"shortcut icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
525                    "<link rel=\"stylesheet\" type=\"text/css\" href=\"httpinfo.css\">\n"
526                    "</head>\n"
527                    "<body bgcolor=\"#ffffff\" text=\"#000000\">\n"
528                    "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
529                    "<tbody><tr bgcolor=\"#ffffff\">\n"
530                    "<td height=\"69\" valign=\"middle\" width=\"80%%\">\n"
531                    "<font color=\"black\" face=\"timesroman\" size=\"6\">&nbsp;&nbsp;&nbsp;<a href=\"http://www.olsr.org/\">olsr.org OLSR daemon</a></font></td>\n"
532                    "<td height=\"69\" valign=\"middle\" width=\"20%%\">\n"
533                    "<a href=\"http://www.olsr.org/\"><img border=\"0\" src=\"/logo.gif\" alt=\"olsrd logo\"></a></td>\n"
534                    "</tr>\n" "</tbody>\n" "</table>\n", FRAMEWIDTH);
535
536       build_tabs(&body, i);
537       build_frame(&body, tab_entries[i].build_body_cb);
538
539       stats.ok_hits++;
540
541       abuf_appendf(&body,
542                    "</table>\n"
543                    "<div id=\"footer\">\n"
544                    "<center>\n"
545                    "(C)2005 Andreas T&oslash;nnesen<br/>\n"
546                    "<a href=\"http://www.olsr.org/\">http://www.olsr.org</a>\n" "</center>\n" "</div>\n" "</body>\n" "</html>\n");
547
548 #ifdef NETDIRECT
549       netsprintf_direct = 1;
550       goto close_connection;
551 #else
552       build_http_header(&header, HTTP_OK, true, body.len);
553       goto send_http_data;
554 #endif
555     }
556
557
558     stats.ill_hits++;
559     abuf_puts(&body, HTTP_404_MSG);
560     build_http_header(&header, HTTP_BAD_FILE, true, body.len);
561   } else {
562     /* We only support GET */
563     abuf_puts(&body, HTTP_400_MSG);
564     stats.ill_hits++;
565     build_http_header(&header, HTTP_BAD_REQ, true, body.len);
566   }
567
568 send_http_data:
569
570   r = writen(client_sockets[curr_clients], header.buf, header.len);
571   if (r < 0) {
572     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Failed sending data to client!\n");
573     goto close_connection;
574   }
575
576   r = writen(client_sockets[curr_clients], body.buf, body.len);
577   if (r < 0) {
578     OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Failed sending data to client!\n");
579     goto close_connection;
580   }
581
582 close_connection:
583   abuf_free(&body);
584   abuf_free(&header);
585   os_close(client_sockets[curr_clients]);
586   curr_clients--;
587 }
588
589
590 void
591 build_http_header(struct autobuf *abuf, http_header_type type, bool is_html, uint32_t msgsize)
592 {
593   time_t currtime;
594   const char *h;
595
596   switch (type) {
597   case HTTP_BAD_REQ:
598     h = HTTP_400;
599     break;
600   case HTTP_BAD_FILE:
601     h = HTTP_404;
602     break;
603   default:
604     /* Defaults to OK */
605     h = HTTP_200;
606     break;
607   }
608   abuf_puts(abuf, h);
609
610   /* Date */
611   time(&currtime);
612   abuf_strftime(abuf, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", localtime(&currtime));
613
614   /* Server version */
615   abuf_appendf(abuf, "Server: %s %s %s\r\n", PLUGIN_NAME, PLUGIN_VERSION, HTTP_VERSION);
616
617   /* connection-type */
618   abuf_puts(abuf, "Connection: closed\r\n");
619
620   /* MIME type */
621   abuf_appendf(abuf, "Content-type: text/%s\r\n", is_html ? "html" : "plain");
622
623   /* Content length */
624   if (msgsize > 0) {
625     abuf_appendf(abuf, "Content-length: %u\r\n", msgsize);
626   }
627
628   /* Cache-control
629    * No caching dynamic pages
630    */
631   abuf_puts(abuf, "Cache-Control: no-cache\r\n");
632
633   if (!is_html) {
634     abuf_puts(abuf, "Accept-Ranges: bytes\r\n");
635   }
636   /* End header */
637   abuf_puts(abuf, "\r\n");
638
639   OLSR_DEBUG(LOG_PLUGINS, "HEADER:\n%s", abuf->buf);
640 }
641
642
643 static void
644 build_tabs(struct autobuf *abuf, int active)
645 {
646   int tabs;
647
648   abuf_appendf(abuf,
649                "<table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
650                "<tr bgcolor=\"#ffffff\"><td>\n" "<ul id=\"tabnav\">\n", FRAMEWIDTH);
651   for (tabs = 0; tab_entries[tabs].tab_label; tabs++) {
652     if (!tab_entries[tabs].display_tab) {
653       continue;
654     }
655     abuf_appendf(abuf,
656                  "<li><a href=\"%s\"%s>%s</a></li>\n",
657                  tab_entries[tabs].filename, tabs == active ? " class=\"active\"" : "", tab_entries[tabs].tab_label);
658   }
659   abuf_appendf(abuf, "</ul>\n" "</td></tr>\n" "<tr><td>\n");
660 }
661
662
663 /*
664  * destructor - called at unload
665  */
666 void
667 olsr_plugin_exit(void)
668 {
669   ip_acl_flush(&allowed_nets);
670
671   if (http_socket >= 0) {
672     os_close(http_socket);
673   }
674 }
675
676
677 static void
678 section_title(struct autobuf *abuf, const char *title)
679 {
680   abuf_appendf(abuf,
681                "<h2>%s</h2>\n"
682                "<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" align=\"center\">\n", title);
683 }
684
685 static void
686 build_frame(struct autobuf *abuf, build_body_callback frame_body_cb)
687 {
688   abuf_puts(abuf, "<div id=\"maintable\">\n");
689   frame_body_cb(abuf);
690   abuf_puts(abuf, "</div>\n");
691 }
692
693 static void
694 fmt_href(struct autobuf *abuf, const char *const ipaddr)
695 {
696   abuf_appendf(abuf, "<a href=\"http://%s:%d/all\">", ipaddr, http_port);
697 }
698
699 static void
700 build_ip_txt(struct autobuf *abuf, const bool print_link, const char *const ipaddrstr, const int prefix_len)
701 {
702   if (print_link) {
703     fmt_href(abuf, ipaddrstr);
704   }
705
706   abuf_puts(abuf, ipaddrstr);
707   /* print ip address or ip prefix ? */
708   if (prefix_len != -1 && prefix_len != 8 * (int)olsr_cnf->ipsize) {
709     abuf_appendf(abuf, "/%d", prefix_len);
710   }
711
712   if (print_link) {             /* Print the link only if there is no prefix_len */
713     abuf_puts(abuf, "</a>");
714   }
715 }
716
717 static void
718 build_ipaddr_link(struct autobuf *abuf, const bool want_link, const union olsr_ip_addr *const ipaddr, const int prefix_len)
719 {
720   struct ipaddr_str ipaddrstr;
721   const struct hostent *const hp =
722 #ifndef WIN32
723     resolve_ip_addresses ? gethostbyaddr(ipaddr, olsr_cnf->ipsize, olsr_cnf->ip_version) :
724 #endif
725     NULL;
726   /* Print the link only if there is no prefix_len */
727   const int print_link = want_link && (prefix_len == -1 || prefix_len == 8 * (int)olsr_cnf->ipsize);
728   olsr_ip_to_string(&ipaddrstr, ipaddr);
729
730   abuf_puts(abuf, "<td>");
731   build_ip_txt(abuf, print_link, ipaddrstr.buf, prefix_len);
732   abuf_puts(abuf, "</td>");
733
734   if (resolve_ip_addresses) {
735     if (hp) {
736       abuf_puts(abuf, "<td>(");
737       if (print_link) {
738         fmt_href(abuf, ipaddrstr.buf);
739       }
740       abuf_puts(abuf, hp->h_name);
741       if (print_link) {
742         abuf_puts(abuf, "</a>");
743       }
744       abuf_puts(abuf, ")</td>");
745     } else {
746       abuf_puts(abuf, "<td/>");
747     }
748   }
749 }
750
751 #define build_ipaddr_with_link(abuf, ipaddr, plen) \
752           build_ipaddr_link((abuf), true, (ipaddr), (plen))
753 #define build_ipaddr_no_link(abuf, ipaddr, plen) \
754           build_ipaddr_link((abuf), false, (ipaddr), (plen))
755
756 static void
757 build_route(struct autobuf *abuf, const struct rt_entry *rt)
758 {
759   char lqbuffer[LQTEXT_MAXLENGTH];
760
761   abuf_puts(abuf, "<tr>");
762   build_ipaddr_with_link(abuf, &rt->rt_dst.prefix, rt->rt_dst.prefix_len);
763   build_ipaddr_with_link(abuf, &rt->rt_best->rtp_nexthop.gateway, -1);
764
765   abuf_appendf(abuf, "<td>%u</td>", rt->rt_best->rtp_metric.hops);
766   abuf_appendf(abuf, "<td>%s</td>", olsr_get_linkcost_text(rt->rt_best->rtp_metric.cost, true, lqbuffer, sizeof(lqbuffer)));
767   abuf_appendf(abuf,
768                "<td>%s</td></tr>\n", rt->rt_best->rtp_nexthop.interface ? rt->rt_best->rtp_nexthop.interface->int_name : "[null]");
769 }
770
771 static void
772 build_routes_body(struct autobuf *abuf)
773 {
774   struct rt_entry *rt, *iterator;
775
776   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
777   section_title(abuf, "OLSR Routes in Kernel");
778   abuf_appendf(abuf,
779                "<tr><th%s>Destination</th><th%s>Gateway</th><th>Metric</th><th>ETX</th><th>Interface</th></tr>\n",
780                colspan, colspan);
781
782   /* Walk the route table */
783   OLSR_FOR_ALL_RT_ENTRIES(rt, iterator) {
784     build_route(abuf, rt);
785   }
786
787   abuf_puts(abuf, "</table>\n");
788 }
789
790 static void
791 build_config_body(struct autobuf *abuf)
792 {
793   const struct olsr_if_config *ifs;
794   const struct plugin_entry *pentry;
795   const struct plugin_param *pparam;
796   struct ipaddr_str mainaddrbuf;
797   struct millitxt_buf tbuf;
798
799   abuf_appendf(abuf, "Version: %s (built on %s on %s)\n<br>OS: %s\n<br>", olsrd_version, build_date, build_host, OS);
800   {
801     const time_t currtime = time(NULL);
802     abuf_strftime(abuf, "System time: <em>%a, %d %b %Y %H:%M:%S</em><br>", localtime(&currtime));
803   }
804
805   {
806     struct timeval now, uptime;
807     int hours, mins, days;
808     os_gettimeofday(&now, NULL);
809     timersub(&now, &start_time, &uptime);
810
811     days = uptime.tv_sec / 86400;
812     uptime.tv_sec %= 86400;
813     hours = uptime.tv_sec / 3600;
814     uptime.tv_sec %= 3600;
815     mins = uptime.tv_sec / 60;
816     uptime.tv_sec %= 60;
817
818     abuf_puts(abuf, "Olsrd uptime: <em>");
819     if (days) {
820       abuf_appendf(abuf, "%d day(s) ", days);
821     }
822     abuf_appendf(abuf, "%02d hours %02d minutes %02d seconds</em><br/>\n", hours, mins, (int)uptime.tv_sec);
823   }
824
825   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,
826                stats.ill_hits);
827
828   abuf_appendf(abuf, "Click <a href=\"/cfgfile\">here</a> to <em>generate a configuration file for this node</em>.\n");
829
830   abuf_puts(abuf, "<h2>Variables</h2>\n");
831
832   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n<tr>");
833
834   abuf_appendf(abuf, "<td>Main address: <strong>%s</strong></td>\n", olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->router_id));
835   abuf_appendf(abuf, "<td>IP version: %d</td>\n", olsr_cnf->ip_version == AF_INET ? 4 : 6);
836
837   // TODO: add logging information into http info ?
838   abuf_appendf(abuf, "<td></td>\n");
839   abuf_appendf(abuf, "<td>FIB Metrics: %s</td>\n",
840                FIBM_FLAT == olsr_cnf->fib_metric ? CFG_FIBM_FLAT : FIBM_CORRECT ==
841                olsr_cnf->fib_metric ? CFG_FIBM_CORRECT : CFG_FIBM_APPROX);
842
843   abuf_puts(abuf, "</tr>\n<tr>\n");
844
845   abuf_appendf(abuf, "<td>Pollrate: %s</td>\n", olsr_milli_to_txt(&tbuf, olsr_cnf->pollrate));
846   abuf_appendf(abuf, "<td>TC redundancy: %d</td>\n", olsr_cnf->tc_redundancy);
847   abuf_appendf(abuf, "<td>MPR coverage: %d</td>\n", olsr_cnf->mpr_coverage);
848   abuf_appendf(abuf, "<td>NAT threshold: %s</td>\n", olsr_milli_to_txt(&tbuf, olsr_cnf->lq_nat_thresh));
849
850   abuf_puts(abuf, "</tr>\n<tr>\n");
851
852   abuf_appendf(abuf, "<td>Fisheye: %s</td>\n", olsr_cnf->lq_fish ? "Enabled" : "Disabled");
853   abuf_appendf(abuf, "<td>TOS: 0x%04x</td>\n", olsr_cnf->tos);
854   abuf_appendf(abuf, "<td>RtTable: 0x%04x/%d</td>\n", olsr_cnf->rt_table, olsr_cnf->rt_table);
855   abuf_appendf(abuf, "<td>RtTableDefault: 0x%04x/%d</td>\n", olsr_cnf->rt_table_default, olsr_cnf->rt_table_default);
856   abuf_appendf(abuf, "<td>Willingness: %d %s</td>\n", olsr_cnf->willingness, olsr_cnf->willingness_auto ? "(auto)" : "");
857
858   abuf_puts(abuf, "</tr></table>\n");
859
860   abuf_puts(abuf, "<h2>Interfaces</h2>\n");
861   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n");
862   for (ifs = olsr_cnf->if_configs; ifs != NULL; ifs = ifs->next) {
863     const struct interface *const rifs = ifs->interf;
864     struct ipaddr_str addrbuf, bcastbuf;
865
866     abuf_appendf(abuf, "<tr><th colspan=\"3\">%s</th>\n", ifs->name);
867     if (!rifs) {
868       abuf_puts(abuf, "<tr><td colspan=\"3\">Status: DOWN</td></tr>\n");
869       continue;
870     }
871
872     abuf_appendf(abuf,
873                  "<tr>\n"
874                  "<td>IP: %s</td>\n"
875                  "<td>MCAST: %s</td>\n"
876                  "<td></td>"
877                  "</tr>\n",
878                  olsr_sockaddr_to_string(&addrbuf, &rifs->int_src),
879                  olsr_sockaddr_to_string(&bcastbuf, &rifs->int_multicast));
880     abuf_appendf(abuf,
881                  "<tr>\n"
882                  "<td>MTU: %d</td>\n"
883                  "<td>STATUS: UP</td>\n" "</tr>\n", rifs->int_mtu);
884   }
885   abuf_puts(abuf, "</table>\n");
886
887   abuf_appendf(abuf,
888                "<em>Olsrd is configured to %s if no interfaces are available</em><br>\n",
889                olsr_cnf->allow_no_interfaces ? "run even" : "halt");
890
891   abuf_puts(abuf, "<h2>Plugins</h2>\n");
892   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\"><tr><th>Name</th><th>Parameters</th></tr>\n");
893   for (pentry = olsr_cnf->plugins; pentry; pentry = pentry->next) {
894     abuf_appendf(abuf, "<tr><td>%s</td>\n" "<td><select>\n" "<option>KEY, VALUE</option>\n", pentry->name);
895
896     for (pparam = pentry->params; pparam; pparam = pparam->next) {
897       abuf_appendf(abuf, "<option>\"%s\", \"%s\"</option>\n", pparam->key, pparam->value);
898     }
899     abuf_puts(abuf, "</select></td></tr>\n");
900
901   }
902   abuf_puts(abuf, "</table>\n");
903
904   section_title(abuf, "Announced HNA entries");
905   if (list_is_empty(&olsr_cnf->hna_entries)) {
906     struct ip_prefix_entry *hna, *iterator;
907
908     abuf_puts(abuf, "<tr><th>Network</th></tr>\n");
909     OLSR_FOR_ALL_IPPREFIX_ENTRIES(&olsr_cnf->hna_entries, hna, iterator) {
910       struct ipprefix_str netbuf;
911       abuf_appendf(abuf, "<tr><td>%s</td></tr>\n", olsr_ip_prefix_to_string(&netbuf, &hna->net));
912     }
913   } else {
914     abuf_puts(abuf, "<tr><td></td></tr>\n");
915   }
916   abuf_puts(abuf, "</table>\n");
917 }
918
919 static void
920 build_neigh_body(struct autobuf *abuf)
921 {
922   struct nbr_entry *neigh, *neigh_iterator;
923   struct link_entry *lnk, *lnk_iterator;
924   size_t i;
925   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
926
927   section_title(abuf, "Links");
928
929   abuf_appendf(abuf, "<tr><th%s>Local IP</th><th%s>Remote IP</th>", colspan, colspan);
930   for (i=1; i<olsr_get_linklabel_count(); i++) {
931     abuf_appendf(abuf, "<th>%s</th>", olsr_get_linklabel(i));
932   }
933   abuf_puts(abuf, "<th>LinkCost</th>");
934   abuf_puts(abuf, "</tr>\n");
935
936   /* Link set */
937   OLSR_FOR_ALL_LINK_ENTRIES(lnk, lnk_iterator) {
938     char lqbuffer[LQTEXT_MAXLENGTH];
939     abuf_puts(abuf, "<tr>");
940     build_ipaddr_with_link(abuf, &lnk->local_iface_addr, -1);
941     build_ipaddr_with_link(abuf, &lnk->neighbor_iface_addr, -1);
942
943     for (i=1; i<olsr_get_linklabel_count(); i++) {
944       abuf_appendf(abuf, "<td>%s</td>", olsr_get_linkdata_text(lnk, i, lqbuffer, sizeof(lqbuffer)));
945     }
946     abuf_appendf(abuf, "<td>%s</td>", olsr_get_linkcost_text(lnk->linkcost, false, lqbuffer, sizeof(lqbuffer)));
947     abuf_puts(abuf, "</tr>\n");
948   }
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, neigh_iterator) {
958     struct nbr_con *connector, *con_iterator;
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",
969                  neigh->mprs_count > 0 ? "YES" : "NO",
970                  neigh->willingness);
971
972     abuf_puts(abuf, "<td><select>\n" "<option>IP ADDRESS</option>\n");
973
974     thop_cnt = 0;
975     OLSR_FOR_ALL_NBR_CON_ENTRIES(neigh, connector, con_iterator) {
976       struct ipaddr_str strbuf;
977       abuf_appendf(abuf, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &connector->nbr2->nbr2_addr));
978       thop_cnt++;
979     }
980     abuf_appendf(abuf, "</select> (%d)</td></tr>\n", thop_cnt);
981   }
982
983   abuf_puts(abuf, "</table>\n");
984 }
985
986 static void
987 build_topo_body(struct autobuf *abuf)
988 {
989   struct tc_entry *tc, *tc_iterator;
990   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
991
992   section_title(abuf, "Topology Entries");
993   abuf_appendf(abuf, "<tr><th%s>Destination IP</th><th%s>Last Hop IP</th>", colspan, colspan);
994   abuf_puts(abuf, "<th colspan=\"3\">Linkcost</th>");
995   abuf_puts(abuf, "</tr>\n");
996
997   OLSR_FOR_ALL_TC_ENTRIES(tc, tc_iterator) {
998     struct tc_edge_entry *tc_edge, *edge_iterator;
999     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge, edge_iterator) {
1000       if (tc_edge->edge_inv) {
1001         char lqbuffer[LQTEXT_MAXLENGTH];
1002         abuf_puts(abuf, "<tr>");
1003         build_ipaddr_with_link(abuf, &tc_edge->T_dest_addr, -1);
1004         build_ipaddr_with_link(abuf, &tc->addr, -1);
1005         abuf_appendf(abuf, "<td colspan=\"3\">%s</td>\n",
1006                      olsr_get_linkcost_text(tc_edge->cost, false, lqbuffer, sizeof(lqbuffer)));
1007         abuf_puts(abuf, "</tr>\n");
1008       }
1009     }
1010   }
1011
1012   abuf_puts(abuf, "</table>\n");
1013 }
1014
1015 static void
1016 build_mid_body(struct autobuf *abuf)
1017 {
1018   struct tc_entry *tc, *tc_iterator;
1019   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1020
1021   section_title(abuf, "MID Entries");
1022   abuf_appendf(abuf, "<tr><th%s>Main Address</th><th>Aliases</th></tr>\n", colspan);
1023
1024   /* MID */
1025   OLSR_FOR_ALL_TC_ENTRIES(tc, tc_iterator) {
1026     struct mid_entry *alias, *alias_iterator;
1027     abuf_puts(abuf, "<tr>");
1028     build_ipaddr_with_link(abuf, &tc->addr, -1);
1029     abuf_puts(abuf, "<td><select>\n<option>IP ADDRESS</option>\n");
1030
1031     OLSR_FOR_ALL_TC_MID_ENTRIES(tc, alias, alias_iterator) {
1032       struct ipaddr_str strbuf;
1033       abuf_appendf(abuf, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &alias->mid_alias_addr));
1034     }
1035     abuf_appendf(abuf, "</select> (%u)</td></tr>\n", tc->mid_tree.count);
1036   }
1037
1038   abuf_puts(abuf, "</table>\n");
1039 }
1040
1041
1042 static void
1043 build_nodes_body(struct autobuf *abuf)
1044 {
1045   build_neigh_body(abuf);
1046   build_topo_body(abuf);
1047   build_mid_body(abuf);
1048 }
1049
1050 static void
1051 build_all_body(struct autobuf *abuf)
1052 {
1053   build_config_body(abuf);
1054   build_routes_body(abuf);
1055   build_nodes_body(abuf);
1056 }
1057
1058
1059 static void
1060 build_about_body(struct autobuf *abuf)
1061 {
1062   abuf_appendf(abuf,
1063                "<strong>" PLUGIN_NAME " version " PLUGIN_VERSION "</strong><br/>\n"
1064                "by Andreas T&oslash;nnesen (C)2005.<br/>\n" "Compiled "
1065 #if ADMIN_INTERFACE
1066                "<em>with experimental admin interface</em> "
1067 #endif
1068                "%s at %s<hr/>\n"
1069                "This plugin implements a HTTP server that supplies\n"
1070                "the client with various dynamic web pages representing\n"
1071                "the current olsrd status.<br/>The different pages include:\n"
1072                "<ul>\n<li><strong>Configuration</strong> - This page displays information\n"
1073                "about the current olsrd configuration. This includes various\n"
1074                "olsr settings such as IP version, MID/TC redundancy, hysteresis\n"
1075                "etc. Information about the current status of the interfaces on\n"
1076                "which olsrd is configured to run is also displayed. Loaded olsrd\n"
1077                "plugins are shown with their plugin parameters. Finally all local\n"
1078                "HNA entries are shown. These are the networks that the local host\n"
1079                "will anounce itself as a gateway to.</li>\n"
1080                "<li><strong>Routes</strong> - This page displays all routes currently set in\n"
1081                "the kernel <em>by olsrd</em>. The type of route is also displayed(host\n"
1082                "or HNA).</li>\n"
1083                "<li><strong>Links/Topology</strong> - This page displays all information about\n"
1084                "links, neighbors, topology, MID and HNA entries.</li>\n"
1085                "<li><strong>All</strong> - Here all the previous pages are displayed as one.\n"
1086                "This is to make all information available as easy as possible(for example\n"
1087                "for a script) and using as few resources as possible.</li>\n"
1088 #if ADMIN_INTERFACE
1089                "<li><strong>Admin</strong> - This page is highly experimental(and unsecure)!\n"
1090                "As of now it is not working at all but it provides a impression of\n"
1091                "the future possibilities of httpinfo. This is to be a interface to\n"
1092                "changing olsrd settings in realtime. These settings include various\n"
1093                "\"basic\" settings and local HNA settings.</li>\n"
1094 #endif
1095                "<li><strong>About</strong> - this help page.</li>\n</ul>"
1096                "<hr/>\n"
1097                "Send questions or comments to\n"
1098                "<a href=\"mailto:olsr-users@olsr.org\">olsr-users@olsr.org</a> or\n"
1099                "<a href=\"mailto:andreto-at-olsr.org\">andreto-at-olsr.org</a><br/>\n"
1100                "Official olsrd homepage: <a href=\"http://www.olsr.org/\">http://www.olsr.org</a><br/>\n", build_date, build_host);
1101 }
1102
1103 static void
1104 build_cfgfile_body(struct autobuf *abuf)
1105 {
1106   abuf_puts(abuf,
1107             "\n\n"
1108             "<strong>This is an automatically generated configuration\n"
1109             "file based on the current olsrd configuration of this node.</strong><br/>\n" "<hr/>\n" "<pre>\n");
1110
1111 #ifdef NETDIRECT
1112   {
1113     /* Hack to make netdirect stuff work with
1114        olsr_write_cnf_buf
1115      */
1116     char tmpBuf[10000];
1117     size = olsr_write_cnf_buf(olsr_cnf, true, tmpBuf, 10000);
1118     snprintf(&buf[size], bufsize - size, tmpBuf);
1119   }
1120 #else
1121   olsr_write_cnf_buf(abuf, olsr_cnf, true);
1122 #endif
1123
1124   abuf_puts(abuf, "</pre>\n<hr/>\n");
1125 }
1126
1127 #if 0
1128
1129 /*
1130  * In a bigger mesh, there are probs with the fixed
1131  * bufsize. Because the Content-Length header is
1132  * optional, the sprintf() is changed to a more
1133  * scalable solution here.
1134  */
1135
1136 int
1137 netsprintf(char *str, const char *format, ...)
1138 {
1139   va_list arg;
1140   int rv;
1141   va_start(arg, format);
1142   rv = vsprintf(str, format, arg);
1143   va_end(arg);
1144   if (0 != netsprintf_direct) {
1145     if (0 == netsprintf_error) {
1146       if (0 > send(client_sockets[curr_clients], str, rv, 0)) {
1147         OLSR_WARN(LOG_PLUGINS, "(HTTPINFO) Failed sending data to client!\n");
1148         netsprintf_error = 1;
1149       }
1150     }
1151     return 0;
1152   }
1153   return rv;
1154 }
1155 #endif
1156
1157 static ssize_t
1158 writen(int fd, const void *buf, size_t count)
1159 {
1160   size_t bytes_left = count;
1161   const char *p = buf;
1162   while (bytes_left > 0) {
1163     const ssize_t written = write(fd, p, bytes_left);
1164     if (written == -1) {        /* error */
1165       if (errno == EINTR) {
1166         continue;
1167       }
1168       return -1;
1169     }
1170     /* We wrote something */
1171     bytes_left -= written;
1172     p += written;
1173   }
1174   return count;
1175 }
1176
1177 /*
1178  * Local Variables:
1179  * c-basic-offset: 2
1180  * indent-tabs-mode: nil
1181  * End:
1182  */