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