]>
git.proxmox.com Git - mirror_frr.git/blob - lib/buffer.c
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.
31 DEFINE_MTYPE_STATIC(LIB
, BUFFER
, "Buffer")
32 DEFINE_MTYPE_STATIC(LIB
, BUFFER_DATA
, "Buffer data")
37 struct buffer_data
*head
;
38 struct buffer_data
*tail
;
40 /* Size of each buffer_data chunk. */
46 struct buffer_data
*next
;
48 /* Location to add new data. */
51 /* Pointer to data not yet flushed. */
54 /* Actual data stream (variable length). */
55 unsigned char data
[]; /* real dimension is buffer->size */
58 /* It should always be true that: 0 <= sp <= cp <= size */
60 /* Default buffer size (used if none specified). It is rounded up to the
61 next page boundery. */
62 #define BUFFER_SIZE_DEFAULT 4096
64 #define BUFFER_DATA_FREE(D) XFREE(MTYPE_BUFFER_DATA, (D))
66 /* Make new buffer. */
67 struct buffer
*buffer_new(size_t size
)
71 b
= XCALLOC(MTYPE_BUFFER
, sizeof(struct buffer
));
76 static size_t default_size
;
78 long pgsz
= sysconf(_SC_PAGESIZE
);
79 default_size
= ((((BUFFER_SIZE_DEFAULT
- 1) / pgsz
) + 1)
82 b
->size
= default_size
;
89 void buffer_free(struct buffer
*b
)
92 XFREE(MTYPE_BUFFER
, b
);
95 /* Make string clone. */
96 char *buffer_getstr(struct buffer
*b
)
99 struct buffer_data
*data
;
103 for (data
= b
->head
; data
; data
= data
->next
)
104 totlen
+= data
->cp
- data
->sp
;
105 if (!(s
= XMALLOC(MTYPE_TMP
, totlen
+ 1)))
108 for (data
= b
->head
; data
; data
= data
->next
) {
109 memcpy(p
, data
->data
+ data
->sp
, data
->cp
- data
->sp
);
110 p
+= data
->cp
- data
->sp
;
116 /* Return 1 if buffer is empty. */
117 int buffer_empty(struct buffer
*b
)
119 return (b
->head
== NULL
);
122 /* Clear and free all allocated data. */
123 void buffer_reset(struct buffer
*b
)
125 struct buffer_data
*data
;
126 struct buffer_data
*next
;
128 for (data
= b
->head
; data
; data
= next
) {
130 BUFFER_DATA_FREE(data
);
132 b
->head
= b
->tail
= NULL
;
135 /* Add buffer_data to the end of buffer. */
136 static struct buffer_data
*buffer_add(struct buffer
*b
)
138 struct buffer_data
*d
;
140 d
= XMALLOC(MTYPE_BUFFER_DATA
,
141 offsetof(struct buffer_data
, data
) + b
->size
);
154 /* Write data to buffer. */
155 void buffer_put(struct buffer
*b
, const void *p
, size_t size
)
157 struct buffer_data
*data
= b
->tail
;
160 /* We use even last one byte of data buffer. */
164 /* If there is no data buffer add it. */
165 if (data
== NULL
|| data
->cp
== b
->size
)
166 data
= buffer_add(b
);
168 chunk
= ((size
<= (b
->size
- data
->cp
)) ? size
169 : (b
->size
- data
->cp
));
170 memcpy((data
->data
+ data
->cp
), ptr
, chunk
);
177 /* Insert character into the buffer. */
178 void buffer_putc(struct buffer
*b
, u_char c
)
180 buffer_put(b
, &c
, 1);
183 /* Put string to the buffer. */
184 void buffer_putstr(struct buffer
*b
, const char *c
)
186 buffer_put(b
, c
, strlen(c
));
189 /* Keep flushing data to the fd until the buffer is empty or an error is
190 encountered or the operation would block. */
191 buffer_status_t
buffer_flush_all(struct buffer
*b
, int fd
)
194 struct buffer_data
*head
;
199 head_sp
= (head
= b
->head
)->sp
;
200 /* Flush all data. */
201 while ((ret
= buffer_flush_available(b
, fd
)) == BUFFER_PENDING
) {
202 if ((b
->head
== head
) && (head_sp
== head
->sp
)
204 /* No data was flushed, so kernel buffer must be full.
207 head_sp
= (head
= b
->head
)->sp
;
213 /* Flush enough data to fill a terminal window of the given scene (used only
214 by vty telnet interface). */
215 buffer_status_t
buffer_flush_window(struct buffer
*b
, int fd
, int width
,
216 int height
, int erase_flag
,
223 struct iovec small_iov
[3];
224 char more
[] = " --More-- ";
225 char erase
[] = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
226 0x08, 0x08, ' ', ' ', ' ', ' ', ' ', ' ',
227 ' ', ' ', ' ', ' ', 0x08, 0x08, 0x08, 0x08,
228 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
229 struct buffer_data
*data
;
237 "%s called with non-positive window height %d, forcing to 1",
240 } else if (height
>= 2)
244 "%s called with non-positive window width %d, forcing to 1",
249 /* For erase and more data add two to b's buffer_data count.*/
250 if (b
->head
->next
== NULL
) {
251 iov_alloc
= array_size(small_iov
);
254 iov_alloc
= ((height
* (width
+ 2)) / b
->size
) + 10;
255 iov
= XMALLOC(MTYPE_TMP
, iov_alloc
* sizeof(*iov
));
259 /* Previously print out is performed. */
261 iov
[iov_index
].iov_base
= erase
;
262 iov
[iov_index
].iov_len
= sizeof erase
;
267 column
= 1; /* Column position of next character displayed. */
268 for (data
= b
->head
; data
&& (height
> 0); data
= data
->next
) {
272 while ((cp
< data
->cp
) && (height
> 0)) {
273 /* Calculate lines remaining and column position after
276 if (data
->data
[cp
] == '\r')
278 else if ((data
->data
[cp
] == '\n')
279 || (column
== width
)) {
286 iov
[iov_index
].iov_base
= (char *)(data
->data
+ data
->sp
);
287 iov
[iov_index
++].iov_len
= cp
- data
->sp
;
290 if (iov_index
== iov_alloc
)
291 /* This should not ordinarily happen. */
294 if (iov
!= small_iov
) {
296 "%s: growing iov array to %d; "
297 "width %d, height %d, size %lu",
298 __func__
, iov_alloc
, width
, height
,
300 iov
= XREALLOC(MTYPE_TMP
, iov
,
301 iov_alloc
* sizeof(*iov
));
303 /* This should absolutely never occur. */
305 "%s: corruption detected: iov_small overflowed; "
306 "head %p, tail %p, head->next %p",
307 __func__
, (void *)b
->head
,
308 (void *)b
->tail
, (void *)b
->head
->next
);
309 iov
= XMALLOC(MTYPE_TMP
,
310 iov_alloc
* sizeof(*iov
));
311 memcpy(iov
, small_iov
, sizeof(small_iov
));
316 /* In case of `more' display need. */
317 if (b
->tail
&& (b
->tail
->sp
< b
->tail
->cp
) && !no_more_flag
) {
318 iov
[iov_index
].iov_base
= more
;
319 iov
[iov_index
].iov_len
= sizeof more
;
325 /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
326 example: Solaris2.6 are defined IOV_MAX size at 16. */
328 struct iovec
*c_iov
= iov
;
329 nbytes
= 0; /* Make sure it's initialized. */
331 while (iov_index
> 0) {
335 ((iov_index
> IOV_MAX
) ? IOV_MAX
: iov_index
);
336 if ((nbytes
= writev(fd
, c_iov
, iov_size
)) < 0) {
337 zlog_warn("%s: writev to fd %d failed: %s",
338 __func__
, fd
, safe_strerror(errno
));
342 /* move pointer io-vector */
344 iov_index
-= iov_size
;
348 if ((nbytes
= writev(fd
, iov
, iov_index
)) < 0)
349 zlog_warn("%s: writev to fd %d failed: %s", __func__
, fd
,
350 safe_strerror(errno
));
353 /* Free printed buffer data. */
354 while (b
->head
&& (b
->head
->sp
== b
->head
->cp
)) {
355 struct buffer_data
*del
;
356 if (!(b
->head
= (del
= b
->head
)->next
))
358 BUFFER_DATA_FREE(del
);
361 if (iov
!= small_iov
)
362 XFREE(MTYPE_TMP
, iov
);
364 return (nbytes
< 0) ? BUFFER_ERROR
365 : (b
->head
? BUFFER_PENDING
: BUFFER_EMPTY
);
368 /* This function (unlike other buffer_flush* functions above) is designed
369 to work with non-blocking sockets. It does not attempt to write out
370 all of the queued data, just a "big" chunk. It returns 0 if it was
371 able to empty out the buffers completely, 1 if more flushing is
372 required later, or -1 on a fatal write error. */
373 buffer_status_t
buffer_flush_available(struct buffer
*b
, int fd
)
376 /* These are just reasonable values to make sure a significant amount of
377 data is written. There's no need to go crazy and try to write it all
380 #define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX)
382 #define MAX_CHUNKS 16
384 #define MAX_FLUSH 131072
386 struct buffer_data
*d
;
388 struct iovec iov
[MAX_CHUNKS
];
392 for (d
= b
->head
; d
&& (iovcnt
< MAX_CHUNKS
) && (nbyte
< MAX_FLUSH
);
393 d
= d
->next
, iovcnt
++) {
394 iov
[iovcnt
].iov_base
= d
->data
+ d
->sp
;
395 nbyte
+= (iov
[iovcnt
].iov_len
= d
->cp
- d
->sp
);
399 /* No data to flush: should we issue a warning message? */
402 /* only place where written should be sign compared */
403 if ((ssize_t
)(written
= writev(fd
, iov
, iovcnt
)) < 0) {
404 if (ERRNO_IO_RETRY(errno
))
405 /* Calling code should try again later. */
406 return BUFFER_PENDING
;
407 zlog_warn("%s: write error on fd %d: %s", __func__
, fd
,
408 safe_strerror(errno
));
412 /* Free printed buffer data. */
413 while (written
> 0) {
414 struct buffer_data
*d
;
415 if (!(d
= b
->head
)) {
417 "%s: corruption detected: buffer queue empty, "
418 "but written is %lu",
419 __func__
, (u_long
)written
);
422 if (written
< d
->cp
- d
->sp
) {
424 return BUFFER_PENDING
;
427 written
-= (d
->cp
- d
->sp
);
428 if (!(b
->head
= d
->next
))
433 return b
->head
? BUFFER_PENDING
: BUFFER_EMPTY
;
439 buffer_status_t
buffer_write(struct buffer
*b
, int fd
, const void *p
,
445 /* Should we attempt to drain any previously buffered data? This could help
446 reduce latency in pushing out the data if we are stuck in a long-running
447 thread that is preventing the main select loop from calling the flush
449 if (b
->head
&& (buffer_flush_available(b
, fd
) == BUFFER_ERROR
))
453 /* Buffer is not empty, so do not attempt to write the new data.
456 else if ((nbytes
= write(fd
, p
, size
)) < 0) {
457 if (ERRNO_IO_RETRY(errno
))
460 zlog_warn("%s: write error on fd %d: %s", __func__
, fd
,
461 safe_strerror(errno
));
465 /* Add any remaining data to the buffer. */
467 size_t written
= nbytes
;
469 buffer_put(b
, ((const char *)p
) + written
,
472 return b
->head
? BUFFER_PENDING
: BUFFER_EMPTY
;