blob: 8666ab78d1b23d6ca51bff383fa929bf52cb41b6 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
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"
paul2265d202004-11-08 15:43:21 +000027#include "log.h"
ajs49ff6d92004-11-04 19:26:16 +000028#include <stddef.h>
paul718e3742002-12-13 20:15:29 +000029
30/* Make buffer data. */
ajs49ff6d92004-11-04 19:26:16 +000031static struct buffer_data *
paul718e3742002-12-13 20:15:29 +000032buffer_data_new (size_t size)
33{
34 struct buffer_data *d;
35
ajs49ff6d92004-11-04 19:26:16 +000036 d = XMALLOC (MTYPE_BUFFER_DATA, offsetof(struct buffer_data,data[size]));
37 d->cp = d->sp = 0;
paul718e3742002-12-13 20:15:29 +000038 return d;
39}
40
ajs49ff6d92004-11-04 19:26:16 +000041static void
paul718e3742002-12-13 20:15:29 +000042buffer_data_free (struct buffer_data *d)
43{
paul718e3742002-12-13 20:15:29 +000044 XFREE (MTYPE_BUFFER_DATA, d);
45}
46
47/* Make new buffer. */
48struct buffer *
49buffer_new (size_t size)
50{
51 struct buffer *b;
52
53 b = XMALLOC (MTYPE_BUFFER, sizeof (struct buffer));
54 memset (b, 0, sizeof (struct buffer));
55
56 b->size = size;
57
58 return b;
59}
60
61/* Free buffer. */
62void
63buffer_free (struct buffer *b)
64{
65 struct buffer_data *d;
66 struct buffer_data *next;
67
68 d = b->head;
69 while (d)
70 {
71 next = d->next;
72 buffer_data_free (d);
73 d = next;
74 }
75
76 d = b->unused_head;
77 while (d)
78 {
79 next = d->next;
80 buffer_data_free (d);
81 d = next;
82 }
83
84 XFREE (MTYPE_BUFFER, b);
85}
86
87/* Make string clone. */
88char *
89buffer_getstr (struct buffer *b)
90{
ajsafb8b602005-01-28 20:41:07 +000091 size_t totlen = 0;
92 struct buffer_data *data;
93 char *s;
94 char *p;
95
96 for (data = b->head; data; data = data->next)
97 totlen += data->cp - data->sp;
ajs3b8b1852005-01-29 18:19:13 +000098 if (!(s = XMALLOC(MTYPE_TMP, totlen+1)))
ajsafb8b602005-01-28 20:41:07 +000099 return NULL;
100 p = s;
101 for (data = b->head; data; data = data->next)
102 {
103 memcpy(p, data->data + data->sp, data->cp - data->sp);
104 p += data->cp - data->sp;
105 }
106 *p = '\0';
107 return s;
paul718e3742002-12-13 20:15:29 +0000108}
109
110/* Return 1 if buffer is empty. */
111int
112buffer_empty (struct buffer *b)
113{
114 if (b->tail == NULL || b->tail->cp == b->tail->sp)
115 return 1;
116 else
117 return 0;
118}
119
120/* Clear and free all allocated data. */
121void
122buffer_reset (struct buffer *b)
123{
124 struct buffer_data *data;
125 struct buffer_data *next;
126
127 for (data = b->head; data; data = next)
128 {
129 next = data->next;
130 buffer_data_free (data);
131 }
132 b->head = b->tail = NULL;
133 b->alloc = 0;
134 b->length = 0;
135}
136
137/* Add buffer_data to the end of buffer. */
138void
139buffer_add (struct buffer *b)
140{
141 struct buffer_data *d;
142
143 d = buffer_data_new (b->size);
144
145 if (b->tail == NULL)
146 {
147 d->prev = NULL;
148 d->next = NULL;
149 b->head = d;
150 b->tail = d;
151 }
152 else
153 {
154 d->prev = b->tail;
155 d->next = NULL;
156
157 b->tail->next = d;
158 b->tail = d;
159 }
160
161 b->alloc++;
162}
163
164/* Write data to buffer. */
165int
paul9035efa2004-10-10 11:56:56 +0000166buffer_write (struct buffer *b, const void *p, size_t size)
paul718e3742002-12-13 20:15:29 +0000167{
168 struct buffer_data *data;
paul9035efa2004-10-10 11:56:56 +0000169 const char *ptr = p;
paul718e3742002-12-13 20:15:29 +0000170 data = b->tail;
171 b->length += size;
172
173 /* We use even last one byte of data buffer. */
174 while (size)
175 {
ajs49ff6d92004-11-04 19:26:16 +0000176 size_t chunk;
177
paul718e3742002-12-13 20:15:29 +0000178 /* If there is no data buffer add it. */
179 if (data == NULL || data->cp == b->size)
180 {
181 buffer_add (b);
182 data = b->tail;
183 }
184
ajs49ff6d92004-11-04 19:26:16 +0000185 chunk = ((size <= (b->size - data->cp)) ? size : (b->size - data->cp));
186 memcpy ((data->data + data->cp), ptr, chunk);
187 size -= chunk;
188 ptr += chunk;
189 data->cp += chunk;
paul718e3742002-12-13 20:15:29 +0000190 }
191 return 1;
192}
193
194/* Insert character into the buffer. */
195int
196buffer_putc (struct buffer *b, u_char c)
197{
198 buffer_write (b, &c, 1);
199 return 1;
200}
201
202/* Insert word (2 octets) into ther buffer. */
203int
204buffer_putw (struct buffer *b, u_short c)
205{
206 buffer_write (b, (char *)&c, 2);
207 return 1;
208}
209
210/* Put string to the buffer. */
211int
paul9035efa2004-10-10 11:56:56 +0000212buffer_putstr (struct buffer *b, const char *c)
paul718e3742002-12-13 20:15:29 +0000213{
214 size_t size;
215
paul5228ad22004-06-04 17:58:18 +0000216 size = strlen (c);
217 buffer_write (b, (void *) c, size);
paul718e3742002-12-13 20:15:29 +0000218 return 1;
219}
220
221/* Flush specified size to the fd. */
222void
223buffer_flush (struct buffer *b, int fd, size_t size)
224{
225 int iov_index;
226 struct iovec *iovec;
227 struct buffer_data *data;
228 struct buffer_data *out;
229 struct buffer_data *next;
230
231 iovec = malloc (sizeof (struct iovec) * b->alloc);
232 iov_index = 0;
233
234 for (data = b->head; data; data = data->next)
235 {
236 iovec[iov_index].iov_base = (char *)(data->data + data->sp);
237
238 if (size <= (data->cp - data->sp))
239 {
240 iovec[iov_index++].iov_len = size;
241 data->sp += size;
ajs49ff6d92004-11-04 19:26:16 +0000242 b->length -= size;
paul718e3742002-12-13 20:15:29 +0000243 if (data->sp == data->cp)
244 data = data->next;
245 break;
246 }
247 else
248 {
249 iovec[iov_index++].iov_len = data->cp - data->sp;
ajs49ff6d92004-11-04 19:26:16 +0000250 b->length -= (data->cp - data->sp);
paul718e3742002-12-13 20:15:29 +0000251 size -= data->cp - data->sp;
252 data->sp = data->cp;
253 }
254 }
255
256 /* Write buffer to the fd. */
257 writev (fd, iovec, iov_index);
258
259 /* Free printed buffer data. */
260 for (out = b->head; out && out != data; out = next)
261 {
262 next = out->next;
263 if (next)
264 next->prev = NULL;
265 else
266 b->tail = next;
267 b->head = next;
268
269 buffer_data_free (out);
270 b->alloc--;
271 }
272
273 free (iovec);
274}
275
276/* Flush all buffer to the fd. */
277int
278buffer_flush_all (struct buffer *b, int fd)
279{
280 int ret;
281 struct buffer_data *d;
282 int iov_index;
283 struct iovec *iovec;
284
285 if (buffer_empty (b))
286 return 0;
287
288 iovec = malloc (sizeof (struct iovec) * b->alloc);
289 iov_index = 0;
290
291 for (d = b->head; d; d = d->next)
292 {
293 iovec[iov_index].iov_base = (char *)(d->data + d->sp);
294 iovec[iov_index].iov_len = d->cp - d->sp;
295 iov_index++;
296 }
297 ret = writev (fd, iovec, iov_index);
298
299 free (iovec);
300
301 buffer_reset (b);
302
303 return ret;
304}
305
306/* Flush all buffer to the fd. */
307int
308buffer_flush_vty_all (struct buffer *b, int fd, int erase_flag,
309 int no_more_flag)
310{
311 int nbytes;
312 int iov_index;
313 struct iovec *iov;
314 struct iovec small_iov[3];
315 char more[] = " --More-- ";
316 char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
317 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
318 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
319 struct buffer_data *data;
320 struct buffer_data *out;
321 struct buffer_data *next;
322
323 /* For erase and more data add two to b's buffer_data count.*/
324 if (b->alloc == 1)
325 iov = small_iov;
326 else
327 iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
328
329 data = b->head;
330 iov_index = 0;
331
332 /* Previously print out is performed. */
333 if (erase_flag)
334 {
335 iov[iov_index].iov_base = erase;
336 iov[iov_index].iov_len = sizeof erase;
337 iov_index++;
338 }
339
340 /* Output data. */
341 for (data = b->head; data; data = data->next)
342 {
343 iov[iov_index].iov_base = (char *)(data->data + data->sp);
344 iov[iov_index].iov_len = data->cp - data->sp;
345 iov_index++;
346 }
347
348 /* In case of `more' display need. */
349 if (! buffer_empty (b) && !no_more_flag)
350 {
351 iov[iov_index].iov_base = more;
352 iov[iov_index].iov_len = sizeof more;
353 iov_index++;
354 }
355
356 /* We use write or writev*/
357 nbytes = writev (fd, iov, iov_index);
358
359 /* Error treatment. */
360 if (nbytes < 0)
361 {
362 if (errno == EINTR)
363 ;
364 if (errno == EWOULDBLOCK)
365 ;
366 }
367
368 /* Free printed buffer data. */
369 for (out = b->head; out && out != data; out = next)
370 {
371 next = out->next;
372 if (next)
373 next->prev = NULL;
374 else
375 b->tail = next;
376 b->head = next;
377
ajs49ff6d92004-11-04 19:26:16 +0000378 b->length -= (out->cp-out->sp);
paul718e3742002-12-13 20:15:29 +0000379 buffer_data_free (out);
380 b->alloc--;
381 }
382
383 if (iov != small_iov)
384 XFREE (MTYPE_TMP, iov);
385
386 return nbytes;
387}
388
389/* Flush buffer to the file descriptor. Mainly used from vty
390 interface. */
391int
hasso8c328f12004-10-05 21:01:23 +0000392buffer_flush_vty (struct buffer *b, int fd, unsigned int size,
paul718e3742002-12-13 20:15:29 +0000393 int erase_flag, int no_more_flag)
394{
395 int nbytes;
396 int iov_index;
397 struct iovec *iov;
398 struct iovec small_iov[3];
399 char more[] = " --More-- ";
400 char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
401 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
402 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
403 struct buffer_data *data;
404 struct buffer_data *out;
405 struct buffer_data *next;
406
407#ifdef IOV_MAX
408 int iov_size;
409 int total_size;
410 struct iovec *c_iov;
411 int c_nbytes;
412#endif /* IOV_MAX */
413
414 /* For erase and more data add two to b's buffer_data count.*/
415 if (b->alloc == 1)
416 iov = small_iov;
417 else
418 iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
419
420 data = b->head;
421 iov_index = 0;
422
423 /* Previously print out is performed. */
424 if (erase_flag)
425 {
426 iov[iov_index].iov_base = erase;
427 iov[iov_index].iov_len = sizeof erase;
428 iov_index++;
429 }
430
431 /* Output data. */
432 for (data = b->head; data; data = data->next)
433 {
434 iov[iov_index].iov_base = (char *)(data->data + data->sp);
435
436 if (size <= (data->cp - data->sp))
437 {
438 iov[iov_index++].iov_len = size;
439 data->sp += size;
ajs49ff6d92004-11-04 19:26:16 +0000440 b->length -= size;
paul718e3742002-12-13 20:15:29 +0000441 if (data->sp == data->cp)
442 data = data->next;
443 break;
444 }
445 else
446 {
447 iov[iov_index++].iov_len = data->cp - data->sp;
448 size -= (data->cp - data->sp);
ajs49ff6d92004-11-04 19:26:16 +0000449 b->length -= (data->cp - data->sp);
paul718e3742002-12-13 20:15:29 +0000450 data->sp = data->cp;
451 }
452 }
453
454 /* In case of `more' display need. */
455 if (!buffer_empty (b) && !no_more_flag)
456 {
457 iov[iov_index].iov_base = more;
458 iov[iov_index].iov_len = sizeof more;
459 iov_index++;
460 }
461
462 /* We use write or writev*/
463
464#ifdef IOV_MAX
465 /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
466 example: Solaris2.6 are defined IOV_MAX size at 16. */
467 c_iov = iov;
468 total_size = iov_index;
469 nbytes = 0;
470
471 while( total_size > 0 )
472 {
473 /* initialize write vector size at once */
474 iov_size = ( total_size > IOV_MAX ) ? IOV_MAX : total_size;
475
476 c_nbytes = writev (fd, c_iov, iov_size );
477
478 if( c_nbytes < 0 )
479 {
480 if(errno == EINTR)
481 ;
482 ;
483 if(errno == EWOULDBLOCK)
484 ;
485 ;
486 nbytes = c_nbytes;
487 break;
488
489 }
490
491 nbytes += c_nbytes;
492
493 /* move pointer io-vector */
494 c_iov += iov_size;
495 total_size -= iov_size;
496 }
497#else /* IOV_MAX */
498 nbytes = writev (fd, iov, iov_index);
499
500 /* Error treatment. */
501 if (nbytes < 0)
502 {
503 if (errno == EINTR)
504 ;
505 if (errno == EWOULDBLOCK)
506 ;
507 }
508#endif /* IOV_MAX */
509
510 /* Free printed buffer data. */
511 for (out = b->head; out && out != data; out = next)
512 {
513 next = out->next;
514 if (next)
515 next->prev = NULL;
516 else
517 b->tail = next;
518 b->head = next;
519
520 buffer_data_free (out);
521 b->alloc--;
522 }
523
524 if (iov != small_iov)
525 XFREE (MTYPE_TMP, iov);
526
527 return nbytes;
528}
529
530/* Calculate size of outputs then flush buffer to the file
531 descriptor. */
532int
533buffer_flush_window (struct buffer *b, int fd, int width, int height,
534 int erase, int no_more)
535{
536 unsigned long cp;
537 unsigned long size;
538 int lp;
539 int lineno;
540 struct buffer_data *data;
541
542 if (height >= 2)
543 height--;
544
545 /* We have to calculate how many bytes should be written. */
546 lp = 0;
547 lineno = 0;
548 size = 0;
549
550 for (data = b->head; data; data = data->next)
551 {
552 cp = data->sp;
553
554 while (cp < data->cp)
555 {
556 if (data->data[cp] == '\n' || lp == width)
557 {
558 lineno++;
559 if (lineno == height)
560 {
561 cp++;
562 size++;
563 goto flush;
564 }
565 lp = 0;
566 }
567 cp++;
568 lp++;
569 size++;
570 }
571 }
572
573 /* Write data to the file descriptor. */
574 flush:
575
576 return buffer_flush_vty (b, fd, size, erase, no_more);
577}
ajs49ff6d92004-11-04 19:26:16 +0000578
579/* This function (unlike other buffer_flush* functions above) is designed
580to work with non-blocking sockets. It does not attempt to write out
581all of the queued data, just a "big" chunk. It returns 0 if it was
582able to empty out the buffers completely, or 1 if more flushing is
583required later. */
584int
585buffer_flush_available(struct buffer *b, int fd)
586{
587
588/* These are just reasonable values to make sure a significant amount of
589data is written. There's no need to go crazy and try to write it all
590in one shot. */
591#ifdef IOV_MAX
592#define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX)
593#else
594#define MAX_CHUNKS 16
595#endif
596#define MAX_FLUSH 131072
597
598 struct buffer_data *d;
599 struct buffer_data *next;
paul2265d202004-11-08 15:43:21 +0000600 size_t written;
ajs49ff6d92004-11-04 19:26:16 +0000601 struct iovec iov[MAX_CHUNKS];
paul2265d202004-11-08 15:43:21 +0000602 size_t iovcnt = 0;
ajs49ff6d92004-11-04 19:26:16 +0000603 size_t nbyte = 0;
604
605 for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH);
606 d = d->next, iovcnt++)
607 {
608 iov[iovcnt].iov_base = d->data+d->sp;
609 nbyte += (iov[iovcnt].iov_len = d->cp-d->sp);
610 }
611
paul2265d202004-11-08 15:43:21 +0000612 /* only place where written should be sign compared */
613 if ((ssize_t)(written = writev(fd,iov,iovcnt)) < 0)
ajs49ff6d92004-11-04 19:26:16 +0000614 {
615 if ((errno != EAGAIN) && (errno != EINTR))
616 zlog_warn("buffer_flush_available write error on fd %d: %s",
ajs6099b3b2004-11-20 02:06:59 +0000617 fd,safe_strerror(errno));
ajs49ff6d92004-11-04 19:26:16 +0000618 return 1;
619 }
620
621 /* Free printed buffer data. */
622 for (d = b->head; (written > 0) && d; d = next)
623 {
624 if (written < d->cp-d->sp)
625 {
626 d->sp += written;
627 b->length -= written;
628 return 1;
629 }
630
631 written -= (d->cp-d->sp);
632 next = d->next;
633 if (next)
634 next->prev = NULL;
635 else
636 b->tail = next;
637 b->head = next;
638
639 b->length -= (d->cp-d->sp);
640 buffer_data_free (d);
641 b->alloc--;
642 }
643
644 return (b->head != NULL);
645
646#undef MAX_CHUNKS
647#undef MAX_FLUSH
648}