2 * $Id: fcgi_buf.c,v 1.16 2002/10/22 01:02:18 robs Exp $
8 #pragma warning( disable : 4127 )
15 /*******************************************************************************
16 * Check buffer consistency with assertions.
18 void fcgi_buf_check(Buffer
*buf
)
20 ap_assert(buf
->size
> 0);
21 ap_assert(buf
->length
>= 0);
22 ap_assert(buf
->length
<= buf
->size
);
24 ap_assert(buf
->begin
>= buf
->data
);
25 ap_assert(buf
->begin
< buf
->data
+ buf
->size
);
26 ap_assert(buf
->end
>= buf
->data
);
27 ap_assert(buf
->end
< buf
->data
+ buf
->size
);
29 ap_assert(((buf
->end
- buf
->begin
+ buf
->size
) % buf
->size
)
30 == (buf
->length
% buf
->size
));
33 /*******************************************************************************
34 * Reset buffer, losing any data that's in it.
36 void fcgi_buf_reset(Buffer
*buf
)
39 buf
->begin
= buf
->end
= buf
->data
;
42 /*******************************************************************************
43 * Allocate and intialize a new buffer of the specified size.
45 Buffer
*fcgi_buf_new(pool
*p
, int size
)
49 buf
= (Buffer
*)ap_pcalloc(p
, sizeof(Buffer
) + size
);
55 void fcgi_buf_removed(Buffer
* const b
, unsigned int len
)
62 b
->begin
= b
->end
= b
->data
;
64 else if (b
->begin
>= b
->data
+ b
->size
)
70 void fcgi_buf_added(Buffer
* const b
, const unsigned int len
)
75 if (b
->end
>= b
->data
+ b
->size
)
83 static int socket_recv(SOCKET fd
, char *buf
, int len
)
85 int bytes_read
= recv(fd
, buf
, len
, 0);
87 if (bytes_read
== SOCKET_ERROR
)
94 static int socket_send(SOCKET fd
, char * buf
, int len
)
96 int bytes_sent
= send(fd
, buf
, len
, 0);
98 if (bytes_sent
== SOCKET_ERROR
)
107 static int socket_recv(int fd
, char * buf
, int len
)
112 bytes_read
= read(fd
, buf
, len
);
117 ap_assert(errno
!= EWOULDBLOCK
);
120 ap_assert(errno
!= EAGAIN
);
123 } while (bytes_read
== -1 && errno
== EINTR
);
128 static int socket_send(int fd
, char * buf
, int len
)
133 bytes_sent
= write(fd
, buf
, len
);
138 ap_assert(errno
!= EWOULDBLOCK
);
141 ap_assert(errno
!= EAGAIN
);
145 while (bytes_sent
== -1 && errno
== EINTR
);
152 /*******************************************************************************
153 * Read from an open file descriptor into buffer.
155 * The caller should disable the default Apache SIGPIPE handler,
156 * otherwise a bad script could cause the request to abort and appear
157 * as though the client's fd caused it.
160 * <0 error, errno is set
162 * >0 successful read or no room in buffer (NOT # of bytes read)
164 int fcgi_buf_socket_recv(Buffer
*buf
, SOCKET fd
)
170 if (buf
->length
== buf
->size
)
171 /* there's no room in the buffer, return "success" */
174 if (buf
->length
== 0)
175 /* the buffer is empty so defrag */
176 buf
->begin
= buf
->end
= buf
->data
;
178 len
= min(buf
->size
- buf
->length
, buf
->data
+ buf
->size
- buf
->end
);
182 /* assume there is a readv() since there is a writev() */
183 if (len
== buf
->size
- buf
->length
)
187 len
= socket_recv(fd
, buf
->end
, len
);
193 /* the buffer is wrapped, use readv() */
196 vec
[0].iov_base
= buf
->end
;
197 vec
[0].iov_len
= len
;
198 vec
[1].iov_base
= buf
->data
;
199 vec
[1].iov_len
= buf
->size
- buf
->length
- len
;
202 ap_assert(vec
[1].iov_len
);
206 len
= readv(fd
, vec
, 2);
208 while (len
== -1 && errno
== EINTR
);
212 if (len
<= 0) return len
;
214 fcgi_buf_added(buf
, len
);
216 return len
; /* this may not contain the number of bytes read */
220 /*******************************************************************************
221 * Write from the buffer to an open file descriptor.
223 * The caller should disable the default Apache SIGPIPE handler,
224 * otherwise a bad script could cause the request to abort appearing
225 * as though the client's fd caused it.
228 * <0 if an error occured (bytes may or may not have been written)
229 * =0 if no bytes were written
230 * >0 successful write
232 int fcgi_buf_socket_send(Buffer
*buf
, SOCKET fd
)
238 if (buf
->length
== 0)
241 len
= min(buf
->length
, buf
->data
+ buf
->size
- buf
->begin
);
244 if (len
== buf
->length
)
248 len
= socket_send(fd
, buf
->begin
, len
);
256 vec
[0].iov_base
= buf
->begin
;
257 vec
[0].iov_len
= len
;
258 vec
[1].iov_base
= buf
->data
;
259 vec
[1].iov_len
= buf
->length
- len
;
263 len
= writev(fd
, vec
, 2);
265 while (len
== -1 && errno
== EINTR
);
269 if (len
<= 0) return len
;
271 fcgi_buf_removed(buf
, len
);
276 /*******************************************************************************
277 * Return the data block start address and the length of the block.
279 void fcgi_buf_get_block_info(Buffer
*buf
, char **beginPtr
, int *countPtr
)
283 *beginPtr
= buf
->begin
;
284 *countPtr
= min(buf
->length
, buf
->data
+ buf
->size
- buf
->begin
);
287 /*******************************************************************************
288 * Throw away bytes from buffer.
290 void fcgi_buf_toss(Buffer
*buf
, int count
)
293 ap_assert(count
>= 0);
294 ap_assert(count
<= buf
->length
);
296 buf
->length
-= count
;
298 if(buf
->begin
>= buf
->data
+ buf
->size
) {
299 buf
->begin
-= buf
->size
;
303 /*******************************************************************************
304 * Return the free data block start address and the length of the block.
306 void fcgi_buf_get_free_block_info(Buffer
*buf
, char **endPtr
, int *countPtr
)
311 *countPtr
= min(buf
->size
- buf
->length
,
312 buf
->data
+ buf
->size
- buf
->end
);
315 /*******************************************************************************
316 * Updates the buf to reflect recently added data.
318 void fcgi_buf_add_update(Buffer
*buf
, int count
)
321 ap_assert(count
>= 0);
322 ap_assert(count
<= BufferFree(buf
));
324 buf
->length
+= count
;
326 if(buf
->end
>= buf
->data
+ buf
->size
) {
327 buf
->end
-= buf
->size
;
333 /*******************************************************************************
334 * Adds a block of data to a buffer, returning the number of bytes added.
336 int fcgi_buf_add_block(Buffer
*buf
, char *data
, int datalen
)
339 int copied
= 0; /* Number of bytes actually copied. */
340 int canCopy
; /* Number of bytes to copy in a given op. */
342 ap_assert(data
!= NULL
);
343 ap_assert(datalen
>= 0);
349 ap_assert(datalen
> 0);
351 end
= buf
->data
+ buf
->size
;
354 * Copy the first part of the data: from here to the end of the
355 * buffer, or the end of the data, whichever comes first.
357 datalen
= min(BufferFree(buf
), datalen
);
358 canCopy
= min(datalen
, end
- buf
->end
);
359 memcpy(buf
->end
, data
, canCopy
);
360 buf
->length
+= canCopy
;
363 if (buf
->end
>= end
) {
364 buf
->end
= buf
->data
;
369 * If there's more to go, copy the second part starting from the
370 * beginning of the buffer.
374 memcpy(buf
->end
, data
, datalen
);
375 buf
->length
+= datalen
;
382 /*******************************************************************************
383 * Add a string to a buffer, returning the number of bytes added.
385 int fcgi_buf_add_string(Buffer
*buf
, char *str
)
387 return fcgi_buf_add_block(buf
, str
, strlen(str
));
390 /*******************************************************************************
391 * Gets a data block from a buffer, returning the number of bytes copied.
393 int fcgi_buf_get_to_block(Buffer
*buf
, char *data
, int datalen
)
396 int copied
= 0; /* Number of bytes actually copied. */
397 int canCopy
; /* Number of bytes to copy in a given op. */
399 ap_assert(data
!= NULL
);
400 ap_assert(datalen
> 0);
403 end
= buf
->data
+ buf
->size
;
406 * Copy the first part out of the buffer: from here to the end
407 * of the buffer, or all of the requested data.
409 canCopy
= min(buf
->length
, datalen
);
410 canCopy
= min(canCopy
, end
- buf
->begin
);
412 memcpy(data
, buf
->begin
, canCopy
);
414 buf
->length
-= canCopy
;
415 buf
->begin
+= canCopy
;
417 if (buf
->begin
>= end
) {
418 buf
->begin
= buf
->data
;
422 * If there's more to go, copy the second part starting from the
423 * beginning of the buffer.
425 if (copied
< datalen
&& buf
->length
> 0) {
427 canCopy
= min(buf
->length
, datalen
- copied
);
429 memcpy(data
, buf
->begin
, canCopy
);
431 buf
->length
-= canCopy
;
432 buf
->begin
+= canCopy
;
440 /*******************************************************************************
441 * Move 'len' bytes from 'src' buffer to 'dest' buffer. There must be at
442 * least 'len' bytes available in the source buffer and space for 'len'
443 * bytes in the destination buffer.
445 void fcgi_buf_get_to_buf(Buffer
*dest
, Buffer
*src
, int len
)
447 char *dest_end
, *src_begin
;
448 int dest_len
, src_len
, move_len
;
451 ap_assert(BufferLength(src
) >= len
);
452 ap_assert(BufferFree(dest
) >= len
);
455 fcgi_buf_check(dest
);
461 fcgi_buf_get_free_block_info(dest
, &dest_end
, &dest_len
);
462 fcgi_buf_get_block_info(src
, &src_begin
, &src_len
);
464 move_len
= min(dest_len
, src_len
);
465 move_len
= min(move_len
, len
);
470 memcpy(dest_end
, src_begin
, move_len
);
471 fcgi_buf_toss(src
, move_len
);
472 fcgi_buf_add_update(dest
, move_len
);
477 static void array_grow(array_header
*arr
, int n
)
482 if (arr
->nelts
+ n
> arr
->nalloc
) {
484 int new_nalloc
= (arr
->nalloc
<= 0) ? n
: arr
->nelts
+ n
;
486 new_elts
= ap_pcalloc(arr
->pool
, arr
->elt_size
* new_nalloc
);
487 memcpy(new_elts
, arr
->elts
, arr
->nelts
* arr
->elt_size
);
489 arr
->elts
= new_elts
;
490 arr
->nalloc
= new_nalloc
;
494 static void array_cat_block(array_header
*arr
, void *block
, int n
)
497 memcpy(arr
->elts
+ arr
->nelts
* arr
->elt_size
, block
, n
* arr
->elt_size
);
501 /*----------------------------------------------------------------------
502 * Append "len" bytes from "buf" into "arr". Apache arrays are used
503 * whenever the data being handled is binary (may contain null chars).
505 void fcgi_buf_get_to_array(Buffer
*buf
, array_header
*arr
, int len
)
507 int len1
= min(buf
->length
, buf
->data
+ buf
->size
- buf
->begin
);
511 ap_assert(len
<= BufferLength(buf
));
513 array_grow(arr
, len
);
515 len1
= min(len1
, len
);
516 array_cat_block(arr
, buf
->begin
, len1
);
519 array_cat_block(arr
, buf
->data
, len
- len1
);
521 fcgi_buf_toss(buf
, len
);