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