add .deps, .project, .cdtproject, Debug, Release
[mod_fastcgi.git] / fcgi_buf.c
blob545e67bef5f3bf96dd12c7107fb0654f3c2c6c52
1 /*
2 * $Id: fcgi_buf.c,v 1.18 2003/02/03 23:07:37 robs Exp $
3 */
5 #include "fcgi.h"
7 #ifdef WIN32
8 #pragma warning( disable : 4127 )
9 #else
10 #ifdef APACHE2
11 #include <unistd.h>
12 #endif
13 #endif
15 /*******************************************************************************
16 * Check buffer consistency with assertions.
18 #ifdef DEBUG
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));
33 #else
34 #define fcgi_buf_check(a) ((void) 0)
35 #endif
37 /*******************************************************************************
38 * Reset buffer, losing any data that's in it.
40 void fcgi_buf_reset(Buffer *buf)
42 buf->length = 0;
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)
51 Buffer *buf;
53 buf = (Buffer *)ap_pcalloc(p, sizeof(Buffer) + size);
54 buf->size = size;
55 fcgi_buf_reset(buf);
56 return buf;
59 void fcgi_buf_removed(Buffer * const b, unsigned int len)
61 b->length -= len;
62 b->begin += len;
64 if (b->length == 0)
66 b->begin = b->end = b->data;
68 else if (b->begin >= b->data + b->size)
70 b->begin -= b->size;
74 void fcgi_buf_added(Buffer * const b, const unsigned int len)
76 b->length += len;
77 b->end += len;
79 if (b->end >= b->data + b->size)
81 b->end -= b->size;
85 #ifdef WIN32
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)
93 return -1;
95 return bytes_read;
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)
104 return -1;
106 return bytes_sent;
109 #else /* !WIN32 */
111 static int socket_recv(int fd, char * buf, int len)
113 int bytes_read;
115 do {
116 bytes_read = read(fd, buf, len);
118 if (bytes_read < 0)
120 #ifdef EWOULDBLOCK
121 ASSERT(errno != EWOULDBLOCK);
122 #endif
123 #ifdef EAGAIN
124 ASSERT(errno != EAGAIN);
125 #endif
127 } while (bytes_read == -1 && errno == EINTR);
129 return bytes_read;
132 static int socket_send(int fd, char * buf, int len)
134 int bytes_sent;
136 do {
137 bytes_sent = write(fd, buf, len);
139 if (bytes_sent < 0)
141 #ifdef EWOULDBLOCK
142 ASSERT(errno != EWOULDBLOCK);
143 #endif
144 #ifdef EAGAIN
145 ASSERT(errno != EAGAIN);
146 #endif
149 while (bytes_sent == -1 && errno == EINTR);
151 return bytes_sent;
154 #endif /* !WIN32 */
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.
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)
168 int fcgi_buf_socket_recv(Buffer *buf, SOCKET fd)
170 int len;
172 fcgi_buf_check(buf);
174 if (buf->length == buf->size)
175 /* there's no room in the buffer, return "success" */
176 return 1;
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);
184 #ifndef NO_WRITEV
186 /* assume there is a readv() since there is a writev() */
187 if (len == buf->size - buf->length)
189 #endif
191 len = socket_recv(fd, buf->end, len);
193 #ifndef NO_WRITEV
195 else
197 /* the buffer is wrapped, use readv() */
198 struct iovec vec[2];
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;
205 ASSERT(len);
206 ASSERT(vec[1].iov_len);
210 len = readv(fd, vec, 2);
212 while (len == -1 && errno == EINTR);
214 #endif
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.
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
236 int fcgi_buf_socket_send(Buffer *buf, SOCKET fd)
238 int len;
240 fcgi_buf_check(buf);
242 if (buf->length == 0)
243 return 0;
245 len = min(buf->length, buf->data + buf->size - buf->begin);
247 #ifndef NO_WRITEV
248 if (len == buf->length)
250 #endif
252 len = socket_send(fd, buf->begin, len);
254 #ifndef NO_WRITEV
256 else
258 struct iovec vec[2];
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);
271 #endif
273 if (len <= 0) return len;
275 fcgi_buf_removed(buf, len);
277 return 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)
285 fcgi_buf_check(buf);
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)
296 fcgi_buf_check(buf);
297 ASSERT(count >= 0);
298 ASSERT(count <= buf->length);
300 buf->length -= count;
301 buf->begin += 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)
312 fcgi_buf_check(buf);
314 *endPtr = buf->end;
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)
324 fcgi_buf_check(buf);
325 ASSERT(count >= 0);
326 ASSERT(count <= BufferFree(buf));
328 buf->length += count;
329 buf->end += count;
330 if(buf->end >= buf->data + buf->size) {
331 buf->end -= buf->size;
334 fcgi_buf_check(buf);
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)
342 char *end;
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);
349 if(datalen == 0) {
350 return 0;
353 ASSERT(datalen > 0);
354 fcgi_buf_check(buf);
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;
365 buf->end += canCopy;
366 copied += canCopy;
367 if (buf->end >= end) {
368 buf->end = buf->data;
370 datalen -= canCopy;
373 * If there's more to go, copy the second part starting from the
374 * beginning of the buffer.
376 if (datalen > 0) {
377 data += canCopy;
378 memcpy(buf->end, data, datalen);
379 buf->length += datalen;
380 buf->end += datalen;
381 copied += datalen;
383 return(copied);
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)
399 char *end;
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);
404 ASSERT(datalen > 0);
405 fcgi_buf_check(buf);
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;
420 copied += 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) {
430 data += copied;
431 canCopy = min(buf->length, datalen - copied);
433 memcpy(data, buf->begin, canCopy);
435 buf->length -= canCopy;
436 buf->begin += canCopy;
437 copied += canCopy;
440 fcgi_buf_check(buf);
441 return(copied);
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;
454 ASSERT(len > 0);
455 ASSERT(BufferLength(src) >= len);
456 ASSERT(BufferFree(dest) >= len);
458 fcgi_buf_check(src);
459 fcgi_buf_check(dest);
461 for (;;) {
462 if (len == 0)
463 return;
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);
471 if (move_len == 0)
472 return;
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;
481 static void array_grow(array_header *arr, int n)
483 if (n <= 0)
484 return;
486 if (arr->nelts + n > arr->nalloc) {
487 char *new_elts;
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)
500 array_grow(arr, n);
501 memcpy(arr->elts + arr->nelts * arr->elt_size, block, n * arr->elt_size);
502 arr->nelts += n;
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);
513 fcgi_buf_check(buf);
514 ASSERT(len > 0);
515 ASSERT(len <= BufferLength(buf));
517 array_grow(arr, len);
519 len1 = min(len1, len);
520 array_cat_block(arr, buf->begin, len1);
522 if (len1 < len)
523 array_cat_block(arr, buf->data, len - len1);
525 fcgi_buf_toss(buf, len);