]>
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.
29 /* Make buffer data. */
30 static struct buffer_data
*
31 buffer_data_new (size_t size
)
33 struct buffer_data
*d
;
35 d
= XMALLOC (MTYPE_BUFFER_DATA
, offsetof(struct buffer_data
,data
[size
]));
41 buffer_data_free (struct buffer_data
*d
)
43 XFREE (MTYPE_BUFFER_DATA
, d
);
46 /* Make new buffer. */
48 buffer_new (size_t size
)
52 b
= XMALLOC (MTYPE_BUFFER
, sizeof (struct buffer
));
53 memset (b
, 0, sizeof (struct buffer
));
62 buffer_free (struct buffer
*b
)
64 struct buffer_data
*d
;
65 struct buffer_data
*next
;
83 XFREE (MTYPE_BUFFER
, b
);
86 /* Make string clone. */
88 buffer_getstr (struct buffer
*b
)
90 return strdup ((char *)b
->head
->data
);
93 /* Return 1 if buffer is empty. */
95 buffer_empty (struct buffer
*b
)
97 if (b
->tail
== NULL
|| b
->tail
->cp
== b
->tail
->sp
)
103 /* Clear and free all allocated data. */
105 buffer_reset (struct buffer
*b
)
107 struct buffer_data
*data
;
108 struct buffer_data
*next
;
110 for (data
= b
->head
; data
; data
= next
)
113 buffer_data_free (data
);
115 b
->head
= b
->tail
= NULL
;
120 /* Add buffer_data to the end of buffer. */
122 buffer_add (struct buffer
*b
)
124 struct buffer_data
*d
;
126 d
= buffer_data_new (b
->size
);
147 /* Write data to buffer. */
149 buffer_write (struct buffer
*b
, const void *p
, size_t size
)
151 struct buffer_data
*data
;
156 /* We use even last one byte of data buffer. */
161 /* If there is no data buffer add it. */
162 if (data
== NULL
|| data
->cp
== b
->size
)
168 chunk
= ((size
<= (b
->size
- data
->cp
)) ? size
: (b
->size
- data
->cp
));
169 memcpy ((data
->data
+ data
->cp
), ptr
, chunk
);
177 /* Insert character into the buffer. */
179 buffer_putc (struct buffer
*b
, u_char c
)
181 buffer_write (b
, &c
, 1);
185 /* Insert word (2 octets) into ther buffer. */
187 buffer_putw (struct buffer
*b
, u_short c
)
189 buffer_write (b
, (char *)&c
, 2);
193 /* Put string to the buffer. */
195 buffer_putstr (struct buffer
*b
, const char *c
)
200 buffer_write (b
, (void *) c
, size
);
204 /* Flush specified size to the fd. */
206 buffer_flush (struct buffer
*b
, int fd
, size_t size
)
210 struct buffer_data
*data
;
211 struct buffer_data
*out
;
212 struct buffer_data
*next
;
214 iovec
= malloc (sizeof (struct iovec
) * b
->alloc
);
217 for (data
= b
->head
; data
; data
= data
->next
)
219 iovec
[iov_index
].iov_base
= (char *)(data
->data
+ data
->sp
);
221 if (size
<= (data
->cp
- data
->sp
))
223 iovec
[iov_index
++].iov_len
= size
;
226 if (data
->sp
== data
->cp
)
232 iovec
[iov_index
++].iov_len
= data
->cp
- data
->sp
;
233 b
->length
-= (data
->cp
- data
->sp
);
234 size
-= data
->cp
- data
->sp
;
239 /* Write buffer to the fd. */
240 writev (fd
, iovec
, iov_index
);
242 /* Free printed buffer data. */
243 for (out
= b
->head
; out
&& out
!= data
; out
= next
)
252 buffer_data_free (out
);
259 /* Flush all buffer to the fd. */
261 buffer_flush_all (struct buffer
*b
, int fd
)
264 struct buffer_data
*d
;
268 if (buffer_empty (b
))
271 iovec
= malloc (sizeof (struct iovec
) * b
->alloc
);
274 for (d
= b
->head
; d
; d
= d
->next
)
276 iovec
[iov_index
].iov_base
= (char *)(d
->data
+ d
->sp
);
277 iovec
[iov_index
].iov_len
= d
->cp
- d
->sp
;
280 ret
= writev (fd
, iovec
, iov_index
);
289 /* Flush all buffer to the fd. */
291 buffer_flush_vty_all (struct buffer
*b
, int fd
, int erase_flag
,
297 struct iovec small_iov
[3];
298 char more
[] = " --More-- ";
299 char erase
[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
300 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
301 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
302 struct buffer_data
*data
;
303 struct buffer_data
*out
;
304 struct buffer_data
*next
;
306 /* For erase and more data add two to b's buffer_data count.*/
310 iov
= XCALLOC (MTYPE_TMP
, sizeof (struct iovec
) * (b
->alloc
+ 2));
315 /* Previously print out is performed. */
318 iov
[iov_index
].iov_base
= erase
;
319 iov
[iov_index
].iov_len
= sizeof erase
;
324 for (data
= b
->head
; data
; data
= data
->next
)
326 iov
[iov_index
].iov_base
= (char *)(data
->data
+ data
->sp
);
327 iov
[iov_index
].iov_len
= data
->cp
- data
->sp
;
331 /* In case of `more' display need. */
332 if (! buffer_empty (b
) && !no_more_flag
)
334 iov
[iov_index
].iov_base
= more
;
335 iov
[iov_index
].iov_len
= sizeof more
;
339 /* We use write or writev*/
340 nbytes
= writev (fd
, iov
, iov_index
);
342 /* Error treatment. */
347 if (errno
== EWOULDBLOCK
)
351 /* Free printed buffer data. */
352 for (out
= b
->head
; out
&& out
!= data
; out
= next
)
361 b
->length
-= (out
->cp
-out
->sp
);
362 buffer_data_free (out
);
366 if (iov
!= small_iov
)
367 XFREE (MTYPE_TMP
, iov
);
372 /* Flush buffer to the file descriptor. Mainly used from vty
375 buffer_flush_vty (struct buffer
*b
, int fd
, unsigned int size
,
376 int erase_flag
, int no_more_flag
)
381 struct iovec small_iov
[3];
382 char more
[] = " --More-- ";
383 char erase
[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
384 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
385 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
386 struct buffer_data
*data
;
387 struct buffer_data
*out
;
388 struct buffer_data
*next
;
397 /* For erase and more data add two to b's buffer_data count.*/
401 iov
= XCALLOC (MTYPE_TMP
, sizeof (struct iovec
) * (b
->alloc
+ 2));
406 /* Previously print out is performed. */
409 iov
[iov_index
].iov_base
= erase
;
410 iov
[iov_index
].iov_len
= sizeof erase
;
415 for (data
= b
->head
; data
; data
= data
->next
)
417 iov
[iov_index
].iov_base
= (char *)(data
->data
+ data
->sp
);
419 if (size
<= (data
->cp
- data
->sp
))
421 iov
[iov_index
++].iov_len
= size
;
424 if (data
->sp
== data
->cp
)
430 iov
[iov_index
++].iov_len
= data
->cp
- data
->sp
;
431 size
-= (data
->cp
- data
->sp
);
432 b
->length
-= (data
->cp
- data
->sp
);
437 /* In case of `more' display need. */
438 if (!buffer_empty (b
) && !no_more_flag
)
440 iov
[iov_index
].iov_base
= more
;
441 iov
[iov_index
].iov_len
= sizeof more
;
445 /* We use write or writev*/
448 /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
449 example: Solaris2.6 are defined IOV_MAX size at 16. */
451 total_size
= iov_index
;
454 while( total_size
> 0 )
456 /* initialize write vector size at once */
457 iov_size
= ( total_size
> IOV_MAX
) ? IOV_MAX
: total_size
;
459 c_nbytes
= writev (fd
, c_iov
, iov_size
);
466 if(errno
== EWOULDBLOCK
)
476 /* move pointer io-vector */
478 total_size
-= iov_size
;
481 nbytes
= writev (fd
, iov
, iov_index
);
483 /* Error treatment. */
488 if (errno
== EWOULDBLOCK
)
493 /* Free printed buffer data. */
494 for (out
= b
->head
; out
&& out
!= data
; out
= next
)
503 buffer_data_free (out
);
507 if (iov
!= small_iov
)
508 XFREE (MTYPE_TMP
, iov
);
513 /* Calculate size of outputs then flush buffer to the file
516 buffer_flush_window (struct buffer
*b
, int fd
, int width
, int height
,
517 int erase
, int no_more
)
523 struct buffer_data
*data
;
528 /* We have to calculate how many bytes should be written. */
533 for (data
= b
->head
; data
; data
= data
->next
)
537 while (cp
< data
->cp
)
539 if (data
->data
[cp
] == '\n' || lp
== width
)
542 if (lineno
== height
)
556 /* Write data to the file descriptor. */
559 return buffer_flush_vty (b
, fd
, size
, erase
, no_more
);
562 /* This function (unlike other buffer_flush* functions above) is designed
563 to work with non-blocking sockets. It does not attempt to write out
564 all of the queued data, just a "big" chunk. It returns 0 if it was
565 able to empty out the buffers completely, or 1 if more flushing is
568 buffer_flush_available(struct buffer
*b
, int fd
)
571 /* These are just reasonable values to make sure a significant amount of
572 data is written. There's no need to go crazy and try to write it all
575 #define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX)
577 #define MAX_CHUNKS 16
579 #define MAX_FLUSH 131072
581 struct buffer_data
*d
;
582 struct buffer_data
*next
;
584 struct iovec iov
[MAX_CHUNKS
];
588 for (d
= b
->head
; d
&& (iovcnt
< MAX_CHUNKS
) && (nbyte
< MAX_FLUSH
);
589 d
= d
->next
, iovcnt
++)
591 iov
[iovcnt
].iov_base
= d
->data
+d
->sp
;
592 nbyte
+= (iov
[iovcnt
].iov_len
= d
->cp
-d
->sp
);
595 if ((written
= writev(fd
,iov
,iovcnt
)) < 0)
597 if ((errno
!= EAGAIN
) && (errno
!= EINTR
))
598 zlog_warn("buffer_flush_available write error on fd %d: %s",
603 /* Free printed buffer data. */
604 for (d
= b
->head
; (written
> 0) && d
; d
= next
)
606 if (written
< d
->cp
-d
->sp
)
609 b
->length
-= written
;
613 written
-= (d
->cp
-d
->sp
);
621 b
->length
-= (d
->cp
-d
->sp
);
622 buffer_data_free (d
);
626 return (b
->head
!= NULL
);