Fixed http/txtinfo plugin which does not stop OLSR when writing blocks.
authorHenning Rogge <hrogge@googlemail.com>
Wed, 5 Aug 2009 16:05:16 +0000 (18:05 +0200)
committerHenning Rogge <hrogge@googlemail.com>
Wed, 5 Aug 2009 16:05:16 +0000 (18:05 +0200)
lib/httpinfo/src/olsrd_httpinfo.c
lib/txtinfo/src/olsrd_txtinfo.c
src/common/autobuf.c [new file with mode: 0644]
src/common/autobuf.h [new file with mode: 0644]

index 76f1b53..a0adf66 100644 (file)
@@ -46,7 +46,6 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <stdarg.h>
 #include <unistd.h>
 #include <errno.h>
 #ifdef WIN32
@@ -64,6 +63,7 @@
 #include "socket_parser.h"
 #include "ipcalc.h"
 #include "lq_plugin.h"
+#include "common/autobuf.h"
 
 #include "olsrd_httpinfo.h"
 #include "admin_interface.h"
@@ -130,7 +130,7 @@ static const char httpinfo_css[] =
   "text-align: center;\nwidth: 120px;\npadding: 0px;\ncolor: #000000;\n"
   "text-decoration: none;\nfont-family: verdana;\nfont-size: 12px;\n" "border: 1px solid #000;\n}\n";
 
