(WIN32) fix/rename the util_gettimeofday()
[mod_fastcgi.git] / fcgi_buf.c
blob5ba9e17e60f8ca4925e229614af9c54b39fca70f
1 /*
2 * $Id: fcgi_buf.c,v 1.12 2001/11/20 01:51:27 robs Exp $
3 */
5 #include "fcgi.h"
7 #ifdef WIN32
8 #pragma warning( disable : 4127 )
9 #endif
11 /*******************************************************************************
12 * Check buffer consistency with assertions.
14 void fcgi_buf_check(Buffer *buf)
16 ap_assert(buf->size > 0);
17 ap_assert(buf->length >= 0);
18 ap_assert(buf->length <= buf->size);
20 ap_assert(buf->begin >= buf->data);
21 ap_assert(buf->begin < buf->data + buf->size);
22 ap_assert(buf->end >= buf->data);
23 ap_assert(buf->end < buf->data + buf->size);
25 ap_assert(((buf->end - buf->begin + buf->size) % buf->size)
26 == (buf->length % buf->size));
29 /*******************************************************************************
30 * Reset buffer, losing any data that's in it.
32 void fcgi_buf_reset(Buffer *buf)
34 buf->length = 0;
35 buf->begin = buf->end = buf->data;
38 /*******************************************************************************
39 * Allocate and intialize a new buffer of the specified size.
41 Buffer *fcgi_buf_new(pool *p, int size)
43 Buffer *buf;
45 buf = (Buffer *)ap_pcalloc(p, sizeof(Buffer) + size);
46 buf->size = size;
47 fcgi_buf_reset(buf);
48 return buf;
51 #ifdef WIN32
53 static int fd_read(SOCKET fd, char *buf, int len)
55 DWORD bytes_read;
57 // HACK - we don't know if its a pipe or socket..
58 if (ReadFile((HANDLE) fd, buf, len, &bytes_read, NULL))
60 return (int) bytes_read;
62 else
64 int rv = GetLastError();
66 if (rv == ERROR_PIPE_NOT_CONNECTED)
68 return 0;
70 else if (rv == ERROR_INVALID_PARAMETER)
72 // Then it must be a real socket
74 SetLastError(ERROR_SUCCESS);
76 rv = recv(fd, buf, len, 0);
77 if (rv == SOCKET_ERROR)
79 errno = WSAGetLastError();
80 return -1;
83 return rv;
85 else
87 errno = rv;
88 return -1;
93 #else
95 static int fd_read(int fd, char * buf, int len)
97 int bytes_read;
98 do {
99 bytes_read = read(fd, buf, len);
100 } while (bytes_read == -1 && errno == EINTR);
101 return bytes_read;
104 #endif
106 /*******************************************************************************
107 * Read from an open file descriptor into buffer.
109 * The caller should disable the default Apache SIGPIPE handler,
110 * otherwise a bad script could cause the request to abort and appear
111 * as though the client's fd caused it.
113 * Results:
114 * <0 error, errno is set
115 * =0 EOF reached
116 * >0 successful read or no room in buffer (NOT # of bytes read)
118 #ifdef WIN32
119 int fcgi_buf_add_fd(Buffer *buf, SOCKET fd)
120 #else
121 int fcgi_buf_add_fd(Buffer *buf, int fd)
122 #endif
124 int len;
126 fcgi_buf_check(buf);
128 if (buf->length == buf->size)
129 /* there's no room in the buffer, return "success" */
130 return 1;
132 if (buf->length == 0)
133 /* the buffer is empty so defrag */
134 buf->begin = buf->end = buf->data;
136 len = min(buf->size - buf->length, buf->data + buf->size - buf->end);
138 #ifndef NO_WRITEV
139 /* assume there is a readv() if there is a writev() */
140 if (len == buf->size - buf->length) {
141 /* its not wrapped, use read() instead of readv() */
142 #endif
144 len = fd_read(fd, buf->end, len);
146 if (len <= 0)
147 return len;
149 buf->end += len;
150 buf->length += len;
152 if (buf->end == (buf->data + buf->size)) {
153 /* the buffer needs to be wrapped */
154 buf->end = buf->data;
155 #ifndef NO_WRITEV
157 } else {
158 /* the buffer is wrapped, use readv() */
159 struct iovec vec[2];
161 vec[0].iov_base = buf->end;
162 vec[0].iov_len = len;
163 vec[1].iov_base = buf->data;
164 vec[1].iov_len = buf->size - buf->length - len;
167 len = readv(fd, vec, 2);
168 while (len == -1 && errno == EINTR);
170 if (len <= 0)
171 return len;
173 buf->end += len;
174 if (buf->end >= (buf->data + buf->size))
175 buf->end -= buf->size;
177 buf->length += len;
180 #else
181 if (buf->length < buf->size) {
182 /* There's still more buffer space to read into. */
184 fd_set read_set;
185 int status;
186 int numFDs = fd + 1;
187 struct timeval timeOut;
189 FD_ZERO(&read_set);
190 FD_SET(fd, &read_set);
192 timeOut.tv_sec = 0;
193 timeOut.tv_usec = 0;
195 status = ap_select(numFDs, &read_set, NULL, NULL, &timeOut);
197 if (status < 0) {
198 #ifdef WIN32
199 // More hackery
200 if (WSAGetLastError() == WSAENOTSOCK)
202 DWORD bytesavail=0;
203 if (PeekNamedPipe((HANDLE) fd, NULL, 0, NULL, &bytesavail, NULL))
205 if (bytesavail > 0)
207 len = fd_read(fd, buf->end, buf->size - buf->length);
209 if (len <= 0)
210 return len;
212 buf->end += len;
213 buf->length += len;
215 return len;
218 #endif
219 return status; /* error, errno is set */
222 if (status > 0 && FD_ISSET(fd, &read_set)) {
224 len = fd_read(fd, buf->end, buf->size - buf->length);
226 if (len <= 0)
227 return len;
229 buf->end += len;
230 buf->length += len;
234 #endif
236 return len; /* this may not contain the number of bytes read */
239 #ifdef WIN32
241 static int fd_write(SOCKET fd, char * buf, int len)
243 DWORD bytes_sent;
245 // HACK - We don't know if its a pipe or socket..
246 if (WriteFile((HANDLE) fd, buf, len, &bytes_sent, NULL))
248 return (int) bytes_sent;
250 else
252 int rv = GetLastError();
254 if (rv == ERROR_INVALID_PARAMETER)
256 // Then it must be a real socket..
258 SetLastError(ERROR_SUCCESS);
260 rv = send(fd, buf, len, 0);
262 if (rv == SOCKET_ERROR)
264 rv = WSAGetLastError();
265 if (rv == WSAEWOULDBLOCK)
267 return 0;;
269 else
271 errno = rv;
272 return -1;
276 return rv;
278 else if (rv == WSAEWOULDBLOCK)
280 return 0;
282 else
284 errno = rv;
285 return -1;
290 #else
292 static int fd_write(int fd, char * buf, int len)
294 int bytes_sent;
296 do {
297 bytes_sent = write(fd, buf, len);
299 #ifdef EWOULDBLOCK
300 if (bytes_sent == -1 && errno == EWOULDBLOCK) {
301 bytes_sent = 0;
303 #endif
304 } while (bytes_sent == -1 && errno == EINTR);
306 return bytes_sent;
309 #endif
311 /*******************************************************************************
312 * Write from the buffer to an open file descriptor.
314 * The caller should disable the default Apache SIGPIPE handler,
315 * otherwise a bad script could cause the request to abort appearing
316 * as though the client's fd caused it.
318 * Results:
319 * <0 if an error occured (bytes may or may not have been written)
320 * =0 if no bytes were written
321 * >0 successful write
323 #ifdef WIN32
324 int fcgi_buf_get_to_fd(Buffer *buf, SOCKET fd)
325 #else
326 int fcgi_buf_get_to_fd(Buffer *buf, int fd)
327 #endif
329 int len;
331 fcgi_buf_check(buf);
333 if (buf->length == 0)
334 return 0;
336 len = min(buf->length, buf->data + buf->size - buf->begin);
338 #ifndef NO_WRITEV
339 if (len == buf->length) {
340 /* the buffer is not wrapped, we don't need to use writev() */
341 #endif
343 len = fd_write(fd, buf->begin, len);
345 if (len <= 0)
346 goto Return;
348 buf->begin += len;
349 buf->length -= len;
351 if (buf->begin == buf->data + buf->size) {
352 /* the buffer needs to be wrapped */
353 buf->begin = buf->data;
355 #ifndef NO_WRITEV
357 } else {
358 /* the buffer is wrapped, use writev() */
359 struct iovec vec[2];
361 vec[0].iov_base = buf->begin;
362 vec[0].iov_len = len;
363 vec[1].iov_base = buf->data;
364 vec[1].iov_len = buf->length - len;
367 len = writev(fd, vec, 2);
368 while (len == -1 && errno == EINTR);
370 if (len <= 0)
371 goto Return;
373 buf->begin += len;
374 buf->length -= len;
376 if (buf->begin >= buf->data + buf->size)
377 buf->begin -= buf->size;
379 #else
380 if (buf->length > 0) {
381 /* there's still more data to write */
383 fd_set write_set;
384 int status;
385 int numFDs = fd + 1;
386 struct timeval timeOut;
388 FD_ZERO(&write_set);
389 FD_SET(fd, &write_set);
391 timeOut.tv_sec = 0;
392 timeOut.tv_usec = 0;
394 status = ap_select(numFDs, NULL, &write_set, NULL, &timeOut);
396 if (status < 0) {
397 len = status; /* error, errno is set */
398 goto Return;
401 if (status > 0 && FD_ISSET(fd, &write_set)) {
402 int len2;
404 len2 = fd_write(fd, buf->begin, buf->length);
406 if (len2 < 0) {
407 len = len2;
408 goto Return;
411 if (len2 > 0) {
412 buf->begin += len2;
413 buf->length -= len2;
414 len += len2;
419 #endif
421 Return:
422 if (buf->length == 0)
423 buf->begin = buf->end = buf->data;
425 return len;
428 /*******************************************************************************
429 * Return the data block start address and the length of the block.
431 void fcgi_buf_get_block_info(Buffer *buf, char **beginPtr, int *countPtr)
433 fcgi_buf_check(buf);
435 *beginPtr = buf->begin;
436 *countPtr = min(buf->length, buf->data + buf->size - buf->begin);
439 /*******************************************************************************
440 * Throw away bytes from buffer.
442 void fcgi_buf_toss(Buffer *buf, int count)
444 fcgi_buf_check(buf);
445 ap_assert(count >= 0);
446 ap_assert(count <= buf->length);
448 buf->length -= count;
449 buf->begin += count;
450 if(buf->begin >= buf->data + buf->size) {
451 buf->begin -= buf->size;
455 /*******************************************************************************
456 * Return the free data block start address and the length of the block.
458 void fcgi_buf_get_free_block_info(Buffer *buf, char **endPtr, int *countPtr)
460 fcgi_buf_check(buf);
462 *endPtr = buf->end;
463 *countPtr = min(buf->size - buf->length,
464 buf->data + buf->size - buf->end);
467 /*******************************************************************************
468 * Updates the buf to reflect recently added data.
470 void fcgi_buf_add_update(Buffer *buf, int count)
472 fcgi_buf_check(buf);
473 ap_assert(count >= 0);
474 ap_assert(count <= BufferFree(buf));
476 buf->length += count;
477 buf->end += count;
478 if(buf->end >= buf->data + buf->size) {
479 buf->end -= buf->size;
482 fcgi_buf_check(buf);
485 /*******************************************************************************
486 * Adds a block of data to a buffer, returning the number of bytes added.
488 int fcgi_buf_add_block(Buffer *buf, char *data, int datalen)
490 char *end;
491 int copied = 0; /* Number of bytes actually copied. */
492 int canCopy; /* Number of bytes to copy in a given op. */
494 ap_assert(data != NULL);
495 ap_assert(datalen >= 0);
497 if(datalen == 0) {
498 return 0;
501 ap_assert(datalen > 0);
502 fcgi_buf_check(buf);
503 end = buf->data + buf->size;
506 * Copy the first part of the data: from here to the end of the
507 * buffer, or the end of the data, whichever comes first.
509 datalen = min(BufferFree(buf), datalen);
510 canCopy = min(datalen, end - buf->end);
511 memcpy(buf->end, data, canCopy);
512 buf->length += canCopy;
513 buf->end += canCopy;
514 copied += canCopy;
515 if (buf->end >= end) {
516 buf->end = buf->data;
518 datalen -= canCopy;
521 * If there's more to go, copy the second part starting from the
522 * beginning of the buffer.
524 if (datalen > 0) {
525 data += canCopy;
526 memcpy(buf->end, data, datalen);
527 buf->length += datalen;
528 buf->end += datalen;
529 copied += datalen;
531 return(copied);
534 /*******************************************************************************
535 * Add a string to a buffer, returning the number of bytes added.
537 int fcgi_buf_add_string(Buffer *buf, char *str)
539 return fcgi_buf_add_block(buf, str, strlen(str));
542 /*******************************************************************************
543 * Gets a data block from a buffer, returning the number of bytes copied.
545 int fcgi_buf_get_to_block(Buffer *buf, char *data, int datalen)
547 char *end;
548 int copied = 0; /* Number of bytes actually copied. */
549 int canCopy; /* Number of bytes to copy in a given op. */
551 ap_assert(data != NULL);
552 ap_assert(datalen > 0);
553 fcgi_buf_check(buf);
555 end = buf->data + buf->size;
558 * Copy the first part out of the buffer: from here to the end
559 * of the buffer, or all of the requested data.
561 canCopy = min(buf->length, datalen);
562 canCopy = min(canCopy, end - buf->begin);
564 memcpy(data, buf->begin, canCopy);
566 buf->length -= canCopy;
567 buf->begin += canCopy;
568 copied += canCopy;
569 if (buf->begin >= end) {
570 buf->begin = buf->data;
574 * If there's more to go, copy the second part starting from the
575 * beginning of the buffer.
577 if (copied < datalen && buf->length > 0) {
578 data += copied;
579 canCopy = min(buf->length, datalen - copied);
581 memcpy(data, buf->begin, canCopy);
583 buf->length -= canCopy;
584 buf->begin += canCopy;
585 copied += canCopy;
588 fcgi_buf_check(buf);
589 return(copied);
592 /*******************************************************************************
593 * Move 'len' bytes from 'src' buffer to 'dest' buffer. There must be at
594 * least 'len' bytes available in the source buffer and space for 'len'
595 * bytes in the destination buffer.
597 void fcgi_buf_get_to_buf(Buffer *dest, Buffer *src, int len)
599 char *dest_end, *src_begin;
600 int dest_len, src_len, move_len;
602 ap_assert(len > 0);
603 ap_assert(BufferLength(src) >= len);
604 ap_assert(BufferFree(dest) >= len);
606 fcgi_buf_check(src);
607 fcgi_buf_check(dest);
609 for (;;) {
610 if (len == 0)
611 return;
613 fcgi_buf_get_free_block_info(dest, &dest_end, &dest_len);
614 fcgi_buf_get_block_info(src, &src_begin, &src_len);
616 move_len = min(dest_len, src_len);
617 move_len = min(move_len, len);
619 if (move_len == 0)
620 return;
622 memcpy(dest_end, src_begin, move_len);
623 fcgi_buf_toss(src, move_len);
624 fcgi_buf_add_update(dest, move_len);
625 len -= move_len;
629 static void array_grow(array_header *arr, int n)
631 if (n <= 0)
632 return;
634 if (arr->nelts + n > arr->nalloc) {
635 char *new_elts;
636 int new_nalloc = (arr->nalloc <= 0) ? n : arr->nelts + n;
638 new_elts = ap_pcalloc(arr->pool, arr->elt_size * new_nalloc);
639 memcpy(new_elts, arr->elts, arr->nelts * arr->elt_size);
641 arr->elts = new_elts;
642 arr->nalloc = new_nalloc;
646 static void array_cat_block(array_header *arr, void *block, int n)
648 array_grow(arr, n);
649 memcpy(arr->elts + arr->nelts * arr->elt_size, block, n * arr->elt_size);
650 arr->nelts += n;
653 /*----------------------------------------------------------------------
654 * Append "len" bytes from "buf" into "arr". Apache arrays are used
655 * whenever the data being handled is binary (may contain null chars).
657 void fcgi_buf_get_to_array(Buffer *buf, array_header *arr, int len)
659 int len1 = min(buf->length, buf->data + buf->size - buf->begin);
661 fcgi_buf_check(buf);
662 ap_assert(len > 0);
663 ap_assert(len <= BufferLength(buf));
665 array_grow(arr, len);
667 len1 = min(len1, len);
668 array_cat_block(arr, buf->begin, len1);
670 if (len1 < len)
671 array_cat_block(arr, buf->data, len - len1);
673 fcgi_buf_toss(buf, len);