]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/buffer.c
isisd: implemented the 'sequence-number-skipped' notification
[mirror_frr.git] / lib / buffer.c
index 649677fc93ea237e2c55c9f1272d6e324cbf4bd4..bb2cdb7e5449dd2084e8a32a90df1620a09dc42f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Buffering of output and input. 
+ * Buffering of output and input.
  * Copyright (C) 1998 Kunihiro Ishiguro
  *
  * This file is part of GNU Zebra.
 #include "buffer.h"
 #include "log.h"
 #include "network.h"
+#include "lib_errors.h"
+
 #include <stddef.h>
 
-DEFINE_MTYPE_STATIC(LIB, BUFFER,      "Buffer")
+DEFINE_MTYPE_STATIC(LIB, BUFFER, "Buffer")
 DEFINE_MTYPE_STATIC(LIB, BUFFER_DATA, "Buffer data")
 
 /* Buffer master. */
-struct buffer
-{
-  /* Data list. */
-  struct buffer_data *head;
-  struct buffer_data *tail;
-  
-  /* Size of each buffer_data chunk. */
-  size_t size;
+struct buffer {
+       /* Data list. */
+       struct buffer_data *head;
+       struct buffer_data *tail;
+
+       /* Size of each buffer_data chunk. */
+       size_t size;
 };
 
 /* Data container. */
-struct buffer_data
-{
-  struct buffer_data *next;
+struct buffer_data {
+       struct buffer_data *next;
 
-  /* Location to add new data. */
-  size_t cp;
+       /* Location to add new data. */
+       size_t cp;
 
-  /* Pointer to data not yet flushed. */
-  size_t sp;
+       /* Pointer to data not yet flushed. */
+       size_t sp;
 
-  /* Actual data stream (variable length). */
-  unsigned char data[];  /* real dimension is buffer->size */
+       /* Actual data stream (variable length). */
+       unsigned char data[]; /* real dimension is buffer->size */
 };
 
 /* It should always be true that: 0 <= sp <= cp <= size */
@@ -62,327 +62,339 @@ struct buffer_data
    next page boundery. */
 #define BUFFER_SIZE_DEFAULT            4096
 
-
 #define BUFFER_DATA_FREE(D) XFREE(MTYPE_BUFFER_DATA, (D))
 
 /* Make new buffer. */
-struct buffer *
-buffer_new (size_t size)
+struct buffer *buffer_new(size_t size)
 {
-  struct buffer *b;
-
-  b = XCALLOC (MTYPE_BUFFER, sizeof (struct buffer));
-
-  if (size)
-    b->size = size;
-  else
-    {
-      static size_t default_size;
-      if (!default_size)
-        {
-         long pgsz = sysconf(_SC_PAGESIZE);
-         default_size = ((((BUFFER_SIZE_DEFAULT-1)/pgsz)+1)*pgsz);
+       struct buffer *b;
+
+       b = XCALLOC(MTYPE_BUFFER, sizeof(struct buffer));
+
+       if (size)
+               b->size = size;
+       else {
+               static size_t default_size;
+               if (!default_size) {
+                       long pgsz = sysconf(_SC_PAGESIZE);
+                       default_size = ((((BUFFER_SIZE_DEFAULT - 1) / pgsz) + 1)
+                                       * pgsz);
+               }
+               b->size = default_size;
        }
-      b->size = default_size;
-    }
 
-  return b;
+       return b;
 }
 
 /* Free buffer. */
-void
-buffer_free (struct buffer *b)
+void buffer_free(struct buffer *b)
 {
-  buffer_reset(b);
-  XFREE (MTYPE_BUFFER, b);
+       buffer_reset(b);
+       XFREE(MTYPE_BUFFER, b);
 }
 
 /* Make string clone. */
-char *
-buffer_getstr (struct buffer *b)
+char *buffer_getstr(struct buffer *b)
 {
-  size_t totlen = 0;
-  struct buffer_data *data;
-  char *s;
-  char *p;
-
-  for (data = b->head; data; data = data->next)
-    totlen += data->cp - data->sp;
-  if (!(s = XMALLOC(MTYPE_TMP, totlen+1)))
-    return NULL;
-  p = s;
-  for (data = b->head; data; data = data->next)
-    {
-      memcpy(p, data->data + data->sp, data->cp - data->sp);
-      p += data->cp - data->sp;
-    }
-  *p = '\0';
-  return s;
+       size_t totlen = 0;
+       struct buffer_data *data;
+       char *s;
+       char *p;
+
+       for (data = b->head; data; data = data->next)
+               totlen += data->cp - data->sp;
+       if (!(s = XMALLOC(MTYPE_TMP, totlen + 1)))
+               return NULL;
+       p = s;
+       for (data = b->head; data; data = data->next) {
+               memcpy(p, data->data + data->sp, data->cp - data->sp);
+               p += data->cp - data->sp;
+       }
+       *p = '\0';
+       return s;
 }
 
 /* Return 1 if buffer is empty. */
-int
-buffer_empty (struct buffer *b)
+int buffer_empty(struct buffer *b)
 {
-  return (b->head == NULL);
+       return (b->head == NULL);
 }
 
 /* Clear and free all allocated data. */
-void
-buffer_reset (struct buffer *b)
+void buffer_reset(struct buffer *b)
 {
-  struct buffer_data *data;
-  struct buffer_data *next;
-  
-  for (data = b->head; data; data = next)
-    {
-      next = data->next;
-      BUFFER_DATA_FREE(data);
-    }
-  b->head = b->tail = NULL;
+       struct buffer_data *data;
+       struct buffer_data *next;
+
+       for (data = b->head; data; data = next) {
+               next = data->next;
+               BUFFER_DATA_FREE(data);
+       }
+       b->head = b->tail = NULL;
 }
 
 /* Add buffer_data to the end of buffer. */
-static struct buffer_data *
-buffer_add (struct buffer *b)
+static struct buffer_data *buffer_add(struct buffer *b)
 {
-  struct buffer_data *d;
+       struct buffer_data *d;
 
-  d = XMALLOC(MTYPE_BUFFER_DATA, offsetof(struct buffer_data, data) + b->size);
-  d->cp = d->sp = 0;
-  d->next = NULL;
+       d = XMALLOC(MTYPE_BUFFER_DATA,
+                   offsetof(struct buffer_data, data) + b->size);
+       d->cp = d->sp = 0;
+       d->next = NULL;
 
-  if (b->tail)
-    b->tail->next = d;
-  else
-    b->head = d;
-  b->tail = d;
+       if (b->tail)
+               b->tail->next = d;
+       else
+               b->head = d;
+       b->tail = d;
 
-  return d;
+       return d;
 }
 
 /* Write data to buffer. */
-void
-buffer_put(struct buffer *b, const void *p, size_t size)
+void buffer_put(struct buffer *b, const void *p, size_t size)
 {
-  struct buffer_data *data = b->tail;
-  const char *ptr = p;
-
-  /* We use even last one byte of data buffer. */
-  while (size)    
-    {
-      size_t chunk;
-
-      /* If there is no data buffer add it. */
-      if (data == NULL || data->cp == b->size)
-       data = buffer_add (b);
-
-      chunk = ((size <= (b->size - data->cp)) ? size : (b->size - data->cp));
-      memcpy ((data->data + data->cp), ptr, chunk);
-      size -= chunk;
-      ptr += chunk;
-      data->cp += chunk;
-    }
+       struct buffer_data *data = b->tail;
+       const char *ptr = p;
+
+       /* We use even last one byte of data buffer. */
+       while (size) {
+               size_t chunk;
+
+               /* If there is no data buffer add it. */
+               if (data == NULL || data->cp == b->size)
+                       data = buffer_add(b);
+
+               chunk = ((size <= (b->size - data->cp)) ? size
+                                                       : (b->size - data->cp));
+               memcpy((data->data + data->cp), ptr, chunk);
+               size -= chunk;
+               ptr += chunk;
+               data->cp += chunk;
+       }
 }
 
 /* Insert character into the buffer. */
-void
-buffer_putc (struct buffer *b, u_char c)
+void buffer_putc(struct buffer *b, uint8_t c)
 {
-  buffer_put(b, &c, 1);
+       buffer_put(b, &c, 1);
 }
 
 /* Put string to the buffer. */
-void
-buffer_putstr (struct buffer *b, const char *c)
+void buffer_putstr(struct buffer *b, const char *c)
 {
-  buffer_put(b, c, strlen(c));
+       buffer_put(b, c, strlen(c));
+}
+
+/* Expand \n to \r\n */
+void buffer_put_crlf(struct buffer *b, const void *origp, size_t origsize)
+{
+       struct buffer_data *data = b->tail;
+       const char *p = origp, *end = p + origsize, *lf;
+       size_t size;
+
+       lf = memchr(p, '\n', end - p);
+
+       /* We use even last one byte of data buffer. */
+       while (p < end) {
+               size_t avail, chunk;
+
+               /* If there is no data buffer add it. */
+               if (data == NULL || data->cp == b->size)
+                       data = buffer_add(b);
+
+               size = (lf ? lf : end) - p;
+               avail = b->size - data->cp;
+
+               chunk = (size <= avail) ? size : avail;
+               memcpy(data->data + data->cp, p, chunk);
+
+               p += chunk;
+               data->cp += chunk;
+
+               if (lf && size <= avail) {
+                       /* we just copied up to (including) a '\n' */
+                       if (data->cp == b->size)
+                               data = buffer_add(b);
+                       data->data[data->cp++] = '\r';
+                       if (data->cp == b->size)
+                               data = buffer_add(b);
+                       data->data[data->cp++] = '\n';
+
+                       p++;
+                       lf = memchr(p, '\n', end - p);
+               }
+       }
 }
 
 /* Keep flushing data to the fd until the buffer is empty or an error is
    encountered or the operation would block. */
-buffer_status_t
-buffer_flush_all (struct buffer *b, int fd)
+buffer_status_t buffer_flush_all(struct buffer *b, int fd)
 {
-  buffer_status_t ret;
-  struct buffer_data *head;
-  size_t head_sp;
-
-  if (!b->head)
-    return BUFFER_EMPTY;
-  head_sp = (head = b->head)->sp;
-  /* Flush all data. */
-  while ((ret = buffer_flush_available(b, fd)) == BUFFER_PENDING)
-    {
-      if ((b->head == head) && (head_sp == head->sp) && (errno != EINTR))
-        /* No data was flushed, so kernel buffer must be full. */
-       return ret;
-      head_sp = (head = b->head)->sp;
-    }
+       buffer_status_t ret;
+       struct buffer_data *head;
+       size_t head_sp;
+
+       if (!b->head)
+               return BUFFER_EMPTY;
+       head_sp = (head = b->head)->sp;
+       /* Flush all data. */
+       while ((ret = buffer_flush_available(b, fd)) == BUFFER_PENDING) {
+               if ((b->head == head) && (head_sp == head->sp)
+                   && (errno != EINTR))
+                       /* No data was flushed, so kernel buffer must be full.
+                        */
+                       return ret;
+               head_sp = (head = b->head)->sp;
+       }
 
-  return ret;
+       return ret;
 }
 
 /* Flush enough data to fill a terminal window of the given scene (used only
    by vty telnet interface). */
-buffer_status_t
-buffer_flush_window (struct buffer *b, int fd, int width, int height, 
-                    int erase_flag, int no_more_flag)
+buffer_status_t buffer_flush_window(struct buffer *b, int fd, int width,
+                                   int height, int erase_flag,
+                                   int no_more_flag)
 {
-  int nbytes;
-  int iov_alloc;
-  int iov_index;
-  struct iovec *iov;
-  struct iovec small_iov[3];
-  char more[] = " --More-- ";
-  char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
-                  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
-                  0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
-  struct buffer_data *data;
-  int column;
-
-  if (!b->head)
-    return BUFFER_EMPTY;
-
-  if (height < 1)
-    {
-      zlog_warn("%s called with non-positive window height %d, forcing to 1",
-               __func__, height);
-      height = 1;
-    }
-  else if (height >= 2)
-    height--;
-  if (width < 1)
-    {
-      zlog_warn("%s called with non-positive window width %d, forcing to 1",
-               __func__, width);
-      width = 1;
-    }
-
-  /* For erase and more data add two to b's buffer_data count.*/
-  if (b->head->next == NULL)
-    {
-      iov_alloc = array_size(small_iov);
-      iov = small_iov;
-    }
-  else
-    {
-      iov_alloc = ((height*(width+2))/b->size)+10;
-      iov = XMALLOC(MTYPE_TMP, iov_alloc*sizeof(*iov));
-    }
-  iov_index = 0;
-
-  /* Previously print out is performed. */
-  if (erase_flag)
-    {
-      iov[iov_index].iov_base = erase;
-      iov[iov_index].iov_len = sizeof erase;
-      iov_index++;
-    }
-
-  /* Output data. */
-  column = 1;  /* Column position of next character displayed. */
-  for (data = b->head; data && (height > 0); data = data->next)
-    {
-      size_t cp;
-
-      cp = data->sp;
-      while ((cp < data->cp) && (height > 0))
-        {
-         /* Calculate lines remaining and column position after displaying
-            this character. */
-         if (data->data[cp] == '\r')
-           column = 1;
-         else if ((data->data[cp] == '\n') || (column == width))
-           {
-             column = 1;
-             height--;
-           }
-         else
-           column++;
-         cp++;
-        }
-      iov[iov_index].iov_base = (char *)(data->data + data->sp);
-      iov[iov_index++].iov_len = cp-data->sp;
-      data->sp = cp;
-
-      if (iov_index == iov_alloc)
-       /* This should not ordinarily happen. */
-        {
-         iov_alloc *= 2;
-         if (iov != small_iov)
-           {
-             zlog_warn("%s: growing iov array to %d; "
-                       "width %d, height %d, size %lu",
-                       __func__, iov_alloc, width, height, (u_long)b->size);
-             iov = XREALLOC(MTYPE_TMP, iov, iov_alloc*sizeof(*iov));
-           }
-         else
-           {
-             /* This should absolutely never occur. */
-             zlog_err("%s: corruption detected: iov_small overflowed; "
-                      "head %p, tail %p, head->next %p",
-                      __func__, (void *)b->head, (void *)b->tail,
-                      (void *)b->head->next);
-             iov = XMALLOC(MTYPE_TMP, iov_alloc*sizeof(*iov));
-             memcpy(iov, small_iov, sizeof(small_iov));
-           }
+       int nbytes;
+       int iov_alloc;
+       int iov_index;
+       struct iovec *iov;
+       struct iovec small_iov[3];
+       char more[] = " --More-- ";
+       char erase[] = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+                       0x08, 0x08, ' ',  ' ',  ' ',  ' ',  ' ',  ' ',
+                       ' ',  ' ',  ' ',  ' ',  0x08, 0x08, 0x08, 0x08,
+                       0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
+       struct buffer_data *data;
+       int column;
+
+       if (!b->head)
+               return BUFFER_EMPTY;
+
+       if (height < 1)
+               height = 1;
+       else if (height >= 2)
+               height--;
+       if (width < 1)
+               width = 1;
+
+       /* For erase and more data add two to b's buffer_data count.*/
+       if (b->head->next == NULL) {
+               iov_alloc = array_size(small_iov);
+               iov = small_iov;
+       } else {
+               iov_alloc = ((height * (width + 2)) / b->size) + 10;
+               iov = XMALLOC(MTYPE_TMP, iov_alloc * sizeof(*iov));
+       }
+       iov_index = 0;
+
+       /* Previously print out is performed. */
+       if (erase_flag) {
+               iov[iov_index].iov_base = erase;
+               iov[iov_index].iov_len = sizeof erase;
+               iov_index++;
+       }
+
+       /* Output data. */
+       column = 1; /* Column position of next character displayed. */
+       for (data = b->head; data && (height > 0); data = data->next) {
+               size_t cp;
+
+               cp = data->sp;
+               while ((cp < data->cp) && (height > 0)) {
+                       /* Calculate lines remaining and column position after
+                          displaying
+                          this character. */
+                       if (data->data[cp] == '\r')
+                               column = 1;
+                       else if ((data->data[cp] == '\n')
+                                || (column == width)) {
+                               column = 1;
+                               height--;
+                       } else
+                               column++;
+                       cp++;
+               }
+               iov[iov_index].iov_base = (char *)(data->data + data->sp);
+               iov[iov_index++].iov_len = cp - data->sp;
+               data->sp = cp;
+
+               if (iov_index == iov_alloc)
+               /* This should not ordinarily happen. */
+               {
+                       iov_alloc *= 2;
+                       if (iov != small_iov) {
+                               iov = XREALLOC(MTYPE_TMP, iov,
+                                              iov_alloc * sizeof(*iov));
+                       } else {
+                               /* This should absolutely never occur. */
+                               flog_err_sys(
+                                       EC_LIB_SYSTEM_CALL,
+                                       "%s: corruption detected: iov_small overflowed; "
+                                       "head %p, tail %p, head->next %p",
+                                       __func__, (void *)b->head,
+                                       (void *)b->tail, (void *)b->head->next);
+                               iov = XMALLOC(MTYPE_TMP,
+                                             iov_alloc * sizeof(*iov));
+                               memcpy(iov, small_iov, sizeof(small_iov));
+                       }
+               }
        }
-    }
 
-  /* In case of `more' display need. */
-  if (b->tail && (b->tail->sp < b->tail->cp) && !no_more_flag)
-    {
-      iov[iov_index].iov_base = more;
-      iov[iov_index].iov_len = sizeof more;
-      iov_index++;
-    }
+       /* In case of `more' display need. */
+       if (b->tail && (b->tail->sp < b->tail->cp) && !no_more_flag) {
+               iov[iov_index].iov_base = more;
+               iov[iov_index].iov_len = sizeof more;
+               iov_index++;
+       }
 
 
 #ifdef IOV_MAX
-  /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
-     example: Solaris2.6 are defined IOV_MAX size at 16.     */
-  {
-    struct iovec *c_iov = iov;
-    nbytes = 0; /* Make sure it's initialized. */
-
-    while (iov_index > 0)
-      {
-        int iov_size;
-
-        iov_size = ((iov_index > IOV_MAX) ? IOV_MAX : iov_index);
-        if ((nbytes = writev(fd, c_iov, iov_size)) < 0)
-          {
-            zlog_warn("%s: writev to fd %d failed: %s",
-                      __func__, fd, safe_strerror(errno));
-            break;
-          }
-
-        /* move pointer io-vector */
-        c_iov += iov_size;
-        iov_index -= iov_size;
-      }
-  }
+       /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
+          example: Solaris2.6 are defined IOV_MAX size at 16.     */
+       {
+               struct iovec *c_iov = iov;
+               nbytes = 0; /* Make sure it's initialized. */
+
+               while (iov_index > 0) {
+                       int iov_size;
+
+                       iov_size =
+                               ((iov_index > IOV_MAX) ? IOV_MAX : iov_index);
+                       if ((nbytes = writev(fd, c_iov, iov_size)) < 0) {
+                               flog_err(EC_LIB_SOCKET,
+                                        "%s: writev to fd %d failed: %s",
+                                        __func__, fd, safe_strerror(errno));
+                               break;
+                       }
+
+                       /* move pointer io-vector */
+                       c_iov += iov_size;
+                       iov_index -= iov_size;
+               }
+       }
 #else  /* IOV_MAX */
-   if ((nbytes = writev (fd, iov, iov_index)) < 0)
-     zlog_warn("%s: writev to fd %d failed: %s",
-              __func__, fd, safe_strerror(errno));
+       if ((nbytes = writev(fd, iov, iov_index)) < 0)
+               flog_err(EC_LIB_SOCKET, "%s: writev to fd %d failed: %s",
+                        __func__, fd, safe_strerror(errno));
 #endif /* IOV_MAX */
 
-  /* Free printed buffer data. */
-  while (b->head && (b->head->sp == b->head->cp))
-    {
-      struct buffer_data *del;
-      if (!(b->head = (del = b->head)->next))
-        b->tail = NULL;
-      BUFFER_DATA_FREE(del);
-    }
+       /* Free printed buffer data. */
+       while (b->head && (b->head->sp == b->head->cp)) {
+               struct buffer_data *del;
+               if (!(b->head = (del = b->head)->next))
+                       b->tail = NULL;
+               BUFFER_DATA_FREE(del);
+       }
 
-  if (iov != small_iov)
-    XFREE (MTYPE_TMP, iov);
+       if (iov != small_iov)
+               XFREE(MTYPE_TMP, iov);
 
-  return (nbytes < 0) ? BUFFER_ERROR :
-                       (b->head ? BUFFER_PENDING : BUFFER_EMPTY);
+       return (nbytes < 0) ? BUFFER_ERROR
+                           : (b->head ? BUFFER_PENDING : BUFFER_EMPTY);
 }
 
 /* This function (unlike other buffer_flush* functions above) is designed
@@ -390,8 +402,7 @@ to work with non-blocking sockets.  It does not attempt to write out
 all of the queued data, just a "big" chunk.  It returns 0 if it was
 able to empty out the buffers completely, 1 if more flushing is
 required later, or -1 on a fatal write error. */
-buffer_status_t
-buffer_flush_available(struct buffer *b, int fd)
+buffer_status_t buffer_flush_available(struct buffer *b, int fd)
 {
 
 /* These are just reasonable values to make sure a significant amount of
@@ -404,94 +415,95 @@ in one shot. */
 #endif
 #define MAX_FLUSH 131072
 
-  struct buffer_data *d;
-  size_t written;
-  struct iovec iov[MAX_CHUNKS];
-  size_t iovcnt = 0;
-  size_t nbyte = 0;
-
-  for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH);
-       d = d->next, iovcnt++)
-    {
-      iov[iovcnt].iov_base = d->data+d->sp;
-      nbyte += (iov[iovcnt].iov_len = d->cp-d->sp);
-    }
-
-  if (!nbyte)
-    /* No data to flush: should we issue a warning message? */
-    return BUFFER_EMPTY;
-
-  /* only place where written should be sign compared */
-  if ((ssize_t)(written = writev(fd,iov,iovcnt)) < 0)
-    {
-      if (ERRNO_IO_RETRY(errno))
-       /* Calling code should try again later. */
-        return BUFFER_PENDING;
-      zlog_warn("%s: write error on fd %d: %s",
-               __func__, fd, safe_strerror(errno));
-      return BUFFER_ERROR;
-    }
-
-  /* Free printed buffer data. */
-  while (written > 0)
-    {
-      struct buffer_data *d;
-      if (!(d = b->head))
-        {
-          zlog_err("%s: corruption detected: buffer queue empty, "
-                  "but written is %lu", __func__, (u_long)written);
-         break;
-        }
-      if (written < d->cp-d->sp)
-        {
-         d->sp += written;
-         return BUFFER_PENDING;
+       struct buffer_data *d;
+       size_t written;
+       struct iovec iov[MAX_CHUNKS];
+       size_t iovcnt = 0;
+       size_t nbyte = 0;
+
+       if (fd < 0)
+               return BUFFER_ERROR;
+
+       for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH);
+            d = d->next, iovcnt++) {
+               iov[iovcnt].iov_base = d->data + d->sp;
+               nbyte += (iov[iovcnt].iov_len = d->cp - d->sp);
        }
 
-      written -= (d->cp-d->sp);
-      if (!(b->head = d->next))
-        b->tail = NULL;
-      BUFFER_DATA_FREE(d);
-    }
+       if (!nbyte)
+               /* No data to flush: should we issue a warning message? */
+               return BUFFER_EMPTY;
+
+       /* only place where written should be sign compared */
+       if ((ssize_t)(written = writev(fd, iov, iovcnt)) < 0) {
+               if (ERRNO_IO_RETRY(errno))
+                       /* Calling code should try again later. */
+                       return BUFFER_PENDING;
+               flog_err(EC_LIB_SOCKET, "%s: write error on fd %d: %s",
+                        __func__, fd, safe_strerror(errno));
+               return BUFFER_ERROR;
+       }
+
+       /* Free printed buffer data. */
+       while (written > 0) {
+               if (!(d = b->head)) {
+                       flog_err(
+                               EC_LIB_DEVELOPMENT,
+                               "%s: corruption detected: buffer queue empty, but written is %lu",
+                               __func__, (unsigned long)written);
+                       break;
+               }
+               if (written < d->cp - d->sp) {
+                       d->sp += written;
+                       return BUFFER_PENDING;
+               }
+
+               written -= (d->cp - d->sp);
+               if (!(b->head = d->next))
+                       b->tail = NULL;
+               BUFFER_DATA_FREE(d);
+       }
 
-  return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
+       return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
 
 #undef MAX_CHUNKS
 #undef MAX_FLUSH
 }
 
-buffer_status_t
-buffer_write(struct buffer *b, int fd, const void *p, size_t size)
+buffer_status_t buffer_write(struct buffer *b, int fd, const void *p,
+                            size_t size)
 {
-  ssize_t nbytes;
+       ssize_t nbytes;
 
 #if 0
-  /* Should we attempt to drain any previously buffered data?  This could help
-     reduce latency in pushing out the data if we are stuck in a long-running
-     thread that is preventing the main select loop from calling the flush
-     thread... */
-  if (b->head && (buffer_flush_available(b, fd) == BUFFER_ERROR))
-    return BUFFER_ERROR;
+       /*
+        * Should we attempt to drain any previously buffered data?
+        * This could help reduce latency in pushing out the data if
+        * we are stuck in a long-running thread that is preventing
+        * the main select loop from calling the flush thread...
+        */
+       if (b->head && (buffer_flush_available(b, fd) == BUFFER_ERROR))
+               return BUFFER_ERROR;
 #endif
-  if (b->head)
-    /* Buffer is not empty, so do not attempt to write the new data. */
-    nbytes = 0;
-  else if ((nbytes = write(fd, p, size)) < 0)
-    {
-      if (ERRNO_IO_RETRY(errno))
-        nbytes = 0;
-      else
-        {
-         zlog_warn("%s: write error on fd %d: %s",
-                   __func__, fd, safe_strerror(errno));
-         return BUFFER_ERROR;
+       if (b->head)
+               /* Buffer is not empty, so do not attempt to write the new data.
+                */
+               nbytes = 0;
+       else if ((nbytes = write(fd, p, size)) < 0) {
+               if (ERRNO_IO_RETRY(errno))
+                       nbytes = 0;
+               else {
+                       flog_err(EC_LIB_SOCKET, "%s: write error on fd %d: %s",
+                                __func__, fd, safe_strerror(errno));
+                       return BUFFER_ERROR;
+               }
+       }
+       /* Add any remaining data to the buffer. */
+       {
+               size_t written = nbytes;
+               if (written < size)
+                       buffer_put(b, ((const char *)p) + written,
+                                  size - written);
        }
-    }
-  /* Add any remaining data to the buffer. */
-  {
-    size_t written = nbytes;
-    if (written < size)
-      buffer_put(b, ((const char *)p)+written, size-written);
-  }
-  return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
+       return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
 }