1251877Speter/* Copyright 2002-2004 Justin Erenkrantz and Greg Stein
2251877Speter *
3251877Speter * Licensed under the Apache License, Version 2.0 (the "License");
4251877Speter * you may not use this file except in compliance with the License.
5251877Speter * You may obtain a copy of the License at
6251877Speter *
7251877Speter *     http://www.apache.org/licenses/LICENSE-2.0
8251877Speter *
9251877Speter * Unless required by applicable law or agreed to in writing, software
10251877Speter * distributed under the License is distributed on an "AS IS" BASIS,
11251877Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12251877Speter * See the License for the specific language governing permissions and
13251877Speter * limitations under the License.
14251877Speter */
15251877Speter
16251877Speter#include <apr_pools.h>
17251877Speter
18251877Speter#include "serf.h"
19251877Speter#include "serf_bucket_util.h"
20253895Speter#include "serf_private.h"
21251877Speter
22251877Speterserf_bucket_t *serf_bucket_create(
23251877Speter    const serf_bucket_type_t *type,
24251877Speter    serf_bucket_alloc_t *allocator,
25251877Speter    void *data)
26251877Speter{
27251877Speter    serf_bucket_t *bkt = serf_bucket_mem_alloc(allocator, sizeof(*bkt));
28251877Speter
29251877Speter    bkt->type = type;
30251877Speter    bkt->data = data;
31251877Speter    bkt->allocator = allocator;
32251877Speter
33251877Speter    return bkt;
34251877Speter}
35251877Speter
36251877Speter
37251877Speterapr_status_t serf_default_read_iovec(
38251877Speter    serf_bucket_t *bucket,
39251877Speter    apr_size_t requested,
40251877Speter    int vecs_size,
41251877Speter    struct iovec *vecs,
42251877Speter    int *vecs_used)
43251877Speter{
44251877Speter    const char *data;
45251877Speter    apr_size_t len;
46251877Speter
47251877Speter    /* Read some data from the bucket.
48251877Speter     *
49251877Speter     * Because we're an internal 'helper' to the bucket, we can't call the
50251877Speter     * normal serf_bucket_read() call because the debug allocator tracker will
51251877Speter     * end up marking the bucket as read *twice* - once for us and once for
52251877Speter     * our caller - which is reading the same bucket.  This leads to premature
53251877Speter     * abort()s if we ever see EAGAIN.  Instead, we'll go directly to the
54251877Speter     * vtable and bypass the debug tracker.
55251877Speter     */
56251877Speter    apr_status_t status = bucket->type->read(bucket, requested, &data, &len);
57251877Speter
58251877Speter    /* assert that vecs_size >= 1 ? */
59251877Speter
60251877Speter    /* Return that data as a single iovec. */
61251877Speter    if (len) {
62251877Speter        vecs[0].iov_base = (void *)data; /* loses the 'const' */
63251877Speter        vecs[0].iov_len = len;
64251877Speter        *vecs_used = 1;
65251877Speter    }
66251877Speter    else {
67251877Speter        *vecs_used = 0;
68251877Speter    }
69251877Speter
70251877Speter    return status;
71251877Speter}
72251877Speter
73251877Speter
74251877Speterapr_status_t serf_default_read_for_sendfile(
75251877Speter    serf_bucket_t *bucket,
76251877Speter    apr_size_t requested,
77251877Speter    apr_hdtr_t *hdtr,
78251877Speter    apr_file_t **file,
79251877Speter    apr_off_t *offset,
80251877Speter    apr_size_t *len)
81251877Speter{
82251877Speter    /* Read a bunch of stuff into the headers.
83251877Speter     *
84251877Speter     * See serf_default_read_iovec as to why we call into the vtable
85251877Speter     * directly.
86251877Speter     */
87251877Speter    apr_status_t status = bucket->type->read_iovec(bucket, requested,
88251877Speter                                                   hdtr->numheaders,
89251877Speter                                                   hdtr->headers,
90251877Speter                                                   &hdtr->numheaders);
91251877Speter
92251877Speter    /* There isn't a file, and there are no trailers. */
93251877Speter    *file = NULL;
94251877Speter    hdtr->numtrailers = 0;
95251877Speter
96251877Speter    return status;
97251877Speter}
98251877Speter
99251877Speter
100251877Speterserf_bucket_t *serf_default_read_bucket(
101251877Speter    serf_bucket_t *bucket,
102251877Speter    const serf_bucket_type_t *type)
103251877Speter{
104251877Speter    return NULL;
105251877Speter}
106251877Speter
107251877Speter
108251877Spetervoid serf_default_destroy(serf_bucket_t *bucket)
109251877Speter{
110251877Speter#ifdef SERF_DEBUG_BUCKET_USE
111251877Speter    serf_debug__bucket_destroy(bucket);
112251877Speter#endif
113251877Speter
114251877Speter    serf_bucket_mem_free(bucket->allocator, bucket);
115251877Speter}
116251877Speter
117251877Speter
118251877Spetervoid serf_default_destroy_and_data(serf_bucket_t *bucket)
119251877Speter{
120251877Speter    serf_bucket_mem_free(bucket->allocator, bucket->data);
121251877Speter    serf_default_destroy(bucket);
122251877Speter}
123251877Speter
124251877Speter
125251877Speter/* ==================================================================== */
126251877Speter
127251877Speter
128251877Speterchar *serf_bstrmemdup(serf_bucket_alloc_t *allocator,
129251877Speter                      const char *str,
130251877Speter                      apr_size_t size)
131251877Speter{
132251877Speter    char *newstr = serf_bucket_mem_alloc(allocator, size + 1);
133251877Speter    memcpy(newstr, str, size);
134251877Speter    newstr[size] = '\0';
135251877Speter    return newstr;
136251877Speter}
137251877Speter
138251877Speter
139251877Spetervoid *serf_bmemdup(serf_bucket_alloc_t *allocator,
140251877Speter                   const void *mem,
141251877Speter                   apr_size_t size)
142251877Speter{
143251877Speter    void *newmem = serf_bucket_mem_alloc(allocator, size);
144251877Speter    memcpy(newmem, mem, size);
145251877Speter    return newmem;
146251877Speter}
147251877Speter
148251877Speter
149251877Speterchar *serf_bstrdup(serf_bucket_alloc_t *allocator,
150251877Speter                   const char *str)
151251877Speter{
152251877Speter    apr_size_t size = strlen(str) + 1;
153251877Speter    char *newstr = serf_bucket_mem_alloc(allocator, size);
154251877Speter    memcpy(newstr, str, size);
155251877Speter    return newstr;
156251877Speter}
157251877Speter
158253895Speterchar *serf_bstrcatv(serf_bucket_alloc_t *allocator, struct iovec *vec,
159253895Speter                    int vecs, apr_size_t *bytes_written)
160253895Speter{
161253895Speter    int i;
162253895Speter    apr_size_t new_len = 0;
163253895Speter    char *c, *newstr;
164251877Speter
165253895Speter    for (i = 0; i < vecs; i++) {
166253895Speter        new_len += vec[i].iov_len;
167253895Speter    }
168253895Speter
169253895Speter    /* It's up to the caller to free this memory later. */
170253895Speter    newstr = serf_bucket_mem_alloc(allocator, new_len);
171253895Speter
172253895Speter    c = newstr;
173253895Speter    for (i = 0; i < vecs; i++) {
174253895Speter        memcpy(c, vec[i].iov_base, vec[i].iov_len);
175253895Speter        c += vec[i].iov_len;
176253895Speter    }
177253895Speter
178253895Speter    if (bytes_written) {
179253895Speter        *bytes_written = c - newstr;
180253895Speter    }
181253895Speter
182253895Speter    return newstr;
183253895Speter}
184253895Speter
185251877Speter/* ==================================================================== */
186251877Speter
187251877Speter
188251877Speterstatic void find_crlf(const char **data, apr_size_t *len, int *found)
189251877Speter{
190251877Speter    const char *start = *data;
191251877Speter    const char *end = start + *len;
192251877Speter
193251877Speter    while (start < end) {
194251877Speter        const char *cr = memchr(start, '\r', *len);
195251877Speter
196251877Speter        if (cr == NULL) {
197251877Speter            break;
198251877Speter        }
199251877Speter        ++cr;
200251877Speter
201251877Speter        if (cr < end && cr[0] == '\n') {
202251877Speter            *len -= cr + 1 - start;
203251877Speter            *data = cr + 1;
204251877Speter            *found = SERF_NEWLINE_CRLF;
205251877Speter            return;
206251877Speter        }
207251877Speter        if (cr == end) {
208251877Speter            *len = 0;
209251877Speter            *data = end;
210251877Speter            *found = SERF_NEWLINE_CRLF_SPLIT;
211251877Speter            return;
212251877Speter        }
213251877Speter
214251877Speter        /* It was a bare CR without an LF. Just move past it. */
215251877Speter        *len -= cr - start;
216251877Speter        start = cr;
217251877Speter    }
218251877Speter
219251877Speter    *data = start + *len;
220251877Speter    *len -= *data - start;
221251877Speter    *found = SERF_NEWLINE_NONE;
222251877Speter}
223251877Speter
224251877Speter
225251877Spetervoid serf_util_readline(
226251877Speter    const char **data,
227251877Speter    apr_size_t *len,
228251877Speter    int acceptable,
229251877Speter    int *found)
230251877Speter{
231251877Speter    const char *start;
232251877Speter    const char *cr;
233251877Speter    const char *lf;
234251877Speter    int want_cr;
235251877Speter    int want_crlf;
236251877Speter    int want_lf;
237251877Speter
238251877Speter    /* If _only_ CRLF is acceptable, then the scanning needs a loop to
239251877Speter     * skip false hits on CR characters. Use a separate function.
240251877Speter     */
241251877Speter    if (acceptable == SERF_NEWLINE_CRLF) {
242251877Speter        find_crlf(data, len, found);
243251877Speter        return;
244251877Speter    }
245251877Speter
246251877Speter    start = *data;
247251877Speter    cr = lf = NULL;
248251877Speter    want_cr = acceptable & SERF_NEWLINE_CR;
249251877Speter    want_crlf = acceptable & SERF_NEWLINE_CRLF;
250251877Speter    want_lf = acceptable & SERF_NEWLINE_LF;
251251877Speter
252251877Speter    if (want_cr || want_crlf) {
253251877Speter        cr = memchr(start, '\r', *len);
254251877Speter    }
255251877Speter    if (want_lf) {
256251877Speter        lf = memchr(start, '\n', *len);
257251877Speter    }
258251877Speter
259251877Speter    if (cr != NULL) {
260251877Speter        if (lf != NULL) {
261251877Speter            if (cr + 1 == lf)
262251877Speter                *found = want_crlf ? SERF_NEWLINE_CRLF : SERF_NEWLINE_CR;
263251877Speter            else if (want_cr && cr < lf)
264251877Speter                *found = SERF_NEWLINE_CR;
265251877Speter            else
266251877Speter                *found = SERF_NEWLINE_LF;
267251877Speter        }
268251877Speter        else if (cr == start + *len - 1) {
269251877Speter            /* the CR occurred in the last byte of the buffer. this could be
270251877Speter             * a CRLF split across the data boundary.
271251877Speter             * ### FIX THIS LOGIC? does caller need to detect?
272251877Speter             */
273251877Speter            *found = want_crlf ? SERF_NEWLINE_CRLF_SPLIT : SERF_NEWLINE_CR;
274251877Speter        }
275251877Speter        else if (want_cr)
276251877Speter            *found = SERF_NEWLINE_CR;
277251877Speter        else /* want_crlf */
278251877Speter            *found = SERF_NEWLINE_NONE;
279251877Speter    }
280251877Speter    else if (lf != NULL)
281251877Speter        *found = SERF_NEWLINE_LF;
282251877Speter    else
283251877Speter        *found = SERF_NEWLINE_NONE;
284251877Speter
285251877Speter    switch (*found) {
286251877Speter      case SERF_NEWLINE_LF:
287251877Speter        *data = lf + 1;
288251877Speter        break;
289251877Speter      case SERF_NEWLINE_CR:
290251877Speter      case SERF_NEWLINE_CRLF:
291251877Speter      case SERF_NEWLINE_CRLF_SPLIT:
292251877Speter        *data = cr + 1 + (*found == SERF_NEWLINE_CRLF);
293251877Speter        break;
294251877Speter      case SERF_NEWLINE_NONE:
295251877Speter        *data += *len;
296251877Speter        break;
297251877Speter      default:
298251877Speter        /* Not reachable */
299251877Speter        return;
300251877Speter    }
301251877Speter
302251877Speter    *len -= *data - start;
303251877Speter}
304251877Speter
305251877Speter
306251877Speter/* ==================================================================== */
307251877Speter
308251877Speter
309251877Spetervoid serf_databuf_init(serf_databuf_t *databuf)
310251877Speter{
311251877Speter    /* nothing is sitting in the buffer */
312251877Speter    databuf->remaining = 0;
313251877Speter
314251877Speter    /* avoid thinking we have hit EOF */
315251877Speter    databuf->status = APR_SUCCESS;
316251877Speter}
317251877Speter
318251877Speter/* Ensure the buffer is prepared for reading. Will return APR_SUCCESS,
319251877Speter * APR_EOF, or some failure code. *len is only set for EOF. */
320251877Speterstatic apr_status_t common_databuf_prep(serf_databuf_t *databuf,
321251877Speter                                        apr_size_t *len)
322251877Speter{
323251877Speter    apr_size_t readlen;
324251877Speter    apr_status_t status;
325251877Speter
326251877Speter    /* if there is data in the buffer, then we're happy. */
327251877Speter    if (databuf->remaining > 0)
328251877Speter        return APR_SUCCESS;
329251877Speter
330251877Speter    /* if we already hit EOF, then keep returning that. */
331251877Speter    if (APR_STATUS_IS_EOF(databuf->status)) {
332251877Speter        /* *data = NULL;   ?? */
333251877Speter        *len = 0;
334251877Speter        return APR_EOF;
335251877Speter    }
336251877Speter
337251877Speter    /* refill the buffer */
338251877Speter    status = (*databuf->read)(databuf->read_baton, sizeof(databuf->buf),
339251877Speter                              databuf->buf, &readlen);
340251877Speter    if (SERF_BUCKET_READ_ERROR(status)) {
341251877Speter        return status;
342251877Speter    }
343251877Speter
344251877Speter    databuf->current = databuf->buf;
345251877Speter    databuf->remaining = readlen;
346251877Speter    databuf->status = status;
347251877Speter
348251877Speter    return APR_SUCCESS;
349251877Speter}
350251877Speter
351251877Speter
352251877Speterapr_status_t serf_databuf_read(
353251877Speter    serf_databuf_t *databuf,
354251877Speter    apr_size_t requested,
355251877Speter    const char **data,
356251877Speter    apr_size_t *len)
357251877Speter{
358251877Speter    apr_status_t status = common_databuf_prep(databuf, len);
359251877Speter    if (status)
360251877Speter        return status;
361251877Speter
362251877Speter    /* peg the requested amount to what we have remaining */
363251877Speter    if (requested == SERF_READ_ALL_AVAIL || requested > databuf->remaining)
364251877Speter        requested = databuf->remaining;
365251877Speter
366251877Speter    /* return the values */
367251877Speter    *data = databuf->current;
368251877Speter    *len = requested;
369251877Speter
370251877Speter    /* adjust our internal state to note we've consumed some data */
371251877Speter    databuf->current += requested;
372251877Speter    databuf->remaining -= requested;
373251877Speter
374251877Speter    /* If we read everything, then we need to return whatever the data
375251877Speter     * read returned to us. This is going to be APR_EOF or APR_EGAIN.
376251877Speter     * If we have NOT read everything, then return APR_SUCCESS to indicate
377251877Speter     * that we're ready to return some more if asked.
378251877Speter     */
379251877Speter    return databuf->remaining ? APR_SUCCESS : databuf->status;
380251877Speter}
381251877Speter
382251877Speter
383251877Speterapr_status_t serf_databuf_readline(
384251877Speter    serf_databuf_t *databuf,
385251877Speter    int acceptable,
386251877Speter    int *found,
387251877Speter    const char **data,
388251877Speter    apr_size_t *len)
389251877Speter{
390251877Speter    apr_status_t status = common_databuf_prep(databuf, len);
391251877Speter    if (status)
392251877Speter        return status;
393251877Speter
394251877Speter    /* the returned line will start at the current position. */
395251877Speter    *data = databuf->current;
396251877Speter
397251877Speter    /* read a line from the buffer, and adjust the various pointers. */
398251877Speter    serf_util_readline(&databuf->current, &databuf->remaining, acceptable,
399251877Speter                       found);
400251877Speter
401251877Speter    /* the length matches the amount consumed by the readline */
402251877Speter    *len = databuf->current - *data;
403251877Speter
404251877Speter    /* see serf_databuf_read's return condition */
405251877Speter    return databuf->remaining ? APR_SUCCESS : databuf->status;
406251877Speter}
407251877Speter
408251877Speter
409251877Speterapr_status_t serf_databuf_peek(
410251877Speter    serf_databuf_t *databuf,
411251877Speter    const char **data,
412251877Speter    apr_size_t *len)
413251877Speter{
414251877Speter    apr_status_t status = common_databuf_prep(databuf, len);
415251877Speter    if (status)
416251877Speter        return status;
417251877Speter
418251877Speter    /* return everything we have */
419251877Speter    *data = databuf->current;
420251877Speter    *len = databuf->remaining;
421251877Speter
422251877Speter    /* If the last read returned EOF, then the peek should return the same.
423251877Speter     * The other possibility in databuf->status is APR_EAGAIN, which we
424251877Speter     * should never return. Thus, just return APR_SUCCESS for non-EOF cases.
425251877Speter     */
426251877Speter    if (APR_STATUS_IS_EOF(databuf->status))
427251877Speter        return APR_EOF;
428251877Speter    return APR_SUCCESS;
429251877Speter}
430251877Speter
431251877Speter
432251877Speter/* ==================================================================== */
433251877Speter
434251877Speter
435251877Spetervoid serf_linebuf_init(serf_linebuf_t *linebuf)
436251877Speter{
437251877Speter    linebuf->state = SERF_LINEBUF_EMPTY;
438251877Speter    linebuf->used = 0;
439251877Speter}
440251877Speter
441251877Speter
442251877Speterapr_status_t serf_linebuf_fetch(
443251877Speter    serf_linebuf_t *linebuf,
444251877Speter    serf_bucket_t *bucket,
445251877Speter    int acceptable)
446251877Speter{
447251877Speter    /* If we had a complete line, then assume the caller has used it, so
448251877Speter     * we can now reset the state.
449251877Speter     */
450251877Speter    if (linebuf->state == SERF_LINEBUF_READY) {
451251877Speter        linebuf->state = SERF_LINEBUF_EMPTY;
452251877Speter
453251877Speter        /* Reset the line_used, too, so we don't have to test the state
454251877Speter         * before using this value.
455251877Speter         */
456251877Speter        linebuf->used = 0;
457251877Speter    }
458251877Speter
459251877Speter    while (1) {
460251877Speter        apr_status_t status;
461251877Speter        const char *data;
462251877Speter        apr_size_t len;
463251877Speter
464251877Speter        if (linebuf->state == SERF_LINEBUF_CRLF_SPLIT) {
465251877Speter            /* On the previous read, we received just a CR. The LF might
466251877Speter             * be present, but the bucket couldn't see it. We need to
467251877Speter             * examine a single character to determine how to handle the
468251877Speter             * split CRLF.
469251877Speter             */
470251877Speter
471251877Speter            status = serf_bucket_peek(bucket, &data, &len);
472251877Speter            if (SERF_BUCKET_READ_ERROR(status))
473251877Speter                return status;
474251877Speter
475251877Speter            if (len > 0) {
476251877Speter                if (*data == '\n') {
477251877Speter                    /* We saw the second part of CRLF. We don't need to
478251877Speter                     * save that character, so do an actual read to suck
479251877Speter                     * up that character.
480251877Speter                     */
481251877Speter                    /* ### check status */
482251877Speter                    (void) serf_bucket_read(bucket, 1, &data, &len);
483251877Speter                }
484251877Speter                /* else:
485251877Speter                 *   We saw the first character of the next line. Thus,
486251877Speter                 *   the current line is terminated by the CR. Just
487251877Speter                 *   ignore whatever we peeked at. The next reader will
488251877Speter                 *   see it and handle it as appropriate.
489251877Speter                 */
490251877Speter
491251877Speter                /* Whatever was read, the line is now ready for use. */
492251877Speter                linebuf->state = SERF_LINEBUF_READY;
493251877Speter            } else {
494251877Speter                /* no data available, try again later. */
495251877Speter                return APR_EAGAIN;
496251877Speter            }
497251877Speter        }
498251877Speter        else {
499251877Speter            int found;
500251877Speter
501251877Speter            status = serf_bucket_readline(bucket, acceptable, &found,
502251877Speter                                          &data, &len);
503251877Speter            if (SERF_BUCKET_READ_ERROR(status)) {
504251877Speter                return status;
505251877Speter            }
506251877Speter            /* Some bucket types (socket) might need an extra read to find
507251877Speter               out EOF state, so they'll return no data in that read. This
508251877Speter               means we're done reading, return what we got. */
509251877Speter            if (APR_STATUS_IS_EOF(status) && len == 0) {
510251877Speter	        return status;
511251877Speter            }
512251877Speter            if (linebuf->used + len > sizeof(linebuf->line)) {
513251877Speter                /* ### need a "line too long" error */
514251877Speter                return APR_EGENERAL;
515251877Speter            }
516251877Speter
517251877Speter            /* Note: our logic doesn't change for SERF_LINEBUF_PARTIAL. That
518251877Speter             * only affects how we fill the buffer. It is a communication to
519251877Speter             * our caller on whether the line is ready or not.
520251877Speter             */
521251877Speter
522251877Speter            /* If we didn't see a newline, then we should mark the line
523251877Speter             * buffer as partially complete.
524251877Speter             */
525251877Speter            if (found == SERF_NEWLINE_NONE) {
526251877Speter                linebuf->state = SERF_LINEBUF_PARTIAL;
527251877Speter            }
528251877Speter            else if (found == SERF_NEWLINE_CRLF_SPLIT) {
529251877Speter                linebuf->state = SERF_LINEBUF_CRLF_SPLIT;
530251877Speter
531251877Speter                /* Toss the partial CR. We won't ever need it. */
532251877Speter                --len;
533251877Speter            }
534251877Speter            else {
535251877Speter                /* We got a newline (of some form). We don't need it
536251877Speter                 * in the line buffer, so back up the length. Then
537251877Speter                 * mark the line as ready.
538251877Speter                 */
539251877Speter                len -= 1 + (found == SERF_NEWLINE_CRLF);
540251877Speter
541251877Speter                linebuf->state = SERF_LINEBUF_READY;
542251877Speter            }
543251877Speter
544251877Speter            /* ### it would be nice to avoid this copy if at all possible,
545251877Speter               ### and just return the a data/len pair to the caller. we're
546251877Speter               ### keeping it simple for now. */
547251877Speter            memcpy(&linebuf->line[linebuf->used], data, len);
548251877Speter            linebuf->used += len;
549251877Speter        }
550251877Speter
551251877Speter        /* If we saw anything besides "success. please read again", then
552251877Speter         * we should return that status. If the line was completed, then
553251877Speter         * we should also return.
554251877Speter         */
555251877Speter        if (status || linebuf->state == SERF_LINEBUF_READY)
556251877Speter            return status;
557251877Speter
558251877Speter        /* We got APR_SUCCESS and the line buffer is not complete. Let's
559251877Speter         * loop to read some more data.
560251877Speter         */
561251877Speter    }
562251877Speter    /* NOTREACHED */
563251877Speter}
564251877Speter
565251877Speter/* Logging functions.
566251877Speter   Use with one of the [COMP]_VERBOSE defines so that the compiler knows to
567251877Speter   optimize this code out when no logging is needed. */
568251877Speterstatic void log_time()
569251877Speter{
570251877Speter    apr_time_exp_t tm;
571251877Speter
572251877Speter    apr_time_exp_lt(&tm, apr_time_now());
573251877Speter    fprintf(stderr, "[%d-%02d-%02dT%02d:%02d:%02d.%06d%+03d] ",
574251877Speter            1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday,
575251877Speter            tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec,
576251877Speter            tm.tm_gmtoff/3600);
577251877Speter}
578251877Speter
579251877Spetervoid serf__log(int verbose_flag, const char *filename, const char *fmt, ...)
580251877Speter{
581251877Speter    va_list argp;
582251877Speter
583251877Speter    if (verbose_flag) {
584251877Speter        log_time();
585251877Speter
586251877Speter        if (filename)
587251877Speter            fprintf(stderr, "%s: ", filename);
588251877Speter
589251877Speter        va_start(argp, fmt);
590251877Speter        vfprintf(stderr, fmt, argp);
591251877Speter        va_end(argp);
592251877Speter    }
593251877Speter}
594251877Speter
595251877Spetervoid serf__log_nopref(int verbose_flag, const char *fmt, ...)
596251877Speter{
597251877Speter    va_list argp;
598251877Speter
599251877Speter    if (verbose_flag) {
600251877Speter        va_start(argp, fmt);
601251877Speter        vfprintf(stderr, fmt, argp);
602251877Speter        va_end(argp);
603251877Speter    }
604251877Speter}
605251877Speter
606251877Spetervoid serf__log_skt(int verbose_flag, const char *filename, apr_socket_t *skt,
607251877Speter                   const char *fmt, ...)
608251877Speter{
609251877Speter    va_list argp;
610251877Speter
611251877Speter    if (verbose_flag) {
612251877Speter        apr_sockaddr_t *sa;
613251877Speter        log_time();
614251877Speter
615251877Speter        if (skt) {
616251877Speter            /* Log local and remote ip address:port */
617251877Speter            fprintf(stderr, "[l:");
618251877Speter            if (apr_socket_addr_get(&sa, APR_LOCAL, skt) == APR_SUCCESS) {
619251877Speter                char buf[32];
620251877Speter                apr_sockaddr_ip_getbuf(buf, 32, sa);
621251877Speter                fprintf(stderr, "%s:%d", buf, sa->port);
622251877Speter            }
623251877Speter            fprintf(stderr, " r:");
624251877Speter            if (apr_socket_addr_get(&sa, APR_REMOTE, skt) == APR_SUCCESS) {
625251877Speter                char buf[32];
626251877Speter                apr_sockaddr_ip_getbuf(buf, 32, sa);
627251877Speter                fprintf(stderr, "%s:%d", buf, sa->port);
628251877Speter            }
629251877Speter            fprintf(stderr, "] ");
630251877Speter        }
631251877Speter
632251877Speter        if (filename)
633251877Speter            fprintf(stderr, "%s: ", filename);
634251877Speter
635251877Speter        va_start(argp, fmt);
636251877Speter        vfprintf(stderr, fmt, argp);
637251877Speter        va_end(argp);
638251877Speter    }
639251877Speter}
640251877Speter
641