]> jfr.im git - solanum.git/blame - librb/src/linebuf.c
Merge branch 'authd-framework-2' into authd-framework
[solanum.git] / librb / src / linebuf.c
CommitLineData
db137867
AC
1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * linebuf.c: Maintains linebuffers.
4 *
5 * Copyright (C) 2001-2002 Adrian Chadd <adrian@creative.net.au>
6 * Copyright (C) 2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 * USA
23 *
db137867
AC
24 */
25
fe037171
EM
26#include <librb_config.h>
27#include <rb_lib.h>
db137867
AC
28#include <commio-int.h>
29
db137867 30static rb_bh *rb_linebuf_heap;
db137867
AC
31
32static int bufline_count = 0;
33
34#ifndef LINEBUF_HEAP_SIZE
35#define LINEBUF_HEAP_SIZE 2048
36#endif
37
38/*
39 * rb_linebuf_init
40 *
41 * Initialise the linebuf mechanism
42 */
43
44void
45rb_linebuf_init(size_t heap_size)
46{
db137867 47 rb_linebuf_heap = rb_bh_create(sizeof(buf_line_t), heap_size, "librb_linebuf_heap");
db137867
AC
48}
49
50static buf_line_t *
51rb_linebuf_allocate(void)
52{
53 buf_line_t *t;
db137867 54 t = rb_bh_alloc(rb_linebuf_heap);
db137867
AC
55 return (t);
56
57}
58
59static void
60rb_linebuf_free(buf_line_t * p)
61{
db137867 62 rb_bh_free(rb_linebuf_heap, p);
db137867
AC
63}
64
65/*
66 * rb_linebuf_new_line
67 *
68 * Create a new line, and link it to the given linebuf.
69 * It will be initially empty.
70 */
71static buf_line_t *
72rb_linebuf_new_line(buf_head_t * bufhead)
73{
74 buf_line_t *bufline;
75 rb_dlink_node *node;
76
77 bufline = rb_linebuf_allocate();
78 if(bufline == NULL)
79 return NULL;
80 ++bufline_count;
81
82
83 node = rb_make_rb_dlink_node();
84
85 /* Stick it at the end of the buf list */
86 rb_dlinkAddTail(bufline, node, &bufhead->list);
87 bufline->refcount++;
88
89 /* And finally, update the allocated size */
90 bufhead->alloclen++;
91 bufhead->numlines++;
92
93 return bufline;
94}
95
96
97/*
98 * rb_linebuf_done_line
99 *
100 * We've finished with the given line, so deallocate it
101 */
102static void
3202e249 103rb_linebuf_done_line(buf_head_t * bufhead, buf_line_t * bufline, rb_dlink_node *node)
db137867
AC
104{
105 /* Remove it from the linked list */
106 rb_dlinkDestroy(node, &bufhead->list);
107
108 /* Update the allocated size */
109 bufhead->alloclen--;
110 bufhead->len -= bufline->len;
111 lrb_assert(bufhead->len >= 0);
112 bufhead->numlines--;
113
114 bufline->refcount--;
115 lrb_assert(bufline->refcount >= 0);
116
117 if(bufline->refcount == 0)
118 {
119 /* and finally, deallocate the buf */
120 --bufline_count;
121 lrb_assert(bufline_count >= 0);
122 rb_linebuf_free(bufline);
123 }
124}
125
126
127/*
128 * skip to end of line or the crlfs, return the number of bytes ..
129 */
130static inline int
131rb_linebuf_skip_crlf(char *ch, int len)
132{
133 int orig_len = len;
134
135 /* First, skip until the first non-CRLF */
136 for(; len; len--, ch++)
137 {
138 if(*ch == '\r')
139 break;
140 else if(*ch == '\n')
141 break;
142 }
143
144 /* Then, skip until the last CRLF */
145 for(; len; len--, ch++)
146 {
147 if((*ch != '\r') && (*ch != '\n'))
148 break;
149 }
150 lrb_assert(orig_len > len);
151 return (orig_len - len);
152}
153
154
155
156/*
157 * rb_linebuf_newbuf
158 *
159 * Initialise the new buffer
160 */
161void
162rb_linebuf_newbuf(buf_head_t * bufhead)
163{
164 /* not much to do right now :) */
165 memset(bufhead, 0, sizeof(buf_head_t));
166}
167
168/*
169 * rb_linebuf_donebuf
170 *
171 * Flush all the lines associated with this buffer
172 */
173void
174rb_linebuf_donebuf(buf_head_t * bufhead)
175{
176 while(bufhead->list.head != NULL)
177 {
3202e249
VY
178 rb_linebuf_done_line(bufhead, (buf_line_t *) bufhead->list.head->data,
179 bufhead->list.head);
db137867
AC
180 }
181}
182
183/*
184 * rb_linebuf_copy_line
185 *
186 * Okay..this functions comments made absolutely no sense.
55abcbb2 187 *
db137867
AC
188 * Basically what we do is this. Find the first chunk of text
189 * and then scan for a CRLF. If we didn't find it, but we didn't
190 * overflow our buffer..we wait for some more data.
191 * If we found a CRLF, we replace them with a \0 character.
192 * If we overflowed, we copy the most our buffer can handle, terminate
193 * it with a \0 and return.
194 *
195 * The return value is the amount of data we consumed. This could
196 * be different than the size of the linebuffer, as when we discard
197 * the overflow, we don't want to process it again.
198 *
199 * This still sucks in my opinion, but it seems to work.
200 *
201 * -Aaron
202 */
203static int
204rb_linebuf_copy_line(buf_head_t * bufhead, buf_line_t * bufline, char *data, int len)
205{
206 int cpylen = 0; /* how many bytes we've copied */
207 char *ch = data; /* Pointer to where we are in the read data */
208 char *bufch = bufline->buf + bufline->len;
209 int clen = 0; /* how many bytes we've processed,
210 and don't ever want to see again.. */
211
212 /* If its full or terminated, ignore it */
213
214 bufline->raw = 0;
215 lrb_assert(bufline->len < BUF_DATA_SIZE);
216 if(bufline->terminated == 1)
217 return 0;
218
219 clen = cpylen = rb_linebuf_skip_crlf(ch, len);
220 if(clen == -1)
221 return -1;
222
223 /* This is the ~overflow case..This doesn't happen often.. */
224 if(cpylen > (BUF_DATA_SIZE - bufline->len - 1))
225 {
1c864688
JT
226 cpylen = BUF_DATA_SIZE - bufline->len - 1;
227 memcpy(bufch, ch, cpylen);
db137867
AC
228 bufline->buf[BUF_DATA_SIZE - 1] = '\0';
229 bufch = bufline->buf + BUF_DATA_SIZE - 2;
230 while(cpylen && (*bufch == '\r' || *bufch == '\n'))
231 {
232 *bufch = '\0';
233 cpylen--;
234 bufch--;
235 }
236 bufline->terminated = 1;
237 bufline->len = BUF_DATA_SIZE - 1;
238 bufhead->len += BUF_DATA_SIZE - 1;
239 return clen;
240 }
241
242 memcpy(bufch, ch, cpylen);
243 bufch += cpylen;
244 *bufch = '\0';
245 bufch--;
246
247 if(*bufch != '\r' && *bufch != '\n')
248 {
249 /* No linefeed, bail for the next time */
250 bufhead->len += cpylen;
251 bufline->len += cpylen;
252 bufline->terminated = 0;
253 return clen;
254 }
255
256 /* Yank the CRLF off this, replace with a \0 */
257 while(cpylen && (*bufch == '\r' || *bufch == '\n'))
258 {
259 *bufch = '\0';
260 cpylen--;
261 bufch--;
262 }
263
264 bufline->terminated = 1;
265 bufhead->len += cpylen;
266 bufline->len += cpylen;
267 return clen;
268}
269
270/*
271 * rb_linebuf_copy_raw
272 *
273 * Copy as much data as possible directly into a linebuf,
274 * splitting at \r\n, but without altering any data.
275 *
276 */
277static int
278rb_linebuf_copy_raw(buf_head_t * bufhead, buf_line_t * bufline, char *data, int len)
279{
280 int cpylen = 0; /* how many bytes we've copied */
281 char *ch = data; /* Pointer to where we are in the read data */
282 char *bufch = bufline->buf + bufline->len;
283 int clen = 0; /* how many bytes we've processed,
284 and don't ever want to see again.. */
285
286 /* If its full or terminated, ignore it */
287
288 bufline->raw = 1;
289 lrb_assert(bufline->len < BUF_DATA_SIZE);
290 if(bufline->terminated == 1)
291 return 0;
292
293 clen = cpylen = rb_linebuf_skip_crlf(ch, len);
294 if(clen == -1)
295 return -1;
296
297 /* This is the overflow case..This doesn't happen often.. */
298 if(cpylen > (BUF_DATA_SIZE - bufline->len - 1))
299 {
300 clen = BUF_DATA_SIZE - bufline->len - 1;
301 memcpy(bufch, ch, clen);
302 bufline->buf[BUF_DATA_SIZE - 1] = '\0';
303 bufch = bufline->buf + BUF_DATA_SIZE - 2;
304 bufline->terminated = 1;
305 bufline->len = BUF_DATA_SIZE - 1;
306 bufhead->len += BUF_DATA_SIZE - 1;
307 return clen;
308 }
309
310 memcpy(bufch, ch, cpylen);
311 bufch += cpylen;
312 *bufch = '\0';
313 bufch--;
314
315 if(*bufch != '\r' && *bufch != '\n')
316 {
317 /* No linefeed, bail for the next time */
318 bufhead->len += cpylen;
319 bufline->len += cpylen;
320 bufline->terminated = 0;
321 return clen;
322 }
323
324 bufline->terminated = 1;
325 bufhead->len += cpylen;
326 bufline->len += cpylen;
327 return clen;
328}
329
330
331/*
332 * rb_linebuf_parse
333 *
334 * Take a given buffer and break out as many buffers as we can.
335 * If we find a CRLF, we terminate that buffer and create a new one.
336 * If we don't find a CRLF whilst parsing a buffer, we don't mark it
337 * 'finished', so the next loop through we can continue appending ..
338 *
339 * A few notes here, which you'll need to understand before continuing.
340 *
341 * - right now I'm only dealing with single sized buffers. Later on,
342 * I might consider chaining buffers together to get longer "lines"
343 * but seriously, I don't see the advantage right now.
344 *
345 * - This *is* designed to turn into a reference-counter-protected setup
346 * to dodge copious copies.
347 */
348int
349rb_linebuf_parse(buf_head_t * bufhead, char *data, int len, int raw)
350{
351 buf_line_t *bufline;
352 int cpylen;
353 int linecnt = 0;
354
355 /* First, if we have a partial buffer, try to squeze data into it */
356 if(bufhead->list.tail != NULL)
357 {
358 /* Check we're doing the partial buffer thing */
359 bufline = bufhead->list.tail->data;
db137867
AC
360 /* just try, the worst it could do is *reject* us .. */
361 if(!raw)
362 cpylen = rb_linebuf_copy_line(bufhead, bufline, data, len);
363 else
364 cpylen = rb_linebuf_copy_raw(bufhead, bufline, data, len);
365
366 if(cpylen == -1)
367 return -1;
368
369 linecnt++;
370 /* If we've copied the same as what we've got, quit now */
371 if(cpylen == len)
372 return linecnt; /* all the data done so soon? */
373
374 /* Skip the data and update len .. */
375 len -= cpylen;
376 lrb_assert(len >= 0);
377 data += cpylen;
378 }
379
380 /* Next, the loop */
381 while(len > 0)
382 {
383 /* We obviously need a new buffer, so .. */
384 bufline = rb_linebuf_new_line(bufhead);
385
386 /* And parse */
387 if(!raw)
388 cpylen = rb_linebuf_copy_line(bufhead, bufline, data, len);
389 else
390 cpylen = rb_linebuf_copy_raw(bufhead, bufline, data, len);
391
392 if(cpylen == -1)
393 return -1;
394
395 len -= cpylen;
396 lrb_assert(len >= 0);
397 data += cpylen;
398 linecnt++;
399 }
400 return linecnt;
401}
402
403
404/*
405 * rb_linebuf_get
406 *
407 * get the next buffer from our line. For the time being it will copy
408 * data into the given buffer and free the underlying linebuf.
409 */
410int
411rb_linebuf_get(buf_head_t * bufhead, char *buf, int buflen, int partial, int raw)
412{
413 buf_line_t *bufline;
414 int cpylen;
415 char *start, *ch;
416
417 /* make sure we have a line */
418 if(bufhead->list.head == NULL)
419 return 0; /* Obviously not.. hrm. */
420
421 bufline = bufhead->list.head->data;
422
423 /* make sure that the buffer was actually *terminated */
424 if(!(partial || bufline->terminated))
425 return 0; /* Wait for more data! */
426
427 if(buflen < bufline->len)
428 cpylen = buflen - 1;
429 else
430 cpylen = bufline->len;
431
432 /* Copy it */
433 start = bufline->buf;
434
435 /* if we left extraneous '\r\n' characters in the string,
436 * and we don't want to read the raw data, clean up the string.
437 */
438 if(bufline->raw && !raw)
439 {
440 /* skip leading EOL characters */
441 while(cpylen && (*start == '\r' || *start == '\n'))
442 {
443 start++;
444 cpylen--;
445 }
446 /* skip trailing EOL characters */
447 ch = &start[cpylen - 1];
448 while(cpylen && (*ch == '\r' || *ch == '\n'))
449 {
450 ch--;
451 cpylen--;
452 }
453 }
454
455 memcpy(buf, start, cpylen);
456
457 /* convert CR/LF to NULL */
458 if(!raw)
459 buf[cpylen] = '\0';
460
461 lrb_assert(cpylen >= 0);
462
463 /* Deallocate the line */
464 rb_linebuf_done_line(bufhead, bufline, bufhead->list.head);
465
466 /* return how much we copied */
467 return cpylen;
468}
469
470/*
471 * rb_linebuf_attach
472 *
473 * attach the lines in a buf_head_t to another buf_head_t
474 * without copying the data (using refcounts).
475 */
476void
477rb_linebuf_attach(buf_head_t * bufhead, buf_head_t * new)
478{
479 rb_dlink_node *ptr;
480 buf_line_t *line;
481
482 RB_DLINK_FOREACH(ptr, new->list.head)
483 {
484 line = ptr->data;
485 rb_dlinkAddTailAlloc(line, &bufhead->list);
486
487 /* Update the allocated size */
488 bufhead->alloclen++;
489 bufhead->len += line->len;
490 bufhead->numlines++;
491
492 line->refcount++;
493 }
494}
495
db137867
AC
496/*
497 * rb_linebuf_putmsg
498 *
499 * Similar to rb_linebuf_put, but designed for use by send.c.
500 *
501 * prefixfmt is used as a format for the varargs, and is inserted first.
502 * Then format/va_args is appended to the buffer.
503 */
504void
3202e249
VY
505rb_linebuf_putmsg(buf_head_t * bufhead, const char *format, va_list * va_args,
506 const char *prefixfmt, ...)
db137867
AC
507{
508 buf_line_t *bufline;
509 int len = 0;
510 va_list prefix_args;
511
512 /* make sure the previous line is terminated */
513#ifndef NDEBUG
514 if(bufhead->list.tail)
515 {
516 bufline = bufhead->list.tail->data;
517 lrb_assert(bufline->terminated);
518 }
519#endif
520 /* Create a new line */
521 bufline = rb_linebuf_new_line(bufhead);
522
523 if(prefixfmt != NULL)
524 {
525 va_start(prefix_args, prefixfmt);
5203cba5 526 len = vsnprintf(bufline->buf, BUF_DATA_SIZE, prefixfmt, prefix_args);
db137867
AC
527 va_end(prefix_args);
528 }
529
530 if(va_args != NULL)
531 {
5203cba5 532 len += vsnprintf((bufline->buf + len), (BUF_DATA_SIZE - len), format, *va_args);
db137867
AC
533 }
534
535 bufline->terminated = 1;
536
537 /* Truncate the data if required */
c2ac22cc 538 if(rb_unlikely(len > 510))
db137867
AC
539 {
540 len = 510;
541 bufline->buf[len++] = '\r';
542 bufline->buf[len++] = '\n';
543 }
c2ac22cc 544 else if(rb_unlikely(len == 0))
db137867
AC
545 {
546 bufline->buf[len++] = '\r';
547 bufline->buf[len++] = '\n';
548 bufline->buf[len] = '\0';
549 }
550 else
551 {
552 /* Chop trailing CRLF's .. */
3202e249
VY
553 while((bufline->buf[len] == '\r') || (bufline->buf[len] == '\n')
554 || (bufline->buf[len] == '\0'))
db137867
AC
555 {
556 len--;
557 }
558
559 bufline->buf[++len] = '\r';
560 bufline->buf[++len] = '\n';
561 bufline->buf[++len] = '\0';
562 }
563
564 bufline->len = len;
565 bufhead->len += len;
566}
567
5abeae60
AC
568/*
569 * rb_linebuf_putprefix
570 *
571 * Similar to rb_linebuf_put, but designed for use by send.c.
572 *
573 * prefix is inserted first, then format/va_args is appended to the buffer.
574 */
575void
576rb_linebuf_putprefix(buf_head_t * bufhead, const char *format, va_list * va_args,
577 const char *prefix)
578{
579 buf_line_t *bufline;
580 int len = 0;
581
582 /* make sure the previous line is terminated */
583#ifndef NDEBUG
584 if(bufhead->list.tail)
585 {
586 bufline = bufhead->list.tail->data;
587 lrb_assert(bufline->terminated);
588 }
589#endif
590 /* Create a new line */
591 bufline = rb_linebuf_new_line(bufhead);
592
593 if(prefix != NULL)
594 len = rb_strlcpy(bufline->buf, prefix, BUF_DATA_SIZE);
595
596 if(va_args != NULL)
597 {
598 len += vsnprintf((bufline->buf + len), (BUF_DATA_SIZE - len), format, *va_args);
599 }
600
601 bufline->terminated = 1;
602
603 /* Truncate the data if required */
604 if(rb_unlikely(len > 510))
605 {
606 len = 510;
607 bufline->buf[len++] = '\r';
608 bufline->buf[len++] = '\n';
609 }
610 else if(rb_unlikely(len == 0))
611 {
612 bufline->buf[len++] = '\r';
613 bufline->buf[len++] = '\n';
614 bufline->buf[len] = '\0';
615 }
616 else
617 {
618 /* Chop trailing CRLF's .. */
619 while((bufline->buf[len] == '\r') || (bufline->buf[len] == '\n')
620 || (bufline->buf[len] == '\0'))
621 {
622 len--;
623 }
624
625 bufline->buf[++len] = '\r';
626 bufline->buf[++len] = '\n';
627 bufline->buf[++len] = '\0';
628 }
629
630 bufline->len = len;
631 bufhead->len += len;
632}
633
db137867 634void
3202e249 635rb_linebuf_putbuf(buf_head_t * bufhead, const char *buffer)
db137867
AC
636{
637 buf_line_t *bufline;
638 int len = 0;
639
640 /* make sure the previous line is terminated */
641#ifndef NDEBUG
642 if(bufhead->list.tail)
643 {
644 bufline = bufhead->list.tail->data;
645 lrb_assert(bufline->terminated);
646 }
647#endif
648 /* Create a new line */
649 bufline = rb_linebuf_new_line(bufhead);
650
c2ac22cc 651 if(rb_unlikely(buffer != NULL))
db137867
AC
652 len = rb_strlcpy(bufline->buf, buffer, BUF_DATA_SIZE);
653
654 bufline->terminated = 1;
655
656 /* Truncate the data if required */
c2ac22cc 657 if(rb_unlikely(len > 510))
db137867
AC
658 {
659 len = 510;
660 bufline->buf[len++] = '\r';
661 bufline->buf[len++] = '\n';
662 }
c2ac22cc 663 else if(rb_unlikely(len == 0))
db137867
AC
664 {
665 bufline->buf[len++] = '\r';
666 bufline->buf[len++] = '\n';
667 bufline->buf[len] = '\0';
668 }
669 else
670 {
671 /* Chop trailing CRLF's .. */
3202e249
VY
672 while((bufline->buf[len] == '\r') || (bufline->buf[len] == '\n')
673 || (bufline->buf[len] == '\0'))
db137867
AC
674 {
675 len--;
676 }
677
678 bufline->buf[++len] = '\r';
679 bufline->buf[++len] = '\n';
680 bufline->buf[++len] = '\0';
681 }
682
683 bufline->len = len;
684 bufhead->len += len;
685
3202e249 686
db137867
AC
687}
688
689void
690rb_linebuf_put(buf_head_t * bufhead, const char *format, ...)
691{
692 buf_line_t *bufline;
693 int len = 0;
694 va_list args;
695
696 /* make sure the previous line is terminated */
697#ifndef NDEBUG
698 if(bufhead->list.tail)
699 {
700 bufline = bufhead->list.tail->data;
701 lrb_assert(bufline->terminated);
702 }
703#endif
704 /* Create a new line */
705 bufline = rb_linebuf_new_line(bufhead);
706
c2ac22cc 707 if(rb_unlikely(format != NULL))
db137867
AC
708 {
709 va_start(args, format);
5203cba5 710 len = vsnprintf(bufline->buf, BUF_DATA_SIZE, format, args);
db137867
AC
711 va_end(args);
712 }
713
714 bufline->terminated = 1;
715
716 /* Truncate the data if required */
c2ac22cc 717 if(rb_unlikely(len > 510))
db137867
AC
718 {
719 len = 510;
720 bufline->buf[len++] = '\r';
721 bufline->buf[len++] = '\n';
722 }
c2ac22cc 723 else if(rb_unlikely(len == 0))
db137867
AC
724 {
725 bufline->buf[len++] = '\r';
726 bufline->buf[len++] = '\n';
727 bufline->buf[len] = '\0';
728 }
729 else
730 {
731 /* Chop trailing CRLF's .. */
3202e249
VY
732 while((bufline->buf[len] == '\r') || (bufline->buf[len] == '\n')
733 || (bufline->buf[len] == '\0'))
db137867
AC
734 {
735 len--;
736 }
737
738 bufline->buf[++len] = '\r';
739 bufline->buf[++len] = '\n';
740 bufline->buf[++len] = '\0';
741 }
742
743 bufline->len = len;
744 bufhead->len += len;
745}
746
747
748
749/*
750 * rb_linebuf_flush
751 *
752 * Flush data to the buffer. It tries to write as much data as possible
753 * to the given socket. Any return values are passed straight through.
754 * If there is no data in the socket, EWOULDBLOCK is set as an errno
755 * rather than returning 0 (which would map to an EOF..)
756 *
757 * Notes: XXX We *should* have a clue here when a non-full buffer is arrived.
758 * and tag it so that we don't re-schedule another write until
759 * we have a CRLF.
760 */
761int
762rb_linebuf_flush(rb_fde_t *F, buf_head_t * bufhead)
763{
764 buf_line_t *bufline;
765 int retval;
766
55abcbb2
KB
767/*
768 * autoconf checks for this..but really just want to use it if we have a
db137867
AC
769 * native version even if libircd provides a fake version...
770 */
771#ifdef HAVE_WRITEV
772 if(!rb_fd_ssl(F))
773 {
774 rb_dlink_node *ptr;
775 int x = 0, y;
776 int xret;
777 static struct rb_iovec vec[RB_UIO_MAXIOV];
778
779 memset(vec, 0, sizeof(vec));
780 /* Check we actually have a first buffer */
781 if(bufhead->list.head == NULL)
782 {
783 /* nope, so we return none .. */
784 errno = EWOULDBLOCK;
785 return -1;
786 }
787
788 ptr = bufhead->list.head;
3202e249 789
db137867
AC
790 bufline = ptr->data;
791 if(!bufline->terminated)
792 {
793 errno = EWOULDBLOCK;
794 return -1;
795
796 }
797
39930c66
JT
798 vec[x].iov_base = bufline->buf + bufhead->writeofs;
799 vec[x++].iov_len = bufline->len - bufhead->writeofs;
800 ptr = ptr->next;
db137867
AC
801
802 do
803 {
804 if(ptr == NULL)
805 break;
806
807 bufline = ptr->data;
808 if(!bufline->terminated)
809 break;
3202e249 810
db137867
AC
811 vec[x].iov_base = bufline->buf;
812 vec[x].iov_len = bufline->len;
813 ptr = ptr->next;
814
3202e249
VY
815 }
816 while(++x < RB_UIO_MAXIOV);
db137867
AC
817
818 if(x == 0)
819 {
820 errno = EWOULDBLOCK;
821 return -1;
822 }
823
824 xret = retval = rb_writev(F, vec, x);
825 if(retval <= 0)
826 return retval;
827
828 ptr = bufhead->list.head;
829
830 for(y = 0; y < x; y++)
831 {
832 bufline = ptr->data;
833
39930c66 834 if(xret >= bufline->len - bufhead->writeofs)
db137867 835 {
39930c66 836 xret -= bufline->len - bufhead->writeofs;
db137867
AC
837 ptr = ptr->next;
838 rb_linebuf_done_line(bufhead, bufline, bufhead->list.head);
39930c66 839 bufhead->writeofs = 0;
db137867 840 }
3202e249 841 else
db137867 842 {
39930c66 843 bufhead->writeofs += xret;
db137867
AC
844 break;
845 }
db137867
AC
846 }
847
848 return retval;
849 }
3202e249
VY
850#endif
851
852 /* this is the non-writev case */
db137867 853
db137867
AC
854 /* Check we actually have a first buffer */
855 if(bufhead->list.head == NULL)
856 {
857 /* nope, so we return none .. */
858 errno = EWOULDBLOCK;
859 return -1;
860 }
861
862 bufline = bufhead->list.head->data;
863
864 /* And that its actually full .. */
865 if(!bufline->terminated)
866 {
867 errno = EWOULDBLOCK;
868 return -1;
869 }
870
db137867
AC
871 /* Now, try writing data */
872 retval = rb_write(F, bufline->buf + bufhead->writeofs, bufline->len - bufhead->writeofs);
873
874 if(retval <= 0)
875 return retval;
876
877 /* we've got data, so update the write offset */
878 bufhead->writeofs += retval;
879
880 /* if we've written everything *and* the CRLF, deallocate and update
881 bufhead */
882 if(bufhead->writeofs == bufline->len)
883 {
884 bufhead->writeofs = 0;
885 lrb_assert(bufhead->len >= 0);
886 rb_linebuf_done_line(bufhead, bufline, bufhead->list.head);
887 }
888
889 /* Return line length */
890 return retval;
891}
892
893
894
895/*
896 * count linebufs for stats z
897 */
898
899void
3202e249 900rb_count_rb_linebuf_memory(size_t *count, size_t *rb_linebuf_memory_used)
db137867 901{
db137867 902 rb_bh_usage(rb_linebuf_heap, count, NULL, rb_linebuf_memory_used, NULL);
db137867 903}