]>
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 along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 DEFINE_MTYPE_STATIC(LIB
, BUFFER
, "Buffer")
31 DEFINE_MTYPE_STATIC(LIB
, BUFFER_DATA
, "Buffer data")
36 struct buffer_data
*head
;
37 struct buffer_data
*tail
;
39 /* Size of each buffer_data chunk. */
45 struct buffer_data
*next
;
47 /* Location to add new data. */
50 /* Pointer to data not yet flushed. */
53 /* Actual data stream (variable length). */
54 unsigned char data
[]; /* real dimension is buffer->size */
57 /* It should always be true that: 0 <= sp <= cp <= size */
59 /* Default buffer size (used if none specified). It is rounded up to the
60 next page boundery. */
61 #define BUFFER_SIZE_DEFAULT 4096
63 #define BUFFER_DATA_FREE(D) XFREE(MTYPE_BUFFER_DATA, (D))
65 /* Make new buffer. */
66 struct buffer
*buffer_new(size_t size
)
70 b
= XCALLOC(MTYPE_BUFFER
, sizeof(struct buffer
));
75 static size_t default_size
;
77 long pgsz
= sysconf(_SC_PAGESIZE
);
78 default_size
= ((((BUFFER_SIZE_DEFAULT
- 1) / pgsz
) + 1)
81 b
->size
= default_size
;
88 void buffer_free(struct buffer
*b
)
91 XFREE(MTYPE_BUFFER
, b
);
94 /* Make string clone. */
95 char *buffer_getstr(struct buffer
*b
)
98 struct buffer_data
*data
;
102 for (data
= b
->head
; data
; data
= data
->next
)
103 totlen
+= data
->cp
- data
->sp
;
104 if (!(s
= XMALLOC(MTYPE_TMP
, totlen
+ 1)))
107 for (data
= b
->head
; data
; data
= data
->next
) {
108 memcpy(p
, data
->data
+ data
->sp
, data
->cp
- data
->sp
);
109 p
+= data
->cp
- data
->sp
;
115 /* Return 1 if buffer is empty. */
116 int buffer_empty(struct buffer
*b
)
118 return (b
->head
== NULL
);
121 /* Clear and free all allocated data. */
122 void buffer_reset(struct buffer
*b
)
124 struct buffer_data
*data
;
125 struct buffer_data
*next
;
127 for (data
= b
->head
; data
; data
= next
) {
129 BUFFER_DATA_FREE(data
);
131 b
->head
= b
->tail
= NULL
;
134 /* Add buffer_data to the end of buffer. */
135 static struct buffer_data
*buffer_add(struct buffer
*b
)
137 struct buffer_data
*d
;
139 d
= XMALLOC(MTYPE_BUFFER_DATA
,
140 offsetof(struct buffer_data
, data
) + b
->size
);
153 /* Write data to buffer. */
154 void buffer_put(struct buffer
*b
, const void *p
, size_t size
)
156 struct buffer_data
*data
= b
->tail
;
159 /* We use even last one byte of data buffer. */
163 /* If there is no data buffer add it. */
164 if (data
== NULL
|| data
->cp
== b
->size
)
165 data
= buffer_add(b
);
167 chunk
= ((size
<= (b
->size
- data
->cp
)) ? size
168 : (b
->size
- data
->cp
));
169 memcpy((data
->data
+ data
->cp
), ptr
, chunk
);
176 /* Insert character into the buffer. */
177 void buffer_putc(struct buffer
*b
, u_char c
)
179 buffer_put(b
, &c
, 1);
182 /* Put string to the buffer. */
183 void buffer_putstr(struct buffer
*b
, const char *c
)
185 buffer_put(b
, c
, strlen(c
));
188 /* Expand \n to \r\n */
189 void buffer_put_crlf(struct buffer
*b
, const void *origp
, size_t origsize
)
191 struct buffer_data
*data
= b
->tail
;
192 const char *p
= origp
, *end
= p
+ origsize
, *lf
;
195 lf
= memchr(p
, '\n', end
- p
);
197 /* We use even last one byte of data buffer. */
201 /* If there is no data buffer add it. */
202 if (data
== NULL
|| data
->cp
== b
->size
)
203 data
= buffer_add(b
);
205 size
= (lf
? lf
: end
) - p
;
206 avail
= b
->size
- data
->cp
;
208 chunk
= (size
<= avail
) ? size
: avail
;
209 memcpy(data
->data
+ data
->cp
, p
, chunk
);
214 if (lf
&& size
<= avail
) {
215 /* we just copied up to (including) a '\n' */
216 if (data
->cp
== b
->size
)
217 data
= buffer_add(b
);
218 data
->data
[data
->cp
++] = '\r';
219 if (data
->cp
== b
->size
)
220 data
= buffer_add(b
);
221 data
->data
[data
->cp
++] = '\n';
224 lf
= memchr(p
, '\n', end
- p
);
229 /* Keep flushing data to the fd until the buffer is empty or an error is
230 encountered or the operation would block. */
231 buffer_status_t
buffer_flush_all(struct buffer
*b
, int fd
)
234 struct buffer_data
*head
;
239 head_sp
= (head
= b
->head
)->sp
;
240 /* Flush all data. */
241 while ((ret
= buffer_flush_available(b
, fd
)) == BUFFER_PENDING
) {
242 if ((b
->head
== head
) && (head_sp
== head
->sp
)
244 /* No data was flushed, so kernel buffer must be full.
247 head_sp
= (head
= b
->head
)->sp
;
253 /* Flush enough data to fill a terminal window of the given scene (used only
254 by vty telnet interface). */
255 buffer_status_t
buffer_flush_window(struct buffer
*b
, int fd
, int width
,
256 int height
, int erase_flag
,
263 struct iovec small_iov
[3];
264 char more
[] = " --More-- ";
265 char erase
[] = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
266 0x08, 0x08, ' ', ' ', ' ', ' ', ' ', ' ',
267 ' ', ' ', ' ', ' ', 0x08, 0x08, 0x08, 0x08,
268 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
269 struct buffer_data
*data
;
277 "%s called with non-positive window height %d, forcing to 1",
280 } else if (height
>= 2)
284 "%s called with non-positive window width %d, forcing to 1",
289 /* For erase and more data add two to b's buffer_data count.*/
290 if (b
->head
->next
== NULL
) {
291 iov_alloc
= array_size(small_iov
);
294 iov_alloc
= ((height
* (width
+ 2)) / b
->size
) + 10;
295 iov
= XMALLOC(MTYPE_TMP
, iov_alloc
* sizeof(*iov
));
299 /* Previously print out is performed. */
301 iov
[iov_index
].iov_base
= erase
;
302 iov
[iov_index
].iov_len
= sizeof erase
;
307 column
= 1; /* Column position of next character displayed. */
308 for (data
= b
->head
; data
&& (height
> 0); data
= data
->next
) {
312 while ((cp
< data
->cp
) && (height
> 0)) {
313 /* Calculate lines remaining and column position after
316 if (data
->data
[cp
] == '\r')
318 else if ((data
->data
[cp
] == '\n')
319 || (column
== width
)) {
326 iov
[iov_index
].iov_base
= (char *)(data
->data
+ data
->sp
);
327 iov
[iov_index
++].iov_len
= cp
- data
->sp
;
330 if (iov_index
== iov_alloc
)
331 /* This should not ordinarily happen. */
334 if (iov
!= small_iov
) {
336 "%s: growing iov array to %d; "
337 "width %d, height %d, size %lu",
338 __func__
, iov_alloc
, width
, height
,
340 iov
= XREALLOC(MTYPE_TMP
, iov
,
341 iov_alloc
* sizeof(*iov
));
343 /* This should absolutely never occur. */
345 "%s: corruption detected: iov_small overflowed; "
346 "head %p, tail %p, head->next %p",
347 __func__
, (void *)b
->head
,
348 (void *)b
->tail
, (void *)b
->head
->next
);
349 iov
= XMALLOC(MTYPE_TMP
,
350 iov_alloc
* sizeof(*iov
));
351 memcpy(iov
, small_iov
, sizeof(small_iov
));
356 /* In case of `more' display need. */
357 if (b
->tail
&& (b
->tail
->sp
< b
->tail
->cp
) && !no_more_flag
) {
358 iov
[iov_index
].iov_base
= more
;
359 iov
[iov_index
].iov_len
= sizeof more
;
365 /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
366 example: Solaris2.6 are defined IOV_MAX size at 16. */
368 struct iovec
*c_iov
= iov
;
369 nbytes
= 0; /* Make sure it's initialized. */
371 while (iov_index
> 0) {
375 ((iov_index
> IOV_MAX
) ? IOV_MAX
: iov_index
);
376 if ((nbytes
= writev(fd
, c_iov
, iov_size
)) < 0) {
377 zlog_warn("%s: writev to fd %d failed: %s",
378 __func__
, fd
, safe_strerror(errno
));
382 /* move pointer io-vector */
384 iov_index
-= iov_size
;
388 if ((nbytes
= writev(fd
, iov
, iov_index
)) < 0)
389 zlog_warn("%s: writev to fd %d failed: %s", __func__
, fd
,
390 safe_strerror(errno
));
393 /* Free printed buffer data. */
394 while (b
->head
&& (b
->head
->sp
== b
->head
->cp
)) {
395 struct buffer_data
*del
;
396 if (!(b
->head
= (del
= b
->head
)->next
))
398 BUFFER_DATA_FREE(del
);
401 if (iov
!= small_iov
)
402 XFREE(MTYPE_TMP
, iov
);
404 return (nbytes
< 0) ? BUFFER_ERROR
405 : (b
->head
? BUFFER_PENDING
: BUFFER_EMPTY
);
408 /* This function (unlike other buffer_flush* functions above) is designed
409 to work with non-blocking sockets. It does not attempt to write out
410 all of the queued data, just a "big" chunk. It returns 0 if it was
411 able to empty out the buffers completely, 1 if more flushing is
412 required later, or -1 on a fatal write error. */
413 buffer_status_t
buffer_flush_available(struct buffer
*b
, int fd
)
416 /* These are just reasonable values to make sure a significant amount of
417 data is written. There's no need to go crazy and try to write it all
420 #define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX)
422 #define MAX_CHUNKS 16
424 #define MAX_FLUSH 131072
426 struct buffer_data
*d
;
428 struct iovec iov
[MAX_CHUNKS
];
432 for (d
= b
->head
; d
&& (iovcnt
< MAX_CHUNKS
) && (nbyte
< MAX_FLUSH
);
433 d
= d
->next
, iovcnt
++) {
434 iov
[iovcnt
].iov_base
= d
->data
+ d
->sp
;
435 nbyte
+= (iov
[iovcnt
].iov_len
= d
->cp
- d
->sp
);
439 /* No data to flush: should we issue a warning message? */
442 /* only place where written should be sign compared */
443 if ((ssize_t
)(written
= writev(fd
, iov
, iovcnt
)) < 0) {
444 if (ERRNO_IO_RETRY(errno
))
445 /* Calling code should try again later. */
446 return BUFFER_PENDING
;
447 zlog_warn("%s: write error on fd %d: %s", __func__
, fd
,
448 safe_strerror(errno
));
452 /* Free printed buffer data. */
453 while (written
> 0) {
454 struct buffer_data
*d
;
455 if (!(d
= b
->head
)) {
457 "%s: corruption detected: buffer queue empty, "
458 "but written is %lu",
459 __func__
, (u_long
)written
);
462 if (written
< d
->cp
- d
->sp
) {
464 return BUFFER_PENDING
;
467 written
-= (d
->cp
- d
->sp
);
468 if (!(b
->head
= d
->next
))
473 return b
->head
? BUFFER_PENDING
: BUFFER_EMPTY
;
479 buffer_status_t
buffer_write(struct buffer
*b
, int fd
, const void *p
,
485 /* Should we attempt to drain any previously buffered data? This could help
486 reduce latency in pushing out the data if we are stuck in a long-running
487 thread that is preventing the main select loop from calling the flush
489 if (b
->head
&& (buffer_flush_available(b
, fd
) == BUFFER_ERROR
))
493 /* Buffer is not empty, so do not attempt to write the new data.
496 else if ((nbytes
= write(fd
, p
, size
)) < 0) {
497 if (ERRNO_IO_RETRY(errno
))
500 zlog_warn("%s: write error on fd %d: %s", __func__
, fd
,
501 safe_strerror(errno
));
505 /* Add any remaining data to the buffer. */
507 size_t written
= nbytes
;
509 buffer_put(b
, ((const char *)p
) + written
,
512 return b
->head
? BUFFER_PENDING
: BUFFER_EMPTY
;