📄 proxy_util.c
字号:
server_rec *s = (server_rec *)params;
#if 0
if (conn->sock)
apr_socket_close(conn->sock);
conn->sock = NULL;
apr_pool_cleanup_kill(conn->pool, conn, proxy_conn_cleanup);
#endif
if (conn->pool)
apr_pool_destroy(conn->pool);
conn->pool = NULL;
#if 0
if (s != NULL)
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: socket is destructed");
#endif
return APR_SUCCESS;
}
/* Close the connection
* The proxy_conn_rec from now on can not be used
*/
PROXY_DECLARE(apr_status_t) ap_proxy_close_connection(proxy_conn_rec *conn)
{
if (conn->worker && conn->worker->cp)
conn->worker->cp->conn = NULL;
return connection_destructor(conn, NULL, NULL);
}
static apr_status_t init_conn_worker(proxy_worker *worker, server_rec *s)
{
apr_status_t rv;
#if APR_HAS_THREADS
int mpm_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;
worker->cp->nfree = worker->hmax;
}
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,
s, worker->cp->pool);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: initialized worker for (%s) min=%d max=%d smax=%d",
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
{
connection_constructor((void **)&(worker->cp->conn), s, worker->cp->pool);
rv = APR_SUCCESS;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: initialized single connection worker for (%s)",
worker->hostname);
}
return rv;
}
PROXY_DECLARE(int) ap_proxy_retry_worker(const char *proxy_function,
proxy_worker *worker,
server_rec *s)
{
if (worker->status & PROXY_WORKER_IN_ERROR) {
apr_interval_time_t diff;
apr_time_t now = apr_time_now();
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: %s: retrying the worker for (%s)",
proxy_function, worker->hostname);
if (worker->retry)
diff = worker->retry;
else
diff = apr_time_from_sec((60 + 60 * worker->retries++));
if (now > worker->error_time + diff) {
worker->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 (!(worker->status & PROXY_WORKER_INITIALIZED)) {
if ((rv = init_conn_worker(worker, s)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"proxy: %s: failed to initialize worker for (%s)",
proxy_function, worker->hostname);
return HTTP_INTERNAL_SERVER_ERROR;
}
worker->status = PROXY_WORKER_INITIALIZED;
}
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, rv, s,
"proxy: %s: disabled connection for (%s)",
proxy_function, worker->hostname);
return HTTP_SERVICE_UNAVAILABLE;
}
}
#if APR_HAS_THREADS
if (worker->hmax) {
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, s, 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;
return OK;
}
PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function,
proxy_conn_rec *conn,
server_rec *s)
{
apr_status_t rv = APR_SUCCESS;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: %s: has relesed connection for (%s)",
proxy_function, conn->worker->hostname);
/* If there is a connection kill it's cleanup */
if (conn->connection)
apr_pool_cleanup_kill(conn->connection->pool, conn, connection_cleanup);
connection_cleanup(conn);
conn->connection = NULL;
return OK;
}
PROXY_DECLARE(int)
ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
proxy_server_conf *conf,
proxy_worker *worker,
proxy_conn_rec *conn,
apr_pool_t *ppool,
apr_uri_t *uri,
char **url,
const char *proxyname,
apr_port_t proxyport,
char *server_portstr,
int server_portstr_size)
{
int server_port;
apr_status_t err = APR_SUCCESS;
/*
* Break up the URL to determine the host to connect to
*/
/* we break the URL into host, port, uri */
if (APR_SUCCESS != apr_uri_parse(p, *url, uri)) {
return ap_proxyerror(r, HTTP_BAD_REQUEST,
apr_pstrcat(p,"URI cannot be parsed: ", *url,
NULL));
}
if (!uri->port) {
uri->port = apr_uri_port_of_scheme(uri->scheme);
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: connecting %s to %s:%d", *url, uri->hostname,
uri->port);
/* allocate these out of the specified connection pool
* The scheme handler decides if this is permanent or
* short living pool.
*/
/* are we connecting directly, or via a proxy? */
if (proxyname) {
conn->hostname = apr_pstrdup(ppool, proxyname);
conn->port = proxyport;
} else {
conn->hostname = apr_pstrdup(ppool, uri->hostname);
conn->port = uri->port;
*url = apr_pstrcat(p, uri->path, uri->query ? "?" : "",
uri->query ? uri->query : "",
uri->fragment ? "#" : "",
uri->fragment ? uri->fragment : "", NULL);
}
/* Worker can have the single constant backend adress.
* The single DNS lookup is used once per worker.
* If dynamic change is needed then set the addr to NULL
* inside dynamic config to force the lookup.
*/
if (!worker->cp->addr)
err = apr_sockaddr_info_get(&(worker->cp->addr),
conn->hostname, APR_UNSPEC,
conn->port, 0,
worker->cp->pool);
if (err != APR_SUCCESS) {
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
apr_pstrcat(p, "DNS lookup failure for: ",
conn->hostname, NULL));
}
/* Get the server port for the Via headers */
{
server_port = ap_get_server_port(r);
if (ap_is_default_port(server_port, r)) {
strcpy(server_portstr,"");
} else {
apr_snprintf(server_portstr, server_portstr_size, ":%d",
server_port);
}
}
/* check if ProxyBlock directive on this host */
if (OK != ap_proxy_checkproxyblock(r, conf, worker->cp->addr)) {
return ap_proxyerror(r, HTTP_FORBIDDEN,
"Connect to remote machine blocked");
}
return OK;
}
static int is_socket_connected(apr_socket_t *sock)
{
apr_size_t buffer_len = 1;
char test_buffer[1];
apr_status_t socket_status;
apr_interval_time_t current_timeout;
/* save timeout */
apr_socket_timeout_get(sock, ¤t_timeout);
/* set no timeout */
apr_socket_timeout_set(sock, 0);
socket_status = apr_socket_recv(sock, test_buffer, &buffer_len);
/* put back old timeout */
apr_socket_timeout_set(sock, current_timeout);
if (APR_STATUS_IS_EOF(socket_status))
return 0;
else
return 1;
}
PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
proxy_conn_rec *conn,
proxy_worker *worker,
server_rec *s)
{
apr_status_t rv;
int connected = 0;
int loglevel;
apr_sockaddr_t *backend_addr = worker->cp->addr;
apr_socket_t *newsock;
if (conn->sock) {
/* This increases the connection pool size
* but the number of dropped connections is
* relatively small compared to connection lifetime
*/
if (!(connected = is_socket_connected(conn->sock))) {
apr_socket_close(conn->sock);
conn->sock = NULL;
}
}
while (backend_addr && !connected) {
if ((rv = apr_socket_create(&newsock, backend_addr->family,
SOCK_STREAM, APR_PROTO_TCP,
conn->pool)) != APR_SUCCESS) {
loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
ap_log_error(APLOG_MARK, loglevel, rv, s,
"proxy: %s: error creating fam %d socket for target %s",
proxy_function,
backend_addr->family,
worker->hostname);
/* this could be an IPv6 address from the DNS but the
* local machine won't give us an IPv6 socket; hopefully the
* DNS returned an additional address to try
*/
backend_addr = backend_addr->next;
continue;
}
#if !defined(TPF) && !defined(BEOS)
if (worker->recv_buffer_size > 0 &&
(rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF,
worker->recv_buffer_size))) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"apr_socket_opt_set(SO_RCVBUF): Failed to set "
"ProxyReceiveBufferSize, using default");
}
#endif
/* Set a timeout on the socket */
if (worker->timeout_set == 1) {
apr_socket_timeout_set(newsock, worker->timeout);
}
else {
apr_socket_timeout_set(newsock, s->timeout);
}
/* Set a keepalive option */
if (worker->keepalive) {
if ((rv = apr_socket_opt_set(newsock,
APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"apr_socket_opt_set(SO_KEEPALIVE): Failed to set"
" Keepalive");
}
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: %s: fam %d socket created to connect to %s",
proxy_function, backend_addr->family, worker->hostname);
/* make the connection out of the socket */
rv = apr_socket_connect(newsock, backend_addr);
/* if an error occurred, loop round and try again */
if (rv != APR_SUCCESS) {
apr_socket_close(newsock);
loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
ap_log_error(APLOG_MARK, loglevel, rv, s,
"proxy: %s: attempt to connect to %pI (%s) failed",
proxy_function,
backend_addr,
worker->hostname);
backend_addr = backend_addr->next;
continue;
}
conn->sock = newsock;
connected = 1;
}
/* Put the entire worker to error state
* Altrough some connections may be alive
* no further connections to the worker could be made
*/
if (!connected && PROXY_WORKER_IS_USABLE(worker)) {
worker->status |= PROXY_WORKER_IN_ERROR;
worker->error_time = apr_time_now();
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
"ap_proxy_connect_backend disabling worker for (%s)",
worker->hostname);
}
else {
worker->error_time = 0;
worker->retries = 0;
}
return connected ? OK : DECLINED;
}
PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,
proxy_conn_rec *conn,
conn_rec *c,
server_rec *s)
{
proxy_worker *worker = conn->worker;
apr_sockaddr_t *backend_addr = worker->cp->addr;
/* The socket is now open, create a new backend server connection
*
*/
conn->connection = ap_run_create_connection(c->pool, s, conn->sock,
c->id, c->sbh,
c->bucket_alloc);
if (!conn->connection) {
/* the peer reset the connection already; ap_run_create_connection()
* closed the socket
*/
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
s, "proxy: %s: an error occurred creating a "
"new connection to %pI (%s)", proxy_function,
backend_addr, conn->hostname);
/* XXX: Will be closed when proxy_conn is closed */
apr_socket_close(conn->sock);
conn->sock = NULL;
return HTTP_INTERNAL_SERVER_ERROR;
}
/* register the connection cleanup to client connection
* so that the connection can be closed or reused
*/
apr_pool_cleanup_register(c->pool, (void *)conn,
connection_cleanup,
apr_pool_cleanup_null);
/* For ssl connection to backend */
if (conn->is_ssl) {
if (!ap_proxy_ssl_enable(conn->connection)) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0,
s, "proxy: %s: failed to enable ssl support "
"for %pI (%s)", proxy_function,
backend_addr, conn->hostname);
return HTTP_INTERNAL_SERVER_ERROR;
}
}
else {
/* TODO: See if this will break FTP */
ap_proxy_ssl_disable(conn->connection);
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: %s: connection complete to %pI (%s)",
proxy_function, backend_addr, conn->hostname);
/* set up the connection filters */
ap_run_pre_connection(conn->connection, conn->sock);
return OK;
}
PROXY_DECLARE(int) ap_proxy_lb_workers(void)
{
/* Set the dynamic #workers limit */
lb_workers_limit = lb_workers + PROXY_DYNAMIC_BALANCER_LIMIT;
return lb_workers_limit;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -