From fb2c08c1e745041c3d7193f85f3bf32a46cc6952 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 20 Nov 2005 16:25:23 +0000 Subject: rename move rename old module back to mod_zerconf.c to move it out of the way for a new module git-svn-id: file:///home/lennart/svn/public/mod_dnssd/trunk@5 634eccf8-0006-0410-930e-e16565b0b7de --- Makefile | 7 +- mod_dnssd.c | 408 --------------------------------------------------------- mod_zeroconf.c | 408 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 412 insertions(+), 411 deletions(-) delete mode 100644 mod_dnssd.c create mode 100644 mod_zeroconf.c diff --git a/Makefile b/Makefile index a484ebc..50f1669 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +# $Id$ + APXS=/usr/bin/apxs2 APACHECTL=apache2ctl LIBS=$(shell pkg-config --libs howl) @@ -18,12 +20,11 @@ reload: install restart start: $(APACHECTL) start - + restart: $(APACHECTL) restart - + stop: $(APACHECTL) stop - .PHONY: all install clean reload start restart stop diff --git a/mod_dnssd.c b/mod_dnssd.c deleted file mode 100644 index 6246436..0000000 --- a/mod_dnssd.c +++ /dev/null @@ -1,408 +0,0 @@ -/* - * $Id: mod_zeroconf.c,v 1.20 2004/10/07 15:30:25 sctemme Exp $ - * - * Copyright 2003, 2004 Sander Temme - * - * Licensed 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 -#include -#include -#include - -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "apr_strings.h" - -#include - -/* Macro to test result of Howl functions */ -#define TESTORBAIL(f) if ((f) != SW_OKAY) { \ - return HTTP_INTERNAL_SERVER_ERROR; \ - } - -typedef struct zc_cfg { - int enabled; - char *serviceName; - char *partialURI; -} - zc_cfg; - -sw_discovery howl_session; - -module AP_MODULE_DECLARE_DATA zeroconf_module; - -/* - * Locate server configuration record for specified server - */ -static zc_cfg *our_sconfig(const server_rec *s) -{ - return (zc_cfg *) ap_get_module_config(s->module_config, - &zeroconf_module); -} - -static const char *cmd_zeroconf_enable(cmd_parms *cmd, void *mconfig, - int enable) -{ - zc_cfg *cfg = our_sconfig(cmd->server); - cfg->enabled = enable; - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, cmd->server, - "Zeroconf switched %s", enable ? "on" : "off"); - - return NULL; -} - -static const char *cmd_zeroconf_register(cmd_parms *cmd, void *mconfig, - const char *serviceName, - const char *partialURI) -{ - zc_cfg *cfg = our_sconfig(cmd->server); - - cfg->serviceName = (char *) serviceName; - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, cmd->server, - "Service Name is \"%s\"", cfg->serviceName); - cfg->partialURI = (char *) partialURI; - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, cmd->server, - "Partial Path is %s", - (partialURI == NULL) ? "not set" : cfg->partialURI); - return NULL; -} - -static void *zc_create_server_config(apr_pool_t * p, server_rec *s) -{ - zc_cfg *cfg; - - cfg = (zc_cfg *) apr_palloc(p, sizeof(zc_cfg)); - cfg->enabled = 0; /* Default to disabled */ - cfg->serviceName = NULL; - cfg->partialURI = NULL; - - return (void *) cfg; -} - -static void *zc_merge_server_config(apr_pool_t * p, void *server1_conf, - void *server2_conf) -{ - zc_cfg *merged_cfg, *s1cfg, *s2cfg; - merged_cfg = (zc_cfg *) apr_palloc(p, sizeof(zc_cfg)); - s1cfg = (zc_cfg *) server1_conf; - s2cfg = (zc_cfg *) server2_conf; - - /* - * Inherit the zeroconf enablement. Config language does not allow - * turning it off, so just assume the main server value. - */ - merged_cfg->enabled = s1cfg->enabled; - /* - * Don't care about any main server registration info. - * Use vhost reg info, even if it's NULL. - */ - merged_cfg->serviceName = s2cfg->serviceName; - merged_cfg->partialURI = s2cfg->partialURI; - - return (void *) merged_cfg; -} - -static sw_result howl_publish_reply(sw_discovery rendezvous, - sw_discovery_publish_status status, - sw_discovery_oid id, - sw_opaque opaque) -{ - static sw_string status_text[] = { - "Started", - "Stopped", - "Name Collision", - "Invalid" - }; - fprintf(stderr, "publish reply: %s\n", status_text[status]); - return SW_OKAY; -} - -static sw_result host_publish_reply(sw_discovery rendezvous, - sw_discovery_publish_status status, - sw_discovery_oid id, - sw_opaque extra) -{ - static sw_string status_text[] = { - "Started", - "Stopped", - "Name Collision", - "Invalid" - }; - fprintf(stderr, "host registration reply: %s\n", status_text[status]); - fprintf(stderr, "Host registration callback: %d\n", status); - return SW_OKAY; -} - -/* - * Publish the hostname of server s through mDNS, using the IP - * address(es) that the server is bound to, if any. - * - */ - -static int zc_register_host(server_rec *s) -{ - - apr_sockaddr_t *mysock; - apr_status_t aprstatus; - char *thehostip; - sw_result hr; - sw_ipv4_address serveraddr; - sw_discovery_oid host_id; - - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, - s, "Registering host with name %s", - s->server_hostname); - for (mysock = s->addrs->host_addr; mysock; - mysock = mysock->next) { - /* - * First, get the IP address string from the server - * record - */ - aprstatus = apr_sockaddr_ip_get(&thehostip, mysock); - if (aprstatus != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, aprstatus, s, - "Failed to obtain server address"); - return HTTP_INTERNAL_SERVER_ERROR; - } - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, - 0, s, "Server bound to IP address [%s] port [%d][%d]", - thehostip, mysock->port,s->port); - /* - * Howl doesn't know what to do with IPv6 at this - * time - */ - if (mysock->family == APR_INET) { - if (mysock->sa.sin.sin_addr.s_addr != INADDR_ANY - && mysock->sa.sin.sin_addr.s_addr != INADDR_NONE) - /* What about localhost ? */ - { - hr = sw_ipv4_address_init_from_name(&serveraddr, thehostip); - } - else { - hr = sw_ipv4_address_init_from_this_host(&serveraddr); - } - } - hr = sw_discovery_publish_host(howl_session, - 0, - s->server_hostname, - NULL, - serveraddr, - host_publish_reply, - (sw_opaque) s, - &host_id); - if (hr != SW_OKAY) { - ap_log_error(APLOG_MARK, APLOG_ERR, hr, - s, - "Failed to publish hostname \"%s\" " - "with IP address \"%s\"", - s->server_hostname, thehostip); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - return OK; -} - -static int zc_post_config(apr_pool_t * pconf, apr_pool_t * plog, - apr_pool_t * ptemp, server_rec *s) -{ - void *data; - sw_discovery_oid *pubidPtr; - const char *userdata_key = "zeroconf_init_module"; - zc_cfg *cfg; - sw_result howl_result; - sw_discovery_oid howl_id; - sw_port serverport; - sw_text_record text_record; - sw_octets pathinfo; - sw_ulong pilength; - char *thehostname; -#if APR_HAS_FORK - apr_proc_t *callbackchild; - apr_status_t forkstatus; -#endif - server_rec *ws; /* Walk Server; we need the top server_rec - * later */ - - /* raise(SIGSTOP); */ - - apr_pool_userdata_get(&data, userdata_key, s->process->pool); - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s, - "In post_config, userdata pointer is %#lx, pid is %d", - data, getpid()); - if (!data) { - /* - * Tell the world we've been here before, so we don't end up forking - * more than one callback processes. - */ - apr_pool_userdata_set((const void *) 1, userdata_key, - apr_pool_cleanup_null, s->process->pool); - } else { - /* Check if Zeroconf has been enabled globally. If not, bail here */ - cfg = our_sconfig(s); - if (cfg->enabled == 0) { - return OK; - } - /* Still here? Let's go. */ - TESTORBAIL(sw_discovery_init(&howl_session)); - - /* - * Need to know the hostname of the machine, so we know not to - * re-register an existing one - */ - thehostname = apr_palloc(pconf, APRMAXHOSTLEN + 1); - if (!thehostname) { - return HTTP_INTERNAL_SERVER_ERROR; - } - if (!APR_STATUS_IS_SUCCESS(apr_gethostname(thehostname, - APRMAXHOSTLEN, pconf))) { - return HTTP_INTERNAL_SERVER_ERROR; - } - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s, - "The hostname is [%s]", thehostname); - for (ws = s; ws; ws = ws->next) { - cfg = our_sconfig(ws); - if (cfg->serviceName) { - if (cfg->partialURI) { - TESTORBAIL(sw_text_record_init(&text_record)); - TESTORBAIL(sw_text_record_add_key_and_string_value(text_record, "path", - cfg->partialURI)); - pathinfo = sw_text_record_bytes(text_record); - pilength = sw_text_record_len(text_record); - } - else { - pathinfo = NULL; - pilength = 0; - } - /* - * for main server port is fetched from eg: - * ServerName hostnam:port - * - * for virtualhost eg: - * - */ - serverport = ws->is_virtual ? ws->addrs->host_port: ws->port; - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, ws, - "Publishing service with service name [%s]; " - "hostname [%s]; port [%d], path [%s]", - cfg->serviceName, - ws->server_hostname, serverport, cfg->partialURI); - if (apr_strnatcasecmp(thehostname, ws->server_hostname) != 0) { - /* Shouldn't throw away the result here. What's up with - * that? - */ - zc_register_host(ws); - } - howl_result = sw_discovery_publish(howl_session, - 0, - cfg->serviceName, - "_http._tcp", - NULL, - ws->server_hostname, - serverport, - pathinfo, - pilength, - howl_publish_reply, - (sw_opaque) ws, - &howl_id); - if (howl_result != SW_OKAY) { - ap_log_error(APLOG_MARK, APLOG_ERR, howl_result, - ws, "Failed to publish service %s", - cfg->serviceName); - return HTTP_INTERNAL_SERVER_ERROR; - } - pubidPtr = apr_palloc(s->process->pool, - sizeof(sw_discovery_oid)); - if (!pubidPtr) { - return HTTP_INTERNAL_SERVER_ERROR; - } - /* - * Store publish ID in the server's pool userdata, using the - * serviceName as key. The serviceName should be unique, right? - */ - *pubidPtr = howl_id; - apr_pool_userdata_set(pubidPtr, cfg->serviceName, - apr_pool_cleanup_null, - ws->process->pool); - } /* serviceName set for server config */ - } /* Server walk */ - - /* - * On unix-like systems, we need to fork a child process to - * run the callback function. On Windows, this is not necessary. - */ -#if APR_HAS_FORK - callbackchild = apr_palloc(s->process->pool, sizeof(apr_proc_t)); - if (callbackchild == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "Allocating process struct memory from pool failed"); - return HTTP_INTERNAL_SERVER_ERROR; - } - switch(forkstatus = apr_proc_fork(callbackchild, s->process->pool)) { - case APR_INCHILD: - /* I'm the child */ - sw_discovery_run(howl_session); - /* - * This function never returns ... - */ - break; /* Not reached */ - case APR_INPARENT: - /* I'm the parent */ - apr_pool_note_subprocess(s->process->pool, callbackchild, - APR_KILL_AFTER_TIMEOUT); - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s, - "Forked callback child process with pid [%d]", - callbackchild->pid); - break; - default: - /* FUBAR: log and bail */ - ap_log_error(APLOG_MARK, APLOG_ERR, forkstatus, s, - "Failed to fork callback child"); - return HTTP_INTERNAL_SERVER_ERROR; - } -#endif /* APR_HAS_FORK */ - } /* If first time run */ - return OK; -} - -static void zc_register_hooks(apr_pool_t * p) -{ - ap_hook_post_config(zc_post_config, NULL, NULL, APR_HOOK_LAST); -} - -static const command_rec zc_cmds[] = { - AP_INIT_FLAG("Zeroconf", - cmd_zeroconf_enable, - NULL, - GLOBAL_ONLY, - "Enable/disable Zeroconf registration"), - AP_INIT_TAKE12("ZeroconfRegister", - cmd_zeroconf_register, - NULL, - NOT_IN_DIR_LOC_FILE, - "Register server or virtual host with Zeroconf mDNS responder.\n" - "Arguments are service name and, optionally, partial URI"), - {NULL} -}; - -module AP_MODULE_DECLARE_DATA zeroconf_module = { - STANDARD20_MODULE_STUFF, - NULL, - NULL, - zc_create_server_config, - zc_merge_server_config, - zc_cmds, - zc_register_hooks, -}; diff --git a/mod_zeroconf.c b/mod_zeroconf.c new file mode 100644 index 0000000..6246436 --- /dev/null +++ b/mod_zeroconf.c @@ -0,0 +1,408 @@ +/* + * $Id: mod_zeroconf.c,v 1.20 2004/10/07 15:30:25 sctemme Exp $ + * + * Copyright 2003, 2004 Sander Temme + * + * Licensed 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 +#include +#include +#include + +#include "httpd.h" +#include "http_config.h" +#include "http_log.h" +#include "apr_strings.h" + +#include + +/* Macro to test result of Howl functions */ +#define TESTORBAIL(f) if ((f) != SW_OKAY) { \ + return HTTP_INTERNAL_SERVER_ERROR; \ + } + +typedef struct zc_cfg { + int enabled; + char *serviceName; + char *partialURI; +} + zc_cfg; + +sw_discovery howl_session; + +module AP_MODULE_DECLARE_DATA zeroconf_module; + +/* + * Locate server configuration record for specified server + */ +static zc_cfg *our_sconfig(const server_rec *s) +{ + return (zc_cfg *) ap_get_module_config(s->module_config, + &zeroconf_module); +} + +static const char *cmd_zeroconf_enable(cmd_parms *cmd, void *mconfig, + int enable) +{ + zc_cfg *cfg = our_sconfig(cmd->server); + cfg->enabled = enable; + ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, cmd->server, + "Zeroconf switched %s", enable ? "on" : "off"); + + return NULL; +} + +static const char *cmd_zeroconf_register(cmd_parms *cmd, void *mconfig, + const char *serviceName, + const char *partialURI) +{ + zc_cfg *cfg = our_sconfig(cmd->server); + + cfg->serviceName = (char *) serviceName; + ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, cmd->server, + "Service Name is \"%s\"", cfg->serviceName); + cfg->partialURI = (char *) partialURI; + ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, cmd->server, + "Partial Path is %s", + (partialURI == NULL) ? "not set" : cfg->partialURI); + return NULL; +} + +static void *zc_create_server_config(apr_pool_t * p, server_rec *s) +{ + zc_cfg *cfg; + + cfg = (zc_cfg *) apr_palloc(p, sizeof(zc_cfg)); + cfg->enabled = 0; /* Default to disabled */ + cfg->serviceName = NULL; + cfg->partialURI = NULL; + + return (void *) cfg; +} + +static void *zc_merge_server_config(apr_pool_t * p, void *server1_conf, + void *server2_conf) +{ + zc_cfg *merged_cfg, *s1cfg, *s2cfg; + merged_cfg = (zc_cfg *) apr_palloc(p, sizeof(zc_cfg)); + s1cfg = (zc_cfg *) server1_conf; + s2cfg = (zc_cfg *) server2_conf; + + /* + * Inherit the zeroconf enablement. Config language does not allow + * turning it off, so just assume the main server value. + */ + merged_cfg->enabled = s1cfg->enabled; + /* + * Don't care about any main server registration info. + * Use vhost reg info, even if it's NULL. + */ + merged_cfg->serviceName = s2cfg->serviceName; + merged_cfg->partialURI = s2cfg->partialURI; + + return (void *) merged_cfg; +} + +static sw_result howl_publish_reply(sw_discovery rendezvous, + sw_discovery_publish_status status, + sw_discovery_oid id, + sw_opaque opaque) +{ + static sw_string status_text[] = { + "Started", + "Stopped", + "Name Collision", + "Invalid" + }; + fprintf(stderr, "publish reply: %s\n", status_text[status]); + return SW_OKAY; +} + +static sw_result host_publish_reply(sw_discovery rendezvous, + sw_discovery_publish_status status, + sw_discovery_oid id, + sw_opaque extra) +{ + static sw_string status_text[] = { + "Started", + "Stopped", + "Name Collision", + "Invalid" + }; + fprintf(stderr, "host registration reply: %s\n", status_text[status]); + fprintf(stderr, "Host registration callback: %d\n", status); + return SW_OKAY; +} + +/* + * Publish the hostname of server s through mDNS, using the IP + * address(es) that the server is bound to, if any. + * + */ + +static int zc_register_host(server_rec *s) +{ + + apr_sockaddr_t *mysock; + apr_status_t aprstatus; + char *thehostip; + sw_result hr; + sw_ipv4_address serveraddr; + sw_discovery_oid host_id; + + ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, + s, "Registering host with name %s", + s->server_hostname); + for (mysock = s->addrs->host_addr; mysock; + mysock = mysock->next) { + /* + * First, get the IP address string from the server + * record + */ + aprstatus = apr_sockaddr_ip_get(&thehostip, mysock); + if (aprstatus != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, aprstatus, s, + "Failed to obtain server address"); + return HTTP_INTERNAL_SERVER_ERROR; + } + ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, + 0, s, "Server bound to IP address [%s] port [%d][%d]", + thehostip, mysock->port,s->port); + /* + * Howl doesn't know what to do with IPv6 at this + * time + */ + if (mysock->family == APR_INET) { + if (mysock->sa.sin.sin_addr.s_addr != INADDR_ANY + && mysock->sa.sin.sin_addr.s_addr != INADDR_NONE) + /* What about localhost ? */ + { + hr = sw_ipv4_address_init_from_name(&serveraddr, thehostip); + } + else { + hr = sw_ipv4_address_init_from_this_host(&serveraddr); + } + } + hr = sw_discovery_publish_host(howl_session, + 0, + s->server_hostname, + NULL, + serveraddr, + host_publish_reply, + (sw_opaque) s, + &host_id); + if (hr != SW_OKAY) { + ap_log_error(APLOG_MARK, APLOG_ERR, hr, + s, + "Failed to publish hostname \"%s\" " + "with IP address \"%s\"", + s->server_hostname, thehostip); + return HTTP_INTERNAL_SERVER_ERROR; + } + } + return OK; +} + +static int zc_post_config(apr_pool_t * pconf, apr_pool_t * plog, + apr_pool_t * ptemp, server_rec *s) +{ + void *data; + sw_discovery_oid *pubidPtr; + const char *userdata_key = "zeroconf_init_module"; + zc_cfg *cfg; + sw_result howl_result; + sw_discovery_oid howl_id; + sw_port serverport; + sw_text_record text_record; + sw_octets pathinfo; + sw_ulong pilength; + char *thehostname; +#if APR_HAS_FORK + apr_proc_t *callbackchild; + apr_status_t forkstatus; +#endif + server_rec *ws; /* Walk Server; we need the top server_rec + * later */ + + /* raise(SIGSTOP); */ + + apr_pool_userdata_get(&data, userdata_key, s->process->pool); + ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s, + "In post_config, userdata pointer is %#lx, pid is %d", + data, getpid()); + if (!data) { + /* + * Tell the world we've been here before, so we don't end up forking + * more than one callback processes. + */ + apr_pool_userdata_set((const void *) 1, userdata_key, + apr_pool_cleanup_null, s->process->pool); + } else { + /* Check if Zeroconf has been enabled globally. If not, bail here */ + cfg = our_sconfig(s); + if (cfg->enabled == 0) { + return OK; + } + /* Still here? Let's go. */ + TESTORBAIL(sw_discovery_init(&howl_session)); + + /* + * Need to know the hostname of the machine, so we know not to + * re-register an existing one + */ + thehostname = apr_palloc(pconf, APRMAXHOSTLEN + 1); + if (!thehostname) { + return HTTP_INTERNAL_SERVER_ERROR; + } + if (!APR_STATUS_IS_SUCCESS(apr_gethostname(thehostname, + APRMAXHOSTLEN, pconf))) { + return HTTP_INTERNAL_SERVER_ERROR; + } + ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s, + "The hostname is [%s]", thehostname); + for (ws = s; ws; ws = ws->next) { + cfg = our_sconfig(ws); + if (cfg->serviceName) { + if (cfg->partialURI) { + TESTORBAIL(sw_text_record_init(&text_record)); + TESTORBAIL(sw_text_record_add_key_and_string_value(text_record, "path", + cfg->partialURI)); + pathinfo = sw_text_record_bytes(text_record); + pilength = sw_text_record_len(text_record); + } + else { + pathinfo = NULL; + pilength = 0; + } + /* + * for main server port is fetched from eg: + * ServerName hostnam:port + * + * for virtualhost eg: + * + */ + serverport = ws->is_virtual ? ws->addrs->host_port: ws->port; + ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, ws, + "Publishing service with service name [%s]; " + "hostname [%s]; port [%d], path [%s]", + cfg->serviceName, + ws->server_hostname, serverport, cfg->partialURI); + if (apr_strnatcasecmp(thehostname, ws->server_hostname) != 0) { + /* Shouldn't throw away the result here. What's up with + * that? + */ + zc_register_host(ws); + } + howl_result = sw_discovery_publish(howl_session, + 0, + cfg->serviceName, + "_http._tcp", + NULL, + ws->server_hostname, + serverport, + pathinfo, + pilength, + howl_publish_reply, + (sw_opaque) ws, + &howl_id); + if (howl_result != SW_OKAY) { + ap_log_error(APLOG_MARK, APLOG_ERR, howl_result, + ws, "Failed to publish service %s", + cfg->serviceName); + return HTTP_INTERNAL_SERVER_ERROR; + } + pubidPtr = apr_palloc(s->process->pool, + sizeof(sw_discovery_oid)); + if (!pubidPtr) { + return HTTP_INTERNAL_SERVER_ERROR; + } + /* + * Store publish ID in the server's pool userdata, using the + * serviceName as key. The serviceName should be unique, right? + */ + *pubidPtr = howl_id; + apr_pool_userdata_set(pubidPtr, cfg->serviceName, + apr_pool_cleanup_null, + ws->process->pool); + } /* serviceName set for server config */ + } /* Server walk */ + + /* + * On unix-like systems, we need to fork a child process to + * run the callback function. On Windows, this is not necessary. + */ +#if APR_HAS_FORK + callbackchild = apr_palloc(s->process->pool, sizeof(apr_proc_t)); + if (callbackchild == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Allocating process struct memory from pool failed"); + return HTTP_INTERNAL_SERVER_ERROR; + } + switch(forkstatus = apr_proc_fork(callbackchild, s->process->pool)) { + case APR_INCHILD: + /* I'm the child */ + sw_discovery_run(howl_session); + /* + * This function never returns ... + */ + break; /* Not reached */ + case APR_INPARENT: + /* I'm the parent */ + apr_pool_note_subprocess(s->process->pool, callbackchild, + APR_KILL_AFTER_TIMEOUT); + ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s, + "Forked callback child process with pid [%d]", + callbackchild->pid); + break; + default: + /* FUBAR: log and bail */ + ap_log_error(APLOG_MARK, APLOG_ERR, forkstatus, s, + "Failed to fork callback child"); + return HTTP_INTERNAL_SERVER_ERROR; + } +#endif /* APR_HAS_FORK */ + } /* If first time run */ + return OK; +} + +static void zc_register_hooks(apr_pool_t * p) +{ + ap_hook_post_config(zc_post_config, NULL, NULL, APR_HOOK_LAST); +} + +static const command_rec zc_cmds[] = { + AP_INIT_FLAG("Zeroconf", + cmd_zeroconf_enable, + NULL, + GLOBAL_ONLY, + "Enable/disable Zeroconf registration"), + AP_INIT_TAKE12("ZeroconfRegister", + cmd_zeroconf_register, + NULL, + NOT_IN_DIR_LOC_FILE, + "Register server or virtual host with Zeroconf mDNS responder.\n" + "Arguments are service name and, optionally, partial URI"), + {NULL} +}; + +module AP_MODULE_DECLARE_DATA zeroconf_module = { + STANDARD20_MODULE_STUFF, + NULL, + NULL, + zc_create_server_config, + zc_merge_server_config, + zc_cmds, + zc_register_hooks, +}; -- cgit