diff options
Diffstat (limited to 'modules/cluster')
-rw-r--r-- | modules/cluster/Makefile.in | 3 | ||||
-rw-r--r-- | modules/cluster/NWGNUmakefile | 246 | ||||
-rw-r--r-- | modules/cluster/NWGNUmodheartbeat | 257 | ||||
-rw-r--r-- | modules/cluster/NWGNUmodheartmonitor | 257 | ||||
-rw-r--r-- | modules/cluster/README.heartbeat | 33 | ||||
-rw-r--r-- | modules/cluster/README.heartmonitor | 30 | ||||
-rw-r--r-- | modules/cluster/config5.m4 | 17 | ||||
-rw-r--r-- | modules/cluster/mod_heartbeat.c | 228 | ||||
-rw-r--r-- | modules/cluster/mod_heartbeat.dep | 55 | ||||
-rw-r--r-- | modules/cluster/mod_heartbeat.dsp | 123 | ||||
-rw-r--r-- | modules/cluster/mod_heartbeat.mak | 380 | ||||
-rw-r--r-- | modules/cluster/mod_heartmonitor.c | 918 | ||||
-rw-r--r-- | modules/cluster/mod_heartmonitor.dep | 63 | ||||
-rw-r--r-- | modules/cluster/mod_heartmonitor.dsp | 123 | ||||
-rw-r--r-- | modules/cluster/mod_heartmonitor.mak | 380 |
15 files changed, 3113 insertions, 0 deletions
diff --git a/modules/cluster/Makefile.in b/modules/cluster/Makefile.in new file mode 100644 index 0000000..7c5c149 --- /dev/null +++ b/modules/cluster/Makefile.in @@ -0,0 +1,3 @@ +# a modules Makefile has no explicit targets -- they will be defined by +# whatever modules are enabled. just grab special.mk to deal with this. +include $(top_srcdir)/build/special.mk diff --git a/modules/cluster/NWGNUmakefile b/modules/cluster/NWGNUmakefile new file mode 100644 index 0000000..eda07b1 --- /dev/null +++ b/modules/cluster/NWGNUmakefile @@ -0,0 +1,246 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(AP_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = + +# +# If this is specified, it will override VERSION value in +# $(AP_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/modheartbeat.nlm \ + $(OBJDIR)/modheartmonitor.nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + $(call COPY,$(OBJDIR)/*.nlm, $(INSTALLBASE)/modules/) + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APBUILD)/NWGNUtail.inc + + diff --git a/modules/cluster/NWGNUmodheartbeat b/modules/cluster/NWGNUmodheartbeat new file mode 100644 index 0000000..b2c3ece --- /dev/null +++ b/modules/cluster/NWGNUmodheartbeat @@ -0,0 +1,257 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(AP_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APRUTIL)/include \ + $(AP_WORK)/include \ + $(AP_WORK)/modules/core \ + $(NWOS) \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = modheartbeat + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache $(VERSION_STR) Heart Beat Module + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = modheartbeat + +# +# If this is specified, it will override VERSION value in +# $(AP_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = 8192 + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/modheartbeat.nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/mod_heartbeat.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @aprlib.imp \ + @httpd.imp \ + @libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + heartbeat_module \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APBUILD)/NWGNUtail.inc + + diff --git a/modules/cluster/NWGNUmodheartmonitor b/modules/cluster/NWGNUmodheartmonitor new file mode 100644 index 0000000..2436b27 --- /dev/null +++ b/modules/cluster/NWGNUmodheartmonitor @@ -0,0 +1,257 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(AP_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APRUTIL)/include \ + $(AP_WORK)/include \ + $(AP_WORK)/modules/core \ + $(NWOS) \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = modheartmonitor + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache $(VERSION_STR) Heart Beat Monitor Module + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = modheartmonitor + +# +# If this is specified, it will override VERSION value in +# $(AP_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = 8192 + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/modheartmonitor.nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/mod_heartmonitor.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @aprlib.imp \ + @httpd.imp \ + @libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + heartmonitor_module \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APBUILD)/NWGNUtail.inc + + diff --git a/modules/cluster/README.heartbeat b/modules/cluster/README.heartbeat new file mode 100644 index 0000000..5eec549 --- /dev/null +++ b/modules/cluster/README.heartbeat @@ -0,0 +1,33 @@ +mod_heartbeat + +Broadcasts the current Apache Connection status over multicast. + +Example Configuration: + HeartbeatAddress 239.0.0.1:27999 + +Dependencies: + mod_status must be either a static module, or if a dynamic module, it must be + loaded before mod_heartbeat. + + +Consuming: + Every 1 second, this module generates a single multicast UDP packet, + containing the number of busy and idle workers. + + The packet is a simple ASCII format, similar to GET query parameters in UDP. + + An Example packet: + v=1&ready=75&busy=0 + + Consumers should handle new variables besides busy and ready, separated by '&' + being added in the future. + +Misc: + The interval of 1 seconds is controlled by the HEARTBEAT_INTERVAL + compile time define. This is not currently tunable at run time. To make this + module send the status packet more often, you must add to the CFLAGS used to + compile the module to include: + -DHEARTBEAT_INTERVAL=3 + Would cause the broadcasts to be sent every 3 seconds. + + diff --git a/modules/cluster/README.heartmonitor b/modules/cluster/README.heartmonitor new file mode 100644 index 0000000..0cb70bc --- /dev/null +++ b/modules/cluster/README.heartmonitor @@ -0,0 +1,30 @@ +mod_heartmonitor + +Collects the Apache Connection status data over multicast. + +Example Configuration: + # First parameter is the interface to listen on + HeartbeatListen 239.0.0.1:27999 + # Absolute path, or relative path to ServerRoot + HeartbeatStorage logs/hb.dat + +Dependencies: + Due to a bug in APR's apr_socket_recvfrom, version 1.2.12 or newer must be + used: + <http://svn.apache.org/viewvc?view=rev&revision=467600> + +Consuming: + This module atomically writes to the configured path, a list of servers, + along with metadata about them. + + Included data about each server: + - IP Address + - Busy Slots + - Open Slots + - Last Seen + + Every 5 seconds, this file will be updated with the current status of the + cluster. + + + diff --git a/modules/cluster/config5.m4 b/modules/cluster/config5.m4 new file mode 100644 index 0000000..8667316 --- /dev/null +++ b/modules/cluster/config5.m4 @@ -0,0 +1,17 @@ + +APACHE_MODPATH_INIT(cluster) + +heartbeat_objects='mod_heartbeat.lo' + +case "$host" in + *os2*) + # OS/2 DLLs must resolve all symbols at build time + # and we need some from the watchdog module + heartbeat_objects="$heartbeat_objects ../core/mod_watchdog.la" + ;; +esac + +APACHE_MODULE(heartbeat, Generates Heartbeats, $heartbeat_objects, , , , watchdog) +APACHE_MODULE(heartmonitor, Collects Heartbeats, , , ) + +APACHE_MODPATH_FINISH diff --git a/modules/cluster/mod_heartbeat.c b/modules/cluster/mod_heartbeat.c new file mode 100644 index 0000000..1dc4a91 --- /dev/null +++ b/modules/cluster/mod_heartbeat.c @@ -0,0 +1,228 @@ +/* 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. + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_log.h" +#include "apr_strings.h" + +#include "ap_mpm.h" +#include "scoreboard.h" +#include "mod_watchdog.h" + +#ifndef HEARTBEAT_INTERVAL +#define HEARTBEAT_INTERVAL (1) +#endif + +module AP_MODULE_DECLARE_DATA heartbeat_module; + +typedef struct hb_ctx_t +{ + int active; + apr_sockaddr_t *mcast_addr; + int server_limit; + int thread_limit; + apr_status_t status; +} hb_ctx_t; + +static const char *msg_format = "v=%u&ready=%u&busy=%u"; + +#define MSG_VERSION (1) + +static int hb_monitor(hb_ctx_t *ctx, apr_pool_t *p) +{ + apr_size_t len; + apr_socket_t *sock = NULL; + char buf[256]; + int i, j; + apr_uint32_t ready = 0; + apr_uint32_t busy = 0; + ap_generation_t mpm_generation; + + ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation); + + for (i = 0; i < ctx->server_limit; i++) { + process_score *ps; + ps = ap_get_scoreboard_process(i); + + for (j = 0; j < ctx->thread_limit; j++) { + int res; + + worker_score *ws = NULL; + + ws = &ap_scoreboard_image->servers[i][j]; + + res = ws->status; + + if (res == SERVER_READY && ps->generation == mpm_generation) { + ready++; + } + else if (res != SERVER_DEAD && + res != SERVER_STARTING && res != SERVER_IDLE_KILL && + ps->generation == mpm_generation) { + busy++; + } + } + } + + len = apr_snprintf(buf, sizeof(buf), msg_format, MSG_VERSION, ready, busy); + + do { + apr_status_t rv; + rv = apr_socket_create(&sock, ctx->mcast_addr->family, + SOCK_DGRAM, APR_PROTO_UDP, p); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_WARNING, rv, + NULL, APLOGNO(02097) "Heartbeat: apr_socket_create failed"); + break; + } + + rv = apr_mcast_loopback(sock, 1); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_WARNING, rv, + NULL, APLOGNO(02098) "Heartbeat: apr_mcast_loopback failed"); + break; + } + + rv = apr_socket_sendto(sock, ctx->mcast_addr, 0, buf, &len); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_WARNING, rv, + NULL, APLOGNO(02099) "Heartbeat: apr_socket_sendto failed"); + break; + } + } while (0); + + if (sock) { + apr_socket_close(sock); + } + + return OK; +} + +static int hb_watchdog_init(server_rec *s, const char *name, apr_pool_t *pool) +{ + hb_ctx_t *ctx = ap_get_module_config(s->module_config, &heartbeat_module); + + ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &ctx->thread_limit); + ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &ctx->server_limit); + + return OK; +} + +static int hb_watchdog_exit(server_rec *s, const char *name, apr_pool_t *pool) +{ + return OK; +} + +static int hb_watchdog_step(server_rec *s, const char *name, apr_pool_t *pool) +{ + hb_ctx_t *ctx = ap_get_module_config(s->module_config, &heartbeat_module); + + if (!ctx->active || strcmp(name, AP_WATCHDOG_SINGLETON)) { + return OK; + } + return hb_monitor(ctx, pool); +} + +static int hb_watchdog_need(server_rec *s, const char *name, + int parent, int singleton) +{ + hb_ctx_t *ctx = ap_get_module_config(s->module_config, &heartbeat_module); + + if (ctx->active && singleton && !strcmp(name, AP_WATCHDOG_SINGLETON)) + return OK; + else + return DECLINED; +} + +static void hb_register_hooks(apr_pool_t *p) +{ + ap_hook_watchdog_need(hb_watchdog_need, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_watchdog_init(hb_watchdog_init, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_watchdog_step(hb_watchdog_step, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_watchdog_exit(hb_watchdog_exit, NULL, NULL, APR_HOOK_MIDDLE); +} + +static void *hb_create_config(apr_pool_t *p, server_rec *s) +{ + hb_ctx_t *cfg = (hb_ctx_t *) apr_pcalloc(p, sizeof(hb_ctx_t)); + + return cfg; +} + +static const char *cmd_hb_address(cmd_parms *cmd, + void *dconf, const char *addr) +{ + apr_status_t rv; + char *host_str; + char *scope_id; + apr_port_t port = 0; + apr_pool_t *p = cmd->pool; + hb_ctx_t *ctx = + (hb_ctx_t *) ap_get_module_config(cmd->server->module_config, + &heartbeat_module); + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + + if (err != NULL) { + return err; + } + + if (!ctx->active) { + ctx->active = 1; + } + else { + return "HeartbeatAddress: May only be specified once."; + } + + rv = apr_parse_addr_port(&host_str, &scope_id, &port, addr, cmd->temp_pool); + + if (rv) { + return "HeartbeatAddress: Unable to parse address."; + } + + if (host_str == NULL) { + return "HeartbeatAddress: No host provided in address"; + } + + if (port == 0) { + return "HeartbeatAddress: No port provided in address"; + } + + rv = apr_sockaddr_info_get(&ctx->mcast_addr, host_str, APR_INET, port, 0, + p); + + if (rv) { + return "HeartbeatAddress: apr_sockaddr_info_get failed."; + } + + return NULL; +} + +static const command_rec hb_cmds[] = { + AP_INIT_TAKE1("HeartbeatAddress", cmd_hb_address, NULL, RSRC_CONF, + "Address to send heartbeat requests"), + {NULL} +}; + +AP_DECLARE_MODULE(heartbeat) = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + hb_create_config, /* create per-server config structure */ + NULL, /* merge per-server config structures */ + hb_cmds, /* command apr_table_t */ + hb_register_hooks +}; diff --git a/modules/cluster/mod_heartbeat.dep b/modules/cluster/mod_heartbeat.dep new file mode 100644 index 0000000..d95401f --- /dev/null +++ b/modules/cluster/mod_heartbeat.dep @@ -0,0 +1,55 @@ +# Microsoft Developer Studio Generated Dependency File, included by mod_heartbeat.mak + +.\mod_heartbeat.c : \ + "..\..\include\ap_config.h"\ + "..\..\include\ap_config_layout.h"\ + "..\..\include\ap_hooks.h"\ + "..\..\include\ap_mmn.h"\ + "..\..\include\ap_mpm.h"\ + "..\..\include\ap_provider.h"\ + "..\..\include\ap_regex.h"\ + "..\..\include\ap_release.h"\ + "..\..\include\apache_noprobes.h"\ + "..\..\include\http_config.h"\ + "..\..\include\http_log.h"\ + "..\..\include\httpd.h"\ + "..\..\include\os.h"\ + "..\..\include\scoreboard.h"\ + "..\..\include\util_cfgtree.h"\ + "..\..\srclib\apr-util\include\apr_buckets.h"\ + "..\..\srclib\apr-util\include\apr_hooks.h"\ + "..\..\srclib\apr-util\include\apr_optional.h"\ + "..\..\srclib\apr-util\include\apr_optional_hooks.h"\ + "..\..\srclib\apr-util\include\apr_uri.h"\ + "..\..\srclib\apr-util\include\apu.h"\ + "..\..\srclib\apr\include\apr.h"\ + "..\..\srclib\apr\include\apr_allocator.h"\ + "..\..\srclib\apr\include\apr_dso.h"\ + "..\..\srclib\apr\include\apr_errno.h"\ + "..\..\srclib\apr\include\apr_file_info.h"\ + "..\..\srclib\apr\include\apr_file_io.h"\ + "..\..\srclib\apr\include\apr_general.h"\ + "..\..\srclib\apr\include\apr_global_mutex.h"\ + "..\..\srclib\apr\include\apr_hash.h"\ + "..\..\srclib\apr\include\apr_inherit.h"\ + "..\..\srclib\apr\include\apr_mmap.h"\ + "..\..\srclib\apr\include\apr_network_io.h"\ + "..\..\srclib\apr\include\apr_poll.h"\ + "..\..\srclib\apr\include\apr_pools.h"\ + "..\..\srclib\apr\include\apr_portable.h"\ + "..\..\srclib\apr\include\apr_proc_mutex.h"\ + "..\..\srclib\apr\include\apr_ring.h"\ + "..\..\srclib\apr\include\apr_shm.h"\ + "..\..\srclib\apr\include\apr_strings.h"\ + "..\..\srclib\apr\include\apr_tables.h"\ + "..\..\srclib\apr\include\apr_thread_mutex.h"\ + "..\..\srclib\apr\include\apr_thread_proc.h"\ + "..\..\srclib\apr\include\apr_time.h"\ + "..\..\srclib\apr\include\apr_user.h"\ + "..\..\srclib\apr\include\apr_want.h"\ + "..\core\mod_watchdog.h"\ + + +..\..\build\win32\httpd.rc : \ + "..\..\include\ap_release.h"\ + diff --git a/modules/cluster/mod_heartbeat.dsp b/modules/cluster/mod_heartbeat.dsp new file mode 100644 index 0000000..a2014dc --- /dev/null +++ b/modules/cluster/mod_heartbeat.dsp @@ -0,0 +1,123 @@ +# Microsoft Developer Studio Project File - Name="mod_heartbeat" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=mod_heartbeat - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mod_heartbeat.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mod_heartbeat.mak" CFG="mod_heartbeat - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_heartbeat - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_heartbeat - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mod_heartbeat - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../core" /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_heartbeat_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/mod_heartbeat.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_heartbeat.so" /d LONG_NAME="heartbeat_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:".\Release\mod_heartbeat.so" /base:@..\..\os\win32\BaseAddr.ref,mod_heartbeat.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_heartbeat.so" /base:@..\..\os\win32\BaseAddr.ref,mod_heartbeat.so /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\mod_heartbeat.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "mod_heartbeat - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../core" /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_heartbeat_src" /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/mod_heartbeat.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_heartbeat.so" /d LONG_NAME="heartbeat_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_heartbeat.so" /base:@..\..\os\win32\BaseAddr.ref,mod_heartbeat.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_heartbeat.so" /base:@..\..\os\win32\BaseAddr.ref,mod_heartbeat.so +# Begin Special Build Tool +TargetPath=.\Debug\mod_heartbeat.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "mod_heartbeat - Win32 Release" +# Name "mod_heartbeat - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\mod_heartbeat.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter ".h" +# Begin Source File + +SOURCE=.\mod_proxy.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/modules/cluster/mod_heartbeat.mak b/modules/cluster/mod_heartbeat.mak new file mode 100644 index 0000000..7ce22c7 --- /dev/null +++ b/modules/cluster/mod_heartbeat.mak @@ -0,0 +1,380 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on mod_heartbeat.dsp +!IF "$(CFG)" == "" +CFG=mod_heartbeat - Win32 Release +!MESSAGE No configuration specified. Defaulting to mod_heartbeat - Win32 Release. +!ENDIF + +!IF "$(CFG)" != "mod_heartbeat - Win32 Release" && "$(CFG)" != "mod_heartbeat - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mod_heartbeat.mak" CFG="mod_heartbeat - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_heartbeat - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_heartbeat - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "mod_heartbeat - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\mod_heartbeat.so" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "mod_watchdog - Win32 Release" "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_heartbeat.so" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" "mod_watchdog - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\mod_heartbeat.obj" + -@erase "$(INTDIR)\mod_heartbeat.res" + -@erase "$(INTDIR)\mod_heartbeat_src.idb" + -@erase "$(INTDIR)\mod_heartbeat_src.pdb" + -@erase "$(OUTDIR)\mod_heartbeat.exp" + -@erase "$(OUTDIR)\mod_heartbeat.lib" + -@erase "$(OUTDIR)\mod_heartbeat.pdb" + -@erase "$(OUTDIR)\mod_heartbeat.so" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../core" /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_heartbeat_src" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_heartbeat.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_heartbeat.so" /d LONG_NAME="heartbeat_module for Apache" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_heartbeat.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_heartbeat.pdb" /debug /out:"$(OUTDIR)\mod_heartbeat.so" /implib:"$(OUTDIR)\mod_heartbeat.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_heartbeat.so /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\mod_heartbeat.obj" \ + "$(INTDIR)\mod_heartbeat.res" \ + "..\..\srclib\apr\Release\libapr-1.lib" \ + "..\..\srclib\apr-util\Release\libaprutil-1.lib" \ + "..\..\Release\libhttpd.lib" \ + "..\core\Release\mod_watchdog.lib" + +"$(OUTDIR)\mod_heartbeat.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\mod_heartbeat.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_heartbeat.so" + if exist .\Release\mod_heartbeat.so.manifest mt.exe -manifest .\Release\mod_heartbeat.so.manifest -outputresource:.\Release\mod_heartbeat.so;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "mod_heartbeat - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\mod_heartbeat.so" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "mod_watchdog - Win32 Debug" "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_heartbeat.so" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" "mod_watchdog - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\mod_heartbeat.obj" + -@erase "$(INTDIR)\mod_heartbeat.res" + -@erase "$(INTDIR)\mod_heartbeat_src.idb" + -@erase "$(INTDIR)\mod_heartbeat_src.pdb" + -@erase "$(OUTDIR)\mod_heartbeat.exp" + -@erase "$(OUTDIR)\mod_heartbeat.lib" + -@erase "$(OUTDIR)\mod_heartbeat.pdb" + -@erase "$(OUTDIR)\mod_heartbeat.so" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../core" /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_heartbeat_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_heartbeat.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_heartbeat.so" /d LONG_NAME="heartbeat_module for Apache" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_heartbeat.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_heartbeat.pdb" /debug /out:"$(OUTDIR)\mod_heartbeat.so" /implib:"$(OUTDIR)\mod_heartbeat.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_heartbeat.so +LINK32_OBJS= \ + "$(INTDIR)\mod_heartbeat.obj" \ + "$(INTDIR)\mod_heartbeat.res" \ + "..\..\srclib\apr\Debug\libapr-1.lib" \ + "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \ + "..\..\Debug\libhttpd.lib" \ + "..\core\Debug\mod_watchdog.lib" + +"$(OUTDIR)\mod_heartbeat.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\mod_heartbeat.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_heartbeat.so" + if exist .\Debug\mod_heartbeat.so.manifest mt.exe -manifest .\Debug\mod_heartbeat.so.manifest -outputresource:.\Debug\mod_heartbeat.so;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("mod_heartbeat.dep") +!INCLUDE "mod_heartbeat.dep" +!ELSE +!MESSAGE Warning: cannot find "mod_heartbeat.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "mod_heartbeat - Win32 Release" || "$(CFG)" == "mod_heartbeat - Win32 Debug" +SOURCE=.\mod_heartbeat.c + +"$(INTDIR)\mod_heartbeat.obj" : $(SOURCE) "$(INTDIR)" + + +!IF "$(CFG)" == "mod_heartbeat - Win32 Release" + +"libapr - Win32 Release" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" + cd "..\..\modules\cluster" + +"libapr - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\modules\cluster" + +!ELSEIF "$(CFG)" == "mod_heartbeat - Win32 Debug" + +"libapr - Win32 Debug" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" + cd "..\..\modules\cluster" + +"libapr - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\modules\cluster" + +!ENDIF + +!IF "$(CFG)" == "mod_heartbeat - Win32 Release" + +"libaprutil - Win32 Release" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" + cd "..\..\modules\cluster" + +"libaprutil - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\modules\cluster" + +!ELSEIF "$(CFG)" == "mod_heartbeat - Win32 Debug" + +"libaprutil - Win32 Debug" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" + cd "..\..\modules\cluster" + +"libaprutil - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\modules\cluster" + +!ENDIF + +!IF "$(CFG)" == "mod_heartbeat - Win32 Release" + +"libhttpd - Win32 Release" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" + cd ".\modules\cluster" + +"libhttpd - Win32 ReleaseCLEAN" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN + cd ".\modules\cluster" + +!ELSEIF "$(CFG)" == "mod_heartbeat - Win32 Debug" + +"libhttpd - Win32 Debug" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" + cd ".\modules\cluster" + +"libhttpd - Win32 DebugCLEAN" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN + cd ".\modules\cluster" + +!ENDIF + +!IF "$(CFG)" == "mod_heartbeat - Win32 Release" + +"mod_watchdog - Win32 Release" : + cd ".\..\core" + $(MAKE) /$(MAKEFLAGS) /F ".\mod_watchdog.mak" CFG="mod_watchdog - Win32 Release" + cd "..\cluster" + +"mod_watchdog - Win32 ReleaseCLEAN" : + cd ".\..\core" + $(MAKE) /$(MAKEFLAGS) /F ".\mod_watchdog.mak" CFG="mod_watchdog - Win32 Release" RECURSE=1 CLEAN + cd "..\cluster" + +!ELSEIF "$(CFG)" == "mod_heartbeat - Win32 Debug" + +"mod_watchdog - Win32 Debug" : + cd ".\..\core" + $(MAKE) /$(MAKEFLAGS) /F ".\mod_watchdog.mak" CFG="mod_watchdog - Win32 Debug" + cd "..\cluster" + +"mod_watchdog - Win32 DebugCLEAN" : + cd ".\..\core" + $(MAKE) /$(MAKEFLAGS) /F ".\mod_watchdog.mak" CFG="mod_watchdog - Win32 Debug" RECURSE=1 CLEAN + cd "..\cluster" + +!ENDIF + +SOURCE=..\..\build\win32\httpd.rc + +!IF "$(CFG)" == "mod_heartbeat - Win32 Release" + + +"$(INTDIR)\mod_heartbeat.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\mod_heartbeat.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_heartbeat.so" /d LONG_NAME="heartbeat_module for Apache" $(SOURCE) + + +!ELSEIF "$(CFG)" == "mod_heartbeat - Win32 Debug" + + +"$(INTDIR)\mod_heartbeat.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\mod_heartbeat.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_heartbeat.so" /d LONG_NAME="heartbeat_module for Apache" $(SOURCE) + + +!ENDIF + + +!ENDIF + diff --git a/modules/cluster/mod_heartmonitor.c b/modules/cluster/mod_heartmonitor.c new file mode 100644 index 0000000..965fef5 --- /dev/null +++ b/modules/cluster/mod_heartmonitor.c @@ -0,0 +1,918 @@ +/* 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. + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_log.h" +#include "http_core.h" +#include "http_protocol.h" +#include "apr_strings.h" +#include "apr_hash.h" +#include "apr_time.h" +#include "ap_mpm.h" +#include "scoreboard.h" +#include "mod_watchdog.h" +#include "ap_slotmem.h" +#include "heartbeat.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_") + +static const ap_slotmem_provider_t *storage = NULL; +static ap_slotmem_instance_t *slotmem = NULL; +static int maxworkers = 0; + +module AP_MODULE_DECLARE_DATA heartmonitor_module; + +typedef struct hm_server_t +{ + const char *ip; + int busy; + int ready; + unsigned int port; + apr_time_t seen; +} hm_server_t; + +typedef struct hm_ctx_t +{ + int active; + const char *storage_path; + ap_watchdog_t *watchdog; + apr_interval_time_t interval; + apr_sockaddr_t *mcast_addr; + apr_status_t status; + volatile int keep_running; + apr_socket_t *sock; + apr_pool_t *p; + apr_hash_t *servers; + server_rec *s; +} hm_ctx_t; + +typedef struct hm_slot_server_ctx_t { + hm_server_t *s; + int found; + unsigned int item_id; +} hm_slot_server_ctx_t; + +static apr_status_t hm_listen(hm_ctx_t *ctx) +{ + apr_status_t rv; + + rv = apr_socket_create(&ctx->sock, ctx->mcast_addr->family, + SOCK_DGRAM, APR_PROTO_UDP, ctx->p); + + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02068) + "Failed to create listening socket."); + return rv; + } + + rv = apr_socket_opt_set(ctx->sock, APR_SO_REUSEADDR, 1); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02069) + "Failed to set APR_SO_REUSEADDR to 1 on socket."); + return rv; + } + + + rv = apr_socket_opt_set(ctx->sock, APR_SO_NONBLOCK, 1); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02070) + "Failed to set APR_SO_NONBLOCK to 1 on socket."); + return rv; + } + + rv = apr_socket_bind(ctx->sock, ctx->mcast_addr); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02071) + "Failed to bind on socket."); + return rv; + } + + rv = apr_mcast_join(ctx->sock, ctx->mcast_addr, NULL, NULL); + + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02072) + "Failed to join multicast group"); + return rv; + } + + rv = apr_mcast_loopback(ctx->sock, 1); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02073) + "Failed to accept localhost mulitcast on socket."); + return rv; + } + + return APR_SUCCESS; +} + +/* XXX: The same exists in mod_lbmethod_heartbeat.c where it is named argstr_to_table */ +static void qs_to_table(const char *input, apr_table_t *parms, + apr_pool_t *p) +{ + char *key; + char *value; + char *query_string; + char *strtok_state; + + if (input == NULL) { + return; + } + + query_string = apr_pstrdup(p, input); + + key = apr_strtok(query_string, "&", &strtok_state); + while (key) { + value = strchr(key, '='); + if (value) { + *value = '\0'; /* Split the string in two */ + value++; /* Skip passed the = */ + } + else { + value = "1"; + } + ap_unescape_url(key); + ap_unescape_url(value); + apr_table_set(parms, key, value); + /* + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03182) + "Found query arg: %s = %s", key, value); + */ + key = apr_strtok(NULL, "&", &strtok_state); + } +} + + +#define SEEN_TIMEOUT (30) + +/* Store in the slotmem */ +static apr_status_t hm_update(void* mem, void *data, apr_pool_t *p) +{ + hm_slot_server_t *old = (hm_slot_server_t *) mem; + hm_slot_server_ctx_t *s = (hm_slot_server_ctx_t *) data; + hm_server_t *new = s->s; + if (strncmp(old->ip, new->ip, MAXIPSIZE)==0) { + s->found = 1; + old->busy = new->busy; + old->ready = new->ready; + old->seen = new->seen; + } + return APR_SUCCESS; +} +/* Read the id corresponding to the entry in the slotmem */ +static apr_status_t hm_readid(void* mem, void *data, apr_pool_t *p) +{ + hm_slot_server_t *old = (hm_slot_server_t *) mem; + hm_slot_server_ctx_t *s = (hm_slot_server_ctx_t *) data; + hm_server_t *new = s->s; + if (strncmp(old->ip, new->ip, MAXIPSIZE)==0) { + s->found = 1; + s->item_id = old->id; + } + return APR_SUCCESS; +} +/* update the entry or create it if not existing */ +static apr_status_t hm_slotmem_update_stat(hm_server_t *s, apr_pool_t *pool) +{ + /* We call do_all (to try to update) otherwise grab + put */ + hm_slot_server_ctx_t ctx; + ctx.s = s; + ctx.found = 0; + storage->doall(slotmem, hm_update, &ctx, pool); + if (!ctx.found) { + unsigned int i; + hm_slot_server_t hmserver; + memcpy(hmserver.ip, s->ip, MAXIPSIZE); + hmserver.busy = s->busy; + hmserver.ready = s->ready; + hmserver.seen = s->seen; + /* XXX locking for grab() / put() */ + storage->grab(slotmem, &i); + hmserver.id = i; + storage->put(slotmem, i, (unsigned char *)&hmserver, sizeof(hmserver)); + } + return APR_SUCCESS; +} +static apr_status_t hm_slotmem_remove_stat(hm_server_t *s, apr_pool_t *pool) +{ + hm_slot_server_ctx_t ctx; + ctx.s = s; + ctx.found = 0; + storage->doall(slotmem, hm_readid, &ctx, pool); + if (ctx.found) { + storage->release(slotmem, ctx.item_id); + } + return APR_SUCCESS; +} +static apr_status_t hm_file_update_stat(hm_ctx_t *ctx, hm_server_t *s, apr_pool_t *pool) +{ + apr_status_t rv; + apr_file_t *fp; + apr_file_t *fpin; + apr_time_t now; + apr_time_t fage; + apr_finfo_t fi; + int updated = 0; + char *path = apr_pstrcat(pool, ctx->storage_path, ".tmp.XXXXXX", NULL); + + + /* TODO: Update stats file (!) */ + rv = apr_file_mktemp(&fp, path, APR_CREATE | APR_WRITE, pool); + + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02074) + "Unable to open tmp file: %s", path); + return rv; + } + rv = apr_file_open(&fpin, ctx->storage_path, APR_READ|APR_BINARY|APR_BUFFERED, + APR_OS_DEFAULT, pool); + + now = apr_time_now(); + if (rv == APR_SUCCESS) { + char *t; + apr_table_t *hbt = apr_table_make(pool, 10); + apr_bucket_alloc_t *ba; + apr_bucket_brigade *bb; + apr_bucket_brigade *tmpbb; + + rv = apr_file_info_get(&fi, APR_FINFO_SIZE | APR_FINFO_MTIME, fpin); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02075) + "Unable to read file: %s", ctx->storage_path); + return rv; + } + + /* Read the file and update the line corresponding to the node */ + ba = apr_bucket_alloc_create(pool); + bb = apr_brigade_create(pool, ba); + apr_brigade_insert_file(bb, fpin, 0, fi.size, pool); + tmpbb = apr_brigade_create(pool, ba); + fage = apr_time_sec(now - fi.mtime); + do { + char buf[4096]; + const char *ip; + apr_size_t bsize = sizeof(buf); + + apr_brigade_cleanup(tmpbb); + if (APR_BRIGADE_EMPTY(bb)) { + break; + } + rv = apr_brigade_split_line(tmpbb, bb, + APR_BLOCK_READ, sizeof(buf)); + + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02076) + "Unable to read from file: %s", ctx->storage_path); + return rv; + } + + apr_brigade_flatten(tmpbb, buf, &bsize); + if (bsize == 0) { + break; + } + buf[bsize - 1] = 0; + t = strchr(buf, ' '); + if (t) { + ip = apr_pstrmemdup(pool, buf, t - buf); + } + else { + ip = NULL; + } + + if (!ip || buf[0] == '#') { + /* copy things we can't process */ + apr_file_printf(fp, "%s\n", buf); + } + else if (strcmp(ip, s->ip) != 0 ) { + hm_server_t node; + apr_time_t seen; + const char *val; + + /* Update seen time according to the last file modification */ + apr_table_clear(hbt); + qs_to_table(apr_pstrdup(pool, t), hbt, pool); + if ((val = apr_table_get(hbt, "busy"))) { + node.busy = atoi(val); + } + else { + node.busy = 0; + } + + if ((val = apr_table_get(hbt, "ready"))) { + node.ready = atoi(val); + } + else { + node.ready = 0; + } + + if ((val = apr_table_get(hbt, "lastseen"))) { + node.seen = atoi(val); + } + else { + node.seen = SEEN_TIMEOUT; + } + seen = fage + node.seen; + + if ((val = apr_table_get(hbt, "port"))) { + node.port = atoi(val); + } + else { + node.port = 80; + } + apr_file_printf(fp, "%s &ready=%u&busy=%u&lastseen=%u&port=%u\n", + ip, node.ready, node.busy, (unsigned int) seen, node.port); + } + else { + apr_time_t seen; + seen = apr_time_sec(now - s->seen); + apr_file_printf(fp, "%s &ready=%u&busy=%u&lastseen=%u&port=%u\n", + s->ip, s->ready, s->busy, (unsigned int) seen, s->port); + updated = 1; + } + } while (1); + } + + if (!updated) { + apr_time_t seen; + seen = apr_time_sec(now - s->seen); + apr_file_printf(fp, "%s &ready=%u&busy=%u&lastseen=%u&port=%u\n", + s->ip, s->ready, s->busy, (unsigned int) seen, s->port); + } + + rv = apr_file_flush(fp); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02077) + "Unable to flush file: %s", path); + return rv; + } + + rv = apr_file_close(fp); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02078) + "Unable to close file: %s", path); + return rv; + } + + rv = apr_file_perms_set(path, + APR_FPROT_UREAD | APR_FPROT_GREAD | + APR_FPROT_WREAD); + if (rv && rv != APR_INCOMPLETE && rv != APR_ENOTIMPL) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02079) + "Unable to set file permissions on %s", + path); + return rv; + } + + rv = apr_file_rename(path, ctx->storage_path, pool); + + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02080) + "Unable to move file: %s -> %s", path, + ctx->storage_path); + return rv; + } + + return APR_SUCCESS; +} +static apr_status_t hm_update_stat(hm_ctx_t *ctx, hm_server_t *s, apr_pool_t *pool) +{ + if (slotmem) + return hm_slotmem_update_stat(s, pool); + else + return hm_file_update_stat(ctx, s, pool); +} + +/* Store in a file */ +static apr_status_t hm_file_update_stats(hm_ctx_t *ctx, apr_pool_t *p) +{ + apr_status_t rv; + apr_file_t *fp; + apr_hash_index_t *hi; + apr_time_t now; + char *path = apr_pstrcat(p, ctx->storage_path, ".tmp.XXXXXX", NULL); + /* TODO: Update stats file (!) */ + rv = apr_file_mktemp(&fp, path, APR_CREATE | APR_WRITE, p); + + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02081) + "Unable to open tmp file: %s", path); + return rv; + } + + now = apr_time_now(); + for (hi = apr_hash_first(p, ctx->servers); + hi != NULL; hi = apr_hash_next(hi)) { + hm_server_t *s = NULL; + apr_time_t seen; + apr_hash_this(hi, NULL, NULL, (void **) &s); + seen = apr_time_sec(now - s->seen); + if (seen > SEEN_TIMEOUT) { + /* + * Skip this entry from the heartbeat file -- when it comes back, + * we will reuse the memory... + */ + } + else { + apr_file_printf(fp, "%s &ready=%u&busy=%u&lastseen=%u&port=%u\n", + s->ip, s->ready, s->busy, (unsigned int) seen, s->port); + } + } + + rv = apr_file_flush(fp); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02082) + "Unable to flush file: %s", path); + return rv; + } + + rv = apr_file_close(fp); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02083) + "Unable to close file: %s", path); + return rv; + } + + rv = apr_file_perms_set(path, + APR_FPROT_UREAD | APR_FPROT_GREAD | + APR_FPROT_WREAD); + if (rv && rv != APR_INCOMPLETE && rv != APR_ENOTIMPL) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02084) + "Unable to set file permissions on %s", + path); + return rv; + } + + rv = apr_file_rename(path, ctx->storage_path, p); + + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02085) + "Unable to move file: %s -> %s", path, + ctx->storage_path); + return rv; + } + + return APR_SUCCESS; +} +/* Store in a slotmem */ +static apr_status_t hm_slotmem_update_stats(hm_ctx_t *ctx, apr_pool_t *p) +{ + apr_status_t rv; + apr_time_t now; + apr_hash_index_t *hi; + now = apr_time_now(); + for (hi = apr_hash_first(p, ctx->servers); + hi != NULL; hi = apr_hash_next(hi)) { + hm_server_t *s = NULL; + apr_time_t seen; + apr_hash_this(hi, NULL, NULL, (void **) &s); + seen = apr_time_sec(now - s->seen); + if (seen > SEEN_TIMEOUT) { + /* remove it */ + rv = hm_slotmem_remove_stat(s, p); + } else { + /* update it */ + rv = hm_slotmem_update_stat(s, p); + } + if (rv !=APR_SUCCESS) + return rv; + } + return APR_SUCCESS; +} +/* Store/update the stats */ +static apr_status_t hm_update_stats(hm_ctx_t *ctx, apr_pool_t *p) +{ + if (slotmem) + return hm_slotmem_update_stats(ctx, p); + else + return hm_file_update_stats(ctx, p); +} + +static hm_server_t *hm_get_server(hm_ctx_t *ctx, const char *ip, const int port) +{ + hm_server_t *s; + + s = apr_hash_get(ctx->servers, ip, APR_HASH_KEY_STRING); + + if (s == NULL) { + s = apr_palloc(ctx->p, sizeof(hm_server_t)); + s->ip = apr_pstrdup(ctx->p, ip); + s->port = port; + s->ready = 0; + s->busy = 0; + s->seen = 0; + apr_hash_set(ctx->servers, s->ip, APR_HASH_KEY_STRING, s); + } + + return s; +} + +/* Process a message received from a backend node */ +static void hm_processmsg(hm_ctx_t *ctx, apr_pool_t *p, + apr_sockaddr_t *from, char *buf, int len) +{ + apr_table_t *tbl; + + buf[len] = '\0'; + + tbl = apr_table_make(p, 10); + + qs_to_table(buf, tbl, p); + + if (apr_table_get(tbl, "v") != NULL && + apr_table_get(tbl, "busy") != NULL && + apr_table_get(tbl, "ready") != NULL) { + char *ip; + int port = 80; + hm_server_t *s; + /* TODO: REMOVE ME BEFORE PRODUCTION (????) */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO(02086) + "%pI busy=%s ready=%s", from, + apr_table_get(tbl, "busy"), apr_table_get(tbl, "ready")); + + apr_sockaddr_ip_get(&ip, from); + + if (apr_table_get(tbl, "port") != NULL) + port = atoi(apr_table_get(tbl, "port")); + + s = hm_get_server(ctx, ip, port); + + s->busy = atoi(apr_table_get(tbl, "busy")); + s->ready = atoi(apr_table_get(tbl, "ready")); + s->seen = apr_time_now(); + } + else { + ap_log_error(APLOG_MARK, APLOG_CRIT, 0, ctx->s, APLOGNO(02087) + "malformed message from %pI", + from); + } + +} +/* Read message from multicast socket */ +#define MAX_MSG_LEN (1000) +static apr_status_t hm_recv(hm_ctx_t *ctx, apr_pool_t *p) +{ + char buf[MAX_MSG_LEN + 1]; + apr_sockaddr_t from; + apr_size_t len = MAX_MSG_LEN; + apr_status_t rv; + + from.pool = p; + + rv = apr_socket_recvfrom(&from, ctx->sock, 0, buf, &len); + + if (APR_STATUS_IS_EAGAIN(rv)) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02088) "would block"); + return APR_SUCCESS; + } + else if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02089) "recvfrom failed"); + return rv; + } + + hm_processmsg(ctx, p, &from, buf, len); + + return rv; +} + +static apr_status_t hm_watchdog_callback(int state, void *data, + apr_pool_t *pool) +{ + apr_status_t rv = APR_SUCCESS; + apr_time_t cur, now; + hm_ctx_t *ctx = (hm_ctx_t *)data; + + if (!ctx->active) { + return rv; + } + + switch (state) { + case AP_WATCHDOG_STATE_STARTING: + rv = hm_listen(ctx); + if (rv) { + ctx->status = rv; + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ctx->s, APLOGNO(02090) + "Unable to listen for connections!"); + } + else { + ctx->keep_running = 1; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO(02091) + "%s listener started.", + HM_WATHCHDOG_NAME); + } + break; + case AP_WATCHDOG_STATE_RUNNING: + /* store in the slotmem or in the file depending on configuration */ + hm_update_stats(ctx, pool); + cur = now = apr_time_sec(apr_time_now()); + /* TODO: Insted HN_UPDATE_SEC use + * the ctx->interval + */ + while ((now - cur) < apr_time_sec(ctx->interval)) { + int n; + apr_status_t rc; + apr_pool_t *p; + apr_pollfd_t pfd; + apr_interval_time_t timeout; + + apr_pool_create(&p, pool); + + pfd.desc_type = APR_POLL_SOCKET; + pfd.desc.s = ctx->sock; + pfd.p = p; + pfd.reqevents = APR_POLLIN; + + timeout = apr_time_from_sec(1); + + rc = apr_poll(&pfd, 1, &n, timeout); + + if (!ctx->keep_running) { + apr_pool_destroy(p); + break; + } + if (rc == APR_SUCCESS && (pfd.rtnevents & APR_POLLIN)) { + hm_recv(ctx, p); + } + now = apr_time_sec(apr_time_now()); + apr_pool_destroy(p); + } + break; + case AP_WATCHDOG_STATE_STOPPING: + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO(02092) + "stopping %s listener.", + HM_WATHCHDOG_NAME); + + ctx->keep_running = 0; + if (ctx->sock) { + apr_socket_close(ctx->sock); + ctx->sock = NULL; + } + break; + } + return rv; +} + +static int hm_post_config(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s) +{ + apr_status_t rv; + hm_ctx_t *ctx = ap_get_module_config(s->module_config, + &heartmonitor_module); + APR_OPTIONAL_FN_TYPE(ap_watchdog_get_instance) *hm_watchdog_get_instance; + APR_OPTIONAL_FN_TYPE(ap_watchdog_register_callback) *hm_watchdog_register_callback; + + hm_watchdog_get_instance = APR_RETRIEVE_OPTIONAL_FN(ap_watchdog_get_instance); + hm_watchdog_register_callback = APR_RETRIEVE_OPTIONAL_FN(ap_watchdog_register_callback); + if (!hm_watchdog_get_instance || !hm_watchdog_register_callback) { + ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, APLOGNO(02093) + "mod_watchdog is required"); + return !OK; + } + + /* Create the slotmem */ + if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_CONFIG) { + /* this is the real thing */ + if (maxworkers) { + storage = ap_lookup_provider(AP_SLOTMEM_PROVIDER_GROUP, "shm", + AP_SLOTMEM_PROVIDER_VERSION); + if (!storage) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02284) + "failed to lookup provider 'shm' for '%s', " + "maybe you need to load mod_slotmem_shm?", + AP_SLOTMEM_PROVIDER_GROUP); + return !OK; + } + storage->create(&slotmem, "mod_heartmonitor", sizeof(hm_slot_server_t), maxworkers, AP_SLOTMEM_TYPE_PREGRAB, p); + if (!slotmem) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02285) + "slotmem_create for status failed"); + return !OK; + } + } + } + + if (!ctx->active) { + return OK; + } + rv = hm_watchdog_get_instance(&ctx->watchdog, + HM_WATHCHDOG_NAME, + 0, 1, p); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(02094) + "Failed to create watchdog instance (%s)", + HM_WATHCHDOG_NAME); + return !OK; + } + /* Register a callback with zero interval. */ + rv = hm_watchdog_register_callback(ctx->watchdog, + 0, + ctx, + hm_watchdog_callback); + if (rv) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(02095) + "Failed to register watchdog callback (%s)", + HM_WATHCHDOG_NAME); + return !OK; + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02096) + "wd callback %s", HM_WATHCHDOG_NAME); + return OK; +} + +static int hm_handler(request_rec *r) +{ + apr_bucket_brigade *input_brigade; + apr_size_t len; + char *buf; + apr_status_t status; + apr_table_t *tbl; + hm_server_t hmserver; + char *ip; + hm_ctx_t *ctx; + + if (strcmp(r->handler, "heartbeat")) { + return DECLINED; + } + if (r->method_number != M_POST) { + return HTTP_METHOD_NOT_ALLOWED; + } + + len = MAX_MSG_LEN; + ctx = ap_get_module_config(r->server->module_config, + &heartmonitor_module); + + buf = apr_pcalloc(r->pool, MAX_MSG_LEN); + input_brigade = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc); + status = ap_get_brigade(r->input_filters, input_brigade, AP_MODE_READBYTES, APR_BLOCK_READ, MAX_MSG_LEN); + if (status != APR_SUCCESS) { + return ap_map_http_request_error(status, HTTP_BAD_REQUEST); + } + apr_brigade_flatten(input_brigade, buf, &len); + + /* we can't use hm_processmsg because it uses hm_get_server() */ + buf[len] = '\0'; + tbl = apr_table_make(r->pool, 10); + qs_to_table(buf, tbl, r->pool); + apr_sockaddr_ip_get(&ip, r->connection->client_addr); + hmserver.ip = ip; + hmserver.port = 80; + if (apr_table_get(tbl, "port") != NULL) + hmserver.port = atoi(apr_table_get(tbl, "port")); + hmserver.busy = atoi(apr_table_get(tbl, "busy")); + hmserver.ready = atoi(apr_table_get(tbl, "ready")); + hmserver.seen = apr_time_now(); + hm_update_stat(ctx, &hmserver, r->pool); + + ap_set_content_type(r, "text/plain"); + ap_set_content_length(r, 2); + ap_rputs("OK", r); + ap_rflush(r); + + return OK; +} + +static void hm_register_hooks(apr_pool_t *p) +{ + static const char * const aszSucc[]={ "mod_proxy.c", NULL }; + ap_hook_post_config(hm_post_config, NULL, NULL, APR_HOOK_MIDDLE); + + ap_hook_handler(hm_handler, NULL, aszSucc, APR_HOOK_FIRST); +} + +static void *hm_create_config(apr_pool_t *p, server_rec *s) +{ + hm_ctx_t *ctx = (hm_ctx_t *) apr_palloc(p, sizeof(hm_ctx_t)); + + ctx->active = 0; + ctx->storage_path = ap_runtime_dir_relative(p, DEFAULT_HEARTBEAT_STORAGE); + /* TODO: Add directive for tuning the update interval + */ + ctx->interval = apr_time_from_sec(HM_UPDATE_SEC); + ctx->s = s; + apr_pool_create(&ctx->p, p); + ctx->servers = apr_hash_make(ctx->p); + + return ctx; +} + +static const char *cmd_hm_storage(cmd_parms *cmd, + void *dconf, const char *path) +{ + apr_pool_t *p = cmd->pool; + hm_ctx_t *ctx = + (hm_ctx_t *) ap_get_module_config(cmd->server->module_config, + &heartmonitor_module); + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + + if (err != NULL) { + return err; + } + + ctx->storage_path = ap_runtime_dir_relative(p, path); + + return NULL; +} + +static const char *cmd_hm_listen(cmd_parms *cmd, + void *dconf, const char *mcast_addr) +{ + apr_status_t rv; + char *host_str; + char *scope_id; + apr_port_t port = 0; + apr_pool_t *p = cmd->pool; + hm_ctx_t *ctx = + (hm_ctx_t *) ap_get_module_config(cmd->server->module_config, + &heartmonitor_module); + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + + if (err != NULL) { + return err; + } + + if (!ctx->active) { + ctx->active = 1; + } + else { + return "HeartbeatListen: May only be specified once."; + } + + rv = apr_parse_addr_port(&host_str, &scope_id, &port, mcast_addr, cmd->temp_pool); + + if (rv) { + return "HeartbeatListen: Unable to parse multicast address."; + } + + if (host_str == NULL) { + return "HeartbeatListen: No host provided in multicast address"; + } + + if (port == 0) { + return "HeartbeatListen: No port provided in multicast address"; + } + + rv = apr_sockaddr_info_get(&ctx->mcast_addr, host_str, APR_INET, port, 0, + p); + + if (rv) { + return + "HeartbeatListen: apr_sockaddr_info_get failed on multicast address"; + } + + return NULL; +} + +static const char *cmd_hm_maxworkers(cmd_parms *cmd, + void *dconf, const char *data) +{ + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + + if (err != NULL) { + return err; + } + + maxworkers = atoi(data); + if (maxworkers <= 10) + return "HeartbeatMaxServers: Should be bigger than 10"; + + return NULL; +} + +static const command_rec hm_cmds[] = { + AP_INIT_TAKE1("HeartbeatListen", cmd_hm_listen, NULL, RSRC_CONF, + "Address to listen for heartbeat requests"), + AP_INIT_TAKE1("HeartbeatStorage", cmd_hm_storage, NULL, RSRC_CONF, + "Path to store heartbeat data."), + AP_INIT_TAKE1("HeartbeatMaxServers", cmd_hm_maxworkers, NULL, RSRC_CONF, + "Max number of servers when using slotmem (instead file) to store heartbeat data."), + {NULL} +}; + +AP_DECLARE_MODULE(heartmonitor) = { + STANDARD20_MODULE_STUFF, + 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 */ + hm_register_hooks +}; diff --git a/modules/cluster/mod_heartmonitor.dep b/modules/cluster/mod_heartmonitor.dep new file mode 100644 index 0000000..266efbf --- /dev/null +++ b/modules/cluster/mod_heartmonitor.dep @@ -0,0 +1,63 @@ +# Microsoft Developer Studio Generated Dependency File, included by mod_heartmonitor.mak + +.\mod_heartmonitor.c : \ + "..\..\include\ap_config.h"\ + "..\..\include\ap_config_layout.h"\ + "..\..\include\ap_expr.h"\ + "..\..\include\ap_hooks.h"\ + "..\..\include\ap_mmn.h"\ + "..\..\include\ap_mpm.h"\ + "..\..\include\ap_provider.h"\ + "..\..\include\ap_regex.h"\ + "..\..\include\ap_release.h"\ + "..\..\include\ap_slotmem.h"\ + "..\..\include\apache_noprobes.h"\ + "..\..\include\heartbeat.h"\ + "..\..\include\http_config.h"\ + "..\..\include\http_core.h"\ + "..\..\include\http_log.h"\ + "..\..\include\http_protocol.h"\ + "..\..\include\httpd.h"\ + "..\..\include\os.h"\ + "..\..\include\scoreboard.h"\ + "..\..\include\util_cfgtree.h"\ + "..\..\include\util_filter.h"\ + "..\..\srclib\apr-util\include\apr_buckets.h"\ + "..\..\srclib\apr-util\include\apr_hooks.h"\ + "..\..\srclib\apr-util\include\apr_md5.h"\ + "..\..\srclib\apr-util\include\apr_optional.h"\ + "..\..\srclib\apr-util\include\apr_optional_hooks.h"\ + "..\..\srclib\apr-util\include\apr_uri.h"\ + "..\..\srclib\apr-util\include\apr_xlate.h"\ + "..\..\srclib\apr-util\include\apu.h"\ + "..\..\srclib\apr\include\apr.h"\ + "..\..\srclib\apr\include\apr_allocator.h"\ + "..\..\srclib\apr\include\apr_dso.h"\ + "..\..\srclib\apr\include\apr_errno.h"\ + "..\..\srclib\apr\include\apr_file_info.h"\ + "..\..\srclib\apr\include\apr_file_io.h"\ + "..\..\srclib\apr\include\apr_general.h"\ + "..\..\srclib\apr\include\apr_global_mutex.h"\ + "..\..\srclib\apr\include\apr_hash.h"\ + "..\..\srclib\apr\include\apr_inherit.h"\ + "..\..\srclib\apr\include\apr_mmap.h"\ + "..\..\srclib\apr\include\apr_network_io.h"\ + "..\..\srclib\apr\include\apr_poll.h"\ + "..\..\srclib\apr\include\apr_pools.h"\ + "..\..\srclib\apr\include\apr_portable.h"\ + "..\..\srclib\apr\include\apr_proc_mutex.h"\ + "..\..\srclib\apr\include\apr_ring.h"\ + "..\..\srclib\apr\include\apr_shm.h"\ + "..\..\srclib\apr\include\apr_strings.h"\ + "..\..\srclib\apr\include\apr_tables.h"\ + "..\..\srclib\apr\include\apr_thread_mutex.h"\ + "..\..\srclib\apr\include\apr_thread_proc.h"\ + "..\..\srclib\apr\include\apr_time.h"\ + "..\..\srclib\apr\include\apr_user.h"\ + "..\..\srclib\apr\include\apr_want.h"\ + "..\core\mod_watchdog.h"\ + + +..\..\build\win32\httpd.rc : \ + "..\..\include\ap_release.h"\ + diff --git a/modules/cluster/mod_heartmonitor.dsp b/modules/cluster/mod_heartmonitor.dsp new file mode 100644 index 0000000..8eb716b --- /dev/null +++ b/modules/cluster/mod_heartmonitor.dsp @@ -0,0 +1,123 @@ +# Microsoft Developer Studio Project File - Name="mod_heartmonitor" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=mod_heartmonitor - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mod_heartmonitor.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mod_heartmonitor.mak" CFG="mod_heartmonitor - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_heartmonitor - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_heartmonitor - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mod_heartmonitor - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../core" /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_heartmonitor_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/mod_heartmonitor.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_heartmonitor.so" /d LONG_NAME="heartmonitor_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:".\Release\mod_heartmonitor.so" /base:@..\..\os\win32\BaseAddr.ref,mod_heartmonitor.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_heartmonitor.so" /base:@..\..\os\win32\BaseAddr.ref,mod_heartmonitor.so /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\mod_heartmonitor.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "mod_heartmonitor - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../core" /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_heartmonitor_src" /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/mod_heartmonitor.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_heartmonitor.so" /d LONG_NAME="heartmonitor_module for Apache" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_heartmonitor.so" /base:@..\..\os\win32\BaseAddr.ref,mod_heartmonitor.so +# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_heartmonitor.so" /base:@..\..\os\win32\BaseAddr.ref,mod_heartmonitor.so +# Begin Special Build Tool +TargetPath=.\Debug\mod_heartmonitor.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "mod_heartmonitor - Win32 Release" +# Name "mod_heartmonitor - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\mod_heartmonitor.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter ".h" +# Begin Source File + +SOURCE=.\mod_proxy.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/modules/cluster/mod_heartmonitor.mak b/modules/cluster/mod_heartmonitor.mak new file mode 100644 index 0000000..2d935d5 --- /dev/null +++ b/modules/cluster/mod_heartmonitor.mak @@ -0,0 +1,380 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on mod_heartmonitor.dsp +!IF "$(CFG)" == "" +CFG=mod_heartmonitor - Win32 Release +!MESSAGE No configuration specified. Defaulting to mod_heartmonitor - Win32 Release. +!ENDIF + +!IF "$(CFG)" != "mod_heartmonitor - Win32 Release" && "$(CFG)" != "mod_heartmonitor - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mod_heartmonitor.mak" CFG="mod_heartmonitor - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_heartmonitor - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_heartmonitor - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "mod_heartmonitor - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\mod_heartmonitor.so" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "mod_watchdog - Win32 Release" "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_heartmonitor.so" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" "mod_watchdog - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\mod_heartmonitor.obj" + -@erase "$(INTDIR)\mod_heartmonitor.res" + -@erase "$(INTDIR)\mod_heartmonitor_src.idb" + -@erase "$(INTDIR)\mod_heartmonitor_src.pdb" + -@erase "$(OUTDIR)\mod_heartmonitor.exp" + -@erase "$(OUTDIR)\mod_heartmonitor.lib" + -@erase "$(OUTDIR)\mod_heartmonitor.pdb" + -@erase "$(OUTDIR)\mod_heartmonitor.so" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../core" /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_heartmonitor_src" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_heartmonitor.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_heartmonitor.so" /d LONG_NAME="heartmonitor_module for Apache" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_heartmonitor.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_heartmonitor.pdb" /debug /out:"$(OUTDIR)\mod_heartmonitor.so" /implib:"$(OUTDIR)\mod_heartmonitor.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_heartmonitor.so /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\mod_heartmonitor.obj" \ + "$(INTDIR)\mod_heartmonitor.res" \ + "..\..\srclib\apr\Release\libapr-1.lib" \ + "..\..\srclib\apr-util\Release\libaprutil-1.lib" \ + "..\..\Release\libhttpd.lib" \ + "..\core\Release\mod_watchdog.lib" + +"$(OUTDIR)\mod_heartmonitor.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\mod_heartmonitor.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_heartmonitor.so" + if exist .\Release\mod_heartmonitor.so.manifest mt.exe -manifest .\Release\mod_heartmonitor.so.manifest -outputresource:.\Release\mod_heartmonitor.so;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "mod_heartmonitor - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\mod_heartmonitor.so" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "mod_watchdog - Win32 Debug" "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_heartmonitor.so" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" "mod_watchdog - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\mod_heartmonitor.obj" + -@erase "$(INTDIR)\mod_heartmonitor.res" + -@erase "$(INTDIR)\mod_heartmonitor_src.idb" + -@erase "$(INTDIR)\mod_heartmonitor_src.pdb" + -@erase "$(OUTDIR)\mod_heartmonitor.exp" + -@erase "$(OUTDIR)\mod_heartmonitor.lib" + -@erase "$(OUTDIR)\mod_heartmonitor.pdb" + -@erase "$(OUTDIR)\mod_heartmonitor.so" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../core" /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_heartmonitor_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_heartmonitor.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_heartmonitor.so" /d LONG_NAME="heartmonitor_module for Apache" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_heartmonitor.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_heartmonitor.pdb" /debug /out:"$(OUTDIR)\mod_heartmonitor.so" /implib:"$(OUTDIR)\mod_heartmonitor.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_heartmonitor.so +LINK32_OBJS= \ + "$(INTDIR)\mod_heartmonitor.obj" \ + "$(INTDIR)\mod_heartmonitor.res" \ + "..\..\srclib\apr\Debug\libapr-1.lib" \ + "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \ + "..\..\Debug\libhttpd.lib" \ + "..\core\Debug\mod_watchdog.lib" + +"$(OUTDIR)\mod_heartmonitor.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\mod_heartmonitor.so +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_heartmonitor.so" + if exist .\Debug\mod_heartmonitor.so.manifest mt.exe -manifest .\Debug\mod_heartmonitor.so.manifest -outputresource:.\Debug\mod_heartmonitor.so;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("mod_heartmonitor.dep") +!INCLUDE "mod_heartmonitor.dep" +!ELSE +!MESSAGE Warning: cannot find "mod_heartmonitor.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "mod_heartmonitor - Win32 Release" || "$(CFG)" == "mod_heartmonitor - Win32 Debug" +SOURCE=.\mod_heartmonitor.c + +"$(INTDIR)\mod_heartmonitor.obj" : $(SOURCE) "$(INTDIR)" + + +!IF "$(CFG)" == "mod_heartmonitor - Win32 Release" + +"libapr - Win32 Release" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" + cd "..\..\modules\cluster" + +"libapr - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\modules\cluster" + +!ELSEIF "$(CFG)" == "mod_heartmonitor - Win32 Debug" + +"libapr - Win32 Debug" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" + cd "..\..\modules\cluster" + +"libapr - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\modules\cluster" + +!ENDIF + +!IF "$(CFG)" == "mod_heartmonitor - Win32 Release" + +"libaprutil - Win32 Release" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" + cd "..\..\modules\cluster" + +"libaprutil - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\modules\cluster" + +!ELSEIF "$(CFG)" == "mod_heartmonitor - Win32 Debug" + +"libaprutil - Win32 Debug" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" + cd "..\..\modules\cluster" + +"libaprutil - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\modules\cluster" + +!ENDIF + +!IF "$(CFG)" == "mod_heartmonitor - Win32 Release" + +"libhttpd - Win32 Release" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" + cd ".\modules\cluster" + +"libhttpd - Win32 ReleaseCLEAN" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN + cd ".\modules\cluster" + +!ELSEIF "$(CFG)" == "mod_heartmonitor - Win32 Debug" + +"libhttpd - Win32 Debug" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" + cd ".\modules\cluster" + +"libhttpd - Win32 DebugCLEAN" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN + cd ".\modules\cluster" + +!ENDIF + +!IF "$(CFG)" == "mod_heartmonitor - Win32 Release" + +"mod_watchdog - Win32 Release" : + cd ".\..\core" + $(MAKE) /$(MAKEFLAGS) /F ".\mod_watchdog.mak" CFG="mod_watchdog - Win32 Release" + cd "..\cluster" + +"mod_watchdog - Win32 ReleaseCLEAN" : + cd ".\..\core" + $(MAKE) /$(MAKEFLAGS) /F ".\mod_watchdog.mak" CFG="mod_watchdog - Win32 Release" RECURSE=1 CLEAN + cd "..\cluster" + +!ELSEIF "$(CFG)" == "mod_heartmonitor - Win32 Debug" + +"mod_watchdog - Win32 Debug" : + cd ".\..\core" + $(MAKE) /$(MAKEFLAGS) /F ".\mod_watchdog.mak" CFG="mod_watchdog - Win32 Debug" + cd "..\cluster" + +"mod_watchdog - Win32 DebugCLEAN" : + cd ".\..\core" + $(MAKE) /$(MAKEFLAGS) /F ".\mod_watchdog.mak" CFG="mod_watchdog - Win32 Debug" RECURSE=1 CLEAN + cd "..\cluster" + +!ENDIF + +SOURCE=..\..\build\win32\httpd.rc + +!IF "$(CFG)" == "mod_heartmonitor - Win32 Release" + + +"$(INTDIR)\mod_heartmonitor.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\mod_heartmonitor.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_heartmonitor.so" /d LONG_NAME="heartmonitor_module for Apache" $(SOURCE) + + +!ELSEIF "$(CFG)" == "mod_heartmonitor - Win32 Debug" + + +"$(INTDIR)\mod_heartmonitor.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\mod_heartmonitor.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_heartmonitor.so" /d LONG_NAME="heartmonitor_module for Apache" $(SOURCE) + + +!ENDIF + + +!ENDIF + |