"Fossies" - the Fresh Open Source Software Archive

Member "mod_fastcgi-2.4.7-0910052141/fcgi_buf.c" (10 Apr 2012, 12624 Bytes) of package /linux/www/apache_httpd_modules/old/mod_fastcgi-2.4.7-0910052141.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * $Id: fcgi_buf.c,v 1.18 2003/02/03 23:07:37 robs Exp $
    3  */
    4 
    5 #include "fcgi.h"
    6 
    7 #ifdef WIN32
    8 #pragma warning( disable : 4127 )
    9 #else
   10 #ifdef APACHE2
   11 #include <unistd.h>
   12 #endif
   13 #endif
   14 
   15 /*******************************************************************************
   16  * Check buffer consistency with assertions.
   17  */
   18 #ifdef DEBUG
   19 static void fcgi_buf_check(Buffer *buf)
   20 {
   21     ASSERT(buf->size > 0);
   22     ASSERT(buf->length >= 0);
   23     ASSERT(buf->length <= buf->size);
   24 
   25     ASSERT(buf->begin >= buf->data);
   26     ASSERT(buf->begin < buf->data + buf->size);
   27     ASSERT(buf->end >= buf->data);
   28     ASSERT(buf->end < buf->data + buf->size);
   29 
   30     ASSERT(((buf->end - buf->begin + buf->size) % buf->size)
   31             == (buf->length % buf->size));
   32 }
   33 #else
   34 #define fcgi_buf_check(a) ((void) 0)
   35 #endif
   36  
   37 /*******************************************************************************
   38  * Reset buffer, losing any data that's in it.
   39  */
   40 void fcgi_buf_reset(Buffer *buf)
   41 {
   42     buf->length = 0;
   43     buf->begin = buf->end = buf->data;
   44 }
   45 
   46 /*******************************************************************************
   47  * Allocate and intialize a new buffer of the specified size.
   48  */
   49 Buffer *fcgi_buf_new(pool *p, int size)
   50 {
   51     Buffer *buf;
   52 
   53     buf = (Buffer *)ap_pcalloc(p, sizeof(Buffer) + size);
   54     buf->size = size;
   55     fcgi_buf_reset(buf);
   56     return buf;
   57 }
   58 
   59 void fcgi_buf_removed(Buffer * const b, unsigned int len)
   60 {
   61     b->length -= len;
   62     b->begin += len;
   63 
   64     if (b->length == 0)
   65     {
   66         b->begin = b->end = b->data;
   67     }
   68     else if (b->begin >= b->data + b->size)
   69     {
   70         b->begin -= b->size;
   71     }
   72 }
   73 
   74 void fcgi_buf_added(Buffer * const b, const unsigned int len)
   75 {
   76     b->length += len;
   77     b->end += len;
   78 
   79     if (b->end >= b->data + b->size)
   80     {
   81         b->end -= b->size;
   82     }
   83 }
   84 
   85 #ifdef WIN32
   86 
   87 static int socket_recv(SOCKET fd, char *buf, int len)
   88 {
   89     int bytes_read = recv(fd, buf, len, 0);
   90 
   91     if (bytes_read == SOCKET_ERROR) 
   92     {
   93         return -1;
   94     }
   95     return bytes_read;
   96 }
   97 
   98 static int socket_send(SOCKET fd, char * buf, int len)
   99 {
  100     int bytes_sent = send(fd, buf, len, 0);
  101 
  102     if (bytes_sent == SOCKET_ERROR) 
  103     {
  104         return -1;
  105     }
  106     return bytes_sent;
  107 }
  108 
  109 #else /* !WIN32 */
  110 
  111 static int socket_recv(int fd, char * buf, int len)
  112 {
  113     int bytes_read;
  114 
  115     do {
  116         bytes_read = read(fd, buf, len);
  117 
  118         if (bytes_read < 0)
  119         {
  120 #ifdef EWOULDBLOCK
  121             ASSERT(errno != EWOULDBLOCK);
  122 #endif
  123 #ifdef EAGAIN
  124             ASSERT(errno != EAGAIN);
  125 #endif
  126         }
  127     } while (bytes_read == -1 && errno == EINTR);
  128 
  129     return bytes_read;
  130 }
  131 
  132 static int socket_send(int fd, char * buf, int len)
  133 {
  134     int bytes_sent;
  135 
  136     do {
  137         bytes_sent = write(fd, buf, len);
  138 
  139         if (bytes_sent < 0)
  140         {
  141 #ifdef EWOULDBLOCK
  142             ASSERT(errno != EWOULDBLOCK);
  143 #endif
  144 #ifdef EAGAIN
  145             ASSERT(errno != EAGAIN);
  146 #endif
  147         }
  148     } 
  149     while (bytes_sent == -1 && errno == EINTR);
  150 
  151     return bytes_sent;
  152 }
  153 
  154 #endif /* !WIN32 */
  155 
  156 /*******************************************************************************
  157  * Read from an open file descriptor into buffer.
  158  *
  159  * The caller should disable the default Apache SIGPIPE handler,
  160  * otherwise a bad script could cause the request to abort and appear
  161  * as though the client's fd caused it.
  162  *
  163  * Results:
  164  *      <0 error, errno is set
  165  *      =0 EOF reached
  166  *      >0 successful read or no room in buffer (NOT # of bytes read)
  167  */
  168 int fcgi_buf_socket_recv(Buffer *buf, SOCKET fd)
  169 {
  170     int len;
  171 
  172     fcgi_buf_check(buf);
  173 
  174     if (buf->length == buf->size)
  175         /* there's no room in the buffer, return "success" */
  176         return 1;
  177 
  178     if (buf->length == 0)
  179         /* the buffer is empty so defrag */
  180         buf->begin = buf->end = buf->data;
  181 
  182     len = min(buf->size - buf->length, buf->data + buf->size - buf->end);
  183 
  184 #ifndef NO_WRITEV
  185 
  186     /* assume there is a readv() since there is a writev() */
  187     if (len == buf->size - buf->length) 
  188     {
  189 #endif
  190 
  191         len = socket_recv(fd, buf->end, len);
  192 
  193 #ifndef NO_WRITEV
  194     } 
  195     else 
  196     {
  197         /* the buffer is wrapped, use readv() */
  198         struct iovec vec[2];
  199 
  200         vec[0].iov_base = buf->end;
  201         vec[0].iov_len = len;
  202         vec[1].iov_base = buf->data;
  203         vec[1].iov_len = buf->size - buf->length - len;
  204 
  205         ASSERT(len);
  206         ASSERT(vec[1].iov_len);
  207 
  208         do
  209         {
  210             len = readv(fd, vec, 2);
  211         }
  212         while (len == -1 && errno == EINTR);
  213     }
  214 #endif
  215 
  216     if (len <= 0) return len;
  217 
  218     fcgi_buf_added(buf, len);
  219 
  220     return len;     /* this may not contain the number of bytes read */
  221 }
  222 
  223 
  224 /*******************************************************************************
  225  * Write from the buffer to an open file descriptor.
  226  *
  227  * The caller should disable the default Apache SIGPIPE handler,
  228  * otherwise a bad script could cause the request to abort appearing
  229  * as though the client's fd caused it.
  230  *
  231  * Results:
  232  *      <0 if an error occured (bytes may or may not have been written)
  233  *      =0 if no bytes were written
  234  *      >0 successful write
  235  */
  236 int fcgi_buf_socket_send(Buffer *buf, SOCKET fd)
  237 {
  238     int len;
  239 
  240     fcgi_buf_check(buf);
  241 
  242     if (buf->length == 0)
  243         return 0;
  244 
  245     len = min(buf->length, buf->data + buf->size - buf->begin);
  246 
  247 #ifndef NO_WRITEV
  248     if (len == buf->length) 
  249     {
  250 #endif
  251 
  252         len = socket_send(fd, buf->begin, len);
  253 
  254 #ifndef NO_WRITEV
  255     } 
  256     else 
  257     {
  258         struct iovec vec[2];
  259 
  260         vec[0].iov_base = buf->begin;
  261         vec[0].iov_len = len;
  262         vec[1].iov_base = buf->data;
  263         vec[1].iov_len = buf->length - len;
  264 
  265         do
  266         {
  267             len = writev(fd, vec, 2);
  268         }
  269         while (len == -1 && errno == EINTR);
  270     }
  271 #endif
  272 
  273     if (len <= 0) return len;
  274 
  275     fcgi_buf_removed(buf, len);
  276 
  277     return len;
  278 }
  279 
  280 /*******************************************************************************
  281  * Return the data block start address and the length of the block.
  282  */
  283 void fcgi_buf_get_block_info(Buffer *buf, char **beginPtr, int *countPtr)
  284 {
  285     fcgi_buf_check(buf);
  286 
  287     *beginPtr = buf->begin;
  288     *countPtr = min(buf->length, buf->data + buf->size - buf->begin);
  289 }
  290 
  291 /*******************************************************************************
  292  * Throw away bytes from buffer.
  293  */
  294 void fcgi_buf_toss(Buffer *buf, int count)
  295 {
  296     fcgi_buf_check(buf);
  297     ASSERT(count >= 0);
  298     ASSERT(count <= buf->length);
  299 
  300     buf->length -= count;
  301     buf->begin += count;
  302     if(buf->begin >= buf->data + buf->size) {
  303         buf->begin -= buf->size;
  304     }
  305 }
  306 
  307 /*******************************************************************************
  308  * Return the free data block start address and the length of the block.
  309  */
  310 void fcgi_buf_get_free_block_info(Buffer *buf, char **endPtr, int *countPtr)
  311 {
  312     fcgi_buf_check(buf);
  313 
  314     *endPtr = buf->end;
  315     *countPtr = min(buf->size - buf->length,
  316                     buf->data + buf->size - buf->end);
  317 }
  318 
  319 /*******************************************************************************
  320  * Updates the buf to reflect recently added data.
  321  */
  322 void fcgi_buf_add_update(Buffer *buf, int count)
  323 {
  324     fcgi_buf_check(buf);
  325     ASSERT(count >= 0);
  326     ASSERT(count <= BufferFree(buf));
  327 
  328     buf->length += count;
  329     buf->end += count;
  330     if(buf->end >= buf->data + buf->size) {
  331         buf->end -= buf->size;
  332     }
  333 
  334     fcgi_buf_check(buf);
  335 }
  336 
  337 /*******************************************************************************
  338  * Adds a block of data to a buffer, returning the number of bytes added.
  339  */
  340 int fcgi_buf_add_block(Buffer *buf, char *data, int datalen)
  341 {
  342     char *end;
  343     int copied = 0;     /* Number of bytes actually copied. */
  344     int canCopy;        /* Number of bytes to copy in a given op. */
  345 
  346     ASSERT(data != NULL);
  347     ASSERT(datalen >= 0);
  348 
  349     if(datalen == 0) {
  350         return 0;
  351     }
  352 
  353     ASSERT(datalen > 0);
  354     fcgi_buf_check(buf);
  355     end = buf->data + buf->size;
  356 
  357     /*
  358      * Copy the first part of the data:  from here to the end of the
  359      * buffer, or the end of the data, whichever comes first.
  360      */
  361     datalen = min(BufferFree(buf), datalen);
  362     canCopy = min(datalen, end - buf->end);
  363     memcpy(buf->end, data, canCopy);
  364     buf->length += canCopy;
  365     buf->end += canCopy;
  366     copied += canCopy;
  367     if (buf->end >= end) {
  368         buf->end = buf->data;
  369     }
  370     datalen -= canCopy;
  371 
  372     /*
  373      * If there's more to go, copy the second part starting from the
  374      * beginning of the buffer.
  375      */
  376     if (datalen > 0) {
  377         data += canCopy;
  378         memcpy(buf->end, data, datalen);
  379         buf->length += datalen;
  380         buf->end += datalen;
  381         copied += datalen;
  382     }
  383     return(copied);
  384 }
  385 
  386 /*******************************************************************************
  387  * Add a string to a buffer, returning the number of bytes added.
  388  */
  389 int fcgi_buf_add_string(Buffer *buf, char *str)
  390 {
  391     return fcgi_buf_add_block(buf, str, strlen(str));
  392 }
  393 
  394 /*******************************************************************************
  395  * Gets a data block from a buffer, returning the number of bytes copied.
  396  */
  397 int fcgi_buf_get_to_block(Buffer *buf, char *data, int datalen)
  398 {
  399     char *end;
  400     int copied = 0;                /* Number of bytes actually copied. */
  401     int canCopy;                   /* Number of bytes to copy in a given op. */
  402 
  403     ASSERT(data != NULL);
  404     ASSERT(datalen > 0);
  405     fcgi_buf_check(buf);
  406 
  407     end = buf->data + buf->size;
  408 
  409     /*
  410      * Copy the first part out of the buffer: from here to the end
  411      * of the buffer, or all of the requested data.
  412      */
  413     canCopy = min(buf->length, datalen);
  414     canCopy = min(canCopy, end - buf->begin);
  415 
  416     memcpy(data, buf->begin, canCopy);
  417 
  418     buf->length -= canCopy;
  419     buf->begin += canCopy;
  420     copied += canCopy;
  421     if (buf->begin >= end) {
  422         buf->begin = buf->data;
  423     }
  424 
  425     /*
  426      * If there's more to go, copy the second part starting from the
  427      * beginning of the buffer.
  428      */
  429     if (copied < datalen && buf->length > 0) {
  430         data += copied;
  431         canCopy = min(buf->length, datalen - copied);
  432 
  433         memcpy(data, buf->begin, canCopy);
  434 
  435         buf->length -= canCopy;
  436         buf->begin += canCopy;
  437         copied += canCopy;
  438     }
  439 
  440     fcgi_buf_check(buf);
  441     return(copied);
  442 }
  443 
  444 /*******************************************************************************
  445  * Move 'len' bytes from 'src' buffer to 'dest' buffer.  There must be at
  446  * least 'len' bytes available in the source buffer and space for 'len'
  447  * bytes in the destination buffer.
  448  */
  449 void fcgi_buf_get_to_buf(Buffer *dest, Buffer *src, int len)
  450 {
  451     char *dest_end, *src_begin;
  452     int dest_len, src_len, move_len;
  453 
  454     ASSERT(len > 0);
  455     ASSERT(BufferLength(src) >= len);
  456     ASSERT(BufferFree(dest) >= len);
  457 
  458     fcgi_buf_check(src);
  459     fcgi_buf_check(dest);
  460 
  461     for (;;) {
  462         if (len == 0)
  463             return;
  464 
  465         fcgi_buf_get_free_block_info(dest, &dest_end, &dest_len);
  466         fcgi_buf_get_block_info(src, &src_begin, &src_len);
  467 
  468         move_len = min(dest_len, src_len);
  469         move_len = min(move_len, len);
  470 
  471         if (move_len == 0)
  472             return;
  473 
  474         memcpy(dest_end, src_begin, move_len);
  475         fcgi_buf_toss(src, move_len);
  476         fcgi_buf_add_update(dest, move_len);
  477         len -= move_len;
  478     }
  479 }
  480 
  481 static void array_grow(array_header *arr, int n)
  482 {
  483     if (n <= 0)
  484         return;
  485 
  486     if (arr->nelts + n > arr->nalloc) {
  487         char *new_elts;
  488         int new_nalloc = (arr->nalloc <= 0) ? n : arr->nelts + n;
  489 
  490         new_elts = ap_pcalloc(arr->pool, arr->elt_size * new_nalloc);
  491         memcpy(new_elts, arr->elts, arr->nelts * arr->elt_size);
  492 
  493         arr->elts = new_elts;
  494         arr->nalloc = new_nalloc;
  495     }
  496 }
  497 
  498 static void array_cat_block(array_header *arr, void *block, int n)
  499 {
  500     array_grow(arr, n);
  501     memcpy(arr->elts + arr->nelts * arr->elt_size, block, n * arr->elt_size);
  502     arr->nelts += n;
  503 }
  504 
  505 /*----------------------------------------------------------------------
  506  * Append "len" bytes from "buf" into "arr".  Apache arrays are used
  507  * whenever the data being handled is binary (may contain null chars).
  508  */
  509 void fcgi_buf_get_to_array(Buffer *buf, array_header *arr, int len)
  510 {
  511     int len1 = min(buf->length, buf->data + buf->size - buf->begin);
  512 
  513     fcgi_buf_check(buf);
  514     ASSERT(len > 0);
  515     ASSERT(len <= BufferLength(buf));
  516 
  517     array_grow(arr, len);
  518 
  519     len1 = min(len1, len);
  520     array_cat_block(arr, buf->begin, len1);
  521 
  522     if (len1 < len)
  523         array_cat_block(arr, buf->data, len - len1);
  524 
  525     fcgi_buf_toss(buf, len);
  526 }