2 * $Id: fcgi_buf.c,v 1.18 2003/02/03 23:07:37 robs Exp $
8 #pragma warning( disable : 4127 )
15 /*******************************************************************************
16 * Check buffer consistency with assertions.
19 static void fcgi_buf_check(Buffer
*buf
)
21 ASSERT(buf
->size
> 0);
22 ASSERT(buf
->length
>= 0);
23 ASSERT(buf
->length
<= buf
->size
);
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
);
30 ASSERT(((buf
->end
- buf
->begin
+ buf
->size
) % buf
->size
)
31 == (buf
->length
% buf
->size
));
34 #define fcgi_buf_check(a) ((void) 0)
37 /*******************************************************************************
38 * Reset buffer, losing any data that's in it.
40 void fcgi_buf_reset(Buffer
*buf
)
43 buf
->begin
= buf
->end
= buf
->data
;
46 /*******************************************************************************
47 * Allocate and intialize a new buffer of the specified size.
49 Buffer
*fcgi_buf_new(pool
*p
, int size
)
53 buf
= (Buffer
*)ap_pcalloc(p
, sizeof(Buffer
) + size
);
59 void fcgi_buf_removed(Buffer
* const b
, unsigned int len
)
66 b
->begin
= b
->end
= b
->data
;
68 else if (b
->begin
>= b
->data
+ b
->size
)
74 void fcgi_buf_added(Buffer
* const b
, const unsigned int len
)
79 if (b
->end
>= b
->data
+ b
->size
)
87 static int socket_recv(SOCKET fd
, char *buf
, int len
)
89 int bytes_read
= recv(fd
, buf
, len
, 0);
91 if (bytes_read
== SOCKET_ERROR
)
98 static int socket_send(SOCKET fd
, char * buf
, int len
)
100 int bytes_sent
= send(fd
, buf
, len
, 0);
102 if (bytes_sent
== SOCKET_ERROR
)
111 static int socket_recv(int fd
, char * buf
, int len
)
116 bytes_read
= read(fd
, buf
, len
);
121 ASSERT(errno
!= EWOULDBLOCK
);
124 ASSERT(errno
!= EAGAIN
);
127 } while (bytes_read
== -1 && errno
== EINTR
);
132 static int socket_send(int fd
, char * buf
, int len
)
137 bytes_sent
= write(fd
, buf
, len
);
142 ASSERT(errno
!= EWOULDBLOCK
);
145 ASSERT(errno
!= EAGAIN
);
149 while (bytes_sent
== -1 && errno
== EINTR
);
156 /*******************************************************************************
157 * Read from an open file descriptor into buffer.
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.
164 * <0 error, errno is set
166 * >0 successful read or no room in buffer (NOT # of bytes read)
168 int fcgi_buf_socket_recv(Buffer
*buf
, SOCKET fd
)
174 if (buf
->length
== buf
->size
)
175 /* there's no room in the buffer, return "success" */
178 if (buf
->length
== 0)
179 /* the buffer is empty so defrag */
180 buf
->begin
= buf
->end
= buf
->data
;
182 len
= min(buf
->size
- buf
->length
, buf
->data
+ buf
->size
- buf
->end
);
186 /* assume there is a readv() since there is a writev() */
187 if (len
== buf
->size
- buf
->length
)
191 len
= socket_recv(fd
, buf
->end
, len
);
197 /* the buffer is wrapped, use readv() */
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
;
206 ASSERT(vec
[1].iov_len
);
210 len
= readv(fd
, vec
, 2);
212 while (len
== -1 && errno
== EINTR
);
216 if (len
<= 0) return len
;
218 fcgi_buf_added(buf
, len
);
220 return len
; /* this may not contain the number of bytes read */
224 /*******************************************************************************
225 * Write from the buffer to an open file descriptor.
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.
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
236 int fcgi_buf_socket_send(Buffer
*buf
, SOCKET fd
)
242 if (buf
->length
== 0)
245 len
= min(buf
->length
, buf
->data
+ buf
->size
- buf
->begin
);
248 if (len
== buf
->length
)
252 len
= socket_send(fd
, buf
->begin
, len
);
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
;
267 len
= writev(fd
, vec
, 2);
269 while (len
== -1 && errno
== EINTR
);
273 if (len
<= 0) return len
;
275 fcgi_buf_removed(buf
, len
);
280 /*******************************************************************************
281 * Return the data block start address and the length of the block.
283 void fcgi_buf_get_block_info(Buffer
*buf
, char **beginPtr
, int *countPtr
)
287 *beginPtr
= buf
->begin
;
288 *countPtr
= min(buf
->length
, buf
->data
+ buf
->size
- buf
->begin
);
291 /*******************************************************************************
292 * Throw away bytes from buffer.
294 void fcgi_buf_toss(Buffer
*buf
, int count
)
298 ASSERT(count
<= buf
->length
);
300 buf
->length
-= count
;
302 if(buf
->begin
>= buf
->data
+ buf
->size
) {
303 buf
->begin
-= buf
->size
;
307 /*******************************************************************************
308 * Return the free data block start address and the length of the block.
310 void fcgi_buf_get_free_block_info(Buffer
*buf
, char **endPtr
, int *countPtr
)
315 *countPtr
= min(buf
->size
- buf
->length
,
316 buf
->data
+ buf
->size
- buf
->end
);
319 /*******************************************************************************
320 * Updates the buf to reflect recently added data.
322 void fcgi_buf_add_update(Buffer
*buf
, int count
)
326 ASSERT(count
<= BufferFree(buf
));
328 buf
->length
+= count
;
330 if(buf
->end
>= buf
->data
+ buf
->size
) {
331 buf
->end
-= buf
->size
;
337 /*******************************************************************************
338 * Adds a block of data to a buffer, returning the number of bytes added.
340 int fcgi_buf_add_block(Buffer
*buf
, char *data
, int datalen
)
343 int copied
= 0; /* Number of bytes actually copied. */
344 int canCopy
; /* Number of bytes to copy in a given op. */
346 ASSERT(data
!= NULL
);
347 ASSERT(datalen
>= 0);
355 end
= buf
->data
+ buf
->size
;
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.
361 datalen
= min(BufferFree(buf
), datalen
);
362 canCopy
= min(datalen
, end
- buf
->end
);
363 memcpy(buf
->end
, data
, canCopy
);
364 buf
->length
+= canCopy
;
367 if (buf
->end
>= end
) {
368 buf
->end
= buf
->data
;
373 * If there's more to go, copy the second part starting from the
374 * beginning of the buffer.
378 memcpy(buf
->end
, data
, datalen
);
379 buf
->length
+= datalen
;
386 /*******************************************************************************
387 * Add a string to a buffer, returning the number of bytes added.
389 int fcgi_buf_add_string(Buffer
*buf
, char *str
)
391 return fcgi_buf_add_block(buf
, str
, strlen(str
));
394 /*******************************************************************************
395 * Gets a data block from a buffer, returning the number of bytes copied.
397 int fcgi_buf_get_to_block(Buffer
*buf
, char *data
, int datalen
)
400 int copied
= 0; /* Number of bytes actually copied. */
401 int canCopy
; /* Number of bytes to copy in a given op. */
403 ASSERT(data
!= NULL
);
407 end
= buf
->data
+ buf
->size
;
410 * Copy the first part out of the buffer: from here to the end
411 * of the buffer, or all of the requested data.
413 canCopy
= min(buf
->length
, datalen
);
414 canCopy
= min(canCopy
, end
- buf
->begin
);
416 memcpy(data
, buf
->begin
, canCopy
);
418 buf
->length
-= canCopy
;
419 buf
->begin
+= canCopy
;
421 if (buf
->begin
>= end
) {
422 buf
->begin
= buf
->data
;
426 * If there's more to go, copy the second part starting from the
427 * beginning of the buffer.
429 if (copied
< datalen
&& buf
->length
> 0) {
431 canCopy
= min(buf
->length
, datalen
- copied
);
433 memcpy(data
, buf
->begin
, canCopy
);
435 buf
->length
-= canCopy
;
436 buf
->begin
+= canCopy
;
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.
449 void fcgi_buf_get_to_buf(Buffer
*dest
, Buffer
*src
, int len
)
451 char *dest_end
, *src_begin
;
452 int dest_len
, src_len
, move_len
;
455 ASSERT(BufferLength(src
) >= len
);
456 ASSERT(BufferFree(dest
) >= len
);
459 fcgi_buf_check(dest
);
465 fcgi_buf_get_free_block_info(dest
, &dest_end
, &dest_len
);
466 fcgi_buf_get_block_info(src
, &src_begin
, &src_len
);
468 move_len
= min(dest_len
, src_len
);
469 move_len
= min(move_len
, len
);
474 memcpy(dest_end
, src_begin
, move_len
);
475 fcgi_buf_toss(src
, move_len
);
476 fcgi_buf_add_update(dest
, move_len
);
481 static void array_grow(array_header
*arr
, int n
)
486 if (arr
->nelts
+ n
> arr
->nalloc
) {
488 int new_nalloc
= (arr
->nalloc
<= 0) ? n
: arr
->nelts
+ n
;
490 new_elts
= ap_pcalloc(arr
->pool
, arr
->elt_size
* new_nalloc
);
491 memcpy(new_elts
, arr
->elts
, arr
->nelts
* arr
->elt_size
);
493 arr
->elts
= new_elts
;
494 arr
->nalloc
= new_nalloc
;
498 static void array_cat_block(array_header
*arr
, void *block
, int n
)
501 memcpy(arr
->elts
+ arr
->nelts
* arr
->elt_size
, block
, n
* arr
->elt_size
);
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).
509 void fcgi_buf_get_to_array(Buffer
*buf
, array_header
*arr
, int len
)
511 int len1
= min(buf
->length
, buf
->data
+ buf
->size
- buf
->begin
);
515 ASSERT(len
<= BufferLength(buf
));
517 array_grow(arr
, len
);
519 len1
= min(len1
, len
);
520 array_cat_block(arr
, buf
->begin
, len1
);
523 array_cat_block(arr
, buf
->data
, len
- len1
);
525 fcgi_buf_toss(buf
, len
);