outgoing.c | outgoing.c | |||
---|---|---|---|---|
skipping to change at line 32 | skipping to change at line 32 | |||
#include "serf_private.h" | #include "serf_private.h" | |||
/* cleanup for sockets */ | /* cleanup for sockets */ | |||
static apr_status_t clean_skt(void *data) | static apr_status_t clean_skt(void *data) | |||
{ | { | |||
serf_connection_t *conn = data; | serf_connection_t *conn = data; | |||
apr_status_t status = APR_SUCCESS; | apr_status_t status = APR_SUCCESS; | |||
if (conn->skt) { | if (conn->skt) { | |||
serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, "cleanup - "); | ||||
status = apr_socket_close(conn->skt); | status = apr_socket_close(conn->skt); | |||
conn->skt = NULL; | conn->skt = NULL; | |||
serf__log_nopref(SOCK_VERBOSE, "closed socket, status %d\n", status ); | ||||
} | } | |||
return status; | return status; | |||
} | } | |||
static apr_status_t clean_resp(void *data) | static apr_status_t clean_resp(void *data) | |||
{ | { | |||
serf_request_t *request = data; | serf_request_t *request = data; | |||
/* The request's RESPOOL is being cleared. */ | /* The request's RESPOOL is being cleared. */ | |||
skipping to change at line 74 | skipping to change at line 76 | |||
request->respool = NULL; | request->respool = NULL; | |||
return APR_SUCCESS; | return APR_SUCCESS; | |||
} | } | |||
/* cleanup for conns */ | /* cleanup for conns */ | |||
static apr_status_t clean_conn(void *data) | static apr_status_t clean_conn(void *data) | |||
{ | { | |||
serf_connection_t *conn = data; | serf_connection_t *conn = data; | |||
serf__log(CONN_VERBOSE, __FILE__, "cleaning up connection 0x%x\n", | ||||
conn); | ||||
serf_connection_close(conn); | serf_connection_close(conn); | |||
return APR_SUCCESS; | return APR_SUCCESS; | |||
} | } | |||
/* Update the pollset for this connection. We tweak the pollset based on | /* Update the pollset for this connection. We tweak the pollset based on | |||
* whether we want to read and/or write, given conditions within the | * whether we want to read and/or write, given conditions within the | |||
* connection. If the connection is not (yet) in the pollset, then it | * connection. If the connection is not (yet) in the pollset, then it | |||
* will be added. | * will be added. | |||
*/ | */ | |||
skipping to change at line 187 | skipping to change at line 191 | |||
* yet. This is the core of our lazy-connect behavior. | * yet. This is the core of our lazy-connect behavior. | |||
*/ | */ | |||
apr_status_t serf__open_connections(serf_context_t *ctx) | apr_status_t serf__open_connections(serf_context_t *ctx) | |||
{ | { | |||
int i; | int i; | |||
for (i = ctx->conns->nelts; i--; ) { | for (i = ctx->conns->nelts; i--; ) { | |||
serf_connection_t *conn = GET_CONN(ctx, i); | serf_connection_t *conn = GET_CONN(ctx, i); | |||
apr_status_t status; | apr_status_t status; | |||
apr_socket_t *skt; | apr_socket_t *skt; | |||
apr_sockaddr_t *serv_addr; | ||||
conn->seen_in_pollset = 0; | conn->seen_in_pollset = 0; | |||
if (conn->skt != NULL) { | if (conn->skt != NULL) { | |||
#ifdef SERF_DEBUG_BUCKET_USE | #ifdef SERF_DEBUG_BUCKET_USE | |||
check_buckets_drained(conn); | check_buckets_drained(conn); | |||
#endif | #endif | |||
continue; | continue; | |||
} | } | |||
/* Delay opening until we have something to deliver! */ | /* Delay opening until we have something to deliver! */ | |||
if (conn->requests == NULL) { | if (conn->requests == NULL) { | |||
continue; | continue; | |||
} | } | |||
apr_pool_clear(conn->skt_pool); | apr_pool_clear(conn->skt_pool); | |||
apr_pool_cleanup_register(conn->skt_pool, conn, clean_skt, clean_sk t); | apr_pool_cleanup_register(conn->skt_pool, conn, clean_skt, clean_sk t); | |||
/* Do we have to connect to a proxy server? */ | status = apr_socket_create(&skt, conn->address->family, | |||
if (ctx->proxy_address) | SOCK_STREAM, | |||
serv_addr = ctx->proxy_address; | ||||
else | ||||
serv_addr = conn->address; | ||||
if ((status = apr_socket_create(&skt, serv_addr->family, | ||||
SOCK_STREAM, | ||||
#if APR_MAJOR_VERSION > 0 | #if APR_MAJOR_VERSION > 0 | |||
APR_PROTO_TCP, | APR_PROTO_TCP, | |||
#endif | #endif | |||
conn->skt_pool)) != APR_SUCCESS) | conn->skt_pool); | |||
serf__log(SOCK_VERBOSE, __FILE__, | ||||
"created socket for conn 0x%x, status %d\n", conn, status | ||||
); | ||||
if (status != APR_SUCCESS) | ||||
return status; | return status; | |||
/* Set the socket to be non-blocking */ | /* Set the socket to be non-blocking */ | |||
if ((status = apr_socket_timeout_set(skt, 0)) != APR_SUCCESS) | if ((status = apr_socket_timeout_set(skt, 0)) != APR_SUCCESS) | |||
return status; | return status; | |||
/* Disable Nagle's algorithm */ | /* Disable Nagle's algorithm */ | |||
if ((status = apr_socket_opt_set(skt, | if ((status = apr_socket_opt_set(skt, | |||
APR_TCP_NODELAY, 1)) != APR_SUCCES S) | APR_TCP_NODELAY, 1)) != APR_SUCCES S) | |||
return status; | return status; | |||
/* Configured. Store it into the connection now. */ | /* Configured. Store it into the connection now. */ | |||
conn->skt = skt; | conn->skt = skt; | |||
/* Remember time when we started connecting to server to calculate | ||||
network latency. */ | ||||
conn->connect_time = apr_time_now(); | ||||
/* Now that the socket is set up, let's connect it. This should | /* Now that the socket is set up, let's connect it. This should | |||
* return immediately. | * return immediately. | |||
*/ | */ | |||
if ((status = apr_socket_connect(skt, | status = apr_socket_connect(skt, conn->address); | |||
serv_addr)) != APR_SUCCESS) { | serf__log_skt(SOCK_VERBOSE, __FILE__, skt, | |||
"connected socket for conn 0x%x, status %d\n", | ||||
conn, status); | ||||
if (status != APR_SUCCESS) { | ||||
if (!APR_STATUS_IS_EINPROGRESS(status)) | if (!APR_STATUS_IS_EINPROGRESS(status)) | |||
return status; | return status; | |||
} | } | |||
/* Flag our pollset as dirty now that we have a new socket. */ | /* Flag our pollset as dirty now that we have a new socket. */ | |||
conn->dirty_conn = 1; | conn->dirty_conn = 1; | |||
ctx->dirty_pollset = 1; | ctx->dirty_pollset = 1; | |||
/* If the authentication was already started on another connection, | /* If the authentication was already started on another connection, | |||
prepare this connection (it might be possible to skip some | prepare this connection (it might be possible to skip some | |||
skipping to change at line 274 | skipping to change at line 281 | |||
} | } | |||
return APR_SUCCESS; | return APR_SUCCESS; | |||
} | } | |||
static apr_status_t no_more_writes(serf_connection_t *conn, | static apr_status_t no_more_writes(serf_connection_t *conn, | |||
serf_request_t *request) | serf_request_t *request) | |||
{ | { | |||
/* Note that we should hold new requests until we open our new socket. */ | /* Note that we should hold new requests until we open our new socket. */ | |||
conn->state = SERF_CONN_CLOSING; | conn->state = SERF_CONN_CLOSING; | |||
serf__log(CONN_VERBOSE, __FILE__, "stop writing on conn 0x%x\n", | ||||
conn); | ||||
/* Clear our iovec. */ | /* Clear our iovec. */ | |||
conn->vec_len = 0; | conn->vec_len = 0; | |||
/* Update the pollset to know we don't want to write on this socket any | /* Update the pollset to know we don't want to write on this socket any | |||
* more. | * more. | |||
*/ | */ | |||
conn->dirty_conn = 1; | conn->dirty_conn = 1; | |||
conn->ctx->dirty_pollset = 1; | conn->ctx->dirty_pollset = 1; | |||
return APR_SUCCESS; | return APR_SUCCESS; | |||
skipping to change at line 422 | skipping to change at line 431 | |||
conn->probable_keepalive_limit = conn->completed_responses; | conn->probable_keepalive_limit = conn->completed_responses; | |||
conn->completed_requests = 0; | conn->completed_requests = 0; | |||
conn->completed_responses = 0; | conn->completed_responses = 0; | |||
old_reqs = conn->requests; | old_reqs = conn->requests; | |||
conn->requests = NULL; | conn->requests = NULL; | |||
conn->requests_tail = NULL; | conn->requests_tail = NULL; | |||
/* Handle all outstanding requests. These have either not been written | ||||
yet, | ||||
or have been written but the expected reply wasn't received yet. */ | ||||
while (old_reqs) { | while (old_reqs) { | |||
/* If we haven't started to write the connection, bring it over | /* If we haven't started to write the connection, bring it over | |||
* unchanged to our new socket. Otherwise, call the cancel functio n. | * unchanged to our new socket. | |||
*/ | */ | |||
if (requeue_requests && !old_reqs->written) { | if (requeue_requests && !old_reqs->written) { | |||
serf_request_t *req = old_reqs; | serf_request_t *req = old_reqs; | |||
old_reqs = old_reqs->next; | old_reqs = old_reqs->next; | |||
req->next = NULL; | req->next = NULL; | |||
link_requests(&conn->requests, &conn->requests_tail, req); | link_requests(&conn->requests, &conn->requests_tail, req); | |||
} | } | |||
else { | else { | |||
/* Request has been consumed, or we don't want to requeue the | ||||
request. Either way, inform the application that the request | ||||
is cancelled. */ | ||||
cancel_request(old_reqs, &old_reqs, requeue_requests); | cancel_request(old_reqs, &old_reqs, requeue_requests); | |||
} | } | |||
} | } | |||
/* Requests queue has been prepared for a new socket, close the old one . */ | ||||
if (conn->skt != NULL) { | if (conn->skt != NULL) { | |||
remove_connection(ctx, conn); | remove_connection(ctx, conn); | |||
status = apr_socket_close(conn->skt); | status = apr_socket_close(conn->skt); | |||
serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, | ||||
"closed socket, status %d\n", status); | ||||
if (conn->closed != NULL) { | if (conn->closed != NULL) { | |||
handle_conn_closed(conn, status); | handle_conn_closed(conn, status); | |||
} | } | |||
conn->skt = NULL; | conn->skt = NULL; | |||
} | } | |||
if (conn->stream != NULL) { | if (conn->stream != NULL) { | |||
serf_bucket_destroy(conn->stream); | serf_bucket_destroy(conn->stream); | |||
conn->stream = NULL; | conn->stream = NULL; | |||
} | } | |||
destroy_ostream(conn); | destroy_ostream(conn); | |||
/* Don't try to resume any writes */ | /* Don't try to resume any writes */ | |||
conn->vec_len = 0; | conn->vec_len = 0; | |||
conn->dirty_conn = 1; | conn->dirty_conn = 1; | |||
conn->ctx->dirty_pollset = 1; | conn->ctx->dirty_pollset = 1; | |||
conn->state = SERF_CONN_INIT; | conn->state = SERF_CONN_INIT; | |||
serf__log(CONN_VERBOSE, __FILE__, "reset connection 0x%x\n", conn); | ||||
conn->status = APR_SUCCESS; | conn->status = APR_SUCCESS; | |||
/* Let our context know that we've 'reset' the socket already. */ | /* Let our context know that we've 'reset' the socket already. */ | |||
conn->seen_in_pollset |= APR_POLLHUP; | conn->seen_in_pollset |= APR_POLLHUP; | |||
/* Found the connection. Closed it. All done. */ | /* Found the connection. Closed it. All done. */ | |||
return APR_SUCCESS; | return APR_SUCCESS; | |||
} | } | |||
static apr_status_t socket_writev(serf_connection_t *conn) | static apr_status_t socket_writev(serf_connection_t *conn) | |||
{ | { | |||
apr_size_t written; | apr_size_t written; | |||
apr_status_t status; | apr_status_t status; | |||
status = apr_socket_sendv(conn->skt, conn->vec, | status = apr_socket_sendv(conn->skt, conn->vec, | |||
conn->vec_len, &written); | conn->vec_len, &written); | |||
if (status && !APR_STATUS_IS_EAGAIN(status)) | ||||
serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, | ||||
"socket_sendv error %d\n", status); | ||||
/* did we write everything? */ | /* did we write everything? */ | |||
if (written) { | if (written) { | |||
apr_size_t len = 0; | apr_size_t len = 0; | |||
int i; | int i; | |||
serf__log_skt(SOCK_MSG_VERBOSE, __FILE__, conn->skt, | ||||
"--- socket_sendv:\n"); | ||||
for (i = 0; i < conn->vec_len; i++) { | for (i = 0; i < conn->vec_len; i++) { | |||
len += conn->vec[i].iov_len; | len += conn->vec[i].iov_len; | |||
if (written < len) { | if (written < len) { | |||
serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s", | ||||
conn->vec[i].iov_len - (len - written), | ||||
conn->vec[i].iov_base); | ||||
if (i) { | if (i) { | |||
memmove(conn->vec, &conn->vec[i], | memmove(conn->vec, &conn->vec[i], | |||
sizeof(struct iovec) * (conn->vec_len - i)); | sizeof(struct iovec) * (conn->vec_len - i)); | |||
conn->vec_len -= i; | conn->vec_len -= i; | |||
} | } | |||
conn->vec[0].iov_base = (char *)conn->vec[0].iov_base + (co nn->vec[0].iov_len - (len - written)); | conn->vec[0].iov_base = (char *)conn->vec[0].iov_base + (co nn->vec[0].iov_len - (len - written)); | |||
conn->vec[0].iov_len = len - written; | conn->vec[0].iov_len = len - written; | |||
break; | break; | |||
} else { | ||||
serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s", | ||||
conn->vec[i].iov_len, conn->vec[i].iov_b | ||||
ase); | ||||
} | } | |||
} | } | |||
if (len == written) { | if (len == written) { | |||
conn->vec_len = 0; | conn->vec_len = 0; | |||
} | } | |||
serf__log_nopref(SOCK_MSG_VERBOSE, "-(%d)-\n", written); | ||||
/* Log progress information */ | /* Log progress information */ | |||
serf__context_progress_delta(conn->ctx, 0, written); | serf__context_progress_delta(conn->ctx, 0, written); | |||
} | } | |||
return status; | return status; | |||
} | } | |||
static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket ) | static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket ) | |||
{ | { | |||
skipping to change at line 565 | skipping to change at line 597 | |||
[en/de]cryption. | [en/de]cryption. | |||
*/ | */ | |||
static apr_status_t prepare_conn_streams(serf_connection_t *conn, | static apr_status_t prepare_conn_streams(serf_connection_t *conn, | |||
serf_bucket_t **istream, | serf_bucket_t **istream, | |||
serf_bucket_t **ostreamt, | serf_bucket_t **ostreamt, | |||
serf_bucket_t **ostreamh) | serf_bucket_t **ostreamh) | |||
{ | { | |||
apr_status_t status; | apr_status_t status; | |||
if (conn->stream == NULL) { | ||||
conn->latency = apr_time_now() - conn->connect_time; | ||||
} | ||||
/* Do we need a SSL tunnel first? */ | /* Do we need a SSL tunnel first? */ | |||
if (conn->state == SERF_CONN_CONNECTED) { | if (conn->state == SERF_CONN_CONNECTED) { | |||
/* If the connection does not have an associated bucket, then | /* If the connection does not have an associated bucket, then | |||
* call the setup callback to get one. | * call the setup callback to get one. | |||
*/ | */ | |||
if (conn->stream == NULL) { | if (conn->stream == NULL) { | |||
status = do_conn_setup(conn); | status = do_conn_setup(conn); | |||
if (status) { | if (status) { | |||
return status; | return status; | |||
} | } | |||
skipping to change at line 919 | skipping to change at line 955 | |||
* | * | |||
* 1) when the other end has closed the socket and we're | * 1) when the other end has closed the socket and we're | |||
* pending an EOF return. | * pending an EOF return. | |||
* 2) Doing the initial SSL handshake - we'll get EAGAIN | * 2) Doing the initial SSL handshake - we'll get EAGAIN | |||
* as the SSL buckets will hide the handshake from us | * as the SSL buckets will hide the handshake from us | |||
* but not return any data. | * but not return any data. | |||
* 3) When the server sends us an SSL alert. | * 3) When the server sends us an SSL alert. | |||
* | * | |||
* In these cases, we should not receive any actual user data. | * In these cases, we should not receive any actual user data. | |||
* | * | |||
* If we see an EOF (due to either an expired timeout or the serer | * 4) When the server sends a error response, like 408 Request time | |||
out. | ||||
* This response should be passed to the application. | ||||
* | ||||
* If we see an EOF (due to either an expired timeout or the server | ||||
* sending the SSL 'close notify' shutdown alert), we'll reset the | * sending the SSL 'close notify' shutdown alert), we'll reset the | |||
* connection and open a new one. | * connection and open a new one. | |||
*/ | */ | |||
if (request->req_bkt || !request->written) { | if (request->req_bkt || !request->written) { | |||
const char *data; | const char *data; | |||
apr_size_t len; | apr_size_t len; | |||
status = serf_bucket_read(conn->stream, SERF_READ_ALL_AVAIL, | status = serf_bucket_peek(conn->stream, &data, &len); | |||
&data, &len); | ||||
if (!status && len) { | if (APR_STATUS_IS_EOF(status)) { | |||
status = APR_EGENERAL; | ||||
} | ||||
else if (APR_STATUS_IS_EOF(status)) { | ||||
reset_connection(conn, 1); | reset_connection(conn, 1); | |||
status = APR_SUCCESS; | status = APR_SUCCESS; | |||
goto error; | ||||
} | } | |||
else if (APR_STATUS_IS_EAGAIN(status)) { | else if (APR_STATUS_IS_EAGAIN(status) && !len) { | |||
status = APR_SUCCESS; | status = APR_SUCCESS; | |||
goto error; | ||||
} else if (status && !APR_STATUS_IS_EAGAIN(status)) { | ||||
/* Read error */ | ||||
goto error; | ||||
} | } | |||
goto error; | /* Unexpected response from the server */ | |||
} | } | |||
/* If the request doesn't have a response bucket, then call the | /* If the request doesn't have a response bucket, then call the | |||
* acceptor to get one created. | * acceptor to get one created. | |||
*/ | */ | |||
if (request->resp_bkt == NULL) { | if (request->resp_bkt == NULL) { | |||
request->resp_bkt = (*request->acceptor)(request, conn->stream, | request->resp_bkt = (*request->acceptor)(request, conn->stream, | |||
request->acceptor_bato n, | request->acceptor_bato n, | |||
tmppool); | tmppool); | |||
apr_pool_clear(tmppool); | apr_pool_clear(tmppool); | |||
} | } | |||
status = handle_response(request, tmppool); | status = handle_response(request, tmppool); | |||
/* Some systems will not generate a HUP poll event so we have to | /* Some systems will not generate a HUP poll event so we have to | |||
* handle the ECONNRESET issue and ECONNABORT here. | * handle the ECONNRESET issue and ECONNABORT here. | |||
*/ | */ | |||
if (APR_STATUS_IS_ECONNRESET(status) || | if (APR_STATUS_IS_ECONNRESET(status) || | |||
APR_STATUS_IS_ECONNABORTED(status) || | APR_STATUS_IS_ECONNABORTED(status) || | |||
status == SERF_ERROR_REQUEST_LOST) { | status == SERF_ERROR_REQUEST_LOST) { | |||
reset_connection(conn, 1); | /* If the connection had ever been good, be optimistic & try ag | |||
status = APR_SUCCESS; | ain. | |||
* If it has never tried again (incl. a retry), fail. | ||||
*/ | ||||
if (conn->completed_responses) { | ||||
reset_connection(conn, 1); | ||||
status = APR_SUCCESS; | ||||
} | ||||
else if (status == SERF_ERROR_REQUEST_LOST) { | ||||
status = SERF_ERROR_ABORTED_CONNECTION; | ||||
} | ||||
goto error; | goto error; | |||
} | } | |||
/* If our response handler says it can't do anything more, we now | /* If our response handler says it can't do anything more, we now | |||
* treat that as a success. | * treat that as a success. | |||
*/ | */ | |||
if (APR_STATUS_IS_EAGAIN(status)) { | if (APR_STATUS_IS_EAGAIN(status)) { | |||
status = APR_SUCCESS; | status = APR_SUCCESS; | |||
goto error; | goto error; | |||
} | } | |||
skipping to change at line 990 | skipping to change at line 1039 | |||
close_connection = is_conn_closing(request->resp_bkt); | close_connection = is_conn_closing(request->resp_bkt); | |||
if (!APR_STATUS_IS_EOF(status) && | if (!APR_STATUS_IS_EOF(status) && | |||
close_connection != SERF_ERROR_CLOSING) { | close_connection != SERF_ERROR_CLOSING) { | |||
/* Whether success, or an error, there is no more to do unless | /* Whether success, or an error, there is no more to do unless | |||
* this request has been completed. | * this request has been completed. | |||
*/ | */ | |||
goto error; | goto error; | |||
} | } | |||
/* The request has been fully-delivered, and the response has | /* The response has been fully-read, so that means the request has | |||
* been fully-read. Remove it from our queue and loop to read | * either been fully-delivered (most likely), or that we don't need | |||
* another response. | to | |||
* write the rest of it anymore, e.g. when a 408 Request timeout wa | ||||
s | ||||
$ received. | ||||
* Remove it from our queue and loop to read another response. | ||||
*/ | */ | |||
conn->requests = request->next; | conn->requests = request->next; | |||
destroy_request(request); | destroy_request(request); | |||
request = conn->requests; | request = conn->requests; | |||
/* If we're truly empty, update our tail. */ | /* If we're truly empty, update our tail. */ | |||
if (request == NULL) { | if (request == NULL) { | |||
conn->requests_tail = NULL; | conn->requests_tail = NULL; | |||
skipping to change at line 1070 | skipping to change at line 1121 | |||
/* If we decided to reset our connection, return now as we don't | /* If we decided to reset our connection, return now as we don't | |||
* want to write. | * want to write. | |||
*/ | */ | |||
if ((conn->seen_in_pollset & APR_POLLHUP) != 0) { | if ((conn->seen_in_pollset & APR_POLLHUP) != 0) { | |||
return APR_SUCCESS; | return APR_SUCCESS; | |||
} | } | |||
} | } | |||
if ((events & APR_POLLHUP) != 0) { | if ((events & APR_POLLHUP) != 0) { | |||
/* The connection got reset by the server. On Windows this can happ en | /* The connection got reset by the server. On Windows this can happ en | |||
when all data is read, so just cleanup the connection and open | when all data is read, so just cleanup the connection and open | |||
a new one. */ | a new one. | |||
return reset_connection(conn, 1); | If we haven't had any successful responses on this connection, | |||
then error out as it is likely a server issue. */ | ||||
if (conn->completed_responses) { | ||||
return reset_connection(conn, 1); | ||||
} | ||||
return SERF_ERROR_ABORTED_CONNECTION; | ||||
} | } | |||
if ((events & APR_POLLERR) != 0) { | if ((events & APR_POLLERR) != 0) { | |||
/* We might be talking to a buggy HTTP server that doesn't | /* We might be talking to a buggy HTTP server that doesn't | |||
* do lingering-close. (httpd < 2.1.8 does this.) | * do lingering-close. (httpd < 2.1.8 does this.) | |||
* | * | |||
* See: | * See: | |||
* | * | |||
* http://issues.apache.org/bugzilla/show_bug.cgi?id=35292 | * http://issues.apache.org/bugzilla/show_bug.cgi?id=35292 | |||
*/ | */ | |||
if (conn->completed_requests && !conn->probable_keepalive_limit) { | if (conn->completed_requests && !conn->probable_keepalive_limit) { | |||
skipping to change at line 1106 | skipping to change at line 1162 | |||
serf_connection_setup_t setup, | serf_connection_setup_t setup, | |||
void *setup_baton, | void *setup_baton, | |||
serf_connection_closed_t closed, | serf_connection_closed_t closed, | |||
void *closed_baton, | void *closed_baton, | |||
apr_pool_t *pool) | apr_pool_t *pool) | |||
{ | { | |||
serf_connection_t *conn = apr_pcalloc(pool, sizeof(*conn)); | serf_connection_t *conn = apr_pcalloc(pool, sizeof(*conn)); | |||
conn->ctx = ctx; | conn->ctx = ctx; | |||
conn->status = APR_SUCCESS; | conn->status = APR_SUCCESS; | |||
conn->address = address; | /* Ignore server address if proxy was specified. */ | |||
conn->address = ctx->proxy_address ? ctx->proxy_address : address; | ||||
conn->setup = setup; | conn->setup = setup; | |||
conn->setup_baton = setup_baton; | conn->setup_baton = setup_baton; | |||
conn->closed = closed; | conn->closed = closed; | |||
conn->closed_baton = closed_baton; | conn->closed_baton = closed_baton; | |||
conn->pool = pool; | conn->pool = pool; | |||
conn->allocator = serf_bucket_allocator_create(pool, NULL, NULL); | conn->allocator = serf_bucket_allocator_create(pool, NULL, NULL); | |||
conn->stream = NULL; | conn->stream = NULL; | |||
conn->ostream_head = NULL; | conn->ostream_head = NULL; | |||
conn->ostream_tail = NULL; | conn->ostream_tail = NULL; | |||
conn->baton.type = SERF_IO_CONN; | conn->baton.type = SERF_IO_CONN; | |||
conn->baton.u.conn = conn; | conn->baton.u.conn = conn; | |||
conn->hit_eof = 0; | conn->hit_eof = 0; | |||
conn->state = SERF_CONN_INIT; | conn->state = SERF_CONN_INIT; | |||
conn->latency = -1; /* unknown */ | ||||
/* Create a subpool for our connection. */ | /* Create a subpool for our connection. */ | |||
apr_pool_create(&conn->skt_pool, conn->pool); | apr_pool_create(&conn->skt_pool, conn->pool); | |||
/* register a cleanup */ | /* register a cleanup */ | |||
apr_pool_cleanup_register(conn->pool, conn, clean_conn, apr_pool_cleanu p_null); | apr_pool_cleanup_register(conn->pool, conn, clean_conn, apr_pool_cleanu p_null); | |||
/* Add the connection to the context. */ | /* Add the connection to the context. */ | |||
*(serf_connection_t **)apr_array_push(ctx->conns) = conn; | *(serf_connection_t **)apr_array_push(ctx->conns) = conn; | |||
serf__log(CONN_VERBOSE, __FILE__, "created connection 0x%x\n", | ||||
conn); | ||||
return conn; | return conn; | |||
} | } | |||
apr_status_t serf_connection_create2( | apr_status_t serf_connection_create2( | |||
serf_connection_t **conn, | serf_connection_t **conn, | |||
serf_context_t *ctx, | serf_context_t *ctx, | |||
apr_uri_t host_info, | apr_uri_t host_info, | |||
serf_connection_setup_t setup, | serf_connection_setup_t setup, | |||
void *setup_baton, | void *setup_baton, | |||
serf_connection_closed_t closed, | serf_connection_closed_t closed, | |||
void *closed_baton, | void *closed_baton, | |||
apr_pool_t *pool) | apr_pool_t *pool) | |||
{ | { | |||
apr_status_t status; | apr_status_t status = APR_SUCCESS; | |||
serf_connection_t *c; | serf_connection_t *c; | |||
apr_sockaddr_t *host_address; | apr_sockaddr_t *host_address = NULL; | |||
/* Parse the url, store the address of the server. */ | /* Set the port number explicitly, needed to create the socket later. * | |||
status = apr_sockaddr_info_get(&host_address, | / | |||
host_info.hostname, | if (!host_info.port) { | |||
APR_UNSPEC, host_info.port, 0, pool); | host_info.port = apr_uri_port_of_scheme(host_info.scheme); | |||
if (status) | } | |||
return status; | ||||
/* Only lookup the address of the server if no proxy server was | ||||
configured. */ | ||||
if (!ctx->proxy_address) { | ||||
status = apr_sockaddr_info_get(&host_address, | ||||
host_info.hostname, | ||||
APR_UNSPEC, host_info.port, 0, pool) | ||||
; | ||||
if (status) | ||||
return status; | ||||
} | ||||
c = serf_connection_create(ctx, host_address, setup, setup_baton, | c = serf_connection_create(ctx, host_address, setup, setup_baton, | |||
closed, closed_baton, pool); | closed, closed_baton, pool); | |||
/* We're not interested in the path following the hostname. */ | /* We're not interested in the path following the hostname. */ | |||
c->host_url = apr_uri_unparse(c->pool, | c->host_url = apr_uri_unparse(c->pool, | |||
&host_info, | &host_info, | |||
APR_URI_UNP_OMITPATHINFO); | APR_URI_UNP_OMITPATHINFO); | |||
c->host_info = host_info; | c->host_info = host_info; | |||
skipping to change at line 1191 | skipping to change at line 1260 | |||
for (i = ctx->conns->nelts; i--; ) { | for (i = ctx->conns->nelts; i--; ) { | |||
serf_connection_t *conn_seq = GET_CONN(ctx, i); | serf_connection_t *conn_seq = GET_CONN(ctx, i); | |||
if (conn_seq == conn) { | if (conn_seq == conn) { | |||
while (conn->requests) { | while (conn->requests) { | |||
serf_request_cancel(conn->requests); | serf_request_cancel(conn->requests); | |||
} | } | |||
if (conn->skt != NULL) { | if (conn->skt != NULL) { | |||
remove_connection(ctx, conn); | remove_connection(ctx, conn); | |||
status = apr_socket_close(conn->skt); | status = apr_socket_close(conn->skt); | |||
serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, | ||||
"closed socket, status %d\n", | ||||
status); | ||||
if (conn->closed != NULL) { | if (conn->closed != NULL) { | |||
handle_conn_closed(conn, status); | handle_conn_closed(conn, status); | |||
} | } | |||
conn->skt = NULL; | conn->skt = NULL; | |||
} | } | |||
if (conn->stream != NULL) { | if (conn->stream != NULL) { | |||
serf_bucket_destroy(conn->stream); | serf_bucket_destroy(conn->stream); | |||
conn->stream = NULL; | conn->stream = NULL; | |||
} | } | |||
skipping to change at line 1215 | skipping to change at line 1287 | |||
*/ | */ | |||
if (i < ctx->conns->nelts - 1) { | if (i < ctx->conns->nelts - 1) { | |||
/* move later connections over this one. */ | /* move later connections over this one. */ | |||
memmove( | memmove( | |||
&GET_CONN(ctx, i), | &GET_CONN(ctx, i), | |||
&GET_CONN(ctx, i + 1), | &GET_CONN(ctx, i + 1), | |||
(ctx->conns->nelts - i - 1) * sizeof(serf_connection_t *)); | (ctx->conns->nelts - i - 1) * sizeof(serf_connection_t *)); | |||
} | } | |||
--ctx->conns->nelts; | --ctx->conns->nelts; | |||
serf__log(CONN_VERBOSE, __FILE__, "closed connection 0x%x\n", | ||||
conn); | ||||
/* Found the connection. Closed it. All done. */ | /* Found the connection. Closed it. All done. */ | |||
return APR_SUCCESS; | return APR_SUCCESS; | |||
} | } | |||
} | } | |||
/* We didn't find the specified connection. */ | /* We didn't find the specified connection. */ | |||
/* ### doc talks about this w.r.t poll structures. use something else? */ | /* ### doc talks about this w.r.t poll structures. use something else? */ | |||
return APR_NOTFOUND; | return APR_NOTFOUND; | |||
} | } | |||
void serf_connection_set_max_outstanding_requests( | void serf_connection_set_max_outstanding_requests( | |||
serf_connection_t *conn, | serf_connection_t *conn, | |||
unsigned int max_requests) | unsigned int max_requests) | |||
{ | { | |||
if (max_requests == 0) | ||||
serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt, | ||||
"Set max. nr. of outstanding requests for this " | ||||
"connection to unlimited.\n"); | ||||
else | ||||
serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt, | ||||
"Limit max. nr. of outstanding requests for this " | ||||
"connection to %u.\n", max_requests); | ||||
conn->max_outstanding_requests = max_requests; | conn->max_outstanding_requests = max_requests; | |||
} | } | |||
void serf_connection_set_async_responses( | void serf_connection_set_async_responses( | |||
serf_connection_t *conn, | serf_connection_t *conn, | |||
serf_response_acceptor_t acceptor, | serf_response_acceptor_t acceptor, | |||
void *acceptor_baton, | void *acceptor_baton, | |||
serf_response_handler_t handler, | serf_response_handler_t handler, | |||
void *handler_baton) | void *handler_baton) | |||
{ | { | |||
skipping to change at line 1331 | skipping to change at line 1415 | |||
conn->dirty_conn = 1; | conn->dirty_conn = 1; | |||
return request; | return request; | |||
} | } | |||
apr_status_t serf_request_cancel(serf_request_t *request) | apr_status_t serf_request_cancel(serf_request_t *request) | |||
{ | { | |||
return cancel_request(request, &request->conn->requests, 0); | return cancel_request(request, &request->conn->requests, 0); | |||
} | } | |||
apr_status_t serf_request_is_written(serf_request_t *request) | ||||
{ | ||||
if (request->written && !request->req_bkt) | ||||
return APR_SUCCESS; | ||||
return APR_EBUSY; | ||||
} | ||||
apr_pool_t *serf_request_get_pool(const serf_request_t *request) | apr_pool_t *serf_request_get_pool(const serf_request_t *request) | |||
{ | { | |||
return request->respool; | return request->respool; | |||
} | } | |||
serf_bucket_alloc_t *serf_request_get_alloc( | serf_bucket_alloc_t *serf_request_get_alloc( | |||
const serf_request_t *request) | const serf_request_t *request) | |||
{ | { | |||
return request->allocator; | return request->allocator; | |||
} | } | |||
skipping to change at line 1381 | skipping to change at line 1473 | |||
/* Proxy? */ | /* Proxy? */ | |||
if (ctx->proxy_address && conn->host_url) | if (ctx->proxy_address && conn->host_url) | |||
serf_bucket_request_set_root(req_bkt, conn->host_url); | serf_bucket_request_set_root(req_bkt, conn->host_url); | |||
if (conn->host_info.hostinfo) | if (conn->host_info.hostinfo) | |||
serf_bucket_headers_setn(hdrs_bkt, "Host", | serf_bucket_headers_setn(hdrs_bkt, "Host", | |||
conn->host_info.hostinfo); | conn->host_info.hostinfo); | |||
/* Setup server authorization headers */ | /* Setup server authorization headers */ | |||
if (ctx->authn_info.scheme) | if (ctx->authn_info.scheme) | |||
ctx->authn_info.scheme->setup_request_func(401, conn, method, uri, | ctx->authn_info.scheme->setup_request_func(HOST, 0, conn, method, u ri, | |||
hdrs_bkt); | hdrs_bkt); | |||
/* Setup proxy authorization headers */ | /* Setup proxy authorization headers */ | |||
if (ctx->proxy_authn_info.scheme) | if (ctx->proxy_authn_info.scheme) | |||
ctx->proxy_authn_info.scheme->setup_request_func(407, conn, method, | ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn, | |||
uri, hdrs_bkt); | method, uri, hdrs_ | |||
bkt); | ||||
return req_bkt; | return req_bkt; | |||
} | } | |||
apr_interval_time_t serf_connection_get_latency(serf_connection_t *conn) | ||||
{ | ||||
if (conn->ctx->proxy_address) { | ||||
/* Detecting network latency for proxied connection is not implemen | ||||
ted | ||||
yet. */ | ||||
return -1; | ||||
} | ||||
return conn->latency; | ||||
} | ||||
End of changes. 45 change blocks. | ||||
42 lines changed or deleted | 144 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |