blob: 81cd0f2aa23e1bc554f7b27ddfb021bdba644be9 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
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"
paul2265d202004-11-08 15:43:21 +000027#include "log.h"
ajs9fc7ebf2005-02-23 15:12:34 +000028#include "network.h"
ajs49ff6d92004-11-04 19:26:16 +000029#include <stddef.h>
paul718e3742002-12-13 20:15:29 +000030
paul718e3742002-12-13 20:15:29 +000031
paul718e3742002-12-13 20:15:29 +000032
ajs9fc7ebf2005-02-23 15:12:34 +000033/* Buffer master. */
34struct buffer
paul718e3742002-12-13 20:15:29 +000035{
ajs9fc7ebf2005-02-23 15:12:34 +000036 /* 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. */
45struct 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[0]; /* 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))
paul718e3742002-12-13 20:15:29 +000067
68/* Make new buffer. */
69struct buffer *
70buffer_new (size_t size)
71{
72 struct buffer *b;
73
ajs9fc7ebf2005-02-23 15:12:34 +000074 b = XCALLOC (MTYPE_BUFFER, sizeof (struct buffer));
paul718e3742002-12-13 20:15:29 +000075
ajs9fc7ebf2005-02-23 15:12:34 +000076 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 }
paul718e3742002-12-13 20:15:29 +000088
89 return b;
90}
91
92/* Free buffer. */
93void
94buffer_free (struct buffer *b)
95{
ajs9fc7ebf2005-02-23 15:12:34 +000096 buffer_reset(b);
paul718e3742002-12-13 20:15:29 +000097 XFREE (MTYPE_BUFFER, b);
98}
99
100/* Make string clone. */
101char *
102buffer_getstr (struct buffer *b)
103{
ajsafb8b602005-01-28 20:41:07 +0000104 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;
ajs3b8b1852005-01-29 18:19:13 +0000111 if (!(s = XMALLOC(MTYPE_TMP, totlen+1)))
ajsafb8b602005-01-28 20:41:07 +0000112 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;
paul718e3742002-12-13 20:15:29 +0000121}
122
123/* Return 1 if buffer is empty. */
124int
125buffer_empty (struct buffer *b)
126{
ajs9fc7ebf2005-02-23 15:12:34 +0000127 return (b->head == NULL);
paul718e3742002-12-13 20:15:29 +0000128}
129
130/* Clear and free all allocated data. */
131void
132buffer_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;
ajs9fc7ebf2005-02-23 15:12:34 +0000140 BUFFER_DATA_FREE(data);
paul718e3742002-12-13 20:15:29 +0000141 }
142 b->head = b->tail = NULL;
paul718e3742002-12-13 20:15:29 +0000143}
144
145/* Add buffer_data to the end of buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +0000146static struct buffer_data *
paul718e3742002-12-13 20:15:29 +0000147buffer_add (struct buffer *b)
148{
149 struct buffer_data *d;
150
ajs9fc7ebf2005-02-23 15:12:34 +0000151 d = XMALLOC(MTYPE_BUFFER_DATA, offsetof(struct buffer_data, data[b->size]));
152 d->cp = d->sp = 0;
153 d->next = NULL;
paul718e3742002-12-13 20:15:29 +0000154
ajs9fc7ebf2005-02-23 15:12:34 +0000155 if (b->tail)
156 b->tail->next = d;
paul718e3742002-12-13 20:15:29 +0000157 else
ajs9fc7ebf2005-02-23 15:12:34 +0000158 b->head = d;
159 b->tail = d;
paul718e3742002-12-13 20:15:29 +0000160
ajs9fc7ebf2005-02-23 15:12:34 +0000161 return d;
paul718e3742002-12-13 20:15:29 +0000162}
163
164/* Write data to buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +0000165void
166buffer_put(struct buffer *b, const void *p, size_t size)
paul718e3742002-12-13 20:15:29 +0000167{
ajs9fc7ebf2005-02-23 15:12:34 +0000168 struct buffer_data *data = b->tail;
paul9035efa2004-10-10 11:56:56 +0000169 const char *ptr = p;
paul718e3742002-12-13 20:15:29 +0000170
171 /* We use even last one byte of data buffer. */
172 while (size)
173 {
ajs49ff6d92004-11-04 19:26:16 +0000174 size_t chunk;
175
paul718e3742002-12-13 20:15:29 +0000176 /* If there is no data buffer add it. */
177 if (data == NULL || data->cp == b->size)
ajs9fc7ebf2005-02-23 15:12:34 +0000178 data = buffer_add (b);
paul718e3742002-12-13 20:15:29 +0000179
ajs49ff6d92004-11-04 19:26:16 +0000180 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;
paul718e3742002-12-13 20:15:29 +0000185 }
paul718e3742002-12-13 20:15:29 +0000186}
187
188/* Insert character into the buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +0000189void
paul718e3742002-12-13 20:15:29 +0000190buffer_putc (struct buffer *b, u_char c)
191{
ajs9fc7ebf2005-02-23 15:12:34 +0000192 buffer_put(b, &c, 1);
paul718e3742002-12-13 20:15:29 +0000193}
194
195/* Put string to the buffer. */
ajs9fc7ebf2005-02-23 15:12:34 +0000196void
paul9035efa2004-10-10 11:56:56 +0000197buffer_putstr (struct buffer *b, const char *c)
paul718e3742002-12-13 20:15:29 +0000198{
ajs9fc7ebf2005-02-23 15:12:34 +0000199 buffer_put(b, c, strlen(c));
paul718e3742002-12-13 20:15:29 +0000200}
201
ajs9fc7ebf2005-02-23 15:12:34 +0000202/* Keep flushing data to the fd until the buffer is empty or an error is
203 encountered or the operation would block. */
204buffer_status_t
paul718e3742002-12-13 20:15:29 +0000205buffer_flush_all (struct buffer *b, int fd)
206{
ajs9fc7ebf2005-02-23 15:12:34 +0000207 buffer_status_t ret;
208 struct buffer_data *head;
209 size_t head_sp;
paul718e3742002-12-13 20:15:29 +0000210
ajs9fc7ebf2005-02-23 15:12:34 +0000211 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)
paul718e3742002-12-13 20:15:29 +0000216 {
ajs9fc7ebf2005-02-23 15:12:34 +0000217 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;
paul718e3742002-12-13 20:15:29 +0000221 }
paul718e3742002-12-13 20:15:29 +0000222
223 return ret;
224}
225
ajs9fc7ebf2005-02-23 15:12:34 +0000226/* Flush enough data to fill a terminal window of the given scene (used only
227 by vty telnet interface). */
228buffer_status_t
229buffer_flush_window (struct buffer *b, int fd, int width, int height,
230 int erase_flag, int no_more_flag)
paul718e3742002-12-13 20:15:29 +0000231{
232 int nbytes;
ajs9fc7ebf2005-02-23 15:12:34 +0000233 int iov_alloc;
paul718e3742002-12-13 20:15:29 +0000234 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;
ajs9fc7ebf2005-02-23 15:12:34 +0000242 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 }
paul718e3742002-12-13 20:15:29 +0000261
262 /* For erase and more data add two to b's buffer_data count.*/
ajs9fc7ebf2005-02-23 15:12:34 +0000263 if (b->head->next == NULL)
264 {
265 iov_alloc = sizeof(small_iov)/sizeof(small_iov[0]);
266 iov = small_iov;
267 }
paul718e3742002-12-13 20:15:29 +0000268 else
ajs9fc7ebf2005-02-23 15:12:34 +0000269 {
270 iov_alloc = ((height*(width+2))/b->size)+10;
271 iov = XMALLOC(MTYPE_TMP, iov_alloc*sizeof(*iov));
272 }
paul718e3742002-12-13 20:15:29 +0000273 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. */
ajs9fc7ebf2005-02-23 15:12:34 +0000284 column = 1; /* Column position of next character displayed. */
285 for (data = b->head; data && (height > 0); data = data->next)
paul718e3742002-12-13 20:15:29 +0000286 {
ajs9fc7ebf2005-02-23 15:12:34 +0000287 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 }
paul718e3742002-12-13 20:15:29 +0000305 iov[iov_index].iov_base = (char *)(data->data + data->sp);
ajs9fc7ebf2005-02-23 15:12:34 +0000306 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__, b->head, b->tail, b->head->next);
326 iov = XMALLOC(MTYPE_TMP, iov_alloc*sizeof(*iov));
327 memcpy(iov, small_iov, sizeof(small_iov));
328 }
329 }
paul718e3742002-12-13 20:15:29 +0000330 }
331
332 /* In case of `more' display need. */
ajs9fc7ebf2005-02-23 15:12:34 +0000333 if (b->tail && (b->tail->sp < b->tail->cp) && !no_more_flag)
paul718e3742002-12-13 20:15:29 +0000334 {
335 iov[iov_index].iov_base = more;
336 iov[iov_index].iov_len = sizeof more;
337 iov_index++;
338 }
339
paul718e3742002-12-13 20:15:29 +0000340
341#ifdef IOV_MAX
342 /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
343 example: Solaris2.6 are defined IOV_MAX size at 16. */
ajs9fc7ebf2005-02-23 15:12:34 +0000344 {
345 struct iovec *c_iov = iov;
346 nbytes = 0; /* Make sure it's initialized. */
paul718e3742002-12-13 20:15:29 +0000347
ajs9fc7ebf2005-02-23 15:12:34 +0000348 while (iov_index > 0)
349 {
350 int iov_size;
paul718e3742002-12-13 20:15:29 +0000351
ajs9fc7ebf2005-02-23 15:12:34 +0000352 iov_size = ((iov_index > IOV_MAX) ? IOV_MAX : iov_index);
353 if ((nbytes = writev(fd, c_iov, iov_size)) < 0)
354 {
355 zlog_warn("%s: writev to fd %d failed: %s",
356 __func__, fd, safe_strerror(errno));
357 break;
358 }
paul718e3742002-12-13 20:15:29 +0000359
ajs9fc7ebf2005-02-23 15:12:34 +0000360 /* move pointer io-vector */
361 c_iov += iov_size;
362 iov_index -= iov_size;
363 }
364 }
paul718e3742002-12-13 20:15:29 +0000365#else /* IOV_MAX */
ajs9fc7ebf2005-02-23 15:12:34 +0000366 if ((nbytes = writev (fd, iov, iov_index)) < 0)
367 zlog_warn("%s: writev to fd %d failed: %s",
368 __func__, fd, safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +0000369#endif /* IOV_MAX */
370
371 /* Free printed buffer data. */
ajs9fc7ebf2005-02-23 15:12:34 +0000372 while (b->head && (b->head->sp == b->head->cp))
paul718e3742002-12-13 20:15:29 +0000373 {
ajs9fc7ebf2005-02-23 15:12:34 +0000374 struct buffer_data *del;
375 if (!(b->head = (del = b->head)->next))
376 b->tail = NULL;
377 BUFFER_DATA_FREE(del);
paul718e3742002-12-13 20:15:29 +0000378 }
379
380 if (iov != small_iov)
381 XFREE (MTYPE_TMP, iov);
382
ajs9fc7ebf2005-02-23 15:12:34 +0000383 return (nbytes < 0) ? BUFFER_ERROR :
384 (b->head ? BUFFER_PENDING : BUFFER_EMPTY);
paul718e3742002-12-13 20:15:29 +0000385}
ajs49ff6d92004-11-04 19:26:16 +0000386
387/* This function (unlike other buffer_flush* functions above) is designed
388to work with non-blocking sockets. It does not attempt to write out
389all of the queued data, just a "big" chunk. It returns 0 if it was
ajs9fc7ebf2005-02-23 15:12:34 +0000390able to empty out the buffers completely, 1 if more flushing is
391required later, or -1 on a fatal write error. */
392buffer_status_t
ajs49ff6d92004-11-04 19:26:16 +0000393buffer_flush_available(struct buffer *b, int fd)
394{
395
396/* These are just reasonable values to make sure a significant amount of
397data is written. There's no need to go crazy and try to write it all
398in one shot. */
399#ifdef IOV_MAX
400#define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX)
401#else
402#define MAX_CHUNKS 16
403#endif
404#define MAX_FLUSH 131072
405
406 struct buffer_data *d;
paul2265d202004-11-08 15:43:21 +0000407 size_t written;
ajs49ff6d92004-11-04 19:26:16 +0000408 struct iovec iov[MAX_CHUNKS];
paul2265d202004-11-08 15:43:21 +0000409 size_t iovcnt = 0;
ajs49ff6d92004-11-04 19:26:16 +0000410 size_t nbyte = 0;
411
412 for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH);
413 d = d->next, iovcnt++)
414 {
415 iov[iovcnt].iov_base = d->data+d->sp;
416 nbyte += (iov[iovcnt].iov_len = d->cp-d->sp);
417 }
418
ajs9fc7ebf2005-02-23 15:12:34 +0000419 if (!nbyte)
420 /* No data to flush: should we issue a warning message? */
421 return BUFFER_EMPTY;
422
paul2265d202004-11-08 15:43:21 +0000423 /* only place where written should be sign compared */
424 if ((ssize_t)(written = writev(fd,iov,iovcnt)) < 0)
ajs49ff6d92004-11-04 19:26:16 +0000425 {
ajs9fc7ebf2005-02-23 15:12:34 +0000426 if (ERRNO_IO_RETRY(errno))
427 /* Calling code should try again later. */
428 return BUFFER_PENDING;
429 zlog_warn("%s: write error on fd %d: %s",
430 __func__, fd, safe_strerror(errno));
431 return BUFFER_ERROR;
ajs49ff6d92004-11-04 19:26:16 +0000432 }
433
434 /* Free printed buffer data. */
ajs9fc7ebf2005-02-23 15:12:34 +0000435 while (written > 0)
ajs49ff6d92004-11-04 19:26:16 +0000436 {
ajs9fc7ebf2005-02-23 15:12:34 +0000437 struct buffer_data *d;
438 if (!(d = b->head))
439 {
440 zlog_err("%s: corruption detected: buffer queue empty, "
441 "but written is %lu", __func__, (u_long)written);
442 break;
443 }
ajs49ff6d92004-11-04 19:26:16 +0000444 if (written < d->cp-d->sp)
445 {
446 d->sp += written;
ajs9fc7ebf2005-02-23 15:12:34 +0000447 return BUFFER_PENDING;
ajs49ff6d92004-11-04 19:26:16 +0000448 }
449
450 written -= (d->cp-d->sp);
ajs9fc7ebf2005-02-23 15:12:34 +0000451 if (!(b->head = d->next))
452 b->tail = NULL;
453 BUFFER_DATA_FREE(d);
ajs49ff6d92004-11-04 19:26:16 +0000454 }
455
ajs9fc7ebf2005-02-23 15:12:34 +0000456 return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
ajs49ff6d92004-11-04 19:26:16 +0000457
458#undef MAX_CHUNKS
459#undef MAX_FLUSH
460}
ajs9fc7ebf2005-02-23 15:12:34 +0000461
462buffer_status_t
463buffer_write(struct buffer *b, int fd, const void *p, size_t size)
464{
465 ssize_t nbytes;
466
ajs07334da2005-04-26 17:14:30 +0000467#if 0
468 /* Should we attempt to drain any previously buffered data? This could help
469 reduce latency in pushing out the data if we are stuck in a long-running
470 thread that is preventing the main select loop from calling the flush
471 thread... */
ajs9fc7ebf2005-02-23 15:12:34 +0000472 if (b->head && (buffer_flush_available(b, fd) == BUFFER_ERROR))
473 return BUFFER_ERROR;
ajs07334da2005-04-26 17:14:30 +0000474#endif
ajs9fc7ebf2005-02-23 15:12:34 +0000475 if (b->head)
ajs07334da2005-04-26 17:14:30 +0000476 /* Buffer is not empty, so do not attempt to write the new data. */
ajs9fc7ebf2005-02-23 15:12:34 +0000477 nbytes = 0;
478 else if ((nbytes = write(fd, p, size)) < 0)
479 {
480 if (ERRNO_IO_RETRY(errno))
481 nbytes = 0;
482 else
483 {
484 zlog_warn("%s: write error on fd %d: %s",
485 __func__, fd, safe_strerror(errno));
486 return BUFFER_ERROR;
487 }
488 }
489 /* Add any remaining data to the buffer. */
490 {
491 size_t written = nbytes;
492 if (written < size)
493 buffer_put(b, ((const char *)p)+written, size-written);
494 }
495 return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
496}