]>
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")
38 struct buffer_data
*head
;
39 struct buffer_data
*tail
;
41 /* Size of each buffer_data chunk. */
48 struct buffer_data
*next
;
50 /* Location to add new data. */
53 /* Pointer to data not yet flushed. */
56 /* Actual data stream (variable length). */
57 unsigned char data
[]; /* real dimension is buffer->size */
60 /* It should always be true that: 0 <= sp <= cp <= size */
62 /* Default buffer size (used if none specified). It is rounded up to the
63 next page boundery. */
64 #define BUFFER_SIZE_DEFAULT 4096
67 #define BUFFER_DATA_FREE(D) XFREE(MTYPE_BUFFER_DATA, (D))
69 /* Make new buffer. */
71 buffer_new (size_t size
)
75 b
= XCALLOC (MTYPE_BUFFER
, sizeof (struct buffer
));
81 static size_t default_size
;
84 long pgsz
= sysconf(_SC_PAGESIZE
);
85 default_size
= ((((BUFFER_SIZE_DEFAULT
-1)/pgsz
)+1)*pgsz
);
87 b
->size
= default_size
;
95 buffer_free (struct buffer
*b
)
98 XFREE (MTYPE_BUFFER
, b
);
101 /* Make string clone. */
103 buffer_getstr (struct buffer
*b
)
106 struct buffer_data
*data
;
110 for (data
= b
->head
; data
; data
= data
->next
)
111 totlen
+= data
->cp
- data
->sp
;
112 if (!(s
= XMALLOC(MTYPE_TMP
, totlen
+1)))
115 for (data
= b
->head
; data
; data
= data
->next
)
117 memcpy(p
, data
->data
+ data
->sp
, data
->cp
- data
->sp
);
118 p
+= data
->cp
- data
->sp
;
124 /* Return 1 if buffer is empty. */
126 buffer_empty (struct buffer
*b
)
128 return (b
->head
== NULL
);
131 /* Clear and free all allocated data. */
133 buffer_reset (struct buffer
*b
)
135 struct buffer_data
*data
;
136 struct buffer_data
*next
;
138 for (data
= b
->head
; data
; data
= next
)
141 BUFFER_DATA_FREE(data
);
143 b
->head
= b
->tail
= NULL
;
146 /* Add buffer_data to the end of buffer. */
147 static struct buffer_data
*
148 buffer_add (struct buffer
*b
)
150 struct buffer_data
*d
;
152 d
= XMALLOC(MTYPE_BUFFER_DATA
, offsetof(struct buffer_data
, data
) + b
->size
);
165 /* Write data to buffer. */
167 buffer_put(struct buffer
*b
, const void *p
, size_t size
)
169 struct buffer_data
*data
= b
->tail
;
172 /* We use even last one byte of data buffer. */
177 /* If there is no data buffer add it. */
178 if (data
== NULL
|| data
->cp
== b
->size
)
179 data
= buffer_add (b
);
181 chunk
= ((size
<= (b
->size
- data
->cp
)) ? size
: (b
->size
- data
->cp
));
182 memcpy ((data
->data
+ data
->cp
), ptr
, chunk
);
189 /* Insert character into the buffer. */
191 buffer_putc (struct buffer
*b
, u_char c
)
193 buffer_put(b
, &c
, 1);
196 /* Put string to the buffer. */
198 buffer_putstr (struct buffer
*b
, const char *c
)
200 buffer_put(b
, c
, strlen(c
));
203 /* Keep flushing data to the fd until the buffer is empty or an error is
204 encountered or the operation would block. */
206 buffer_flush_all (struct buffer
*b
, int fd
)
209 struct buffer_data
*head
;
214 head_sp
= (head
= b
->head
)->sp
;
215 /* Flush all data. */
216 while ((ret
= buffer_flush_available(b
, fd
)) == BUFFER_PENDING
)
218 if ((b
->head
== head
) && (head_sp
== head
->sp
) && (errno
!= EINTR
))
219 /* No data was flushed, so kernel buffer must be full. */
221 head_sp
= (head
= b
->head
)->sp
;
227 /* Flush enough data to fill a terminal window of the given scene (used only
228 by vty telnet interface). */
230 buffer_flush_window (struct buffer
*b
, int fd
, int width
, int height
,
231 int erase_flag
, int no_more_flag
)
237 struct iovec small_iov
[3];
238 char more
[] = " --More-- ";
239 char erase
[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
240 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
241 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
242 struct buffer_data
*data
;
250 zlog_warn("%s called with non-positive window height %d, forcing to 1",
254 else if (height
>= 2)
258 zlog_warn("%s called with non-positive window width %d, forcing to 1",
263 /* For erase and more data add two to b's buffer_data count.*/
264 if (b
->head
->next
== NULL
)
266 iov_alloc
= array_size(small_iov
);
271 iov_alloc
= ((height
*(width
+2))/b
->size
)+10;
272 iov
= XMALLOC(MTYPE_TMP
, iov_alloc
*sizeof(*iov
));
276 /* Previously print out is performed. */
279 iov
[iov_index
].iov_base
= erase
;
280 iov
[iov_index
].iov_len
= sizeof erase
;
285 column
= 1; /* Column position of next character displayed. */
286 for (data
= b
->head
; data
&& (height
> 0); data
= data
->next
)
291 while ((cp
< data
->cp
) && (height
> 0))
293 /* Calculate lines remaining and column position after displaying
295 if (data
->data
[cp
] == '\r')
297 else if ((data
->data
[cp
] == '\n') || (column
== width
))
306 iov
[iov_index
].iov_base
= (char *)(data
->data
+ data
->sp
);
307 iov
[iov_index
++].iov_len
= cp
-data
->sp
;
310 if (iov_index
== iov_alloc
)
311 /* This should not ordinarily happen. */
314 if (iov
!= small_iov
)
316 zlog_warn("%s: growing iov array to %d; "
317 "width %d, height %d, size %lu",
318 __func__
, iov_alloc
, width
, height
, (u_long
)b
->size
);
319 iov
= XREALLOC(MTYPE_TMP
, iov
, iov_alloc
*sizeof(*iov
));
323 /* This should absolutely never occur. */
324 zlog_err("%s: corruption detected: iov_small overflowed; "
325 "head %p, tail %p, head->next %p",
326 __func__
, (void *)b
->head
, (void *)b
->tail
,
327 (void *)b
->head
->next
);
328 iov
= XMALLOC(MTYPE_TMP
, iov_alloc
*sizeof(*iov
));
329 memcpy(iov
, small_iov
, sizeof(small_iov
));
334 /* In case of `more' display need. */
335 if (b
->tail
&& (b
->tail
->sp
< b
->tail
->cp
) && !no_more_flag
)
337 iov
[iov_index
].iov_base
= more
;
338 iov
[iov_index
].iov_len
= sizeof more
;
344 /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
345 example: Solaris2.6 are defined IOV_MAX size at 16. */
347 struct iovec
*c_iov
= iov
;
348 nbytes
= 0; /* Make sure it's initialized. */
350 while (iov_index
> 0)
354 iov_size
= ((iov_index
> IOV_MAX
) ? IOV_MAX
: iov_index
);
355 if ((nbytes
= writev(fd
, c_iov
, iov_size
)) < 0)
357 zlog_warn("%s: writev to fd %d failed: %s",
358 __func__
, fd
, safe_strerror(errno
));
362 /* move pointer io-vector */
364 iov_index
-= iov_size
;
368 if ((nbytes
= writev (fd
, iov
, iov_index
)) < 0)
369 zlog_warn("%s: writev to fd %d failed: %s",
370 __func__
, fd
, safe_strerror(errno
));
373 /* Free printed buffer data. */
374 while (b
->head
&& (b
->head
->sp
== b
->head
->cp
))
376 struct buffer_data
*del
;
377 if (!(b
->head
= (del
= b
->head
)->next
))
379 BUFFER_DATA_FREE(del
);
382 if (iov
!= small_iov
)
383 XFREE (MTYPE_TMP
, iov
);
385 return (nbytes
< 0) ? BUFFER_ERROR
:
386 (b
->head
? BUFFER_PENDING
: BUFFER_EMPTY
);
389 /* This function (unlike other buffer_flush* functions above) is designed
390 to work with non-blocking sockets. It does not attempt to write out
391 all of the queued data, just a "big" chunk. It returns 0 if it was
392 able to empty out the buffers completely, 1 if more flushing is
393 required later, or -1 on a fatal write error. */
395 buffer_flush_available(struct buffer
*b
, int fd
)
398 /* These are just reasonable values to make sure a significant amount of
399 data is written. There's no need to go crazy and try to write it all
402 #define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX)
404 #define MAX_CHUNKS 16
406 #define MAX_FLUSH 131072
408 struct buffer_data
*d
;
410 struct iovec iov
[MAX_CHUNKS
];
414 for (d
= b
->head
; d
&& (iovcnt
< MAX_CHUNKS
) && (nbyte
< MAX_FLUSH
);
415 d
= d
->next
, iovcnt
++)
417 iov
[iovcnt
].iov_base
= d
->data
+d
->sp
;
418 nbyte
+= (iov
[iovcnt
].iov_len
= d
->cp
-d
->sp
);
422 /* No data to flush: should we issue a warning message? */
425 /* only place where written should be sign compared */
426 if ((ssize_t
)(written
= writev(fd
,iov
,iovcnt
)) < 0)
428 if (ERRNO_IO_RETRY(errno
))
429 /* Calling code should try again later. */
430 return BUFFER_PENDING
;
431 zlog_warn("%s: write error on fd %d: %s",
432 __func__
, fd
, safe_strerror(errno
));
436 /* Free printed buffer data. */
439 struct buffer_data
*d
;
442 zlog_err("%s: corruption detected: buffer queue empty, "
443 "but written is %lu", __func__
, (u_long
)written
);
446 if (written
< d
->cp
-d
->sp
)
449 return BUFFER_PENDING
;
452 written
-= (d
->cp
-d
->sp
);
453 if (!(b
->head
= d
->next
))
458 return b
->head
? BUFFER_PENDING
: BUFFER_EMPTY
;
465 buffer_write(struct buffer
*b
, int fd
, const void *p
, size_t size
)
470 /* Should we attempt to drain any previously buffered data? This could help
471 reduce latency in pushing out the data if we are stuck in a long-running
472 thread that is preventing the main select loop from calling the flush
474 if (b
->head
&& (buffer_flush_available(b
, fd
) == BUFFER_ERROR
))
478 /* Buffer is not empty, so do not attempt to write the new data. */
480 else if ((nbytes
= write(fd
, p
, size
)) < 0)
482 if (ERRNO_IO_RETRY(errno
))
486 zlog_warn("%s: write error on fd %d: %s",
487 __func__
, fd
, safe_strerror(errno
));
491 /* Add any remaining data to the buffer. */
493 size_t written
= nbytes
;
495 buffer_put(b
, ((const char *)p
)+written
, size
-written
);
497 return b
->head
? BUFFER_PENDING
: BUFFER_EMPTY
;