mod_heartmonitor.c revision 241231595dff3cf310d887bf0532d9125694f2f0
/* 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 "apr_time.h"
#include "ap_mpm.h"
#include "scoreboard.h"
#include "mod_watchdog.h"
#ifndef HM_UPDATE_SEC
/* How often we update the stats file */
/* TODO: Make a runtime config */
#define HM_UPDATE_SEC (5)
#endif
#define HM_WATHCHDOG_NAME ("_heartmonitor_")
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;
volatile int keep_running;
apr_pool_t *p;
server_rec *s;
} 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;
}
{
return rv;
}
switch (state) {
if (rv) {
"Heartmonitor: Unable to listen for connections!");
}
else {
"Heartmonitor: %s listener started.",
}
break;
/* TODO: Insted HN_UPDATE_SEC use
* the ctx->interval
*/
int n;
apr_pool_t *p;
apr_pool_create(&p, pool);
pfd.p = p;
if (!ctx->keep_running) {
apr_pool_destroy(p);
break;
}
}
apr_pool_destroy(p);
}
break;
"Heartmonitor: stopping %s listener.",
ctx->keep_running = 0;
}
break;
}
return rv;
}
{
return OK;
}
apr_pool_create(&ctx->p, p);
0, 1, p);
if (rv) {
"Heartmonitor: Failed to create watchdog "
"instance (%s)", HM_WATHCHDOG_NAME);
return !OK;
}
/* Register a callback with zero interval. */
0,
ctx,
if (rv) {
"Heartmonitor: Failed to register watchdog "
"callback (%s)", HM_WATHCHDOG_NAME);
return !OK;
}
"Heartmonitor: wd callback %s", HM_WATHCHDOG_NAME);
return OK;
}
static void hm_register_hooks(apr_pool_t *p)
{
}
{
/* TODO: Add directive for tuning the update interval
*/
ctx->s = s;
return ctx;
}
{
return err;
}
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 */
};