mod_proxy_balancer.c revision 842ecd514118c56a88f0b969840775dba2cbc720
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny/* Licensed to the Apache Software Foundation (ASF) under one or more
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * contributor license agreements. See the NOTICE file distributed with
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * this work for additional information regarding copyright ownership.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * The ASF licenses this file to You under the Apache License, Version 2.0
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * (the "License"); you may not use this file except in compliance with
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * the License. You may obtain a copy of the License at
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * http://www.apache.org/licenses/LICENSE-2.0
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * Unless required by applicable law or agreed to in writing, software
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * distributed under the License is distributed on an "AS IS" BASIS,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * See the License for the specific language governing permissions and
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * limitations under the License.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny/* Load balancer module for Apache proxy */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#define CORE_PRIVATE
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "mod_proxy.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "ap_mpm.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "apr_version.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "apr_hooks.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce#if APR_HAVE_UNISTD_H
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include <unistd.h> /* for getpid() */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#endif
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenymodule AP_MODULE_DECLARE_DATA proxy_balancer_module;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystatic int proxy_balancer_canon(request_rec *r, char *url)
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce{
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny char *host, *path, *search;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny const char *err;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose apr_port_t port = 0;
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if (strncasecmp(url, "balancer:", 9) == 0) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny url += 9;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny else {
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose return DECLINED;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose }
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose "proxy: BALANCER: canonicalising URL %s", url);
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek /* do syntatic check.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * We break the URL into host, port, path, search
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (err) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "error parsing URL %s: %s",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny url, err);
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce return HTTP_BAD_REQUEST;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny /* now parse path/search args, according to rfc1738 */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny /* N.B. if this isn't a true proxy request, then the URL _path_
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * has already been decoded. True proxy requests have r->uri
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce * == r->unparsed_uri, and no others have that property.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (r->uri == r->unparsed_uri) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny search = strchr(url, '?');
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (search != NULL)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *(search++) = '\0';
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny else
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce search = r->args;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce /* process path */
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0, r->proxyreq);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (path == NULL)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce return HTTP_BAD_REQUEST;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce r->filename = apr_pstrcat(r->pool, "proxy:balancer://", host,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny r->path_info = apr_pstrcat(r->pool, "/", path, NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce return OK;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce}
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorcestatic int init_balancer_members(proxy_server_conf *conf, server_rec *s,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov proxy_balancer *balancer)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov{
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny int i;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny proxy_worker *workers;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny workers = (proxy_worker *)balancer->workers->elts;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce for (i = 0; i < balancer->workers->nelts; i++) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_proxy_initialize_worker_share(conf, workers, s);
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce ap_proxy_initialize_worker(workers, s);
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce ++workers;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce }
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce workers = (proxy_worker *)balancer->workers->elts;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny for (i = 0; i < balancer->workers->nelts; i++) {
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose /* Set to the original configuration */
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose workers[i].s->lbstatus = workers[i].s->lbfactor =
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose (workers[i].lbfactor ? workers[i].lbfactor : 1);
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek }
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek /* Set default number of attempts to the number of
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek * workers.
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose */
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if (!balancer->max_attempts_set && balancer->workers->nelts > 1) {
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose balancer->max_attempts = balancer->workers->nelts - 1;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce balancer->max_attempts_set = 1;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce return 0;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce}
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce/* Retrieve the parameter with the given name
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * Something like 'JSESSIONID=12345...N'
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashovstatic char *get_path_param(apr_pool_t *pool, char *url,
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce const char *name)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce{
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce char *path = NULL;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce for (path = strstr(url, name); path; path = strstr(path + 1, name)) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce path += strlen(name);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (*path == '=') {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce /*
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * Session path was found, get it's value
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov ++path;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (strlen(path)) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce char *q;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce path = apr_pstrdup(pool, path);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if ((q = strchr(path, '?')))
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce *q = '\0';
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce return path;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov return NULL;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov}
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorcestatic char *get_cookie_param(request_rec *r, const char *name)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce{
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce const char *cookies;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce const char *start_cookie;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if ((cookies = apr_table_get(r->headers_in, "Cookie"))) {
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose for (start_cookie = ap_strstr_c(cookies, name); start_cookie;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose start_cookie = ap_strstr_c(start_cookie + 1, name)) {
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose if (start_cookie == cookies ||
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov start_cookie[-1] == ';' ||
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose start_cookie[-1] == ',' ||
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov isspace(start_cookie[-1])) {
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose start_cookie += strlen(name);
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose while(*start_cookie && isspace(*start_cookie))
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek ++start_cookie;
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek if (*start_cookie == '=' && start_cookie[1]) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /*
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek * Session cookie was found, get it's value
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov */
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek char *end_cookie, *cookie;
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek ++start_cookie;
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek cookie = apr_pstrdup(r->pool, start_cookie);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if ((end_cookie = strchr(cookie, ';')) != NULL)
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose *end_cookie = '\0';
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if((end_cookie = strchr(cookie, ',')) != NULL)
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose *end_cookie = '\0';
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov return cookie;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose }
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose }
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose }
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose return NULL;
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose}
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose/* Find the worker that has the 'route' defined
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosestatic proxy_worker *find_route_worker(proxy_balancer *balancer,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose const char *route, request_rec *r)
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose{
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose int i;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose int checking_standby = 0;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose int checked_standby = 0;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose proxy_worker *worker;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose while (!checked_standby) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose worker = (proxy_worker *)balancer->workers->elts;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose for (i = 0; i < balancer->workers->nelts; i++, worker++) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose continue;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (*(worker->s->route) && strcmp(worker->s->route, route) == 0) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (worker && PROXY_WORKER_IS_USABLE(worker)) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return worker;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose } else {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /*
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * If the worker is in error state run
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * retry on that worker. It will be marked as
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * operational if the retry timeout is elapsed.
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * The worker might still be unusable, but we try
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * anyway.
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose ap_proxy_retry_worker("BALANCER", worker, r->server);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (PROXY_WORKER_IS_USABLE(worker)) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return worker;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose } else {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /*
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * We have a worker that is unusable.
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * It can be in error or disabled, but in case
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * it has a redirection set use that redirection worker.
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * This enables to safely remove the member from the
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * balancer. Of course you will need some kind of
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek * session replication between those two remote.
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose */
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (*worker->s->redirect) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce proxy_worker *rworker = NULL;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce rworker = find_route_worker(balancer, worker->s->redirect, r);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce /* Check if the redirect worker is usable */
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (rworker && !PROXY_WORKER_IS_USABLE(rworker)) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny /*
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * If the worker is in error state run
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * retry on that worker. It will be marked as
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * operational if the retry timeout is elapsed.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * The worker might still be unusable, but we try
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * anyway.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_proxy_retry_worker("BALANCER", rworker, r->server);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (rworker && PROXY_WORKER_IS_USABLE(rworker))
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce return rworker;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny checked_standby = checking_standby++;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce return NULL;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny}
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
17195241500e46272018d7897d6e87249870caf2Pavel Reichlstatic proxy_worker *find_session_route(proxy_balancer *balancer,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny request_rec *r,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose char **route,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny char **url)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny{
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny proxy_worker *worker = NULL;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (!balancer->sticky)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return NULL;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce /* Try to find the sticky route inside url */
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce *route = get_path_param(r->pool, *url, balancer->sticky);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (!*route)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny *route = get_cookie_param(r, balancer->sticky);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "proxy: BALANCER: Found value %s for "
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce "stickysession %s", *route, balancer->sticky);
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce /*
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * If we found a value for sticksession, find the first '.' within.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * Everything after '.' (if present) is our route.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if ((*route) && ((*route = strchr(*route, '.')) != NULL ))
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny (*route)++;
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce if ((*route) && (**route)) {
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce "proxy: BALANCER: Found route %s", *route);
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce /* We have a route in path or in cookie
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce * Find the worker that has this route defined.
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov worker = find_route_worker(balancer, *route, r);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov return worker;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny else
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return NULL;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny}
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorcestatic proxy_worker *find_best_worker(proxy_balancer *balancer,
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce request_rec *r)
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce{
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce proxy_worker *candidate = NULL;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce if (PROXY_THREAD_LOCK(balancer) != APR_SUCCESS)
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce return NULL;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce candidate = (*balancer->lbmethod->finder)(balancer, r);
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce/*
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny PROXY_THREAD_UNLOCK(balancer);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return NULL;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce*/
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce PROXY_THREAD_UNLOCK(balancer);
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce if (candidate == NULL) {
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce /* All the workers are in error state or disabled.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * If the balancer has a timeout sleep for a while
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * and try again to find the worker. The chances are
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * that some other thread will release a connection.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * By default the timeout is not set, and the server
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * returns SERVER_BUSY.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny#if APR_HAS_THREADS
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce if (balancer->timeout) {
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce /* XXX: This can perhaps be build using some
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce * smarter mechanism, like tread_cond.
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce * But since the statuses can came from
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce * different childs, use the provided algo.
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_interval_time_t timeout = balancer->timeout;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_interval_time_t step, tval = 0;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* Set the timeout to 0 so that we don't
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * end in infinite loop
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny */
17195241500e46272018d7897d6e87249870caf2Pavel Reichl balancer->timeout = 0;
17195241500e46272018d7897d6e87249870caf2Pavel Reichl step = timeout / 100;
17195241500e46272018d7897d6e87249870caf2Pavel Reichl while (tval < timeout) {
17195241500e46272018d7897d6e87249870caf2Pavel Reichl apr_sleep(step);
17195241500e46272018d7897d6e87249870caf2Pavel Reichl /* Try again */
17195241500e46272018d7897d6e87249870caf2Pavel Reichl if ((candidate = find_best_worker(balancer, r)))
17195241500e46272018d7897d6e87249870caf2Pavel Reichl break;
17195241500e46272018d7897d6e87249870caf2Pavel Reichl tval += step;
17195241500e46272018d7897d6e87249870caf2Pavel Reichl }
17195241500e46272018d7897d6e87249870caf2Pavel Reichl /* restore the timeout */
17195241500e46272018d7897d6e87249870caf2Pavel Reichl balancer->timeout = timeout;
17195241500e46272018d7897d6e87249870caf2Pavel Reichl }
17195241500e46272018d7897d6e87249870caf2Pavel Reichl#endif
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return candidate;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose}
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosestatic int rewrite_url(request_rec *r, proxy_worker *worker,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose char **url)
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose{
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose const char *scheme = strstr(*url, "://");
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose const char *path = NULL;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (scheme)
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose path = ap_strchr_c(scheme + 3, '/');
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* we break the URL into host, port, uri */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (!worker) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return ap_proxyerror(r, HTTP_BAD_REQUEST, apr_pstrcat(r->pool,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose "missing worker. URI cannot be parsed: ", *url,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose NULL));
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose *url = apr_pstrcat(r->pool, worker->name, path, NULL);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return OK;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose}
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosestatic int proxy_balancer_pre_request(proxy_worker **worker,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose proxy_balancer **balancer,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose request_rec *r,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose proxy_server_conf *conf, char **url)
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose{
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose int access_status;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose proxy_worker *runtime;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose char *route = NULL;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose apr_status_t rv;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose *worker = NULL;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* Step 1: check if the url is for us
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * The url we can handle starts with 'balancer://'
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * If balancer is already provided skip the search
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * for balancer, because this is failover attempt.
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (!*balancer &&
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose !(*balancer = ap_proxy_get_balancer(r->pool, conf, *url)))
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return DECLINED;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* Step 2: find the session route */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose runtime = find_session_route(*balancer, r, &route, url);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* Lock the LoadBalancer
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * XXX: perhaps we need the process lock here
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if ((rv = PROXY_THREAD_LOCK(*balancer)) != APR_SUCCESS) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose "proxy: BALANCER: lock");
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return DECLINED;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (runtime) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose int i, total_factor = 0;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose proxy_worker *workers;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* We have a sticky load balancer
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * Update the workers status
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * so that even session routes get
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * into account.
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose workers = (proxy_worker *)(*balancer)->workers->elts;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose for (i = 0; i < (*balancer)->workers->nelts; i++) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* Take into calculation only the workers that are
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * not in error state or not disabled.
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose *
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * TODO: Abstract the below, since this is dependent
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * on the LB implementation
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (PROXY_WORKER_IS_USABLE(workers)) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose workers->s->lbstatus += workers->s->lbfactor;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose total_factor += workers->s->lbfactor;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose workers++;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose runtime->s->lbstatus -= total_factor;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose runtime->s->elected++;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose *worker = runtime;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose else if (route && (*balancer)->sticky_force) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose "proxy: BALANCER: (%s). All workers are in error state for route (%s)",
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny (*balancer)->name, route);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny PROXY_THREAD_UNLOCK(*balancer);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return HTTP_SERVICE_UNAVAILABLE;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce PROXY_THREAD_UNLOCK(*balancer);
17195241500e46272018d7897d6e87249870caf2Pavel Reichl if (!*worker) {
17195241500e46272018d7897d6e87249870caf2Pavel Reichl runtime = find_best_worker(*balancer, r);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (!runtime) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "proxy: BALANCER: (%s). All workers are in error state",
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny (*balancer)->name);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return HTTP_SERVICE_UNAVAILABLE;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny *worker = runtime;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* Add balancer/worker info to env. */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_table_setn(r->subprocess_env,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "BALANCER_NAME", (*balancer)->name);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_table_setn(r->subprocess_env,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "BALANCER_WORKER_NAME", (*worker)->name);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_table_setn(r->subprocess_env,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "BALANCER_WORKER_ROUTE", (*worker)->s->route);
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce
0754ff886f909f0404038eb9c99dd61be1acf5b9Simo Sorce /* Rewrite the url from 'balancer://url'
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * to the 'worker_scheme://worker_hostname[:worker_port]/url'
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * This replaces the balancers fictional name with the
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * real hostname of the elected worker.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny access_status = rewrite_url(r, *worker, url);
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce /* Add the session route to request notes if present */
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce if (route) {
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce apr_table_setn(r->notes, "session-sticky", (*balancer)->sticky);
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce apr_table_setn(r->notes, "session-route", route);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* Add session info to env. */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_table_setn(r->subprocess_env,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "BALANCER_SESSION_STICKY", (*balancer)->sticky);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_table_setn(r->subprocess_env,
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce "BALANCER_SESSION_ROUTE", route);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
c03b28a38b14fdb59f74864ae4dc56affe256508Simo Sorce ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "proxy: BALANCER (%s) worker (%s) rewritten to %s",
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny (*balancer)->name, (*worker)->name, *url);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return access_status;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny}
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorcestatic int proxy_balancer_post_request(proxy_worker *worker,
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce proxy_balancer *balancer,
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce request_rec *r,
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce proxy_server_conf *conf)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny{
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_status_t rv;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce "proxy: BALANCER: lock");
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return HTTP_INTERNAL_SERVER_ERROR;
c03b28a38b14fdb59f74864ae4dc56affe256508Simo Sorce }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* TODO: calculate the bytes transferred
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * This will enable to elect the worker that has
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * the lowest load.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * The bytes transferred depends on the protocol
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * used, so each protocol handler should keep the
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * track on that.
17195241500e46272018d7897d6e87249870caf2Pavel Reichl */
17195241500e46272018d7897d6e87249870caf2Pavel Reichl
17195241500e46272018d7897d6e87249870caf2Pavel Reichl PROXY_THREAD_UNLOCK(balancer);
17195241500e46272018d7897d6e87249870caf2Pavel Reichl ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
17195241500e46272018d7897d6e87249870caf2Pavel Reichl "proxy_balancer_post_request for (%s)", balancer->name);
17195241500e46272018d7897d6e87249870caf2Pavel Reichl
17195241500e46272018d7897d6e87249870caf2Pavel Reichl return OK;
17195241500e46272018d7897d6e87249870caf2Pavel Reichl}
17195241500e46272018d7897d6e87249870caf2Pavel Reichl
17195241500e46272018d7897d6e87249870caf2Pavel Reichlstatic void recalc_factors(proxy_balancer *balancer)
17195241500e46272018d7897d6e87249870caf2Pavel Reichl{
17195241500e46272018d7897d6e87249870caf2Pavel Reichl int i;
17195241500e46272018d7897d6e87249870caf2Pavel Reichl proxy_worker *workers;
17195241500e46272018d7897d6e87249870caf2Pavel Reichl
17195241500e46272018d7897d6e87249870caf2Pavel Reichl
17195241500e46272018d7897d6e87249870caf2Pavel Reichl /* Recalculate lbfactors */
17195241500e46272018d7897d6e87249870caf2Pavel Reichl workers = (proxy_worker *)balancer->workers->elts;
17195241500e46272018d7897d6e87249870caf2Pavel Reichl /* Special case if there is only one worker it's
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * load factor will always be 1
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (balancer->workers->nelts == 1) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny workers->s->lbstatus = workers->s->lbfactor = 1;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return;
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny for (i = 0; i < balancer->workers->nelts; i++) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* Update the status entries */
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce workers[i].s->lbstatus = workers[i].s->lbfactor;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny}
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny/* Manages the loadfactors and member status
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny */
3b0e0352d8076909608d04750d3ea6b0d9ba33f6Jakub Hrozekstatic int balancer_handler(request_rec *r)
3b0e0352d8076909608d04750d3ea6b0d9ba33f6Jakub Hrozek{
3b0e0352d8076909608d04750d3ea6b0d9ba33f6Jakub Hrozek void *sconf = r->server->module_config;
3b0e0352d8076909608d04750d3ea6b0d9ba33f6Jakub Hrozek proxy_server_conf *conf = (proxy_server_conf *)
3b0e0352d8076909608d04750d3ea6b0d9ba33f6Jakub Hrozek ap_get_module_config(sconf, &proxy_module);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny proxy_balancer *balancer, *bsel = NULL;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny proxy_worker *worker, *wsel = NULL;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_table_t *params = apr_table_make(r->pool, 10);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny int access_status;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny int i, n;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny const char *name;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce /* is this for us? */
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if (strcmp(r->handler, "balancer-manager"))
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce return DECLINED;
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose r->allowed = (AP_METHOD_BIT << M_GET);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if (r->method_number != M_GET)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny return DECLINED;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (r->args) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce char *args = apr_pstrdup(r->pool, r->args);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce char *tok, *val;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce while (args && *args) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if ((val = ap_strchr(args, '='))) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce *val++ = '\0';
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if ((tok = ap_strchr(val, '&')))
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose *tok++ = '\0';
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek /*
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose * Special case: workers are allowed path information
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce */
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if ((access_status = ap_unescape_url(val)) != OK)
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose if (strcmp(args, "w") || (access_status != HTTP_NOT_FOUND))
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce return access_status;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce apr_table_setn(params, args, val);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce args = tok;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce }
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose else
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek return HTTP_BAD_REQUEST;
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if ((name = apr_table_get(params, "b")))
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny bsel = ap_proxy_get_balancer(r->pool, conf,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny apr_pstrcat(r->pool, "balancer://", name, NULL));
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if ((name = apr_table_get(params, "w"))) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny proxy_worker *ws;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ws = ap_proxy_get_worker(r->pool, conf, name);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if (ws) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce worker = (proxy_worker *)bsel->workers->elts;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce for (n = 0; n < bsel->workers->nelts; n++) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if (strcasecmp(worker->name, ws->name) == 0) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce wsel = worker;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce break;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce }
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ++worker;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce /* First set the params */
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if (bsel) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce const char *val;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if ((val = apr_table_get(params, "ss"))) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if (strlen(val))
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce bsel->sticky = apr_pstrdup(conf->pool, val);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce else
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce bsel->sticky = NULL;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce }
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose if ((val = apr_table_get(params, "tm"))) {
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek int ival = atoi(val);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if (ival >= 0)
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce bsel->timeout = apr_time_from_sec(ival);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if ((val = apr_table_get(params, "fa"))) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce int ival = atoi(val);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if (ival >= 0)
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce bsel->max_attempts = ival;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce bsel->max_attempts_set = 1;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce }
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if ((val = apr_table_get(params, "lm"))) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce proxy_balancer_method *provider;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce provider = ap_lookup_provider(PROXY_LBMETHOD, val, "0");
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if (provider) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce bsel->lbmethod = provider;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce }
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce }
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce }
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if (wsel) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce const char *val;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if ((val = apr_table_get(params, "lf"))) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce int ival = atoi(val);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if (ival >= 1 && ival <= 100) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce wsel->s->lbfactor = ival;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if (bsel)
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce recalc_factors(bsel);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce }
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose }
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose if ((val = apr_table_get(params, "wr"))) {
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose if (strlen(val) && strlen(val) < PROXY_WORKER_MAX_ROUTE_SIZ)
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose strcpy(wsel->s->route, val);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose else
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose *wsel->s->route = '\0';
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek }
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek if ((val = apr_table_get(params, "rr"))) {
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek if (strlen(val) && strlen(val) < PROXY_WORKER_MAX_ROUTE_SIZ)
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek strcpy(wsel->s->redirect, val);
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek else
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose *wsel->s->redirect = '\0';
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose }
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if ((val = apr_table_get(params, "dw"))) {
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if (!strcasecmp(val, "Disable"))
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose wsel->s->status |= PROXY_WORKER_DISABLED;
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose else if (!strcasecmp(val, "Enable"))
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose wsel->s->status &= ~PROXY_WORKER_DISABLED;
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose if (apr_table_get(params, "xml")) {
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_set_content_type(r, "text/xml");
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rputs("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<httpd:manager xmlns:httpd=\"http://httpd.apache.org\">\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs(" <httpd:balancers>\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny balancer = (proxy_balancer *)conf->balancers->elts;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce for (i = 0; i < conf->balancers->nelts; i++) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rputs(" <httpd:balancer>\n", r);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rvputs(r, " <httpd:name>", balancer->name, "</httpd:name>\n", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs(" <httpd:workers>\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny worker = (proxy_worker *)balancer->workers->elts;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce for (n = 0; n < balancer->workers->nelts; n++) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rputs(" <httpd:worker>\n", r);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose ap_rvputs(r, " <httpd:scheme>", worker->scheme,
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce "</httpd:scheme>\n", NULL);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rvputs(r, " <httpd:hostname>", worker->hostname,
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce "</httpd:hostname>\n", NULL);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rprintf(r, " <httpd:loadfactor>%d</httpd:loadfactor>\n",
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce worker->s->lbfactor);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rputs(" </httpd:worker>\n", r);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ++worker;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce }
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rputs(" </httpd:workers>\n", r);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rputs(" </httpd:balancer>\n", r);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ++balancer;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs(" </httpd:balancers>\n", r);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rputs("</httpd:manager>", r);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce }
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce else {
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce ap_set_content_type(r, "text/html");
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce ap_rputs(DOCTYPE_HTML_3_2
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce "<html><head><title>Balancer Manager</title></head>\n", r);
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce ap_rputs("<body><h1>Load Balancer Manager for ", r);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rvputs(r, ap_get_server_name(r), "</h1>\n\n", NULL);
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce ap_rvputs(r, "<dl><dt>Server Version: ",
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce ap_get_server_version(), "</dt>\n", NULL);
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce ap_rvputs(r, "<dt>Server Built: ",
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce ap_get_server_built(), "\n</dt></dl>\n", NULL);
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce balancer = (proxy_balancer *)conf->balancers->elts;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce for (i = 0; i < conf->balancers->nelts; i++) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rputs("<hr />\n<h3>LoadBalancer Status for ", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "<a href=\"", r->uri, "?b=",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny balancer->name + sizeof("balancer://") - 1,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "\">", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, balancer->name, "</a></h3>\n\n", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("\n\n<table border=\"0\" style=\"text-align: left;\"><tr>"
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce "<th>StickySession</th><th>Timeout</th><th>FailoverAttempts</th><th>Method</th>"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "</tr>\n<tr>", r);
c03b28a38b14fdb59f74864ae4dc56affe256508Simo Sorce ap_rvputs(r, "<td>", balancer->sticky, NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rprintf(r, "</td><td>%" APR_TIME_T_FMT "</td>",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny apr_time_sec(balancer->timeout));
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rprintf(r, "<td>%d</td>\n", balancer->max_attempts);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rprintf(r, "<td>%s</td>\n",
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce balancer->lbmethod->name);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rputs("</table>\n<br />", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("\n\n<table border=\"0\" style=\"text-align: left;\"><tr>"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "<th>Worker URL</th>"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "<th>Route</th><th>RouteRedir</th>"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "<th>Factor</th><th>Status</th>"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "<th>Elected</th><th>To</th><th>From</th>"
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce "</tr>\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
c03b28a38b14fdb59f74864ae4dc56affe256508Simo Sorce worker = (proxy_worker *)balancer->workers->elts;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny for (n = 0; n < balancer->workers->nelts; n++) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "<tr>\n<td><a href=\"", r->uri, "?b=",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny balancer->name + sizeof("balancer://") - 1, "&w=",
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose ap_escape_uri(r->pool, worker->name),
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose "\">", NULL);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose ap_rvputs(r, worker->name, "</a></td>", NULL);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose ap_rvputs(r, "<td>", worker->s->route, NULL);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose ap_rvputs(r, "</td><td>", worker->s->redirect, NULL);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose ap_rprintf(r, "</td><td>%d</td><td>", worker->s->lbfactor);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose if (worker->s->status & PROXY_WORKER_DISABLED)
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose ap_rputs("Dis ", r);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose if (worker->s->status & PROXY_WORKER_IN_ERROR)
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose ap_rputs("Err ", r);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose if (worker->s->status & PROXY_WORKER_STOPPED)
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose ap_rputs("Stop ", r);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose if (worker->s->status & PROXY_WORKER_HOT_STANDBY)
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose ap_rputs("Stby ", r);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose if (PROXY_WORKER_IS_USABLE(worker))
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ap_rputs("Ok", r);
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek if (!PROXY_WORKER_IS_INITIALIZED(worker))
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ap_rputs("-", r);
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ap_rputs("</td>", r);
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ap_rprintf(r, "<td>%" APR_SIZE_T_FMT "</td>", worker->s->elected);
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ap_rprintf(r, "<td>%" APR_OFF_T_FMT "</td>", worker->s->transferred);
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ap_rprintf(r, "<td>%" APR_OFF_T_FMT "</td>", worker->s->read);
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ap_rputs("</tr>\n", r);
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ++worker;
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek }
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ap_rputs("</table>\n", r);
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ++balancer;
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek }
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ap_rputs("<hr />\n", r);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if (wsel && bsel) {
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rputs("<h3>Edit worker settings for ", r);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rvputs(r, wsel->name, "</h3>\n", NULL);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rvputs(r, "<form method=\"GET\" action=\"", NULL);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rvputs(r, r->uri, "\">\n<dl>", NULL);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rputs("<table><tr><td>Load factor:</td><td><input name=\"lf\" type=text ", r);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rprintf(r, "value=\"%d\"></td><tr>\n", wsel->s->lbfactor);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rputs("<tr><td>Route:</td><td><input name=\"wr\" type=text ", r);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rvputs(r, "value=\"", wsel->route, NULL);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rputs("\"></td><tr>\n", r);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rputs("<tr><td>Route Redirect:</td><td><input name=\"rr\" type=text ", r);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rvputs(r, "value=\"", wsel->redirect, NULL);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rputs("\"></td><tr>\n", r);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rputs("<tr><td>Status:</td><td>Disabled: <input name=\"dw\" value=\"Disable\" type=radio", r);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if (wsel->s->status & PROXY_WORKER_DISABLED)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs(" checked", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("> | Enabled: <input name=\"dw\" value=\"Enable\" type=radio", r);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (!(wsel->s->status & PROXY_WORKER_DISABLED))
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rputs(" checked", r);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov ap_rputs("></td><tr>\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<tr><td colspan=2><input type=submit value=\"Submit\"></td></tr>\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "</table>\n<input type=hidden name=\"w\" ", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "value=\"", ap_escape_uri(r->pool, wsel->name), "\">\n", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "<input type=hidden name=\"b\" ", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "value=\"", bsel->name + sizeof("balancer://") - 1,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "\">\n</form>\n", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<hr />\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny else if (bsel) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<h3>Edit balancer settings for ", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, bsel->name, "</h3>\n", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "<form method=\"GET\" action=\"", NULL);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce ap_rvputs(r, r->uri, "\">\n<dl>", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<table><tr><td>StickySession Identifier:</td><td><input name=\"ss\" type=text ", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (bsel->sticky)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "value=\"", bsel->sticky, "\"", NULL);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce ap_rputs("></td><tr>\n<tr><td>Timeout:</td><td><input name=\"tm\" type=text ", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rprintf(r, "value=\"%" APR_TIME_T_FMT "\"></td></tr>\n",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny apr_time_sec(bsel->timeout));
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<tr><td>Failover Attempts:</td><td><input name=\"fa\" type=text ", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rprintf(r, "value=\"%d\"></td></tr>\n",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny bsel->max_attempts);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<tr><td>LB Method:</td><td><select name=\"lm\">", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov apr_array_header_t *methods;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce ap_list_provider_names_t *method;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce int i;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny methods = ap_list_provider_names(r->pool, PROXY_LBMETHOD, "0");
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny method = (ap_list_provider_names_t *)methods->elts;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny for (i = 0; i < methods->nelts; i++) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rprintf(r, "<option value=\"%s\" %s>%s</option>", method->provider_name,
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce (!strcasecmp(bsel->lbmethod->name, method->provider_name)) ? "selected" : "",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny method->provider_name);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov method++;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("</select></td></tr>\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<tr><td colspan=2><input type=submit value=\"Submit\"></td></tr>\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "</table>\n<input type=hidden name=\"b\" ", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "value=\"", bsel->name + sizeof("balancer://") - 1,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "\">\n</form>\n", NULL);
ap_rputs("<hr />\n", r);
}
ap_rputs(ap_psignature("",r), r);
ap_rputs("</body></html>\n", r);
}
return OK;
}
static void child_init(apr_pool_t *p, server_rec *s)
{
while (s) {
void *sconf = s->module_config;
proxy_server_conf *conf;
proxy_balancer *balancer;
int i;
conf = (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module);
/* Initialize shared scoreboard data */
balancer = (proxy_balancer *)conf->balancers->elts;
for (i = 0; i < conf->balancers->nelts; i++) {
init_balancer_members(conf, s, balancer);
balancer++;
}
s = s->next;
}
}
/*
* The idea behind the find_best_byrequests scheduler is the following:
*
* lbfactor is "how much we expect this worker to work", or "the worker's
* normalized work quota".
*
* lbstatus is "how urgent this worker has to work to fulfill its quota
* of work".
*
* We distribute each worker's work quota to the worker, and then look
* which of them needs to work most urgently (biggest lbstatus). This
* worker is then selected for work, and its lbstatus reduced by the
* total work quota we distributed to all workers. Thus the sum of all
* lbstatus does not change.(*)
*
* If some workers are disabled, the others will
* still be scheduled correctly.
*
* If a balancer is configured as follows:
*
* worker a b c d
* lbfactor 25 25 25 25
*
* And b gets disabled, the following schedule is produced:
*
* a c d a c d a c d ...
*
* Note that the above lbfactor setting is the *exact* same as:
*
* worker a b c d
* lbfactor 1 1 1 1
*
* Asymmetric configurations work as one would expect. For
* example:
*
* worker a b c d
* lbfactor 1 1 1 2
*
* would have a, b and c all handling about the same
* amount of load with d handling twice what a or b
* or c handles individually. So we could see:
*
* b a d c d a c d b d ...
*
*/
static proxy_worker *find_best_byrequests(proxy_balancer *balancer,
request_rec *r)
{
int i;
int total_factor = 0;
proxy_worker *worker;
proxy_worker *mycandidate = NULL;
int checking_standby = 0;
int checked_standby = 0;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: Entering byrequests for BALANCER (%s)",
balancer->name);
/* First try to see if we have available candidate */
while (!mycandidate && !checked_standby) {
worker = (proxy_worker *)balancer->workers->elts;
for (i = 0; i < balancer->workers->nelts; i++, worker++) {
if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
continue;
/* If the worker is in error state run
* retry on that worker. It will be marked as
* operational if the retry timeout is elapsed.
* The worker might still be unusable, but we try
* anyway.
*/
if (!PROXY_WORKER_IS_USABLE(worker))
ap_proxy_retry_worker("BALANCER", worker, r->server);
/* Take into calculation only the workers that are
* not in error state or not disabled.
*/
if (PROXY_WORKER_IS_USABLE(worker)) {
worker->s->lbstatus += worker->s->lbfactor;
total_factor += worker->s->lbfactor;
if (!mycandidate || worker->s->lbstatus > mycandidate->s->lbstatus)
mycandidate = worker;
}
}
checked_standby = checking_standby++;
}
if (mycandidate) {
mycandidate->s->lbstatus -= total_factor;
mycandidate->s->elected++;
}
return mycandidate;
}
/*
* The idea behind the find_best_bytraffic scheduler is the following:
*
* We know the amount of traffic (bytes in and out) handled by each
* worker. We normalize that traffic by each workers' weight. So assuming
* a setup as below:
*
* worker a b c
* lbfactor 1 1 3
*
* the scheduler will allow worker c to handle 3 times the
* traffic of a and b. If each request/response results in the
* same amount of traffic, then c would be accessed 3 times as
* often as a or b. If, for example, a handled a request that
* resulted in a large i/o bytecount, then b and c would be
* chosen more often, to even things out.
*/
static proxy_worker *find_best_bytraffic(proxy_balancer *balancer,
request_rec *r)
{
int i;
apr_off_t mytraffic = 0;
apr_off_t curmin = 0;
proxy_worker *worker;
int checking_standby = 0;
int checked_standby = 0;
proxy_worker *mycandidate = NULL;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: Entering bytraffic for BALANCER (%s)",
balancer->name);
/* First try to see if we have available candidate */
while (!mycandidate && !checked_standby) {
worker = (proxy_worker *)balancer->workers->elts;
for (i = 0; i < balancer->workers->nelts; i++, worker++) {
if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
continue;
/* If the worker is in error state run
* retry on that worker. It will be marked as
* operational if the retry timeout is elapsed.
* The worker might still be unusable, but we try
* anyway.
*/
if (!PROXY_WORKER_IS_USABLE(worker))
ap_proxy_retry_worker("BALANCER", worker, r->server);
/* Take into calculation only the workers that are
* not in error state or not disabled.
*/
if (PROXY_WORKER_IS_USABLE(worker)) {
mytraffic = (worker->s->transferred/worker->s->lbfactor) +
(worker->s->read/worker->s->lbfactor);
if (!mycandidate || mytraffic < curmin) {
mycandidate = worker;
curmin = mytraffic;
}
}
}
checked_standby = checking_standby++;
}
if (mycandidate) {
mycandidate->s->elected++;
}
return mycandidate;
}
/*
* How to add additional lbmethods:
* 1. Create func which determines "best" candidate worker
* (eg: find_best_bytraffic, above)
* 2. Register it as a provider.
*/
static const proxy_balancer_method byrequests =
{
"byrequests",
&find_best_byrequests,
NULL
};
static const proxy_balancer_method bytraffic =
{
"bytraffic",
&find_best_bytraffic,
NULL
};
static void ap_proxy_balancer_register_hook(apr_pool_t *p)
{
/* Only the mpm_winnt has child init hook handler.
* make sure that we are called after the mpm
* initializes and after the mod_proxy
*/
static const char *const aszPred[] = { "mpm_winnt.c", "mod_proxy.c", NULL};
/* manager handler */
ap_hook_handler(balancer_handler, NULL, NULL, APR_HOOK_FIRST);
ap_hook_child_init(child_init, aszPred, NULL, APR_HOOK_MIDDLE);
proxy_hook_pre_request(proxy_balancer_pre_request, NULL, NULL, APR_HOOK_FIRST);
proxy_hook_post_request(proxy_balancer_post_request, NULL, NULL, APR_HOOK_FIRST);
proxy_hook_canon_handler(proxy_balancer_canon, NULL, NULL, APR_HOOK_FIRST);
ap_register_provider(p, PROXY_LBMETHOD, "bytraffic", "0", &bytraffic);
ap_register_provider(p, PROXY_LBMETHOD, "byrequests", "0", &byrequests);
}
module AP_MODULE_DECLARE_DATA proxy_balancer_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
NULL, /* create per-server config structure */
NULL, /* merge per-server config structures */
NULL, /* command apr_table_t */
ap_proxy_balancer_register_hook /* register hooks */
};