2 * Buffering of output and input.
3 * Copyright (C) 1998 Kunihiro Ishiguro
5 * This file is part of GNU Zebra.
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.
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.
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.
37 struct buffer_data
*head
;
38 struct buffer_data
*tail
;
40 /* Size of each buffer_data chunk. */
47 struct buffer_data
*next
;
49 /* Location to add new data. */
52 /* Pointer to data not yet flushed. */
55 /* Actual data stream (variable length). */
56 unsigned char data
[]; /* real dimension is buffer->size */
59 /* It should always be true that: 0 <= sp <= cp <= size */
61 /* Default buffer size (used if none specified). It is rounded up to the
62 next page boundery. */
63 #define BUFFER_SIZE_DEFAULT 4096
66 #define BUFFER_DATA_FREE(D) XFREE(MTYPE_BUFFER_DATA, (D))
68 /* Make new buffer. */
70 buffer_new (size_t size
)
74 b
= XCALLOC (MTYPE_BUFFER
, sizeof (struct buffer
));
80 static size_t default_size
;
83 long pgsz
= sysconf(_SC_PAGESIZE
);
84 default_size
= ((((BUFFER_SIZE_DEFAULT
-1)/pgsz
)+1)*pgsz
);
86 b
->size
= default_size
;
94 buffer_free (struct buffer
*b
)
97 XFREE (MTYPE_BUFFER
, b
);
100 /* Make string clone. */
102 buffer_getstr (struct buffer
*b
)
105 struct buffer_data
*data
;
109 for (data
= b
->head
; data
; data
= data
->next
)
110 totlen
+= data
->cp
- data
->sp
;
111 if (!(s
= XMALLOC(MTYPE_TMP
, totlen
+1)))
114 for (data
= b
->head
; data
; data
= data
->next
)
116 memcpy(p
, data
->data
+ data
->sp
, data
->cp
- data
->sp
);
117 p
+= data
->cp
- data
->sp
;
123 /* Return 1 if buffer is empty. */
125 buffer_empty (struct buffer
*b
)
127 return (b
->head
== NULL
);
130 /* Clear and free all allocated data. */
132 buffer_reset (struct buffer
*b
)
134 struct buffer_data
*data
;
135 struct buffer_data
*next
;
137 for (data
= b
->head
; data
; data
= next
)
140 BUFFER_DATA_FREE(data
);
142 b
->head
= b
->tail
= NULL
;
145 /* Add buffer_data to the end of buffer. */
146 static struct buffer_data
*
147 buffer_add (struct buffer
*b
)
149 struct buffer_data
*d
;
151 d
= XMALLOC(MTYPE_BUFFER_DATA
, offsetof(struct buffer_data
, data
[b
->size
]));
164 /* Write data to buffer. */
166 buffer_put(struct buffer
*b
, const void *p
, size_t size
)
168 struct buffer_data
*data
= b
->tail
;
171 /* We use even last one byte of data buffer. */
176 /* If there is no data buffer add it. */
177 if (data
== NULL
|| data
->cp
== b
->size
)
178 data
= buffer_add (b
);
180 chunk
= ((size
<= (b
->size
- data
->cp
)) ? size
: (b
->size
- data
->cp
));
181 memcpy ((data
->data
+ data
->cp
), ptr
, chunk
);
188 /* Insert character into the buffer. */
190 buffer_putc (struct buffer
*b
, u_char c
)
192 buffer_put(b
, &c
, 1);
195 /* Put string to the buffer. */
197 buffer_putstr (struct buffer
*b
, const char *c
)
199 buffer_put(b
, c
, strlen(c
));
202 /* Keep flushing data to the fd until the buffer is empty or an error is
203 encountered or the operation would block. */
205 buffer_flush_all (struct buffer
*b
, int fd
)
208 struct buffer_data
*head
;
213 head_sp
= (head
= b
->head
)->sp
;
214 /* Flush all data. */
215 while ((ret
= buffer_flush_available(b
, fd
)) == BUFFER_PENDING
)
217 if ((b
->head
== head
) && (head_sp
== head
->sp
) && (errno
!= EINTR
))
218 /* No data was flushed, so kernel buffer must be full. */
220 head_sp
= (head
= b
->head
)->sp
;
226 /* Flush enough data to fill a terminal window of the given scene (used only
227 by vty telnet interface). */
229 buffer_flush_window (struct buffer
*b
, int fd
, int width
, int height
,
230 int erase_flag
, int no_more_flag
)
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
;
249 zlog_warn("%s called with non-positive window height %d, forcing to 1",
253 else if (height
>= 2)
257 zlog_warn("%s called with non-positive window width %d, forcing to 1",
262 /* For erase and more data add two to b's buffer_data count.*/
263 if (b
->head
->next
== NULL
)
265 iov_alloc
= sizeof(small_iov
)/sizeof(small_iov
[0]);
270 iov_alloc
= ((height
*(width
+2))/b
->size
)+10;
271 iov
= XMALLOC(MTYPE_TMP
, iov_alloc
*sizeof(*iov
));
275 /* Previously print out is performed. */
278 iov
[iov_index
].iov_base
= erase
;
279 iov
[iov_index
].iov_len
= sizeof erase
;
284 column
= 1; /* Column position of next character displayed. */
285 for (data
= b
->head
; data
&& (height
> 0); data
= data
->next
)
290 while ((cp
< data
->cp
) && (height
> 0))
292 /* Calculate lines remaining and column position after displaying
294 if (data
->data
[cp
] == '\r')
296 else if ((data
->data
[cp
] == '\n') || (column
== width
))
305 iov
[iov_index
].iov_base
= (char *)(data
->data
+ data
->sp
);
306 iov
[iov_index
++].iov_len
= cp
-data
->sp
;
309 if (iov_index
== iov_alloc
)
310 /* This should not ordinarily happen. */
313 if (iov
!= small_iov
)
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
));
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
));
332 /* In case of `more' display need. */
333 if (b
->tail
&& (b
->tail
->sp
< b
->tail
->cp
) && !no_more_flag
)
335 iov
[iov_index
].iov_base
= more
;
336 iov
[iov_index
].iov_len
= sizeof more
;
342 /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
343 example: Solaris2.6 are defined IOV_MAX size at 16. */
345 struct iovec
*c_iov
= iov
;
346 nbytes
= 0; /* Make sure it's initialized. */
348 while (iov_index
> 0)
352 iov_size
= ((iov_index
> IOV_MAX
) ? IOV_MAX
: iov_index
);
353 if ((nbytes
= writev(fd
, c_iov
, iov_size
)) < 0)
355 zlog_warn("%s: writev to fd %d failed: %s",
356 __func__
, fd
, safe_strerror(errno
));
360 /* move pointer io-vector */
362 iov_index
-= iov_size
;
366 if ((nbytes
= writev (fd
, iov
, iov_index
)) < 0)
367 zlog_warn("%s: writev to fd %d failed: %s",
368 __func__
, fd
, safe_strerror(errno
));
371 /* Free printed buffer data. */
372 while (b
->head
&& (b
->head
->sp
== b
->head
->cp
))
374 struct buffer_data
*del
;
375 if (!(b
->head
= (del
= b
->head
)->next
))
377 BUFFER_DATA_FREE(del
);
380 if (iov
!= small_iov
)
381 XFREE (MTYPE_TMP
, iov
);
383 return (nbytes
< 0) ? BUFFER_ERROR
:
384 (b
->head
? BUFFER_PENDING
: BUFFER_EMPTY
);
387 /* This function (unlike other buffer_flush* functions above) is designed
388 to work with non-blocking sockets. It does not attempt to write out
389 all of the queued data, just a "big" chunk. It returns 0 if it was
390 able to empty out the buffers completely, 1 if more flushing is
391 required later, or -1 on a fatal write error. */
393 buffer_flush_available(struct buffer
*b
, int fd
)
396 /* These are just reasonable values to make sure a significant amount of
397 data is written. There's no need to go crazy and try to write it all
400 #define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX)
402 #define MAX_CHUNKS 16
404 #define MAX_FLUSH 131072
406 struct buffer_data
*d
;
408 struct iovec iov
[MAX_CHUNKS
];
412 for (d
= b
->head
; d
&& (iovcnt
< MAX_CHUNKS
) && (nbyte
< MAX_FLUSH
);
413 d
= d
->next
, iovcnt
++)
415 iov
[iovcnt
].iov_base
= d
->data
+d
->sp
;
416 nbyte
+= (iov
[iovcnt
].iov_len
= d
->cp
-d
->sp
);
420 /* No data to flush: should we issue a warning message? */
423 /* only place where written should be sign compared */
424 if ((ssize_t
)(written
= writev(fd
,iov
,iovcnt
)) < 0)
426 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
));
434 /* Free printed buffer data. */
437 struct buffer_data
*d
;
440 zlog_err("%s: corruption detected: buffer queue empty, "
441 "but written is %lu", __func__
, (u_long
)written
);
444 if (written
< d
->cp
-d
->sp
)
447 return BUFFER_PENDING
;
450 written
-= (d
->cp
-d
->sp
);
451 if (!(b
->head
= d
->next
))
456 return b
->head
? BUFFER_PENDING
: BUFFER_EMPTY
;
463 buffer_write(struct buffer
*b
, int fd
, const void *p
, size_t size
)
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
472 if (b
->head
&& (buffer_flush_available(b
, fd
) == BUFFER_ERROR
))
476 /* Buffer is not empty, so do not attempt to write the new data. */
478 else if ((nbytes
= write(fd
, p
, size
)) < 0)
480 if (ERRNO_IO_RETRY(errno
))
484 zlog_warn("%s: write error on fd %d: %s",
485 __func__
, fd
, safe_strerror(errno
));
489 /* Add any remaining data to the buffer. */
491 size_t written
= nbytes
;
493 buffer_put(b
, ((const char *)p
)+written
, size
-written
);
495 return b
->head
? BUFFER_PENDING
: BUFFER_EMPTY
;