]> git.proxmox.com Git - mirror_frr.git/blob - lib/buffer.c
2004-11-04 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
[mirror_frr.git] / lib / buffer.c
1 /*
2 * Buffering of output and input.
3 * Copyright (C) 1998 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
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.
11 *
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.
16 *
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.
21 */
22
23 #include <zebra.h>
24
25 #include "memory.h"
26 #include "buffer.h"
27 #include <stddef.h>
28
29 /* Make buffer data. */
30 static struct buffer_data *
31 buffer_data_new (size_t size)
32 {
33 struct buffer_data *d;
34
35 d = XMALLOC (MTYPE_BUFFER_DATA, offsetof(struct buffer_data,data[size]));
36 d->cp = d->sp = 0;
37 return d;
38 }
39
40 static void
41 buffer_data_free (struct buffer_data *d)
42 {
43 XFREE (MTYPE_BUFFER_DATA, d);
44 }
45
46 /* Make new buffer. */
47 struct buffer *
48 buffer_new (size_t size)
49 {
50 struct buffer *b;
51
52 b = XMALLOC (MTYPE_BUFFER, sizeof (struct buffer));
53 memset (b, 0, sizeof (struct buffer));
54
55 b->size = size;
56
57 return b;
58 }
59
60 /* Free buffer. */
61 void
62 buffer_free (struct buffer *b)
63 {
64 struct buffer_data *d;
65 struct buffer_data *next;
66
67 d = b->head;
68 while (d)
69 {
70 next = d->next;
71 buffer_data_free (d);
72 d = next;
73 }
74
75 d = b->unused_head;
76 while (d)
77 {
78 next = d->next;
79 buffer_data_free (d);
80 d = next;
81 }
82
83 XFREE (MTYPE_BUFFER, b);
84 }
85
86 /* Make string clone. */
87 char *
88 buffer_getstr (struct buffer *b)
89 {
90 return strdup ((char *)b->head->data);
91 }
92
93 /* Return 1 if buffer is empty. */
94 int
95 buffer_empty (struct buffer *b)
96 {
97 if (b->tail == NULL || b->tail->cp == b->tail->sp)
98 return 1;
99 else
100 return 0;
101 }
102
103 /* Clear and free all allocated data. */
104 void
105 buffer_reset (struct buffer *b)
106 {
107 struct buffer_data *data;
108 struct buffer_data *next;
109
110 for (data = b->head; data; data = next)
111 {
112 next = data->next;
113 buffer_data_free (data);
114 }
115 b->head = b->tail = NULL;
116 b->alloc = 0;
117 b->length = 0;
118 }
119
120 /* Add buffer_data to the end of buffer. */
121 void
122 buffer_add (struct buffer *b)
123 {
124 struct buffer_data *d;
125
126 d = buffer_data_new (b->size);
127
128 if (b->tail == NULL)
129 {
130 d->prev = NULL;
131 d->next = NULL;
132 b->head = d;
133 b->tail = d;
134 }
135 else
136 {
137 d->prev = b->tail;
138 d->next = NULL;
139
140 b->tail->next = d;
141 b->tail = d;
142 }
143
144 b->alloc++;
145 }
146
147 /* Write data to buffer. */
148 int
149 buffer_write (struct buffer *b, const void *p, size_t size)
150 {
151 struct buffer_data *data;
152 const char *ptr = p;
153 data = b->tail;
154 b->length += size;
155
156 /* We use even last one byte of data buffer. */
157 while (size)
158 {
159 size_t chunk;
160
161 /* If there is no data buffer add it. */
162 if (data == NULL || data->cp == b->size)
163 {
164 buffer_add (b);
165 data = b->tail;
166 }
167
168 chunk = ((size <= (b->size - data->cp)) ? size : (b->size - data->cp));
169 memcpy ((data->data + data->cp), ptr, chunk);
170 size -= chunk;
171 ptr += chunk;
172 data->cp += chunk;
173 }
174 return 1;
175 }
176
177 /* Insert character into the buffer. */
178 int
179 buffer_putc (struct buffer *b, u_char c)
180 {
181 buffer_write (b, &c, 1);
182 return 1;
183 }
184
185 /* Insert word (2 octets) into ther buffer. */
186 int
187 buffer_putw (struct buffer *b, u_short c)
188 {
189 buffer_write (b, (char *)&c, 2);
190 return 1;
191 }
192
193 /* Put string to the buffer. */
194 int
195 buffer_putstr (struct buffer *b, const char *c)
196 {
197 size_t size;
198
199 size = strlen (c);
200 buffer_write (b, (void *) c, size);
201 return 1;
202 }
203
204 /* Flush specified size to the fd. */
205 void
206 buffer_flush (struct buffer *b, int fd, size_t size)
207 {
208 int iov_index;
209 struct iovec *iovec;
210 struct buffer_data *data;
211 struct buffer_data *out;
212 struct buffer_data *next;
213
214 iovec = malloc (sizeof (struct iovec) * b->alloc);
215 iov_index = 0;
216
217 for (data = b->head; data; data = data->next)
218 {
219 iovec[iov_index].iov_base = (char *)(data->data + data->sp);
220
221 if (size <= (data->cp - data->sp))
222 {
223 iovec[iov_index++].iov_len = size;
224 data->sp += size;
225 b->length -= size;
226 if (data->sp == data->cp)
227 data = data->next;
228 break;
229 }
230 else
231 {
232 iovec[iov_index++].iov_len = data->cp - data->sp;
233 b->length -= (data->cp - data->sp);
234 size -= data->cp - data->sp;
235 data->sp = data->cp;
236 }
237 }
238
239 /* Write buffer to the fd. */
240 writev (fd, iovec, iov_index);
241
242 /* Free printed buffer data. */
243 for (out = b->head; out && out != data; out = next)
244 {
245 next = out->next;
246 if (next)
247 next->prev = NULL;
248 else
249 b->tail = next;
250 b->head = next;
251
252 buffer_data_free (out);
253 b->alloc--;
254 }
255
256 free (iovec);
257 }
258
259 /* Flush all buffer to the fd. */
260 int
261 buffer_flush_all (struct buffer *b, int fd)
262 {
263 int ret;
264 struct buffer_data *d;
265 int iov_index;
266 struct iovec *iovec;
267
268 if (buffer_empty (b))
269 return 0;
270
271 iovec = malloc (sizeof (struct iovec) * b->alloc);
272 iov_index = 0;
273
274 for (d = b->head; d; d = d->next)
275 {
276 iovec[iov_index].iov_base = (char *)(d->data + d->sp);
277 iovec[iov_index].iov_len = d->cp - d->sp;
278 iov_index++;
279 }
280 ret = writev (fd, iovec, iov_index);
281
282 free (iovec);
283
284 buffer_reset (b);
285
286 return ret;
287 }
288
289 /* Flush all buffer to the fd. */
290 int
291 buffer_flush_vty_all (struct buffer *b, int fd, int erase_flag,
292 int no_more_flag)
293 {
294 int nbytes;
295 int iov_index;
296 struct iovec *iov;
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;
305
306 /* For erase and more data add two to b's buffer_data count.*/
307 if (b->alloc == 1)
308 iov = small_iov;
309 else
310 iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
311
312 data = b->head;
313 iov_index = 0;
314
315 /* Previously print out is performed. */
316 if (erase_flag)
317 {
318 iov[iov_index].iov_base = erase;
319 iov[iov_index].iov_len = sizeof erase;
320 iov_index++;
321 }
322
323 /* Output data. */
324 for (data = b->head; data; data = data->next)
325 {
326 iov[iov_index].iov_base = (char *)(data->data + data->sp);
327 iov[iov_index].iov_len = data->cp - data->sp;
328 iov_index++;
329 }
330
331 /* In case of `more' display need. */
332 if (! buffer_empty (b) && !no_more_flag)
333 {
334 iov[iov_index].iov_base = more;
335 iov[iov_index].iov_len = sizeof more;
336 iov_index++;
337 }
338
339 /* We use write or writev*/
340 nbytes = writev (fd, iov, iov_index);
341
342 /* Error treatment. */
343 if (nbytes < 0)
344 {
345 if (errno == EINTR)
346 ;
347 if (errno == EWOULDBLOCK)
348 ;
349 }
350
351 /* Free printed buffer data. */
352 for (out = b->head; out && out != data; out = next)
353 {
354 next = out->next;
355 if (next)
356 next->prev = NULL;
357 else
358 b->tail = next;
359 b->head = next;
360
361 b->length -= (out->cp-out->sp);
362 buffer_data_free (out);
363 b->alloc--;
364 }
365
366 if (iov != small_iov)
367 XFREE (MTYPE_TMP, iov);
368
369 return nbytes;
370 }
371
372 /* Flush buffer to the file descriptor. Mainly used from vty
373 interface. */
374 int
375 buffer_flush_vty (struct buffer *b, int fd, unsigned int size,
376 int erase_flag, int no_more_flag)
377 {
378 int nbytes;
379 int iov_index;
380 struct iovec *iov;
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;
389
390 #ifdef IOV_MAX
391 int iov_size;
392 int total_size;
393 struct iovec *c_iov;
394 int c_nbytes;
395 #endif /* IOV_MAX */
396
397 /* For erase and more data add two to b's buffer_data count.*/
398 if (b->alloc == 1)
399 iov = small_iov;
400 else
401 iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
402
403 data = b->head;
404 iov_index = 0;
405
406 /* Previously print out is performed. */
407 if (erase_flag)
408 {
409 iov[iov_index].iov_base = erase;
410 iov[iov_index].iov_len = sizeof erase;
411 iov_index++;
412 }
413
414 /* Output data. */
415 for (data = b->head; data; data = data->next)
416 {
417 iov[iov_index].iov_base = (char *)(data->data + data->sp);
418
419 if (size <= (data->cp - data->sp))
420 {
421 iov[iov_index++].iov_len = size;
422 data->sp += size;
423 b->length -= size;
424 if (data->sp == data->cp)
425 data = data->next;
426 break;
427 }
428 else
429 {
430 iov[iov_index++].iov_len = data->cp - data->sp;
431 size -= (data->cp - data->sp);
432 b->length -= (data->cp - data->sp);
433 data->sp = data->cp;
434 }
435 }
436
437 /* In case of `more' display need. */
438 if (!buffer_empty (b) && !no_more_flag)
439 {
440 iov[iov_index].iov_base = more;
441 iov[iov_index].iov_len = sizeof more;
442 iov_index++;
443 }
444
445 /* We use write or writev*/
446
447 #ifdef IOV_MAX
448 /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
449 example: Solaris2.6 are defined IOV_MAX size at 16. */
450 c_iov = iov;
451 total_size = iov_index;
452 nbytes = 0;
453
454 while( total_size > 0 )
455 {
456 /* initialize write vector size at once */
457 iov_size = ( total_size > IOV_MAX ) ? IOV_MAX : total_size;
458
459 c_nbytes = writev (fd, c_iov, iov_size );
460
461 if( c_nbytes < 0 )
462 {
463 if(errno == EINTR)
464 ;
465 ;
466 if(errno == EWOULDBLOCK)
467 ;
468 ;
469 nbytes = c_nbytes;
470 break;
471
472 }
473
474 nbytes += c_nbytes;
475
476 /* move pointer io-vector */
477 c_iov += iov_size;
478 total_size -= iov_size;
479 }
480 #else /* IOV_MAX */
481 nbytes = writev (fd, iov, iov_index);
482
483 /* Error treatment. */
484 if (nbytes < 0)
485 {
486 if (errno == EINTR)
487 ;
488 if (errno == EWOULDBLOCK)
489 ;
490 }
491 #endif /* IOV_MAX */
492
493 /* Free printed buffer data. */
494 for (out = b->head; out && out != data; out = next)
495 {
496 next = out->next;
497 if (next)
498 next->prev = NULL;
499 else
500 b->tail = next;
501 b->head = next;
502
503 buffer_data_free (out);
504 b->alloc--;
505 }
506
507 if (iov != small_iov)
508 XFREE (MTYPE_TMP, iov);
509
510 return nbytes;
511 }
512
513 /* Calculate size of outputs then flush buffer to the file
514 descriptor. */
515 int
516 buffer_flush_window (struct buffer *b, int fd, int width, int height,
517 int erase, int no_more)
518 {
519 unsigned long cp;
520 unsigned long size;
521 int lp;
522 int lineno;
523 struct buffer_data *data;
524
525 if (height >= 2)
526 height--;
527
528 /* We have to calculate how many bytes should be written. */
529 lp = 0;
530 lineno = 0;
531 size = 0;
532
533 for (data = b->head; data; data = data->next)
534 {
535 cp = data->sp;
536
537 while (cp < data->cp)
538 {
539 if (data->data[cp] == '\n' || lp == width)
540 {
541 lineno++;
542 if (lineno == height)
543 {
544 cp++;
545 size++;
546 goto flush;
547 }
548 lp = 0;
549 }
550 cp++;
551 lp++;
552 size++;
553 }
554 }
555
556 /* Write data to the file descriptor. */
557 flush:
558
559 return buffer_flush_vty (b, fd, size, erase, no_more);
560 }
561
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
566 required later. */
567 int
568 buffer_flush_available(struct buffer *b, int fd)
569 {
570
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
573 in one shot. */
574 #ifdef IOV_MAX
575 #define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX)
576 #else
577 #define MAX_CHUNKS 16
578 #endif
579 #define MAX_FLUSH 131072
580
581 struct buffer_data *d;
582 struct buffer_data *next;
583 ssize_t written;
584 struct iovec iov[MAX_CHUNKS];
585 int iovcnt = 0;
586 size_t nbyte = 0;
587
588 for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH);
589 d = d->next, iovcnt++)
590 {
591 iov[iovcnt].iov_base = d->data+d->sp;
592 nbyte += (iov[iovcnt].iov_len = d->cp-d->sp);
593 }
594
595 if ((written = writev(fd,iov,iovcnt)) < 0)
596 {
597 if ((errno != EAGAIN) && (errno != EINTR))
598 zlog_warn("buffer_flush_available write error on fd %d: %s",
599 fd,strerror(errno));
600 return 1;
601 }
602
603 /* Free printed buffer data. */
604 for (d = b->head; (written > 0) && d; d = next)
605 {
606 if (written < d->cp-d->sp)
607 {
608 d->sp += written;
609 b->length -= written;
610 return 1;
611 }
612
613 written -= (d->cp-d->sp);
614 next = d->next;
615 if (next)
616 next->prev = NULL;
617 else
618 b->tail = next;
619 b->head = next;
620
621 b->length -= (d->cp-d->sp);
622 buffer_data_free (d);
623 b->alloc--;
624 }
625
626 return (b->head != NULL);
627
628 #undef MAX_CHUNKS
629 #undef MAX_FLUSH
630 }