1739 lines
53 KiB
Diff
1739 lines
53 KiB
Diff
|
Upstream-Status: Pending
|
||
|
|
||
|
--- upstream/aclocal.m4 1970-01-01 01:00:00.000000000 +0100
|
||
|
+++ lennart/aclocal.m4 2005-11-18 04:19:18.000000000 +0100
|
||
|
@@ -0,0 +1,171 @@
|
||
|
+# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
|
||
|
+
|
||
|
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||
|
+# 2005 Free Software Foundation, Inc.
|
||
|
+# This file is free software; the Free Software Foundation
|
||
|
+# gives unlimited permission to copy and/or distribute it,
|
||
|
+# with or without modifications, as long as this notice is preserved.
|
||
|
+
|
||
|
+# This program is distributed in the hope that it will be useful,
|
||
|
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||
|
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||
|
+# PARTICULAR PURPOSE.
|
||
|
+
|
||
|
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||
|
+#
|
||
|
+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||
|
+#
|
||
|
+# This program is free software; you can redistribute it and/or modify
|
||
|
+# it under the terms of the GNU General Public License as published by
|
||
|
+# the Free Software Foundation; either version 2 of the License, or
|
||
|
+# (at your option) any later version.
|
||
|
+#
|
||
|
+# This program 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
|
||
|
+# General Public License for more details.
|
||
|
+#
|
||
|
+# You should have received a copy of the GNU General Public License
|
||
|
+# along with this program; if not, write to the Free Software
|
||
|
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
+#
|
||
|
+# As a special exception to the GNU General Public License, if you
|
||
|
+# distribute this file as part of a program that contains a
|
||
|
+# configuration script generated by Autoconf, you may include it under
|
||
|
+# the same distribution terms that you use for the rest of that program.
|
||
|
+
|
||
|
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||
|
+# ----------------------------------
|
||
|
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
|
||
|
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
|
||
|
+m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
|
||
|
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
|
||
|
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
|
||
|
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
|
||
|
+fi
|
||
|
+if test -n "$PKG_CONFIG"; then
|
||
|
+ _pkg_min_version=m4_default([$1], [0.9.0])
|
||
|
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
|
||
|
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
|
||
|
+ AC_MSG_RESULT([yes])
|
||
|
+ else
|
||
|
+ AC_MSG_RESULT([no])
|
||
|
+ PKG_CONFIG=""
|
||
|
+ fi
|
||
|
+
|
||
|
+fi[]dnl
|
||
|
+])# PKG_PROG_PKG_CONFIG
|
||
|
+
|
||
|
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||
|
+#
|
||
|
+# Check to see whether a particular set of modules exists. Similar
|
||
|
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||
|
+#
|
||
|
+#
|
||
|
+# Similar to PKG_CHECK_MODULES, make sure that the first instance of
|
||
|
+# this or PKG_CHECK_MODULES is called, or make sure to call
|
||
|
+# PKG_CHECK_EXISTS manually
|
||
|
+# --------------------------------------------------------------
|
||
|
+AC_DEFUN([PKG_CHECK_EXISTS],
|
||
|
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||
|
+if test -n "$PKG_CONFIG" && \
|
||
|
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
|
||
|
+ m4_ifval([$2], [$2], [:])
|
||
|
+m4_ifvaln([$3], [else
|
||
|
+ $3])dnl
|
||
|
+fi])
|
||
|
+
|
||
|
+
|
||
|
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||
|
+# ---------------------------------------------
|
||
|
+m4_define([_PKG_CONFIG],
|
||
|
+[if test -n "$PKG_CONFIG"; then
|
||
|
+ if test -n "$$1"; then
|
||
|
+ pkg_cv_[]$1="$$1"
|
||
|
+ else
|
||
|
+ PKG_CHECK_EXISTS([$3],
|
||
|
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
|
||
|
+ [pkg_failed=yes])
|
||
|
+ fi
|
||
|
+else
|
||
|
+ pkg_failed=untried
|
||
|
+fi[]dnl
|
||
|
+])# _PKG_CONFIG
|
||
|
+
|
||
|
+# _PKG_SHORT_ERRORS_SUPPORTED
|
||
|
+# -----------------------------
|
||
|
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
|
||
|
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||
|
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||
|
+ _pkg_short_errors_supported=yes
|
||
|
+else
|
||
|
+ _pkg_short_errors_supported=no
|
||
|
+fi[]dnl
|
||
|
+])# _PKG_SHORT_ERRORS_SUPPORTED
|
||
|
+
|
||
|
+
|
||
|
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||
|
+# [ACTION-IF-NOT-FOUND])
|
||
|
+#
|
||
|
+#
|
||
|
+# Note that if there is a possibility the first call to
|
||
|
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||
|
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||
|
+#
|
||
|
+#
|
||
|
+# --------------------------------------------------------------
|
||
|
+AC_DEFUN([PKG_CHECK_MODULES],
|
||
|
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||
|
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
|
||
|
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
|
||
|
+
|
||
|
+pkg_failed=no
|
||
|
+AC_MSG_CHECKING([for $1])
|
||
|
+
|
||
|
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
|
||
|
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
|
||
|
+
|
||
|
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
|
||
|
+and $1[]_LIBS to avoid the need to call pkg-config.
|
||
|
+See the pkg-config man page for more details.])
|
||
|
+
|
||
|
+if test $pkg_failed = yes; then
|
||
|
+ _PKG_SHORT_ERRORS_SUPPORTED
|
||
|
+ if test $_pkg_short_errors_supported = yes; then
|
||
|
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
|
||
|
+ else
|
||
|
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
|
||
|
+ fi
|
||
|
+ # Put the nasty error message in config.log where it belongs
|
||
|
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
|
||
|
+
|
||
|
+ ifelse([$4], , [AC_MSG_ERROR(dnl
|
||
|
+[Package requirements ($2) were not met:
|
||
|
+
|
||
|
+$$1_PKG_ERRORS
|
||
|
+
|
||
|
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
|
||
|
+installed software in a non-standard prefix.
|
||
|
+
|
||
|
+_PKG_TEXT
|
||
|
+])],
|
||
|
+ [$4])
|
||
|
+elif test $pkg_failed = untried; then
|
||
|
+ ifelse([$4], , [AC_MSG_FAILURE(dnl
|
||
|
+[The pkg-config script could not be found or is too old. Make sure it
|
||
|
+is in your PATH or set the PKG_CONFIG environment variable to the full
|
||
|
+path to pkg-config.
|
||
|
+
|
||
|
+_PKG_TEXT
|
||
|
+
|
||
|
+To get pkg-config, see <http://www.freedesktop.org/software/pkgconfig>.])],
|
||
|
+ [$4])
|
||
|
+else
|
||
|
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
|
||
|
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
|
||
|
+ AC_MSG_RESULT([yes])
|
||
|
+ ifelse([$3], , :, [$3])
|
||
|
+fi[]dnl
|
||
|
+])# PKG_CHECK_MODULES
|
||
|
+
|
||
|
+m4_include([acinclude.m4])
|
||
|
--- upstream/Makefile.in 2005-11-18 16:15:40.000000000 +0100
|
||
|
+++ lennart/Makefile.in 2005-11-18 01:14:43.000000000 +0100
|
||
|
@@ -171,6 +171,7 @@
|
||
|
src/ssh.o src/state.o src/strip.o \
|
||
|
src/timefile.o src/traceenv.o \
|
||
|
src/where.o \
|
||
|
+ @ZEROCONF_DISTCC_OBJS@ \
|
||
|
$(common_obj)
|
||
|
|
||
|
distccd_obj = src/access.o \
|
||
|
@@ -178,6 +179,7 @@
|
||
|
src/ncpus.o \
|
||
|
src/prefork.o \
|
||
|
src/serve.o src/setuid.o src/srvnet.o src/srvrpc.o src/state.o \
|
||
|
+ @ZEROCONF_DISTCCD_OBJS@ \
|
||
|
$(common_obj) @BUILD_POPT@
|
||
|
|
||
|
# Objects that need to be linked in to build monitors
|
||
|
--- upstream/src/distcc.c 2005-11-18 16:15:40.000000000 +0100
|
||
|
+++ lennart/src/distcc.c 2005-11-18 01:14:43.000000000 +0100
|
||
|
@@ -83,6 +83,9 @@
|
||
|
" COMPILER defaults to \"cc\"\n"
|
||
|
" --help explain usage and exit\n"
|
||
|
" --version show version and exit\n"
|
||
|
+" --show-hosts show host list and exit\n"
|
||
|
+" -j calculate the concurrency level from\n"
|
||
|
+" the host list.\n"
|
||
|
"\n"
|
||
|
"Environment variables:\n"
|
||
|
" See the manual page for a complete list.\n"
|
||
|
@@ -135,7 +138,46 @@
|
||
|
signal(SIGHUP, &dcc_client_signalled);
|
||
|
}
|
||
|
|
||
|
+static void dcc_free_hostlist(struct dcc_hostdef *list) {
|
||
|
+ while (list) {
|
||
|
+ struct dcc_hostdef *l = list;
|
||
|
+ list = list->next;
|
||
|
+ dcc_free_hostdef(l);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void dcc_show_hosts(void) {
|
||
|
+ struct dcc_hostdef *list, *l;
|
||
|
+ int nhosts;
|
||
|
+
|
||
|
+ if (dcc_get_hostlist(&list, &nhosts) != 0) {
|
||
|
+ rs_log_crit("Failed to get host list");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (l = list; l; l = l->next)
|
||
|
+ printf("%s\n", l->hostdef_string);
|
||
|
+
|
||
|
+ dcc_free_hostlist(list);
|
||
|
+}
|
||
|
+
|
||
|
+static void dcc_concurrency_level(void) {
|
||
|
+ struct dcc_hostdef *list, *l;
|
||
|
+ int nhosts;
|
||
|
+ int nslots = 0;
|
||
|
+
|
||
|
+ if (dcc_get_hostlist(&list, &nhosts) != 0) {
|
||
|
+ rs_log_crit("Failed to get host list");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (l = list; l; l = l->next)
|
||
|
+ nslots += l->n_slots;
|
||
|
|
||
|
+ dcc_free_hostlist(list);
|
||
|
+
|
||
|
+ printf("%i\n", nslots);
|
||
|
+}
|
||
|
|
||
|
/**
|
||
|
* distcc client entry point.
|
||
|
@@ -182,6 +224,18 @@
|
||
|
ret = 0;
|
||
|
goto out;
|
||
|
}
|
||
|
+
|
||
|
+ if (!strcmp(argv[1], "--show-hosts")) {
|
||
|
+ dcc_show_hosts();
|
||
|
+ ret = 0;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!strcmp(argv[1], "-j")) {
|
||
|
+ dcc_concurrency_level();
|
||
|
+ ret = 0;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
|
||
|
dcc_find_compiler(argv, &compiler_args);
|
||
|
/* compiler_args is now respectively either "cc -c hello.c" or
|
||
|
--- upstream/src/distcc.h 2005-11-18 16:15:40.000000000 +0100
|
||
|
+++ lennart/src/distcc.h 2005-11-18 01:14:43.000000000 +0100
|
||
|
@@ -112,7 +112,7 @@
|
||
|
int *ret_nhosts);
|
||
|
int dcc_parse_hosts(const char *where, const char *source_name,
|
||
|
struct dcc_hostdef **ret_list,
|
||
|
- int *ret_nhosts);
|
||
|
+ int *ret_nhosts, struct dcc_hostdef **ret_prev);
|
||
|
|
||
|
/* ncpu.c */
|
||
|
int dcc_ncpus(int *);
|
||
|
@@ -226,6 +226,7 @@
|
||
|
int dcc_make_tmpnam(const char *, const char *suffix, char **);
|
||
|
|
||
|
int dcc_mkdir(const char *path) WARN_UNUSED;
|
||
|
+int dcc_get_subdir(const char *name, char **path_ret) WARN_UNUSED;
|
||
|
int dcc_get_lock_dir(char **path_ret) WARN_UNUSED;
|
||
|
int dcc_get_state_dir(char **path_ret) WARN_UNUSED;
|
||
|
int dcc_get_top_dir(char **path_ret) WARN_UNUSED;
|
||
|
--- upstream/src/dopt.c 2005-11-18 16:15:40.000000000 +0100
|
||
|
+++ lennart/src/dopt.c 2005-11-18 04:14:26.000000000 +0100
|
||
|
@@ -93,6 +93,10 @@
|
||
|
opt_log_level
|
||
|
};
|
||
|
|
||
|
+#ifdef HAVE_AVAHI
|
||
|
+/* Flag for enabling/disabling Zeroconf using Avahi */
|
||
|
+int opt_zeroconf = 0;
|
||
|
+#endif
|
||
|
|
||
|
const struct poptOption options[] = {
|
||
|
{ "allow", 'a', POPT_ARG_STRING, 0, 'a', 0, 0 },
|
||
|
@@ -115,6 +119,9 @@
|
||
|
{ "verbose", 0, POPT_ARG_NONE, 0, 'v', 0, 0 },
|
||
|
{ "version", 0, POPT_ARG_NONE, 0, 'V', 0, 0 },
|
||
|
{ "wizard", 'W', POPT_ARG_NONE, 0, 'W', 0, 0 },
|
||
|
+#ifdef HAVE_AVAHI
|
||
|
+ { "zeroconf", 0, POPT_ARG_NONE, &opt_zeroconf, 0, 0, 0 },
|
||
|
+#endif
|
||
|
{ 0, 0, 0, 0, 0, 0, 0 }
|
||
|
};
|
||
|
|
||
|
@@ -137,6 +144,9 @@
|
||
|
" -p, --port PORT TCP port to listen on\n"
|
||
|
" --listen ADDRESS IP address to listen on\n"
|
||
|
" -a, --allow IP[/BITS] client address access control\n"
|
||
|
+#ifdef HAVE_AVAHI
|
||
|
+" --zeroconf register via mDNS/DNS-SD\n"
|
||
|
+#endif
|
||
|
" Debug and trace:\n"
|
||
|
" --log-level=LEVEL set detail level for log file\n"
|
||
|
" levels: critical, error, warning, notice, info, debug\n"
|
||
|
--- upstream/src/dopt.h 2005-11-18 16:15:40.000000000 +0100
|
||
|
+++ lennart/src/dopt.h 2005-11-18 02:27:45.000000000 +0100
|
||
|
@@ -38,3 +38,7 @@
|
||
|
extern int opt_lifetime;
|
||
|
extern char *opt_listen_addr;
|
||
|
extern int opt_niceness;
|
||
|
+
|
||
|
+#ifdef HAVE_AVAHI
|
||
|
+extern int opt_zeroconf;
|
||
|
+#endif
|
||
|
--- upstream/src/dparent.c 2005-11-18 16:15:40.000000000 +0100
|
||
|
+++ lennart/src/dparent.c 2005-11-18 04:13:23.000000000 +0100
|
||
|
@@ -70,6 +70,7 @@
|
||
|
#include "types.h"
|
||
|
#include "daemon.h"
|
||
|
#include "netutil.h"
|
||
|
+#include "zeroconf.h"
|
||
|
|
||
|
static void dcc_nofork_parent(int listen_fd) NORETURN;
|
||
|
static void dcc_detach(void);
|
||
|
@@ -94,6 +95,9 @@
|
||
|
int listen_fd;
|
||
|
int n_cpus;
|
||
|
int ret;
|
||
|
+#ifdef HAVE_AVAHI
|
||
|
+ void *avahi = NULL;
|
||
|
+#endif
|
||
|
|
||
|
if ((ret = dcc_socket_listen(arg_port, &listen_fd, opt_listen_addr)) != 0)
|
||
|
return ret;
|
||
|
@@ -131,6 +135,14 @@
|
||
|
/* Don't catch signals until we've detached or created a process group. */
|
||
|
dcc_daemon_catch_signals();
|
||
|
|
||
|
+#ifdef HAVE_AVAHI
|
||
|
+ /* Zeroconf registration */
|
||
|
+ if (opt_zeroconf) {
|
||
|
+ if (!(avahi = dcc_zeroconf_register((uint16_t) arg_port, n_cpus)))
|
||
|
+ return EXIT_CONNECT_FAILED;
|
||
|
+ }
|
||
|
+#endif
|
||
|
+
|
||
|
/* This is called in the master daemon, whether that is detached or
|
||
|
* not. */
|
||
|
dcc_master_pid = getpid();
|
||
|
@@ -138,10 +150,21 @@
|
||
|
if (opt_no_fork) {
|
||
|
dcc_log_daemon_started("non-forking daemon");
|
||
|
dcc_nofork_parent(listen_fd);
|
||
|
+ ret = 0;
|
||
|
} else {
|
||
|
dcc_log_daemon_started("preforking daemon");
|
||
|
- return dcc_preforking_parent(listen_fd);
|
||
|
+ ret = dcc_preforking_parent(listen_fd);
|
||
|
}
|
||
|
+
|
||
|
+#ifdef HAVE_AVAHI
|
||
|
+ /* Remove zeroconf registration */
|
||
|
+ if (opt_zeroconf) {
|
||
|
+ if (dcc_zeroconf_unregister(avahi) != 0)
|
||
|
+ return EXIT_CONNECT_FAILED;
|
||
|
+ }
|
||
|
+#endif
|
||
|
+
|
||
|
+ return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
--- upstream/src/help.c 2005-11-18 16:15:40.000000000 +0100
|
||
|
+++ lennart/src/help.c 2005-11-18 02:27:45.000000000 +0100
|
||
|
@@ -62,6 +62,9 @@
|
||
|
"distcc comes with ABSOLUTELY NO WARRANTY. distcc is free software, and\n"
|
||
|
"you may use, modify and redistribute it under the terms of the GNU \n"
|
||
|
"General Public License version 2 or later.\n"
|
||
|
+#ifdef HAVE_AVAHI
|
||
|
+"\nBuilt with Zeroconf support.\n"
|
||
|
+#endif
|
||
|
"\n"
|
||
|
,
|
||
|
prog, PACKAGE_VERSION, GNU_HOST, DISTCC_DEFAULT_PORT,
|
||
|
--- upstream/src/hostfile.c 2005-11-18 16:15:40.000000000 +0100
|
||
|
+++ lennart/src/hostfile.c 2005-11-18 01:14:43.000000000 +0100
|
||
|
@@ -59,7 +59,7 @@
|
||
|
if ((ret = dcc_load_file_string(fname, &body)) != 0)
|
||
|
return ret;
|
||
|
|
||
|
- ret = dcc_parse_hosts(body, fname, ret_list, ret_nhosts);
|
||
|
+ ret = dcc_parse_hosts(body, fname, ret_list, ret_nhosts, NULL);
|
||
|
|
||
|
free(body);
|
||
|
|
||
|
--- upstream/src/hosts.c 2005-11-18 16:15:40.000000000 +0100
|
||
|
+++ lennart/src/hosts.c 2005-11-18 02:27:45.000000000 +0100
|
||
|
@@ -96,6 +96,10 @@
|
||
|
#include "hosts.h"
|
||
|
#include "exitcode.h"
|
||
|
#include "snprintf.h"
|
||
|
+#ifdef HAVE_AVAHI
|
||
|
+#include "zeroconf.h"
|
||
|
+#define ZEROCONF_MAGIC "+zeroconf"
|
||
|
+#endif
|
||
|
|
||
|
const int dcc_default_port = DISTCC_DEFAULT_PORT;
|
||
|
|
||
|
@@ -134,9 +138,12 @@
|
||
|
char *path, *top;
|
||
|
int ret;
|
||
|
|
||
|
+ *ret_list = NULL;
|
||
|
+ *ret_nhosts = 0;
|
||
|
+
|
||
|
if ((env = getenv("DISTCC_HOSTS")) != NULL) {
|
||
|
rs_trace("read hosts from environment");
|
||
|
- return dcc_parse_hosts(env, "$DISTCC_HOSTS", ret_list, ret_nhosts);
|
||
|
+ return dcc_parse_hosts(env, "$DISTCC_HOSTS", ret_list, ret_nhosts, NULL);
|
||
|
}
|
||
|
|
||
|
/* $DISTCC_DIR or ~/.distcc */
|
||
|
@@ -163,7 +170,7 @@
|
||
|
rs_trace("not reading %s: %s", path, strerror(errno));
|
||
|
free(path);
|
||
|
}
|
||
|
-
|
||
|
+
|
||
|
/* FIXME: Clearer message? */
|
||
|
rs_log_warning("no hostlist is set; can't distribute work");
|
||
|
|
||
|
@@ -346,17 +353,19 @@
|
||
|
**/
|
||
|
int dcc_parse_hosts(const char *where, const char *source_name,
|
||
|
struct dcc_hostdef **ret_list,
|
||
|
- int *ret_nhosts)
|
||
|
+ int *ret_nhosts, struct dcc_hostdef **ret_prev)
|
||
|
{
|
||
|
int ret;
|
||
|
- struct dcc_hostdef *prev, *curr;
|
||
|
+ struct dcc_hostdef *curr, *_prev;
|
||
|
+
|
||
|
+ if (!ret_prev) {
|
||
|
+ ret_prev = &_prev;
|
||
|
+ _prev = NULL;
|
||
|
+ }
|
||
|
|
||
|
/* TODO: Check for '/' in places where it might cause trouble with
|
||
|
* a lock file name. */
|
||
|
|
||
|
- prev = NULL;
|
||
|
- *ret_list = NULL;
|
||
|
- *ret_nhosts = 0;
|
||
|
/* A simple, hardcoded scanner. Some of the GNU routines might be
|
||
|
* useful here, but they won't work on less capable systems.
|
||
|
*
|
||
|
@@ -390,6 +399,15 @@
|
||
|
token_start = where;
|
||
|
token_len = strcspn(where, " #\t\n\f\r");
|
||
|
|
||
|
+#ifdef HAVE_AVAHI
|
||
|
+ if (token_len == sizeof(ZEROCONF_MAGIC)-1 &&
|
||
|
+ !strncmp(token_start, ZEROCONF_MAGIC, (unsigned) token_len)) {
|
||
|
+ if ((ret = dcc_zeroconf_add_hosts(ret_list, ret_nhosts, 4, ret_prev) != 0))
|
||
|
+ return ret;
|
||
|
+ goto skip;
|
||
|
+ }
|
||
|
+#endif
|
||
|
+
|
||
|
/* Allocate new list item */
|
||
|
curr = calloc(1, sizeof(struct dcc_hostdef));
|
||
|
if (!curr) {
|
||
|
@@ -404,8 +422,8 @@
|
||
|
}
|
||
|
|
||
|
/* Link into list */
|
||
|
- if (prev) {
|
||
|
- prev->next = curr;
|
||
|
+ if (*ret_prev) {
|
||
|
+ (*ret_prev)->next = curr;
|
||
|
} else {
|
||
|
*ret_list = curr; /* first */
|
||
|
}
|
||
|
@@ -434,10 +452,15 @@
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+ (*ret_nhosts)++;
|
||
|
+ *ret_prev = curr;
|
||
|
+
|
||
|
+#ifdef HAVE_AVAHI
|
||
|
+ skip:
|
||
|
+#endif
|
||
|
+
|
||
|
/* continue to next token if any */
|
||
|
where = token_start + token_len;
|
||
|
- prev = curr;
|
||
|
- (*ret_nhosts)++;
|
||
|
}
|
||
|
|
||
|
if (*ret_nhosts) {
|
||
|
--- upstream/src/io.c 2005-11-18 16:15:40.000000000 +0100
|
||
|
+++ lennart/src/io.c 2005-11-18 01:14:43.000000000 +0100
|
||
|
@@ -163,7 +163,7 @@
|
||
|
return ret;
|
||
|
else
|
||
|
continue;
|
||
|
- } else if (r == -1 && errno == EAGAIN) {
|
||
|
+ } else if (r == -1 && errno == EINTR) {
|
||
|
continue;
|
||
|
} else if (r == -1) {
|
||
|
rs_log_error("failed to read: %s", strerror(errno));
|
||
|
@@ -205,9 +205,6 @@
|
||
|
} else if (r == -1) {
|
||
|
rs_log_error("failed to write: %s", strerror(errno));
|
||
|
return EXIT_IO_ERROR;
|
||
|
- } else if (r == 0) {
|
||
|
- rs_log_error("unexpected eof on fd%d", fd);
|
||
|
- return EXIT_TRUNCATED;
|
||
|
} else {
|
||
|
buf = &((char *) buf)[r];
|
||
|
len -= r;
|
||
|
--- upstream/src/tempfile.c 2005-11-18 16:15:40.000000000 +0100
|
||
|
+++ lennart/src/tempfile.c 2005-11-18 01:14:43.000000000 +0100
|
||
|
@@ -161,7 +161,7 @@
|
||
|
* Return a subdirectory of the DISTCC_DIR of the given name, making
|
||
|
* sure that the directory exists.
|
||
|
**/
|
||
|
-static int dcc_get_subdir(const char *name,
|
||
|
+int dcc_get_subdir(const char *name,
|
||
|
char **dir_ret)
|
||
|
{
|
||
|
int ret;
|
||
|
--- upstream/configure.ac 2005-11-18 16:15:40.000000000 +0100
|
||
|
+++ lennart/configure.ac 2005-11-18 04:18:07.000000000 +0100
|
||
|
@@ -388,6 +388,23 @@
|
||
|
AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1, [define if you have struct sockaddr_storage]),,
|
||
|
[#include <sys/socket.h>])
|
||
|
|
||
|
+dnl check for avahi
|
||
|
+PKG_CHECK_MODULES(AVAHI, [avahi-client >= 0.6],
|
||
|
+[AC_DEFINE(HAVE_AVAHI, 1, [defined if Avahi is available])
|
||
|
+CFLAGS="$CFLAGS $AVAHI_CFLAGS"
|
||
|
+LIBS="$LIBS $AVAHI_LIBS"
|
||
|
+ZEROCONF_DISTCC_OBJS="src/zeroconf.o"
|
||
|
+ZEROCONF_DISTCCD_OBJS="src/zeroconf-reg.o"],
|
||
|
+[ZEROCONF_DISTCC_OBJS=""
|
||
|
+ZEROCONF_DISTCCD_OBJS=""])
|
||
|
+AC_SUBST(ZEROCONF_DISTCC_OBJS)
|
||
|
+AC_SUBST(ZEROCONF_DISTCCD_OBJS)
|
||
|
+
|
||
|
+ACX_PTHREAD
|
||
|
+LIBS="$PTHREAD_LIBS $LIBS"
|
||
|
+CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||
|
+CC="$PTHREAD_CC"
|
||
|
+
|
||
|
dnl ##### Output
|
||
|
AC_SUBST(docdir)
|
||
|
AC_SUBST(CFLAGS)
|
||
|
--- upstream/acinclude.m4 1970-01-01 01:00:00.000000000 +0100
|
||
|
+++ lennart/acinclude.m4 2005-11-18 04:17:08.000000000 +0100
|
||
|
@@ -0,0 +1,235 @@
|
||
|
+dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||
|
+dnl
|
||
|
+dnl This macro figures out how to build C programs using POSIX threads.
|
||
|
+dnl It sets the PTHREAD_LIBS output variable to the threads library and
|
||
|
+dnl linker flags, and the PTHREAD_CFLAGS output variable to any special
|
||
|
+dnl C compiler flags that are needed. (The user can also force certain
|
||
|
+dnl compiler flags/libs to be tested by setting these environment
|
||
|
+dnl variables.)
|
||
|
+dnl
|
||
|
+dnl Also sets PTHREAD_CC to any special C compiler that is needed for
|
||
|
+dnl multi-threaded programs (defaults to the value of CC otherwise).
|
||
|
+dnl (This is necessary on AIX to use the special cc_r compiler alias.)
|
||
|
+dnl
|
||
|
+dnl NOTE: You are assumed to not only compile your program with these
|
||
|
+dnl flags, but also link it with them as well. e.g. you should link
|
||
|
+dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
|
||
|
+dnl $LIBS
|
||
|
+dnl
|
||
|
+dnl If you are only building threads programs, you may wish to use
|
||
|
+dnl these variables in your default LIBS, CFLAGS, and CC:
|
||
|
+dnl
|
||
|
+dnl LIBS="$PTHREAD_LIBS $LIBS"
|
||
|
+dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||
|
+dnl CC="$PTHREAD_CC"
|
||
|
+dnl
|
||
|
+dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
|
||
|
+dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
|
||
|
+dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||
|
+dnl
|
||
|
+dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
|
||
|
+dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to
|
||
|
+dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the
|
||
|
+dnl default action will define HAVE_PTHREAD.
|
||
|
+dnl
|
||
|
+dnl Please let the authors know if this macro fails on any platform, or
|
||
|
+dnl if you have any other suggestions or comments. This macro was based
|
||
|
+dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with
|
||
|
+dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros
|
||
|
+dnl posted by Alejandro Forero Cuervo to the autoconf macro repository.
|
||
|
+dnl We are also grateful for the helpful feedback of numerous users.
|
||
|
+dnl
|
||
|
+dnl @category InstalledPackages
|
||
|
+dnl @author Steven G. Johnson <stevenj@alum.mit.edu>
|
||
|
+dnl @version 2005-01-14
|
||
|
+dnl @license GPLWithACException
|
||
|
+
|
||
|
+AC_DEFUN([ACX_PTHREAD], [
|
||
|
+AC_REQUIRE([AC_CANONICAL_HOST])
|
||
|
+AC_LANG_SAVE
|
||
|
+AC_LANG_C
|
||
|
+acx_pthread_ok=no
|
||
|
+
|
||
|
+# We used to check for pthread.h first, but this fails if pthread.h
|
||
|
+# requires special compiler flags (e.g. on True64 or Sequent).
|
||
|
+# It gets checked for in the link test anyway.
|
||
|
+
|
||
|
+# First of all, check if the user has set any of the PTHREAD_LIBS,
|
||
|
+# etcetera environment variables, and if threads linking works using
|
||
|
+# them:
|
||
|
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
|
||
|
+ save_CFLAGS="$CFLAGS"
|
||
|
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||
|
+ save_LIBS="$LIBS"
|
||
|
+ LIBS="$PTHREAD_LIBS $LIBS"
|
||
|
+ AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
|
||
|
+ AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
|
||
|
+ AC_MSG_RESULT($acx_pthread_ok)
|
||
|
+ if test x"$acx_pthread_ok" = xno; then
|
||
|
+ PTHREAD_LIBS=""
|
||
|
+ PTHREAD_CFLAGS=""
|
||
|
+ fi
|
||
|
+ LIBS="$save_LIBS"
|
||
|
+ CFLAGS="$save_CFLAGS"
|
||
|
+fi
|
||
|
+
|
||
|
+# We must check for the threads library under a number of different
|
||
|
+# names; the ordering is very important because some systems
|
||
|
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
||
|
+# libraries is broken (non-POSIX).
|
||
|
+
|
||
|
+# Create a list of thread flags to try. Items starting with a "-" are
|
||
|
+# C compiler flags, and other items are library names, except for "none"
|
||
|
+# which indicates that we try without any flags at all, and "pthread-config"
|
||
|
+# which is a program returning the flags for the Pth emulation library.
|
||
|
+
|
||
|
+acx_pthread_flags="pthreads pthread none -Kthread -kthread lthread -pthread -pthreads -mthreads --thread-safe -mt pthread-config"
|
||
|
+
|
||
|
+# The ordering *is* (sometimes) important. Some notes on the
|
||
|
+# individual items follow:
|
||
|
+
|
||
|
+# pthreads: AIX (must check this before -lpthread)
|
||
|
+# none: in case threads are in libc; should be tried before -Kthread and
|
||
|
+# other compiler flags to prevent continual compiler warnings
|
||
|
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||
|
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||
|
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||
|
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
|
||
|
+# -pthreads: Solaris/gcc
|
||
|
+# -mthreads: Mingw32/gcc, Lynx/gcc
|
||
|
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||
|
+# doesn't hurt to check since this sometimes defines pthreads too;
|
||
|
+# also defines -D_REENTRANT)
|
||
|
+# pthread: Linux, etcetera
|
||
|
+# --thread-safe: KAI C++
|
||
|
+# pthread-config: use pthread-config program (for GNU Pth library)
|
||
|
+
|
||
|
+case "${host_cpu}-${host_os}" in
|
||
|
+ *solaris*)
|
||
|
+
|
||
|
+ # On Solaris (at least, for some versions), libc contains stubbed
|
||
|
+ # (non-functional) versions of the pthreads routines, so link-based
|
||
|
+ # tests will erroneously succeed. (We need to link with -pthread or
|
||
|
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||
|
+ # a function called by this macro, so we could check for that, but
|
||
|
+ # who knows whether they'll stub that too in a future libc.) So,
|
||
|
+ # we'll just look for -pthreads and -lpthread first:
|
||
|
+
|
||
|
+ acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"
|
||
|
+ ;;
|
||
|
+esac
|
||
|
+
|
||
|
+if test x"$acx_pthread_ok" = xno; then
|
||
|
+for flag in $acx_pthread_flags; do
|
||
|
+
|
||
|
+ case $flag in
|
||
|
+ none)
|
||
|
+ AC_MSG_CHECKING([whether pthreads work without any flags])
|
||
|
+ ;;
|
||
|
+
|
||
|
+ -*)
|
||
|
+ AC_MSG_CHECKING([whether pthreads work with $flag])
|
||
|
+ PTHREAD_CFLAGS="$flag"
|
||
|
+ ;;
|
||
|
+
|
||
|
+ pthread-config)
|
||
|
+ AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
|
||
|
+ if test x"$acx_pthread_config" = xno; then continue; fi
|
||
|
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
|
||
|
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||
|
+ ;;
|
||
|
+
|
||
|
+ *)
|
||
|
+ AC_MSG_CHECKING([for the pthreads library -l$flag])
|
||
|
+ PTHREAD_LIBS="-l$flag"
|
||
|
+ ;;
|
||
|
+ esac
|
||
|
+
|
||
|
+ save_LIBS="$LIBS"
|
||
|
+ save_CFLAGS="$CFLAGS"
|
||
|
+ LIBS="$PTHREAD_LIBS $LIBS"
|
||
|
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||
|
+
|
||
|
+ # Check for various functions. We must include pthread.h,
|
||
|
+ # since some functions may be macros. (On the Sequent, we
|
||
|
+ # need a special flag -Kthread to make this header compile.)
|
||
|
+ # We check for pthread_join because it is in -lpthread on IRIX
|
||
|
+ # while pthread_create is in libc. We check for pthread_attr_init
|
||
|
+ # due to DEC craziness with -lpthreads. We check for
|
||
|
+ # pthread_cleanup_push because it is one of the few pthread
|
||
|
+ # functions on Solaris that doesn't have a non-functional libc stub.
|
||
|
+ # We try pthread_create on general principles.
|
||
|
+ AC_TRY_LINK([#include <pthread.h>],
|
||
|
+ [pthread_t th; pthread_join(th, 0);
|
||
|
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
|
||
|
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
|
||
|
+ [acx_pthread_ok=yes])
|
||
|
+
|
||
|
+ LIBS="$save_LIBS"
|
||
|
+ CFLAGS="$save_CFLAGS"
|
||
|
+
|
||
|
+ AC_MSG_RESULT($acx_pthread_ok)
|
||
|
+ if test "x$acx_pthread_ok" = xyes; then
|
||
|
+ break;
|
||
|
+ fi
|
||
|
+
|
||
|
+ PTHREAD_LIBS=""
|
||
|
+ PTHREAD_CFLAGS=""
|
||
|
+done
|
||
|
+fi
|
||
|
+
|
||
|
+# Various other checks:
|
||
|
+if test "x$acx_pthread_ok" = xyes; then
|
||
|
+ save_LIBS="$LIBS"
|
||
|
+ LIBS="$PTHREAD_LIBS $LIBS"
|
||
|
+ save_CFLAGS="$CFLAGS"
|
||
|
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||
|
+
|
||
|
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
||
|
+ AC_MSG_CHECKING([for joinable pthread attribute])
|
||
|
+ attr_name=unknown
|
||
|
+ for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||
|
+ AC_TRY_LINK([#include <pthread.h>], [int attr=$attr;],
|
||
|
+ [attr_name=$attr; break])
|
||
|
+ done
|
||
|
+ AC_MSG_RESULT($attr_name)
|
||
|
+ if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
|
||
|
+ AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
|
||
|
+ [Define to necessary symbol if this constant
|
||
|
+ uses a non-standard name on your system.])
|
||
|
+ fi
|
||
|
+
|
||
|
+ AC_MSG_CHECKING([if more special flags are required for pthreads])
|
||
|
+ flag=no
|
||
|
+ case "${host_cpu}-${host_os}" in
|
||
|
+ *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
|
||
|
+ *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
|
||
|
+ esac
|
||
|
+ AC_MSG_RESULT(${flag})
|
||
|
+ if test "x$flag" != xno; then
|
||
|
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
|
||
|
+ fi
|
||
|
+
|
||
|
+ LIBS="$save_LIBS"
|
||
|
+ CFLAGS="$save_CFLAGS"
|
||
|
+
|
||
|
+ # More AIX lossage: must compile with cc_r
|
||
|
+ AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
|
||
|
+else
|
||
|
+ PTHREAD_CC="$CC"
|
||
|
+fi
|
||
|
+
|
||
|
+AC_SUBST(PTHREAD_LIBS)
|
||
|
+AC_SUBST(PTHREAD_CFLAGS)
|
||
|
+AC_SUBST(PTHREAD_CC)
|
||
|
+
|
||
|
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||
|
+if test x"$acx_pthread_ok" = xyes; then
|
||
|
+ ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
|
||
|
+ :
|
||
|
+else
|
||
|
+ acx_pthread_ok=no
|
||
|
+ $2
|
||
|
+fi
|
||
|
+AC_LANG_RESTORE
|
||
|
+])dnl ACX_PTHREAD
|
||
|
--- upstream/src/zeroconf.h 1970-01-01 01:00:00.000000000 +0100
|
||
|
+++ lennart/src/zeroconf.h 2005-11-18 04:06:29.000000000 +0100
|
||
|
@@ -0,0 +1,13 @@
|
||
|
+#ifndef foozeroconfhfoo
|
||
|
+#define foozeroconfhfoo
|
||
|
+
|
||
|
+#include <inttypes.h>
|
||
|
+
|
||
|
+int dcc_zeroconf_add_hosts(struct dcc_hostdef **re_list, int *ret_nhosts, int slots, struct dcc_hostdef **ret_prev);
|
||
|
+
|
||
|
+void * dcc_zeroconf_register(uint16_t port, int n_cpus);
|
||
|
+int dcc_zeroconf_unregister(void*);
|
||
|
+
|
||
|
+#define DCC_DNS_SERVICE_TYPE "_distcc._tcp"
|
||
|
+
|
||
|
+#endif
|
||
|
--- upstream/src/zeroconf.c 1970-01-01 01:00:00.000000000 +0100
|
||
|
+++ lennart/src/zeroconf.c 2005-11-18 15:51:45.000000000 +0100
|
||
|
@@ -0,0 +1,602 @@
|
||
|
+/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- */
|
||
|
+
|
||
|
+#include "config.h"
|
||
|
+
|
||
|
+#include <assert.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <sys/select.h>
|
||
|
+#include <signal.h>
|
||
|
+#include <sys/file.h>
|
||
|
+#include <sys/time.h>
|
||
|
+#include <time.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+#include <string.h>
|
||
|
+#include <errno.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <limits.h>
|
||
|
+
|
||
|
+#include <avahi-common/domain.h>
|
||
|
+#include <avahi-common/error.h>
|
||
|
+#include <avahi-common/malloc.h>
|
||
|
+#include <avahi-common/address.h>
|
||
|
+#include <avahi-common/simple-watch.h>
|
||
|
+#include <avahi-client/lookup.h>
|
||
|
+
|
||
|
+#include "distcc.h"
|
||
|
+#include "hosts.h"
|
||
|
+#include "zeroconf.h"
|
||
|
+#include "trace.h"
|
||
|
+#include "exitcode.h"
|
||
|
+
|
||
|
+/* How long shall the background daemon be idle before i terminates itself? */
|
||
|
+#define MAX_IDLE_TIME 20
|
||
|
+
|
||
|
+/* Maxium size of host file to load */
|
||
|
+#define MAX_FILE_SIZE (1024*100)
|
||
|
+
|
||
|
+/* General daemon data */
|
||
|
+struct daemon_data {
|
||
|
+ struct host *hosts;
|
||
|
+ int fd;
|
||
|
+ int n_slots;
|
||
|
+
|
||
|
+ AvahiClient *client;
|
||
|
+ AvahiServiceBrowser *browser;
|
||
|
+ AvahiSimplePoll *simple_poll;
|
||
|
+};
|
||
|
+
|
||
|
+/* Zeroconf service wrapper */
|
||
|
+struct host {
|
||
|
+ struct daemon_data *daemon_data;
|
||
|
+ struct host *next;
|
||
|
+
|
||
|
+ AvahiIfIndex interface;
|
||
|
+ AvahiProtocol protocol;
|
||
|
+ char *service;
|
||
|
+ char *domain;
|
||
|
+
|
||
|
+ AvahiAddress address;
|
||
|
+ uint16_t port;
|
||
|
+ int n_cpus;
|
||
|
+
|
||
|
+ AvahiServiceResolver *resolver;
|
||
|
+};
|
||
|
+
|
||
|
+/* A generic, system independant lock routine, similar to sys_lock,
|
||
|
+ * but more powerful:
|
||
|
+ * rw: if non-zero: r/w lock instead of r/o lock
|
||
|
+ * enable: lock or unlock
|
||
|
+ * block: block when locking */
|
||
|
+static int generic_lock(int fd, int rw, int enable, int block) {
|
||
|
+#if defined(F_SETLK)
|
||
|
+ struct flock lockparam;
|
||
|
+
|
||
|
+ lockparam.l_type = enable ? (rw ? F_WRLCK : F_RDLCK) : F_UNLCK;
|
||
|
+ lockparam.l_whence = SEEK_SET;
|
||
|
+ lockparam.l_start = 0;
|
||
|
+ lockparam.l_len = 0; /* whole file */
|
||
|
+
|
||
|
+ return fcntl(fd, block ? F_SETLKW : F_SETLK, &lockparam);
|
||
|
+#elif defined(HAVE_FLOCK)
|
||
|
+ return flock(fd, (enable ? (rw ? LOCK_EX : LOCK_SH) : LOCK_UN) | (block ? LOCK_NB : 0));
|
||
|
+#elif defined(HAVE_LOCKF)
|
||
|
+ return lockf(fd, (enable ? (block ? F_LOCK : F_TLOCK) : F_ULOCK));
|
||
|
+#else
|
||
|
+# error "No supported lock method. Please port this code."
|
||
|
+#endif
|
||
|
+}
|
||
|
+
|
||
|
+/* Return the number of seconds, when the specified file was last
|
||
|
+ * read. If the atime of that file is < clip_time, use clip_time
|
||
|
+ * instead */
|
||
|
+static time_t fd_last_used(int fd, time_t clip_time) {
|
||
|
+ struct stat st;
|
||
|
+ time_t now, ft;
|
||
|
+ assert(fd >= 0);
|
||
|
+
|
||
|
+ if (fstat(fd, &st) < 0) {
|
||
|
+ rs_log_crit("fstat() failed: %s\n", strerror(errno));
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ((now = time(NULL)) == (time_t) -1) {
|
||
|
+ rs_log_crit("time() failed: %s\n", strerror(errno));
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ ft = clip_time ? (st.st_atime < clip_time ? clip_time : st.st_atime) : st.st_atime;
|
||
|
+ assert(ft <= now);
|
||
|
+
|
||
|
+ return now - ft;
|
||
|
+}
|
||
|
+
|
||
|
+/* Write host data to host file */
|
||
|
+static int write_hosts(struct daemon_data *d) {
|
||
|
+ struct host *h;
|
||
|
+ int r = 0;
|
||
|
+ assert(d);
|
||
|
+
|
||
|
+ rs_log_info("writing zeroconf data.\n");
|
||
|
+
|
||
|
+ if (generic_lock(d->fd, 1, 1, 1) < 0) {
|
||
|
+ rs_log_crit("lock failed: %s\n", strerror(errno));
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (lseek(d->fd, 0, SEEK_SET) < 0) {
|
||
|
+ rs_log_crit("lseek() failed: %s\n", strerror(errno));
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (ftruncate(d->fd, 0) < 0) {
|
||
|
+ rs_log_crit("ftruncate() failed: %s\n", strerror(errno));
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (h = d->hosts; h; h = h->next) {
|
||
|
+ char t[256], a[AVAHI_ADDRESS_STR_MAX];
|
||
|
+
|
||
|
+ if (h->resolver)
|
||
|
+ /* Not yet fully resolved */
|
||
|
+ continue;
|
||
|
+
|
||
|
+ snprintf(t, sizeof(t), "%s:%u/%i\n", avahi_address_snprint(a, sizeof(a), &h->address), h->port, d->n_slots * h->n_cpus);
|
||
|
+
|
||
|
+ if (dcc_writex(d->fd, t, strlen(t)) != 0) {
|
||
|
+ rs_log_crit("write() failed: %s\n", strerror(errno));
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ r = 0;
|
||
|
+
|
||
|
+finish:
|
||
|
+
|
||
|
+ generic_lock(d->fd, 1, 0, 1);
|
||
|
+ return r;
|
||
|
+
|
||
|
+};
|
||
|
+
|
||
|
+/* Free host data */
|
||
|
+static void free_host(struct host *h) {
|
||
|
+ assert(h);
|
||
|
+
|
||
|
+ if (h->resolver)
|
||
|
+ avahi_service_resolver_free(h->resolver);
|
||
|
+
|
||
|
+ free(h->service);
|
||
|
+ free(h->domain);
|
||
|
+ free(h);
|
||
|
+}
|
||
|
+
|
||
|
+/* Remove a service from the host list */
|
||
|
+static void remove_service(struct daemon_data *d, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *domain) {
|
||
|
+ struct host *h, *p = NULL;
|
||
|
+ assert(d);
|
||
|
+
|
||
|
+ for (h = d->hosts; h; h = h->next) {
|
||
|
+ if (h->interface == interface &&
|
||
|
+ h->protocol == protocol &&
|
||
|
+ !strcmp(h->service, name) &&
|
||
|
+ avahi_domain_equal(h->domain, domain)) {
|
||
|
+
|
||
|
+ if (p)
|
||
|
+ p->next = h->next;
|
||
|
+ else
|
||
|
+ d->hosts = h->next;
|
||
|
+
|
||
|
+ free_host(h);
|
||
|
+
|
||
|
+ break;
|
||
|
+ } else
|
||
|
+ p = h;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/* Called when a resolve call completes */
|
||
|
+static void resolve_reply(AvahiServiceResolver *UNUSED(r),
|
||
|
+ AvahiIfIndex UNUSED(interface),
|
||
|
+ AvahiProtocol UNUSED(protocol),
|
||
|
+ AvahiResolverEvent event,
|
||
|
+ const char *name,
|
||
|
+ const char *UNUSED(type),
|
||
|
+ const char *UNUSED(domain),
|
||
|
+ const char *UNUSED(host_name),
|
||
|
+ const AvahiAddress *a,
|
||
|
+ uint16_t port,
|
||
|
+ AvahiStringList *txt,
|
||
|
+ AvahiLookupResultFlags UNUSED(flags),
|
||
|
+ void *userdata) {
|
||
|
+
|
||
|
+ struct host *h = userdata;
|
||
|
+
|
||
|
+ switch (event) {
|
||
|
+
|
||
|
+ case AVAHI_RESOLVER_FOUND: {
|
||
|
+ AvahiStringList *i;
|
||
|
+
|
||
|
+ /* Look for the number of CPUs in TXT RRs */
|
||
|
+ for (i = txt; i; i = i->next) {
|
||
|
+ char *key, *value;
|
||
|
+
|
||
|
+ if (avahi_string_list_get_pair(i, &key, &value, NULL) < 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (!strcmp(key, "cpus"))
|
||
|
+ if ((h->n_cpus = atoi(value)) <= 0)
|
||
|
+ h->n_cpus = 1;
|
||
|
+
|
||
|
+ avahi_free(key);
|
||
|
+ avahi_free(value);
|
||
|
+ }
|
||
|
+
|
||
|
+ h->address = *a;
|
||
|
+ h->port = port;
|
||
|
+
|
||
|
+ avahi_service_resolver_free(h->resolver);
|
||
|
+ h->resolver = NULL;
|
||
|
+
|
||
|
+ /* Write modified hosts file */
|
||
|
+ write_hosts(h->daemon_data);
|
||
|
+
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ case AVAHI_RESOLVER_FAILURE:
|
||
|
+
|
||
|
+ rs_log_warning("Failed to resolve service '%s': %s\n", name,
|
||
|
+ avahi_strerror(avahi_client_errno(h->daemon_data->client)));
|
||
|
+
|
||
|
+ free_host(h);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+/* Called whenever a new service is found or removed */
|
||
|
+static void browse_reply(AvahiServiceBrowser *UNUSED(b),
|
||
|
+ AvahiIfIndex interface,
|
||
|
+ AvahiProtocol protocol,
|
||
|
+ AvahiBrowserEvent event,
|
||
|
+ const char *name,
|
||
|
+ const char *type,
|
||
|
+ const char *domain,
|
||
|
+ AvahiLookupResultFlags UNUSED(flags),
|
||
|
+ void *userdata) {
|
||
|
+
|
||
|
+ struct daemon_data *d = userdata;
|
||
|
+ assert(d);
|
||
|
+
|
||
|
+ switch (event) {
|
||
|
+ case AVAHI_BROWSER_NEW: {
|
||
|
+ struct host *h;
|
||
|
+
|
||
|
+ h = malloc(sizeof(struct host));
|
||
|
+ assert(h);
|
||
|
+
|
||
|
+ rs_log_info("new service: %s\n", name);
|
||
|
+
|
||
|
+ if (!(h->resolver = avahi_service_resolver_new(d->client,
|
||
|
+ interface,
|
||
|
+ protocol,
|
||
|
+ name,
|
||
|
+ type,
|
||
|
+ domain,
|
||
|
+ AVAHI_PROTO_UNSPEC,
|
||
|
+ 0,
|
||
|
+ resolve_reply,
|
||
|
+ h))) {
|
||
|
+ rs_log_warning("Failed to create service resolver for '%s': %s\n", name,
|
||
|
+ avahi_strerror(avahi_client_errno(d->client)));
|
||
|
+
|
||
|
+ free(h);
|
||
|
+
|
||
|
+ } else {
|
||
|
+
|
||
|
+ /* Fill in missing data */
|
||
|
+ h->service = strdup(name);
|
||
|
+ assert(h->service);
|
||
|
+ h->domain = strdup(domain);
|
||
|
+ assert(h->domain);
|
||
|
+ h->daemon_data = d;
|
||
|
+ h->interface = interface;
|
||
|
+ h->protocol = protocol;
|
||
|
+ h->next = d->hosts;
|
||
|
+ h->n_cpus = 1;
|
||
|
+ d->hosts = h;
|
||
|
+ }
|
||
|
+
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ case AVAHI_BROWSER_REMOVE:
|
||
|
+
|
||
|
+ rs_log_info("Removed service: %s\n", name);
|
||
|
+
|
||
|
+ remove_service(d, interface, protocol, name, domain);
|
||
|
+ write_hosts(d);
|
||
|
+ break;
|
||
|
+
|
||
|
+ case AVAHI_BROWSER_FAILURE:
|
||
|
+ rs_log_crit("Service Browser failure '%s': %s\n", name,
|
||
|
+ avahi_strerror(avahi_client_errno(d->client)));
|
||
|
+
|
||
|
+ avahi_simple_poll_quit(d->simple_poll);
|
||
|
+ break;
|
||
|
+
|
||
|
+ case AVAHI_BROWSER_CACHE_EXHAUSTED:
|
||
|
+ case AVAHI_BROWSER_ALL_FOR_NOW:
|
||
|
+ ;
|
||
|
+
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void client_callback(AvahiClient *client, AvahiClientState state, void *userdata) {
|
||
|
+ struct daemon_data *d = userdata;
|
||
|
+
|
||
|
+ switch (state) {
|
||
|
+
|
||
|
+ case AVAHI_CLIENT_FAILURE:
|
||
|
+ rs_log_crit("Client failure: %s\n", avahi_strerror(avahi_client_errno(client)));
|
||
|
+ avahi_simple_poll_quit(d->simple_poll);
|
||
|
+ break;
|
||
|
+
|
||
|
+ case AVAHI_CLIENT_S_COLLISION:
|
||
|
+ case AVAHI_CLIENT_S_REGISTERING:
|
||
|
+ case AVAHI_CLIENT_S_RUNNING:
|
||
|
+ case AVAHI_CLIENT_CONNECTING:
|
||
|
+ ;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/* The main function of the background daemon */
|
||
|
+static void daemon_proc(const char *host_file, const char *lock_file, int n_slots) {
|
||
|
+ int ret = 1;
|
||
|
+ int lock_fd = -1;
|
||
|
+ struct daemon_data d;
|
||
|
+ time_t clip_time;
|
||
|
+ int error;
|
||
|
+
|
||
|
+ rs_add_logger(rs_logger_syslog, RS_LOG_DEBUG, NULL, 0);
|
||
|
+
|
||
|
+ /* Prepare daemon data structure */
|
||
|
+ d.fd = -1;
|
||
|
+ d.hosts = NULL;
|
||
|
+ d.n_slots = n_slots;
|
||
|
+ d.simple_poll = NULL;
|
||
|
+ d.browser = NULL;
|
||
|
+ d.client = NULL;
|
||
|
+ clip_time = time(NULL);
|
||
|
+
|
||
|
+ rs_log_info("Zeroconf daemon running.\n");
|
||
|
+
|
||
|
+ /* Open daemon lock file and lock it */
|
||
|
+ if ((lock_fd = open(lock_file, O_RDWR|O_CREAT, 0666)) < 0) {
|
||
|
+ rs_log_crit("open('%s') failed: %s\n", lock_file, strerror(errno));
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (generic_lock(lock_fd, 1, 1, 0) < 0) {
|
||
|
+ /* lock failed, there's probably already another daemon running */
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Open host file */
|
||
|
+ if ((d.fd = open(host_file, O_RDWR|O_CREAT, 0666)) < 0) {
|
||
|
+ rs_log_crit("open('%s') failed: %s\n", host_file, strerror(errno));
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Clear host file */
|
||
|
+ write_hosts(&d);
|
||
|
+
|
||
|
+ if (!(d.simple_poll = avahi_simple_poll_new())) {
|
||
|
+ rs_log_crit("Failed to create simple poll object.\n");
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!(d.client = avahi_client_new(avahi_simple_poll_get(d.simple_poll),
|
||
|
+ 0,
|
||
|
+ client_callback,
|
||
|
+ &d,
|
||
|
+ &error))) {
|
||
|
+ rs_log_crit("Failed to create Avahi client object: %s\n", avahi_strerror(error));
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!(d.browser = avahi_service_browser_new(d.client,
|
||
|
+ AVAHI_IF_UNSPEC,
|
||
|
+ AVAHI_PROTO_UNSPEC,
|
||
|
+ DCC_DNS_SERVICE_TYPE,
|
||
|
+ NULL,
|
||
|
+ 0,
|
||
|
+ browse_reply,
|
||
|
+ &d))) {
|
||
|
+ rs_log_crit("Failed to create service browser object: %s\n", avahi_strerror(avahi_client_errno(d.client)));
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Check whether the host file has been used recently */
|
||
|
+ while (fd_last_used(d.fd, clip_time) <= MAX_IDLE_TIME) {
|
||
|
+
|
||
|
+ /* Iterate the main loop for 500ms */
|
||
|
+ if (avahi_simple_poll_iterate(d.simple_poll, 500) != 0) {
|
||
|
+ rs_log_crit("Event loop exited abnormaly.\n");
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Wer are idle */
|
||
|
+ rs_log_info("Zeroconf daemon unused.\n");
|
||
|
+
|
||
|
+ ret = 0;
|
||
|
+
|
||
|
+finish:
|
||
|
+
|
||
|
+ /* Cleanup */
|
||
|
+ if (lock_fd >= 0) {
|
||
|
+ generic_lock(lock_fd, 1, 0, 0);
|
||
|
+ close(lock_fd);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (d.fd >= 0)
|
||
|
+ close(d.fd);
|
||
|
+
|
||
|
+ while (d.hosts) {
|
||
|
+ struct host *h = d.hosts;
|
||
|
+ d.hosts = d.hosts->next;
|
||
|
+ free_host(h);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (d.client)
|
||
|
+ avahi_client_free(d.client);
|
||
|
+
|
||
|
+ if (d.simple_poll)
|
||
|
+ avahi_simple_poll_free(d.simple_poll);
|
||
|
+
|
||
|
+ rs_log_info("zeroconf daemon ended.\n");
|
||
|
+
|
||
|
+ _exit(ret);
|
||
|
+}
|
||
|
+
|
||
|
+/* Return path to the zeroconf directory in ~/.distcc */
|
||
|
+static int get_zeroconf_dir(char **dir_ret) {
|
||
|
+ static char *cached;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ if (cached) {
|
||
|
+ *dir_ret = cached;
|
||
|
+ return 0;
|
||
|
+ } else {
|
||
|
+ ret = dcc_get_subdir("zeroconf", dir_ret);
|
||
|
+ if (ret == 0)
|
||
|
+ cached = *dir_ret;
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/* Get the host list from zeroconf */
|
||
|
+int dcc_zeroconf_add_hosts(struct dcc_hostdef **ret_list, int *ret_nhosts, int n_slots, struct dcc_hostdef **ret_prev) {
|
||
|
+ char host_file[PATH_MAX], lock_file[PATH_MAX], *s = NULL;
|
||
|
+ int lock_fd = -1, host_fd = -1;
|
||
|
+ int fork_daemon = 0;
|
||
|
+ int r = -1;
|
||
|
+ char *dir;
|
||
|
+ struct stat st;
|
||
|
+
|
||
|
+ if (get_zeroconf_dir(&dir) != 0) {
|
||
|
+ rs_log_crit("failed to get zeroconf dir.\n");
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ snprintf(lock_file, sizeof(lock_file), "%s/lock", dir);
|
||
|
+ snprintf(host_file, sizeof(host_file), "%s/hosts", dir);
|
||
|
+
|
||
|
+ /* Open lock file */
|
||
|
+ if ((lock_fd = open(lock_file, O_RDWR|O_CREAT, 0666)) < 0) {
|
||
|
+ rs_log_crit("open('%s') failed: %s\n", lock_file, strerror(errno));
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Try to lock the lock file */
|
||
|
+ if (generic_lock(lock_fd, 1, 1, 0) >= 0) {
|
||
|
+ /* The lock succeeded => there's no daemon running yet! */
|
||
|
+ fork_daemon = 1;
|
||
|
+ generic_lock(lock_fd, 1, 0, 0);
|
||
|
+ }
|
||
|
+
|
||
|
+ close(lock_fd);
|
||
|
+
|
||
|
+ /* Shall we fork a new daemon? */
|
||
|
+ if (fork_daemon) {
|
||
|
+ pid_t pid;
|
||
|
+
|
||
|
+ rs_log_info("Spawning zeroconf daemon.\n");
|
||
|
+
|
||
|
+ if ((pid = fork()) == -1) {
|
||
|
+ rs_log_crit("fork() failed: %s\n", strerror(errno));
|
||
|
+ goto finish;
|
||
|
+ } else if (pid == 0) {
|
||
|
+ int fd;
|
||
|
+ /* Child */
|
||
|
+
|
||
|
+ /* Close file descriptors and replace them by /dev/null */
|
||
|
+ close(0);
|
||
|
+ close(1);
|
||
|
+ close(2);
|
||
|
+ fd = open("/dev/null", O_RDWR);
|
||
|
+ assert(fd == 0);
|
||
|
+ fd = dup(0);
|
||
|
+ assert(fd == 1);
|
||
|
+ fd = dup(0);
|
||
|
+ assert(fd == 2);
|
||
|
+
|
||
|
+#ifdef HAVE_SETSID
|
||
|
+ setsid();
|
||
|
+#endif
|
||
|
+
|
||
|
+ chdir("/");
|
||
|
+ rs_add_logger(rs_logger_syslog, RS_LOG_DEBUG, NULL, 0);
|
||
|
+ daemon_proc(host_file, lock_file, n_slots);
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Parent */
|
||
|
+
|
||
|
+ /* Wait some time for initial host gathering */
|
||
|
+ usleep(1000000); /* 1000 ms */
|
||
|
+
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Open host list read-only */
|
||
|
+ if ((host_fd = open(host_file, O_RDONLY)) < 0) {
|
||
|
+ rs_log_crit("open('%s') failed: %s\n", host_file, strerror(errno));
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* A read lock */
|
||
|
+ if (generic_lock(host_fd, 0, 1, 1) < 0) {
|
||
|
+ rs_log_crit("lock failed: %s\n", strerror(errno));
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Get file size */
|
||
|
+ if (fstat(host_fd, &st) < 0) {
|
||
|
+ rs_log_crit("stat() failed: %s\n", strerror(errno));
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (st.st_size >= MAX_FILE_SIZE) {
|
||
|
+ rs_log_crit("file too large.\n");
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* read file data */
|
||
|
+ s = malloc((size_t) st.st_size+1);
|
||
|
+ assert(s);
|
||
|
+
|
||
|
+ if (dcc_readx(host_fd, s, (size_t) st.st_size) != 0) {
|
||
|
+ rs_log_crit("failed to read from file.\n");
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+ s[st.st_size] = 0;
|
||
|
+
|
||
|
+ /* Parse host data */
|
||
|
+ if (dcc_parse_hosts(s, host_file, ret_list, ret_nhosts, ret_prev) != 0) {
|
||
|
+ rs_log_crit("failed to parse host file.\n");
|
||
|
+ goto finish;
|
||
|
+ }
|
||
|
+
|
||
|
+ r = 0;
|
||
|
+
|
||
|
+finish:
|
||
|
+ if (host_fd >= 0) {
|
||
|
+ generic_lock(host_fd, 0, 0, 1);
|
||
|
+ close(host_fd);
|
||
|
+ }
|
||
|
+
|
||
|
+ free(s);
|
||
|
+
|
||
|
+ return r;
|
||
|
+}
|
||
|
+
|
||
|
--- upstream/src/zeroconf-reg.c 1970-01-01 01:00:00.000000000 +0100
|
||
|
+++ lennart/src/zeroconf-reg.c 2005-11-18 15:34:00.000000000 +0100
|
||
|
@@ -0,0 +1,297 @@
|
||
|
+/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- */
|
||
|
+
|
||
|
+#include "config.h"
|
||
|
+
|
||
|
+#include <assert.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <sys/select.h>
|
||
|
+#include <signal.h>
|
||
|
+#include <sys/file.h>
|
||
|
+#include <sys/time.h>
|
||
|
+#include <time.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+#include <sys/poll.h>
|
||
|
+#include <pthread.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <string.h>
|
||
|
+#include <errno.h>
|
||
|
+
|
||
|
+#include <avahi-common/simple-watch.h>
|
||
|
+#include <avahi-common/error.h>
|
||
|
+#include <avahi-common/alternative.h>
|
||
|
+#include <avahi-common/malloc.h>
|
||
|
+#include <avahi-client/publish.h>
|
||
|
+
|
||
|
+#include "distcc.h"
|
||
|
+#include "zeroconf.h"
|
||
|
+#include "trace.h"
|
||
|
+#include "exitcode.h"
|
||
|
+
|
||
|
+struct context {
|
||
|
+ int thread_running;
|
||
|
+ pthread_t thread_id;
|
||
|
+ pthread_mutex_t mutex;
|
||
|
+ char *name;
|
||
|
+ AvahiSimplePoll *simple_poll;
|
||
|
+ AvahiClient *client;
|
||
|
+ AvahiEntryGroup *group;
|
||
|
+ uint16_t port;
|
||
|
+ int n_cpus;
|
||
|
+};
|
||
|
+
|
||
|
+static void publish_reply(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata);
|
||
|
+
|
||
|
+static void register_stuff(struct context *ctx) {
|
||
|
+
|
||
|
+ if (!ctx->group) {
|
||
|
+
|
||
|
+ if (!(ctx->group = avahi_entry_group_new(ctx->client, publish_reply, ctx))) {
|
||
|
+ rs_log_crit("Failed to create entry group: %s\n", avahi_strerror(avahi_client_errno(ctx->client)));
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ }
|
||
|
+
|
||
|
+ if (avahi_entry_group_is_empty(ctx->group)) {
|
||
|
+ char cpus[32];
|
||
|
+
|
||
|
+ snprintf(cpus, sizeof(cpus), "cpus=%i", ctx->n_cpus);
|
||
|
+
|
||
|
+ /* Register our service */
|
||
|
+
|
||
|
+ if (avahi_entry_group_add_service(ctx->group,
|
||
|
+ AVAHI_IF_UNSPEC,
|
||
|
+ AVAHI_PROTO_UNSPEC,
|
||
|
+ 0,
|
||
|
+ ctx->name,
|
||
|
+ DCC_DNS_SERVICE_TYPE,
|
||
|
+ NULL,
|
||
|
+ NULL,
|
||
|
+ ctx->port,
|
||
|
+ "txtvers=1",
|
||
|
+ cpus,
|
||
|
+ "distcc="PACKAGE_VERSION,
|
||
|
+ "gnuhost="GNU_HOST,
|
||
|
+ NULL) < 0) {
|
||
|
+ rs_log_crit("Failed to add service: %s\n", avahi_strerror(avahi_client_errno(ctx->client)));
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (avahi_entry_group_commit(ctx->group) < 0) {
|
||
|
+ rs_log_crit("Failed to commit entry group: %s\n", avahi_strerror(avahi_client_errno(ctx->client)));
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return;
|
||
|
+
|
||
|
+ fail:
|
||
|
+ avahi_simple_poll_quit(ctx->simple_poll);
|
||
|
+}
|
||
|
+
|
||
|
+/* Called when publishing of service data completes */
|
||
|
+static void publish_reply(AvahiEntryGroup *UNUSED(g), AvahiEntryGroupState state, void *userdata) {
|
||
|
+ struct context *ctx = userdata;
|
||
|
+
|
||
|
+ switch (state) {
|
||
|
+
|
||
|
+ case AVAHI_ENTRY_GROUP_COLLISION: {
|
||
|
+ char *n;
|
||
|
+
|
||
|
+ /* Pick a new name for our service */
|
||
|
+
|
||
|
+ n = avahi_alternative_service_name(ctx->name);
|
||
|
+ assert(n);
|
||
|
+
|
||
|
+ avahi_free(ctx->name);
|
||
|
+ ctx->name = n;
|
||
|
+
|
||
|
+ register_stuff(ctx);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ case AVAHI_ENTRY_GROUP_FAILURE:
|
||
|
+ rs_log_crit("Failed to register service: %s\n", avahi_strerror(avahi_client_errno(ctx->client)));
|
||
|
+ avahi_simple_poll_quit(ctx->simple_poll);
|
||
|
+ break;
|
||
|
+
|
||
|
+ case AVAHI_ENTRY_GROUP_UNCOMMITED:
|
||
|
+ case AVAHI_ENTRY_GROUP_REGISTERING:
|
||
|
+ case AVAHI_ENTRY_GROUP_ESTABLISHED:
|
||
|
+ ;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void client_callback(AvahiClient *client, AvahiClientState state, void *userdata) {
|
||
|
+ struct context *ctx = userdata;
|
||
|
+
|
||
|
+ ctx->client = client;
|
||
|
+
|
||
|
+ switch (state) {
|
||
|
+
|
||
|
+ case AVAHI_CLIENT_S_RUNNING:
|
||
|
+
|
||
|
+ register_stuff(ctx);
|
||
|
+ break;
|
||
|
+
|
||
|
+ case AVAHI_CLIENT_S_COLLISION:
|
||
|
+
|
||
|
+ if (ctx->group)
|
||
|
+ avahi_entry_group_reset(ctx->group);
|
||
|
+ break;
|
||
|
+
|
||
|
+ case AVAHI_CLIENT_FAILURE:
|
||
|
+
|
||
|
+ if (avahi_client_errno(client) == AVAHI_ERR_DISCONNECTED) {
|
||
|
+ int error;
|
||
|
+
|
||
|
+ avahi_client_free(ctx->client);
|
||
|
+ ctx->client = NULL;
|
||
|
+ ctx->group = NULL;
|
||
|
+
|
||
|
+ /* Reconnect to the server */
|
||
|
+
|
||
|
+ if (!(ctx->client = avahi_client_new(avahi_simple_poll_get(ctx->simple_poll),
|
||
|
+ AVAHI_CLIENT_NO_FAIL,
|
||
|
+ client_callback,
|
||
|
+ ctx,
|
||
|
+ &error))) {
|
||
|
+
|
||
|
+ rs_log_crit("Failed to contact server: %s\n", avahi_strerror(error));
|
||
|
+ avahi_simple_poll_quit(ctx->simple_poll);
|
||
|
+ }
|
||
|
+
|
||
|
+ } else {
|
||
|
+ rs_log_crit("Client failure: %s\n", avahi_strerror(avahi_client_errno(client)));
|
||
|
+ avahi_simple_poll_quit(ctx->simple_poll);
|
||
|
+ }
|
||
|
+
|
||
|
+ break;
|
||
|
+
|
||
|
+ case AVAHI_CLIENT_S_REGISTERING:
|
||
|
+ case AVAHI_CLIENT_CONNECTING:
|
||
|
+ ;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void* thread(void *userdata) {
|
||
|
+ struct context *ctx = userdata;
|
||
|
+ sigset_t mask;
|
||
|
+ int r;
|
||
|
+
|
||
|
+ /* Make sure that signals are delivered to the main thread */
|
||
|
+ sigfillset(&mask);
|
||
|
+ pthread_sigmask(SIG_BLOCK, &mask, NULL);
|
||
|
+
|
||
|
+ pthread_mutex_lock(&ctx->mutex);
|
||
|
+
|
||
|
+ /* Run the main loop */
|
||
|
+ r = avahi_simple_poll_loop(ctx->simple_poll);
|
||
|
+
|
||
|
+ /* Cleanup some stuff */
|
||
|
+ if (ctx->client)
|
||
|
+ avahi_client_free(ctx->client);
|
||
|
+ ctx->client = NULL;
|
||
|
+ ctx->group = NULL;
|
||
|
+
|
||
|
+ pthread_mutex_unlock(&ctx->mutex);
|
||
|
+
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+static int poll_func(struct pollfd *ufds, unsigned int nfds, int timeout, void *userdata) {
|
||
|
+ pthread_mutex_t *mutex = userdata;
|
||
|
+ int r;
|
||
|
+
|
||
|
+ /* Before entering poll() we unlock the mutex, so that
|
||
|
+ * avahi_simple_poll_quit() can succeed from another thread. */
|
||
|
+
|
||
|
+ pthread_mutex_unlock(mutex);
|
||
|
+ r = poll(ufds, nfds, timeout);
|
||
|
+ pthread_mutex_lock(mutex);
|
||
|
+
|
||
|
+ return r;
|
||
|
+}
|
||
|
+
|
||
|
+/* register a distcc service in DNS-SD/mDNS with the given port and number of CPUs */
|
||
|
+void* dcc_zeroconf_register(uint16_t port, int n_cpus) {
|
||
|
+ struct context *ctx = NULL;
|
||
|
+
|
||
|
+ char service[256] = "distcc@";
|
||
|
+ int error, ret;
|
||
|
+
|
||
|
+ ctx = malloc(sizeof(struct context));
|
||
|
+ assert(ctx);
|
||
|
+ ctx->client = NULL;
|
||
|
+ ctx->group = NULL;
|
||
|
+ ctx->simple_poll = NULL;
|
||
|
+ ctx->thread_running = 0;
|
||
|
+ ctx->port = port;
|
||
|
+ ctx->n_cpus = n_cpus;
|
||
|
+ pthread_mutex_init(&ctx->mutex, NULL);
|
||
|
+
|
||
|
+ /* Prepare service name */
|
||
|
+ gethostname(service+7, sizeof(service)-8);
|
||
|
+ service[sizeof(service)-1] = 0;
|
||
|
+
|
||
|
+ ctx->name = strdup(service);
|
||
|
+ assert(ctx->name);
|
||
|
+
|
||
|
+ if (!(ctx->simple_poll = avahi_simple_poll_new())) {
|
||
|
+ rs_log_crit("Failed to create event loop object.\n");
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ avahi_simple_poll_set_func(ctx->simple_poll, poll_func, &ctx->mutex);
|
||
|
+
|
||
|
+ if (!(ctx->client = avahi_client_new(avahi_simple_poll_get(ctx->simple_poll), AVAHI_CLIENT_NO_FAIL, client_callback, ctx, &error))) {
|
||
|
+ rs_log_crit("Failed to create client object: %s\n", avahi_strerror(avahi_client_errno(ctx->client)));
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Create the mDNS event handler */
|
||
|
+ if ((ret = pthread_create(&ctx->thread_id, NULL, thread, ctx)) < 0) {
|
||
|
+ rs_log_crit("Failed to create thread: %s\n", strerror(ret));
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ ctx->thread_running = 1;
|
||
|
+
|
||
|
+ return ctx;
|
||
|
+
|
||
|
+ fail:
|
||
|
+
|
||
|
+ if (ctx)
|
||
|
+ dcc_zeroconf_unregister(ctx);
|
||
|
+
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+/* Unregister this server from DNS-SD/mDNS */
|
||
|
+int dcc_zeroconf_unregister(void *u) {
|
||
|
+ struct context *ctx = u;
|
||
|
+
|
||
|
+ if (ctx->thread_running) {
|
||
|
+ pthread_mutex_lock(&ctx->mutex);
|
||
|
+ avahi_simple_poll_quit(ctx->simple_poll);
|
||
|
+ pthread_mutex_unlock(&ctx->mutex);
|
||
|
+
|
||
|
+ pthread_join(ctx->thread_id, NULL);
|
||
|
+ ctx->thread_running = 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ avahi_free(ctx->name);
|
||
|
+
|
||
|
+ if (ctx->client)
|
||
|
+ avahi_client_free(ctx->client);
|
||
|
+
|
||
|
+ if (ctx->simple_poll)
|
||
|
+ avahi_simple_poll_free(ctx->simple_poll);
|
||
|
+
|
||
|
+ pthread_mutex_destroy(&ctx->mutex);
|
||
|
+
|
||
|
+ free(ctx);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|