mirror of
https://github.com/apache/httpd.git
synced 2026-10-23 22:49:01 +03:00
could its retry logic. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/httpd-proxy-scoreboard@428503 13f79535-47bb-0310-9956-ffa450edef68
332 lines
8.8 KiB
C
332 lines
8.8 KiB
C
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
* (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
|
|
/*
|
|
* proxymonitor.c: simple program for monitor proxy back-end server.
|
|
*
|
|
*/
|
|
|
|
#include "apr.h"
|
|
#include "apr_lib.h"
|
|
#include "apr_strings.h"
|
|
#include "apr_file_io.h"
|
|
#include "apr_file_info.h"
|
|
#include "apr_pools.h"
|
|
#include "apr_hash.h"
|
|
#include "apr_thread_proc.h"
|
|
#include "apr_signal.h"
|
|
#include "apr_getopt.h"
|
|
#include "apr_ring.h"
|
|
#include "apr_date.h"
|
|
|
|
#include "mod_proxy.h"
|
|
#include "ajp.h"
|
|
|
|
#include "slotmem.h"
|
|
#include "sharedmem_util.h"
|
|
#include "mod_proxy_health_checker.h"
|
|
|
|
#if APR_HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#if APR_HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
static int interrupted; /* flag: true if SIGINT or SIGTERM occurred */
|
|
|
|
static apr_time_t now; /* start time of this processing run */
|
|
|
|
extern int AP_DECLARE_DATA ap_default_loglevel;
|
|
|
|
static apr_file_t *errfile; /* stderr file handle */
|
|
static apr_file_t *outfile; /* stdout file handle */
|
|
|
|
/* short program name as called */
|
|
static const char *shortname = "proxymonitor";
|
|
|
|
static const health_worker_method *worker_storage;
|
|
|
|
char *basedir = NULL;
|
|
char *filename = NULL;
|
|
|
|
/* XXX: hack to use a part of the mod_sharedmem and mod_proxy_health_checker */
|
|
static apr_status_t init_healthck(apr_pool_t *pool, int *num)
|
|
{
|
|
apr_status_t rv;
|
|
const slotmem_storage_method *checkstorage;
|
|
|
|
/* Initialise the providers */
|
|
sharedmem_initglobalpool(pool);
|
|
worker_storage = health_checker_get_storage();
|
|
checkstorage = sharedmem_getstorage();
|
|
|
|
worker_storage->set_slotmem_storage_method(checkstorage);
|
|
rv = worker_storage->attach_slotmem(filename, num, pool);
|
|
|
|
if (rv != APR_SUCCESS) {
|
|
apr_file_printf(errfile, "Can't attach to httpd memory error: %d\n", rv);
|
|
return rv;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* httpd routine to be able to link with the modules.
|
|
*/
|
|
char * ap_server_root_relative(apr_pool_t *p, const char *name)
|
|
{
|
|
char *fname;
|
|
|
|
/* XXX: apr_filepath_merge better ? */
|
|
if (basedir && name[0] != '/') {
|
|
fname = apr_pstrcat(p, basedir, "/", name, NULL);
|
|
} else {
|
|
fname = apr_pstrdup(p, name);
|
|
}
|
|
return fname;
|
|
}
|
|
|
|
/*
|
|
* called on SIGINT or SIGTERM
|
|
*/
|
|
static void setterm(int unused)
|
|
{
|
|
interrupted = 1;
|
|
}
|
|
|
|
/*
|
|
* called in out of memory condition
|
|
*/
|
|
static int oom(int unused)
|
|
{
|
|
static int called = 0;
|
|
|
|
/* be careful to call exit() only once */
|
|
if (!called) {
|
|
called = 1;
|
|
exit(1);
|
|
}
|
|
return APR_ENOMEM;
|
|
}
|
|
|
|
/*
|
|
* usage info
|
|
*/
|
|
#define NL APR_EOL_STR
|
|
static void usage(void)
|
|
{
|
|
apr_file_printf(errfile,
|
|
"%s -- program for monitoring proxies of httpd." NL
|
|
"Usage: %s [-nFILENAME] [-pPATH] [-dINTERVAL] [-rN]" NL
|
|
NL
|
|
"Options:" NL
|
|
" -n Specify FILENAME to use to locate shared slotmem." NL
|
|
NL
|
|
" -d Repeat checking every INTERVAL seconds." NL
|
|
NL
|
|
" -r Repeat checking N times." NL
|
|
NL
|
|
" -p Specify PATH where the httpd is running." NL,
|
|
|
|
shortname,
|
|
shortname,
|
|
shortname
|
|
);
|
|
|
|
exit(1);
|
|
}
|
|
#undef NL
|
|
|
|
/* Quick hack to allow logging */
|
|
AP_DECLARE(void) ap_log_error(const char *file, int line, int level,
|
|
apr_status_t status, const server_rec *s,
|
|
const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
char scratch[MAX_STRING_LEN];
|
|
|
|
va_start(args, fmt);
|
|
apr_vsnprintf(scratch, MAX_STRING_LEN, fmt, args);
|
|
apr_file_printf(errfile,"%s\n", scratch);
|
|
va_end(args);
|
|
}
|
|
|
|
/*
|
|
* Reads the configuration from shared memory
|
|
*/
|
|
int process_sharedmem(apr_pool_t *pool, int num)
|
|
{
|
|
apr_status_t rv;
|
|
int n;
|
|
struct proxy_worker_conf *worker;
|
|
char *balancer_name;
|
|
int status;
|
|
|
|
for (n = 0; n < num; n++) {
|
|
|
|
rv = worker_storage->get_entryconf(n, &worker, &balancer_name, pool);
|
|
if (rv != APR_SUCCESS) {
|
|
apr_file_printf(errfile, "Can't read entry %d\n", n);
|
|
return rv;
|
|
}
|
|
if (worker->used == 0 || worker->used == 2)
|
|
continue;
|
|
worker_storage->get_health(n, &status);
|
|
apr_file_printf(outfile, "balancer %s worker %s: host %s port %d status: %d ",
|
|
worker->balancer_name, worker->name,
|
|
worker->hostname, worker->port, status);
|
|
rv = worker_storage->check_entryhealth(n, pool);
|
|
if (rv != APR_SUCCESS) {
|
|
apr_file_printf(outfile, "now: FAILED\n");
|
|
worker_storage->set_health(n, HEALTH_NO);
|
|
} else {
|
|
apr_file_printf(outfile, "now: OK\n");
|
|
worker_storage->set_health(n, HEALTH_OK);
|
|
}
|
|
}
|
|
return APR_SUCCESS;
|
|
}
|
|
/*
|
|
* When stopping write health = unknown
|
|
*/
|
|
void markunknown_sharedmem(apr_pool_t *pool, int num)
|
|
{
|
|
int n;
|
|
|
|
for (n = 0; n < num; n++)
|
|
worker_storage->set_health(n, HEALTH_UNKNOWN);
|
|
}
|
|
|
|
/*
|
|
* main
|
|
*/
|
|
int main(int argc, const char * const argv[])
|
|
{
|
|
apr_time_t current, delay;
|
|
apr_status_t status;
|
|
apr_pool_t *pool, *instance, *instance_socket;
|
|
apr_getopt_t *o;
|
|
int repeat = -1;
|
|
char opt;
|
|
const char *arg;
|
|
char datestring[APR_RFC822_DATE_LEN];
|
|
int num;
|
|
|
|
/* only log errors */
|
|
// ap_default_loglevel = APLOG_ERR;
|
|
|
|
delay = 5 * APR_USEC_PER_SEC;
|
|
|
|
if (apr_app_initialize(&argc, &argv, NULL) != APR_SUCCESS) {
|
|
return 1;
|
|
}
|
|
atexit(apr_terminate);
|
|
|
|
if (argc) {
|
|
shortname = apr_filepath_name_get(argv[0]);
|
|
}
|
|
|
|
if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
|
|
return 1;
|
|
}
|
|
apr_pool_abort_set(oom, pool);
|
|
apr_file_open_stderr(&errfile, pool);
|
|
apr_file_open_stdout(&outfile, pool);
|
|
apr_signal(SIGINT, setterm);
|
|
apr_signal(SIGTERM, setterm);
|
|
|
|
apr_getopt_init(&o, pool, argc, argv);
|
|
|
|
while (1) {
|
|
status = apr_getopt(o, "n:p:d:r:", &opt, &arg);
|
|
if (status == APR_EOF) {
|
|
break;
|
|
}
|
|
else if (status != APR_SUCCESS) {
|
|
usage();
|
|
}
|
|
else {
|
|
switch (opt) {
|
|
case 'd':
|
|
delay = apr_atoi64(arg);
|
|
delay *= APR_USEC_PER_SEC;
|
|
break;
|
|
|
|
|
|
case 'r':
|
|
repeat = apr_atoi64(arg);
|
|
break;
|
|
|
|
case 'p':
|
|
if (basedir) {
|
|
usage();
|
|
}
|
|
basedir = apr_pstrdup(pool, arg);
|
|
break;
|
|
case 'n':
|
|
if (filename) {
|
|
usage();
|
|
}
|
|
filename = apr_pstrdup(pool, arg);
|
|
break;
|
|
default:
|
|
usage();
|
|
} /* switch */
|
|
} /* else */
|
|
} /* while */
|
|
if (basedir == NULL)
|
|
usage();
|
|
if (filename == NULL)
|
|
usage();
|
|
|
|
instance_socket = NULL;
|
|
|
|
while (repeat && ! interrupted) {
|
|
|
|
if (instance_socket == NULL) {
|
|
apr_pool_create(&instance_socket, pool);
|
|
status = init_healthck(instance_socket, &num);
|
|
if (status != APR_SUCCESS)
|
|
return 1;
|
|
}
|
|
|
|
apr_pool_create(&instance, instance_socket);
|
|
apr_sleep(delay);
|
|
now = apr_time_now();
|
|
process_sharedmem(instance_socket, num);
|
|
current = apr_time_now();
|
|
apr_rfc822_date(datestring, current);
|
|
apr_file_printf(outfile,"at %s in %d\n", datestring, current-now);
|
|
|
|
if (repeat>0)
|
|
repeat--;
|
|
apr_pool_destroy(instance);
|
|
/* If something goes really wrong we should clean all, via apr_pool_destroy(instance_socket) */
|
|
}
|
|
if (instance_socket != NULL)
|
|
markunknown_sharedmem(instance_socket, num);
|
|
if (interrupted) {
|
|
apr_file_printf(errfile, "Monitoring aborted due to user "
|
|
"request." APR_EOL_STR);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|