Tweak to Makefile.tmpl to support DSOs. Dave Hill [ddhill@zk3.dec.com]
[mod_fastcgi.git] / fcgi_buf.c
blobe14b075bd5b4317cbe6edbfecf37af613eba789d
1 /*
2 * $Id: fcgi_buf.c,v 1.8 2000/05/10 05:15:47 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) {
238 bytes_sent = send(fd, buf, len, 0);
239 if (bytes_sent == SOCKET_ERROR) {
240 errno = WSAGetLastError();
241 bytes_sent = -1;
244 else {
245 errno = rv;
246 bytes_sent = -1;
249 return bytes_sent;
252 #else
254 static int fd_write(int fd, char * buf, int len)
256 int bytes_sent;
257 do {
258 bytes_sent = write(fd, buf, len);
259 } while (bytes_sent == -1 && errno == EINTR);
260 return bytes_sent;
263 #endif
265 /*******************************************************************************
266 * Write from the buffer to an open file descriptor.
268 * The caller should disable the default Apache SIGPIPE handler,
269 * otherwise a bad script could cause the request to abort appearing
270 * as though the client's fd caused it.
272 * Results:
273 * <0 if an error occured (bytes may or may not have been written)
274 * =0 if no bytes were written
275 * >0 successful write
277 #ifdef WIN32
278 int fcgi_buf_get_to_fd(Buffer *buf, SOCKET fd)
279 #else
280 int fcgi_buf_get_to_fd(Buffer *buf, int fd)
281 #endif
283 #ifdef WIN32
284 DWORD len;
285 #else
286 size_t len;
287 #endif
289 fcgi_buf_check(buf);
291 if (buf->length == 0)
292 return 0;
294 len = min(buf->length, buf->data + buf->size - buf->begin);
296 #ifndef NO_WRITEV
297 if (len == buf->length) {
298 /* the buffer is not wrapped, we don't need to use writev() */
299 #endif
301 len = fd_write(fd, buf->begin, len);
303 if (len <= 0)
304 goto Return;
306 buf->begin += len;
307 buf->length -= len;
309 if (buf->begin == buf->data + buf->size) {
310 /* the buffer needs to be wrapped */
311 buf->begin = buf->data;
313 #ifndef NO_WRITEV
315 } else {
316 /* the buffer is wrapped, use writev() */
317 struct iovec vec[2];
319 vec[0].iov_base = buf->begin;
320 vec[0].iov_len = len;
321 vec[1].iov_base = buf->data;
322 vec[1].iov_len = buf->length - len;
325 len = writev(fd, vec, 2);
326 while (len == -1 && errno == EINTR);
328 if (len <= 0)
329 goto Return;
331 buf->begin += len;
332 buf->length -= len;
334 if (buf->begin >= buf->data + buf->size)
335 buf->begin -= buf->size;
337 #else
338 if (buf->length > 0) {
339 /* there's still more data to write */
341 fd_set write_set;
342 int status;
343 int numFDs = fd + 1;
344 struct timeval timeOut;
346 FD_ZERO(&write_set);
347 FD_SET(fd, &write_set);
349 timeOut.tv_sec = 0;
350 timeOut.tv_usec = 0;
352 status = ap_select(numFDs, NULL, &write_set, NULL, &timeOut);
354 if (status < 0) {
355 len = status; /* error, errno is set */
356 goto Return;
359 if (status > 0 && FD_ISSET(fd, &write_set)) {
360 int len2;
362 len2 = fd_write(fd, buf->begin, buf->length);
364 if (len2 < 0) {
365 len = len2;
366 goto Return;
369 if (len2 > 0) {
370 buf->begin += len2;
371 buf->length -= len2;
372 len += len2;
377 #endif
379 Return:
380 if (buf->length == 0)
381 buf->begin = buf->end = buf->data;
383 return len;
386 /*******************************************************************************
387 * Return the data block start address and the length of the block.
389 void fcgi_buf_get_block_info(Buffer *buf, char **beginPtr, size_t *countPtr)
391 fcgi_buf_check(buf);
392 *beginPtr = buf->begin;
393 *countPtr = min(buf->length,
394 buf->data + buf->size - buf->begin);
397 /*******************************************************************************
398 * Throw away bytes from buffer.
400 void fcgi_buf_toss(Buffer *buf, size_t count)
402 fcgi_buf_check(buf);
403 ap_assert(count >= 0 && (int) count <= buf->length);
405 buf->length -= count;
406 buf->begin += count;
407 if(buf->begin >= buf->data + buf->size) {
408 buf->begin -= buf->size;
412 /*******************************************************************************
413 * Return the free data block start address and the length of the block.
415 void fcgi_buf_get_free_block_info(Buffer *buf, char **endPtr, size_t *countPtr)
417 fcgi_buf_check(buf);
418 *endPtr = buf->end;
419 *countPtr = min(buf->size - buf->length,
420 buf->data + buf->size - buf->end);
423 /*******************************************************************************
424 * Updates the buf to reflect recently added data.
426 void fcgi_buf_add_update(Buffer *buf, size_t count)
428 fcgi_buf_check(buf);
429 ap_assert(count >= 0 && (int) count <= BufferFree(buf));
431 buf->length += count;
432 buf->end += count;
433 if(buf->end >= buf->data + buf->size) {
434 buf->end -= buf->size;
437 fcgi_buf_check(buf);
440 /*******************************************************************************
441 * Adds a block of data to a buffer, returning the number of bytes added.
443 int fcgi_buf_add_block(Buffer *buf, char *data, size_t datalen)
445 char *end;
446 int copied = 0; /* Number of bytes actually copied. */
447 size_t canCopy; /* Number of bytes to copy in a given op. */
449 ap_assert(data != NULL);
450 if(datalen == 0) {
451 return 0;
454 ap_assert(datalen > 0);
455 fcgi_buf_check(buf);
456 end = buf->data + buf->size;
459 * Copy the first part of the data: from here to the end of the
460 * buffer, or the end of the data, whichever comes first.
462 datalen = min(BufferFree(buf), (int) datalen);
463 canCopy = min((int) datalen, end - buf->end);
464 memcpy(buf->end, data, canCopy);
465 buf->length += canCopy;
466 buf->end += canCopy;
467 copied += canCopy;
468 if (buf->end >= end) {
469 buf->end = buf->data;
471 datalen -= canCopy;
474 * If there's more to go, copy the second part starting from the
475 * beginning of the buffer.
477 if (datalen > 0) {
478 data += canCopy;
479 memcpy(buf->end, data, datalen);
480 buf->length += datalen;
481 buf->end += datalen;
482 copied += datalen;
484 return(copied);
487 /*******************************************************************************
488 * Add a string to a buffer, returning the number of bytes added.
490 int fcgi_buf_add_string(Buffer *buf, char *str)
492 return fcgi_buf_add_block(buf, str, strlen(str));
495 /*******************************************************************************
496 * Gets a data block from a buffer, returning the number of bytes copied.
498 int fcgi_buf_get_to_block(Buffer *buf, char *data, int datalen)
500 char *end;
501 int copied = 0; /* Number of bytes actually copied. */
502 size_t canCopy; /* Number of bytes to copy in a given op. */
504 ap_assert(data != NULL);
505 ap_assert(datalen > 0);
506 fcgi_buf_check(buf);
507 end = buf->data + buf->size;
510 * Copy the first part out of the buffer: from here to the end
511 * of the buffer, or all of the requested data.
513 canCopy = min(buf->length, datalen);
514 canCopy = min((int) canCopy, end - buf->begin);
515 memcpy(data, buf->begin, canCopy);
516 buf->length -= canCopy;
517 buf->begin += canCopy;
518 copied += canCopy;
519 if (buf->begin >= end) {
520 buf->begin = buf->data;
524 * If there's more to go, copy the second part starting from the
525 * beginning of the buffer.
527 if (copied < datalen && buf->length > 0) {
528 data += copied;
529 canCopy = min(buf->length, datalen - copied);
530 memcpy(data, buf->begin, canCopy);
531 buf->length -= canCopy;
532 buf->begin += canCopy;
533 copied += canCopy;
535 fcgi_buf_check(buf);
536 return(copied);
539 /*******************************************************************************
540 * Move 'len' bytes from 'src' buffer to 'dest' buffer. There must be at
541 * least 'len' bytes available in the source buffer and space for 'len'
542 * bytes in the destination buffer.
544 void fcgi_buf_get_to_buf(Buffer *dest, Buffer *src, int len)
546 char *dest_end, *src_begin;
547 size_t dest_len, src_len, move_len;
549 ap_assert(len > 0);
550 ap_assert(BufferLength(src) >= len);
551 ap_assert(BufferFree(dest) >= len);
553 fcgi_buf_check(src);
554 fcgi_buf_check(dest);
556 for (;;) {
557 if (len == 0)
558 return;
560 fcgi_buf_get_free_block_info(dest, &dest_end, &dest_len);
561 fcgi_buf_get_block_info(src, &src_begin, &src_len);
563 move_len = min(dest_len, src_len);
564 move_len = min((int) move_len, len);
566 if (move_len == 0)
567 return;
569 memcpy(dest_end, src_begin, move_len);
570 fcgi_buf_toss(src, move_len);
571 fcgi_buf_add_update(dest, move_len);
572 len -= move_len;
576 static void array_grow(array_header *arr, size_t n)
578 if (n <= 0)
579 return;
581 if ((int) (arr->nelts + n) > arr->nalloc) {
582 char *new_elts;
583 int new_nalloc = (arr->nalloc <= 0) ? n : arr->nelts + n;
585 new_elts = ap_pcalloc(arr->pool, arr->elt_size * new_nalloc);
586 memcpy(new_elts, arr->elts, arr->nelts * arr->elt_size);
588 arr->elts = new_elts;
589 arr->nalloc = new_nalloc;
593 static void array_cat_block(array_header *arr, void *block, size_t n)
595 array_grow(arr, n);
596 memcpy(arr->elts + arr->nelts * arr->elt_size, block, n * arr->elt_size);
597 arr->nelts += n;
600 /*----------------------------------------------------------------------
601 * Append "len" bytes from "buf" into "arr". Apache arrays are used
602 * whenever the data being handled is binary (may contain null chars).
604 void fcgi_buf_get_to_array(Buffer *buf, array_header *arr, size_t len)
606 int len1 = min(buf->length, buf->data + buf->size - buf->begin);
608 fcgi_buf_check(buf);
609 ap_assert(len > 0);
610 ap_assert((int) len <= BufferLength(buf));
612 array_grow(arr, len);
614 len1 = min(len1, (int) len);
615 array_cat_block(arr, buf->begin, len1);
617 if (len1 < (int) len)
618 array_cat_block(arr, buf->data, len - len1);
620 fcgi_buf_toss(buf, len);