From 56b9485f26d6811e9afe9e45ccecd5bfeb33c1a7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 19 Jan 2006 01:00:17 +0000 Subject: add autoconf stuff git-svn-id: file:///home/lennart/svn/public/mod_dnssd/trunk@11 634eccf8-0006-0410-930e-e16565b0b7de --- Makefile | 30 --- Makefile.am | 39 +++ bootstrap.sh | 58 +++++ configure.ac | 119 +++++++++ mod_dnssd.c | 776 ------------------------------------------------------- src/Makefile.in | 39 +++ src/mod_dnssd.c | 777 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1032 insertions(+), 806 deletions(-) delete mode 100644 Makefile create mode 100644 Makefile.am create mode 100755 bootstrap.sh create mode 100644 configure.ac delete mode 100644 mod_dnssd.c create mode 100644 src/Makefile.in create mode 100644 src/mod_dnssd.c diff --git a/Makefile b/Makefile deleted file mode 100644 index 4156e3b..0000000 --- a/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# $Id$ - -APXS=/usr/bin/apxs2 -APACHECTL=apache2ctl -LIBS=$(shell pkg-config --libs avahi-client) -CFLAGS=$(shell pkg-config --cflags avahi-client) - -all: mod_dnssd.la - -mod_dnssd.la: mod_dnssd.c - $(APXS) -c $(CFLAGS) $(LIBS) mod_dnssd.c - -install: mod_dnssd.la - $(APXS) -i -a mod_dnssd.la - -clean: - rm -rf *.o *.so *.loT .deps/ *.la *.lo *.slo .libs - -reload: install restart - -start: - $(APACHECTL) start - -restart: - $(APACHECTL) restart - -stop: - $(APACHECTL) stop - -.PHONY: all install clean reload start restart stop diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..bc9e28c --- /dev/null +++ b/Makefile.am @@ -0,0 +1,39 @@ +# $Id$ + +# Copyright 2006 Lennart Poettering +# +# 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. + +EXTRA_DIST=bootstrap.sh LICENSE src/mod_dnssd.c src/Makefile.in +SUBDIRS=src +# doc + +#MAINTAINERCLEANFILES = README +#noinst_DATA = README LICENSE + +#README: +# rm -f README +# $(MAKE) -C doc README +# cd $(srcdir) && ln -s doc/README README + +#homepage: all dist +# test -d $$HOME/homepage/private +# mkdir -p $$HOME/homepage/private/projects/mod_mime_xattr +# cp *.tar.gz $$HOME/homepage/private/projects/mod_mime_xattr +# cp doc/README.html doc/style.css $$HOME/homepage/private/projects/mod_mime_xattr +# cp $$HOME/homepage/private/projects/mod_mime_xattr/README.html $$HOME/homepage/private/projects/mod_mime_xattr/index.html + +#distcleancheck: +# @: + +#.PHONY: homepage distcleancheck diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..db38ffb --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# $Id$ + +# Copyright 2006 Lennart Poettering +# +# 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. + +VERSION=1.9 + +run_versioned() { + local P + local V + + V=$(echo "$2" | sed -e 's,\.,,g') + + if [ -e "`which $1$V`" ] ; then + P="$1$V" + else + if [ -e "`which $1-$2`" ] ; then + P="$1-$2" + else + P="$1" + fi + fi + + shift 2 + "$P" "$@" +} + +set -ex + +if [ "x$1" = "xam" ] ; then + run_versioned automake "$VERSION" -a -c --foreign + ./config.status +else + rm -rf autom4te.cache + rm -f config.cache + + run_versioned aclocal "$VERSION" + run_versioned autoconf 2.59 -Wall + run_versioned autoheader 2.59 + run_versioned automake "$VERSION" -a -c --foreign + + if test "x$NOCONFIGURE" = "x"; then + CFLAGS="-g -O0" ./configure --sysconfdir=/etc "$@" + make clean + fi +fi diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..a4651ff --- /dev/null +++ b/configure.ac @@ -0,0 +1,119 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +# $Id$ + +# Copyright 2006 Lennart Poettering +# +# 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. + +AC_PREREQ(2.57) +AC_INIT([mod_dnssd],[0.1],[mzzbqqaffq (at) 0pointer (dot) net]) +AC_CONFIG_SRCDIR([src/mod_dnssd.c]) +AC_CONFIG_HEADERS([config.h]) +AM_INIT_AUTOMAKE([foreign 1.9 -Wall]) + +AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/mod_dnssd/]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_MAKE_SET + +test_gcc_flag() { + AC_LANG_CONFTEST([int main() {}]) + $CC -c conftest.c $CFLAGS $@ > /dev/null 2> /dev/null + ret=$? + rm -f conftest.o + return $ret +} + +# If using GCC specify some additional parameters +if test "x$GCC" = "xyes" ; then + + DESIRED_FLAGS="-Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Winline" + + if test "x$HAVE_NETLINK" = "xyes" ; then + # Test whether rtnetlink.h can be included when compiled with -std=c99 + # some distributions (e.g. archlinux) have broken headers that dont + # define __u64 with -std=c99 + AC_MSG_CHECKING([checking whether rtnetlink.h can be included with -std=c99]) + OLDCFLAGS="$CFLAGS" + CFLAGS="-std=c99" + AC_TRY_COMPILE([#include ], [], + use_stdc99=yes, use_stdc99=no) + + if test x"$use_stdc99" = xyes; then + DESIRED_FLAGS="-std=c99 $DESIRED_FLAGS" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + + CFLAGS="$OLDCFLAGS" + else + DESIRED_FLAGS="-std=c99 $DESIRED_FLAGS" + fi + + for flag in $DESIRED_FLAGS ; do + AC_MSG_CHECKING([whether $CC accepts $flag]) + if test_gcc_flag $flag ; then + CFLAGS="$CFLAGS $flag" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + done +fi + +AC_ARG_WITH(apxs, + AS_HELP_STRING(--with-apxs=PATH,/path/to/apxs), + [ AC_PATH_PROGS(APXS, [apxs2 apxs], "notfound", "$withval:$PATH") ], + [ AC_PATH_PROGS(APXS, [apxs2 apxs], "notfound", "/usr/local/apache/bin:/usr/local/bin:/usr/sbin:$PATH")]) + +if test "x$APXS" = "xnotfound" ; then + AC_MSG_ERROR([*** Sorry, could not find apxs ***]) +fi + +AC_ARG_WITH(apachectl, + AS_HELP_STRING(--with-apachectl=PATH,/path/to/apachectl), + [ AC_PATH_PROGS(APACHECTL, [apache2ctl apachectl], "notfound", "$withval:$PATH") ], + [ AC_PATH_PROGS(APACHECTL, [apache2ctl apachectl], "notfound", "/usr/local/apache/bin:/usr/local/bin:/usr/sbin:$PATH")]) + +PKG_CHECK_MODULES(AVAHI, [ avahi-client >= 0.6 ]) +AC_SUBST(AVAHI_CFLAGS) +AC_SUBST(AVAHI_LIBS) + +# LYNX documentation generation +AC_ARG_ENABLE(lynx, + AS_HELP_STRING(--disable-lynx,Turn off lynx usage for documentation generation), +[case "${enableval}" in + yes) lynx=yes ;; + no) lynx=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-lynx) ;; +esac],[lynx=yes]) + +if test x$lynx = xyes ; then + AC_CHECK_PROG(have_lynx, lynx, yes, no) + + if test x$have_lynx = xno ; then + AC_MSG_ERROR([*** Sorry, you have to install lynx or use --disable-lynx ***]) + fi +fi + +AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes]) + +AC_CONFIG_FILES([src/Makefile Makefile]) +dnl AC_CONFIG_FILES([src/Makefile Makefile doc/Makefile doc/README.html]) +AC_OUTPUT diff --git a/mod_dnssd.c b/mod_dnssd.c deleted file mode 100644 index 37992b6..0000000 --- a/mod_dnssd.c +++ /dev/null @@ -1,776 +0,0 @@ -/* $Id$ */ - -/*** - Copyright 2006 Lennart Poettering - - 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 -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#define MOD_DNSSD_USERDATA_KEY "mod-dnssd" - -struct runtime_data; - -struct service_data { - struct runtime_data *runtime; - apr_pool_t *pool; - - char *host_name; - uint16_t port; - char *location; - char *name; - apr_array_header_t *types; - int append_host_name; - char *chosen_name; - - AvahiEntryGroup *group; - - struct service_data *next; -}; - -struct runtime_data { - server_rec *main_server; - AvahiClient *client; - AvahiSimplePoll *simple_poll; - struct global_config_data *global_config_data; - apr_pool_t* pool; - struct service_data *services; -}; - -struct global_config_data { - int enabled; - int user_dir; - int vhost; -}; - -static int sigterm_pipe_fds[2] = { -1, -1 }; - -module AP_MODULE_DECLARE_DATA dnssd_module; - -#define GET_CONFIG_DATA(s) ap_get_module_config((s)->module_config, &dnssd_module) - -static int set_nonblock(int fd) { - int n; - - ap_assert(fd >= 0); - - if ((n = fcntl(fd, F_GETFL)) < 0) - return -1; - - if (n & O_NONBLOCK) - return 0; - - return fcntl(fd, F_SETFL, n|O_NONBLOCK); -} - -static void add_service(struct runtime_data *r, const char *host_name, uint16_t port, const char *location, const char *name, const char *types, int append_host_name) { - struct service_data *d; - char *w; - ap_assert(r); - -/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "add_service: %s %s %s", host_name, location, name); */ - - d = apr_palloc(r->pool, sizeof(struct service_data)); - ap_assert(d); - - d->pool = NULL; - d->runtime = r; - d->host_name = apr_pstrdup(r->pool, host_name); - d->port = port; - d->location = apr_pstrdup(r->pool, location); - d->name = apr_pstrdup(r->pool, name); - d->append_host_name = append_host_name; - d->chosen_name = NULL; - - d->types = apr_array_make(r->pool, 4, sizeof(char*)); - - if (types) - while (*(w = ap_getword_conf(r->pool, &types)) != 0) - *(char**) apr_array_push(d->types) = w; - - d->group = NULL; - - d->next = r->services; - r->services = d; - -/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "done"); */ - -} - -static void assemble_services(struct runtime_data *r) { - ap_directive_t *v; - const char *default_host_name = NULL; - uint16_t default_port = 80; - struct service_data *j; - apr_pool_t *t; - - ap_assert(r); - - apr_pool_create(&t, r->pool); - - for (v = ap_conftree; v; v = v->next) { - const char *a = v->args; - - if (strcasecmp(v->directive, "ServerName") == 0) - default_host_name = ap_getword_conf(t, &a); - else if (strcasecmp(v->directive, "Port") == 0) - default_port = (uint16_t) atoi(ap_getword_conf(t, &a)); - else if (strcasecmp(v->directive, "services; - - if ((colon = strchr(v->args, ':'))) - port = (uint8_t) atoi(colon+1); - -/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "VHOST: %s ", v->directive); */ - - for (l = v->first_child; l; l = l->next) { - a = l->args; - -/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "VHOST_INTERNAL %s | %s | %s | %s", l->directive, l->args, vname, vtypes); */ - - if (strcasecmp(l->directive, "ServerName") == 0) - host_name = ap_getword_conf(t, &a); - else if (strcasecmp(l->directive, "Port") == 0) - port = (uint16_t) atoi(ap_getword_conf(t, &a)); - else if (strcasecmp(l->directive, "DNSSDServiceName") == 0) - vname = ap_getword_conf(t, &a); - else if (strcasecmp(l->directive, "DNSSDServiceTypes") == 0) - vtypes = a; - else if (strcasecmp(l->directive, "args); - - if (*path != 0 && (path[(i = strlen(path) - 1)] == '>')) - path[i] = 0; - - for (s = l->first_child; s; s = s->next) { - a = s->args; - - if (strcasecmp(s->directive, "DNSSDServiceName") == 0) - sname = ap_getword_conf(t, &a); - else if (strcasecmp(s->directive, "DNSSDServiceTypes") == 0) - stypes = a; - } - - if (sname) - add_service(r, NULL, 0, path, sname, stypes, 0); - } - } - - /* Fill in missing data in based services */ - for (j = r->services; j && j != marker; j = j->next) { - j->port = port; - j->host_name = apr_pstrdup(r->pool, host_name); - } - - if (r->global_config_data->vhost || vname || vtypes) - add_service(r, host_name, port, NULL, vname ? vname : host_name, vtypes, 0); - } - } - -/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "ping"); */ - - if (r->global_config_data->user_dir) { - struct passwd *pw; - apr_pool_t *p_loop; - - apr_pool_create(&p_loop, t); - - while ((pw = getpwent())) { - apr_finfo_t finfo; - char *path; - const char *u; - - apr_pool_clear(p_loop); - - if (pw->pw_uid <= 500) - continue; - - if (*pw->pw_dir == 0 || strcmp(pw->pw_dir, "/") == 0) - continue; - - path = apr_pstrcat(p_loop, pw->pw_dir, "/public_html", NULL); - - if (apr_stat(&finfo, path, APR_FINFO_TYPE, p_loop) != APR_SUCCESS) - continue; - - if (finfo.filetype != APR_DIR) - continue; - - if (access(path, X_OK) != 0) - continue; - - if (pw->pw_gecos && *pw->pw_gecos) { - char *comma; - u = apr_pstrdup(p_loop, pw->pw_gecos); - if ((comma = strchr(u, ','))) - *comma = 0; - } else - u = pw->pw_name; - - add_service(r, NULL, 0, apr_pstrcat(p_loop, "/~", pw->pw_name), apr_pstrcat(p_loop, u, " on ", NULL), NULL, 1); - } - - endpwent(); - - apr_pool_destroy(p_loop); - } - - /* Fill in missing data in all services */ - for (j = r->services; j; j = j->next) { - if (!j->port) - j->port = default_port; - - if (!j->host_name) - j->host_name = apr_pstrdup(r->pool, default_host_name); - - if (!j->name) - j->name = apr_pstrdup(r->pool, j->host_name); - } - - apr_pool_destroy(t); -} - -static void create_service(struct service_data *j); - -void service_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { - struct service_data *j = userdata; - - switch (state) { - case AVAHI_ENTRY_GROUP_UNCOMMITED: - case AVAHI_ENTRY_GROUP_REGISTERING: - case AVAHI_ENTRY_GROUP_ESTABLISHED: - break; - - case AVAHI_ENTRY_GROUP_COLLISION: { - - char *n; - ap_assert(j->chosen_name); - - n = avahi_alternative_service_name(j->chosen_name); - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, j->runtime->main_server, "Name collision on '%s', changing to '%s'", j->chosen_name, n); - - apr_pool_clear(j->pool); - j->chosen_name = apr_pstrdup(j->pool, n); - - create_service(j); - - break; - } - - case AVAHI_ENTRY_GROUP_FAILURE: - ap_log_error(APLOG_MARK, APLOG_ERR, 0, j->runtime->main_server, "Failed to register service: %s", avahi_strerror(avahi_client_errno(j->runtime->client))); - break; - } -} - -static void create_service(struct service_data *j) { - apr_pool_t *t; - const char *n; - char *p; - struct runtime_data *r = j->runtime; - - if (!j->group) - if (!(j->group = avahi_entry_group_new(r->client, service_callback, j))) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "avahi_entry_group_new() failed: %s", avahi_strerror(avahi_client_errno(r->client))); - return; - } - - ap_assert(j->group); - ap_assert(avahi_entry_group_is_empty(j->group)); - - apr_pool_create(&t, r->pool); - -/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "Service <%s>, host <%s>, port <%u>, location <%s>", j->name, j->host_name, j->port, j->location); */ - - if (j->chosen_name) - n = j->chosen_name; - else if (!j->name) - n = avahi_client_get_host_name(r->client); - else if (j->append_host_name) - n = apr_pstrcat(t, j->name, avahi_client_get_host_name(r->client), NULL); - else - n = j->name; - - if (!j->pool) - apr_pool_create(&j->pool, r->pool); - - if (n != j->chosen_name) { - apr_pool_clear(j->pool); - j->chosen_name = apr_pstrdup(j->pool, n); - } - - p = j->location ? apr_pstrcat(t, "path=", j->location, NULL) : NULL; - -/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "%s, %s", p, n); */ - - if (apr_is_empty_array(j->types)) { - - if (avahi_entry_group_add_service( - j->group, - AVAHI_IF_UNSPEC, - AVAHI_PROTO_UNSPEC, - 0, - n, - j->port == 443 ? "_https._tcp" : "_http._tcp", - NULL, - j->host_name, - j->port, - p, - NULL) < 0) { - - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "avahi_entry_group_add_service(\"%s\") failed: %s\n", n, avahi_strerror(avahi_client_errno(r->client))); - } - } else { - - char **type; - - for (type = (char**) j->types->elts; *type; type++) { - - if (avahi_entry_group_add_service( - j->group, - AVAHI_IF_UNSPEC, - AVAHI_PROTO_UNSPEC, - 0, - n, - *type, - NULL, - j->host_name, - j->port, - p, - NULL) < 0) { - - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "avahi_entry_group_add_service(\"%s\") failed: %s\n", n, avahi_strerror(avahi_client_errno(r->client))); - } - - } - - } - - if (avahi_entry_group_is_empty(j->group)) { - avahi_entry_group_free(j->group); - j->group = NULL; - } else - avahi_entry_group_commit(j->group); - - apr_pool_destroy(t); -} - -static void create_all_services(struct runtime_data *r) { - struct service_data *j; - ap_assert(r); - - for (j = r->services; j; j = j->next) - create_service(j); -} - -static void reset_services(struct runtime_data *r) { - struct service_data *j; - - ap_assert(r); - - for (j = r->services; j; j = j->next) { - if (j->group) - avahi_entry_group_reset(j->group); - - if (j->pool) - apr_pool_clear(j->pool); - - j->chosen_name = NULL; - } -} - -static void free_services(struct runtime_data *r) { - struct service_data *j; - - ap_assert(r); - - for (j = r->services; j; j = j->next) { - - if (j->group) { - avahi_entry_group_free(j->group); - j->group = NULL; - } - - if (j->pool) - apr_pool_clear(j->pool); - - j->chosen_name = NULL; - } -} - -static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata) { - struct runtime_data *r = userdata; - - ap_assert(r); - - r->client = c; - -/* ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->main_server, "client_callback(%u)", state); */ - - switch (state) { - case AVAHI_CLIENT_S_RUNNING: - create_all_services(r); - break; - - case AVAHI_CLIENT_S_COLLISION: - reset_services(r); - break; - - case AVAHI_CLIENT_FAILURE: - - if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) { - int error; - - free_services(r); - avahi_client_free(r->client); - - if ((r->client = avahi_client_new(avahi_simple_poll_get(r->simple_poll), AVAHI_CLIENT_NO_FAIL, client_callback, r, &error))) - break; - - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "avahi_client_new() failed: %s", avahi_strerror(error)); - } else - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "Client failure: %s", avahi_strerror(avahi_client_errno(c))); - - avahi_simple_poll_quit(r->simple_poll); - - break; - - case AVAHI_CLIENT_CONNECTING: - case AVAHI_CLIENT_S_REGISTERING: - break; - } - -} - -static void sigterm(int s) { - const char c = 'x'; - write(sigterm_pipe_fds[1], &c, sizeof(c)); -} - -static void watch_callback(AvahiWatch *w, int fd, AvahiWatchEvent event, void *userdata) { - char c; - ssize_t l; - struct runtime_data *r = userdata; - - ap_assert(w); - ap_assert(fd == sigterm_pipe_fds[0]); - ap_assert(event == AVAHI_WATCH_IN); - ap_assert(r); - - l = read(fd, &c, sizeof(c)); - ap_assert(l == sizeof(c)); - - avahi_simple_poll_quit(r->simple_poll); -} - -static void child_process(apr_pool_t *p, server_rec *server, struct global_config_data *d) { - struct runtime_data r; - int error; - const AvahiPoll *api; - AvahiWatch *w; - - ap_assert(d); - - unixd_setup_child(); - - if (pipe(sigterm_pipe_fds) < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r.main_server, "pipe() failed: %s", strerror(errno)); - goto quit; - } - - set_nonblock(sigterm_pipe_fds[0]); - set_nonblock(sigterm_pipe_fds[1]); - - apr_signal(SIGTERM, sigterm); - - r.main_server = server; - r.global_config_data = d; - r.client = NULL; - r.simple_poll = NULL; - r.services = NULL; - apr_pool_create(&r.pool, p); - -/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r.main_server, "Child process startup pid=%lu", (unsigned long) getpid()); */ - - assemble_services(&r); - - if (!r.services) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r.main_server, __FILE__": No services found to register"); - goto quit; - } - - if (!(r.simple_poll = avahi_simple_poll_new())) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r.main_server, "avahi_simple_poll_new() failed: %s", strerror(errno)); - goto quit; - } - - api = avahi_simple_poll_get(r.simple_poll); - w = api->watch_new(api, sigterm_pipe_fds[0], AVAHI_WATCH_IN, watch_callback, &r); - ap_assert(w); - - if (!(r.client = avahi_client_new(avahi_simple_poll_get(r.simple_poll), AVAHI_CLIENT_NO_FAIL, client_callback, &r, &error))) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r.main_server, "avahi_client_new() failed: %s", avahi_strerror(error)); - goto quit; - } - -/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r.main_server, "Child process running"); */ - - avahi_simple_poll_loop(r.simple_poll); - -quit: - - if (r.client) - avahi_client_free(r.client); - - if (r.simple_poll) - avahi_simple_poll_free(r.simple_poll); - - if (r.pool) - apr_pool_destroy(r.pool); - - if (sigterm_pipe_fds[0] >= 0) - close(sigterm_pipe_fds[0]); - - if (sigterm_pipe_fds[1] >= 0) - close(sigterm_pipe_fds[1]); - - sigterm_pipe_fds[0] = sigterm_pipe_fds[1] = -1; - -/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r.main_server, "Child process ending"); */ -} - -static int start_child_process(apr_pool_t *p, server_rec *server, struct global_config_data *d) { - apr_proc_t* proc; - apr_status_t status; - -/* ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, server, "Spawning child pid=%lu", (unsigned long) getpid()); */ - - proc = apr_palloc(p, sizeof(apr_proc_t)); - ap_assert(proc); - - switch (status = apr_proc_fork(proc, p)) { - - case APR_INCHILD: - child_process(p, server, d); - exit(1); - /* never reached */ - break; - - case APR_INPARENT: - apr_pool_note_subprocess(p, proc, APR_KILL_AFTER_TIMEOUT); -/* ap_log_error(APLOG_MARK, APLOG_NOTICE, status, server, "Child process %lu", (unsigned long) proc->pid); */ - - break; - - default: - ap_log_error(APLOG_MARK, APLOG_ERR, status, server, "apr_proc_fork() failed"); - return HTTP_INTERNAL_SERVER_ERROR; - } - - return OK; -} - -static int post_config( - apr_pool_t *pconf, - apr_pool_t *plog, - apr_pool_t *ptemp, - server_rec *s) { - - void *flag; - struct global_config_data *d = GET_CONFIG_DATA(s); - - /* All post_config hooks are called twice, we're only interested in the second call. */ - - apr_pool_userdata_get(&flag, MOD_DNSSD_USERDATA_KEY, s->process->pool); - if (!flag) { - apr_pool_userdata_set((void*) 1, MOD_DNSSD_USERDATA_KEY, apr_pool_cleanup_null, s->process->pool); - return OK; - } - - if (d->enabled) - return start_child_process(pconf, s, d); - - return OK; -} - -static void register_hooks(apr_pool_t *p){ - ap_hook_post_config(post_config, NULL, NULL, APR_HOOK_LAST); -} - -static void *create_server_config(apr_pool_t *p, server_rec *s) { - struct global_config_data *d; - - d = apr_palloc(p, sizeof(struct global_config_data)); - ap_assert(d); - - d->enabled = 0; - d->user_dir = 1; - d->vhost = 1; - - return d; -} - -static const char *cmd_dnssd_enable( - cmd_parms *cmd, - void *mconfig, - int enable) { - - struct global_config_data *d = GET_CONFIG_DATA(cmd->server); - const char *err; - - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) - return err; - - d->enabled = enable; - return NULL; -} - -static const char *cmd_dnssd_enable_user_dir( - cmd_parms *cmd, - void *mconfig, - int enable) { - - struct global_config_data *d = GET_CONFIG_DATA(cmd->server); - const char *err; - - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) - return err; - - d->user_dir = enable; - return NULL; -} - -static const char *cmd_dnssd_enable_vhost( - cmd_parms *cmd, - void *mconfig, - int enable) { - - struct global_config_data *d = GET_CONFIG_DATA(cmd->server); - const char *err; - - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) - return err; - - d->vhost = enable; - return NULL; -} - -static const char *cmd_dnssd_service_name( - cmd_parms *cmd, - void *mconfig, - const char *value) { - - const char *err; - - if ((err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|NOT_IN_LIMIT))) - return err; - - if (!avahi_is_valid_service_name(value)) - return "Invalid service name"; - - return NULL; -} - -static const char *cmd_dnssd_service_type( - cmd_parms *cmd, - void *mconfig, - const char *value) { - - const char *err; - - if ((err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|NOT_IN_LIMIT))) - return err; - - if (!avahi_is_valid_service_type_strict(value)) - return "Invalid service type"; - - return NULL; -} - -static const command_rec commands[] = { - - AP_INIT_FLAG( - "DNSSDEnable", - cmd_dnssd_enable, - NULL, - RSRC_CONF, - "Enable/disable DNS-SD registration entirely (default: no)"), - - AP_INIT_FLAG( - "DNSSDAutoRegisterUserDir", - cmd_dnssd_enable_user_dir, - NULL, - RSRC_CONF, - "Enable/disable DNS-SD registration of ~/public_html (default: yes)"), - - AP_INIT_FLAG( - "DNSSDAutoRegisterVHosts", - cmd_dnssd_enable_vhost, - NULL, - RSRC_CONF, - "Enable/disable DNS-SD registration of all virtual hosts (default: yes)"), - - AP_INIT_TAKE1( - "DNSSDServiceName", - cmd_dnssd_service_name, - NULL, - OR_OPTIONS, - "Set the DNS-SD service name"), - - AP_INIT_ITERATE( - "DNSSDServiceTypes", - cmd_dnssd_service_type, - NULL, - OR_OPTIONS, - "Set on or more DNS-SD service types"), - - { NULL } -}; - -module AP_MODULE_DECLARE_DATA dnssd_module = { - STANDARD20_MODULE_STUFF, - NULL, /* create per-dir config structures */ - NULL, /* merge per-dir config structures */ - create_server_config, /* create per-server config structures */ - NULL, /* merge per-server config structures */ - commands, /* table of config file commands */ - register_hooks /* register hooks */ -}; - diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..c16ff43 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,39 @@ +# $Id$ + +APXS=@APXS@ +APACHECTL=@APACHECTL@ +LIBS=-Wl,"@LIBS@" @AVAHI_LIBS@ +CFLAGS=-Wc,"@CFLAGS@" @AVAHI_CFLAGS@ + +all: mod_dnssd.la + +mod_dnssd.la: mod_dnssd.c + $(APXS) -c $(CFLAGS) $(LIBS) mod_dnssd.c + +install: mod_dnssd.la + $(APXS) -i -a mod_dnssd.la + +clean: + rm -rf *.o *.so *.loT .deps/ *.la *.lo *.slo .libs/ + +reload: install restart + +start: + $(APACHECTL) start + +restart: + $(APACHECTL) restart + +stop: + $(APACHECTL) stop + +mostlyclean: clean +distclean: clean +maintainer-clean: clean + rm -f Makefile + +Makefile: Makefile.in + (cd .. && ../configure.status ) + + +.PHONY: all install clean reload start restart stop mostlyclean distclean maintainer-clean diff --git a/src/mod_dnssd.c b/src/mod_dnssd.c new file mode 100644 index 0000000..96206b9 --- /dev/null +++ b/src/mod_dnssd.c @@ -0,0 +1,777 @@ +/* $Id$ */ + +/*** + Copyright 2006 Lennart Poettering + + 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 +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#define MOD_DNSSD_USERDATA_KEY "mod-dnssd" + +struct runtime_data; + +struct service_data { + struct runtime_data *runtime; + apr_pool_t *pool; + + char *host_name; + uint16_t port; + char *location; + char *name; + apr_array_header_t *types; + int append_host_name; + char *chosen_name; + + AvahiEntryGroup *group; + + struct service_data *next; +}; + +struct runtime_data { + server_rec *main_server; + AvahiClient *client; + AvahiSimplePoll *simple_poll; + struct global_config_data *global_config_data; + apr_pool_t* pool; + struct service_data *services; +}; + +struct global_config_data { + int enabled; + int user_dir; + int vhost; +}; + +static int sigterm_pipe_fds[2] = { -1, -1 }; + +module AP_MODULE_DECLARE_DATA dnssd_module; + +#define GET_CONFIG_DATA(s) ap_get_module_config((s)->module_config, &dnssd_module) + +static int set_nonblock(int fd) { + int n; + + ap_assert(fd >= 0); + + if ((n = fcntl(fd, F_GETFL)) < 0) + return -1; + + if (n & O_NONBLOCK) + return 0; + + return fcntl(fd, F_SETFL, n|O_NONBLOCK); +} + +static void add_service(struct runtime_data *r, const char *host_name, uint16_t port, const char *location, const char *name, const char *types, int append_host_name) { + struct service_data *d; + char *w; + ap_assert(r); + +/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "add_service: %s %s %s", host_name, location, name); */ + + d = apr_palloc(r->pool, sizeof(struct service_data)); + ap_assert(d); + + d->pool = NULL; + d->runtime = r; + d->host_name = apr_pstrdup(r->pool, host_name); + d->port = port; + d->location = apr_pstrdup(r->pool, location); + d->name = apr_pstrdup(r->pool, name); + d->append_host_name = append_host_name; + d->chosen_name = NULL; + + d->types = apr_array_make(r->pool, 4, sizeof(char*)); + + if (types) + while (*(w = ap_getword_conf(r->pool, &types)) != 0) + *(char**) apr_array_push(d->types) = w; + + d->group = NULL; + + d->next = r->services; + r->services = d; + +/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "done"); */ + +} + +static void assemble_services(struct runtime_data *r) { + ap_directive_t *v; + const char *default_host_name = NULL; + uint16_t default_port = 80; + struct service_data *j; + apr_pool_t *t; + + ap_assert(r); + + apr_pool_create(&t, r->pool); + + for (v = ap_conftree; v; v = v->next) { + const char *a = v->args; + + if (strcasecmp(v->directive, "ServerName") == 0) + default_host_name = ap_getword_conf(t, &a); + else if (strcasecmp(v->directive, "Port") == 0) + default_port = (uint16_t) atoi(ap_getword_conf(t, &a)); + else if (strcasecmp(v->directive, "services; + + if ((colon = strchr(v->args, ':'))) + port = (uint8_t) atoi(colon+1); + +/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "VHOST: %s ", v->directive); */ + + for (l = v->first_child; l; l = l->next) { + a = l->args; + +/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "VHOST_INTERNAL %s | %s | %s | %s", l->directive, l->args, vname, vtypes); */ + + if (strcasecmp(l->directive, "ServerName") == 0) + host_name = ap_getword_conf(t, &a); + else if (strcasecmp(l->directive, "Port") == 0) + port = (uint16_t) atoi(ap_getword_conf(t, &a)); + else if (strcasecmp(l->directive, "DNSSDServiceName") == 0) + vname = ap_getword_conf(t, &a); + else if (strcasecmp(l->directive, "DNSSDServiceTypes") == 0) + vtypes = a; + else if (strcasecmp(l->directive, "args); + + if (*path != 0 && (path[(i = strlen(path) - 1)] == '>')) + path[i] = 0; + + for (s = l->first_child; s; s = s->next) { + a = s->args; + + if (strcasecmp(s->directive, "DNSSDServiceName") == 0) + sname = ap_getword_conf(t, &a); + else if (strcasecmp(s->directive, "DNSSDServiceTypes") == 0) + stypes = a; + } + + if (sname) + add_service(r, NULL, 0, path, sname, stypes, 0); + } + } + + /* Fill in missing data in based services */ + for (j = r->services; j && j != marker; j = j->next) { + j->port = port; + j->host_name = apr_pstrdup(r->pool, host_name); + } + + if (r->global_config_data->vhost || vname || vtypes) + add_service(r, host_name, port, NULL, vname ? vname : host_name, vtypes, 0); + } + } + +/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "ping"); */ + + if (r->global_config_data->user_dir) { + struct passwd *pw; + apr_pool_t *p_loop; + + apr_pool_create(&p_loop, t); + + while ((pw = getpwent())) { + apr_finfo_t finfo; + char *path; + const char *u; + + apr_pool_clear(p_loop); + + if (pw->pw_uid <= 500) + continue; + + if (*pw->pw_dir == 0 || strcmp(pw->pw_dir, "/") == 0) + continue; + + path = apr_pstrcat(p_loop, pw->pw_dir, "/public_html", NULL); + + if (apr_stat(&finfo, path, APR_FINFO_TYPE, p_loop) != APR_SUCCESS) + continue; + + if (finfo.filetype != APR_DIR) + continue; + + if (access(path, X_OK) != 0) + continue; + + if (pw->pw_gecos && *pw->pw_gecos) { + char *comma; + u = apr_pstrdup(p_loop, pw->pw_gecos); + if ((comma = strchr(u, ','))) + *comma = 0; + } else + u = pw->pw_name; + + add_service(r, NULL, 0, apr_pstrcat(p_loop, "/~", pw->pw_name), apr_pstrcat(p_loop, u, " on ", NULL), NULL, 1); + } + + endpwent(); + + apr_pool_destroy(p_loop); + } + + /* Fill in missing data in all services */ + for (j = r->services; j; j = j->next) { + if (!j->port) + j->port = default_port; + + if (!j->host_name) + j->host_name = apr_pstrdup(r->pool, default_host_name); + + if (!j->name) + j->name = apr_pstrdup(r->pool, j->host_name); + } + + apr_pool_destroy(t); +} + +static void create_service(struct service_data *j); + +static void service_callback(AVAHI_GCC_UNUSED AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { + struct service_data *j = userdata; + + switch (state) { + case AVAHI_ENTRY_GROUP_UNCOMMITED: + case AVAHI_ENTRY_GROUP_REGISTERING: + case AVAHI_ENTRY_GROUP_ESTABLISHED: + break; + + case AVAHI_ENTRY_GROUP_COLLISION: { + + char *n; + ap_assert(j->chosen_name); + + n = avahi_alternative_service_name(j->chosen_name); + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, j->runtime->main_server, "Name collision on '%s', changing to '%s'", j->chosen_name, n); + + apr_pool_clear(j->pool); + j->chosen_name = apr_pstrdup(j->pool, n); + + create_service(j); + + break; + } + + case AVAHI_ENTRY_GROUP_FAILURE: + ap_log_error(APLOG_MARK, APLOG_ERR, 0, j->runtime->main_server, "Failed to register service: %s", avahi_strerror(avahi_client_errno(j->runtime->client))); + break; + } +} + +static void create_service(struct service_data *j) { + apr_pool_t *t; + const char *n; + char *p; + struct runtime_data *r = j->runtime; + + if (!j->group) + if (!(j->group = avahi_entry_group_new(r->client, service_callback, j))) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "avahi_entry_group_new() failed: %s", avahi_strerror(avahi_client_errno(r->client))); + return; + } + + ap_assert(j->group); + ap_assert(avahi_entry_group_is_empty(j->group)); + + apr_pool_create(&t, r->pool); + +/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "Service <%s>, host <%s>, port <%u>, location <%s>", j->name, j->host_name, j->port, j->location); */ + + if (j->chosen_name) + n = j->chosen_name; + else if (!j->name) + n = avahi_client_get_host_name(r->client); + else if (j->append_host_name) + n = apr_pstrcat(t, j->name, avahi_client_get_host_name(r->client), NULL); + else + n = j->name; + + if (!j->pool) + apr_pool_create(&j->pool, r->pool); + + if (n != j->chosen_name) { + apr_pool_clear(j->pool); + j->chosen_name = apr_pstrdup(j->pool, n); + } + + p = j->location ? apr_pstrcat(t, "path=", j->location, NULL) : NULL; + +/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "%s, %s", p, n); */ + + if (apr_is_empty_array(j->types)) { + + if (avahi_entry_group_add_service( + j->group, + AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + 0, + n, + j->port == 443 ? "_https._tcp" : "_http._tcp", + NULL, + j->host_name, + j->port, + p, + NULL) < 0) { + + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "avahi_entry_group_add_service(\"%s\") failed: %s\n", n, avahi_strerror(avahi_client_errno(r->client))); + } + } else { + + char **type; + + for (type = (char**) j->types->elts; *type; type++) { + + if (avahi_entry_group_add_service( + j->group, + AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + 0, + n, + *type, + NULL, + j->host_name, + j->port, + p, + NULL) < 0) { + + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "avahi_entry_group_add_service(\"%s\") failed: %s\n", n, avahi_strerror(avahi_client_errno(r->client))); + } + + } + + } + + if (avahi_entry_group_is_empty(j->group)) { + avahi_entry_group_free(j->group); + j->group = NULL; + } else + avahi_entry_group_commit(j->group); + + apr_pool_destroy(t); +} + +static void create_all_services(struct runtime_data *r) { + struct service_data *j; + ap_assert(r); + + for (j = r->services; j; j = j->next) + create_service(j); +} + +static void reset_services(struct runtime_data *r) { + struct service_data *j; + + ap_assert(r); + + for (j = r->services; j; j = j->next) { + if (j->group) + avahi_entry_group_reset(j->group); + + if (j->pool) + apr_pool_clear(j->pool); + + j->chosen_name = NULL; + } +} + +static void free_services(struct runtime_data *r) { + struct service_data *j; + + ap_assert(r); + + for (j = r->services; j; j = j->next) { + + if (j->group) { + avahi_entry_group_free(j->group); + j->group = NULL; + } + + if (j->pool) + apr_pool_clear(j->pool); + + j->chosen_name = NULL; + } +} + +static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata) { + struct runtime_data *r = userdata; + + ap_assert(r); + + r->client = c; + +/* ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->main_server, "client_callback(%u)", state); */ + + switch (state) { + case AVAHI_CLIENT_S_RUNNING: + create_all_services(r); + break; + + case AVAHI_CLIENT_S_COLLISION: + reset_services(r); + break; + + case AVAHI_CLIENT_FAILURE: + + if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) { + int error; + + free_services(r); + avahi_client_free(r->client); + + if ((r->client = avahi_client_new(avahi_simple_poll_get(r->simple_poll), AVAHI_CLIENT_NO_FAIL, client_callback, r, &error))) + break; + + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "avahi_client_new() failed: %s", avahi_strerror(error)); + } else + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->main_server, "Client failure: %s", avahi_strerror(avahi_client_errno(c))); + + avahi_simple_poll_quit(r->simple_poll); + + break; + + case AVAHI_CLIENT_CONNECTING: + case AVAHI_CLIENT_S_REGISTERING: + break; + } + +} + +static void sigterm(AVAHI_GCC_UNUSED int s) { + const char c = 'x'; + write(sigterm_pipe_fds[1], &c, sizeof(c)); +} + +static void watch_callback(AvahiWatch *w, int fd, AvahiWatchEvent event, void *userdata) { + char c; + ssize_t l; + struct runtime_data *r = userdata; + + ap_assert(w); + ap_assert(fd == sigterm_pipe_fds[0]); + ap_assert(event == AVAHI_WATCH_IN); + ap_assert(r); + + l = read(fd, &c, sizeof(c)); + ap_assert(l == sizeof(c)); + + avahi_simple_poll_quit(r->simple_poll); +} + +static void child_process(apr_pool_t *p, server_rec *server, struct global_config_data *d) { + struct runtime_data r; + int error; + const AvahiPoll *api; + AvahiWatch *w; + + ap_assert(d); + + unixd_setup_child(); + + if (pipe(sigterm_pipe_fds) < 0) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r.main_server, "pipe() failed: %s", strerror(errno)); + goto quit; + } + + set_nonblock(sigterm_pipe_fds[0]); + set_nonblock(sigterm_pipe_fds[1]); + + apr_signal(SIGTERM, sigterm); + + r.main_server = server; + r.global_config_data = d; + r.client = NULL; + r.simple_poll = NULL; + r.services = NULL; + apr_pool_create(&r.pool, p); + +/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r.main_server, "Child process startup pid=%lu", (unsigned long) getpid()); */ + + assemble_services(&r); + + if (!r.services) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r.main_server, __FILE__": No services found to register"); + goto quit; + } + + if (!(r.simple_poll = avahi_simple_poll_new())) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r.main_server, "avahi_simple_poll_new() failed: %s", strerror(errno)); + goto quit; + } + + api = avahi_simple_poll_get(r.simple_poll); + w = api->watch_new(api, sigterm_pipe_fds[0], AVAHI_WATCH_IN, watch_callback, &r); + ap_assert(w); + + if (!(r.client = avahi_client_new(avahi_simple_poll_get(r.simple_poll), AVAHI_CLIENT_NO_FAIL, client_callback, &r, &error))) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r.main_server, "avahi_client_new() failed: %s", avahi_strerror(error)); + goto quit; + } + +/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r.main_server, "Child process running"); */ + + avahi_simple_poll_loop(r.simple_poll); + +quit: + + if (r.client) + avahi_client_free(r.client); + + if (r.simple_poll) + avahi_simple_poll_free(r.simple_poll); + + if (r.pool) + apr_pool_destroy(r.pool); + + if (sigterm_pipe_fds[0] >= 0) + close(sigterm_pipe_fds[0]); + + if (sigterm_pipe_fds[1] >= 0) + close(sigterm_pipe_fds[1]); + + sigterm_pipe_fds[0] = sigterm_pipe_fds[1] = -1; + +/* ap_log_error(APLOG_MARK, APLOG_ERR, 0, r.main_server, "Child process ending"); */ +} + +static int start_child_process(apr_pool_t *p, server_rec *server, struct global_config_data *d) { + apr_proc_t* proc; + apr_status_t status; + +/* ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, server, "Spawning child pid=%lu", (unsigned long) getpid()); */ + + proc = apr_palloc(p, sizeof(apr_proc_t)); + ap_assert(proc); + + switch (status = apr_proc_fork(proc, p)) { + + case APR_INCHILD: + child_process(p, server, d); + exit(1); + /* never reached */ + break; + + case APR_INPARENT: + apr_pool_note_subprocess(p, proc, APR_KILL_AFTER_TIMEOUT); +/* ap_log_error(APLOG_MARK, APLOG_NOTICE, status, server, "Child process %lu", (unsigned long) proc->pid); */ + + break; + + default: + ap_log_error(APLOG_MARK, APLOG_ERR, status, server, "apr_proc_fork() failed"); + return HTTP_INTERNAL_SERVER_ERROR; + } + + return OK; +} + +static int post_config( + apr_pool_t *pconf, + AVAHI_GCC_UNUSED apr_pool_t *plog, + AVAHI_GCC_UNUSED apr_pool_t *ptemp, + server_rec *s) { + + void *flag; + struct global_config_data *d = GET_CONFIG_DATA(s); + + /* All post_config hooks are called twice, we're only interested in the second call. */ + + apr_pool_userdata_get(&flag, MOD_DNSSD_USERDATA_KEY, s->process->pool); + if (!flag) { + apr_pool_userdata_set((void*) 1, MOD_DNSSD_USERDATA_KEY, apr_pool_cleanup_null, s->process->pool); + return OK; + } + + if (d->enabled) + return start_child_process(pconf, s, d); + + return OK; +} + +static void register_hooks(AVAHI_GCC_UNUSED apr_pool_t *p){ + ap_hook_post_config(post_config, NULL, NULL, APR_HOOK_LAST); +} + +static void *create_server_config(apr_pool_t *p, AVAHI_GCC_UNUSED server_rec *s) { + struct global_config_data *d; + + d = apr_palloc(p, sizeof(struct global_config_data)); + ap_assert(d); + + d->enabled = 0; + d->user_dir = 1; + d->vhost = 1; + + return d; +} + +static const char *cmd_dnssd_enable( + cmd_parms *cmd, + AVAHI_GCC_UNUSED void *mconfig, + int enable) { + + struct global_config_data *d = GET_CONFIG_DATA(cmd->server); + const char *err; + + if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) + return err; + + d->enabled = enable; + return NULL; +} + +static const char *cmd_dnssd_enable_user_dir( + cmd_parms *cmd, + AVAHI_GCC_UNUSED void *mconfig, + int enable) { + + struct global_config_data *d = GET_CONFIG_DATA(cmd->server); + const char *err; + + if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) + return err; + + d->user_dir = enable; + return NULL; +} + +static const char *cmd_dnssd_enable_vhost( + cmd_parms *cmd, + AVAHI_GCC_UNUSED void *mconfig, + int enable) { + + struct global_config_data *d = GET_CONFIG_DATA(cmd->server); + const char *err; + + if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) + return err; + + d->vhost = enable; + return NULL; +} + +static const char *cmd_dnssd_service_name( + cmd_parms *cmd, + AVAHI_GCC_UNUSED void *mconfig, + const char *value) { + + const char *err; + + if ((err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|NOT_IN_LIMIT))) + return err; + + if (!avahi_is_valid_service_name(value)) + return "Invalid service name"; + + return NULL; +} + +static const char *cmd_dnssd_service_type( + cmd_parms *cmd, + AVAHI_GCC_UNUSED void *mconfig, + const char *value) { + + const char *err; + + if ((err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|NOT_IN_LIMIT))) + return err; + + if (!avahi_is_valid_service_type_strict(value)) + return "Invalid service type"; + + return NULL; +} + +static const command_rec commands[] = { + + AP_INIT_FLAG( + "DNSSDEnable", + cmd_dnssd_enable, + NULL, + RSRC_CONF, + "Enable/disable DNS-SD registration entirely (default: no)"), + + AP_INIT_FLAG( + "DNSSDAutoRegisterUserDir", + cmd_dnssd_enable_user_dir, + NULL, + RSRC_CONF, + "Enable/disable DNS-SD registration of ~/public_html (default: yes)"), + + AP_INIT_FLAG( + "DNSSDAutoRegisterVHosts", + cmd_dnssd_enable_vhost, + NULL, + RSRC_CONF, + "Enable/disable DNS-SD registration of all virtual hosts (default: yes)"), + + AP_INIT_TAKE1( + "DNSSDServiceName", + cmd_dnssd_service_name, + NULL, + OR_OPTIONS, + "Set the DNS-SD service name"), + + AP_INIT_ITERATE( + "DNSSDServiceTypes", + cmd_dnssd_service_type, + NULL, + OR_OPTIONS, + "Set on or more DNS-SD service types"), + + { NULL } +}; + +module AP_MODULE_DECLARE_DATA dnssd_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + create_server_config, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + commands, /* table of config file commands */ + register_hooks /* register hooks */ +}; + -- cgit