proxy_util.c
来自「linux网络服务器工具」· C语言 代码 · 共 2,062 行 · 第 1/5 页
C
2,062 行
* network filters get flushed to the network. This is needed since * these buckets have been created with the bucket allocator of the * backend connection. This allocator either gets destroyed if * conn->close is set or the worker address is not reusable which * causes the connection to the backend to be closed or it will be used * again by another frontend connection that wants to recycle the * backend connection. * In this case we could run into nasty race conditions (e.g. if the * next user of the backend connection destroys the allocator before we * sent the buckets to the network). * * Remark 1: Only do this if buckets where sent down the chain before * that could still be buffered in the network filter. This is the case * if we have sent an EOS bucket or if we actually sent buckets with * data down the chain. In all other cases we either have not sent any * buckets at all down the chain or we only sent meta buckets that are * not EOS buckets down the chain. The only meta bucket that remains in * this case is the flush bucket which would have removed all possibly * buffered buckets in the network filter. * If we sent a flush bucket in the case where not ANY buckets were * sent down the chain, we break error handling which happens AFTER us. * * Remark 2: Doing a setaside does not help here as the buckets remain * created by the wrong allocator in this case. * * Remark 3: Yes, this creates a possible performance penalty in the case * of pipelined requests as we may send only a small amount of data over * the wire. */ c = r->connection; bb = apr_brigade_create(r->pool, c->bucket_alloc); if (r->eos_sent) { /* * If we have already sent an EOS bucket send directly to the * connection based filters. We just want to flush the buckets * if something hasn't been sent to the network yet. */ ap_fflush(c->output_filters, bb); } else { ap_fflush(r->output_filters, bb); } apr_brigade_destroy(bb); conn->r = NULL; conn->need_flush = 0; } /* determine if the connection need to be closed */ if (conn->close_on_recycle || conn->close || worker->disablereuse || !worker->is_address_reusable) { apr_pool_t *p = conn->pool; apr_pool_clear(p); conn = apr_pcalloc(p, sizeof(proxy_conn_rec)); conn->pool = p; conn->worker = worker; apr_pool_create(&(conn->scpool), p); apr_pool_tag(conn->scpool, "proxy_conn_scpool"); }#if APR_HAS_THREADS if (worker->hmax && worker->cp->res) { conn->inreslist = 1; apr_reslist_release(worker->cp->res, (void *)conn); } else#endif { worker->cp->conn = conn; } /* Always return the SUCCESS */ return APR_SUCCESS;}static void socket_cleanup(proxy_conn_rec *conn){ conn->sock = NULL; conn->connection = NULL; apr_pool_clear(conn->scpool);}PROXY_DECLARE(apr_status_t) ap_proxy_ssl_connection_cleanup(proxy_conn_rec *conn, request_rec *r){ apr_bucket_brigade *bb; apr_status_t rv; /* * If we have an existing SSL connection it might be possible that the * server sent some SSL message we have not read so far (e.g. a SSL * shutdown message if the server closed the keepalive connection while * the connection was held unused in our pool). * So ensure that if present (=> APR_NONBLOCK_READ) it is read and * processed. We don't expect any data to be in the returned brigade. */ if (conn->sock && conn->connection) { bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); rv = ap_get_brigade(conn->connection->input_filters, bb, AP_MODE_READBYTES, APR_NONBLOCK_READ, HUGE_STRING_LEN); if ((rv != APR_SUCCESS) && !APR_STATUS_IS_EAGAIN(rv)) { socket_cleanup(conn); } if (!APR_BRIGADE_EMPTY(bb)) { apr_off_t len; rv = apr_brigade_length(bb, 0, &len); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, "proxy: SSL cleanup brigade contained %" APR_OFF_T_FMT " bytes of data.", len); } apr_brigade_destroy(bb); } return APR_SUCCESS;}/* reslist constructor */static apr_status_t connection_constructor(void **resource, void *params, apr_pool_t *pool){ apr_pool_t *ctx; apr_pool_t *scpool; proxy_conn_rec *conn; proxy_worker *worker = (proxy_worker *)params; /* * Create the subpool for each connection * This keeps the memory consumption constant * when disconnecting from backend. */ apr_pool_create(&ctx, pool); apr_pool_tag(ctx, "proxy_conn_pool"); /* * Create another subpool that manages the data for the * socket and the connection member of the proxy_conn_rec struct as we * destroy this data more frequently than other data in the proxy_conn_rec * struct like hostname and addr (at least in the case where we have * keepalive connections that timed out). */ apr_pool_create(&scpool, ctx); apr_pool_tag(scpool, "proxy_conn_scpool"); conn = apr_pcalloc(ctx, sizeof(proxy_conn_rec)); conn->pool = ctx; conn->scpool = scpool; conn->worker = worker;#if APR_HAS_THREADS conn->inreslist = 1;#endif *resource = conn; return APR_SUCCESS;}#if APR_HAS_THREADS /* only needed when threads are used *//* reslist destructor */static apr_status_t connection_destructor(void *resource, void *params, apr_pool_t *pool){ proxy_conn_rec *conn = (proxy_conn_rec *)resource; /* Destroy the pool only if not called from reslist_destroy */ if (conn->worker->cp->pool) { apr_pool_destroy(conn->pool); } return APR_SUCCESS;}#endif/* * ap_proxy_initialize_worker_share() concerns itself * with initializing those parts of worker which * are, or could be, shared. Basically worker->s */PROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf, proxy_worker *worker, server_rec *s){#if PROXY_HAS_SCOREBOARD lb_score *score = NULL;#else void *score = NULL;#endif if (PROXY_WORKER_IS_INITIALIZED(worker)) { /* The worker share is already initialized */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: worker %s already initialized", worker->name); return; }#if PROXY_HAS_SCOREBOARD /* Get scoreboard slot */ if (ap_scoreboard_image) { score = ap_get_scoreboard_lb(worker->id); if (!score) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "proxy: ap_get_scoreboard_lb(%d) failed in child %" APR_PID_T_FMT " for worker %s", worker->id, getpid(), worker->name); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: grabbed scoreboard slot %d in child %" APR_PID_T_FMT " for worker %s", worker->id, getpid(), worker->name); } }#endif if (!score) { score = apr_pcalloc(conf->pool, sizeof(proxy_worker_stat)); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: initialized plain memory in child %" APR_PID_T_FMT " for worker %s", getpid(), worker->name); } worker->s = (proxy_worker_stat *)score; /* * recheck to see if we've already been here. Possible * if proxy is using scoreboard to hold shared stats */ if (PROXY_WORKER_IS_INITIALIZED(worker)) { /* The worker share is already initialized */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: worker %s already initialized", worker->name); return; } if (worker->route) { strcpy(worker->s->route, worker->route); } else { *worker->s->route = '\0'; } if (worker->redirect) { strcpy(worker->s->redirect, worker->redirect); } else { *worker->s->redirect = '\0'; } worker->s->status |= (worker->status | PROXY_WORKER_INITIALIZED);}PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, server_rec *s){ apr_status_t rv;#if APR_HAS_THREADS int mpm_threads;#endif if (worker->status & PROXY_WORKER_INITIALIZED) { /* The worker is already initialized */ return APR_SUCCESS; } /* Set default parameters */ if (!worker->retry_set) { worker->retry = apr_time_from_sec(PROXY_WORKER_DEFAULT_RETRY); } /* By default address is reusable unless DisableReuse is set */ if (worker->disablereuse) { worker->is_address_reusable = 0; } else { worker->is_address_reusable = 1; }#if APR_HAS_THREADS ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads); if (mpm_threads > 1) { /* Set hard max to no more then mpm_threads */ if (worker->hmax == 0 || worker->hmax > mpm_threads) { worker->hmax = mpm_threads; } if (worker->smax == 0 || worker->smax > worker->hmax) { worker->smax = worker->hmax; } /* Set min to be lower then smax */ if (worker->min > worker->smax) { worker->min = worker->smax; } } else { /* This will supress the apr_reslist creation */ worker->min = worker->smax = worker->hmax = 0; } if (worker->hmax) { rv = apr_reslist_create(&(worker->cp->res), worker->min, worker->smax, worker->hmax, worker->ttl, connection_constructor, connection_destructor, worker, worker->cp->pool); apr_pool_cleanup_register(worker->cp->pool, (void *)worker, conn_pool_cleanup, apr_pool_cleanup_null); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: initialized worker %d in child %" APR_PID_T_FMT " for (%s) min=%d max=%d smax=%d", worker->id, getpid(), worker->hostname, worker->min, worker->hmax, worker->smax);#if (APR_MAJOR_VERSION > 0) /* Set the acquire timeout */ if (rv == APR_SUCCESS && worker->acquire_set) { apr_reslist_timeout_set(worker->cp->res, worker->acquire); }#endif } else#endif { rv = connection_constructor((void **)&(worker->cp->conn), worker, worker->cp->pool); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: initialized single connection worker %d in child %" APR_PID_T_FMT " for (%s)", worker->id, getpid(), worker->hostname); } if (rv == APR_SUCCESS) { worker->status |= (PROXY_WORKER_INITIALIZED); } return rv;}PROXY_DECLARE(int) ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worker, server_rec *s){ if (worker->s->status & PROXY_WORKER_IN_ERROR) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: %s: retrying the worker for (%s)", proxy_function, worker->hostname); if (apr_time_now() > worker->s->error_time + worker->retry) { ++worker->s->retries; worker->s->status &= ~PROXY_WORKER_IN_ERROR; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: %s: worker for (%s) has been marked for retry", proxy_function, worker->hostname); return OK; } else { return DECLINED; } } else { return OK; }}PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function, proxy_conn_rec **conn, proxy_worker *worker, server_rec *s){ apr_status_t rv; if (!PROXY_WORKER_IS_USABLE(worker)) { /* Retry the worker */ ap_proxy_retry_worker(proxy_function, worker, s); if (!PROXY_WORKER_IS_USABLE(worker)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "proxy: %s: disabled connection for (%s)", proxy_function, worker->hostname); return HTTP_SERVICE_UNAVAILABLE; } }#if APR_HAS_THREADS if (worker->hmax && worker->cp->res) { rv = apr_reslist_acquire(worker->cp->res, (void **)conn); } else#endif { /* create the new connection if the previous was destroyed */ if (!worker->cp->conn) { connection_constructor((void **)conn, worker, worker->cp->pool); } else { *conn = worker->cp->conn; worker->cp->conn = NULL; } rv = APR_SUCCESS; } if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "proxy: %s: failed to acquire connection for (%s)", proxy_function, worker->hostname); return HTTP_SERVICE_UNAVAILABLE; } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: %s: has acquired connection for (%s)", proxy_function, worker->hostname); (*conn)->worker = worker; (*conn)->close = 0; (*conn)->close_on_recycle = 0;#if APR_HAS_THREADS (*conn)->inreslist = 0;#endif return OK;}PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function, proxy_conn_rec *conn, server_rec *s){ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?