Import Upstream version 1.2.2
[quagga-debian.git] / lib / buffer.c
1 /*
2  * Buffering of output and input. 
3  * Copyright (C) 1998 Kunihiro Ishiguro
4  *
5  * This file is part of GNU Zebra.
6  *
7  * GNU Zebra is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published
9  * by the Free Software Foundation; either version 2, or (at your
10  * option) any later version.
11  * 
12  * GNU Zebra is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Zebra; see the file COPYING.  If not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA. 
21  */
22
23 #include <zebra.h>
24
25 #include "memory.h"
26 #include "buffer.h"
27 #include "log.h"
28 #include "network.h"
29 #include <stddef.h>
30
31
32
33 /* Buffer master. */
34 struct buffer
35 {
36   /* Data list. */
37   struct buffer_data *head;
38   struct buffer_data *tail;
39   
40   /* Size of each buffer_data chunk. */
41   size_t size;
42 };
43
44 /* Data container. */
45 struct buffer_data
46 {
47   struct buffer_data *next;
48
49   /* Location to add new data. */
50   size_t cp;
51
52   /* Pointer to data not yet flushed. */
53   size_t sp;
54
55   /* Actual data stream (variable length). */
56   unsigned char data[];  /* real dimension is buffer->size */
57 };
58
59 /* It should always be true that: 0 <= sp <= cp <= size */
60
61 /* Default buffer size (used if none specified).  It is rounded up to the
62    next page boundery. */
63 #define BUFFER_SIZE_DEFAULT             4096
64
65
66 #define BUFFER_DATA_FREE(D) XFREE(MTYPE_BUFFER_DATA, (D))
67
68 /* Make new buffer. */
69 struct buffer *
70 buffer_new (size_t size)
71 {
72   struct buffer *b;
73
74   b = XCALLOC (MTYPE_BUFFER, sizeof (struct buffer));
75
76   if (size)
77     b->size = size;
78   else
79     {
80       static size_t default_size;
81       if (!default_size)
82         {
83           long pgsz = sysconf(_SC_PAGESIZE);
84           default_size = ((((BUFFER_SIZE_DEFAULT-1)/pgsz)+1)*pgsz);
85         }
86       b->size = default_size;
87     }
88
89   return b;
90 }
91
92 /* Free buffer. */
93 void
94 buffer_free (struct buffer *b)
95 {
96   buffer_reset(b);
97   XFREE (MTYPE_BUFFER, b);
98 }
99
100 /* Make string clone. */
101 char *
102 buffer_getstr (struct buffer *b)
103 {
104   size_t totlen = 0;
105   struct buffer_data *data;
106   char *s;
107   char *p;
108
109   for (data = b->head; data; data = data->next)
110     totlen += data->cp - data->sp;
111   if (!(s = XMALLOC(MTYPE_TMP, totlen+1)))
112     return NULL;
113   p = s;
114   for (data = b->head; data; data = data->next)
115     {
116       memcpy(p, data->data + data->sp, data->cp - data->sp);
117       p += data->cp - data->sp;
118     }
119   *p = '\0';
120   return s;
121 }
122
123 /* Return 1 if buffer is empty. */
124 int
125 buffer_empty (struct buffer *b)
126 {
127   return (b->head == NULL);
128 }
129
130 /* Clear and free all allocated data. */
131 void
132 buffer_reset (struct buffer *b)
133 {
134   struct buffer_data *data;
135   struct buffer_data *next;
136   
137   for (data = b->head; data; data = next)
138     {
139       next = data->next;
140       BUFFER_DATA_FREE(data);
141     }
142   b->head = b->tail = NULL;
143 }
144
145 /* Add buffer_data to the end of buffer. */
146 static struct buffer_data *
147 buffer_add (struct buffer *b)
148 {
149   struct buffer_data *d;
150
151   d = XMALLOC(MTYPE_BUFFER_DATA, offsetof(struct buffer_data, data) + b->size);
152   d->cp = d->sp = 0;
153   d->next = NULL;
154
155   if (b->tail)
156     b->tail->next = d;
157   else
158     b->head = d;
159   b->tail = d;
160
161   return d;
162 }
163
164 /* Write data to buffer. */
165 void
166 buffer_put(struct buffer *b, const void *p, size_t size)
167 {
168   struct buffer_data *data = b->tail;
169   const char *ptr = p;
170
171   /* We use even last one byte of data buffer. */
172   while (size)    
173     {
174       size_t chunk;
175
176       /* If there is no data buffer add it. */
177       if (data == NULL || data->cp == b->size)
178         data = buffer_add (b);
179
180       chunk = ((size <= (b->size - data->cp)) ? size : (b->size - data->cp));
181       memcpy ((data->data + data->cp), ptr, chunk);
182       size -= chunk;
183       ptr += chunk;
184       data->cp += chunk;
185     }
186 }
187
188 /* Insert character into the buffer. */
189 void
190 buffer_putc (struct buffer *b, u_char c)
191 {
192   buffer_put(b, &c, 1);
193 }
194
195 /* Put string to the buffer. */
196 void
197 buffer_putstr (struct buffer *b, const char *c)
198 {
199   buffer_put(b, c, strlen(c));
200 }
201
202 /* Keep flushing data to the fd until the buffer is empty or an error is
203    encountered or the operation would block. */
204 buffer_status_t
205 buffer_flush_all (struct buffer *b, int fd)
206 {
207   buffer_status_t ret;
208   struct buffer_data *head;
209   size_t head_sp;
210
211   if (!b->head)
212     return BUFFER_EMPTY;
213   head_sp = (head = b->head)->sp;
214   /* Flush all data. */
215   while ((ret = buffer_flush_available(b, fd)) == BUFFER_PENDING)
216     {
217       if ((b->head == head) && (head_sp == head->sp) && (errno != EINTR))
218         /* No data was flushed, so kernel buffer must be full. */
219         return ret;
220       head_sp = (head = b->head)->sp;
221     }
222
223   return ret;
224 }
225
226 /* Flush enough data to fill a terminal window of the given scene (used only
227    by vty telnet interface). */
228 buffer_status_t
229 buffer_flush_window (struct buffer *b, int fd, int width, int height, 
230                      int erase_flag, int no_more_flag)
231 {
232   int nbytes;
233   int iov_alloc;
234   int iov_index;
235   struct iovec *iov;
236   struct iovec small_iov[3];
237   char more[] = " --More-- ";
238   char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
239                    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
240                    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
241   struct buffer_data *data;
242   int column;
243
244   if (!b->head)
245     return BUFFER_EMPTY;
246
247   if (height < 1)
248     {
249       zlog_warn("%s called with non-positive window height %d, forcing to 1",
250                 __func__, height);
251       height = 1;
252     }
253   else if (height >= 2)
254     height--;
255   if (width < 1)
256     {
257       zlog_warn("%s called with non-positive window width %d, forcing to 1",
258                 __func__, width);
259       width = 1;
260     }
261
262   /* For erase and more data add two to b's buffer_data count.*/
263   if (b->head->next == NULL)
264     {
265       iov_alloc = array_size(small_iov);
266       iov = small_iov;
267     }
268   else
269     {
270       iov_alloc = ((height*(width+2))/b->size)+10;
271       iov = XMALLOC(MTYPE_TMP, iov_alloc*sizeof(*iov));
272     }
273   iov_index = 0;
274
275   /* Previously print out is performed. */
276   if (erase_flag)
277     {
278       iov[iov_index].iov_base = erase;
279       iov[iov_index].iov_len = sizeof erase;
280       iov_index++;
281     }
282
283   /* Output data. */
284   column = 1;  /* Column position of next character displayed. */
285   for (data = b->head; data && (height > 0); data = data->next)
286     {
287       size_t cp;
288
289       cp = data->sp;
290       while ((cp < data->cp) && (height > 0))
291         {
292           /* Calculate lines remaining and column position after displaying
293              this character. */
294           if (data->data[cp] == '\r')
295             column = 1;
296           else if ((data->data[cp] == '\n') || (column == width))
297             {
298               column = 1;
299               height--;
300             }
301           else
302             column++;
303           cp++;
304         }
305       iov[iov_index].iov_base = (char *)(data->data + data->sp);
306       iov[iov_index++].iov_len = cp-data->sp;
307       data->sp = cp;
308
309       if (iov_index == iov_alloc)
310         /* This should not ordinarily happen. */
311         {
312           iov_alloc *= 2;
313           if (iov != small_iov)
314             {
315               zlog_warn("%s: growing iov array to %d; "
316                         "width %d, height %d, size %lu",
317                         __func__, iov_alloc, width, height, (u_long)b->size);
318               iov = XREALLOC(MTYPE_TMP, iov, iov_alloc*sizeof(*iov));
319             }
320           else
321             {
322               /* This should absolutely never occur. */
323               zlog_err("%s: corruption detected: iov_small overflowed; "
324                        "head %p, tail %p, head->next %p",
325                        __func__, (void *)b->head, (void *)b->tail,
326                        (void *)b->head->next);
327               iov = XMALLOC(MTYPE_TMP, iov_alloc*sizeof(*iov));
328               memcpy(iov, small_iov, sizeof(small_iov));
329             }
330         }
331     }
332
333   /* In case of `more' display need. */
334   if (b->tail && (b->tail->sp < b->tail->cp) && !no_more_flag)
335     {
336       iov[iov_index].iov_base = more;
337       iov[iov_index].iov_len = sizeof more;
338       iov_index++;
339     }
340
341
342 #ifdef IOV_MAX
343   /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
344      example: Solaris2.6 are defined IOV_MAX size at 16.     */
345   {
346     struct iovec *c_iov = iov;
347     nbytes = 0; /* Make sure it's initialized. */
348
349     while (iov_index > 0)
350       {
351          int iov_size;
352
353          iov_size = ((iov_index > IOV_MAX) ? IOV_MAX : iov_index);
354          if ((nbytes = writev(fd, c_iov, iov_size)) < 0)
355            {
356              zlog_warn("%s: writev to fd %d failed: %s",
357                        __func__, fd, safe_strerror(errno));
358              break;
359            }
360
361          /* move pointer io-vector */
362          c_iov += iov_size;
363          iov_index -= iov_size;
364       }
365   }
366 #else  /* IOV_MAX */
367    if ((nbytes = writev (fd, iov, iov_index)) < 0)
368      zlog_warn("%s: writev to fd %d failed: %s",
369                __func__, fd, safe_strerror(errno));
370 #endif /* IOV_MAX */
371
372   /* Free printed buffer data. */
373   while (b->head && (b->head->sp == b->head->cp))
374     {
375       struct buffer_data *del;
376       if (!(b->head = (del = b->head)->next))
377         b->tail = NULL;
378       BUFFER_DATA_FREE(del);
379     }
380
381   if (iov != small_iov)
382     XFREE (MTYPE_TMP, iov);
383
384   return (nbytes < 0) ? BUFFER_ERROR :
385                         (b->head ? BUFFER_PENDING : BUFFER_EMPTY);
386 }
387
388 /* This function (unlike other buffer_flush* functions above) is designed
389 to work with non-blocking sockets.  It does not attempt to write out
390 all of the queued data, just a "big" chunk.  It returns 0 if it was
391 able to empty out the buffers completely, 1 if more flushing is
392 required later, or -1 on a fatal write error. */
393 buffer_status_t
394 buffer_flush_available(struct buffer *b, int fd)
395 {
396
397 /* These are just reasonable values to make sure a significant amount of
398 data is written.  There's no need to go crazy and try to write it all
399 in one shot. */
400 #ifdef IOV_MAX
401 #define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX)
402 #else
403 #define MAX_CHUNKS 16
404 #endif
405 #define MAX_FLUSH 131072
406
407   struct buffer_data *d;
408   size_t written;
409   struct iovec iov[MAX_CHUNKS];
410   size_t iovcnt = 0;
411   size_t nbyte = 0;
412
413   for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH);
414        d = d->next, iovcnt++)
415     {
416       iov[iovcnt].iov_base = d->data+d->sp;
417       nbyte += (iov[iovcnt].iov_len = d->cp-d->sp);
418     }
419
420   if (!nbyte)
421     /* No data to flush: should we issue a warning message? */
422     return BUFFER_EMPTY;
423
424   /* only place where written should be sign compared */
425   if ((ssize_t)(written = writev(fd,iov,iovcnt)) < 0)
426     {
427       if (ERRNO_IO_RETRY(errno))
428         /* Calling code should try again later. */
429         return BUFFER_PENDING;
430       zlog_warn("%s: write error on fd %d: %s",
431                 __func__, fd, safe_strerror(errno));
432       return BUFFER_ERROR;
433     }
434
435   /* Free printed buffer data. */
436   while (written > 0)
437     {
438       struct buffer_data *d;
439       if (!(d = b->head))
440         {
441           zlog_err("%s: corruption detected: buffer queue empty, "
442                    "but written is %lu", __func__, (u_long)written);
443           break;
444         }
445       if (written < d->cp-d->sp)
446         {
447           d->sp += written;
448           return BUFFER_PENDING;
449         }
450
451       written -= (d->cp-d->sp);
452       if (!(b->head = d->next))
453         b->tail = NULL;
454       BUFFER_DATA_FREE(d);
455     }
456
457   return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
458
459 #undef MAX_CHUNKS
460 #undef MAX_FLUSH
461 }
462
463 buffer_status_t
464 buffer_write(struct buffer *b, int fd, const void *p, size_t size)
465 {
466   ssize_t nbytes;
467
468 #if 0
469   /* Should we attempt to drain any previously buffered data?  This could help
470      reduce latency in pushing out the data if we are stuck in a long-running
471      thread that is preventing the main select loop from calling the flush
472      thread... */
473   if (b->head && (buffer_flush_available(b, fd) == BUFFER_ERROR))
474     return BUFFER_ERROR;
475 #endif
476   if (b->head)
477     /* Buffer is not empty, so do not attempt to write the new data. */
478     nbytes = 0;
479   else if ((nbytes = write(fd, p, size)) < 0)
480     {
481       if (ERRNO_IO_RETRY(errno))
482         nbytes = 0;
483       else
484         {
485           zlog_warn("%s: write error on fd %d: %s",
486                     __func__, fd, safe_strerror(errno));
487           return BUFFER_ERROR;
488         }
489     }
490   /* Add any remaining data to the buffer. */
491   {
492     size_t written = nbytes;
493     if (written < size)
494       buffer_put(b, ((const char *)p)+written, size-written);
495   }
496   return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
497 }