fix the closesocket call that I just committed
[mod_fastcgi.git] / fcgi_buf.c
blobb9e1d5cd3196d5e3f905a84a776b1eabdb42c8c5
1 /*
2 * $Id: fcgi_buf.c,v 1.15 2002/03/12 13:06:29 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 void fcgi_buf_removed(Buffer * const b, unsigned int len)
53 b->length -= len;
54 b->begin += len;
56 if (b->length == 0)
58 b->begin = b->end = b->data;
60 else if (b->begin >= b->data + b->size)
62 b->begin -= b->size;
66 void fcgi_buf_added(Buffer * const b, const unsigned int len)
68 b->length += len;
69 b->end += len;
71 if (b->end >= b->data + b->size)
73 b->end -= b->size;
77 #ifdef WIN32
79 static int socket_recv(SOCKET fd, char *buf, int len)
81 int bytes_read = recv(fd, buf, len, 0);
83 if (bytes_read == SOCKET_ERROR)
85 return -1;
87 return bytes_read;
90 static int socket_send(SOCKET fd, char * buf, int len)
92 int bytes_sent = send(fd, buf, len, 0);
94 if (bytes_sent == SOCKET_ERROR)
96 return -1;
98 return bytes_sent;
101 #else /* !WIN32 */
103 static int socket_recv(int fd, char * buf, int len)
105 int bytes_read;
107 do {
108 bytes_read = read(fd, buf, len);
110 if (bytes_read < 0)
112 #ifdef EWOULDBLOCK
113 ap_assert(errno != EWOULDBLOCK);
114 #endif
115 #ifdef EAGAIN
116 ap_assert(errno != EAGAIN);
117 #endif
119 } while (bytes_read == -1 && errno == EINTR);
121 return bytes_read;
124 static int socket_send(int fd, char * buf, int len)
126 int bytes_sent;
128 do {
129 bytes_sent = write(fd, buf, len);
131 if (bytes_sent < 0)
133 #ifdef EWOULDBLOCK
134 ap_assert(errno != EWOULDBLOCK);
135 #endif
136 #ifdef EAGAIN
137 ap_assert(errno != EAGAIN);
138 #endif
141 while (bytes_sent == -1 && errno == EINTR);
143 return bytes_sent;
146 #endif /* !WIN32 */
148 /*******************************************************************************
149 * Read from an open file descriptor into buffer.
151 * The caller should disable the default Apache SIGPIPE handler,
152 * otherwise a bad script could cause the request to abort and appear
153 * as though the client's fd caused it.
155 * Results:
156 * <0 error, errno is set
157 * =0 EOF reached
158 * >0 successful read or no room in buffer (NOT # of bytes read)
160 int fcgi_buf_socket_recv(Buffer *buf, SOCKET fd)
162 int len;
164 fcgi_buf_check(buf);
166 if (buf->length == buf->size)
167 /* there's no room in the buffer, return "success" */
168 return 1;
170 if (buf->length == 0)
171 /* the buffer is empty so defrag */
172 buf->begin = buf->end = buf->data;
174 len = min(buf->size - buf->length, buf->data + buf->size - buf->end);
176 #ifndef NO_WRITEV
178 /* assume there is a readv() since there is a writev() */
179 if (len == buf->size - buf->length)
181 #endif
183 len = socket_recv(fd, buf->end, len);
185 #ifndef NO_WRITEV
187 else
189 /* the buffer is wrapped, use readv() */
190 struct iovec vec[2];
192 vec[0].iov_base = buf->end;
193 vec[0].iov_len = len;
194 vec[1].iov_base = buf->data;
195 vec[1].iov_len = buf->size - buf->length - len;
197 ap_assert(len);
198 ap_assert(vec[1].iov_len);
202 len = readv(fd, vec, 2);
204 while (len == -1 && errno == EINTR);
206 #endif
208 if (len <= 0) return len;
210 fcgi_buf_added(buf, len);
212 return len; /* this may not contain the number of bytes read */
216 /*******************************************************************************
217 * Write from the buffer to an open file descriptor.
219 * The caller should disable the default Apache SIGPIPE handler,
220 * otherwise a bad script could cause the request to abort appearing
221 * as though the client's fd caused it.
223 * Results:
224 * <0 if an error occured (bytes may or may not have been written)
225 * =0 if no bytes were written
226 * >0 successful write
228 int fcgi_buf_socket_send(Buffer *buf, SOCKET fd)
230 int len;
232 fcgi_buf_check(buf);
234 if (buf->length == 0)
235 return 0;
237 len = min(buf->length, buf->data + buf->size - buf->begin);
239 #ifndef NO_WRITEV
240 if (len == buf->length)
242 #endif
244 len = socket_send(fd, buf->begin, len);
246 #ifndef NO_WRITEV
248 else
250 struct iovec vec[2];
252 vec[0].iov_base = buf->begin;
253 vec[0].iov_len = len;
254 vec[1].iov_base = buf->data;
255 vec[1].iov_len = buf->length - len;
259 len = writev(fd, vec, 2);
261 while (len == -1 && errno == EINTR);
263 #endif
265 if (len <= 0) return len;
267 fcgi_buf_removed(buf, len);
269 return len;
272 /*******************************************************************************
273 * Return the data block start address and the length of the block.
275 void fcgi_buf_get_block_info(Buffer *buf, char **beginPtr, int *countPtr)
277 fcgi_buf_check(buf);
279 *beginPtr = buf->begin;
280 *countPtr = min(buf->length, buf->data + buf->size - buf->begin);
283 /*******************************************************************************
284 * Throw away bytes from buffer.
286 void fcgi_buf_toss(Buffer *buf, int count)
288 fcgi_buf_check(buf);
289 ap_assert(count >= 0);
290 ap_assert(count <= buf->length);
292 buf->length -= count;
293 buf->begin += count;
294 if(buf->begin >= buf->data + buf->size) {
295 buf->begin -= buf->size;
299 /*******************************************************************************
300 * Return the free data block start address and the length of the block.
302 void fcgi_buf_get_free_block_info(Buffer *buf, char **endPtr, int *countPtr)
304 fcgi_buf_check(buf);
306 *endPtr = buf->end;
307 *countPtr = min(buf->size - buf->length,
308 buf->data + buf->size - buf->end);
311 /*******************************************************************************
312 * Updates the buf to reflect recently added data.
314 void fcgi_buf_add_update(Buffer *buf, int count)
316 fcgi_buf_check(buf);
317 ap_assert(count >= 0);
318 ap_assert(count <= BufferFree(buf));
320 buf->length += count;
321 buf->end += count;
322 if(buf->end >= buf->data + buf->size) {
323 buf->end -= buf->size;
326 fcgi_buf_check(buf);
329 /*******************************************************************************
330 * Adds a block of data to a buffer, returning the number of bytes added.
332 int fcgi_buf_add_block(Buffer *buf, char *data, int datalen)
334 char *end;
335 int copied = 0; /* Number of bytes actually copied. */
336 int canCopy; /* Number of bytes to copy in a given op. */
338 ap_assert(data != NULL);
339 ap_assert(datalen >= 0);
341 if(datalen == 0) {
342 return 0;
345 ap_assert(datalen > 0);
346 fcgi_buf_check(buf);
347 end = buf->data + buf->size;
350 * Copy the first part of the data: from here to the end of the
351 * buffer, or the end of the data, whichever comes first.
353 datalen = min(BufferFree(buf), datalen);
354 canCopy = min(datalen, end - buf->end);
355 memcpy(buf->end, data, canCopy);
356 buf->length += canCopy;
357 buf->end += canCopy;
358 copied += canCopy;
359 if (buf->end >= end) {
360 buf->end = buf->data;
362 datalen -= canCopy;
365 * If there's more to go, copy the second part starting from the
366 * beginning of the buffer.
368 if (datalen > 0) {
369 data += canCopy;
370 memcpy(buf->end, data, datalen);
371 buf->length += datalen;
372 buf->end += datalen;
373 copied += datalen;
375 return(copied);
378 /*******************************************************************************
379 * Add a string to a buffer, returning the number of bytes added.
381 int fcgi_buf_add_string(Buffer *buf, char *str)
383 return fcgi_buf_add_block(buf, str, strlen(str));
386 /*******************************************************************************
387 * Gets a data block from a buffer, returning the number of bytes copied.
389 int fcgi_buf_get_to_block(Buffer *buf, char *data, int datalen)
391 char *end;
392 int copied = 0; /* Number of bytes actually copied. */
393 int canCopy; /* Number of bytes to copy in a given op. */
395 ap_assert(data != NULL);
396 ap_assert(datalen > 0);
397 fcgi_buf_check(buf);
399 end = buf->data + buf->size;
402 * Copy the first part out of the buffer: from here to the end
403 * of the buffer, or all of the requested data.
405 canCopy = min(buf->length, datalen);
406 canCopy = min(canCopy, end - buf->begin);
408 memcpy(data, buf->begin, canCopy);
410 buf->length -= canCopy;
411 buf->begin += canCopy;
412 copied += canCopy;
413 if (buf->begin >= end) {
414 buf->begin = buf->data;
418 * If there's more to go, copy the second part starting from the
419 * beginning of the buffer.
421 if (copied < datalen && buf->length > 0) {
422 data += copied;
423 canCopy = min(buf->length, datalen - copied);
425 memcpy(data, buf->begin, canCopy);
427 buf->length -= canCopy;
428 buf->begin += canCopy;
429 copied += canCopy;
432 fcgi_buf_check(buf);
433 return(copied);
436 /*******************************************************************************
437 * Move 'len' bytes from 'src' buffer to 'dest' buffer. There must be at
438 * least 'len' bytes available in the source buffer and space for 'len'
439 * bytes in the destination buffer.
441 void fcgi_buf_get_to_buf(Buffer *dest, Buffer *src, int len)
443 char *dest_end, *src_begin;
444 int dest_len, src_len, move_len;
446 ap_assert(len > 0);
447 ap_assert(BufferLength(src) >= len);
448 ap_assert(BufferFree(dest) >= len);
450 fcgi_buf_check(src);
451 fcgi_buf_check(dest);
453 for (;;) {
454 if (len == 0)
455 return;
457 fcgi_buf_get_free_block_info(dest, &dest_end, &dest_len);
458 fcgi_buf_get_block_info(src, &src_begin, &src_len);
460 move_len = min(dest_len, src_len);
461 move_len = min(move_len, len);
463 if (move_len == 0)
464 return;
466 memcpy(dest_end, src_begin, move_len);
467 fcgi_buf_toss(src, move_len);
468 fcgi_buf_add_update(dest, move_len);
469 len -= move_len;
473 static void array_grow(array_header *arr, int n)
475 if (n <= 0)
476 return;
478 if (arr->nelts + n > arr->nalloc) {
479 char *new_elts;
480 int new_nalloc = (arr->nalloc <= 0) ? n : arr->nelts + n;
482 new_elts = ap_pcalloc(arr->pool, arr->elt_size * new_nalloc);
483 memcpy(new_elts, arr->elts, arr->nelts * arr->elt_size);
485 arr->elts = new_elts;
486 arr->nalloc = new_nalloc;
490 static void array_cat_block(array_header *arr, void *block, int n)
492 array_grow(arr, n);
493 memcpy(arr->elts + arr->nelts * arr->elt_size, block, n * arr->elt_size);
494 arr->nelts += n;
497 /*----------------------------------------------------------------------
498 * Append "len" bytes from "buf" into "arr". Apache arrays are used
499 * whenever the data being handled is binary (may contain null chars).
501 void fcgi_buf_get_to_array(Buffer *buf, array_header *arr, int len)
503 int len1 = min(buf->length, buf->data + buf->size - buf->begin);
505 fcgi_buf_check(buf);
506 ap_assert(len > 0);
507 ap_assert(len <= BufferLength(buf));
509 array_grow(arr, len);
511 len1 = min(len1, len);
512 array_cat_block(arr, buf->begin, len1);
514 if (len1 < len)
515 array_cat_block(arr, buf->data, len - len1);
517 fcgi_buf_toss(buf, len);