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