"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * $Id: fcgi_buf.c,v 1.18 2003/02/03 23:07:37 robs Exp $
3 */
4
5 #include "fcgi.h"
6
7 #ifdef WIN32
8 #pragma warning( disable : 4127 )
9 #else
10 #ifdef APACHE2
11 #include <unistd.h>
12 #endif
13 #endif
14
15 /*******************************************************************************
16 * Check buffer consistency with assertions.
17 */
18 #ifdef DEBUG
19 static void fcgi_buf_check(Buffer *buf)
20 {
21 ASSERT(buf->size > 0);
22 ASSERT(buf->length >= 0);
23 ASSERT(buf->length <= buf->size);
24
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);
29
30 ASSERT(((buf->end - buf->begin + buf->size) % buf->size)
31 == (buf->length % buf->size));
32 }
33 #else
34 #define fcgi_buf_check(a) ((void) 0)
35 #endif
36
37 /*******************************************************************************
38 * Reset buffer, losing any data that's in it.
39 */
40 void fcgi_buf_reset(Buffer *buf)
41 {
42 buf->length = 0;
43 buf->begin = buf->end = buf->data;
44 }
45
46 /*******************************************************************************
47 * Allocate and intialize a new buffer of the specified size.
48 */
49 Buffer *fcgi_buf_new(pool *p, int size)
50 {
51 Buffer *buf;
52
53 buf = (Buffer *)ap_pcalloc(p, sizeof(Buffer) + size);
54 buf->size = size;
55 fcgi_buf_reset(buf);
56 return buf;
57 }
58
59 void fcgi_buf_removed(Buffer * const b, unsigned int len)
60 {
61 b->length -= len;
62 b->begin += len;
63
64 if (b->length == 0)
65 {
66 b->begin = b->end = b->data;
67 }
68 else if (b->begin >= b->data + b->size)
69 {
70 b->begin -= b->size;
71 }
72 }
73
74 void fcgi_buf_added(Buffer * const b, const unsigned int len)
75 {
76 b->length += len;
77 b->end += len;
78
79 if (b->end >= b->data + b->size)
80 {
81 b->end -= b->size;
82 }
83 }
84
85 #ifdef WIN32
86
87 static int socket_recv(SOCKET fd, char *buf, int len)
88 {
89 int bytes_read = recv(fd, buf, len, 0);
90
91 if (bytes_read == SOCKET_ERROR)
92 {
93 return -1;
94 }
95 return bytes_read;
96 }
97
98 static int socket_send(SOCKET fd, char * buf, int len)
99 {
100 int bytes_sent = send(fd, buf, len, 0);
101
102 if (bytes_sent == SOCKET_ERROR)
103 {
104 return -1;
105 }
106 return bytes_sent;
107 }
108
109 #else /* !WIN32 */
110
111 static int socket_recv(int fd, char * buf, int len)
112 {
113 int bytes_read;
114
115 do {
116 bytes_read = read(fd, buf, len);
117
118 if (bytes_read < 0)
119 {
120 #ifdef EWOULDBLOCK
121 ASSERT(errno != EWOULDBLOCK);
122 #endif
123 #ifdef EAGAIN
124 ASSERT(errno != EAGAIN);
125 #endif
126 }
127 } while (bytes_read == -1 && errno == EINTR);
128
129 return bytes_read;
130 }
131
132 static int socket_send(int fd, char * buf, int len)
133 {
134 int bytes_sent;
135
136 do {
137 bytes_sent = write(fd, buf, len);
138
139 if (bytes_sent < 0)
140 {
141 #ifdef EWOULDBLOCK
142 ASSERT(errno != EWOULDBLOCK);
143 #endif
144 #ifdef EAGAIN
145 ASSERT(errno != EAGAIN);
146 #endif
147 }
148 }
149 while (bytes_sent == -1 && errno == EINTR);
150
151 return bytes_sent;
152 }
153
154 #endif /* !WIN32 */
155
156 /*******************************************************************************
157 * Read from an open file descriptor into buffer.
158 *
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.
162 *
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)
167 */
168 int fcgi_buf_socket_recv(Buffer *buf, SOCKET fd)
169 {
170 int len;
171
172 fcgi_buf_check(buf);
173
174 if (buf->length == buf->size)
175 /* there's no room in the buffer, return "success" */
176 return 1;
177
178 if (buf->length == 0)
179 /* the buffer is empty so defrag */
180 buf->begin = buf->end = buf->data;
181
182 len = min(buf->size - buf->length, buf->data + buf->size - buf->end);
183
184 #ifndef NO_WRITEV
185
186 /* assume there is a readv() since there is a writev() */
187 if (len == buf->size - buf->length)
188 {
189 #endif
190
191 len = socket_recv(fd, buf->end, len);
192
193 #ifndef NO_WRITEV
194 }
195 else
196 {
197 /* the buffer is wrapped, use readv() */
198 struct iovec vec[2];
199
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;
204
205 ASSERT(len);
206 ASSERT(vec[1].iov_len);
207
208 do
209 {
210 len = readv(fd, vec, 2);
211 }
212 while (len == -1 && errno == EINTR);
213 }
214 #endif
215
216 if (len <= 0) return len;
217
218 fcgi_buf_added(buf, len);
219
220 return len; /* this may not contain the number of bytes read */
221 }
222
223
224 /*******************************************************************************
225 * Write from the buffer to an open file descriptor.
226 *
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.
230 *
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
235 */
236 int fcgi_buf_socket_send(Buffer *buf, SOCKET fd)
237 {
238 int len;
239
240 fcgi_buf_check(buf);
241
242 if (buf->length == 0)
243 return 0;
244
245 len = min(buf->length, buf->data + buf->size - buf->begin);
246
247 #ifndef NO_WRITEV
248 if (len == buf->length)
249 {
250 #endif
251
252 len = socket_send(fd, buf->begin, len);
253
254 #ifndef NO_WRITEV
255 }
256 else
257 {
258 struct iovec vec[2];
259
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;
264
265 do
266 {
267 len = writev(fd, vec, 2);
268 }
269 while (len == -1 && errno == EINTR);
270 }
271 #endif
272
273 if (len <= 0) return len;
274
275 fcgi_buf_removed(buf, len);
276
277 return len;
278 }
279
280 /*******************************************************************************
281 * Return the data block start address and the length of the block.
282 */
283 void fcgi_buf_get_block_info(Buffer *buf, char **beginPtr, int *countPtr)
284 {
285 fcgi_buf_check(buf);
286
287 *beginPtr = buf->begin;
288 *countPtr = min(buf->length, buf->data + buf->size - buf->begin);
289 }
290
291 /*******************************************************************************
292 * Throw away bytes from buffer.
293 */
294 void fcgi_buf_toss(Buffer *buf, int count)
295 {
296 fcgi_buf_check(buf);
297 ASSERT(count >= 0);
298 ASSERT(count <= buf->length);
299
300 buf->length -= count;
301 buf->begin += count;
302 if(buf->begin >= buf->data + buf->size) {
303 buf->begin -= buf->size;
304 }
305 }
306
307 /*******************************************************************************
308 * Return the free data block start address and the length of the block.
309 */
310 void fcgi_buf_get_free_block_info(Buffer *buf, char **endPtr, int *countPtr)
311 {
312 fcgi_buf_check(buf);
313
314 *endPtr = buf->end;
315 *countPtr = min(buf->size - buf->length,
316 buf->data + buf->size - buf->end);
317 }
318
319 /*******************************************************************************
320 * Updates the buf to reflect recently added data.
321 */
322 void fcgi_buf_add_update(Buffer *buf, int count)
323 {
324 fcgi_buf_check(buf);
325 ASSERT(count >= 0);
326 ASSERT(count <= BufferFree(buf));
327
328 buf->length += count;
329 buf->end += count;
330 if(buf->end >= buf->data + buf->size) {
331 buf->end -= buf->size;
332 }
333
334 fcgi_buf_check(buf);
335 }
336
337 /*******************************************************************************
338 * Adds a block of data to a buffer, returning the number of bytes added.
339 */
340 int fcgi_buf_add_block(Buffer *buf, char *data, int datalen)
341 {
342 char *end;
343 int copied = 0; /* Number of bytes actually copied. */
344 int canCopy; /* Number of bytes to copy in a given op. */
345
346 ASSERT(data != NULL);
347 ASSERT(datalen >= 0);
348
349 if(datalen == 0) {
350 return 0;
351 }
352
353 ASSERT(datalen > 0);
354 fcgi_buf_check(buf);
355 end = buf->data + buf->size;
356
357 /*
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.
360 */
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;
369 }
370 datalen -= canCopy;
371
372 /*
373 * If there's more to go, copy the second part starting from the
374 * beginning of the buffer.
375 */
376 if (datalen > 0) {
377 data += canCopy;
378 memcpy(buf->end, data, datalen);
379 buf->length += datalen;
380 buf->end += datalen;
381 copied += datalen;
382 }
383 return(copied);
384 }
385
386 /*******************************************************************************
387 * Add a string to a buffer, returning the number of bytes added.
388 */
389 int fcgi_buf_add_string(Buffer *buf, char *str)
390 {
391 return fcgi_buf_add_block(buf, str, strlen(str));
392 }
393
394 /*******************************************************************************
395 * Gets a data block from a buffer, returning the number of bytes copied.
396 */
397 int fcgi_buf_get_to_block(Buffer *buf, char *data, int datalen)
398 {
399 char *end;
400 int copied = 0; /* Number of bytes actually copied. */
401 int canCopy; /* Number of bytes to copy in a given op. */
402
403 ASSERT(data != NULL);
404 ASSERT(datalen > 0);
405 fcgi_buf_check(buf);
406
407 end = buf->data + buf->size;
408
409 /*
410 * Copy the first part out of the buffer: from here to the end
411 * of the buffer, or all of the requested data.
412 */
413 canCopy = min(buf->length, datalen);
414 canCopy = min(canCopy, end - buf->begin);
415
416 memcpy(data, buf->begin, canCopy);
417
418 buf->length -= canCopy;
419 buf->begin += canCopy;
420 copied += canCopy;
421 if (buf->begin >= end) {
422 buf->begin = buf->data;
423 }
424
425 /*
426 * If there's more to go, copy the second part starting from the
427 * beginning of the buffer.
428 */
429 if (copied < datalen && buf->length > 0) {
430 data += copied;
431 canCopy = min(buf->length, datalen - copied);
432
433 memcpy(data, buf->begin, canCopy);
434
435 buf->length -= canCopy;
436 buf->begin += canCopy;
437 copied += canCopy;
438 }
439
440 fcgi_buf_check(buf);
441 return(copied);
442 }
443
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.
448 */
449 void fcgi_buf_get_to_buf(Buffer *dest, Buffer *src, int len)
450 {
451 char *dest_end, *src_begin;
452 int dest_len, src_len, move_len;
453
454 ASSERT(len > 0);
455 ASSERT(BufferLength(src) >= len);
456 ASSERT(BufferFree(dest) >= len);
457
458 fcgi_buf_check(src);
459 fcgi_buf_check(dest);
460
461 for (;;) {
462 if (len == 0)
463 return;
464
465 fcgi_buf_get_free_block_info(dest, &dest_end, &dest_len);
466 fcgi_buf_get_block_info(src, &src_begin, &src_len);
467
468 move_len = min(dest_len, src_len);
469 move_len = min(move_len, len);
470
471 if (move_len == 0)
472 return;
473
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;
478 }
479 }
480
481 static void array_grow(array_header *arr, int n)
482 {
483 if (n <= 0)
484 return;
485
486 if (arr->nelts + n > arr->nalloc) {
487 char *new_elts;
488 int new_nalloc = (arr->nalloc <= 0) ? n : arr->nelts + n;
489
490 new_elts = ap_pcalloc(arr->pool, arr->elt_size * new_nalloc);
491 memcpy(new_elts, arr->elts, arr->nelts * arr->elt_size);
492
493 arr->elts = new_elts;
494 arr->nalloc = new_nalloc;
495 }
496 }
497
498 static void array_cat_block(array_header *arr, void *block, int n)
499 {
500 array_grow(arr, n);
501 memcpy(arr->elts + arr->nelts * arr->elt_size, block, n * arr->elt_size);
502 arr->nelts += n;
503 }
504
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).
508 */
509 void fcgi_buf_get_to_array(Buffer *buf, array_header *arr, int len)
510 {
511 int len1 = min(buf->length, buf->data + buf->size - buf->begin);
512
513 fcgi_buf_check(buf);
514 ASSERT(len > 0);
515 ASSERT(len <= BufferLength(buf));
516
517 array_grow(arr, len);
518
519 len1 = min(len1, len);
520 array_cat_block(arr, buf->begin, len1);
521
522 if (len1 < len)
523 array_cat_block(arr, buf->data, len - len1);
524
525 fcgi_buf_toss(buf, len);
526 }