Fix the loadFactor calculation used to determine when dyanmic applications could...
[mod_fastcgi.git] / fcgi_buf.c
blob971580e491b77e29ca0e487bd6bfcb78664e61c5
1 /*
2 * $Id: fcgi_buf.c,v 1.9 2001/02/19 03:18:56 robs Exp $
3 */
5 #include "fcgi.h"
7 /*******************************************************************************
8 * Check buffer consistency with assertions.
9 */
10 void fcgi_buf_check(Buffer *buf)
12 ap_assert(buf->size > 0);
13 ap_assert(buf->length >= 0);
14 ap_assert(buf->length <= buf->size);
16 ap_assert(buf->begin >= buf->data);
17 ap_assert(buf->begin < buf->data + buf->size);
18 ap_assert(buf->end >= buf->data);
19 ap_assert(buf->end < buf->data + buf->size);
21 ap_assert(((buf->end - buf->begin + buf->size) % buf->size)
22 == (buf->length % buf->size));
25 /*******************************************************************************
26 * Reset buffer, losing any data that's in it.
28 void fcgi_buf_reset(Buffer *buf)
30 buf->length = 0;
31 buf->begin = buf->end = buf->data;
34 /*******************************************************************************
35 * Allocate and intialize a new buffer of the specified size.
37 Buffer *fcgi_buf_new(pool *p, int size)
39 Buffer *buf;
41 buf = (Buffer *)ap_pcalloc(p, sizeof(Buffer) + size);
42 buf->size = size;
43 fcgi_buf_reset(buf);
44 return buf;
47 #ifdef WIN32
49 static int fd_read(SOCKET fd, char *buf, int len)
51 long bytes_read;
53 // HACK - we don't know if its a pipe or socket..
54 if (!ReadFile((HANDLE) fd, buf, len, (unsigned long *) &bytes_read, NULL)) {
56 int rv = GetLastError();
58 if (rv == ERROR_PIPE_NOT_CONNECTED) {
59 bytes_read = 0;
61 else if (rv == ERROR_INVALID_PARAMETER) {
62 bytes_read = recv(fd, buf, len, 0);
63 if (bytes_read == SOCKET_ERROR) {
64 errno = WSAGetLastError();
65 bytes_read = -1;
68 else {
69 errno = rv;
70 bytes_read = -1;
73 return bytes_read;
76 #else
78 static int fd_read(int fd, char * buf, int len)
80 int bytes_read;
81 do {
82 bytes_read = read(fd, buf, len);
83 } while (bytes_read == -1 && errno == EINTR);
84 return bytes_read;
87 #endif
89 /*******************************************************************************
90 * Read from an open file descriptor into buffer.
92 * The caller should disable the default Apache SIGPIPE handler,
93 * otherwise a bad script could cause the request to abort and appear
94 * as though the client's fd caused it.
96 * Results:
97 * <0 error, errno is set
98 * =0 EOF reached
99 * >0 successful read or no room in buffer (NOT # of bytes read)
101 #ifdef WIN32
102 int fcgi_buf_add_fd(Buffer *buf, SOCKET fd)
103 #else
104 int fcgi_buf_add_fd(Buffer *buf, int fd)
105 #endif
107 #ifdef WIN32
108 DWORD len;
109 #else
110 size_t len;
111 #endif
113 fcgi_buf_check(buf);
115 if (buf->length == buf->size)
116 /* there's no room in the buffer, return "success" */
117 return 1;
119 if (buf->length == 0)
120 /* the buffer is empty so defrag */
121 buf->begin = buf->end = buf->data;
123 len = min(buf->size - buf->length, buf->data + buf->size - buf->end);
125 #ifndef NO_WRITEV
126 /* assume there is a readv() if there is a writev() */
127 if (len == buf->size - buf->length) {
128 /* its not wrapped, use read() instead of readv() */
129 #endif
131 len = fd_read(fd, buf->end, len);
133 if (len <= 0)
134 return len;
136 buf->end += len;
137 buf->length += len;
139 if (buf->end == (buf->data + buf->size)) {
140 /* the buffer needs to be wrapped */
141 buf->end = buf->data;
142 #ifndef NO_WRITEV
144 } else {
145 /* the buffer is wrapped, use readv() */
146 struct iovec vec[2];
148 vec[0].iov_base = buf->end;
149 vec[0].iov_len = len;
150 vec[1].iov_base = buf->data;
151 vec[1].iov_len = buf->size - buf->length - len;
154 len = readv(fd, vec, 2);
155 while (len == -1 && errno == EINTR);
157 if (len <= 0)
158 return len;
160 buf->end += len;
161 if (buf->end >= (buf->data + buf->size))
162 buf->end -= buf->size;
164 buf->length += len;
167 #else
168 if (buf->length < buf->size) {
169 /* There's still more buffer space to read into. */
171 fd_set read_set;
172 int status;
173 int numFDs = fd + 1;
174 struct timeval timeOut;
176 FD_ZERO(&read_set);
177 FD_SET(fd, &read_set);
179 timeOut.tv_sec = 0;
180 timeOut.tv_usec = 0;
182 status = ap_select(numFDs, &read_set, NULL, NULL, &timeOut);
184 if (status < 0) {
185 #ifdef WIN32
186 // More hackery
187 if (WSAGetLastError() == WSAENOTSOCK)
189 DWORD bytesavail=0;
190 if (PeekNamedPipe((HANDLE) fd, NULL, 0, NULL, &bytesavail, NULL))
192 if (bytesavail > 0)
194 len = fd_read(fd, buf->end, buf->size - buf->length);
196 if (len <= 0)
197 return len;
199 buf->end += len;
200 buf->length += len;
202 return len;
205 #endif
206 return status; /* error, errno is set */
209 if (status > 0 && FD_ISSET(fd, &read_set)) {
211 len = fd_read(fd, buf->end, buf->size - buf->length);
213 if (len <= 0)
214 return len;
216 buf->end += len;
217 buf->length += len;
221 #endif
223 return len; /* this may not contain the number of bytes read */
226 #ifdef WIN32
228 static int fd_write(SOCKET fd, char * buf, int len)
230 long bytes_sent;
232 // HACK - We don't know if its a pipe or socket..
233 if (!WriteFile((HANDLE) fd, (LPVOID) buf, len, (unsigned long *) &bytes_sent, NULL)) {
235 int rv = GetLastError();
237 if (rv == ERROR_INVALID_PARAMETER) {
239 // Then it must be a real socket..
240 bytes_sent = send(fd, buf, len, 0);
241 if (bytes_sent == SOCKET_ERROR) {
242 rv = WSAGetLastError();
243 if (rv == WSAEWOULDBLOCK) {
244 bytes_sent = 0;
246 else {
247 bytes_sent = -1;
248 errno = rv;
252 else if (rv == WSAEWOULDBLOCK) {
253 bytes_sent = 0;
255 else {
256 bytes_sent = -1;
257 errno = rv;
261 return bytes_sent;
264 #else
266 static int fd_write(int fd, char * buf, int len)
268 int bytes_sent;
270 do {
271 bytes_sent = write(fd, buf, len);
273 #ifdef EWOULDBLOCK
274 if (bytes_sent == -1 && errno == EWOULDBLOCK) {
275 bytes_sent = 0;
277 #endif
278 } while (bytes_sent == -1 && errno == EINTR);
280 return bytes_sent;
283 #endif
285 /*******************************************************************************
286 * Write from the buffer to an open file descriptor.
288 * The caller should disable the default Apache SIGPIPE handler,
289 * otherwise a bad script could cause the request to abort appearing
290 * as though the client's fd caused it.
292 * Results:
293 * <0 if an error occured (bytes may or may not have been written)
294 * =0 if no bytes were written
295 * >0 successful write
297 #ifdef WIN32
298 int fcgi_buf_get_to_fd(Buffer *buf, SOCKET fd)
300 DWORD len;
301 #else
302 int fcgi_buf_get_to_fd(Buffer *buf, int fd)
304 size_t len;
305 #endif
307 fcgi_buf_check(buf);
309 if (buf->length == 0)
310 return 0;
312 len = min(buf->length, buf->data + buf->size - buf->begin);
314 #ifndef NO_WRITEV
315 if (len == buf->length) {
316 /* the buffer is not wrapped, we don't need to use writev() */
317 #endif
319 len = fd_write(fd, buf->begin, len);
321 if (len <= 0)
322 goto Return;
324 buf->begin += len;
325 buf->length -= len;
327 if (buf->begin == buf->data + buf->size) {
328 /* the buffer needs to be wrapped */
329 buf->begin = buf->data;
331 #ifndef NO_WRITEV
333 } else {
334 /* the buffer is wrapped, use writev() */
335 struct iovec vec[2];
337 vec[0].iov_base = buf->begin;
338 vec[0].iov_len = len;
339 vec[1].iov_base = buf->data;
340 vec[1].iov_len = buf->length - len;
343 len = writev(fd, vec, 2);
344 while (len == -1 && errno == EINTR);
346 if (len <= 0)
347 goto Return;
349 buf->begin += len;
350 buf->length -= len;
352 if (buf->begin >= buf->data + buf->size)
353 buf->begin -= buf->size;
355 #else
356 if (buf->length > 0) {
357 /* there's still more data to write */
359 fd_set write_set;
360 int status;
361 int numFDs = fd + 1;
362 struct timeval timeOut;
364 FD_ZERO(&write_set);
365 FD_SET(fd, &write_set);
367 timeOut.tv_sec = 0;
368 timeOut.tv_usec = 0;
370 status = ap_select(numFDs, NULL, &write_set, NULL, &timeOut);
372 if (status < 0) {
373 len = status; /* error, errno is set */
374 goto Return;
377 if (status > 0 && FD_ISSET(fd, &write_set)) {
378 int len2;
380 len2 = fd_write(fd, buf->begin, buf->length);
382 if (len2 < 0) {
383 len = len2;
384 goto Return;
387 if (len2 > 0) {
388 buf->begin += len2;
389 buf->length -= len2;
390 len += len2;
395 #endif
397 Return:
398 if (buf->length == 0)
399 buf->begin = buf->end = buf->data;
401 return len;
404 /*******************************************************************************
405 * Return the data block start address and the length of the block.
407 void fcgi_buf_get_block_info(Buffer *buf, char **beginPtr, size_t *countPtr)
409 fcgi_buf_check(buf);
410 *beginPtr = buf->begin;
411 *countPtr = min(buf->length,
412 buf->data + buf->size - buf->begin);
415 /*******************************************************************************
416 * Throw away bytes from buffer.
418 void fcgi_buf_toss(Buffer *buf, size_t count)
420 fcgi_buf_check(buf);
421 ap_assert(count >= 0 && (int) count <= buf->length);
423 buf->length -= count;
424 buf->begin += count;
425 if(buf->begin >= buf->data + buf->size) {
426 buf->begin -= buf->size;
430 /*******************************************************************************
431 * Return the free data block start address and the length of the block.
433 void fcgi_buf_get_free_block_info(Buffer *buf, char **endPtr, size_t *countPtr)
435 fcgi_buf_check(buf);
436 *endPtr = buf->end;
437 *countPtr = min(buf->size - buf->length,
438 buf->data + buf->size - buf->end);
441 /*******************************************************************************
442 * Updates the buf to reflect recently added data.
444 void fcgi_buf_add_update(Buffer *buf, size_t count)
446 fcgi_buf_check(buf);
447 ap_assert(count >= 0 && (int) count <= BufferFree(buf));
449 buf->length += count;
450 buf->end += count;
451 if(buf->end >= buf->data + buf->size) {
452 buf->end -= buf->size;
455 fcgi_buf_check(buf);
458 /*******************************************************************************
459 * Adds a block of data to a buffer, returning the number of bytes added.
461 int fcgi_buf_add_block(Buffer *buf, char *data, size_t datalen)
463 char *end;
464 int copied = 0; /* Number of bytes actually copied. */
465 size_t canCopy; /* Number of bytes to copy in a given op. */
467 ap_assert(data != NULL);
468 if(datalen == 0) {
469 return 0;
472 ap_assert(datalen > 0);
473 fcgi_buf_check(buf);
474 end = buf->data + buf->size;
477 * Copy the first part of the data: from here to the end of the
478 * buffer, or the end of the data, whichever comes first.
480 datalen = min(BufferFree(buf), (int) datalen);
481 canCopy = min((int) datalen, end - buf->end);
482 memcpy(buf->end, data, canCopy);
483 buf->length += canCopy;
484 buf->end += canCopy;
485 copied += canCopy;
486 if (buf->end >= end) {
487 buf->end = buf->data;
489 datalen -= canCopy;
492 * If there's more to go, copy the second part starting from the
493 * beginning of the buffer.
495 if (datalen > 0) {
496 data += canCopy;
497 memcpy(buf->end, data, datalen);
498 buf->length += datalen;
499 buf->end += datalen;
500 copied += datalen;
502 return(copied);
505 /*******************************************************************************
506 * Add a string to a buffer, returning the number of bytes added.
508 int fcgi_buf_add_string(Buffer *buf, char *str)
510 return fcgi_buf_add_block(buf, str, strlen(str));
513 /*******************************************************************************
514 * Gets a data block from a buffer, returning the number of bytes copied.
516 int fcgi_buf_get_to_block(Buffer *buf, char *data, int datalen)
518 char *end;
519 int copied = 0; /* Number of bytes actually copied. */
520 size_t canCopy; /* Number of bytes to copy in a given op. */
522 ap_assert(data != NULL);
523 ap_assert(datalen > 0);
524 fcgi_buf_check(buf);
525 end = buf->data + buf->size;
528 * Copy the first part out of the buffer: from here to the end
529 * of the buffer, or all of the requested data.
531 canCopy = min(buf->length, datalen);
532 canCopy = min((int) canCopy, end - buf->begin);
533 memcpy(data, buf->begin, canCopy);
534 buf->length -= canCopy;
535 buf->begin += canCopy;
536 copied += canCopy;
537 if (buf->begin >= end) {
538 buf->begin = buf->data;
542 * If there's more to go, copy the second part starting from the
543 * beginning of the buffer.
545 if (copied < datalen && buf->length > 0) {
546 data += copied;
547 canCopy = min(buf->length, datalen - copied);
548 memcpy(data, buf->begin, canCopy);
549 buf->length -= canCopy;
550 buf->begin += canCopy;
551 copied += canCopy;
553 fcgi_buf_check(buf);
554 return(copied);
557 /*******************************************************************************
558 * Move 'len' bytes from 'src' buffer to 'dest' buffer. There must be at
559 * least 'len' bytes available in the source buffer and space for 'len'
560 * bytes in the destination buffer.
562 void fcgi_buf_get_to_buf(Buffer *dest, Buffer *src, int len)
564 char *dest_end, *src_begin;
565 size_t dest_len, src_len, move_len;
567 ap_assert(len > 0);
568 ap_assert(BufferLength(src) >= len);
569 ap_assert(BufferFree(dest) >= len);
571 fcgi_buf_check(src);
572 fcgi_buf_check(dest);
574 for (;;) {
575 if (len == 0)
576 return;
578 fcgi_buf_get_free_block_info(dest, &dest_end, &dest_len);
579 fcgi_buf_get_block_info(src, &src_begin, &src_len);
581 move_len = min(dest_len, src_len);
582 move_len = min((int) move_len, len);
584 if (move_len == 0)
585 return;
587 memcpy(dest_end, src_begin, move_len);
588 fcgi_buf_toss(src, move_len);
589 fcgi_buf_add_update(dest, move_len);
590 len -= move_len;
594 static void array_grow(array_header *arr, size_t n)
596 if (n <= 0)
597 return;
599 if ((int) (arr->nelts + n) > arr->nalloc) {
600 char *new_elts;
601 int new_nalloc = (arr->nalloc <= 0) ? n : arr->nelts + n;
603 new_elts = ap_pcalloc(arr->pool, arr->elt_size * new_nalloc);
604 memcpy(new_elts, arr->elts, arr->nelts * arr->elt_size);
606 arr->elts = new_elts;
607 arr->nalloc = new_nalloc;
611 static void array_cat_block(array_header *arr, void *block, size_t n)
613 array_grow(arr, n);
614 memcpy(arr->elts + arr->nelts * arr->elt_size, block, n * arr->elt_size);
615 arr->nelts += n;
618 /*----------------------------------------------------------------------
619 * Append "len" bytes from "buf" into "arr". Apache arrays are used
620 * whenever the data being handled is binary (may contain null chars).
622 void fcgi_buf_get_to_array(Buffer *buf, array_header *arr, size_t len)
624 int len1 = min(buf->length, buf->data + buf->size - buf->begin);
626 fcgi_buf_check(buf);
627 ap_assert(len > 0);
628 ap_assert((int) len <= BufferLength(buf));
630 array_grow(arr, len);
632 len1 = min(len1, (int) len);
633 array_cat_block(arr, buf->begin, len1);
635 if (len1 < (int) len)
636 array_cat_block(arr, buf->data, len - len1);
638 fcgi_buf_toss(buf, len);