home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Web / Servers / apache-1.2.4-MIHS / original-source / src / buff.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-07  |  22.6 KB  |  990 lines

  1. /* ====================================================================
  2.  * Copyright (c) 1996,1997 The Apache Group.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  *
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in
  13.  *    the documentation and/or other materials provided with the
  14.  *    distribution.
  15.  *
  16.  * 3. All advertising materials mentioning features or use of this
  17.  *    software must display the following acknowledgment:
  18.  *    "This product includes software developed by the Apache Group
  19.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  20.  *
  21.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  22.  *    endorse or promote products derived from this software without
  23.  *    prior written permission.
  24.  *
  25.  * 5. Redistributions of any form whatsoever must retain the following
  26.  *    acknowledgment:
  27.  *    "This product includes software developed by the Apache Group
  28.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  31.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  33.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  34.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  41.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  42.  * ====================================================================
  43.  *
  44.  * This software consists of voluntary contributions made by many
  45.  * individuals on behalf of the Apache Group and was originally based
  46.  * on public domain software written at the National Center for
  47.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  48.  * For more information on the Apache Group and the Apache HTTP server
  49.  * project, please see <http://www.apache.org/>.
  50.  *
  51.  */
  52.  
  53. #include "conf.h"
  54. #include "alloc.h"
  55. #include "buff.h"
  56.  
  57. #include <errno.h>
  58. #include <stdio.h>
  59. #include <stdarg.h>
  60. #include <string.h>
  61. #ifndef NO_UNISTD_H
  62. #include <unistd.h>
  63. #endif
  64. #ifndef NO_WRITEV
  65. #include <sys/types.h>
  66. #include <sys/uio.h>
  67. #endif
  68.  
  69. #ifdef HAVE_BSTRING_H
  70. #include <bstring.h>        /* for IRIX, FD_SET calls bzero() */
  71. #endif
  72.  
  73. #define DEFAULT_BUFSIZE (4096)
  74.  
  75. /*
  76.  * Buffered I/O routines.
  77.  * These are a replacement for the stdio routines.
  78.  * Advantages:
  79.  *  Known semantics for handling of file-descriptors (on close etc.)
  80.  *  No problems reading and writing simultanously to the same descriptor
  81.  *  No limits on the number of open file handles.
  82.  *  Only uses memory resources; no need to ensure the close routine
  83.  *  is called.
  84.  *  Extra code could be inserted between the buffered and un-buffered routines.
  85.  *  Timeouts could be handled by using select or poll before read or write.
  86.  *  Extra error handling could be introduced; e.g.
  87.  *   keep an address to which we should longjump(), or
  88.  *   keep a stack of routines to call on error.
  89.  */
  90.  
  91. /* Notes:
  92.  *  On reading EOF, EOF will set in the flags and no further Input will
  93.  * be done.
  94.  *
  95.  * On an error except for EAGAIN, ERROR will be set in the flags and no
  96.  * futher I/O will be done
  97.  */
  98.  
  99. static void
  100. doerror(BUFF *fb, int err)
  101. {
  102.     int errsave = errno;  /* Save errno to prevent overwriting it below */
  103.  
  104.     if (err == B_RD)
  105.     fb->flags |= B_RDERR;
  106.     else
  107.     fb->flags |= B_WRERR;
  108.     if (fb->error != NULL) (*fb->error)(fb, err, fb->error_data);
  109.  
  110.     errno = errsave;
  111. }
  112.  
  113. /* Buffering routines */
  114. /*
  115.  * Create a new buffered stream
  116.  */
  117. BUFF *
  118. bcreate(pool *p, int flags)
  119. {
  120.     BUFF *fb;
  121.  
  122.     fb = palloc(p, sizeof(BUFF));
  123.     fb->pool=p;
  124.     fb->bufsiz = DEFAULT_BUFSIZE;
  125.     fb->flags = flags & B_RDWR;
  126.  
  127.     if (flags & B_RD) fb->inbase = palloc(p, fb->bufsiz);
  128.     else fb->inbase = NULL;
  129.  
  130.     /* overallocate so that we can put a chunk trailer of CRLF into this
  131.      * buffer */
  132.     if (flags & B_WR) fb->outbase = palloc(p, fb->bufsiz + 2);
  133.     else fb->outbase = NULL;
  134.  
  135.     fb->inptr = fb->inbase;
  136.  
  137.     fb->incnt = 0;
  138.     fb->outcnt = 0;
  139.     fb->outchunk = -1;
  140.     fb->error = NULL;
  141.     fb->bytes_sent = 0L;
  142.  
  143.     fb->fd = -1;
  144.     fb->fd_in = -1;
  145.  
  146.     return fb;
  147. }
  148.  
  149. /*
  150.  * Push some I/O file descriptors onto the stream
  151.  */
  152. void
  153. bpushfd(BUFF *fb, int fd_in, int fd_out)
  154. {
  155.     fb->fd = fd_out;
  156.     fb->fd_in = fd_in;
  157. }
  158.  
  159. int
  160. bsetopt(BUFF *fb, int optname, const void *optval)
  161. {
  162.     if (optname == BO_BYTECT)
  163.     {
  164.     fb->bytes_sent = *(const long int *)optval - (long int)fb->outcnt;;
  165.     return 0;
  166.     } else
  167.     {
  168.     errno = EINVAL;
  169.     return -1;
  170.     }
  171. }
  172.  
  173. int
  174. bgetopt(BUFF *fb, int optname, void *optval)
  175. {
  176.     if (optname == BO_BYTECT)
  177.     {
  178.     long int bs=fb->bytes_sent + fb->outcnt;
  179.     if (bs < 0L) bs = 0L;
  180.     *(long int *)optval = bs;
  181.     return 0;
  182.     } else
  183.     {
  184.     errno = EINVAL;
  185.     return -1;
  186.     }
  187. }
  188.  
  189. /*
  190.  * start chunked encoding
  191.  */
  192. static void
  193. start_chunk( BUFF *fb )
  194. {
  195.     char chunksize[16];    /* Big enough for practically anything */
  196.     int chunk_header_size;
  197.  
  198.     if (fb->outchunk != -1) {
  199.     /* already chunking */
  200.     return;
  201.     }
  202.     if (!(fb->flags & B_WR) || (fb->flags & (B_WRERR|B_EOUT))) {
  203.     /* unbuffered writes */
  204.     return;
  205.     }
  206.  
  207.     /* we know that the chunk header is going to take at least 3 bytes... */
  208.     chunk_header_size = ap_snprintf( chunksize, sizeof(chunksize),
  209.     "%x\015\012", fb->bufsiz - fb->outcnt - 3 );
  210.     /* we need at least the header_len + at least 1 data byte
  211.      * remember that we've overallocated fb->outbase so that we can always
  212.      * fit the two byte CRLF trailer
  213.      */
  214.     if( fb->bufsiz - fb->outcnt < chunk_header_size + 1 ) {
  215.     bflush(fb);
  216.     }
  217.     /* assume there's enough space now */
  218.     memcpy( &fb->outbase[fb->outcnt], chunksize, chunk_header_size );
  219.     fb->outchunk = fb->outcnt;
  220.     fb->outcnt += chunk_header_size;
  221.     fb->outchunk_header_size = chunk_header_size;
  222. }
  223.  
  224.  
  225. /*
  226.  * end a chunk -- tweak the chunk_header from start_chunk, and add a trailer
  227.  */
  228. static void
  229. end_chunk( BUFF *fb )
  230. {
  231.     int i;
  232.  
  233.     if( fb->outchunk == -1 ) {
  234.     /* not chunking */
  235.     return;
  236.     }
  237.  
  238.     if( fb->outchunk + fb->outchunk_header_size == fb->outcnt ) {
  239.     /* nothing was written into this chunk, and we can't write a 0 size
  240.      * chunk because that signifies EOF, so just erase it
  241.      */
  242.     fb->outcnt = fb->outchunk;
  243.     fb->outchunk = -1;
  244.     return;
  245.     }
  246.  
  247.     /* we know this will fit because of how we wrote it in start_chunk() */
  248.     i = ap_snprintf( (char *)&fb->outbase[fb->outchunk],
  249.     fb->outchunk_header_size,
  250.     "%x", fb->outcnt - fb->outchunk - fb->outchunk_header_size );
  251.  
  252.     /* we may have to tack some trailing spaces onto the number we just wrote
  253.      * in case it was smaller than our estimated size.  We've also written
  254.      * a \0 into the buffer with ap_snprintf so we might have to put a
  255.      * \r back in.
  256.      */
  257.     i += fb->outchunk;
  258.     while( fb->outbase[i] != '\015' && fb->outbase[i] != '\012' ) {
  259.     fb->outbase[i++] = ' ';
  260.     }
  261.     if( fb->outbase[i] == '\012' ) {
  262.     /* we overwrote the \r, so put it back */
  263.     fb->outbase[i-1] = '\015';
  264.     }
  265.  
  266.     /* tack on the trailing CRLF, we've reserved room for this */
  267.     fb->outbase[fb->outcnt++] = '\015';
  268.     fb->outbase[fb->outcnt++] = '\012';
  269.  
  270.     fb->outchunk = -1;
  271. }
  272.  
  273.  
  274. /*
  275.  * Set a flag on (1) or off (0).
  276.  */
  277. int bsetflag(BUFF *fb, int flag, int value)
  278. {
  279.     if (value) {
  280.     fb->flags |= flag;
  281.     if( flag & B_CHUNK ) {
  282.         start_chunk(fb);
  283.     }
  284.     } else {
  285.     fb->flags &= ~flag;
  286.     if( flag & B_CHUNK ) {
  287.         end_chunk(fb);
  288.     }
  289.     }
  290.     return value;
  291. }
  292.  
  293.  
  294. /*
  295.  * This is called instead of read() everywhere in here.  It implements
  296.  * the B_SAFEREAD functionality -- which is to force a flush() if a read()
  297.  * would block.  It also deals with the EINTR errno result from read().
  298.  * return code is like read() except EINTR is eliminated.
  299.  */
  300. static int
  301. saferead( BUFF *fb, void *buf, int nbyte )
  302. {
  303.     int rv;
  304.  
  305.     if( fb->flags & B_SAFEREAD ) {
  306.     fd_set fds;
  307.     struct timeval tv;
  308.  
  309.     /* test for a block */
  310.     do {
  311.         FD_ZERO( &fds );
  312.         FD_SET( fb->fd_in, &fds );
  313.         tv.tv_sec = 0;
  314.         tv.tv_usec = 0;
  315. #ifdef SELECT_NEEDS_CAST
  316.         rv = select( fb->fd_in + 1, (int *)&fds, NULL, NULL, &tv );
  317. #else
  318.         rv = select( fb->fd_in + 1, &fds, NULL, NULL, &tv );
  319. #endif
  320.     } while( rv < 0 && errno == EINTR );
  321.     /* treat any error as if it would block as well */
  322.     if( rv != 1 ) {
  323.         bflush(fb);
  324.     }
  325.     }
  326.     do {
  327.     rv = read( fb->fd_in, buf, nbyte );
  328.     } while (rv == -1 && errno == EINTR && !(fb->flags & B_EOUT));
  329.     return( rv );
  330. }
  331.  
  332.  
  333. /*
  334.  * Read up to nbyte bytes into buf.
  335.  * If fewer than byte bytes are currently available, then return those.
  336.  * Returns 0 for EOF, -1 for error.
  337.  */
  338. int
  339. bread(BUFF *fb, void *buf, int nbyte)
  340. {
  341.     int i, nrd;
  342.  
  343.     if (fb->flags & B_RDERR) return -1;
  344.     if (nbyte == 0) return 0;
  345.  
  346.     if (!(fb->flags & B_RD))
  347.     {
  348. /* Unbuffered reading */
  349.     i = saferead( fb, buf, nbyte );
  350.     if (i == -1 && errno != EAGAIN) doerror(fb, B_RD);
  351.     return i;
  352.     }
  353.  
  354.     nrd = fb->incnt;
  355. /* can we fill the buffer */
  356.     if (nrd >= nbyte)
  357.     {
  358.     memcpy(buf, fb->inptr, nbyte);
  359.     fb->incnt = nrd - nbyte;
  360.     fb->inptr += nbyte;
  361.     return nbyte;
  362.     }
  363.     
  364.     if (nrd > 0)
  365.     {
  366.     memcpy(buf, fb->inptr, nrd);
  367.     nbyte -= nrd;
  368.     buf = nrd + (char *)buf;
  369.     fb->incnt = 0;
  370.     }
  371.     if (fb->flags & B_EOF) return nrd;
  372.  
  373. /* do a single read */
  374.     if (nbyte >= fb->bufsiz)
  375.     {
  376. /* read directly into buffer */
  377.     i = saferead( fb, buf, nbyte );
  378.     if (i == -1)
  379.     {
  380.         if (nrd == 0)
  381.         {
  382.         if (errno != EAGAIN) doerror(fb, B_RD);
  383.         return -1;
  384.         }
  385.         else return nrd;
  386.     } else if (i == 0) fb->flags |= B_EOF;
  387.     } else
  388.     {
  389. /* read into hold buffer, then memcpy */
  390.     fb->inptr = fb->inbase;
  391.     i = saferead( fb, fb->inptr, fb->bufsiz );
  392.     if (i == -1)
  393.     {
  394.         if (nrd == 0)
  395.         {
  396.         if (errno != EAGAIN) doerror(fb, B_RD);
  397.         return -1;
  398.         }
  399.         else return nrd;
  400.     } else if (i == 0) fb->flags |= B_EOF;
  401.     fb->incnt = i;
  402.     if (i > nbyte) i = nbyte;
  403.     memcpy(buf, fb->inptr, i);
  404.     fb->incnt -= i;
  405.     fb->inptr += i;
  406.     }
  407.     return nrd + i;
  408. }
  409.  
  410.  
  411. /*
  412.  * Reads from the stream into the array pointed to by buff, until
  413.  * a (CR)LF sequence is read, or end-of-file condition is encountered
  414.  * or until n-1 bytes have been stored in buff. If a CRLF sequence is
  415.  * read, it is replaced by a newline character.  The string is then
  416.  * terminated with a null character.
  417.  *
  418.  * Returns the number of bytes stored in buff, or zero on end of
  419.  * transmission, or -1 on an error.
  420.  *
  421.  * Notes:
  422.  *  If null characters are exepected in the data stream, then
  423.  * buff should not be treated as a null terminated C string; instead
  424.  * the returned count should be used to determine the length of the
  425.  * string.
  426.  *  CR characters in the byte stream not immediately followed by a LF
  427.  * will be preserved.
  428.  */
  429. int
  430. bgets(char *buff, int n, BUFF *fb)
  431. {
  432.     int i, ch, ct;
  433.  
  434. /* Can't do bgets on an unbuffered stream */
  435.     if (!(fb->flags & B_RD))
  436.     {
  437.     errno = EINVAL;
  438.     return -1;
  439.     }
  440.     if (fb->flags & B_RDERR) return -1;
  441.  
  442.     ct = 0;
  443.     i = 0;
  444.     for (;;)
  445.     {
  446.     if (i == fb->incnt)
  447.     {
  448. /* no characters left */
  449.         fb->inptr = fb->inbase;
  450.         fb->incnt = 0;
  451.         if (fb->flags & B_EOF) break;
  452.         i = saferead( fb, fb->inptr, fb->bufsiz );
  453.         if (i == -1)
  454.         {
  455.         buff[ct] = '\0';
  456.         if (ct == 0)
  457.         {
  458.             if (errno != EAGAIN) doerror(fb, B_RD);
  459.             return -1;
  460.         }
  461.         else return ct;
  462.         }
  463.         fb->incnt = i;
  464.         if (i == 0)
  465.         {
  466.         fb->flags |= B_EOF;
  467.         break; /* EOF */
  468.         }
  469.         i = 0;
  470.         continue;  /* restart with the new data */
  471.     }
  472.  
  473.     ch = fb->inptr[i++];
  474.     if (ch == '\012')  /* got LF */
  475.     {
  476.         if (ct == 0) buff[ct++] = '\n';
  477. /* if just preceeded by CR, replace CR with LF */
  478.         else if (buff[ct-1] == '\015') buff[ct-1] = '\n';
  479.         else if (ct < n-1) buff[ct++] = '\n';
  480.         else i--; /* no room for LF */
  481.         break;
  482.     }
  483.     if (ct == n-1)
  484.     {
  485.         i--;  /* push back ch */
  486.         break;
  487.     }
  488.     
  489.     buff[ct++] = ch;
  490.     }
  491.     fb->incnt -= i;
  492.     fb->inptr += i;
  493.  
  494.     buff[ct] = '\0';
  495.     return ct;
  496. }
  497.  
  498. /*
  499.  * Looks at the stream fb and places the first character into buff
  500.  * without removing it from the stream buffer.
  501.  *
  502.  * Returns 1 on success, zero on end of transmission, or -1 on an error.
  503.  *
  504.  */
  505. int blookc(char *buff, BUFF *fb)
  506. {
  507.     int i;
  508.  
  509.     *buff = '\0';
  510.     
  511.     if (!(fb->flags & B_RD)) {   /* Can't do blookc on an unbuffered stream */
  512.         errno = EINVAL;
  513.         return -1;
  514.     }
  515.     if (fb->flags & B_RDERR) return -1;
  516.  
  517.     if (fb->incnt == 0) {        /* no characters left in stream buffer */
  518.         fb->inptr = fb->inbase;
  519.         if (fb->flags & B_EOF)
  520.             return 0;
  521.  
  522.     i = saferead( fb, fb->inptr, fb->bufsiz );
  523.  
  524.         if (i == -1) {
  525.             if (errno != EAGAIN)
  526.                 doerror(fb, B_RD);
  527.             return -1;
  528.         }
  529.         if (i == 0) {
  530.             fb->flags |= B_EOF;
  531.             return 0; /* EOF */
  532.         }
  533.         else fb->incnt = i;
  534.     }
  535.  
  536.     *buff = fb->inptr[0];
  537.     return 1;
  538. }
  539.  
  540. /*
  541.  * Skip data until a linefeed character is read
  542.  * Returns 1 on success, 0 if no LF found, or -1 on error
  543.  */
  544. int
  545. bskiplf(BUFF *fb)
  546. {
  547.     unsigned char *x;
  548.     int i;
  549.  
  550. /* Can't do bskiplf on an unbuffered stream */
  551.     if (!(fb->flags & B_RD))
  552.     {
  553.     errno = EINVAL;
  554.     return -1;
  555.     }
  556.     if (fb->flags & B_RDERR) return -1;
  557.  
  558.     for (;;)
  559.     {
  560.     x = (unsigned char *)memchr(fb->inptr, '\012', fb->incnt);
  561.     if (x != NULL)
  562.     {
  563.         x++;
  564.         fb->incnt -= x - fb->inptr;
  565.         fb->inptr = x;
  566.         return 1;
  567.     }
  568.  
  569.     fb->inptr = fb->inbase;
  570.     fb->incnt = 0;
  571.     if (fb->flags & B_EOF) return 0;
  572.     i = saferead( fb, fb->inptr, fb->bufsiz );
  573.     if (i == 0) fb->flags |= B_EOF;
  574.     if (i == -1 && errno != EAGAIN) doerror(fb, B_RD);
  575.     if (i == 0 || i == -1) return i;
  576.     fb->incnt = i;
  577.     }
  578. }
  579.  
  580. /*
  581.  * Emtpy the buffer after putting a single character in it
  582.  */
  583. int
  584. bflsbuf(int c, BUFF *fb)
  585. {
  586.     char ss[1];
  587.  
  588.     ss[0] = c;
  589.     return bwrite(fb, ss, 1);
  590. }
  591.  
  592. /*
  593.  * Fill the buffer and read a character from it
  594.  */
  595. int
  596. bfilbuf(BUFF *fb)
  597. {
  598.     int i;
  599.     char buf[1];
  600.  
  601.     i = bread(fb, buf, 1);
  602.     if (i == 0) errno = 0;  /* no error; EOF */
  603.     if (i != 1) return EOF;
  604.     else return buf[0];
  605. }
  606.  
  607.  
  608. /*
  609.  * When doing chunked encodings we really have to write everything in the
  610.  * chunk before proceeding onto anything else.  This routine either writes
  611.  * nbytes and returns 0 or returns -1 indicating a failure.
  612.  *
  613.  * This is *seriously broken* if used on a non-blocking fd.  It will poll.
  614.  */
  615. static int
  616. write_it_all(BUFF *fb, const void *buf, int nbyte)
  617. {
  618.     int i;
  619.  
  620.     if (fb->flags & (B_WRERR|B_EOUT))
  621.     return -1;
  622.  
  623.     while (nbyte > 0) {
  624.     i = write(fb->fd, buf, nbyte);
  625.     if (i < 0) {
  626.         if (errno != EAGAIN && errno != EINTR) {
  627.         doerror (fb, B_WR);
  628.         return -1;
  629.         }
  630.     }
  631.     else {
  632.         nbyte -= i;
  633.         buf = i + (const char *)buf;
  634.     }
  635.     if (fb->flags & B_EOUT)
  636.         return -1;
  637.     }
  638.     return 0;
  639. }
  640.  
  641.  
  642. /*
  643.  * A hook to write() that deals with chunking. This is really a protocol-
  644.  * level issue, but we deal with it here because it's simpler; this is
  645.  * an interim solution pending a complete rewrite of all this stuff in
  646.  * 2.0, using something like sfio stacked disciplines or BSD's funopen().
  647.  */
  648. static int
  649. bcwrite(BUFF *fb, const void *buf, int nbyte)
  650. {
  651.     char chunksize[16];    /* Big enough for practically anything */
  652.     int rv;
  653. #ifndef NO_WRITEV
  654.     struct iovec vec[3];
  655.     int i;
  656. #endif
  657.  
  658.     if (fb->flags & (B_WRERR|B_EOUT))
  659.     return -1;
  660.  
  661.     if (!(fb->flags & B_CHUNK)) {
  662.     do rv = write(fb->fd, buf, nbyte);
  663.     while (rv == -1 && errno == EINTR && !(fb->flags & B_EOUT));
  664.     if (rv == -1) {
  665.         if (errno != EAGAIN) {
  666.         doerror (fb, B_WR);
  667.         }
  668.         return -1;
  669.     } else if (rv == 0) {
  670.         errno = EAGAIN;
  671.     }
  672.     return rv;
  673.     }
  674.  
  675. #ifdef NO_WRITEV
  676.     /* without writev() this has poor performance, too bad */
  677.  
  678.     ap_snprintf(chunksize, sizeof(chunksize), "%x\015\012", nbyte);
  679.     if (write_it_all(fb, chunksize, strlen(chunksize)) == -1)
  680.     return -1;
  681.     if (write_it_all(fb, buf, nbyte) == -1)
  682.     return -1;
  683.     if (write_it_all(fb, "\015\012", 2) == -1)
  684.     return -1;
  685.     return nbyte;
  686. #else
  687.  
  688. #define NVEC    (sizeof(vec)/sizeof(vec[0]))
  689.  
  690.     vec[0].iov_base = chunksize;
  691.     vec[0].iov_len = ap_snprintf(chunksize, sizeof(chunksize), "%x\015\012",
  692.     nbyte);
  693.     vec[1].iov_base = (void *)buf;    /* cast is to avoid const warning */
  694.     vec[1].iov_len = nbyte;
  695.     vec[2].iov_base = "\r\n";
  696.     vec[2].iov_len = 2;
  697.     /* while it's nice an easy to build the vector and crud, it's painful
  698.      * to deal with a partial writev()
  699.      */
  700.     for( i = 0; i < NVEC; ) {
  701.     do {
  702.         rv = writev( fb->fd, &vec[i], NVEC - i );
  703.     } while ((rv <= 0)
  704.              && !(fb->flags & B_EOUT)
  705.              && (errno == EINTR || errno == EAGAIN || rv == 0));
  706.     if (rv == -1) {
  707.         doerror (fb, B_WR);
  708.         return -1;
  709.     }
  710.     /* recalculate vec to deal with partial writes */
  711.     while (rv > 0) {
  712.         if( rv <= vec[i].iov_len ) {
  713.         vec[i].iov_base = (char *)vec[i].iov_base + rv;
  714.         vec[i].iov_len -= rv;
  715.         rv = 0;
  716.         if( vec[i].iov_len == 0 ) {
  717.             ++i;
  718.         }
  719.         } else {
  720.         rv -= vec[i].iov_len;
  721.         ++i;
  722.         }
  723.     }
  724.     if (fb->flags & B_EOUT)
  725.         return -1;
  726.     }
  727.     /* if we got here, we wrote it all */
  728.     return nbyte;
  729. #undef NVEC
  730. #endif
  731. }
  732.  
  733.  
  734. /*
  735.  * Write nbyte bytes.
  736.  * Only returns fewer than nbyte if an error ocurred.
  737.  * Returns -1 if no bytes were written before the error ocurred.
  738.  * It is worth noting that if an error occurs, the buffer is in an unknown
  739.  * state.
  740.  */
  741. int
  742. bwrite(BUFF *fb, const void *buf, int nbyte)
  743. {
  744.     int i, nwr;
  745.  
  746.     if (fb->flags & (B_WRERR|B_EOUT)) return -1;
  747.     if (nbyte == 0) return 0;
  748.  
  749.     if (!(fb->flags & B_WR))
  750.     {
  751. /* unbuffered write -- have to use bcwrite since we aren't taking care
  752.  * of chunking any other way */
  753.     i = bcwrite(fb, buf, nbyte);
  754.     if (i <= 0) {
  755.         return -1;
  756.     }
  757.     fb->bytes_sent += i;
  758.     if (fb->flags & B_EOUT)
  759.         return -1;
  760.     else
  761.         return i;
  762.     }
  763.  
  764. /*
  765.  * Whilst there is data in the buffer, keep on adding to it and writing it
  766.  * out
  767.  */
  768.     nwr = 0;
  769.     while (fb->outcnt > 0)
  770.     {
  771. /* can we accept some data? */
  772.     i = fb->bufsiz - fb->outcnt;
  773.     if (i > 0)
  774.     {
  775.         if (i > nbyte) i = nbyte;
  776.         memcpy(fb->outbase + fb->outcnt, buf, i);
  777.         fb->outcnt += i;
  778.         nbyte -= i;
  779.         buf = i + (const char *)buf;
  780.         nwr += i;
  781.         if (nbyte == 0) return nwr; /* return if none left */
  782.     }
  783.  
  784. /* the buffer must be full */
  785.     if (fb->flags & B_CHUNK) {
  786.         end_chunk(fb);
  787.         /* it is just too painful to try to re-cram the buffer while
  788.          * chunking
  789.          */
  790.         if (write_it_all(fb, fb->outbase, fb->outcnt) == -1) {
  791.         /* we cannot continue after a chunked error */
  792.         return -1;
  793.         }
  794.         fb->bytes_sent += fb->outcnt;
  795.         fb->outcnt = 0;
  796.         break;
  797.     }
  798.     do {
  799.         i = write(fb->fd, fb->outbase, fb->outcnt);
  800.     } while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT));
  801.     if (i <= 0) {
  802.         if (i == 0) /* return of 0 means non-blocking */
  803.             errno = EAGAIN;
  804.         if (nwr == 0) {
  805.         if (errno != EAGAIN) doerror(fb, B_WR);
  806.         return -1;
  807.         }
  808.         else return nwr;
  809.     }
  810.     fb->bytes_sent += i;
  811.  
  812.     /* deal with a partial write */
  813.     if (i < fb->outcnt)
  814.     {
  815.         int j, n=fb->outcnt;
  816.         unsigned char *x=fb->outbase;
  817.         for (j=i; j < n; j++) x[j-i] = x[j];
  818.         fb->outcnt -= i;
  819.     }
  820.     else
  821.         fb->outcnt = 0;
  822.  
  823.     if (fb->flags & B_EOUT)
  824.         return -1;
  825.     }
  826. /* we have emptied the file buffer. Now try to write the data from the
  827.  * original buffer until there is less than bufsiz left.  Note that we
  828.  * use bcwrite() to do this for us, it will do the chunking so that
  829.  * we don't have to dink around building a chunk in our own buffer.
  830.  */
  831.     while (nbyte >= fb->bufsiz)
  832.     {
  833.     i = bcwrite(fb, buf, nbyte);
  834.     if (i <= 0) {
  835.         if (nwr == 0) {
  836.         return -1;
  837.         }
  838.         else return nwr;
  839.     }
  840.     fb->bytes_sent += i;
  841.  
  842.     buf = i + (const char *)buf;
  843.     nwr += i;
  844.     nbyte -= i;
  845.  
  846.     if (fb->flags & B_EOUT)
  847.         return -1;
  848.     }
  849. /* copy what's left to the file buffer */
  850.     fb->outcnt = 0;
  851.     if( fb->flags & B_CHUNK ) start_chunk( fb );
  852.     if (nbyte > 0) memcpy(fb->outbase + fb->outcnt, buf, nbyte);
  853.     fb->outcnt += nbyte;
  854.     nwr += nbyte;
  855.     return nwr;
  856. }
  857.  
  858. /*
  859.  * Flushes the buffered stream.
  860.  * Returns 0 on success or -1 on error
  861.  */
  862. int
  863. bflush(BUFF *fb)
  864. {
  865.     int i;
  866.  
  867.     if (!(fb->flags & B_WR) || (fb->flags & B_EOUT)) return 0;
  868.  
  869.     if (fb->flags & B_WRERR) return -1;
  870.     
  871.     if (fb->flags & B_CHUNK) end_chunk(fb);
  872.  
  873.     while (fb->outcnt > 0)
  874.     {
  875.     do {
  876.         i = write(fb->fd, fb->outbase, fb->outcnt);
  877.     } while ((i <= 0)
  878.              && !(fb->flags & B_EOUT)
  879.              && (errno == EINTR || errno == EAGAIN || i == 0));
  880.  
  881.     if (i == 0) {
  882.         errno = EAGAIN;
  883.         return -1;  /* return of 0 means B_EOUT and non-blocking */
  884.     }
  885.     else if (i < 0) {
  886.         if (errno != EAGAIN) doerror(fb, B_WR);
  887.         return -1;
  888.     }
  889.     fb->bytes_sent += i;
  890.  
  891.     /*
  892.       * We should have written all the data, but if the fd was in a
  893.       * strange (non-blocking) mode, then we might not have done so.
  894.       */
  895.     if (i < fb->outcnt)
  896.     {
  897.         int j, n=fb->outcnt;
  898.         unsigned char *x=fb->outbase;
  899.         for (j=i; j < n; j++) x[j-i] = x[j];
  900.     }
  901.     fb->outcnt -= i;
  902.  
  903.     /* If a soft timeout occurs while flushing, the handler should
  904.      * have set the buffer flag B_EOUT.
  905.      */
  906.     if (fb->flags & B_EOUT)
  907.         return -1;
  908.     }
  909.     return 0;
  910. }
  911.  
  912. /*
  913.  * Flushes and closes the file, even if an error occurred.
  914.  * Discards an data that was not read, or not written by bflush()
  915.  * Sets the EOF flag to indicate no futher data can be read,
  916.  * and the EOUT flag to indicate no further data can be written.
  917.  */
  918. int
  919. bclose(BUFF *fb)
  920. {
  921.     int rc1, rc2, rc3;
  922.  
  923.     if (fb->flags & B_WR) rc1 = bflush(fb);
  924.     else rc1 = 0;
  925.     rc2 = close(fb->fd);
  926.     if (fb->fd_in != fb->fd) rc3 = close(fb->fd_in);
  927.     else rc3 = 0;
  928.  
  929.     fb->inptr = fb->inbase;
  930.     fb->incnt = 0;
  931.     fb->outcnt = 0;
  932.  
  933.     fb->flags |= B_EOF | B_EOUT;
  934.     fb->fd = -1;
  935.     fb->fd_in = -1;
  936.  
  937.     if (rc1 != 0) return rc1;
  938.     else if (rc2 != 0) return rc2;
  939.     else return rc3;
  940. }
  941.  
  942. /*
  943.  * returns the number of bytes written or -1 on error
  944.  */
  945. int
  946. bputs(const char *x, BUFF *fb)
  947. {
  948.     int i, j=strlen(x);
  949.     i = bwrite(fb, x, j);
  950.     if (i != j) return -1;
  951.     else return j;
  952. }
  953.  
  954. /*
  955.  * returns the number of bytes written or -1 on error
  956.  */
  957. int
  958. bvputs(BUFF *fb, ...)
  959. {
  960.     int i, j, k;
  961.     va_list v;
  962.     const char *x;
  963.  
  964.     va_start(v, fb);
  965.     for (k=0;;)
  966.     {
  967.     x = va_arg(v, const char *);
  968.     if (x == NULL) break;
  969.     j = strlen(x);
  970.     i = bwrite(fb, x, j);
  971.     if (i != j)
  972.     {
  973.         va_end(v);
  974.         return -1;
  975.     }
  976.     k += i;
  977.     }
  978.  
  979.     va_end(v);
  980.  
  981.     return k;
  982. }
  983.  
  984. void
  985. bonerror(BUFF *fb, void (*error)(BUFF *, int, void *), void *data)
  986. {
  987.     fb->error = error;
  988.     fb->error_data = data;
  989. }
  990.