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