-typedef int (*build_body_callback) (char *, uint32_t);
+typedef void (*build_body_callback) (struct autobuf *);
 
 struct tab_entry {
   const char *tab_label;
@@ -157,48 +157,54 @@ struct dynamic_file_entry {
 
 static int get_http_socket(int);
 
-static int build_tabs(char *, uint32_t, int);
+static void build_tabs(struct autobuf *, int);
 
 static void parse_http_request(int);
 
 static int build_http_header(http_header_type, bool, uint32_t, char *, uint32_t);
 
-static int build_frame(char *, uint32_t, const char *, const char *, int, build_body_callback frame_body_cb);
+static void build_frame(struct autobuf *, const char *, const char *, int, build_body_callback frame_body_cb);
 
-static int build_routes_body(char *, uint32_t);
+static void build_routes_body(struct autobuf *);
 
-static int build_config_body(char *, uint32_t);
+static void build_config_body(struct autobuf *);
 
-static int build_neigh_body(char *, uint32_t);
+static void build_neigh_body(struct autobuf *);
 
-static int build_topo_body(char *, uint32_t);
+static void build_topo_body(struct autobuf *);
 
-static int build_mid_body(char *, uint32_t);
+static void build_mid_body(struct autobuf *);
 
-static int build_nodes_body(char *, uint32_t);
+static void build_nodes_body(struct autobuf *);
 
-static int build_all_body(char *, uint32_t);
+static void build_all_body(struct autobuf *);
 
-static int build_about_body(char *, uint32_t);
+static void build_about_body(struct autobuf *);
 
-static int build_cfgfile_body(char *, uint32_t);
+static void build_cfgfile_body(struct autobuf *);
 
 static int check_allowed_ip(const struct allowed_net *const allowed_nets, const union olsr_ip_addr *const addr);
 
-static int build_ip_txt(char *buf, const uint32_t bufsize, const bool want_link, const char *const ipaddrstr, const int prefix_len);
+static void build_ip_txt(struct autobuf *, const bool want_link, const char *const ipaddrstr, const int prefix_len);
 
-static int build_ipaddr_link(char *buf, const uint32_t bufsize, const bool want_link, const union olsr_ip_addr *const ipaddr,
+static void build_ipaddr_link(struct autobuf *, const bool want_link, const union olsr_ip_addr *const ipaddr,
                              const int prefix_len);
-static int section_title(char *buf, uint32_t bufsize, const char *title);
+static void section_title(struct autobuf *, const char *title);
 
-static ssize_t writen(int fd, const void *buf, size_t count);
+static void httpinfo_write_data(void *foo);
 
 static struct timeval start_time;
 static struct http_stats stats;
-static int client_sockets[MAX_CLIENTS];
-static int curr_clients;
 static int http_socket;
 
+static char *outbuffer[MAX_CLIENTS];
+static size_t outbuffer_size[MAX_CLIENTS];
+static size_t outbuffer_written[MAX_CLIENTS];
+static int outbuffer_socket[MAX_CLIENTS];
+static int outbuffer_count;
+
+static struct timer_entry *writetimer_entry;
+
 #if 0
 int netsprintf(char *str, const char *format, ...) __attribute__ ((format(printf, 2, 3)));
 static int netsprintf_direct = 0;
@@ -298,7 +304,6 @@ olsrd_plugin_init(void)
   /* Get start time */
   gettimeofday(&start_time, NULL);
 
-  curr_clients = 0;
   /* set up HTTP socket */
   http_socket = get_http_socket(http_port != 0 ? http_port : DEFAULT_TCP_PORT);
 
@@ -318,44 +323,59 @@ void
 parse_http_request(int fd)
 {
   struct sockaddr_in pin;
+  struct autobuf body_abuf = { 0, 0, NULL };
   socklen_t addrlen;
   char *addr;
-  char req[MAX_HTTPREQ_SIZE];
-  static char body[HTML_BUFSIZE];
+  char header_buf[MAX_HTTPREQ_SIZE];
   char req_type[11];
   char filename[251];
   char http_version[11];
-  unsigned int c = 0;
-  int r = 1, size = 0;
+  int client_socket;
+  size_t header_length = 0;
+  size_t c = 0;
+  int r = 1;
+#ifdef linux
+  struct timeval timeout = { 0, 200 };
+#endif
 
-  if (curr_clients >= MAX_CLIENTS) {
+  if (outbuffer_count >= MAX_CLIENTS) {
+    olsr_printf(1, "(HTTPINFO) maximum number of connection reached\n");
     return;
   }
-  curr_clients++;
 
   addrlen = sizeof(struct sockaddr_in);
-  client_sockets[curr_clients] = accept(fd, (struct sockaddr *)&pin, &addrlen);
-  if (client_sockets[curr_clients] == -1) {
+  client_socket = accept(fd, (struct sockaddr *)&pin, &addrlen);
+  if (client_socket == -1) {
     olsr_printf(1, "(HTTPINFO) accept: %s\n", strerror(errno));
     goto close_connection;
   }
 
+#ifdef linux
+  if (setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
+    olsr_printf(1, "(HTTPINFO)SO_RCVTIMEO failed %s\n", strerror(errno));
+    goto close_connection;
+  }
+
+  if (setsockopt(client_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
+    olsr_printf(1, "(HTTPINFO)SO_SNDTIMEO failed %s\n", strerror(errno));
+    goto close_connection;
+  }
+#endif
   if (!check_allowed_ip(allowed_nets, (union olsr_ip_addr *)&pin.sin_addr.s_addr)) {
     struct ipaddr_str strbuf;
     olsr_printf(0, "HTTP request from non-allowed host %s!\n",
                 olsr_ip_to_string(&strbuf, (union olsr_ip_addr *)&pin.sin_addr.s_addr));
-    close(client_sockets[curr_clients]);
+    goto close_connection;
   }
 
   addr = inet_ntoa(pin.sin_addr);
 
-  memset(req, 0, sizeof(req));
-  memset(body, 0, sizeof(body));
+  memset(header_buf, 0, sizeof(header_buf));
 
-  while ((r = recv(client_sockets[curr_clients], &req[c], 1, 0)) > 0 && (c < sizeof(req) - 1)) {
+  while ((r = recv(client_socket, &header_buf[c], 1, 0)) > 0 && (c < sizeof(header_buf) - 1)) {
     c++;
 
-    if ((c > 3 && !strcmp(&req[c - 4], "\r\n\r\n")) || (c > 1 && !strcmp(&req[c - 2], "\n\n")))
+    if ((c > 3 && !strcmp(&header_buf[c - 4], "\r\n\r\n")) || (c > 1 && !strcmp(&header_buf[c - 2], "\n\n")))
       break;
   }
 
@@ -366,16 +386,17 @@ parse_http_request(int fd)
   }
 
   /* Get the request */
-  if (sscanf(req, "%10s %250s %10s\n", req_type, filename, http_version) != 3) {
+  if (sscanf(header_buf, "%10s %250s %10s\n", req_type, filename, http_version) != 3) {
     /* Try without HTTP version */
-    if (sscanf(req, "%10s %250s\n", req_type, filename) != 2) {
-      olsr_printf(1, "(HTTPINFO) Error parsing request %s!\n", req);
+    if (sscanf(header_buf, "%10s %250s\n", req_type, filename) != 2) {
+      olsr_printf(1, "(HTTPINFO) Error parsing request %s!\n", header_buf);
       stats.err_hits++;
       goto close_connection;
     }
   }
 
   olsr_printf(1, "Request: %s\nfile: %s\nVersion: %s\n\n", req_type, filename, http_version);
+  abuf_init(&body_abuf, 102400);
 
   if (!strcmp(req_type, "POST")) {
 #ifdef ADMIN_INTERFACE
@@ -387,23 +408,23 @@ parse_http_request(int fd)
 
         stats.ok_hits++;
 
-        param_size = recv(client_sockets[curr_clients], req, sizeof(req) - 1, 0);
+        param_size = recv(client_sockets[curr_clients], header_buf, sizeof(header_buf) - 1, 0);
 
-        req[param_size] = '\0';
+        header_buf[param_size] = '\0';
         printf("Dynamic read %d bytes\n", param_size);
 
         //memcpy(body, dynamic_files[i].data, static_bin_files[i].data_size);
-        size += dynamic_files[i].process_data_cb(req, param_size, &body[size], sizeof(body) - size);
-        c = build_http_header(HTTP_OK, true, size, req, sizeof(req));
+        body_length += dynamic_files[i].process_data_cb(header_buf, param_size, &body_buf[body_length], sizeof(body_buf) - body_length);
+        header_length = build_http_header(HTTP_OK, true, body_length, header_buf, sizeof(header_buf));
         goto send_http_data;
       }
       i++;
     }
 #endif
     /* We only support GET */
-    strscpy(body, HTTP_400_MSG, sizeof(body));
+    abuf_puts(&body_abuf, HTTP_400_MSG);
     stats.ill_hits++;
-    c = build_http_header(HTTP_BAD_REQ, true, strlen(body), req, sizeof(req));
+    header_length = build_http_header(HTTP_BAD_REQ, true, body_abuf.len, header_buf, sizeof(header_buf));
   } else if (!strcmp(req_type, "GET")) {
     int i = 0;
 
@@ -415,9 +436,8 @@ parse_http_request(int fd)
 
     if (static_bin_files[i].filename) {
       stats.ok_hits++;
-      memcpy(body, static_bin_files[i].data, static_bin_files[i].data_size);
-      size = static_bin_files[i].data_size;
-      c = build_http_header(HTTP_OK, false, size, req, sizeof(req));
+      abuf_memcpy(&body_abuf, static_bin_files[i].data, static_bin_files[i].data_size);
+      header_length = build_http_header(HTTP_OK, false, body_abuf.len, header_buf, sizeof(header_buf));
       goto send_http_data;
     }
 
@@ -431,8 +451,8 @@ parse_http_request(int fd)
 
     if (static_txt_files[i].filename) {
       stats.ok_hits++;
-      size += snprintf(&body[size], sizeof(body) - size, "%s", static_txt_files[i].data);
-      c = build_http_header(HTTP_OK, false, size, req, sizeof(req));
+      abuf_puts(&body_abuf, static_txt_files[i].data);
+      header_length = build_http_header(HTTP_OK, false, body_abuf.len, header_buf, sizeof(header_buf));
       goto send_http_data;
     }
 
@@ -448,8 +468,8 @@ parse_http_request(int fd)
 
     if (tab_entries[i].filename) {
 #ifdef NETDIRECT
-      c = build_http_header(HTTP_OK, true, size, req, sizeof(req));
-      r = send(client_sockets[curr_clients], req, c, 0);
+      header_length = build_http_header(HTTP_OK, true, body_length, header_buf, sizeof(header_buf));
+      r = send(client_sockets[curr_clients], header_buf, header_length, 0);
       if (r < 0) {
         olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
         goto close_connection;
@@ -457,8 +477,7 @@ parse_http_request(int fd)
       netsprintf_error = 0;
       netsprintf_direct = 1;
 #endif
-      size +=
-        snprintf(&body[size], sizeof(body) - size,
+      abuf_appendf(&body_abuf,
                  "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" "<head>\n"
                  "<meta http-equiv=\"Content-type\" content=\"text/html; charset=ISO-8859-1\">\n"
                  "<title>olsr.org httpinfo plugin</title>\n" "<link rel=\"icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
@@ -472,13 +491,12 @@ parse_http_request(int fd)
                  "<a href=\"http://www.olsr.org/\"><img border=\"0\" src=\"/logo.gif\" alt=\"olsrd logo\"></a></td>\n" "</tr>\n"
                  "</tbody>\n" "</table>\n", FRAMEWIDTH);
 
-      size += build_tabs(&body[size], sizeof(body) - size, i);
-      size += build_frame(&body[size], sizeof(body) - size, "Current Routes", "routes", FRAMEWIDTH, tab_entries[i].build_body_cb);
+      build_tabs(&body_abuf, i);
+      build_frame(&body_abuf, "Current Routes", "routes", FRAMEWIDTH, tab_entries[i].build_body_cb);
 
       stats.ok_hits++;
 
-      size +=
-        snprintf(&body[size], sizeof(body) - size,
+      abuf_appendf(&body_abuf,
                  "</table>\n" "<div id=\"footer\">\n" "<center>\n" "(C)2005 Andreas T&oslash;nnesen<br/>\n"
                  "<a href=\"http://www.olsr.org/\">http://www.olsr.org</a>\n" "</center>\n" "</div>\n" "</body>\n" "</html>\n");
 
@@ -486,39 +504,94 @@ parse_http_request(int fd)
       netsprintf_direct = 1;
       goto close_connection;
 #else
-      c = build_http_header(HTTP_OK, true, size, req, sizeof(req));
+      header_length = build_http_header(HTTP_OK, true, body_abuf.len, header_buf, sizeof(header_buf));
       goto send_http_data;
 #endif
     }
 
     stats.ill_hits++;
-    strscpy(body, HTTP_404_MSG, sizeof(body));
-    c = build_http_header(HTTP_BAD_FILE, true, strlen(body), req, sizeof(req));
+    abuf_puts(&body_abuf, HTTP_404_MSG);
+    header_length = build_http_header(HTTP_BAD_FILE, true, body_abuf.len, header_buf, sizeof(header_buf));
   } else {
     /* We only support GET */
-    strscpy(body, HTTP_400_MSG, sizeof(body));
+    abuf_puts(&body_abuf, HTTP_404_MSG);
     stats.ill_hits++;
-    c = build_http_header(HTTP_BAD_REQ, true, strlen(body), req, sizeof(req));
+    header_length = build_http_header(HTTP_BAD_REQ, true, body_abuf.len, header_buf, sizeof(header_buf));
   }
 
 send_http_data:
+  if (header_length + body_abuf.len > 0) {
+    outbuffer[outbuffer_count] = olsr_malloc(header_length + body_abuf.len, "http output buffer");
+    outbuffer_size[outbuffer_count] = header_length + body_abuf.len;
+    outbuffer_written[outbuffer_count] = 0;
+    outbuffer_socket[outbuffer_count] = client_socket;
+
+    memcpy(outbuffer[outbuffer_count], header_buf, header_length);
+    if (body_abuf.len > 0) {
+      memcpy((outbuffer[outbuffer_count]) + header_length, body_abuf.buf, body_abuf.len);
+    }
+    outbuffer_count++;
 
-  r = writen(client_sockets[curr_clients], req, c);
-  if (r < 0) {
-    olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
-    goto close_connection;
+    if (outbuffer_count == 1) {
+      writetimer_entry = olsr_start_timer(100, 0, OLSR_TIMER_PERIODIC, &httpinfo_write_data, NULL, 0);
+    }
   }
+  abuf_free(&body_abuf);
+  return;
 
-  r = writen(client_sockets[curr_clients], body, size);
-  if (r < 0) {
-    olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
-    goto close_connection;
+close_connection:
+  abuf_free(&body_abuf);
+  close(client_socket);
+}
+
+static void
+httpinfo_write_data(void *foo __attribute__ ((unused))) {
+  fd_set set;
+  int result, i, j, max;
+  struct timeval tv;
+
+  FD_ZERO(&set);
+  max = 0;
+  for (i=0; i<outbuffer_count; i++) {
+    FD_SET(outbuffer_socket[i], &set);
+    if (outbuffer_socket[i] > max) {
+      max = outbuffer_socket[i];
+    }
   }
 
-close_connection:
-  close(client_sockets[curr_clients]);
-  curr_clients--;
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+
+  result = select(max + 1, NULL, &set, NULL, &tv);
+  if (result <= 0) {
+    return;
+  }
+
+  for (i=0; i<outbuffer_count; i++) {
+    if (FD_ISSET(outbuffer_socket[i], &set)) {
+      result = write(outbuffer_socket[i], outbuffer[i] + outbuffer_written[i], outbuffer_size[i] - outbuffer_written[i]);
+      if (result > 0) {
+        outbuffer_written[i] += result;
+      }
 
+      if (result <= 0 || outbuffer_written[i] == outbuffer_size[i]) {
+        /* close this socket and cleanup*/
+        close(outbuffer_socket[i]);
+        free (outbuffer[i]);
+
+        for (j=i+1; j<outbuffer_count; j++) {
+          outbuffer[j-1] = outbuffer[j];
+          outbuffer_size[j-1] = outbuffer_size[j];
+          outbuffer_socket[j-1] = outbuffer_socket[j];
+          outbuffer_written[j-1] = outbuffer_written[j];
+        }
+        outbuffer_count--;
+      }
+    }
+  }
+  if (outbuffer_count == 0) {
+    olsr_stop_timer(writetimer_entry);
+  }
 }
 
 int
@@ -576,25 +649,22 @@ build_http_header(http_header_type type, bool is_html, uint32_t msgsize, char *b
   return size;
 }
 
-static int
-build_tabs(char *buf, const uint32_t bufsize, int active)
+static void
+build_tabs(struct autobuf *abuf, int active)
 {
-  int size = 0, tabs = 0;
+  int tabs = 0;
 
-  size +=
-    snprintf(&buf[size], bufsize - size,
-             "<table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
-             "<tr bgcolor=\"#ffffff\"><td>\n" "<ul id=\"tabnav\">\n", FRAMEWIDTH);
+  abuf_appendf(abuf,
+      "<table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
+      "<tr bgcolor=\"#ffffff\"><td>\n" "<ul id=\"tabnav\">\n", FRAMEWIDTH);
   for (tabs = 0; tab_entries[tabs].tab_label; tabs++) {
     if (!tab_entries[tabs].display_tab) {
       continue;
     }
-    size +=
-      snprintf(&buf[size], bufsize - size, "<li><a href=\"%s\"%s>%s</a></li>\n", tab_entries[tabs].filename,
+    abuf_appendf(abuf, "<li><a href=\"%s\"%s>%s</a></li>\n", tab_entries[tabs].filename,
                tabs == active ? " class=\"active\"" : "", tab_entries[tabs].tab_label);
   }
-  size += snprintf(&buf[size], bufsize - size, "</ul>\n" "</td></tr>\n" "<tr><td>\n");
-  return size;
+  abuf_appendf(abuf, "</ul>\n" "</td></tr>\n" "<tr><td>\n");
 }
 
 /*
@@ -608,57 +678,51 @@ olsr_plugin_exit(void)
   }
 }
 
-static int
-section_title(char *buf, uint32_t bufsize, const char *title)
+static void
+section_title(struct autobuf *abuf, const char *title)
 {
-  return snprintf(buf, bufsize,
+  abuf_appendf(abuf,
                   "<h2>%s</h2>\n" "<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" align=\"center\">\n",
                   title);
 }
 
-static int
-build_frame(char *buf, uint32_t bufsize, const char *title __attribute__ ((unused)), const char *link
+static void
+build_frame(struct autobuf *abuf, const char *title __attribute__ ((unused)), const char *link
             __attribute__ ((unused)), int width __attribute__ ((unused)), build_body_callback frame_body_cb)
 {
-  int size = 0;
-  size += snprintf(&buf[size], bufsize - size, "<div id=\"maintable\">\n");
-  size += frame_body_cb(&buf[size], bufsize - size);
-  size += snprintf(&buf[size], bufsize - size, "</div>\n");
-  return size;
+  abuf_puts(abuf, "<div id=\"maintable\">\n");
+  frame_body_cb(abuf);
+  abuf_puts(abuf, "</div>\n");
 }
 
-static int
-fmt_href(char *buf, const uint32_t bufsize, const char *const ipaddr)
+static void
+fmt_href(struct autobuf *abuf, const char *const ipaddr)
 {
-  return snprintf(buf, bufsize, "<a href=\"http://%s:%d/all\">", ipaddr, http_port);
+  abuf_appendf(abuf, "<a href=\"http://%s:%d/all\">", ipaddr, http_port);
 }
 
-static int
-build_ip_txt(char *buf, const uint32_t bufsize, const bool print_link, const char *const ipaddrstr, const int prefix_len)
+static void
+build_ip_txt(struct autobuf *abuf, const bool print_link, const char *const ipaddrstr, const int prefix_len)
 {
-  int size = 0;
-
   if (print_link) {
-    size += fmt_href(&buf[size], bufsize - size, ipaddrstr);
+    fmt_href(abuf, ipaddrstr);
   }
 
-  size += snprintf(&buf[size], bufsize - size, "%s", ipaddrstr);
+  abuf_puts(abuf, ipaddrstr);
   /* print ip address or ip prefix ? */
   if (prefix_len != -1 && prefix_len != olsr_cnf->maxplen) {
-    size += snprintf(&buf[size], bufsize - size, "/%d", prefix_len);
+    abuf_appendf(abuf, "/%d", prefix_len);
   }
 
   if (print_link) {             /* Print the link only if there is no prefix_len */
-    size += snprintf(&buf[size], bufsize - size, "</a>");
+    abuf_puts(abuf, "</a>");
   }
-  return size;
 }
 
-static int
-build_ipaddr_link(char *buf, const uint32_t bufsize, const bool want_link, const union olsr_ip_addr *const ipaddr,
+static void
+build_ipaddr_link(struct autobuf *abuf, const bool want_link, const union olsr_ip_addr *const ipaddr,
                   const int prefix_len)
 {
-  int size = 0;
   struct ipaddr_str ipaddrstr;
   const struct hostent *const hp =
 #ifndef WIN32
@@ -670,95 +734,82 @@ build_ipaddr_link(char *buf, const uint32_t bufsize, const bool want_link, const
   const int print_link = want_link && (prefix_len == -1 || prefix_len == olsr_cnf->maxplen);
   olsr_ip_to_string(&ipaddrstr, ipaddr);
 
-  size += snprintf(&buf[size], bufsize - size, "<td>");
-  size += build_ip_txt(&buf[size], bufsize - size, print_link, ipaddrstr.buf, prefix_len);
-  size += snprintf(&buf[size], bufsize - size, "</td>");
+  abuf_puts(abuf, "<td>");
+  build_ip_txt(abuf, print_link, ipaddrstr.buf, prefix_len);
+  abuf_puts(abuf, "</td>");
 
   if (resolve_ip_addresses) {
     if (hp) {
-      size += snprintf(&buf[size], bufsize - size, "<td>(");
+      abuf_puts(abuf, "<td>(");
       if (print_link) {
-        size += fmt_href(&buf[size], bufsize - size, ipaddrstr.buf);
+        fmt_href(abuf, ipaddrstr.buf);
       }
-      size += snprintf(&buf[size], bufsize - size, "%s", hp->h_name);
+      abuf_puts(abuf, hp->h_name);
       if (print_link) {
-        size += snprintf(&buf[size], bufsize - size, "</a>");
+        abuf_puts(abuf, "</a>");
       }
-      size += snprintf(&buf[size], bufsize - size, ")</td>");
+      abuf_puts(abuf, ")</td>");
     } else {
-      size += snprintf(&buf[size], bufsize - size, "<td/>");
+      abuf_puts(abuf, "<td/>");
     }
   }
-  return size;
 }
 
-#define build_ipaddr_with_link(buf, bufsize, ipaddr, plen) \
-          build_ipaddr_link((buf), (bufsize), true, (ipaddr), (plen))
-#define build_ipaddr_no_link(buf, bufsize, ipaddr, plen) \
-          build_ipaddr_link((buf), (bufsize), false, (ipaddr), (plen))
+#define build_ipaddr_with_link(buf, ipaddr, plen) \
+          build_ipaddr_link((buf), true, (ipaddr), (plen))
+#define build_ipaddr_no_link(buf, ipaddr, plen) \
+          build_ipaddr_link((buf), false, (ipaddr), (plen))
 
-static int
-build_route(char *buf, uint32_t bufsize, const struct rt_entry *rt)
+static void
+build_route(struct autobuf *abuf, const struct rt_entry *rt)
 {
-  int size = 0;
   struct lqtextbuffer lqbuffer;
 
-  size += snprintf(&buf[size], bufsize - size, "<tr>");
-  size += build_ipaddr_with_link(&buf[size], bufsize - size, &rt->rt_dst.prefix, rt->rt_dst.prefix_len);
-  size += build_ipaddr_with_link(&buf[size], bufsize - size, &rt->rt_best->rtp_nexthop.gateway, -1);
+  abuf_puts(abuf, "<tr>");
+  build_ipaddr_with_link(abuf, &rt->rt_dst.prefix, rt->rt_dst.prefix_len);
+  build_ipaddr_with_link(abuf, &rt->rt_best->rtp_nexthop.gateway, -1);
 
-  size += snprintf(&buf[size], bufsize - size, "<td>%d</td>", rt->rt_best->rtp_metric.hops);
-  size +=
-    snprintf(&buf[size], bufsize - size, "<td>%s</td>",
+  abuf_appendf(abuf, "<td>%d</td>", rt->rt_best->rtp_metric.hops);
+  abuf_appendf(abuf, "<td>%s</td>",
              get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer));
-  size +=
-    snprintf(&buf[size], bufsize - size, "<td>%s</td></tr>\n",
+  abuf_appendf(abuf, "<td>%s</td></tr>\n",
              if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
-  return size;
 }
 
-static int
-build_routes_body(char *buf, uint32_t bufsize)
+static void
+build_routes_body(struct autobuf *abuf)
 {
-  int size = 0;
   struct rt_entry *rt;
   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
-  size += section_title(&buf[size], bufsize - size, "OLSR Routes in Kernel");
-  size +=
-    snprintf(&buf[size], bufsize - size,
+  section_title(abuf, "OLSR Routes in Kernel");
+  abuf_appendf(abuf,
              "<tr><th%s>Destination</th><th%s>Gateway</th><th>Metric</th><th>ETX</th><th>Interface</th></tr>\n",
              colspan, colspan);
 
   /* Walk the route table */
   OLSR_FOR_ALL_RT_ENTRIES(rt) {
-    size += build_route(&buf[size], bufsize - size, rt);
+    build_route(abuf, rt);
   } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
 
-  size += snprintf(&buf[size], bufsize - size, "</table>\n");
-
-  return size;
+  abuf_puts(abuf, "</table>\n");
 }
 
-static int
-build_config_body(char *buf, uint32_t bufsize)
+static void
+build_config_body(struct autobuf *abuf)
 {
-  int size = 0;
   const struct olsr_if *ifs;
   const struct plugin_entry *pentry;
   const struct plugin_param *pparam;
   struct ipaddr_str mainaddrbuf;
 
-  size += snprintf(&buf[size], bufsize - size, "Version: %s (built on %s on %s)\n<br>", olsrd_version, build_date, build_host);
-  size += snprintf(&buf[size], bufsize - size, "OS: %s\n<br>", OS);
+  abuf_appendf(abuf, "Version: %s (built on %s on %s)\n<br>", olsrd_version, build_date, build_host);
+  abuf_appendf(abuf, "OS: %s\n<br>", OS);
 
   {
     const time_t currtime = time(NULL);
-    const int rc = strftime(&buf[size], bufsize - size,
-                            "System time: <em>%a, %d %b %Y %H:%M:%S</em><br>",
+
+    abuf_strftime(abuf, "System time: <em>%a, %d %b %Y %H:%M:%S</em><br>",
                             localtime(&currtime));
-    if (rc > 0) {
-      size += rc;
-    }
   }
 
   {
@@ -774,179 +825,157 @@ build_config_body(char *buf, uint32_t bufsize)
     mins = uptime.tv_sec / 60;
     uptime.tv_sec %= 60;
 
-    size += snprintf(&buf[size], bufsize - size, "Olsrd uptime: <em>");
+    abuf_puts(abuf, "Olsrd uptime: <em>");
     if (days) {
-      size += snprintf(&buf[size], bufsize - size, "%d day(s) ", days);
+      abuf_appendf(abuf, "%d day(s) ", days);
     }
-    size +=
-      snprintf(&buf[size], bufsize - size, "%02d hours %02d minutes %02d seconds</em><br/>\n", hours, mins, (int)uptime.tv_sec);
+    abuf_appendf(abuf, "%02d hours %02d minutes %02d seconds</em><br/>\n", hours, mins, (int)uptime.tv_sec);
   }
 
-  size +=
-    snprintf(&buf[size], bufsize - size, "HTTP stats(ok/dyn/error/illegal): <em>%d/%d/%d/%d</em><br>\n", stats.ok_hits,
+  abuf_appendf(abuf, "HTTP stats(ok/dyn/error/illegal): <em>%d/%d/%d/%d</em><br>\n", stats.ok_hits,
              stats.dyn_hits, stats.err_hits, stats.ill_hits);
 
-  size +=
-    snprintf(&buf[size], bufsize - size,
+  abuf_puts(abuf,
              "Click <a href=\"/cfgfile\">here</a> to <em>generate a configuration file for this node</em>.\n");
 
-  size += snprintf(&buf[size], bufsize - size, "<h2>Variables</h2>\n");
+  abuf_puts(abuf, "<h2>Variables</h2>\n");
 
-  size += snprintf(&buf[size], bufsize - size, "<table width=\"100%%\" border=\"0\">\n<tr>");
+  abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n<tr>");
 
-  size +=
-    snprintf(&buf[size], bufsize - size, "<td>Main address: <strong>%s</strong></td>\n",
+  abuf_appendf(abuf, "<td>Main address: <strong>%s</strong></td>\n",
              olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->main_addr));
-  size += snprintf(&buf[size], bufsize - size, "<td>IP version: %d</td>\n", olsr_cnf->ip_version == AF_INET ? 4 : 6);
-  size += snprintf(&buf[size], bufsize - size, "<td>Debug level: %d</td>\n", olsr_cnf->debug_level);
-  size +=
-    snprintf(&buf[size], bufsize - size, "<td>FIB Metrics: %s</td>\n",
+  abuf_appendf(abuf, "<td>IP version: %d</td>\n", olsr_cnf->ip_version == AF_INET ? 4 : 6);
+  abuf_appendf(abuf, "<td>Debug level: %d</td>\n", olsr_cnf->debug_level);
+  abuf_appendf(abuf, "<td>FIB Metrics: %s</td>\n",
              FIBM_FLAT == olsr_cnf->fib_metric ? CFG_FIBM_FLAT : FIBM_CORRECT ==
              olsr_cnf->fib_metric ? CFG_FIBM_CORRECT : CFG_FIBM_APPROX);
 
-  size += snprintf(&buf[size], bufsize - size, "</tr>\n<tr>\n");
+  abuf_puts(abuf, "</tr>\n<tr>\n");
 
-  size += snprintf(&buf[size], bufsize - size, "<td>Pollrate: %0.2f</td>\n", olsr_cnf->pollrate);
-  size += snprintf(&buf[size], bufsize - size, "<td>TC redundancy: %d</td>\n", olsr_cnf->tc_redundancy);
-  size += snprintf(&buf[size], bufsize - size, "<td>MPR coverage: %d</td>\n", olsr_cnf->mpr_coverage);
-  size += snprintf(&buf[size], bufsize - size, "<td>NAT threshold: %f</td>\n", olsr_cnf->lq_nat_thresh);
+  abuf_appendf(abuf, "<td>Pollrate: %0.2f</td>\n", olsr_cnf->pollrate);
+  abuf_appendf(abuf, "<td>TC redundancy: %d</td>\n", olsr_cnf->tc_redundancy);
+  abuf_appendf(abuf, "<td>MPR coverage: %d</td>\n", olsr_cnf->mpr_coverage);
+  abuf_appendf(abuf, "<td>NAT threshold: %f</td>\n", olsr_cnf->lq_nat_thresh);
 
-  size += snprintf(&buf[size], bufsize - size, "</tr>\n<tr>\n");
+  abuf_puts(abuf, "</tr>\n<tr>\n");
 
-  size += snprintf(&buf[size], bufsize - size, "<td>Fisheye: %s</td>\n", olsr_cnf->lq_fish ? "Enabled" : "Disabled");
-  size += snprintf(&buf[size], bufsize - size, "<td>TOS: 0x%04x</td>\n", olsr_cnf->tos);
-  size += snprintf(&buf[size], bufsize - size, "<td>RtTable: 0x%04x/%d</td>\n", olsr_cnf->rttable, olsr_cnf->rttable);
-  size +=
-    snprintf(&buf[size], bufsize - size, "<td>RtTableDefault: 0x%04x/%d</td>\n", olsr_cnf->rttable_default,
+  abuf_appendf(abuf, "<td>Fisheye: %s</td>\n", olsr_cnf->lq_fish ? "Enabled" : "Disabled");
+  abuf_appendf(abuf, "<td>TOS: 0x%04x</td>\n", olsr_cnf->tos);
+  abuf_appendf(abuf, "<td>RtTable: 0x%04x/%d</td>\n", olsr_cnf->rttable, olsr_cnf->rttable);
+  abuf_appendf(abuf, "<td>RtTableDefault: 0x%04x/%d</td>\n", olsr_cnf->rttable_default,
              olsr_cnf->rttable_default);
-  size +=
-    snprintf(&buf[size], bufsize - size, "<td>Willingness: %d %s</td>\n", olsr_cnf->willingness,
+  abuf_appendf(abuf, "<td>Willingness: %d %s</td>\n", olsr_cnf->willingness,
              olsr_cnf->willingness_auto ? "(auto)" : "");
 
   if (olsr_cnf->lq_level == 0) {
-    size +=
-      snprintf(&buf[size], bufsize - size, "</tr>\n<tr>\n" "<td>Hysteresis: %s</td>\n",
+    abuf_appendf(abuf, "</tr>\n<tr>\n" "<td>Hysteresis: %s</td>\n",
                olsr_cnf->use_hysteresis ? "Enabled" : "Disabled");
     if (olsr_cnf->use_hysteresis) {
-      size += snprintf(&buf[size], bufsize - size, "<td>Hyst scaling: %0.2f</td>\n", olsr_cnf->hysteresis_param.scaling);
-      size +=
-        snprintf(&buf[size], bufsize - size, "<td>Hyst lower/upper: %0.2f/%0.2f</td>\n", olsr_cnf->hysteresis_param.thr_low,
+      abuf_appendf(abuf, "<td>Hyst scaling: %0.2f</td>\n", olsr_cnf->hysteresis_param.scaling);
+      abuf_appendf(abuf, "<td>Hyst lower/upper: %0.2f/%0.2f</td>\n", olsr_cnf->hysteresis_param.thr_low,
                  olsr_cnf->hysteresis_param.thr_high);
     }
   }
 
-  size +=
-    snprintf(&buf[size], bufsize - size, "</tr>\n<tr>\n" "<td>LQ extension: %s</td>\n",
+  abuf_appendf(abuf, "</tr>\n<tr>\n" "<td>LQ extension: %s</td>\n",
              olsr_cnf->lq_level ? "Enabled" : "Disabled");
   if (olsr_cnf->lq_level) {
-    size +=
-      snprintf(&buf[size], bufsize - size, "<td>LQ level: %d</td>\n" "<td>LQ aging: %f</td>\n", olsr_cnf->lq_level,
+    abuf_appendf(abuf, "<td>LQ level: %d</td>\n" "<td>LQ aging: %f</td>\n", olsr_cnf->lq_level,
                olsr_cnf->lq_aging);
   }
-  size += snprintf(&buf[size], bufsize - size, "</tr></table>\n");
+  abuf_puts(abuf, "</tr></table>\n");
 
-  size += snprintf(&buf[size], bufsize - size, "<h2>Interfaces</h2>\n");
-  size += snprintf(&buf[size], bufsize - size, "<table width=\"100%%\" border=\"0\">\n");
+  abuf_puts(abuf, "<h2>Interfaces</h2>\n");
+  abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n");
   for (ifs = olsr_cnf->interfaces; ifs != NULL; ifs = ifs->next) {
     const struct interface *const rifs = ifs->interf;
-    size += snprintf(&buf[size], bufsize - size, "<tr><th colspan=\"3\">%s</th>\n", ifs->name);
+    abuf_appendf(abuf, "<tr><th colspan=\"3\">%s</th>\n", ifs->name);
     if (!rifs) {
-      size += snprintf(&buf[size], bufsize - size, "<tr><td colspan=\"3\">Status: DOWN</td></tr>\n");
+      abuf_puts(abuf, "<tr><td colspan=\"3\">Status: DOWN</td></tr>\n");
       continue;
     }
 
     if (olsr_cnf->ip_version == AF_INET) {
       struct ipaddr_str addrbuf, maskbuf, bcastbuf;
-      size +=
-        snprintf(&buf[size], bufsize - size, "<tr>\n" "<td>IP: %s</td>\n" "<td>MASK: %s</td>\n" "<td>BCAST: %s</td>\n" "</tr>\n",
+      abuf_appendf(abuf, "<tr>\n" "<td>IP: %s</td>\n" "<td>MASK: %s</td>\n" "<td>BCAST: %s</td>\n" "</tr>\n",
                  ip4_to_string(&addrbuf, rifs->int_addr.sin_addr), ip4_to_string(&maskbuf, rifs->int_netmask.sin_addr),
                  ip4_to_string(&bcastbuf, rifs->int_broadaddr.sin_addr));
     } else {
       struct ipaddr_str addrbuf, maskbuf;
-      size +=
-        snprintf(&buf[size], bufsize - size, "<tr>\n" "<td>IP: %s</td>\n" "<td>MCAST: %s</td>\n" "<td></td>\n" "</tr>\n",
+      abuf_appendf(abuf, "<tr>\n" "<td>IP: %s</td>\n" "<td>MCAST: %s</td>\n" "<td></td>\n" "</tr>\n",
                  ip6_to_string(&addrbuf, &rifs->int6_addr.sin6_addr), ip6_to_string(&maskbuf, &rifs->int6_multaddr.sin6_addr));
     }
-    size +=
-      snprintf(&buf[size], bufsize - size, "<tr>\n" "<td>MTU: %d</td>\n" "<td>WLAN: %s</td>\n" "<td>STATUS: UP</td>\n" "</tr>\n",
+    abuf_appendf(abuf, "<tr>\n" "<td>MTU: %d</td>\n" "<td>WLAN: %s</td>\n" "<td>STATUS: UP</td>\n" "</tr>\n",
                rifs->int_mtu, rifs->is_wireless ? "Yes" : "No");
   }
-  size += snprintf(&buf[size], bufsize - size, "</table>\n");
+  abuf_puts(abuf, "</table>\n");
 
-  size +=
-    snprintf(&buf[size], bufsize - size, "<em>Olsrd is configured to %s if no interfaces are available</em><br>\n",
+  abuf_appendf(abuf, "<em>Olsrd is configured to %s if no interfaces are available</em><br>\n",
              olsr_cnf->allow_no_interfaces ? "run even" : "halt");
 
-  size += snprintf(&buf[size], bufsize - size, "<h2>Plugins</h2>\n");
-  size += snprintf(&buf[size], bufsize - size, "<table width=\"100%%\" border=\"0\"><tr><th>Name</th><th>Parameters</th></tr>\n");
+  abuf_puts(abuf, "<h2>Plugins</h2>\n");
+  abuf_puts(abuf, "<table width=\"100%%\" border=\"0\"><tr><th>Name</th><th>Parameters</th></tr>\n");
   for (pentry = olsr_cnf->plugins; pentry; pentry = pentry->next) {
-    size +=
-      snprintf(&buf[size], bufsize - size, "<tr><td>%s</td>\n" "<td><select>\n" "<option>KEY, VALUE</option>\n", pentry->name);
+    abuf_appendf(abuf, "<tr><td>%s</td>\n" "<td><select>\n" "<option>KEY, VALUE</option>\n", pentry->name);
 
     for (pparam = pentry->params; pparam; pparam = pparam->next) {
-      size += snprintf(&buf[size], bufsize - size, "<option>\"%s\", \"%s\"</option>\n", pparam->key, pparam->value);
+      abuf_appendf(abuf, "<option>\"%s\", \"%s\"</option>\n", pparam->key, pparam->value);
     }
-    size += snprintf(&buf[size], bufsize - size, "</select></td></tr>\n");
+    abuf_puts(abuf, "</select></td></tr>\n");
 
   }
-  size += snprintf(&buf[size], bufsize - size, "</table>\n");
+  abuf_puts(abuf, "</table>\n");
 
-  size += section_title(&buf[size], bufsize - size, "Announced HNA entries");
+  section_title(abuf, "Announced HNA entries");
   if (olsr_cnf->hna_entries) {
     struct ip_prefix_list *hna;
-    size += snprintf(&buf[size], bufsize - size, "<tr><th>Network</th></tr>\n");
+    abuf_puts(abuf, "<tr><th>Network</th></tr>\n");
     for (hna = olsr_cnf->hna_entries; hna; hna = hna->next) {
       struct ipaddr_str netbuf;
-      size +=
-        snprintf(&buf[size], bufsize - size, "<tr><td>%s/%d</td></tr>\n", olsr_ip_to_string(&netbuf, &hna->net.prefix),
+      abuf_appendf(abuf, "<tr><td>%s/%d</td></tr>\n", olsr_ip_to_string(&netbuf, &hna->net.prefix),
                  hna->net.prefix_len);
     }
   } else {
-    size += snprintf(&buf[size], bufsize - size, "<tr><td></td></tr>\n");
+    abuf_puts(abuf, "<tr><td></td></tr>\n");
   }
-  size += snprintf(&buf[size], bufsize - size, "</table>\n");
-  return size;
+  abuf_puts(abuf, "</table>\n");
 }
 
-static int
-build_neigh_body(char *buf, uint32_t bufsize)
+static void
+build_neigh_body(struct autobuf *abuf)
 {
   struct neighbor_entry *neigh;
   struct link_entry *link = NULL;
-  int size = 0;
   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
 
-  size += section_title(&buf[size], bufsize - size, "Links");
+  section_title(abuf, "Links");
 
-  size +=
-    snprintf(&buf[size], bufsize - size,
+  abuf_appendf(abuf,
              "<tr><th%s>Local IP</th><th%s>Remote IP</th><th>Hysteresis</th>",
              colspan, colspan);
   if (olsr_cnf->lq_level > 0) {
-    size += snprintf(&buf[size], bufsize - size, "<th>LinkCost</th>");
+    abuf_puts(abuf, "<th>LinkCost</th>");
   }
-  size += snprintf(&buf[size], bufsize - size, "</tr>\n");
+  abuf_puts(abuf, "</tr>\n");
 
   /* Link set */
   OLSR_FOR_ALL_LINK_ENTRIES(link) {
-    size += snprintf(&buf[size], bufsize - size, "<tr>");
-    size += build_ipaddr_with_link(&buf[size], bufsize, &link->local_iface_addr, -1);
-    size += build_ipaddr_with_link(&buf[size], bufsize, &link->neighbor_iface_addr, -1);
-    size += snprintf(&buf[size], bufsize - size, "<td>%0.2f</td>", link->L_link_quality);
+    abuf_puts(abuf, "<tr>");
+    build_ipaddr_with_link(abuf, &link->local_iface_addr, -1);
+    build_ipaddr_with_link(abuf, &link->neighbor_iface_addr, -1);
+    abuf_appendf(abuf, "<td>%0.2f</td>", link->L_link_quality);
     if (olsr_cnf->lq_level > 0) {
       struct lqtextbuffer lqbuffer1, lqbuffer2;
-      size +=
-        snprintf(&buf[size], bufsize - size, "<td>(%s) %s</td>", get_link_entry_text(link, '/', &lqbuffer1),
+      abuf_appendf(abuf, "<td>(%s) %s</td>", get_link_entry_text(link, '/', &lqbuffer1),
                  get_linkcost_text(link->linkcost, false, &lqbuffer2));
     }
-    size += snprintf(&buf[size], bufsize - size, "</tr>\n");
+    abuf_puts(abuf, "</tr>\n");
   } OLSR_FOR_ALL_LINK_ENTRIES_END(link);
 
-  size += snprintf(&buf[size], bufsize - size, "</table>\n");
+  abuf_puts(abuf, "</table>\n");
 
-  size += section_title(&buf[size], bufsize - size, "Neighbors");
-  size +=
-    snprintf(&buf[size], bufsize - size,
+  section_title(abuf, "Neighbors");
+  abuf_appendf(abuf,
              "<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",
              colspan);
   /* Neighbors */
@@ -954,77 +983,68 @@ build_neigh_body(char *buf, uint32_t bufsize)
 
     struct neighbor_2_list_entry *list_2;
     int thop_cnt;
-    size += snprintf(&buf[size], bufsize - size, "<tr>");
-    size += build_ipaddr_with_link(&buf[size], bufsize, &neigh->neighbor_main_addr, -1);
-    size +=
-      snprintf(&buf[size], bufsize - size,
+    abuf_puts(abuf, "<tr>");
+    build_ipaddr_with_link(abuf, &neigh->neighbor_main_addr, -1);
+    abuf_appendf(abuf,
                "<td>%s</td>" "<td>%s</td>" "<td>%s</td>"
                "<td>%d</td>", (neigh->status == SYM) ? "YES" : "NO", neigh->is_mpr ? "YES" : "NO",
                olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO", neigh->willingness);
 
-    size += snprintf(&buf[size], bufsize - size, "<td><select>\n" "<option>IP ADDRESS</option>\n");
+    abuf_puts(abuf, "<td><select>\n" "<option>IP ADDRESS</option>\n");
 
     for (list_2 = neigh->neighbor_2_list.next, thop_cnt = 0; list_2 != &neigh->neighbor_2_list; list_2 = list_2->next, thop_cnt++) {
       struct ipaddr_str strbuf;
-      size +=
-        snprintf(&buf[size], bufsize - size, "<option>%s</option>\n",
+      abuf_appendf(abuf, "<option>%s</option>\n",
                  olsr_ip_to_string(&strbuf, &list_2->neighbor_2->neighbor_2_addr));
     }
-    size += snprintf(&buf[size], bufsize - size, "</select> (%d)</td></tr>\n", thop_cnt);
+    abuf_appendf(abuf, "</select> (%d)</td></tr>\n", thop_cnt);
   } OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
 
-  size += snprintf(&buf[size], bufsize - size, "</table>\n");
-  return size;
+  abuf_puts(abuf, "</table>\n");
 }
 
-static int
-build_topo_body(char *buf, uint32_t bufsize)
+static void
+build_topo_body(struct autobuf *abuf)
 {
-  int size = 0;
   struct tc_entry *tc;
   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
 
-  size += section_title(&buf[size], bufsize - size, "Topology Entries");
-  size +=
-    snprintf(&buf[size], bufsize - size, "<tr><th%s>Destination IP</th><th%s>Last Hop IP</th>",
+  section_title(abuf, "Topology Entries");
+  abuf_appendf(abuf, "<tr><th%s>Destination IP</th><th%s>Last Hop IP</th>",
              colspan, colspan);
   if (olsr_cnf->lq_level > 0) {
-    size += snprintf(&buf[size], bufsize - size, "<th>Linkcost</th>");
+    abuf_puts(abuf, "<th>Linkcost</th>");
   }
-  size += snprintf(&buf[size], bufsize - size, "</tr>\n");
+  abuf_puts(abuf, "</tr>\n");
 
   OLSR_FOR_ALL_TC_ENTRIES(tc) {
     struct tc_edge_entry *tc_edge;
     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
       if (tc_edge->edge_inv) {
-        size += snprintf(&buf[size], bufsize - size, "<tr>");
-        size += build_ipaddr_with_link(&buf[size], bufsize, &tc_edge->T_dest_addr, -1);
-        size += build_ipaddr_with_link(&buf[size], bufsize, &tc->addr, -1);
+        abuf_puts(abuf, "<tr>");
+        build_ipaddr_with_link(abuf, &tc_edge->T_dest_addr, -1);
+        build_ipaddr_with_link(abuf, &tc->addr, -1);
         if (olsr_cnf->lq_level > 0) {
           struct lqtextbuffer lqbuffer1, lqbuffer2;
-          size +=
-            snprintf(&buf[size], bufsize - size, "<td>(%s) %s</td>\n",
+          abuf_appendf(abuf, "<td>(%s) %s</td>\n",
                      get_tc_edge_entry_text(tc_edge, '/', &lqbuffer1), get_linkcost_text(tc_edge->cost, false, &lqbuffer2));
         }
-        size += snprintf(&buf[size], bufsize - size, "</tr>\n");
+        abuf_puts(abuf, "</tr>\n");
       }
     } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
 
-  size += snprintf(&buf[size], bufsize - size, "</table>\n");
-
-  return size;
+  abuf_puts(abuf, "</table>\n");
 }
 
-static int
-build_mid_body(char *buf, uint32_t bufsize)
+static void
+build_mid_body(struct autobuf *abuf)
 {
-  int size = 0;
   int idx;
   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
 
-  size += section_title(&buf[size], bufsize - size, "MID Entries");
-  size += snprintf(&buf[size], bufsize - size, "<tr><th%s>Main Address</th><th>Aliases</th></tr>\n", colspan);
+  section_title(abuf, "MID Entries");
+  abuf_appendf(abuf, "<tr><th%s>Main Address</th><th>Aliases</th></tr>\n", colspan);
 
   /* MID */
   for (idx = 0; idx < HASHSIZE; idx++) {
@@ -1032,52 +1052,43 @@ build_mid_body(char *buf, uint32_t bufsize)
     for (entry = mid_set[idx].next; entry != &mid_set[idx]; entry = entry->next) {
       int mid_cnt;
       struct mid_address *alias;
-      size += snprintf(&buf[size], bufsize - size, "<tr>");
-      size += build_ipaddr_with_link(&buf[size], bufsize, &entry->main_addr, -1);
-      size += snprintf(&buf[size], bufsize - size, "<td><select>\n<option>IP ADDRESS</option>\n");
+      abuf_puts(abuf, "<tr>");
+      build_ipaddr_with_link(abuf, &entry->main_addr, -1);
+      abuf_puts(abuf, "<td><select>\n<option>IP ADDRESS</option>\n");
 
       for (mid_cnt = 0, alias = entry->aliases; alias != NULL; alias = alias->next_alias, mid_cnt++) {
         struct ipaddr_str strbuf;
-        size += snprintf(&buf[size], bufsize - size, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &alias->alias));
+        abuf_appendf(abuf, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &alias->alias));
       }
-      size += snprintf(&buf[size], bufsize - size, "</select> (%d)</td></tr>\n", mid_cnt);
+      abuf_appendf(abuf, "</select> (%d)</td></tr>\n", mid_cnt);
     }
   }
 
-  size += snprintf(&buf[size], bufsize - size, "</table>\n");
-  return size;
+  abuf_puts(abuf, "</table>\n");
 }
 
-static int
-build_nodes_body(char *buf, uint32_t bufsize)
+static void
+build_nodes_body(struct autobuf *abuf)
 {
-  int size = 0;
-
-  size += build_neigh_body(&buf[size], bufsize - size);
-  size += build_topo_body(&buf[size], bufsize - size);
-  size += build_mid_body(&buf[size], bufsize - size);
-
-  return size;
+  build_neigh_body(abuf);
+  build_topo_body(abuf);
+  build_mid_body(abuf);
 }
 
-static int
-build_all_body(char *buf, uint32_t bufsize)
+static void
+build_all_body(struct autobuf *abuf)
 {
-  int size = 0;
-
-  size += build_config_body(&buf[size], bufsize - size);
-  size += build_routes_body(&buf[size], bufsize - size);
-  size += build_neigh_body(&buf[size], bufsize - size);
-  size += build_topo_body(&buf[size], bufsize - size);
-  size += build_mid_body(&buf[size], bufsize - size);
-
-  return size;
+  build_config_body(abuf);
+  build_routes_body(abuf);
+  build_neigh_body(abuf);
+  build_topo_body(abuf);
+  build_mid_body(abuf);
 }
 
-static int
-build_about_body(char *buf, uint32_t bufsize)
+static void
+build_about_body(struct autobuf *abuf)
 {
-  return snprintf(buf, bufsize,
+  abuf_appendf(abuf,
                   "<strong>" PLUGIN_NAME " version " PLUGIN_VERSION "</strong><br/>\n" "by Andreas T&oslash;nnesen (C)2005.<br/>\n"
                   "Compiled "
 #ifdef ADMIN_INTERFACE
@@ -1115,39 +1126,33 @@ build_about_body(char *buf, uint32_t bufsize)
                   build_host);
 }
 
-static int
-build_cfgfile_body(char *buf, uint32_t bufsize)
+static void
+build_cfgfile_body(struct autobuf *abuf)
 {
-  int size = 0;
-
-  size +=
-    snprintf(&buf[size], bufsize - size,
+  abuf_puts(abuf,
              "\n\n" "<strong>This is a automatically generated configuration\n"
              "file based on the current olsrd configuration of this node.<br/>\n" "<hr/>\n" "<pre>\n");
 
-#ifdef NETDIRECT
   {
     /* Hack to make netdirect stuff work with
        olsrd_write_cnf_buf
      */
     char tmpBuf[10000];
+    int size;
     size = olsrd_write_cnf_buf(olsr_cnf, tmpBuf, 10000);
-    snprintf(&buf[size], bufsize - size, tmpBuf);
-  }
-#else
-  size += olsrd_write_cnf_buf(olsr_cnf, &buf[size], bufsize - size);
-#endif
-
-  if (size < 0) {
-    size = snprintf(buf, size, "ERROR GENERATING CONFIGFILE!\n");
+    if (size < 0) {
+      abuf_puts(abuf, "ERROR GENERATING CONFIGFILE!\n");
+    }
+    else {
+      abuf_puts(abuf, tmpBuf);
+    }
   }
 
-  size += snprintf(&buf[size], bufsize - size, "</pre>\n<hr/>\n");
+  abuf_puts(abuf, "</pre>\n<hr/>\n");
 
 #if 0
   printf("RETURNING %d\n", size);
 #endif
-  return size;
 }
 
 static int
@@ -1192,26 +1197,6 @@ netsprintf(char *str, const char *format, ...)
 }
 #endif
 
-static ssize_t
-writen(int fd, const void *buf, size_t count)
-{
-  size_t bytes_left = count;
-  const char *p = buf;
-  while (bytes_left > 0) {
-    const ssize_t written = write(fd, p, bytes_left);
-    if (written == -1) {        /* error */
-      if (errno == EINTR) {
-        continue;
-      }
-      return -1;
-    }
-    /* We wrote something */
-    bytes_left -= written;
-    p += written;
-  }
-  return count;
-}
-
 /*
  * Local Variables:
  * c-basic-offset: 2
index 23e37e4..9c08bfe 100644 (file)
@@ -60,7 +60,6 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <stdarg.h>
 #include <unistd.h>
 #include <errno.h>
 
@@ -77,6 +76,7 @@
 #include "socket_parser.h"
 #include "net_olsr.h"
 #include "lq_plugin.h"
+#include "common/autobuf.h"
 
 #include "olsrd_txtinfo.h"
 #include "olsrd_plugin.h"
 #endif
 
 static int ipc_socket;
-static int ipc_open;
-static int ipc_connection;
-static int ipc_socket_up;
 
 /* IPC initialization function */
 static int plugin_ipc_init(void);
 
-static void send_info(int send_what);
+static void send_info(int send_what, int socket);
 
 static void ipc_action(int);
 
-static void ipc_print_neigh(void);
+static void ipc_print_neigh(struct autobuf *);
 
-static void ipc_print_link(void);
+static void ipc_print_link(struct autobuf *);
 
-static void ipc_print_routes(void);
+static void ipc_print_routes(struct autobuf *);
 
-static void ipc_print_topology(void);
+static void ipc_print_topology(struct autobuf *);
 
-static void ipc_print_hna(void);
+static void ipc_print_hna(struct autobuf *);
 
-static void ipc_print_mid(void);
+static void ipc_print_mid(struct autobuf *);
 
 #define TXT_IPC_BUFSIZE 256
 
@@ -120,7 +117,15 @@ static void ipc_print_mid(void);
 #define SIW_TOPO 6
 #define SIW_NEIGHLINK 7
 
-static int ipc_sendf(const char *format, ...) __attribute__ ((format(printf, 1, 2)));
+#define MAX_CLIENTS 3
+
+static char *outbuffer[MAX_CLIENTS];
+static size_t outbuffer_size[MAX_CLIENTS];
+static size_t outbuffer_written[MAX_CLIENTS];
+static int outbuffer_socket[MAX_CLIENTS];
+static int outbuffer_count;
+
+static struct timer_entry *writetimer_entry;
 
 /**
  *Do initialization here
@@ -132,8 +137,7 @@ int
 olsrd_plugin_init(void)
 {
   /* Initial IPC value */
-  ipc_open = 0;
-  ipc_socket_up = 0;
+  ipc_socket = -1;
 
   plugin_ipc_init();
   return 1;
@@ -145,7 +149,7 @@ olsrd_plugin_init(void)
 void
 olsr_plugin_exit(void)
 {
-  if (ipc_open)
+  if (ipc_socket != -1)
     close(ipc_socket);
 }
 
@@ -223,7 +227,6 @@ plugin_ipc_init(void)
 #ifndef NODEBUG
     olsr_printf(2, "(TXTINFO) listening on port %d\n", ipc_port);
 #endif
-    ipc_socket_up = 1;
   }
   return 1;
 }
@@ -238,12 +241,10 @@ ipc_action(int fd)
   fd_set rfds;
   struct timeval tv;
   int send_what = 0;
+  int ipc_connection;
 
   socklen_t addrlen = sizeof(struct sockaddr_storage);
 
-  if (ipc_open)
-    return;
-
   if ((ipc_connection = accept(fd, (struct sockaddr *)&pin, &addrlen)) == -1) {
 #ifndef NODEBUG
     olsr_printf(1, "(TXTINFO) accept()=%s\n", strerror(errno));
@@ -272,7 +273,7 @@ ipc_action(int fd)
       return;
     }
   }
-  ipc_open = 1;
+
 #ifndef NODEBUG
   olsr_printf(2, "(TXTINFO) Connect from %s\n", addr);
 #endif
@@ -306,25 +307,22 @@ ipc_action(int fd)
     }
   }
 
-  send_info(send_what);
-
-  close(ipc_connection);
-  ipc_open = 0;
+  send_info(send_what, ipc_connection);
 }
 
 static void
-ipc_print_neigh(void)
+ipc_print_neigh(struct autobuf *abuf)
 {
   struct ipaddr_str buf1;
   struct neighbor_entry *neigh;
   struct neighbor_2_list_entry *list_2;
   int thop_cnt;
 
-  ipc_sendf("Table: Neighbors\nIP address\tSYM\tMPR\tMPRS\tWill.\t2 Hop Neighbors\n");
+  abuf_puts(abuf, "Table: Neighbors\nIP address\tSYM\tMPR\tMPRS\tWill.\t2 Hop Neighbors\n");
 
   /* Neighbors */
   OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
-    ipc_sendf("%s\t%s\t%s\t%s\t%d\t", olsr_ip_to_string(&buf1, &neigh->neighbor_main_addr), (neigh->status == SYM) ? "YES" : "NO",
+    abuf_appendf(abuf, "%s\t%s\t%s\t%s\t%d\t", olsr_ip_to_string(&buf1, &neigh->neighbor_main_addr), (neigh->status == SYM) ? "YES" : "NO",
               neigh->is_mpr ? "YES" : "NO", olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO", neigh->willingness);
     thop_cnt = 0;
 
@@ -332,60 +330,60 @@ ipc_print_neigh(void)
       //size += sprintf(&buf[size], "<option>%s</option>\n", olsr_ip_to_string(&buf1, &list_2->neighbor_2->neighbor_2_addr));
       thop_cnt++;
     }
-    ipc_sendf("%d\n", thop_cnt);
+    abuf_appendf(abuf, "%d\n", thop_cnt);
   }
   OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
-  ipc_sendf("\n");
+  abuf_puts(abuf, "\n");
 }
 
 static void
-ipc_print_link(void)
+ipc_print_link(struct autobuf *abuf)
 {
   struct ipaddr_str buf1, buf2;
   struct lqtextbuffer lqbuffer1, lqbuffer2;
 
   struct link_entry *link = NULL;
 
-  ipc_sendf("Table: Links\nLocal IP\tRemote IP\tHyst.\tLQ\tNLQ\tCost\n");
+  abuf_puts(abuf, "Table: Links\nLocal IP\tRemote IP\tHyst.\tLQ\tNLQ\tCost\n");
 
   /* Link set */
   OLSR_FOR_ALL_LINK_ENTRIES(link) {
-    ipc_sendf("%s\t%s\t%0.2f\t%s\t%s\t\n", olsr_ip_to_string(&buf1, &link->local_iface_addr),
+    abuf_appendf(abuf, "%s\t%s\t%0.2f\t%s\t%s\t\n", olsr_ip_to_string(&buf1, &link->local_iface_addr),
               olsr_ip_to_string(&buf2, &link->neighbor_iface_addr), link->L_link_quality, get_link_entry_text(link, '\t',
                                                                                                               &lqbuffer1),
               get_linkcost_text(link->linkcost, false, &lqbuffer2));
   } OLSR_FOR_ALL_LINK_ENTRIES_END(link);
 
-  ipc_sendf("\n");
+  abuf_puts(abuf, "\n");
 }
 
 static void
-ipc_print_routes(void)
+ipc_print_routes(struct autobuf *abuf)
 {
   struct ipaddr_str buf1, buf2;
   struct rt_entry *rt;
   struct lqtextbuffer lqbuffer;
 
-  ipc_sendf("Table: Routes\nDestination\tGateway IP\tMetric\tETX\tInterface\n");
+  abuf_puts(abuf, "Table: Routes\nDestination\tGateway IP\tMetric\tETX\tInterface\n");
 
   /* Walk the route table */
   OLSR_FOR_ALL_RT_ENTRIES(rt) {
-    ipc_sendf("%s/%d\t%s\t%d\t%s\t%s\t\n", olsr_ip_to_string(&buf1, &rt->rt_dst.prefix), rt->rt_dst.prefix_len,
+    abuf_appendf(abuf, "%s/%d\t%s\t%d\t%s\t%s\t\n", olsr_ip_to_string(&buf1, &rt->rt_dst.prefix), rt->rt_dst.prefix_len,
               olsr_ip_to_string(&buf2, &rt->rt_best->rtp_nexthop.gateway), rt->rt_best->rtp_metric.hops,
               get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer),
               if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
   } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
 
-  ipc_sendf("\n");
+  abuf_puts(abuf, "\n");
 
 }
 
 static void
-ipc_print_topology(void)
+ipc_print_topology(struct autobuf *abuf)
 {
   struct tc_entry *tc;
 
-  ipc_sendf("Table: Topology\nDest. IP\tLast hop IP\tLQ\tNLQ\tCost\n");
+  abuf_puts(abuf, "Table: Topology\nDest. IP\tLast hop IP\tLQ\tNLQ\tCost\n");
 
   /* Topology */
   OLSR_FOR_ALL_TC_ENTRIES(tc) {
@@ -394,17 +392,17 @@ ipc_print_topology(void)
       if (tc_edge->edge_inv) {
         struct ipaddr_str dstbuf, addrbuf;
         struct lqtextbuffer lqbuffer1, lqbuffer2;
-        ipc_sendf("%s\t%s\t%s\t%s\n", olsr_ip_to_string(&dstbuf, &tc_edge->T_dest_addr), olsr_ip_to_string(&addrbuf, &tc->addr),
+        abuf_appendf(abuf, "%s\t%s\t%s\t%s\n", olsr_ip_to_string(&dstbuf, &tc_edge->T_dest_addr), olsr_ip_to_string(&addrbuf, &tc->addr),
                   get_tc_edge_entry_text(tc_edge, '\t', &lqbuffer1), get_linkcost_text(tc_edge->cost, false, &lqbuffer2));
       }
     } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
 
-  ipc_sendf("\n");
+  abuf_puts(abuf, "\n");
 }
 
 static void
-ipc_print_hna(void)
+ipc_print_hna(struct autobuf *abuf)
 {
   int size;
   struct ip_prefix_list *hna;
@@ -414,19 +412,19 @@ ipc_print_hna(void)
 
   size = 0;
 
-  ipc_sendf("Table: HNA\nDestination\tGateway\n");
+  abuf_puts(abuf, "Table: HNA\nDestination\tGateway\n");
 
   /* Announced HNA entries */
   if (olsr_cnf->ip_version == AF_INET) {
     for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next) {
       struct ipaddr_str addrbuf, mainaddrbuf;
-      ipc_sendf("%s/%d\t%s\n", olsr_ip_to_string(&addrbuf, &hna->net.prefix), hna->net.prefix_len,
+      abuf_appendf(abuf, "%s/%d\t%s\n", olsr_ip_to_string(&addrbuf, &hna->net.prefix), hna->net.prefix_len,
                 olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->main_addr));
     }
   } else {
     for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next) {
       struct ipaddr_str addrbuf, mainaddrbuf;
-      ipc_sendf("%s/%d\t%s\n", olsr_ip_to_string(&addrbuf, &hna->net.prefix), hna->net.prefix_len,
+      abuf_appendf(abuf, "%s/%d\t%s\n", olsr_ip_to_string(&addrbuf, &hna->net.prefix), hna->net.prefix_len,
                 olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->main_addr));
     }
   }
@@ -437,24 +435,24 @@ ipc_print_hna(void)
     /* Check all networks */
     for (tmp_net = tmp_hna->networks.next; tmp_net != &tmp_hna->networks; tmp_net = tmp_net->next) {
 
-      ipc_sendf("%s/%d\t%s\n", olsr_ip_to_string(&addrbuf, &tmp_net->A_network_addr), tmp_net->prefixlen,
+      abuf_appendf(abuf, "%s/%d\t%s\n", olsr_ip_to_string(&addrbuf, &tmp_net->A_network_addr), tmp_net->prefixlen,
                 olsr_ip_to_string(&mainaddrbuf, &tmp_hna->A_gateway_addr));
     }
   }
   OLSR_FOR_ALL_HNA_ENTRIES_END(tmp_hna);
 
-  ipc_sendf("\n");
+  abuf_puts(abuf, "\n");
 }
 
 static void
-ipc_print_mid(void)
+ipc_print_mid(struct autobuf *abuf)
 {
   int index;
   unsigned short is_first;
   struct mid_entry *entry;
   struct mid_address *alias;
 
-  ipc_sendf("Table: MID\nIP address\tAliases\n");
+  abuf_puts(abuf, "Table: MID\nIP address\tAliases\n");
 
   /* MID */
   for (index = 0; index < HASHSIZE; index++) {
@@ -462,88 +460,122 @@ ipc_print_mid(void)
 
     while (entry != &mid_set[index]) {
       struct ipaddr_str buf;
-      ipc_sendf("%s", olsr_ip_to_string(&buf, &entry->main_addr));
+      abuf_puts(abuf, olsr_ip_to_string(&buf, &entry->main_addr));
       alias = entry->aliases;
       is_first = 1;
 
       while (alias) {
-        ipc_sendf("%s%s", (is_first ? "\t" : ";"), olsr_ip_to_string(&buf, &alias->alias));
+        abuf_appendf(abuf, "%s%s", (is_first ? "\t" : ";"), olsr_ip_to_string(&buf, &alias->alias));
 
         alias = alias->next_alias;
         is_first = 0;
       }
       entry = entry->next;
-      ipc_sendf("\n");
+      abuf_puts(abuf,"\n");
+    }
+  }
+  abuf_puts(abuf, "\n");
+}
+
+static void
+txtinfo_write_data(void *foo __attribute__ ((unused))) {
+  fd_set set;
+  int result, i, j, max;
+  struct timeval tv;
+
+  FD_ZERO(&set);
+  max = 0;
+  for (i=0; i<outbuffer_count; i++) {
+    FD_SET(outbuffer_socket[i], &set);
+    if (outbuffer_socket[i] > max) {
+      max = outbuffer_socket[i];
+    }
+  }
+
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+
+  result = select(max + 1, NULL, &set, NULL, &tv);
+  if (result <= 0) {
+    return;
+  }
+
+  for (i=0; i<outbuffer_count; i++) {
+    if (FD_ISSET(outbuffer_socket[i], &set)) {
+      result = write(outbuffer_socket[i], outbuffer[i] + outbuffer_written[i], outbuffer_size[i] - outbuffer_written[i]);
+      if (result > 0) {
+        outbuffer_written[i] += result;
+      }
+
+      if (result <= 0 || outbuffer_written[i] == outbuffer_size[i]) {
+        /* close this socket and cleanup*/
+        close(outbuffer_socket[i]);
+        free (outbuffer[i]);
+
+        for (j=i+1; j<outbuffer_count; j++) {
+          outbuffer[j-1] = outbuffer[j];
+          outbuffer_size[j-1] = outbuffer_size[j];
+          outbuffer_socket[j-1] = outbuffer_socket[j];
+          outbuffer_written[j-1] = outbuffer_written[j];
+        }
+        outbuffer_count--;
+      }
     }
   }
-  ipc_sendf("\n");
+  if (outbuffer_count == 0) {
+    olsr_stop_timer(writetimer_entry);
+  }
 }
 
 static void
-send_info(int send_what)
+send_info(int send_what, int socket)
 {
+  struct autobuf abuf;
+
+  abuf_init(&abuf, 4096);
+
   /* Print minimal http header */
-  ipc_sendf("HTTP/1.0 200 OK\n");
-  ipc_sendf("Content-type: text/plain\n\n");
+  abuf_puts(&abuf, "HTTP/1.0 200 OK\n");
+  abuf_puts(&abuf, "Content-type: text/plain\n\n");
 
   /* Print tables to IPC socket */
 
   /* links + Neighbors */
   if ((send_what == SIW_ALL) || (send_what == SIW_NEIGHLINK) || (send_what == SIW_LINK))
-    ipc_print_link();
+    ipc_print_link(&abuf);
 
   if ((send_what == SIW_ALL) || (send_what == SIW_NEIGHLINK) || (send_what == SIW_NEIGH))
-    ipc_print_neigh();
+    ipc_print_neigh(&abuf);
 
   /* topology */
   if ((send_what == SIW_ALL) || (send_what == SIW_TOPO))
-    ipc_print_topology();
+    ipc_print_topology(&abuf);
 
   /* hna */
   if ((send_what == SIW_ALL) || (send_what == SIW_HNA))
-    ipc_print_hna();
+    ipc_print_hna(&abuf);
 
   /* mid */
   if ((send_what == SIW_ALL) || (send_what == SIW_MID))
-    ipc_print_mid();
+    ipc_print_mid(&abuf);
 
   /* routes */
   if ((send_what == SIW_ALL) || (send_what == SIW_ROUTE))
-    ipc_print_routes();
-}
+    ipc_print_routes(&abuf);
 
-/*
- * In a bigger mesh, there are probs with the fixed
- * bufsize. Because the Content-Length header is
- * optional, the sprintf() is changed to a more
- * scalable solution here.
- */
+  outbuffer[outbuffer_count] = olsr_malloc(abuf.len, "txt output buffer");
+  outbuffer_size[outbuffer_count] = abuf.len;
+  outbuffer_written[outbuffer_count] = 0;
+  outbuffer_socket[outbuffer_count] = socket;
 
-static int
-ipc_sendf(const char *format, ...)
-{
-  char txtnetbuf[TXT_IPC_BUFSIZE];
-
-  va_list arg;
-  int rv;
-#if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __MacOSX__
-  int flags = 0;
-#else
-  int flags = MSG_NOSIGNAL;
-#endif
-  va_start(arg, format);
-  rv = vsnprintf(txtnetbuf, sizeof(txtnetbuf), format, arg);
-  va_end(arg);
-  if (ipc_socket_up) {
-    if (0 > send(ipc_connection, txtnetbuf, rv, flags)) {
-#ifndef NODEBUG
-      olsr_printf(1, "(TXTINFO) Failed sending data to client!\n");
-#endif
-      close(ipc_connection);
-      return -1;
-    }
+  memcpy(outbuffer[outbuffer_count], abuf.buf, abuf.len);
+  outbuffer_count++;
+
+  if (outbuffer_count == 1) {
+    writetimer_entry = olsr_start_timer(100, 0, OLSR_TIMER_PERIODIC, &txtinfo_write_data, NULL, 0);
   }
-  return rv;
+
+  abuf_free(&abuf);
 }
 
 /*
diff --git a/src/common/autobuf.c b/src/common/autobuf.c
new file mode 100644 (file)
index 0000000..e41d654
--- /dev/null
@@ -0,0 +1,221 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include "common/autobuf.h"
+#include "defs.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+
+static int autobuf_enlarge(struct autobuf *autobuf, int new_size);
+
+
+int
+abuf_init(struct autobuf *autobuf, int initial_size)
+{
+  autobuf->len = 0;
+  if (initial_size <= 0) {
+    autobuf->size = 0;
+    autobuf->buf = NULL;
+    return 0;
+  }
+  autobuf->size = ROUND_UP_TO_POWER_OF_2(initial_size, AUTOBUFCHUNK);
+  autobuf->buf = calloc(autobuf->size, 1);
+  if (autobuf->buf == NULL) {
+    autobuf->size = 0;
+    return -1;
+  }
+  *autobuf->buf = '\0';
+  return 0;
+}
+
+void
+abuf_free(struct autobuf *autobuf)
+{
+  free(autobuf->buf);
+  autobuf->buf = NULL;
+  autobuf->len = 0;
+  autobuf->size = 0;
+}
+
+static int
+autobuf_enlarge(struct autobuf *autobuf, int new_size)
+{
+  new_size++;
+  if (new_size > autobuf->size) {
+    char *p;
+    int roundUpSize = ROUND_UP_TO_POWER_OF_2(new_size, AUTOBUFCHUNK);
+    p = realloc(autobuf->buf, roundUpSize);
+    if (p == NULL) {
+#ifdef WIN32
+      WSASetLastError(ENOMEM);
+#else
+      errno = ENOMEM;
+#endif
+      return -1;
+    }
+    autobuf->buf = p;
+
+    memset(&autobuf->buf[autobuf->size], 0, roundUpSize - autobuf->size);
+    autobuf->size = roundUpSize;
+  }
+  return 0;
+}
+
+int
+abuf_vappendf(struct autobuf *autobuf, const char *format, va_list ap)
+{
+  int rc;
+  int min_size;
+  va_list ap2;
+  va_copy(ap2, ap);
+  rc = vsnprintf(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, ap);
+  va_end(ap);
+  min_size = autobuf->len + rc;
+  if (min_size >= autobuf->size) {
+    if (autobuf_enlarge(autobuf, min_size) < 0) {
+      autobuf->buf[autobuf->len] = '\0';
+      return -1;
+    }
+    vsnprintf(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, ap2);
+  }
+  va_end(ap2);
+  autobuf->len = min_size;
+  return 0;
+}
+
+int
+abuf_appendf(struct autobuf *autobuf, const char *fmt, ...)
+{
+  int rv;
+  va_list ap;
+  va_start(ap, fmt);
+  rv = abuf_vappendf(autobuf, fmt, ap);
+  va_end(ap);
+  return rv;
+}
+
+int
+abuf_puts(struct autobuf *autobuf, const char *s)
+{
+  int len = strlen(s);
+  if (autobuf_enlarge(autobuf, autobuf->len + len + 1) < 0) {
+    return -1;
+  }
+  strcpy(autobuf->buf + autobuf->len, s);
+  autobuf->len += len;
+  return len;
+}
+
+int
+abuf_strftime(struct autobuf *autobuf, const char *format, const struct tm *tm)
+{
+  int rc = strftime(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, tm);
+  if (rc == 0) {
+    /* we had an error! Probably the buffer too small. So we add some bytes. */
+    if (autobuf_enlarge(autobuf, autobuf->size + AUTOBUFCHUNK) < 0) {
+      autobuf->buf[autobuf->len] = '\0';
+      return -1;
+    }
+    rc = strftime(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, tm);
+  }
+  autobuf->len += rc;
+  return rc;
+}
+
+int
+abuf_memcpy(struct autobuf *autobuf, const void *p, const unsigned int len)
+{
+  if (autobuf_enlarge(autobuf, autobuf->len + len) < 0) {
+    return -1;
+  }
+  memcpy(autobuf->buf + autobuf->len, p, len);
+  autobuf->len += len;
+  return len;
+}
+
+int
+abuf_memcpy_prefix(struct autobuf *autobuf, const void *p, const unsigned int len)
+{
+  if (autobuf_enlarge(autobuf, autobuf->len + len) < 0) {
+    return -1;
+  }
+  memmove(&autobuf->buf[len], autobuf->buf, autobuf->len);
+  memcpy(autobuf->buf, p, len);
+  autobuf->len += len;
+  return len;
+}
+
+int
+abuf_pull(struct autobuf * autobuf, int len) {
+  char *p;
+  size_t newsize;
+
+  if (len != autobuf->len) {
+    memmove(autobuf->buf, &autobuf->buf[len], autobuf->len - len);
+  }
+  autobuf->len -= len;
+
+  newsize = ROUND_UP_TO_POWER_OF_2(autobuf->len + 1, AUTOBUFCHUNK);
+  p = realloc(autobuf->buf, newsize);
+  if (p == NULL) {
+#ifdef WIN32
+    WSASetLastError(ENOMEM);
+#else
+    errno = ENOMEM;
+#endif
+    return -1;
+  }
+  autobuf->buf = p;
+  autobuf->size = newsize;
+  return 0;
+}
+/*
+ * Local Variables:
+ * mode: c
+ * style: linux
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/common/autobuf.h b/src/common/autobuf.h
new file mode 100644 (file)
index 0000000..0076920
--- /dev/null
@@ -0,0 +1,76 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef _COMMON_AUTOBUF_H
+#define _COMMON_AUTOBUF_H
+
+#include "defs.h"
+#include <stdarg.h>
+#include <time.h>
+
+#define ROUND_UP_TO_POWER_OF_2(val, pow2) (((val) + (pow2) - 1) & ~((pow2) - 1))
+
+#define AUTOBUFCHUNK   4096
+struct autobuf {
+  int size;
+  int len;
+  char *buf;
+};
+
+int abuf_init (struct autobuf * autobuf, int initial_size);
+void abuf_free (struct autobuf * autobuf);
+int abuf_vappendf (struct autobuf *autobuf, const char *fmt, va_list ap) __attribute__ ((format(printf, 2, 0)));
+int abuf_appendf (struct autobuf * autobuf, const char *fmt, ...) __attribute__ ((format(printf, 2, 3)));
+int abuf_puts (struct autobuf * autobuf, const char *s);
+int abuf_strftime (struct autobuf * autobuf, const char *format, const struct tm * tm);
+int abuf_memcpy (struct autobuf * autobuf, const void *p, const unsigned int len);
+int abuf_memcpy_prefix (struct autobuf *autobuf, const void *p, const unsigned int len);
+int abuf_pull (struct autobuf * autobuf, int len);
+#endif
+
+/*
+ * Local Variables:
+ * mode: c
+ * style: linux
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */