outgoing.c revision 253895
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#include <apr_poll.h> 18251877Speter#include <apr_version.h> 19253895Speter#include <apr_portable.h> 20251877Speter 21251877Speter#include "serf.h" 22251877Speter#include "serf_bucket_util.h" 23251877Speter 24251877Speter#include "serf_private.h" 25251877Speter 26251877Speter/* cleanup for sockets */ 27251877Speterstatic apr_status_t clean_skt(void *data) 28251877Speter{ 29251877Speter serf_connection_t *conn = data; 30251877Speter apr_status_t status = APR_SUCCESS; 31251877Speter 32251877Speter if (conn->skt) { 33251877Speter serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, "cleanup - "); 34251877Speter status = apr_socket_close(conn->skt); 35251877Speter conn->skt = NULL; 36251877Speter serf__log_nopref(SOCK_VERBOSE, "closed socket, status %d\n", status); 37251877Speter } 38251877Speter 39251877Speter return status; 40251877Speter} 41251877Speter 42251877Speterstatic apr_status_t clean_resp(void *data) 43251877Speter{ 44251877Speter serf_request_t *request = data; 45251877Speter 46251877Speter /* The request's RESPOOL is being cleared. */ 47251877Speter 48251877Speter /* If the response has allocated some buckets, then destroy them (since 49251877Speter the bucket may hold resources other than memory in RESPOOL). Also 50251877Speter make sure to set their fields to NULL so connection closure does 51251877Speter not attempt to free them again. */ 52251877Speter if (request->resp_bkt) { 53251877Speter serf_bucket_destroy(request->resp_bkt); 54251877Speter request->resp_bkt = NULL; 55251877Speter } 56251877Speter if (request->req_bkt) { 57251877Speter serf_bucket_destroy(request->req_bkt); 58251877Speter request->req_bkt = NULL; 59251877Speter } 60251877Speter 61251877Speter /* ### should we worry about debug stuff, like that performed in 62251877Speter ### destroy_request()? should we worry about calling req->handler 63251877Speter ### to notify this "cancellation" due to pool clearing? */ 64251877Speter 65251877Speter /* This pool just got cleared/destroyed. Don't try to destroy the pool 66251877Speter (again) when the request is canceled. */ 67251877Speter request->respool = NULL; 68251877Speter 69251877Speter return APR_SUCCESS; 70251877Speter} 71251877Speter 72251877Speter/* cleanup for conns */ 73251877Speterstatic apr_status_t clean_conn(void *data) 74251877Speter{ 75251877Speter serf_connection_t *conn = data; 76251877Speter 77251877Speter serf__log(CONN_VERBOSE, __FILE__, "cleaning up connection 0x%x\n", 78251877Speter conn); 79251877Speter serf_connection_close(conn); 80251877Speter 81251877Speter return APR_SUCCESS; 82251877Speter} 83251877Speter 84251877Speter/* Update the pollset for this connection. We tweak the pollset based on 85251877Speter * whether we want to read and/or write, given conditions within the 86251877Speter * connection. If the connection is not (yet) in the pollset, then it 87251877Speter * will be added. 88251877Speter */ 89251877Speterapr_status_t serf__conn_update_pollset(serf_connection_t *conn) 90251877Speter{ 91251877Speter serf_context_t *ctx = conn->ctx; 92251877Speter apr_status_t status; 93251877Speter apr_pollfd_t desc = { 0 }; 94251877Speter 95251877Speter if (!conn->skt) { 96251877Speter return APR_SUCCESS; 97251877Speter } 98251877Speter 99251877Speter /* Remove the socket from the poll set. */ 100251877Speter desc.desc_type = APR_POLL_SOCKET; 101251877Speter desc.desc.s = conn->skt; 102251877Speter desc.reqevents = conn->reqevents; 103251877Speter 104251877Speter status = ctx->pollset_rm(ctx->pollset_baton, 105251877Speter &desc, conn); 106251877Speter if (status && !APR_STATUS_IS_NOTFOUND(status)) 107251877Speter return status; 108251877Speter 109251877Speter /* Now put it back in with the correct read/write values. */ 110251877Speter desc.reqevents = APR_POLLHUP | APR_POLLERR; 111251877Speter if (conn->requests && 112251877Speter conn->state != SERF_CONN_INIT) { 113251877Speter /* If there are any outstanding events, then we want to read. */ 114251877Speter /* ### not true. we only want to read IF we have sent some data */ 115251877Speter desc.reqevents |= APR_POLLIN; 116251877Speter 117253895Speter /* Don't write if OpenSSL told us that it needs to read data first. */ 118253895Speter if (conn->stop_writing != 1) { 119251877Speter 120253895Speter /* If the connection is not closing down and 121253895Speter * has unwritten data or 122253895Speter * there are any requests that still have buckets to write out, 123253895Speter * then we want to write. 124253895Speter */ 125253895Speter if (conn->vec_len && 126253895Speter conn->state != SERF_CONN_CLOSING) 127253895Speter desc.reqevents |= APR_POLLOUT; 128253895Speter else { 129253895Speter serf_request_t *request = conn->requests; 130253895Speter 131253895Speter if ((conn->probable_keepalive_limit && 132253895Speter conn->completed_requests > conn->probable_keepalive_limit) || 133253895Speter (conn->max_outstanding_requests && 134253895Speter conn->completed_requests - conn->completed_responses >= 135251877Speter conn->max_outstanding_requests)) { 136253895Speter /* we wouldn't try to write any way right now. */ 137253895Speter } 138253895Speter else { 139253895Speter while (request != NULL && request->req_bkt == NULL && 140253895Speter request->written) 141253895Speter request = request->next; 142253895Speter if (request != NULL) 143253895Speter desc.reqevents |= APR_POLLOUT; 144253895Speter } 145251877Speter } 146251877Speter } 147251877Speter } 148251877Speter 149251877Speter /* If we can have async responses, always look for something to read. */ 150251877Speter if (conn->async_responses) { 151251877Speter desc.reqevents |= APR_POLLIN; 152251877Speter } 153251877Speter 154251877Speter /* save our reqevents, so we can pass it in to remove later. */ 155251877Speter conn->reqevents = desc.reqevents; 156251877Speter 157251877Speter /* Note: even if we don't want to read/write this socket, we still 158251877Speter * want to poll it for hangups and errors. 159251877Speter */ 160251877Speter return ctx->pollset_add(ctx->pollset_baton, 161251877Speter &desc, &conn->baton); 162251877Speter} 163251877Speter 164251877Speter#ifdef SERF_DEBUG_BUCKET_USE 165251877Speter 166251877Speter/* Make sure all response buckets were drained. */ 167251877Speterstatic void check_buckets_drained(serf_connection_t *conn) 168251877Speter{ 169251877Speter serf_request_t *request = conn->requests; 170251877Speter 171251877Speter for ( ; request ; request = request->next ) { 172251877Speter if (request->resp_bkt != NULL) { 173251877Speter /* ### crap. can't do this. this allocator may have un-drained 174251877Speter * ### REQUEST buckets. 175251877Speter */ 176251877Speter /* serf_debug__entered_loop(request->resp_bkt->allocator); */ 177251877Speter /* ### for now, pretend we closed the conn (resets the tracking) */ 178251877Speter serf_debug__closed_conn(request->resp_bkt->allocator); 179251877Speter } 180251877Speter } 181251877Speter} 182251877Speter 183251877Speter#endif 184251877Speter 185253895Speterstatic void destroy_ostream(serf_connection_t *conn) 186253895Speter{ 187253895Speter if (conn->ostream_head != NULL) { 188253895Speter serf_bucket_destroy(conn->ostream_head); 189253895Speter conn->ostream_head = NULL; 190253895Speter conn->ostream_tail = NULL; 191253895Speter } 192253895Speter} 193253895Speter 194253895Speterstatic apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket) 195253895Speter{ 196253895Speter serf_connection_t *conn = baton; 197253895Speter conn->hit_eof = 1; 198253895Speter return APR_EAGAIN; 199253895Speter} 200253895Speter 201253895Speterstatic apr_status_t do_conn_setup(serf_connection_t *conn) 202253895Speter{ 203253895Speter apr_status_t status; 204253895Speter serf_bucket_t *ostream; 205253895Speter 206253895Speter if (conn->ostream_head == NULL) { 207253895Speter conn->ostream_head = serf_bucket_aggregate_create(conn->allocator); 208253895Speter } 209253895Speter 210253895Speter if (conn->ostream_tail == NULL) { 211253895Speter conn->ostream_tail = serf__bucket_stream_create(conn->allocator, 212253895Speter detect_eof, 213253895Speter conn); 214253895Speter } 215253895Speter 216253895Speter ostream = conn->ostream_tail; 217253895Speter 218253895Speter status = (*conn->setup)(conn->skt, 219253895Speter &conn->stream, 220253895Speter &ostream, 221253895Speter conn->setup_baton, 222253895Speter conn->pool); 223253895Speter if (status) { 224253895Speter /* extra destroy here since it wasn't added to the head bucket yet. */ 225253895Speter serf_bucket_destroy(conn->ostream_tail); 226253895Speter destroy_ostream(conn); 227253895Speter return status; 228253895Speter } 229253895Speter 230253895Speter serf_bucket_aggregate_append(conn->ostream_head, 231253895Speter ostream); 232253895Speter 233253895Speter return status; 234253895Speter} 235253895Speter 236253895Speter/* Set up the input and output stream buckets. 237253895Speter When a tunnel over an http proxy is needed, create a socket bucket and 238253895Speter empty aggregate bucket for sending and receiving unencrypted requests 239253895Speter over the socket. 240253895Speter 241253895Speter After the tunnel is there, or no tunnel was needed, ask the application 242253895Speter to create the input and output buckets, which should take care of the 243253895Speter [en/de]cryption. 244253895Speter */ 245253895Speter 246253895Speterstatic apr_status_t prepare_conn_streams(serf_connection_t *conn, 247253895Speter serf_bucket_t **istream, 248253895Speter serf_bucket_t **ostreamt, 249253895Speter serf_bucket_t **ostreamh) 250253895Speter{ 251253895Speter apr_status_t status; 252253895Speter 253253895Speter if (conn->stream == NULL) { 254253895Speter conn->latency = apr_time_now() - conn->connect_time; 255253895Speter } 256253895Speter 257253895Speter /* Do we need a SSL tunnel first? */ 258253895Speter if (conn->state == SERF_CONN_CONNECTED) { 259253895Speter /* If the connection does not have an associated bucket, then 260253895Speter * call the setup callback to get one. 261253895Speter */ 262253895Speter if (conn->stream == NULL) { 263253895Speter status = do_conn_setup(conn); 264253895Speter if (status) { 265253895Speter return status; 266253895Speter } 267253895Speter } 268253895Speter *ostreamt = conn->ostream_tail; 269253895Speter *ostreamh = conn->ostream_head; 270253895Speter *istream = conn->stream; 271253895Speter } else { 272253895Speter /* SSL tunnel needed and not set up yet, get a direct unencrypted 273253895Speter stream for this socket */ 274253895Speter if (conn->stream == NULL) { 275253895Speter *istream = serf_bucket_socket_create(conn->skt, 276253895Speter conn->allocator); 277253895Speter } 278253895Speter /* Don't create the ostream bucket chain including the ssl_encrypt 279253895Speter bucket yet. This ensure the CONNECT request is sent unencrypted 280253895Speter to the proxy. */ 281253895Speter *ostreamt = *ostreamh = conn->ssltunnel_ostream; 282253895Speter } 283253895Speter 284253895Speter return APR_SUCCESS; 285253895Speter} 286253895Speter 287251877Speter/* Create and connect sockets for any connections which don't have them 288251877Speter * yet. This is the core of our lazy-connect behavior. 289251877Speter */ 290251877Speterapr_status_t serf__open_connections(serf_context_t *ctx) 291251877Speter{ 292251877Speter int i; 293251877Speter 294251877Speter for (i = ctx->conns->nelts; i--; ) { 295251877Speter serf_connection_t *conn = GET_CONN(ctx, i); 296253895Speter serf__authn_info_t *authn_info; 297251877Speter apr_status_t status; 298251877Speter apr_socket_t *skt; 299251877Speter 300251877Speter conn->seen_in_pollset = 0; 301251877Speter 302251877Speter if (conn->skt != NULL) { 303251877Speter#ifdef SERF_DEBUG_BUCKET_USE 304251877Speter check_buckets_drained(conn); 305251877Speter#endif 306251877Speter continue; 307251877Speter } 308251877Speter 309251877Speter /* Delay opening until we have something to deliver! */ 310251877Speter if (conn->requests == NULL) { 311251877Speter continue; 312251877Speter } 313251877Speter 314251877Speter apr_pool_clear(conn->skt_pool); 315251877Speter apr_pool_cleanup_register(conn->skt_pool, conn, clean_skt, clean_skt); 316251877Speter 317251877Speter status = apr_socket_create(&skt, conn->address->family, 318251877Speter SOCK_STREAM, 319251877Speter#if APR_MAJOR_VERSION > 0 320251877Speter APR_PROTO_TCP, 321251877Speter#endif 322251877Speter conn->skt_pool); 323251877Speter serf__log(SOCK_VERBOSE, __FILE__, 324251877Speter "created socket for conn 0x%x, status %d\n", conn, status); 325251877Speter if (status != APR_SUCCESS) 326251877Speter return status; 327251877Speter 328251877Speter /* Set the socket to be non-blocking */ 329251877Speter if ((status = apr_socket_timeout_set(skt, 0)) != APR_SUCCESS) 330251877Speter return status; 331251877Speter 332251877Speter /* Disable Nagle's algorithm */ 333251877Speter if ((status = apr_socket_opt_set(skt, 334251877Speter APR_TCP_NODELAY, 1)) != APR_SUCCESS) 335251877Speter return status; 336251877Speter 337251877Speter /* Configured. Store it into the connection now. */ 338251877Speter conn->skt = skt; 339251877Speter 340251877Speter /* Remember time when we started connecting to server to calculate 341251877Speter network latency. */ 342251877Speter conn->connect_time = apr_time_now(); 343251877Speter 344251877Speter /* Now that the socket is set up, let's connect it. This should 345251877Speter * return immediately. 346251877Speter */ 347251877Speter status = apr_socket_connect(skt, conn->address); 348251877Speter serf__log_skt(SOCK_VERBOSE, __FILE__, skt, 349251877Speter "connected socket for conn 0x%x, status %d\n", 350251877Speter conn, status); 351253895Speter if (status != APR_SUCCESS) { 352251877Speter if (!APR_STATUS_IS_EINPROGRESS(status)) 353251877Speter return status; 354251877Speter } 355251877Speter 356251877Speter /* Flag our pollset as dirty now that we have a new socket. */ 357251877Speter conn->dirty_conn = 1; 358251877Speter ctx->dirty_pollset = 1; 359251877Speter 360251877Speter /* If the authentication was already started on another connection, 361251877Speter prepare this connection (it might be possible to skip some 362251877Speter part of the handshaking). */ 363251877Speter if (ctx->proxy_address) { 364253895Speter authn_info = &ctx->proxy_authn_info; 365253895Speter if (authn_info->scheme) { 366253895Speter authn_info->scheme->init_conn_func(authn_info->scheme, 407, 367253895Speter conn, conn->pool); 368253895Speter } 369251877Speter } 370251877Speter 371253895Speter authn_info = serf__get_authn_info_for_server(conn); 372253895Speter if (authn_info->scheme) { 373253895Speter authn_info->scheme->init_conn_func(authn_info->scheme, 401, 374253895Speter conn, conn->pool); 375253895Speter } 376251877Speter 377251877Speter /* Does this connection require a SSL tunnel over the proxy? */ 378251877Speter if (ctx->proxy_address && strcmp(conn->host_info.scheme, "https") == 0) 379251877Speter serf__ssltunnel_connect(conn); 380253895Speter else { 381253895Speter serf_bucket_t *dummy1, *dummy2; 382253895Speter 383251877Speter conn->state = SERF_CONN_CONNECTED; 384251877Speter 385253895Speter status = prepare_conn_streams(conn, &conn->stream, 386253895Speter &dummy1, &dummy2); 387253895Speter if (status) { 388253895Speter return status; 389253895Speter } 390253895Speter } 391251877Speter } 392251877Speter 393251877Speter return APR_SUCCESS; 394251877Speter} 395251877Speter 396251877Speterstatic apr_status_t no_more_writes(serf_connection_t *conn, 397251877Speter serf_request_t *request) 398251877Speter{ 399251877Speter /* Note that we should hold new requests until we open our new socket. */ 400251877Speter conn->state = SERF_CONN_CLOSING; 401251877Speter serf__log(CONN_VERBOSE, __FILE__, "stop writing on conn 0x%x\n", 402251877Speter conn); 403251877Speter 404251877Speter /* Clear our iovec. */ 405251877Speter conn->vec_len = 0; 406251877Speter 407251877Speter /* Update the pollset to know we don't want to write on this socket any 408251877Speter * more. 409251877Speter */ 410251877Speter conn->dirty_conn = 1; 411251877Speter conn->ctx->dirty_pollset = 1; 412251877Speter return APR_SUCCESS; 413251877Speter} 414251877Speter 415251877Speter/* Read the 'Connection' header from the response. Return SERF_ERROR_CLOSING if 416251877Speter * the header contains value 'close' indicating the server is closing the 417251877Speter * connection right after this response. 418251877Speter * Otherwise returns APR_SUCCESS. 419251877Speter */ 420251877Speterstatic apr_status_t is_conn_closing(serf_bucket_t *response) 421251877Speter{ 422251877Speter serf_bucket_t *hdrs; 423251877Speter const char *val; 424251877Speter 425251877Speter hdrs = serf_bucket_response_get_headers(response); 426251877Speter val = serf_bucket_headers_get(hdrs, "Connection"); 427251877Speter if (val && strcasecmp("close", val) == 0) 428251877Speter { 429251877Speter return SERF_ERROR_CLOSING; 430251877Speter } 431251877Speter 432251877Speter return APR_SUCCESS; 433251877Speter} 434251877Speter 435251877Speterstatic void link_requests(serf_request_t **list, serf_request_t **tail, 436251877Speter serf_request_t *request) 437251877Speter{ 438251877Speter if (*list == NULL) { 439251877Speter *list = request; 440251877Speter *tail = request; 441251877Speter } 442251877Speter else { 443251877Speter (*tail)->next = request; 444251877Speter *tail = request; 445251877Speter } 446251877Speter} 447251877Speter 448251877Speterstatic apr_status_t destroy_request(serf_request_t *request) 449251877Speter{ 450251877Speter serf_connection_t *conn = request->conn; 451251877Speter 452251877Speter /* The request and response buckets are no longer needed, 453251877Speter nor is the request's pool. */ 454251877Speter if (request->resp_bkt) { 455251877Speter serf_debug__closed_conn(request->resp_bkt->allocator); 456251877Speter serf_bucket_destroy(request->resp_bkt); 457251877Speter request->resp_bkt = NULL; 458251877Speter } 459251877Speter if (request->req_bkt) { 460251877Speter serf_debug__closed_conn(request->req_bkt->allocator); 461251877Speter serf_bucket_destroy(request->req_bkt); 462251877Speter request->req_bkt = NULL; 463251877Speter } 464251877Speter 465251877Speter serf_debug__bucket_alloc_check(request->allocator); 466251877Speter if (request->respool) { 467251877Speter /* ### unregister the pool cleanup for self? */ 468251877Speter apr_pool_destroy(request->respool); 469251877Speter } 470251877Speter 471251877Speter serf_bucket_mem_free(conn->allocator, request); 472251877Speter 473251877Speter return APR_SUCCESS; 474251877Speter} 475251877Speter 476251877Speterstatic apr_status_t cancel_request(serf_request_t *request, 477251877Speter serf_request_t **list, 478251877Speter int notify_request) 479251877Speter{ 480251877Speter /* If we haven't run setup, then we won't have a handler to call. */ 481251877Speter if (request->handler && notify_request) { 482251877Speter /* We actually don't care what the handler returns. 483251877Speter * We have bigger matters at hand. 484251877Speter */ 485251877Speter (*request->handler)(request, NULL, request->handler_baton, 486251877Speter request->respool); 487251877Speter } 488251877Speter 489251877Speter if (*list == request) { 490251877Speter *list = request->next; 491251877Speter } 492251877Speter else { 493251877Speter serf_request_t *scan = *list; 494251877Speter 495251877Speter while (scan->next && scan->next != request) 496251877Speter scan = scan->next; 497251877Speter 498251877Speter if (scan->next) { 499251877Speter scan->next = scan->next->next; 500251877Speter } 501251877Speter } 502251877Speter 503251877Speter return destroy_request(request); 504251877Speter} 505251877Speter 506251877Speterstatic apr_status_t remove_connection(serf_context_t *ctx, 507251877Speter serf_connection_t *conn) 508251877Speter{ 509251877Speter apr_pollfd_t desc = { 0 }; 510251877Speter 511251877Speter desc.desc_type = APR_POLL_SOCKET; 512251877Speter desc.desc.s = conn->skt; 513251877Speter desc.reqevents = conn->reqevents; 514251877Speter 515251877Speter return ctx->pollset_rm(ctx->pollset_baton, 516251877Speter &desc, conn); 517251877Speter} 518251877Speter 519251877Speter/* A socket was closed, inform the application. */ 520251877Speterstatic void handle_conn_closed(serf_connection_t *conn, apr_status_t status) 521251877Speter{ 522251877Speter (*conn->closed)(conn, conn->closed_baton, status, 523251877Speter conn->pool); 524251877Speter} 525251877Speter 526251877Speterstatic apr_status_t reset_connection(serf_connection_t *conn, 527251877Speter int requeue_requests) 528251877Speter{ 529251877Speter serf_context_t *ctx = conn->ctx; 530251877Speter apr_status_t status; 531251877Speter serf_request_t *old_reqs; 532251877Speter 533251877Speter conn->probable_keepalive_limit = conn->completed_responses; 534251877Speter conn->completed_requests = 0; 535251877Speter conn->completed_responses = 0; 536251877Speter 537251877Speter old_reqs = conn->requests; 538251877Speter 539251877Speter conn->requests = NULL; 540251877Speter conn->requests_tail = NULL; 541251877Speter 542251877Speter /* Handle all outstanding requests. These have either not been written yet, 543251877Speter or have been written but the expected reply wasn't received yet. */ 544251877Speter while (old_reqs) { 545251877Speter /* If we haven't started to write the connection, bring it over 546251877Speter * unchanged to our new socket. 547251877Speter */ 548251877Speter if (requeue_requests && !old_reqs->written) { 549251877Speter serf_request_t *req = old_reqs; 550251877Speter old_reqs = old_reqs->next; 551251877Speter req->next = NULL; 552251877Speter link_requests(&conn->requests, &conn->requests_tail, req); 553251877Speter } 554251877Speter else { 555251877Speter /* Request has been consumed, or we don't want to requeue the 556251877Speter request. Either way, inform the application that the request 557251877Speter is cancelled. */ 558251877Speter cancel_request(old_reqs, &old_reqs, requeue_requests); 559251877Speter } 560251877Speter } 561251877Speter 562251877Speter /* Requests queue has been prepared for a new socket, close the old one. */ 563251877Speter if (conn->skt != NULL) { 564251877Speter remove_connection(ctx, conn); 565251877Speter status = apr_socket_close(conn->skt); 566251877Speter serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, 567251877Speter "closed socket, status %d\n", status); 568251877Speter if (conn->closed != NULL) { 569251877Speter handle_conn_closed(conn, status); 570251877Speter } 571251877Speter conn->skt = NULL; 572251877Speter } 573251877Speter 574251877Speter if (conn->stream != NULL) { 575251877Speter serf_bucket_destroy(conn->stream); 576251877Speter conn->stream = NULL; 577251877Speter } 578251877Speter 579251877Speter destroy_ostream(conn); 580251877Speter 581251877Speter /* Don't try to resume any writes */ 582251877Speter conn->vec_len = 0; 583251877Speter 584251877Speter conn->dirty_conn = 1; 585251877Speter conn->ctx->dirty_pollset = 1; 586251877Speter conn->state = SERF_CONN_INIT; 587251877Speter 588251877Speter serf__log(CONN_VERBOSE, __FILE__, "reset connection 0x%x\n", conn); 589251877Speter 590251877Speter conn->status = APR_SUCCESS; 591251877Speter 592251877Speter /* Let our context know that we've 'reset' the socket already. */ 593251877Speter conn->seen_in_pollset |= APR_POLLHUP; 594251877Speter 595251877Speter /* Found the connection. Closed it. All done. */ 596251877Speter return APR_SUCCESS; 597251877Speter} 598251877Speter 599251877Speterstatic apr_status_t socket_writev(serf_connection_t *conn) 600251877Speter{ 601251877Speter apr_size_t written; 602251877Speter apr_status_t status; 603251877Speter 604251877Speter status = apr_socket_sendv(conn->skt, conn->vec, 605251877Speter conn->vec_len, &written); 606253895Speter if (status && !APR_STATUS_IS_EAGAIN(status)) 607251877Speter serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, 608251877Speter "socket_sendv error %d\n", status); 609251877Speter 610251877Speter /* did we write everything? */ 611251877Speter if (written) { 612251877Speter apr_size_t len = 0; 613251877Speter int i; 614251877Speter 615251877Speter serf__log_skt(SOCK_MSG_VERBOSE, __FILE__, conn->skt, 616251877Speter "--- socket_sendv:\n"); 617251877Speter 618251877Speter for (i = 0; i < conn->vec_len; i++) { 619251877Speter len += conn->vec[i].iov_len; 620251877Speter if (written < len) { 621251877Speter serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s", 622251877Speter conn->vec[i].iov_len - (len - written), 623251877Speter conn->vec[i].iov_base); 624251877Speter if (i) { 625251877Speter memmove(conn->vec, &conn->vec[i], 626251877Speter sizeof(struct iovec) * (conn->vec_len - i)); 627251877Speter conn->vec_len -= i; 628251877Speter } 629251877Speter conn->vec[0].iov_base = (char *)conn->vec[0].iov_base + (conn->vec[0].iov_len - (len - written)); 630251877Speter conn->vec[0].iov_len = len - written; 631251877Speter break; 632251877Speter } else { 633251877Speter serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s", 634251877Speter conn->vec[i].iov_len, conn->vec[i].iov_base); 635251877Speter } 636251877Speter } 637251877Speter if (len == written) { 638251877Speter conn->vec_len = 0; 639251877Speter } 640251877Speter serf__log_nopref(SOCK_MSG_VERBOSE, "-(%d)-\n", written); 641251877Speter 642251877Speter /* Log progress information */ 643251877Speter serf__context_progress_delta(conn->ctx, 0, written); 644251877Speter } 645251877Speter 646251877Speter return status; 647251877Speter} 648251877Speter 649253895Speterstatic apr_status_t setup_request(serf_request_t *request) 650251877Speter{ 651253895Speter serf_connection_t *conn = request->conn; 652251877Speter apr_status_t status; 653251877Speter 654253895Speter /* Now that we are about to serve the request, allocate a pool. */ 655253895Speter apr_pool_create(&request->respool, conn->pool); 656253895Speter request->allocator = serf_bucket_allocator_create(request->respool, 657253895Speter NULL, NULL); 658253895Speter apr_pool_cleanup_register(request->respool, request, 659253895Speter clean_resp, clean_resp); 660251877Speter 661253895Speter /* Fill in the rest of the values for the request. */ 662253895Speter status = request->setup(request, request->setup_baton, 663253895Speter &request->req_bkt, 664253895Speter &request->acceptor, 665253895Speter &request->acceptor_baton, 666253895Speter &request->handler, 667253895Speter &request->handler_baton, 668253895Speter request->respool); 669251877Speter return status; 670251877Speter} 671251877Speter 672251877Speter/* write data out to the connection */ 673251877Speterstatic apr_status_t write_to_connection(serf_connection_t *conn) 674251877Speter{ 675251877Speter serf_request_t *request = conn->requests; 676251877Speter 677251877Speter if (conn->probable_keepalive_limit && 678251877Speter conn->completed_requests > conn->probable_keepalive_limit) { 679251877Speter 680251877Speter conn->dirty_conn = 1; 681251877Speter conn->ctx->dirty_pollset = 1; 682251877Speter 683251877Speter /* backoff for now. */ 684251877Speter return APR_SUCCESS; 685251877Speter } 686251877Speter 687251877Speter /* Find a request that has data which needs to be delivered. */ 688251877Speter while (request != NULL && 689251877Speter request->req_bkt == NULL && request->written) 690251877Speter request = request->next; 691251877Speter 692251877Speter /* assert: request != NULL || conn->vec_len */ 693251877Speter 694251877Speter /* Keep reading and sending until we run out of stuff to read, or 695251877Speter * writing would block. 696251877Speter */ 697251877Speter while (1) { 698251877Speter int stop_reading = 0; 699251877Speter apr_status_t status; 700251877Speter apr_status_t read_status; 701251877Speter serf_bucket_t *ostreamt, *ostreamh; 702251877Speter int max_outstanding_requests = conn->max_outstanding_requests; 703251877Speter 704251877Speter /* If we're setting up an ssl tunnel, we can't send real requests 705251877Speter at yet, as they need to be encrypted and our encrypt buckets 706251877Speter aren't created yet as we still need to read the unencrypted 707251877Speter response of the CONNECT request. */ 708251877Speter if (conn->state != SERF_CONN_CONNECTED) 709251877Speter max_outstanding_requests = 1; 710251877Speter 711251877Speter if (max_outstanding_requests && 712251877Speter conn->completed_requests - 713251877Speter conn->completed_responses >= max_outstanding_requests) { 714251877Speter /* backoff for now. */ 715251877Speter return APR_SUCCESS; 716251877Speter } 717251877Speter 718251877Speter /* If we have unwritten data, then write what we can. */ 719251877Speter while (conn->vec_len) { 720251877Speter status = socket_writev(conn); 721251877Speter 722251877Speter /* If the write would have blocked, then we're done. Don't try 723251877Speter * to write anything else to the socket. 724251877Speter */ 725251877Speter if (APR_STATUS_IS_EAGAIN(status)) 726251877Speter return APR_SUCCESS; 727251877Speter if (APR_STATUS_IS_EPIPE(status) || 728251877Speter APR_STATUS_IS_ECONNRESET(status) || 729251877Speter APR_STATUS_IS_ECONNABORTED(status)) 730251877Speter return no_more_writes(conn, request); 731251877Speter if (status) 732251877Speter return status; 733251877Speter } 734251877Speter /* ### can we have a short write, yet no EAGAIN? a short write 735251877Speter ### would imply unwritten_len > 0 ... */ 736251877Speter /* assert: unwritten_len == 0. */ 737251877Speter 738251877Speter /* We may need to move forward to a request which has something 739251877Speter * to write. 740251877Speter */ 741251877Speter while (request != NULL && 742251877Speter request->req_bkt == NULL && request->written) 743251877Speter request = request->next; 744251877Speter 745251877Speter if (request == NULL) { 746251877Speter /* No more requests (with data) are registered with the 747251877Speter * connection. Let's update the pollset so that we don't 748251877Speter * try to write to this socket again. 749251877Speter */ 750251877Speter conn->dirty_conn = 1; 751251877Speter conn->ctx->dirty_pollset = 1; 752251877Speter return APR_SUCCESS; 753251877Speter } 754251877Speter 755251877Speter status = prepare_conn_streams(conn, &conn->stream, &ostreamt, &ostreamh); 756251877Speter if (status) { 757251877Speter return status; 758251877Speter } 759251877Speter 760251877Speter if (request->req_bkt == NULL) { 761253895Speter read_status = setup_request(request); 762251877Speter if (read_status) { 763251877Speter /* Something bad happened. Propagate any errors. */ 764251877Speter return read_status; 765251877Speter } 766253895Speter } 767251877Speter 768253895Speter if (!request->written) { 769251877Speter request->written = 1; 770251877Speter serf_bucket_aggregate_append(ostreamt, request->req_bkt); 771251877Speter } 772251877Speter 773251877Speter /* ### optimize at some point by using read_for_sendfile */ 774253895Speter /* TODO: now that read_iovec will effectively try to return as much 775253895Speter data as available, we probably don't want to read ALL_AVAIL, but 776253895Speter a lower number, like the size of one or a few TCP packets, the 777253895Speter available TCP buffer size ... */ 778251877Speter read_status = serf_bucket_read_iovec(ostreamh, 779251877Speter SERF_READ_ALL_AVAIL, 780251877Speter IOV_MAX, 781251877Speter conn->vec, 782251877Speter &conn->vec_len); 783251877Speter 784251877Speter if (!conn->hit_eof) { 785253895Speter if (APR_STATUS_IS_EAGAIN(read_status)) { 786251877Speter /* We read some stuff, but should not try to read again. */ 787251877Speter stop_reading = 1; 788253895Speter } 789253895Speter else if (read_status == SERF_ERROR_WAIT_CONN) { 790253895Speter /* The bucket told us that it can't provide more data until 791253895Speter more data is read from the socket. This normally happens 792253895Speter during a SSL handshake. 793251877Speter 794253895Speter We should avoid looking for writability for a while so 795253895Speter that (hopefully) something will appear in the bucket so 796253895Speter we can actually write something. otherwise, we could 797253895Speter end up in a CPU spin: socket wants something, but we 798253895Speter don't have anything (and keep returning EAGAIN) 799253895Speter */ 800253895Speter conn->stop_writing = 1; 801253895Speter conn->dirty_conn = 1; 802253895Speter conn->ctx->dirty_pollset = 1; 803251877Speter } 804251877Speter else if (read_status && !APR_STATUS_IS_EOF(read_status)) { 805251877Speter /* Something bad happened. Propagate any errors. */ 806251877Speter return read_status; 807251877Speter } 808251877Speter } 809251877Speter 810251877Speter /* If we got some data, then deliver it. */ 811251877Speter /* ### what to do if we got no data?? is that a problem? */ 812251877Speter if (conn->vec_len > 0) { 813251877Speter status = socket_writev(conn); 814251877Speter 815251877Speter /* If we can't write any more, or an error occurred, then 816251877Speter * we're done here. 817251877Speter */ 818251877Speter if (APR_STATUS_IS_EAGAIN(status)) 819251877Speter return APR_SUCCESS; 820251877Speter if (APR_STATUS_IS_EPIPE(status)) 821251877Speter return no_more_writes(conn, request); 822251877Speter if (APR_STATUS_IS_ECONNRESET(status) || 823251877Speter APR_STATUS_IS_ECONNABORTED(status)) { 824251877Speter return no_more_writes(conn, request); 825251877Speter } 826251877Speter if (status) 827251877Speter return status; 828251877Speter } 829251877Speter 830251877Speter if (read_status == SERF_ERROR_WAIT_CONN) { 831251877Speter stop_reading = 1; 832253895Speter conn->stop_writing = 1; 833253895Speter conn->dirty_conn = 1; 834253895Speter conn->ctx->dirty_pollset = 1; 835251877Speter } 836251877Speter else if (read_status && conn->hit_eof && conn->vec_len == 0) { 837251877Speter /* If we hit the end of the request bucket and all of its data has 838251877Speter * been written, then clear it out to signify that we're done 839251877Speter * sending the request. On the next iteration through this loop: 840251877Speter * - if there are remaining bytes they will be written, and as the 841251877Speter * request bucket will be completely read it will be destroyed then. 842251877Speter * - we'll see if there are other requests that need to be sent 843251877Speter * ("pipelining"). 844251877Speter */ 845251877Speter conn->hit_eof = 0; 846251877Speter serf_bucket_destroy(request->req_bkt); 847251877Speter request->req_bkt = NULL; 848251877Speter 849251877Speter /* If our connection has async responses enabled, we're not 850251877Speter * going to get a reply back, so kill the request. 851251877Speter */ 852251877Speter if (conn->async_responses) { 853251877Speter conn->requests = request->next; 854251877Speter destroy_request(request); 855251877Speter } 856251877Speter 857251877Speter conn->completed_requests++; 858251877Speter 859251877Speter if (conn->probable_keepalive_limit && 860251877Speter conn->completed_requests > conn->probable_keepalive_limit) { 861251877Speter /* backoff for now. */ 862251877Speter stop_reading = 1; 863251877Speter } 864251877Speter } 865251877Speter 866251877Speter if (stop_reading) { 867251877Speter return APR_SUCCESS; 868251877Speter } 869251877Speter } 870251877Speter /* NOTREACHED */ 871251877Speter} 872251877Speter 873251877Speter/* A response message was received from the server, so call 874251877Speter the handler as specified on the original request. */ 875251877Speterstatic apr_status_t handle_response(serf_request_t *request, 876251877Speter apr_pool_t *pool) 877251877Speter{ 878251877Speter apr_status_t status = APR_SUCCESS; 879251877Speter int consumed_response = 0; 880251877Speter 881251877Speter /* Only enable the new authentication framework if the program has 882251877Speter * registered an authentication credential callback. 883251877Speter * 884251877Speter * This permits older Serf apps to still handle authentication 885251877Speter * themselves by not registering credential callbacks. 886251877Speter */ 887251877Speter if (request->conn->ctx->cred_cb) { 888251877Speter status = serf__handle_auth_response(&consumed_response, 889251877Speter request, 890251877Speter request->resp_bkt, 891251877Speter request->handler_baton, 892251877Speter pool); 893251877Speter 894251877Speter /* If there was an error reading the response (maybe there wasn't 895251877Speter enough data available), don't bother passing the response to the 896251877Speter application. 897251877Speter 898251877Speter If the authentication was tried, but failed, pass the response 899251877Speter to the application, maybe it can do better. */ 900251877Speter if (APR_STATUS_IS_EOF(status) || 901251877Speter APR_STATUS_IS_EAGAIN(status)) { 902251877Speter return status; 903251877Speter } 904251877Speter } 905251877Speter 906251877Speter if (!consumed_response) { 907251877Speter return (*request->handler)(request, 908251877Speter request->resp_bkt, 909251877Speter request->handler_baton, 910251877Speter pool); 911251877Speter } 912251877Speter 913251877Speter return status; 914251877Speter} 915251877Speter 916251877Speter/* An async response message was received from the server. */ 917251877Speterstatic apr_status_t handle_async_response(serf_connection_t *conn, 918251877Speter apr_pool_t *pool) 919251877Speter{ 920251877Speter apr_status_t status; 921251877Speter 922251877Speter if (conn->current_async_response == NULL) { 923251877Speter conn->current_async_response = 924251877Speter (*conn->async_acceptor)(NULL, conn->stream, 925251877Speter conn->async_acceptor_baton, pool); 926251877Speter } 927251877Speter 928251877Speter status = (*conn->async_handler)(NULL, conn->current_async_response, 929251877Speter conn->async_handler_baton, pool); 930251877Speter 931251877Speter if (APR_STATUS_IS_EOF(status)) { 932251877Speter serf_bucket_destroy(conn->current_async_response); 933251877Speter conn->current_async_response = NULL; 934251877Speter status = APR_SUCCESS; 935251877Speter } 936251877Speter 937251877Speter return status; 938251877Speter} 939251877Speter 940253895Speter 941253895Speterapr_status_t 942253895Speterserf__provide_credentials(serf_context_t *ctx, 943253895Speter char **username, 944253895Speter char **password, 945253895Speter serf_request_t *request, void *baton, 946253895Speter int code, const char *authn_type, 947253895Speter const char *realm, 948253895Speter apr_pool_t *pool) 949253895Speter{ 950253895Speter serf_connection_t *conn = request->conn; 951253895Speter serf_request_t *authn_req = request; 952253895Speter apr_status_t status; 953253895Speter 954253895Speter if (request->ssltunnel == 1 && 955253895Speter conn->state == SERF_CONN_SETUP_SSLTUNNEL) { 956253895Speter /* This is a CONNECT request to set up an SSL tunnel over a proxy. 957253895Speter This request is created by serf, so if the proxy requires 958253895Speter authentication, we can't ask the application for credentials with 959253895Speter this request. 960253895Speter 961253895Speter Solution: setup the first request created by the application on 962253895Speter this connection, and use that request and its handler_baton to 963253895Speter call back to the application. */ 964253895Speter 965253895Speter authn_req = request->next; 966253895Speter /* assert: app_request != NULL */ 967253895Speter if (!authn_req) 968253895Speter return APR_EGENERAL; 969253895Speter 970253895Speter if (!authn_req->req_bkt) { 971253895Speter apr_status_t status; 972253895Speter 973253895Speter status = setup_request(authn_req); 974253895Speter /* If we can't setup a request, don't bother setting up the 975253895Speter ssl tunnel. */ 976253895Speter if (status) 977253895Speter return status; 978253895Speter } 979253895Speter } 980253895Speter 981253895Speter /* Ask the application. */ 982253895Speter status = (*ctx->cred_cb)(username, password, 983253895Speter authn_req, authn_req->handler_baton, 984253895Speter code, authn_type, realm, pool); 985253895Speter if (status) 986253895Speter return status; 987253895Speter 988253895Speter return APR_SUCCESS; 989253895Speter} 990253895Speter 991251877Speter/* read data from the connection */ 992251877Speterstatic apr_status_t read_from_connection(serf_connection_t *conn) 993251877Speter{ 994251877Speter apr_status_t status; 995251877Speter apr_pool_t *tmppool; 996251877Speter int close_connection = FALSE; 997251877Speter 998251877Speter /* Whatever is coming in on the socket corresponds to the first request 999251877Speter * on our chain. 1000251877Speter */ 1001251877Speter serf_request_t *request = conn->requests; 1002251877Speter 1003253895Speter /* If the stop_writing flag was set on the connection, reset it now because 1004253895Speter there is some data to read. */ 1005253895Speter if (conn->stop_writing) { 1006253895Speter conn->stop_writing = 0; 1007253895Speter conn->dirty_conn = 1; 1008253895Speter conn->ctx->dirty_pollset = 1; 1009253895Speter } 1010253895Speter 1011251877Speter /* assert: request != NULL */ 1012251877Speter 1013251877Speter if ((status = apr_pool_create(&tmppool, conn->pool)) != APR_SUCCESS) 1014251877Speter goto error; 1015251877Speter 1016251877Speter /* Invoke response handlers until we have no more work. */ 1017251877Speter while (1) { 1018251877Speter serf_bucket_t *dummy1, *dummy2; 1019251877Speter 1020251877Speter apr_pool_clear(tmppool); 1021251877Speter 1022251877Speter /* Only interested in the input stream here. */ 1023251877Speter status = prepare_conn_streams(conn, &conn->stream, &dummy1, &dummy2); 1024251877Speter if (status) { 1025251877Speter goto error; 1026251877Speter } 1027251877Speter 1028251877Speter /* We have a different codepath when we can have async responses. */ 1029251877Speter if (conn->async_responses) { 1030251877Speter /* TODO What about socket errors? */ 1031251877Speter status = handle_async_response(conn, tmppool); 1032251877Speter if (APR_STATUS_IS_EAGAIN(status)) { 1033251877Speter status = APR_SUCCESS; 1034251877Speter goto error; 1035251877Speter } 1036251877Speter if (status) { 1037251877Speter goto error; 1038251877Speter } 1039251877Speter continue; 1040251877Speter } 1041251877Speter 1042251877Speter /* We are reading a response for a request we haven't 1043251877Speter * written yet! 1044251877Speter * 1045251877Speter * This shouldn't normally happen EXCEPT: 1046251877Speter * 1047251877Speter * 1) when the other end has closed the socket and we're 1048251877Speter * pending an EOF return. 1049251877Speter * 2) Doing the initial SSL handshake - we'll get EAGAIN 1050251877Speter * as the SSL buckets will hide the handshake from us 1051251877Speter * but not return any data. 1052251877Speter * 3) When the server sends us an SSL alert. 1053251877Speter * 1054251877Speter * In these cases, we should not receive any actual user data. 1055251877Speter * 1056251877Speter * 4) When the server sends a error response, like 408 Request timeout. 1057251877Speter * This response should be passed to the application. 1058251877Speter * 1059251877Speter * If we see an EOF (due to either an expired timeout or the server 1060251877Speter * sending the SSL 'close notify' shutdown alert), we'll reset the 1061251877Speter * connection and open a new one. 1062251877Speter */ 1063251877Speter if (request->req_bkt || !request->written) { 1064251877Speter const char *data; 1065251877Speter apr_size_t len; 1066251877Speter 1067251877Speter status = serf_bucket_peek(conn->stream, &data, &len); 1068251877Speter 1069251877Speter if (APR_STATUS_IS_EOF(status)) { 1070251877Speter reset_connection(conn, 1); 1071251877Speter status = APR_SUCCESS; 1072251877Speter goto error; 1073251877Speter } 1074251877Speter else if (APR_STATUS_IS_EAGAIN(status) && !len) { 1075251877Speter status = APR_SUCCESS; 1076251877Speter goto error; 1077251877Speter } else if (status && !APR_STATUS_IS_EAGAIN(status)) { 1078251877Speter /* Read error */ 1079251877Speter goto error; 1080251877Speter } 1081251877Speter 1082251877Speter /* Unexpected response from the server */ 1083251877Speter 1084251877Speter } 1085251877Speter 1086251877Speter /* If the request doesn't have a response bucket, then call the 1087251877Speter * acceptor to get one created. 1088251877Speter */ 1089251877Speter if (request->resp_bkt == NULL) { 1090251877Speter request->resp_bkt = (*request->acceptor)(request, conn->stream, 1091251877Speter request->acceptor_baton, 1092251877Speter tmppool); 1093251877Speter apr_pool_clear(tmppool); 1094251877Speter } 1095251877Speter 1096251877Speter status = handle_response(request, tmppool); 1097251877Speter 1098251877Speter /* Some systems will not generate a HUP poll event so we have to 1099251877Speter * handle the ECONNRESET issue and ECONNABORT here. 1100251877Speter */ 1101251877Speter if (APR_STATUS_IS_ECONNRESET(status) || 1102251877Speter APR_STATUS_IS_ECONNABORTED(status) || 1103251877Speter status == SERF_ERROR_REQUEST_LOST) { 1104251877Speter /* If the connection had ever been good, be optimistic & try again. 1105251877Speter * If it has never tried again (incl. a retry), fail. 1106251877Speter */ 1107251877Speter if (conn->completed_responses) { 1108251877Speter reset_connection(conn, 1); 1109251877Speter status = APR_SUCCESS; 1110251877Speter } 1111251877Speter else if (status == SERF_ERROR_REQUEST_LOST) { 1112251877Speter status = SERF_ERROR_ABORTED_CONNECTION; 1113251877Speter } 1114251877Speter goto error; 1115251877Speter } 1116251877Speter 1117251877Speter /* If our response handler says it can't do anything more, we now 1118251877Speter * treat that as a success. 1119251877Speter */ 1120251877Speter if (APR_STATUS_IS_EAGAIN(status)) { 1121251877Speter status = APR_SUCCESS; 1122251877Speter goto error; 1123251877Speter } 1124251877Speter 1125251877Speter /* If we received APR_SUCCESS, run this loop again. */ 1126251877Speter if (!status) { 1127251877Speter continue; 1128251877Speter } 1129251877Speter 1130251877Speter close_connection = is_conn_closing(request->resp_bkt); 1131251877Speter 1132251877Speter if (!APR_STATUS_IS_EOF(status) && 1133251877Speter close_connection != SERF_ERROR_CLOSING) { 1134251877Speter /* Whether success, or an error, there is no more to do unless 1135251877Speter * this request has been completed. 1136251877Speter */ 1137251877Speter goto error; 1138251877Speter } 1139251877Speter 1140251877Speter /* The response has been fully-read, so that means the request has 1141251877Speter * either been fully-delivered (most likely), or that we don't need to 1142251877Speter * write the rest of it anymore, e.g. when a 408 Request timeout was 1143251877Speter $ received. 1144251877Speter * Remove it from our queue and loop to read another response. 1145251877Speter */ 1146251877Speter conn->requests = request->next; 1147251877Speter 1148251877Speter destroy_request(request); 1149251877Speter 1150251877Speter request = conn->requests; 1151251877Speter 1152251877Speter /* If we're truly empty, update our tail. */ 1153251877Speter if (request == NULL) { 1154251877Speter conn->requests_tail = NULL; 1155251877Speter } 1156251877Speter 1157251877Speter conn->completed_responses++; 1158251877Speter 1159251877Speter /* We've to rebuild pollset since completed_responses is changed. */ 1160251877Speter conn->dirty_conn = 1; 1161251877Speter conn->ctx->dirty_pollset = 1; 1162251877Speter 1163251877Speter /* This means that we're being advised that the connection is done. */ 1164251877Speter if (close_connection == SERF_ERROR_CLOSING) { 1165251877Speter reset_connection(conn, 1); 1166251877Speter if (APR_STATUS_IS_EOF(status)) 1167251877Speter status = APR_SUCCESS; 1168251877Speter goto error; 1169251877Speter } 1170251877Speter 1171251877Speter /* The server is suddenly deciding to serve more responses than we've 1172251877Speter * seen before. 1173251877Speter * 1174251877Speter * Let our requests go. 1175251877Speter */ 1176251877Speter if (conn->probable_keepalive_limit && 1177251877Speter conn->completed_responses > conn->probable_keepalive_limit) { 1178251877Speter conn->probable_keepalive_limit = 0; 1179251877Speter } 1180251877Speter 1181251877Speter /* If we just ran out of requests or have unwritten requests, then 1182251877Speter * update the pollset. We don't want to read from this socket any 1183251877Speter * more. We are definitely done with this loop, too. 1184251877Speter */ 1185251877Speter if (request == NULL || !request->written) { 1186251877Speter conn->dirty_conn = 1; 1187251877Speter conn->ctx->dirty_pollset = 1; 1188251877Speter status = APR_SUCCESS; 1189251877Speter goto error; 1190251877Speter } 1191251877Speter } 1192251877Speter 1193251877Spetererror: 1194251877Speter apr_pool_destroy(tmppool); 1195251877Speter return status; 1196251877Speter} 1197251877Speter 1198251877Speter/* process all events on the connection */ 1199251877Speterapr_status_t serf__process_connection(serf_connection_t *conn, 1200251877Speter apr_int16_t events) 1201251877Speter{ 1202251877Speter apr_status_t status; 1203251877Speter 1204251877Speter /* POLLHUP/ERR should come after POLLIN so if there's an error message or 1205251877Speter * the like sitting on the connection, we give the app a chance to read 1206251877Speter * it before we trigger a reset condition. 1207251877Speter */ 1208251877Speter if ((events & APR_POLLIN) != 0) { 1209251877Speter if ((status = read_from_connection(conn)) != APR_SUCCESS) 1210251877Speter return status; 1211251877Speter 1212251877Speter /* If we decided to reset our connection, return now as we don't 1213251877Speter * want to write. 1214251877Speter */ 1215251877Speter if ((conn->seen_in_pollset & APR_POLLHUP) != 0) { 1216251877Speter return APR_SUCCESS; 1217251877Speter } 1218251877Speter } 1219251877Speter if ((events & APR_POLLHUP) != 0) { 1220251877Speter /* The connection got reset by the server. On Windows this can happen 1221251877Speter when all data is read, so just cleanup the connection and open 1222251877Speter a new one. 1223251877Speter If we haven't had any successful responses on this connection, 1224251877Speter then error out as it is likely a server issue. */ 1225251877Speter if (conn->completed_responses) { 1226251877Speter return reset_connection(conn, 1); 1227251877Speter } 1228251877Speter return SERF_ERROR_ABORTED_CONNECTION; 1229251877Speter } 1230251877Speter if ((events & APR_POLLERR) != 0) { 1231251877Speter /* We might be talking to a buggy HTTP server that doesn't 1232251877Speter * do lingering-close. (httpd < 2.1.8 does this.) 1233251877Speter * 1234251877Speter * See: 1235251877Speter * 1236251877Speter * http://issues.apache.org/bugzilla/show_bug.cgi?id=35292 1237251877Speter */ 1238251877Speter if (conn->completed_requests && !conn->probable_keepalive_limit) { 1239251877Speter return reset_connection(conn, 1); 1240251877Speter } 1241253895Speter#ifdef SO_ERROR 1242253895Speter /* If possible, get the error from the platform's socket layer and 1243253895Speter convert it to an APR status code. */ 1244253895Speter { 1245253895Speter apr_os_sock_t osskt; 1246253895Speter if (!apr_os_sock_get(&osskt, conn->skt)) { 1247253895Speter int error; 1248253895Speter apr_socklen_t l = sizeof(error); 1249253895Speter 1250253895Speter if (!getsockopt(osskt, SOL_SOCKET, SO_ERROR, (char*)&error, &l)) 1251253895Speter return APR_FROM_OS_ERROR(error); 1252253895Speter } 1253253895Speter } 1254253895Speter#endif 1255251877Speter return APR_EGENERAL; 1256251877Speter } 1257251877Speter if ((events & APR_POLLOUT) != 0) { 1258251877Speter if ((status = write_to_connection(conn)) != APR_SUCCESS) 1259251877Speter return status; 1260251877Speter } 1261251877Speter return APR_SUCCESS; 1262251877Speter} 1263251877Speter 1264251877Speterserf_connection_t *serf_connection_create( 1265251877Speter serf_context_t *ctx, 1266251877Speter apr_sockaddr_t *address, 1267251877Speter serf_connection_setup_t setup, 1268251877Speter void *setup_baton, 1269251877Speter serf_connection_closed_t closed, 1270251877Speter void *closed_baton, 1271251877Speter apr_pool_t *pool) 1272251877Speter{ 1273251877Speter serf_connection_t *conn = apr_pcalloc(pool, sizeof(*conn)); 1274251877Speter 1275251877Speter conn->ctx = ctx; 1276251877Speter conn->status = APR_SUCCESS; 1277251877Speter /* Ignore server address if proxy was specified. */ 1278251877Speter conn->address = ctx->proxy_address ? ctx->proxy_address : address; 1279251877Speter conn->setup = setup; 1280251877Speter conn->setup_baton = setup_baton; 1281251877Speter conn->closed = closed; 1282251877Speter conn->closed_baton = closed_baton; 1283251877Speter conn->pool = pool; 1284251877Speter conn->allocator = serf_bucket_allocator_create(pool, NULL, NULL); 1285251877Speter conn->stream = NULL; 1286251877Speter conn->ostream_head = NULL; 1287251877Speter conn->ostream_tail = NULL; 1288251877Speter conn->baton.type = SERF_IO_CONN; 1289251877Speter conn->baton.u.conn = conn; 1290251877Speter conn->hit_eof = 0; 1291251877Speter conn->state = SERF_CONN_INIT; 1292251877Speter conn->latency = -1; /* unknown */ 1293251877Speter 1294251877Speter /* Create a subpool for our connection. */ 1295251877Speter apr_pool_create(&conn->skt_pool, conn->pool); 1296251877Speter 1297251877Speter /* register a cleanup */ 1298253895Speter apr_pool_cleanup_register(conn->pool, conn, clean_conn, 1299253895Speter apr_pool_cleanup_null); 1300251877Speter 1301251877Speter /* Add the connection to the context. */ 1302251877Speter *(serf_connection_t **)apr_array_push(ctx->conns) = conn; 1303251877Speter 1304251877Speter serf__log(CONN_VERBOSE, __FILE__, "created connection 0x%x\n", 1305251877Speter conn); 1306251877Speter 1307251877Speter return conn; 1308251877Speter} 1309251877Speter 1310251877Speterapr_status_t serf_connection_create2( 1311251877Speter serf_connection_t **conn, 1312251877Speter serf_context_t *ctx, 1313251877Speter apr_uri_t host_info, 1314251877Speter serf_connection_setup_t setup, 1315251877Speter void *setup_baton, 1316251877Speter serf_connection_closed_t closed, 1317251877Speter void *closed_baton, 1318251877Speter apr_pool_t *pool) 1319251877Speter{ 1320251877Speter apr_status_t status = APR_SUCCESS; 1321251877Speter serf_connection_t *c; 1322251877Speter apr_sockaddr_t *host_address = NULL; 1323251877Speter 1324251877Speter /* Set the port number explicitly, needed to create the socket later. */ 1325251877Speter if (!host_info.port) { 1326251877Speter host_info.port = apr_uri_port_of_scheme(host_info.scheme); 1327251877Speter } 1328251877Speter 1329251877Speter /* Only lookup the address of the server if no proxy server was 1330251877Speter configured. */ 1331251877Speter if (!ctx->proxy_address) { 1332251877Speter status = apr_sockaddr_info_get(&host_address, 1333251877Speter host_info.hostname, 1334251877Speter APR_UNSPEC, host_info.port, 0, pool); 1335251877Speter if (status) 1336251877Speter return status; 1337251877Speter } 1338251877Speter 1339251877Speter c = serf_connection_create(ctx, host_address, setup, setup_baton, 1340251877Speter closed, closed_baton, pool); 1341251877Speter 1342251877Speter /* We're not interested in the path following the hostname. */ 1343251877Speter c->host_url = apr_uri_unparse(c->pool, 1344251877Speter &host_info, 1345251877Speter APR_URI_UNP_OMITPATHINFO); 1346251877Speter 1347253895Speter /* Store the host info without the path on the connection. */ 1348253895Speter (void)apr_uri_parse(c->pool, c->host_url, &(c->host_info)); 1349253895Speter if (!c->host_info.port) { 1350253895Speter c->host_info.port = apr_uri_port_of_scheme(c->host_info.scheme); 1351253895Speter } 1352253895Speter 1353251877Speter *conn = c; 1354251877Speter 1355251877Speter return status; 1356251877Speter} 1357251877Speter 1358251877Speterapr_status_t serf_connection_reset( 1359251877Speter serf_connection_t *conn) 1360251877Speter{ 1361251877Speter return reset_connection(conn, 0); 1362251877Speter} 1363251877Speter 1364251877Speter 1365251877Speterapr_status_t serf_connection_close( 1366251877Speter serf_connection_t *conn) 1367251877Speter{ 1368251877Speter int i; 1369251877Speter serf_context_t *ctx = conn->ctx; 1370251877Speter apr_status_t status; 1371251877Speter 1372251877Speter for (i = ctx->conns->nelts; i--; ) { 1373251877Speter serf_connection_t *conn_seq = GET_CONN(ctx, i); 1374251877Speter 1375251877Speter if (conn_seq == conn) { 1376251877Speter while (conn->requests) { 1377251877Speter serf_request_cancel(conn->requests); 1378251877Speter } 1379251877Speter if (conn->skt != NULL) { 1380251877Speter remove_connection(ctx, conn); 1381251877Speter status = apr_socket_close(conn->skt); 1382251877Speter serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, 1383251877Speter "closed socket, status %d\n", 1384251877Speter status); 1385251877Speter if (conn->closed != NULL) { 1386251877Speter handle_conn_closed(conn, status); 1387251877Speter } 1388251877Speter conn->skt = NULL; 1389251877Speter } 1390251877Speter if (conn->stream != NULL) { 1391251877Speter serf_bucket_destroy(conn->stream); 1392251877Speter conn->stream = NULL; 1393251877Speter } 1394251877Speter 1395251877Speter destroy_ostream(conn); 1396251877Speter 1397251877Speter /* Remove the connection from the context. We don't want to 1398251877Speter * deal with it any more. 1399251877Speter */ 1400251877Speter if (i < ctx->conns->nelts - 1) { 1401251877Speter /* move later connections over this one. */ 1402251877Speter memmove( 1403251877Speter &GET_CONN(ctx, i), 1404251877Speter &GET_CONN(ctx, i + 1), 1405251877Speter (ctx->conns->nelts - i - 1) * sizeof(serf_connection_t *)); 1406251877Speter } 1407251877Speter --ctx->conns->nelts; 1408251877Speter 1409251877Speter serf__log(CONN_VERBOSE, __FILE__, "closed connection 0x%x\n", 1410251877Speter conn); 1411251877Speter 1412251877Speter /* Found the connection. Closed it. All done. */ 1413251877Speter return APR_SUCCESS; 1414251877Speter } 1415251877Speter } 1416251877Speter 1417251877Speter /* We didn't find the specified connection. */ 1418251877Speter /* ### doc talks about this w.r.t poll structures. use something else? */ 1419251877Speter return APR_NOTFOUND; 1420251877Speter} 1421251877Speter 1422251877Speter 1423251877Spetervoid serf_connection_set_max_outstanding_requests( 1424251877Speter serf_connection_t *conn, 1425251877Speter unsigned int max_requests) 1426251877Speter{ 1427251877Speter if (max_requests == 0) 1428251877Speter serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt, 1429251877Speter "Set max. nr. of outstanding requests for this " 1430251877Speter "connection to unlimited.\n"); 1431251877Speter else 1432251877Speter serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt, 1433251877Speter "Limit max. nr. of outstanding requests for this " 1434251877Speter "connection to %u.\n", max_requests); 1435251877Speter 1436251877Speter conn->max_outstanding_requests = max_requests; 1437251877Speter} 1438251877Speter 1439251877Speter 1440251877Spetervoid serf_connection_set_async_responses( 1441251877Speter serf_connection_t *conn, 1442251877Speter serf_response_acceptor_t acceptor, 1443251877Speter void *acceptor_baton, 1444251877Speter serf_response_handler_t handler, 1445251877Speter void *handler_baton) 1446251877Speter{ 1447251877Speter conn->async_responses = 1; 1448251877Speter conn->async_acceptor = acceptor; 1449251877Speter conn->async_acceptor_baton = acceptor_baton; 1450251877Speter conn->async_handler = handler; 1451251877Speter conn->async_handler_baton = handler_baton; 1452251877Speter} 1453251877Speter 1454253895Speterstatic serf_request_t * 1455253895Spetercreate_request(serf_connection_t *conn, 1456253895Speter serf_request_setup_t setup, 1457253895Speter void *setup_baton, 1458253895Speter int priority, 1459253895Speter int ssltunnel) 1460251877Speter{ 1461251877Speter serf_request_t *request; 1462251877Speter 1463251877Speter request = serf_bucket_mem_alloc(conn->allocator, sizeof(*request)); 1464251877Speter request->conn = conn; 1465251877Speter request->setup = setup; 1466251877Speter request->setup_baton = setup_baton; 1467251877Speter request->handler = NULL; 1468251877Speter request->respool = NULL; 1469251877Speter request->req_bkt = NULL; 1470251877Speter request->resp_bkt = NULL; 1471253895Speter request->priority = priority; 1472251877Speter request->written = 0; 1473253895Speter request->ssltunnel = ssltunnel; 1474251877Speter request->next = NULL; 1475251877Speter 1476253895Speter return request; 1477253895Speter} 1478253895Speter 1479253895Speterserf_request_t *serf_connection_request_create( 1480253895Speter serf_connection_t *conn, 1481253895Speter serf_request_setup_t setup, 1482253895Speter void *setup_baton) 1483253895Speter{ 1484253895Speter serf_request_t *request; 1485253895Speter 1486253895Speter request = create_request(conn, setup, setup_baton, 1487253895Speter 0, /* priority */ 1488253895Speter 0 /* ssl tunnel */); 1489253895Speter 1490251877Speter /* Link the request to the end of the request chain. */ 1491251877Speter link_requests(&conn->requests, &conn->requests_tail, request); 1492251877Speter 1493251877Speter /* Ensure our pollset becomes writable in context run */ 1494251877Speter conn->ctx->dirty_pollset = 1; 1495251877Speter conn->dirty_conn = 1; 1496251877Speter 1497251877Speter return request; 1498251877Speter} 1499251877Speter 1500253895Speterstatic serf_request_t * 1501253895Speterpriority_request_create(serf_connection_t *conn, 1502253895Speter int ssltunnelreq, 1503253895Speter serf_request_setup_t setup, 1504253895Speter void *setup_baton) 1505251877Speter{ 1506251877Speter serf_request_t *request; 1507251877Speter serf_request_t *iter, *prev; 1508251877Speter 1509253895Speter request = create_request(conn, setup, setup_baton, 1510253895Speter 1, /* priority */ 1511253895Speter ssltunnelreq); 1512251877Speter 1513251877Speter /* Link the new request after the last written request. */ 1514251877Speter iter = conn->requests; 1515251877Speter prev = NULL; 1516251877Speter 1517251877Speter /* Find a request that has data which needs to be delivered. */ 1518251877Speter while (iter != NULL && iter->req_bkt == NULL && iter->written) { 1519251877Speter prev = iter; 1520251877Speter iter = iter->next; 1521251877Speter } 1522251877Speter 1523253895Speter /* A CONNECT request to setup an ssltunnel has absolute priority over all 1524253895Speter other requests on the connection, so: 1525253895Speter a. add it first to the queue 1526253895Speter b. ensure that other priority requests are added after the CONNECT 1527253895Speter request */ 1528253895Speter if (!request->ssltunnel) { 1529253895Speter /* Advance to next non priority request */ 1530253895Speter while (iter != NULL && iter->priority) { 1531253895Speter prev = iter; 1532253895Speter iter = iter->next; 1533253895Speter } 1534251877Speter } 1535251877Speter 1536251877Speter if (prev) { 1537251877Speter request->next = iter; 1538251877Speter prev->next = request; 1539251877Speter } else { 1540251877Speter request->next = iter; 1541251877Speter conn->requests = request; 1542251877Speter } 1543251877Speter 1544251877Speter /* Ensure our pollset becomes writable in context run */ 1545251877Speter conn->ctx->dirty_pollset = 1; 1546251877Speter conn->dirty_conn = 1; 1547251877Speter 1548251877Speter return request; 1549251877Speter} 1550251877Speter 1551253895Speterserf_request_t *serf_connection_priority_request_create( 1552253895Speter serf_connection_t *conn, 1553253895Speter serf_request_setup_t setup, 1554253895Speter void *setup_baton) 1555253895Speter{ 1556253895Speter return priority_request_create(conn, 1557253895Speter 0, /* not a ssltunnel CONNECT request */ 1558253895Speter setup, setup_baton); 1559253895Speter} 1560251877Speter 1561253895Speterserf_request_t *serf__ssltunnel_request_create(serf_connection_t *conn, 1562253895Speter serf_request_setup_t setup, 1563253895Speter void *setup_baton) 1564253895Speter{ 1565253895Speter return priority_request_create(conn, 1566253895Speter 1, /* This is a ssltunnel CONNECT request */ 1567253895Speter setup, setup_baton); 1568253895Speter} 1569253895Speter 1570251877Speterapr_status_t serf_request_cancel(serf_request_t *request) 1571251877Speter{ 1572251877Speter return cancel_request(request, &request->conn->requests, 0); 1573251877Speter} 1574251877Speter 1575251877Speterapr_status_t serf_request_is_written(serf_request_t *request) 1576251877Speter{ 1577251877Speter if (request->written && !request->req_bkt) 1578251877Speter return APR_SUCCESS; 1579251877Speter 1580251877Speter return APR_EBUSY; 1581251877Speter} 1582251877Speter 1583251877Speterapr_pool_t *serf_request_get_pool(const serf_request_t *request) 1584251877Speter{ 1585251877Speter return request->respool; 1586251877Speter} 1587251877Speter 1588251877Speter 1589251877Speterserf_bucket_alloc_t *serf_request_get_alloc( 1590251877Speter const serf_request_t *request) 1591251877Speter{ 1592251877Speter return request->allocator; 1593251877Speter} 1594251877Speter 1595251877Speter 1596251877Speterserf_connection_t *serf_request_get_conn( 1597251877Speter const serf_request_t *request) 1598251877Speter{ 1599251877Speter return request->conn; 1600251877Speter} 1601251877Speter 1602251877Speter 1603251877Spetervoid serf_request_set_handler( 1604251877Speter serf_request_t *request, 1605251877Speter const serf_response_handler_t handler, 1606251877Speter const void **handler_baton) 1607251877Speter{ 1608251877Speter request->handler = handler; 1609251877Speter request->handler_baton = handler_baton; 1610251877Speter} 1611251877Speter 1612251877Speter 1613251877Speterserf_bucket_t *serf_request_bucket_request_create( 1614251877Speter serf_request_t *request, 1615251877Speter const char *method, 1616251877Speter const char *uri, 1617251877Speter serf_bucket_t *body, 1618251877Speter serf_bucket_alloc_t *allocator) 1619251877Speter{ 1620251877Speter serf_bucket_t *req_bkt, *hdrs_bkt; 1621251877Speter serf_connection_t *conn = request->conn; 1622251877Speter serf_context_t *ctx = conn->ctx; 1623253895Speter int ssltunnel; 1624251877Speter 1625253895Speter ssltunnel = ctx->proxy_address && 1626253895Speter (strcmp(conn->host_info.scheme, "https") == 0); 1627253895Speter 1628251877Speter req_bkt = serf_bucket_request_create(method, uri, body, allocator); 1629251877Speter hdrs_bkt = serf_bucket_request_get_headers(req_bkt); 1630251877Speter 1631253895Speter /* Use absolute uri's in requests to a proxy. USe relative uri's in 1632253895Speter requests directly to a server or sent through an SSL tunnel. */ 1633253895Speter if (ctx->proxy_address && conn->host_url && 1634253895Speter !(ssltunnel && !request->ssltunnel)) { 1635253895Speter 1636251877Speter serf_bucket_request_set_root(req_bkt, conn->host_url); 1637253895Speter } 1638251877Speter 1639251877Speter if (conn->host_info.hostinfo) 1640251877Speter serf_bucket_headers_setn(hdrs_bkt, "Host", 1641251877Speter conn->host_info.hostinfo); 1642251877Speter 1643253895Speter /* Setup server authorization headers, unless this is a CONNECT request. */ 1644253895Speter if (!request->ssltunnel) { 1645253895Speter serf__authn_info_t *authn_info; 1646253895Speter authn_info = serf__get_authn_info_for_server(conn); 1647253895Speter if (authn_info->scheme) 1648253895Speter authn_info->scheme->setup_request_func(HOST, 0, conn, request, 1649251877Speter method, uri, 1650251877Speter hdrs_bkt); 1651253895Speter } 1652251877Speter 1653253895Speter /* Setup proxy authorization headers. 1654253895Speter Don't set these headers on the requests to the server if we're using 1655253895Speter an SSL tunnel, only on the CONNECT request to setup the tunnel. */ 1656253895Speter if (ctx->proxy_authn_info.scheme) { 1657253895Speter if (strcmp(conn->host_info.scheme, "https") == 0) { 1658253895Speter if (request->ssltunnel) 1659253895Speter ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn, 1660253895Speter request, 1661253895Speter method, uri, 1662253895Speter hdrs_bkt); 1663253895Speter } else { 1664253895Speter ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn, 1665253895Speter request, 1666253895Speter method, uri, 1667253895Speter hdrs_bkt); 1668253895Speter } 1669253895Speter } 1670251877Speter 1671251877Speter return req_bkt; 1672251877Speter} 1673251877Speter 1674251877Speterapr_interval_time_t serf_connection_get_latency(serf_connection_t *conn) 1675251877Speter{ 1676251877Speter if (conn->ctx->proxy_address) { 1677251877Speter /* Detecting network latency for proxied connection is not implemented 1678251877Speter yet. */ 1679251877Speter return -1; 1680251877Speter } 1681251877Speter 1682251877Speter return conn->latency; 1683251877Speter} 1684