Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
862 lines (776 sloc) 32.6 KB
/*
* ModAdvertise - Apache Httpd advertising module
*
* Copyright(c) 2008 Red Hat Middleware, LLC,
* and individual contributors as indicated by the @authors tag.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* @author Mladen Turk
*/
#define CORE_PRIVATE
#include "mod_advertise.h"
#include "mod_core.h"
#include "util_script.h"
#if APR_HAVE_UNISTD_H
/* for getpid() */
#include <unistd.h>
#endif
/*
* Declare ourselves so the configuration routines can find and know us.
* We'll fill it in at the end of the module.
*/
module AP_MODULE_DECLARE_DATA advertise_module;
/*
* Server private data
*/
#if defined(WIN32)
static pid_t ma_parent_pid = -1;
#endif
/* Global (really) */
static int ma_advertise_run = 0;
static int ma_advertise_stat = 0;
static server_rec *main_server = NULL;
/*
* configuration.
*/
typedef struct mod_advertise_config
{
server_rec *ma_advertise_server;
char *ma_advertise_adrs;
char *ma_advertise_adsi;
char *ma_advertise_srvm;
char *ma_advertise_srvh;
char *ma_advertise_srvs;
char *ma_advertise_srvi;
char *ma_advertise_uuid;
char *ma_advertise_skey;
int ma_bind_set;
char *ma_bind_adrs;
char *ma_bind_adsi;
apr_port_t ma_bind_port;
apr_port_t ma_advertise_port;
apr_port_t ma_advertise_srvp;
ma_advertise_e ma_advertise_mode;
apr_interval_time_t ma_advertise_freq;
} mod_advertise_config;
/* Advertise sockets */
static apr_socket_t *ma_mgroup_socket = NULL;
static apr_sockaddr_t *ma_mgroup_sa = NULL;
static apr_sockaddr_t *ma_listen_sa = NULL;
static apr_sockaddr_t *ma_niface_sa = NULL;
static server_rec *ma_server_rec = NULL;
/* Advertise sequence number */
static volatile apr_int64_t ma_sequence = 0;
/* Parent and child manager thread statuses */
static volatile int is_mp_running = 0;
static volatile int is_mp_created = 0;
/*
* Server global data
*/
typedef struct ma_global_data_t {
unsigned char ssalt[APR_MD5_DIGESTSIZE];
apr_uuid_t suuid;
char srvid[APR_UUID_FORMATTED_LENGTH + 2];
apr_pool_t *ppool;
apr_pool_t *cpool;
} ma_global_data_t;
/*
* Global data instance
* For parent, registered in process pool
*/
static ma_global_data_t *magd = NULL;
/* Evaluates to true if the (apr_sockaddr_t *) addr argument is the
* IPv4 match-any-address, 0.0.0.0. */
#define IS_INADDR_ANY(addr) ((addr)->family == APR_INET && \
(addr)->sa.sin.sin_addr.s_addr == INADDR_ANY)
/* Evaluates to true if the (apr_sockaddr_t *) addr argument is the
* IPv6 match-any-address, [::]. */
#define IS_IN6ADDR_ANY(addr) ((addr)->family == APR_INET6 && \
IN6_IS_ADDR_UNSPECIFIED(&(addr)->sa.sin6.sin6_addr))
/*--------------------------------------------------------------------------*/
/* */
/* ServerAdvertise directive */
/* */
/*--------------------------------------------------------------------------*/
static const char *cmd_advertise_m(cmd_parms *cmd, void *dummy,
const char *arg, const char *opt)
{
mod_advertise_config *mconf = ap_get_module_config(cmd->server->module_config, &advertise_module);
if (mconf->ma_advertise_srvs)
return "Duplicate ServerAdvertise directives are not allowed";
if (strcasecmp(arg, "Off") == 0)
mconf->ma_advertise_mode = ma_advertise_off;
else if (strcasecmp(arg, "On") == 0)
mconf->ma_advertise_mode = ma_advertise_on;
else
return "ServerAdvertise must be Off or On";
if (opt) {
const char *p = ap_strstr_c(opt, "://");
if (p) {
mconf->ma_advertise_srvm = apr_pstrndup(cmd->pool, opt, p - opt);
opt = p + 3;
}
if (apr_parse_addr_port(&mconf->ma_advertise_srvs,
&mconf->ma_advertise_srvi,
&mconf->ma_advertise_srvp,
opt, cmd->pool) != APR_SUCCESS ||
!mconf->ma_advertise_srvs ||
!mconf->ma_advertise_srvp)
return "Invalid ServerAdvertise Address";
}
mconf->ma_advertise_server = cmd->server;
return NULL;
}
/*--------------------------------------------------------------------------*/
/* */
/* AdvertiseGroup directive */
/* */
/*--------------------------------------------------------------------------*/
static const char *cmd_advertise_g(cmd_parms *cmd, void *dummy,
const char *arg)
{
mod_advertise_config *mconf = ap_get_module_config(cmd->server->module_config, &advertise_module);
if (mconf->ma_advertise_port != MA_DEFAULT_ADVPORT &&
(strcmp(mconf->ma_advertise_adrs, MA_DEFAULT_GROUP) != 0))
return "Duplicate AdvertiseGroup directives are not allowed";
if (apr_parse_addr_port(&mconf->ma_advertise_adrs,
&mconf->ma_advertise_adsi,
&mconf->ma_advertise_port,
arg, cmd->pool) != APR_SUCCESS)
return "Invalid AdvertiseGroup address";
if (!mconf->ma_advertise_adrs)
return "Missing Ip part from AdvertiseGroup address";
if (!mconf->ma_advertise_port)
mconf->ma_advertise_port = MA_DEFAULT_ADVPORT;
mconf->ma_advertise_server = cmd->server;
return NULL;
}
/*--------------------------------------------------------------------------*/
/* */
/* AdvertiseBindAddress directive */
/* */
/*--------------------------------------------------------------------------*/
static const char *cmd_bindaddr(cmd_parms *cmd, void *dummy,
const char *arg)
{
mod_advertise_config *mconf = ap_get_module_config(cmd->server->module_config, &advertise_module);
if (mconf->ma_bind_set)
return "Duplicate AdvertiseBindAddress directives are not allowed";
if (apr_parse_addr_port(&mconf->ma_bind_adrs,
&mconf->ma_bind_adsi,
&mconf->ma_bind_port,
arg, cmd->pool) != APR_SUCCESS)
return "Invalid AdvertiseBindAddress address";
if (!mconf->ma_bind_adrs)
return "Missing Ip part from AdvertiseBindAddress address";
if (!mconf->ma_bind_port)
mconf->ma_bind_port = MA_DEFAULT_ADVPORT;
mconf->ma_bind_set = 1;
mconf->ma_advertise_server = cmd->server;
return NULL;
}
/*--------------------------------------------------------------------------*/
/* */
/* AdvertiseFrequency directive */
/* */
/*--------------------------------------------------------------------------*/
static const char *cmd_advertise_f(cmd_parms *cmd, void *dummy,
const char *arg)
{
apr_time_t s, u = 0;
const char *p;
mod_advertise_config *mconf = ap_get_module_config(cmd->server->module_config, &advertise_module);
if (mconf->ma_advertise_freq != MA_DEFAULT_ADV_FREQ)
return "Duplicate AdvertiseFrequency directives are not allowed";
if ((p = ap_strchr_c(arg, '.')) || (p = ap_strchr_c(arg, ',')))
u = atoi(p + 1);
s = atoi(arg);
mconf->ma_advertise_freq = s * APR_USEC_PER_SEC + u * APR_TIME_C(1000);
if (mconf->ma_advertise_freq == 0)
return "Invalid AdvertiseFrequency value";
mconf->ma_advertise_server = cmd->server;
return NULL;
}
/*--------------------------------------------------------------------------*/
/* */
/* AdvertiseSecurityKey directive */
/* */
/*--------------------------------------------------------------------------*/
static const char *cmd_advertise_k(cmd_parms *cmd, void *dummy,
const char *arg)
{
mod_advertise_config *mconf = ap_get_module_config(cmd->server->module_config, &advertise_module);
if (mconf->ma_advertise_skey != NULL)
return "Duplicate AdvertiseSecurityKey directives are not allowed";
mconf->ma_advertise_skey = apr_pstrdup(cmd->pool, arg);
mconf->ma_advertise_server = cmd->server;
return NULL;
}
/*--------------------------------------------------------------------------*/
/* */
/* AdvertiseManagerUrl directive */
/* */
/*--------------------------------------------------------------------------*/
static const char *cmd_advertise_h(cmd_parms *cmd, void *dummy,
const char *arg)
{
mod_advertise_config *mconf = ap_get_module_config(cmd->server->module_config, &advertise_module);
if (mconf->ma_advertise_srvh != NULL)
return "Duplicate AdvertiseManagerUrl directives are not allowed";
mconf->ma_advertise_srvh = apr_pstrdup(cmd->pool, arg);
mconf->ma_advertise_server = cmd->server;
return NULL;
}
#define MA_ADVERTISE_SERVER_FMT \
"HTTP/1.0 %s" CRLF \
"Date: %s" CRLF \
"Sequence: %" APR_INT64_T_FMT CRLF \
"Digest: %s" CRLF \
"Server: %s" CRLF
static const char *hex = "0123456789abcdef";
apr_status_t ma_advertise_server(server_rec *server, int type)
{
char buf[MA_BSIZE];
char dat[APR_RFC822_DATE_LEN];
char add[40];
unsigned char msig[APR_MD5_DIGESTSIZE];
unsigned char ssig[APR_MD5_DIGESTSIZE * 2 + 1];
const char *asl;
char *p = buf;
int i, c = 0;
apr_size_t l = MA_BSIZE - 8;
apr_size_t n = 0;
apr_md5_ctx_t md;
mod_advertise_config *mconf = ap_get_module_config(server->module_config, &advertise_module);
ma_sequence++;
if (ma_sequence < 1)
ma_sequence = 1;
sprintf(buf, "%" APR_INT64_T_FMT, ma_sequence);
ap_recent_rfc822_date(dat, apr_time_now());
asl = ap_get_status_line(ma_advertise_stat);
/* Create MD5 digest
* salt + date + sequence + srvid
*/
apr_md5_init(&md);
apr_md5_update(&md, magd->ssalt, APR_MD5_DIGESTSIZE);
apr_md5_update(&md, dat, strlen(dat));
apr_md5_update(&md, buf, strlen(buf));
apr_md5_update(&md, magd->srvid + 1, strlen(magd->srvid) - 1);
apr_md5_final(msig, &md);
/* Convert MD5 digest to hex string */
for (i = 0; i < APR_MD5_DIGESTSIZE; i++) {
ssig[c++] = hex[msig[i] >> 4];
ssig[c++] = hex[msig[i] & 0x0F];
}
ssig[c] = '\0';
n = apr_snprintf(p, l, MA_ADVERTISE_SERVER_FMT,
asl, dat, ma_sequence, ssig, magd->srvid + 1);
if (type == MA_ADVERTISE_SERVER) {
char *ma_advertise_srvs = mconf->ma_advertise_srvs;
if (strchr(ma_advertise_srvs, ':') != NULL) {
apr_snprintf(add, 40, "[%s]", mconf->ma_advertise_srvs);
ma_advertise_srvs = add;
}
l -= n;
n += apr_snprintf(p + n, l,
"X-Manager-Address: %s:%u" CRLF
"X-Manager-Url: %s" CRLF
"X-Manager-Protocol: %s" CRLF
"X-Manager-Host: %s" CRLF,
ma_advertise_srvs,
mconf->ma_advertise_srvp,
mconf->ma_advertise_srvh,
mconf->ma_advertise_srvm,
server->server_hostname);
}
strcat(p, CRLF);
n += 2;
return apr_socket_sendto(ma_mgroup_socket,
ma_mgroup_sa, 0, buf, &n);
}
static apr_status_t ma_group_join(const char *addr, apr_port_t port,
const char *bindaddr, apr_port_t bindport,
apr_pool_t *pool, server_rec *s)
{
apr_status_t rv;
if ((rv = apr_sockaddr_info_get(&ma_mgroup_sa, addr,
APR_UNSPEC, port,
APR_UNSPEC, pool)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"mod_advertise: ma_group_join apr_sockaddr_info_get(%s:%d) failed",
addr, port);
return rv;
}
if ((rv = apr_sockaddr_info_get(&ma_listen_sa, bindaddr,
ma_mgroup_sa->family, bindport,
APR_UNSPEC, pool)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"mod_advertise: ma_group_join apr_sockaddr_info_get(%s:%d) failed", bindaddr, bindport);
return rv;
}
if ((rv = apr_sockaddr_info_get(&ma_niface_sa, NULL,
ma_mgroup_sa->family, 0,
APR_UNSPEC, pool)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"mod_advertise: ma_group_join apr_sockaddr_info_get(0.0.0.0:0) failed");
return rv;
}
if ((rv = apr_socket_create(&ma_mgroup_socket,
ma_mgroup_sa->family,
SOCK_DGRAM,
APR_PROTO_UDP,
pool)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"mod_advertise: ma_group_join apr_socket_create failed");
return rv;
}
if ((rv = apr_socket_opt_set(ma_mgroup_socket,
APR_SO_REUSEADDR, 1)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"mod_advertise: ma_group_join apr_socket_opt_set failed");
return rv;
}
if ((rv = apr_socket_bind(ma_mgroup_socket, ma_listen_sa)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"mod_advertise: ma_group_join apr_socket_bind failed");
return rv;
}
if ((rv = apr_mcast_join(ma_mgroup_socket, ma_mgroup_sa,
ma_niface_sa, NULL)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s,
"mod_advertise: ma_group_join apr_mcast_join failed");
if ((rv = apr_mcast_loopback(ma_mgroup_socket, 1)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s,
"mod_advertise: ma_group_join apr_mcast_loopback failed");
apr_socket_close(ma_mgroup_socket);
return rv;
}
}
if ((rv = apr_mcast_hops(ma_mgroup_socket,
MA_ADVERTISE_HOPS)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"mod_advertise: ma_group_join apr_mcast_hops failed");
/* Due a bug in apr (fixed by r1309332) apr_mcast_hops may fail */
apr_mcast_leave(ma_mgroup_socket, ma_mgroup_sa,
NULL, NULL);
apr_socket_close(ma_mgroup_socket);
return rv;
}
return APR_SUCCESS;
}
static void ma_group_leave()
{
if (ma_mgroup_socket) {
apr_mcast_leave(ma_mgroup_socket, ma_mgroup_sa,
NULL, NULL);
apr_socket_close(ma_mgroup_socket);
ma_mgroup_socket = NULL;
}
}
static void * APR_THREAD_FUNC parent_thread(apr_thread_t *thd, void *data)
{
static int current_status = 0;
int f_time = 1;
apr_interval_time_t a_step = 0;
server_rec *s = (server_rec *)data;
mod_advertise_config *mconf = ap_get_module_config(s->module_config, &advertise_module);
is_mp_created = 1;
while (is_mp_running) {
apr_sleep(MA_TM_RESOLUTION);
if (!is_mp_running)
break;
if (ma_advertise_run) {
a_step += MA_TM_RESOLUTION;
if (current_status != ma_advertise_stat) {
/* Force advertise on status change */
current_status = ma_advertise_stat;
f_time = 1;
}
if (a_step >= mconf->ma_advertise_freq || f_time) {
/* Run advertise */
ma_advertise_server(s, MA_ADVERTISE_SERVER);
a_step = 0;
f_time = 0;
}
if (!is_mp_running)
break;
}
/* TODO: Implement actual work for parent thread */
if (!is_mp_running)
break;
}
is_mp_created = 0;
return NULL;
}
static apr_status_t pconfig_cleanup(void *data);
static apr_status_t process_cleanup(void *data)
{
int advertise_run = ma_advertise_run;
is_mp_running = 0;
ma_advertise_run = 0;
if (advertise_run) {
ma_advertise_stat = HTTP_FORBIDDEN;
ma_advertise_server(ma_server_rec, MA_ADVERTISE_STATUS);
}
if (is_mp_created) {
apr_sleep(1000);
/* Wait for the parent maintenance thread to finish */
while (is_mp_created) {
apr_sleep(MA_TM_RESOLUTION);
}
}
if (advertise_run) {
ma_advertise_stat = HTTP_GONE;
ma_advertise_server(ma_server_rec, MA_ADVERTISE_STATUS);
ma_group_leave();
}
/* We don't need the post_config cleanup to run,
*/
apr_pool_cleanup_kill(magd->cpool, magd, pconfig_cleanup);
magd = NULL;
return APR_SUCCESS;
}
static apr_status_t pconfig_cleanup(void *data)
{
int advertise_run = ma_advertise_run;
is_mp_running = 0;
ma_advertise_run = 0;
if (advertise_run) {
ma_advertise_stat = HTTP_FORBIDDEN;
ma_advertise_server(ma_server_rec, MA_ADVERTISE_STATUS);
}
if (is_mp_created) {
apr_sleep(1000);
/* Wait for the parent maintenance thread to finish */
while (is_mp_created) {
apr_sleep(MA_TM_RESOLUTION);
}
}
if (advertise_run) {
ma_advertise_stat = HTTP_FORBIDDEN;
ma_advertise_server(ma_server_rec, MA_ADVERTISE_STATUS);
}
if (magd) {
/* Remove the process_cleanup.
* We need to reattach again because the
* module can be reloaded on different address
*/
apr_pool_cleanup_kill(magd->ppool, magd, process_cleanup);
}
return APR_SUCCESS;
}
/*--------------------------------------------------------------------------*/
/* */
/* Post config hook. */
/* Create management thread in parent and initializes Manager */
/* */
/*--------------------------------------------------------------------------*/
static int post_config_hook(apr_pool_t *pconf, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{
apr_status_t rv;
const char *pk = "advertise_init_module_tag";
apr_pool_t *pproc = s->process->pool;
apr_thread_t *tp;
mod_advertise_config *mconf = ap_get_module_config(s->module_config, &advertise_module);
int advertisefound = 0;
server_rec *server = s;
/* Advertise directive in more than one VirtualHost: not supported */
while (server) {
mod_advertise_config *conf = ap_get_module_config(server->module_config, &advertise_module);
if (conf->ma_advertise_server == server) {
if (advertisefound) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
"mod_advertise: directive in more than one VirtualHost: not supported");
return !OK;
} else
advertisefound = -1;
}
server = server->next;
}
/* Our server */
server = s;
while (server) {
mconf = ap_get_module_config(server->module_config, &advertise_module);
if (mconf->ma_advertise_server == server)
break;
server = server->next;
}
apr_pool_userdata_get((void *)&magd, pk, pproc);
if (!magd) {
if (!(magd = apr_pcalloc(pproc, sizeof(ma_global_data_t))))
return apr_get_os_error();
apr_pool_create(&magd->ppool, pproc);
apr_pool_userdata_set(magd, pk, apr_pool_cleanup_null, pproc);
/* First time config phase -- skip. */
return OK;
}
#if defined(WIN32)
{
const char *ppid = getenv("AP_PARENT_PID");
if (ppid) {
ma_parent_pid = atol(ppid);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"[%" APR_PID_T_FMT " - %" APR_PID_T_FMT
"] in child post config hook",
getpid(), ma_parent_pid);
return OK;
}
}
#endif
ma_server_rec = server;
if (mconf->ma_advertise_skey) {
apr_md5_ctx_t mc;
apr_md5_init(&mc);
apr_md5_update(&mc, mconf->ma_advertise_skey, strlen(mconf->ma_advertise_skey));
apr_md5_final(magd->ssalt, &mc);
} else {
/* If security key is not configured, the digest is calculated from zero bytes */
memset(magd->ssalt, '\0', APR_MD5_DIGESTSIZE);
}
apr_uuid_get(&magd->suuid);
magd->srvid[0] = '/';
apr_uuid_format(&magd->srvid[1], &magd->suuid);
if (!mconf->ma_advertise_srvh)
mconf->ma_advertise_srvh = magd->srvid;
/* Check if we have advertise set */
if (mconf->ma_advertise_mode != ma_advertise_off &&
mconf->ma_advertise_adrs) {
rv = ma_group_join(mconf->ma_advertise_adrs, mconf->ma_advertise_port, mconf->ma_bind_adrs, mconf->ma_bind_port, pconf, s);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"mod_advertise: multicast join failed for %s:%d.",
mconf->ma_advertise_adrs, mconf->ma_advertise_port);
ma_advertise_run = 0;
}
else {
ma_advertise_run = 1;
ma_advertise_stat = 200;
}
}
/* Fill default values */
if (!mconf->ma_advertise_srvm) {
if (ma_server_rec && ma_server_rec->server_scheme) {
/* ServerName scheme://fully-qualified-domain-name[:port] */
mconf->ma_advertise_srvm = apr_pstrdup(pconf, ma_server_rec->server_scheme);
} else {
mconf->ma_advertise_srvm = apr_pstrdup(pconf, "http");
}
}
if (mconf->ma_advertise_srvs == NULL && ma_server_rec) {
/*
* That is not easy just use ServerAdvertise with the server parameter
* if the code below doesn't work
*/
char *ptr = NULL;
int port = DEFAULT_HTTP_PORT;
if (ma_server_rec->addrs && ma_server_rec->addrs->host_addr &&
ma_server_rec->addrs->host_addr->next == NULL) {
ptr = apr_psprintf(pproc, "%pI", ma_server_rec->addrs->host_addr);
}
/* Use don't use any as local address too */
if (ptr == NULL || strncmp(ptr,"0.0.0.0", 7) == 0 || strncmp(ptr,"::",2) == 0) {
if ( ma_server_rec->port == 0 || ma_server_rec->port == 1) {
if (ma_server_rec->addrs->host_addr->port != 0)
port = ma_server_rec->addrs->host_addr->port;
} else {
port = ma_server_rec->port;
}
ptr = apr_psprintf(pproc, "%s:%u", ma_server_rec->server_hostname, port);
}
rv = apr_parse_addr_port(&mconf->ma_advertise_srvs,
&mconf->ma_advertise_srvi,
&mconf->ma_advertise_srvp,
ptr, pproc);
if (rv != APR_SUCCESS || !mconf->ma_advertise_srvs ||
!mconf->ma_advertise_srvp) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
"mod_advertise: Invalid ServerAdvertise Address %s",
ptr);
return rv;
}
}
/* prevent X-Manager-Address: (null):0 */
if (!mconf->ma_advertise_srvs || !mconf->ma_advertise_srvp) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
"mod_advertise: ServerAdvertise Address or Port not defined, Advertise disabled!!!");
return OK;
}
/* Create parent management thread */
is_mp_running = 1;
rv = apr_thread_create(&tp, NULL, parent_thread, server, pconf);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
"mod_advertise: parent apr_thread_create");
return rv;
}
apr_thread_detach(tp);
/* Create cleanup pool that will be destroyed first
* in future use new apr_pool_pre_cleanup_register from APR 1.3
*/
apr_pool_create(&magd->cpool, pconf);
apr_pool_cleanup_register(magd->cpool, magd, pconfig_cleanup,
apr_pool_cleanup_null);
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
"Advertise initialized for process %" APR_PID_T_FMT,
getpid());
apr_pool_cleanup_register(magd->ppool, magd, process_cleanup,
apr_pool_cleanup_null);
return OK;
}
static void child_init_hook(apr_pool_t *p, server_rec *s)
{
main_server = s;
}
/*
* Provide information for "status" logic
*/
static void advertise_info(request_rec *r)
{
server_rec *s = main_server;
/* Find the VirtualHost (Server) that does the Advertise */
while (s) {
void *sconf = s->module_config;
mod_advertise_config *mconf = ap_get_module_config(sconf, &advertise_module);
ap_rprintf(r, "Server: %s ", s->server_hostname);
if (s->is_virtual && s->addrs) {
server_addr_rec *srec = s->addrs;
ap_rprintf(r, "VirtualHost: %s:%d", srec->virthost, srec->host_port);
}
if (mconf->ma_advertise_server != NULL) {
ap_rprintf(r, " Advertising on Group %s Port %d ", mconf->ma_advertise_adrs, mconf->ma_advertise_port);
ap_rprintf(r, "for %s://%s:%d every %ld seconds<br/>",
mconf->ma_advertise_srvm, mconf->ma_advertise_srvs,
mconf->ma_advertise_srvp,
apr_time_sec(mconf->ma_advertise_freq)
);
} else {
ap_rputs("<br/>", r);
}
s = s->next;
}
}
/*--------------------------------------------------------------------------*/
/* */
/* List of directives specific to our module. */
/* */
/*--------------------------------------------------------------------------*/
static const command_rec cmd_table[] =
{
AP_INIT_TAKE12(
"ServerAdvertise", /* directive name */
cmd_advertise_m, /* config action routine */
NULL, /* argument to include in call */
RSRC_CONF, /* where available */
"Server advertise mode: On | Off [Address]"
),
AP_INIT_TAKE1(
"AdvertiseGroup", /* directive name */
cmd_advertise_g, /* config action routine */
NULL, /* argument to include in call */
RSRC_CONF, /* where available */
"Multicast group address"
),
AP_INIT_TAKE1(
"AdvertiseFrequency", /* directive name */
cmd_advertise_f, /* config action routine */
NULL, /* argument to include in call */
RSRC_CONF, /* where available */
"Advertise frequency in seconds[.miliseconds]"
),
AP_INIT_TAKE1(
"AdvertiseSecurityKey", /* directive name */
cmd_advertise_k, /* config action routine */
NULL, /* argument to include in call */
RSRC_CONF, /* where available */
"Advertise security key"
),
AP_INIT_TAKE1(
"AdvertiseManagerUrl", /* directive name */
cmd_advertise_h, /* config action routine */
NULL, /* argument to include in call */
RSRC_CONF, /* where available */
"Advertise manager url"
),
AP_INIT_TAKE1(
"AdvertiseBindAddress", /* directive name */
cmd_bindaddr, /* config action routine */
NULL, /* argument to include in call */
RSRC_CONF, /* where available */
"Local adress to bind to for Multicast logic"
),
{NULL}
};
/*--------------------------------------------------------------------------*/
/* */
/* Which functions are responsible for which hooks in the server. */
/* */
/*--------------------------------------------------------------------------*/
static void register_hooks(apr_pool_t *p)
{
/* Post config handling
*/
ap_hook_post_config(post_config_hook,
NULL,
NULL,
APR_HOOK_LAST);
ap_hook_child_init(child_init_hook, NULL, NULL, APR_HOOK_MIDDLE);
/* Provider for the "status" page */
ap_register_provider(p, "advertise" , "info", "0", &advertise_info);
}
/* Create a default conf structure */
static void *create_advertise_server_config(apr_pool_t *p, server_rec *s)
{
mod_advertise_config *mconf = apr_pcalloc(p, sizeof(*mconf));
/* Set default values */
mconf->ma_advertise_server = NULL;
mconf->ma_advertise_adrs = MA_DEFAULT_GROUP;
mconf->ma_advertise_adsi = NULL;
mconf->ma_advertise_srvm = NULL;
mconf->ma_advertise_srvh = NULL;
mconf->ma_advertise_srvs = NULL;
mconf->ma_advertise_srvi = NULL;
mconf->ma_advertise_uuid = NULL;
mconf->ma_advertise_skey = NULL;
mconf->ma_bind_set = 0;
mconf->ma_bind_adrs = NULL;
mconf->ma_bind_adsi = NULL;
mconf->ma_bind_port = MA_DEFAULT_ADVPORT;
mconf->ma_advertise_port = MA_DEFAULT_ADVPORT;
mconf->ma_advertise_srvp = 0;
mconf->ma_advertise_mode = ma_advertise_on;
mconf->ma_advertise_freq = MA_DEFAULT_ADV_FREQ;
return mconf;
}
/*--------------------------------------------------------------------------*/
/* */
/* The list of callback routines and data structures that provide */
/* the static hooks into our module from the other parts of the server. */
/* */
/*--------------------------------------------------------------------------*/
module AP_MODULE_DECLARE_DATA advertise_module =
{
STANDARD20_MODULE_STUFF,
NULL, /* per-directory config creator */
NULL, /* dir config merger */
create_advertise_server_config, /* server config creator */
NULL, /* server config merger */
cmd_table, /* command table */
register_hooks /* set up other request processing hooks */
};
You can’t perform that action at this time.