mod_heartmonitor.c revision 17142c9e83218ee5f509f762e163a310366b0934
/* 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
*
*
* 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.
*/
#include "httpd.h"
#include "http_config.h"
#include "http_log.h"
#include "apr_strings.h"
#include "apr_hash.h"
#include "ap_mpm.h"
#include "scoreboard.h"
#ifndef HN_UPDATE_SEC
/* How often we update the stats file */
/* TODO: Make a runtime config */
#define HN_UPDATE_SEC (5)
#endif
typedef struct hm_server_t
{
const char *ip;
int busy;
int ready;
} hm_server_t;
typedef struct hm_ctx_t
{
int active;
const char *storage_path;
const char *mutex_path;
volatile int keep_running;
apr_pool_t *p;
} hm_ctx_t;
{
if (rv) {
"Heartmonitor: Failed to create listening socket.");
return rv;
}
if (rv) {
"Heartmonitor: Failed to set APR_SO_REUSEADDR to 1 on socket.");
return rv;
}
if (rv) {
"Heartmonitor: Failed to set APR_SO_REUSEADDR to 1 on socket.");
return rv;
}
if (rv) {
"Heartmonitor: Failed to bind on socket.");
return rv;
}
if (rv) {
"Heartmonitor: Failed to join multicast group");
return rv;
}
if (rv) {
"Heartmonitor: Failed to accept localhost mulitcast on socket.");
return rv;
}
return APR_SUCCESS;
}
apr_pool_t *p)
{
char *key;
char *value;
char *query_string;
char *strtok_state;
return;
}
while (key) {
if (value) {
value++; /* Skip passed the = */
}
else {
value = "1";
}
/*
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"Found query arg: %s = %s", key, value);
*/
}
}
#define SEEN_TIMEOUT (30)
{
apr_file_t *fp;
/* TODO: Update stats file (!) */
if (rv) {
"Heartmonitor: Unable to open tmp file: %s", path);
return rv;
}
now = apr_time_now();
hm_server_t *s = NULL;
if (seen > SEEN_TIMEOUT) {
/*
* Skip this entry from the heartbeat file -- when it comes back,
* we will reuse the memory...
*/
}
else {
}
}
if (rv) {
"Heartmonitor: Unable to flush file: %s", path);
return rv;
}
if (rv) {
"Heartmonitor: Unable to close file: %s", path);
return rv;
}
"Heartmonitor: Unable to set file permssions on %s",
path);
return rv;
}
if (rv) {
"Heartmonitor: Unable to move file: %s -> %s", path,
ctx->storage_path);
return rv;
}
return APR_SUCCESS;
}
{
hm_server_t *s;
if (s == NULL) {
s->ready = 0;
s->busy = 0;
s->seen = 0;
}
return s;
}
#define MAX_MSG_LEN (1000)
{
if (APR_STATUS_IS_EAGAIN(rv)) {
"Heartmonitor: would block");
return APR_SUCCESS;
}
else if (rv) {
"Heartmonitor: recvfrom failed");
return rv;
}
char *ip;
hm_server_t *s;
/* TODO: REMOVE ME BEFORE PRODUCTION (????) */
"Heartmonitor: %pI busy=%s ready=%s", &from,
s->seen = apr_time_now();
}
else {
"Heartmonitor: malformed multicast message from %pI",
&from);
}
return rv;
}
#ifndef apr_time_from_msec
#define apr_time_from_msec(x) (x * 1000)
#endif
{
while (ctx->keep_running) {
if (rv == APR_SUCCESS) {
break;
}
}
if (rv) {
"Heartmonitor: Unable to listen for connections!");
return NULL;
}
last = apr_time_now();
while (ctx->keep_running) {
int n;
apr_pool_t *p;
apr_pool_create(&p, ctx->p);
now = apr_time_now();
hm_update_stats(ctx, p);
apr_pool_clear(p);
}
pfd.p = p;
if (!ctx->keep_running) {
break;
}
if (rv) {
apr_pool_destroy(p);
continue;
}
}
apr_pool_destroy(p);
}
return NULL;
}
{
ctx->keep_running = 0;
return rv;
}
{
p);
if (rv) {
"Heartmonitor: apr_thread_mutex_create failed");
return;
}
* cleanup was being invoked before the thread completely spawned.
*/
if (rv) {
"Heartmonitor: apr_thread_create failed");
}
}
{
return;
}
"Heartmonitor: Starting Listener Thread. mcast=%pI",
ctx->mcast_addr);
start_hm_worker(p, ctx);
"Heartmonitor: Failed to start listener thread.");
return;
}
return;
}
{
return OK;
}
#else
#else
#endif
#endif
mech,
p);
if (rv) {
"Heartmonitor: Failed to create listener "
mech);
return !OK;
}
return OK;
}
static void hm_register_hooks(apr_pool_t *p)
{
}
{
ctx->mutex_path =
return ctx;
}
{
return err;
}
ctx->mutex_path =
return NULL;
}
void *dconf, const char *mcast_addr)
{
char *host_str;
char *scope_id;
apr_port_t port = 0;
return err;
}
}
else {
return "HeartbeatListen: May only be specified once.";
}
if (rv) {
return "HeartbeatListen: Unable to parse multicast address.";
}
return "HeartbeatListen: No host provided in multicast address";
}
if (port == 0) {
return "HeartbeatListen: No port provided in multicast address";
}
p);
if (rv) {
return
"HeartbeatListen: apr_sockaddr_info_get failed on multicast address";
}
return NULL;
}
static const command_rec hm_cmds[] = {
"Address to listen for heartbeat requests"),
"Path to store heartbeat data."),
{NULL}
};
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
hm_create_config, /* create per-server config structure */
NULL, /* merge per-server config structures */
hm_cmds, /* command apr_table_t */
};