2 * $Id: fcgi_buf.c,v 1.15 2002/03/12 13:06:29 robs Exp $
8 #pragma warning( disable : 4127 )
11 /*******************************************************************************
12 * Check buffer consistency with assertions.
14 void fcgi_buf_check(Buffer
*buf
)
16 ap_assert(buf
->size
> 0);
17 ap_assert(buf
->length
>= 0);
18 ap_assert(buf
->length
<= buf
->size
);
20 ap_assert(buf
->begin
>= buf
->data
);
21 ap_assert(buf
->begin
< buf
->data
+ buf
->size
);
22 ap_assert(buf
->end
>= buf
->data
);
23 ap_assert(buf
->end
< buf
->data
+ buf
->size
);
25 ap_assert(((buf
->end
- buf
->begin
+ buf
->size
) % buf
->size
)
26 == (buf
->length
% buf
->size
));
29 /*******************************************************************************
30 * Reset buffer, losing any data that's in it.
32 void fcgi_buf_reset(Buffer
*buf
)
35 buf
->begin
= buf
->end
= buf
->data
;
38 /*******************************************************************************
39 * Allocate and intialize a new buffer of the specified size.
41 Buffer
*fcgi_buf_new(pool
*p
, int size
)
45 buf
= (Buffer
*)ap_pcalloc(p
, sizeof(Buffer
) + size
);
51 void fcgi_buf_removed(Buffer
* const b
, unsigned int len
)
58 b
->begin
= b
->end
= b
->data
;
60 else if (b
->begin
>= b
->data
+ b
->size
)
66 void fcgi_buf_added(Buffer
* const b
, const unsigned int len
)
71 if (b
->end
>= b
->data
+ b
->size
)
79 static int socket_recv(SOCKET fd
, char *buf
, int len
)
81 int bytes_read
= recv(fd
, buf
, len
, 0);
83 if (bytes_read
== SOCKET_ERROR
)
90 static int socket_send(SOCKET fd
, char * buf
, int len
)
92 int bytes_sent
= send(fd
, buf
, len
, 0);
94 if (bytes_sent
== SOCKET_ERROR
)
103 static int socket_recv(int fd
, char * buf
, int len
)
108 bytes_read
= read(fd
, buf
, len
);
113 ap_assert(errno
!= EWOULDBLOCK
);
116 ap_assert(errno
!= EAGAIN
);
119 } while (bytes_read
== -1 && errno
== EINTR
);
124 static int socket_send(int fd
, char * buf
, int len
)
129 bytes_sent
= write(fd
, buf
, len
);
134 ap_assert(errno
!= EWOULDBLOCK
);
137 ap_assert(errno
!= EAGAIN
);
141 while (bytes_sent
== -1 && errno
== EINTR
);
148 /*******************************************************************************
149 * Read from an open file descriptor into buffer.
151 * The caller should disable the default Apache SIGPIPE handler,
152 * otherwise a bad script could cause the request to abort and appear
153 * as though the client's fd caused it.
156 * <0 error, errno is set
158 * >0 successful read or no room in buffer (NOT # of bytes read)
160 int fcgi_buf_socket_recv(Buffer
*buf
, SOCKET fd
)
166 if (buf
->length
== buf
->size
)
167 /* there's no room in the buffer, return "success" */
170 if (buf
->length
== 0)
171 /* the buffer is empty so defrag */
172 buf
->begin
= buf
->end
= buf
->data
;
174 len
= min(buf
->size
- buf
->length
, buf
->data
+ buf
->size
- buf
->end
);
178 /* assume there is a readv() since there is a writev() */
179 if (len
== buf
->size
- buf
->length
)
183 len
= socket_recv(fd
, buf
->end
, len
);
189 /* the buffer is wrapped, use readv() */
192 vec
[0].iov_base
= buf
->end
;
193 vec
[0].iov_len
= len
;
194 vec
[1].iov_base
= buf
->data
;
195 vec
[1].iov_len
= buf
->size
- buf
->length
- len
;
198 ap_assert(vec
[1].iov_len
);
202 len
= readv(fd
, vec
, 2);
204 while (len
== -1 && errno
== EINTR
);
208 if (len
<= 0) return len
;
210 fcgi_buf_added(buf
, len
);
212 return len
; /* this may not contain the number of bytes read */
216 /*******************************************************************************
217 * Write from the buffer to an open file descriptor.
219 * The caller should disable the default Apache SIGPIPE handler,
220 * otherwise a bad script could cause the request to abort appearing
221 * as though the client's fd caused it.
224 * <0 if an error occured (bytes may or may not have been written)
225 * =0 if no bytes were written
226 * >0 successful write
228 int fcgi_buf_socket_send(Buffer
*buf
, SOCKET fd
)
234 if (buf
->length
== 0)
237 len
= min(buf
->length
, buf
->data
+ buf
->size
- buf
->begin
);
240 if (len
== buf
->length
)
244 len
= socket_send(fd
, buf
->begin
, len
);
252 vec
[0].iov_base
= buf
->begin
;
253 vec
[0].iov_len
= len
;
254 vec
[1].iov_base
= buf
->data
;
255 vec
[1].iov_len
= buf
->length
- len
;
259 len
= writev(fd
, vec
, 2);
261 while (len
== -1 && errno
== EINTR
);
265 if (len
<= 0) return len
;
267 fcgi_buf_removed(buf
, len
);
272 /*******************************************************************************
273 * Return the data block start address and the length of the block.
275 void fcgi_buf_get_block_info(Buffer
*buf
, char **beginPtr
, int *countPtr
)
279 *beginPtr
= buf
->begin
;
280 *countPtr
= min(buf
->length
, buf
->data
+ buf
->size
- buf
->begin
);
283 /*******************************************************************************
284 * Throw away bytes from buffer.
286 void fcgi_buf_toss(Buffer
*buf
, int count
)
289 ap_assert(count
>= 0);
290 ap_assert(count
<= buf
->length
);
292 buf
->length
-= count
;
294 if(buf
->begin
>= buf
->data
+ buf
->size
) {
295 buf
->begin
-= buf
->size
;
299 /*******************************************************************************
300 * Return the free data block start address and the length of the block.
302 void fcgi_buf_get_free_block_info(Buffer
*buf
, char **endPtr
, int *countPtr
)
307 *countPtr
= min(buf
->size
- buf
->length
,
308 buf
->data
+ buf
->size
- buf
->end
);
311 /*******************************************************************************
312 * Updates the buf to reflect recently added data.
314 void fcgi_buf_add_update(Buffer
*buf
, int count
)
317 ap_assert(count
>= 0);
318 ap_assert(count
<= BufferFree(buf
));
320 buf
->length
+= count
;
322 if(buf
->end
>= buf
->data
+ buf
->size
) {
323 buf
->end
-= buf
->size
;
329 /*******************************************************************************
330 * Adds a block of data to a buffer, returning the number of bytes added.
332 int fcgi_buf_add_block(Buffer
*buf
, char *data
, int datalen
)
335 int copied
= 0; /* Number of bytes actually copied. */
336 int canCopy
; /* Number of bytes to copy in a given op. */
338 ap_assert(data
!= NULL
);
339 ap_assert(datalen
>= 0);
345 ap_assert(datalen
> 0);
347 end
= buf
->data
+ buf
->size
;
350 * Copy the first part of the data: from here to the end of the
351 * buffer, or the end of the data, whichever comes first.
353 datalen
= min(BufferFree(buf
), datalen
);
354 canCopy
= min(datalen
, end
- buf
->end
);
355 memcpy(buf
->end
, data
, canCopy
);
356 buf
->length
+= canCopy
;
359 if (buf
->end
>= end
) {
360 buf
->end
= buf
->data
;
365 * If there's more to go, copy the second part starting from the
366 * beginning of the buffer.
370 memcpy(buf
->end
, data
, datalen
);
371 buf
->length
+= datalen
;
378 /*******************************************************************************
379 * Add a string to a buffer, returning the number of bytes added.
381 int fcgi_buf_add_string(Buffer
*buf
, char *str
)
383 return fcgi_buf_add_block(buf
, str
, strlen(str
));
386 /*******************************************************************************
387 * Gets a data block from a buffer, returning the number of bytes copied.
389 int fcgi_buf_get_to_block(Buffer
*buf
, char *data
, int datalen
)
392 int copied
= 0; /* Number of bytes actually copied. */
393 int canCopy
; /* Number of bytes to copy in a given op. */
395 ap_assert(data
!= NULL
);
396 ap_assert(datalen
> 0);
399 end
= buf
->data
+ buf
->size
;
402 * Copy the first part out of the buffer: from here to the end
403 * of the buffer, or all of the requested data.
405 canCopy
= min(buf
->length
, datalen
);
406 canCopy
= min(canCopy
, end
- buf
->begin
);
408 memcpy(data
, buf
->begin
, canCopy
);
410 buf
->length
-= canCopy
;
411 buf
->begin
+= canCopy
;
413 if (buf
->begin
>= end
) {
414 buf
->begin
= buf
->data
;
418 * If there's more to go, copy the second part starting from the
419 * beginning of the buffer.
421 if (copied
< datalen
&& buf
->length
> 0) {
423 canCopy
= min(buf
->length
, datalen
- copied
);
425 memcpy(data
, buf
->begin
, canCopy
);
427 buf
->length
-= canCopy
;
428 buf
->begin
+= canCopy
;
436 /*******************************************************************************
437 * Move 'len' bytes from 'src' buffer to 'dest' buffer. There must be at
438 * least 'len' bytes available in the source buffer and space for 'len'
439 * bytes in the destination buffer.
441 void fcgi_buf_get_to_buf(Buffer
*dest
, Buffer
*src
, int len
)
443 char *dest_end
, *src_begin
;
444 int dest_len
, src_len
, move_len
;
447 ap_assert(BufferLength(src
) >= len
);
448 ap_assert(BufferFree(dest
) >= len
);
451 fcgi_buf_check(dest
);
457 fcgi_buf_get_free_block_info(dest
, &dest_end
, &dest_len
);
458 fcgi_buf_get_block_info(src
, &src_begin
, &src_len
);
460 move_len
= min(dest_len
, src_len
);
461 move_len
= min(move_len
, len
);
466 memcpy(dest_end
, src_begin
, move_len
);
467 fcgi_buf_toss(src
, move_len
);
468 fcgi_buf_add_update(dest
, move_len
);
473 static void array_grow(array_header
*arr
, int n
)
478 if (arr
->nelts
+ n
> arr
->nalloc
) {
480 int new_nalloc
= (arr
->nalloc
<= 0) ? n
: arr
->nelts
+ n
;
482 new_elts
= ap_pcalloc(arr
->pool
, arr
->elt_size
* new_nalloc
);
483 memcpy(new_elts
, arr
->elts
, arr
->nelts
* arr
->elt_size
);
485 arr
->elts
= new_elts
;
486 arr
->nalloc
= new_nalloc
;
490 static void array_cat_block(array_header
*arr
, void *block
, int n
)
493 memcpy(arr
->elts
+ arr
->nelts
* arr
->elt_size
, block
, n
* arr
->elt_size
);
497 /*----------------------------------------------------------------------
498 * Append "len" bytes from "buf" into "arr". Apache arrays are used
499 * whenever the data being handled is binary (may contain null chars).
501 void fcgi_buf_get_to_array(Buffer
*buf
, array_header
*arr
, int len
)
503 int len1
= min(buf
->length
, buf
->data
+ buf
->size
- buf
->begin
);
507 ap_assert(len
<= BufferLength(buf
));
509 array_grow(arr
, len
);
511 len1
= min(len1
, len
);
512 array_cat_block(arr
, buf
->begin
, len1
);
515 array_cat_block(arr
, buf
->data
, len
- len1
);
517 fcgi_buf_toss(buf
, len
);