From f4ff1b74f6b6e3a2a2ecf18f02a65c007e46eaf2 Mon Sep 17 00:00:00 2001 From: Julien BLACHE Date: Fri, 11 Apr 2008 17:18:19 +0000 Subject: [PATCH] Add mDNS DNS-SD support to saned and the net backend so they can announce and discover each other automatically. Optional at configure time, requires Avahi >= 0.6.4. --- ChangeLog | 12 ++ aclocal.m4 | 162 +++++++++++++++++++++- backend/net.c | 283 ++++++++++++++++++++++++++++++++++++++- configure | 279 ++++++++++++++++++++++++++++++++++---- configure.in | 15 +++ frontend/saned.c | 269 ++++++++++++++++++++++++++++++++++++- include/sane/config.h.in | 3 + 7 files changed, 988 insertions(+), 35 deletions(-) diff --git a/ChangeLog b/ChangeLog index f70fb4c07..c5b7003b3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2008-04-11 Julien Blache + * frontend/saned.c: announce the _sane-port._tcp service via mDNS + (Avahi) when running in standalone or debug mode. A separate + process is responsible for the announcement through Avahi. + * backend/net.c: look for _sane-port._tcp service announcements + via mDNS (Avahi). A separate thread listens to announcements + through Avahi. Start the thread as early as possible in + sane_init() so as to get as much data as possible until + sane_get_devices() is called. + * aclocal.m4, configure, configure.in, include/sane/config.h.in: + add autofoo stuff for Avahi support, disabled by default. + 2008-04-10 Julien Blache * frontend/saned.c: do not use daemon(), as it's a 4.4BSD/glibc function; OS/2 for instance does not have it. Use an open-coded diff --git a/aclocal.m4 b/aclocal.m4 index 8b479e11b..ace734f02 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,7 +1,7 @@ -# generated automatically by aclocal 1.10 -*- Autoconf -*- +# generated automatically by aclocal 1.9.6 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -# 2005, 2006 Free Software Foundation, Inc. +# 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. @@ -11,4 +11,162 @@ # 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 . +# +# 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 +])], + [AC_MSG_RESULT([no]) + $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 .])], + [$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]) diff --git a/backend/net.c b/backend/net.c index 28311d371..353868fdc 100644 --- a/backend/net.c +++ b/backend/net.c @@ -1,7 +1,7 @@ /* sane - Scanner Access Now Easy. Copyright (C) 1997 David Mosberger-Tang - Copyright (C) 2003 Julien BLACHE - AF-independent code + IPv6 + Copyright (C) 2003, 2008 Julien BLACHE + AF-independent code + IPv6, Avahi support This file is part of the SANE package. @@ -66,6 +66,21 @@ #include #include /* OS/2 needs this _after_ , grrr... */ +#ifdef WITH_AVAHI +# include +# include + +# include +# include +# include + +# define SANED_SERVICE_DNS "_sane-port._tcp" + +static AvahiClient *avahi_client = NULL; +static AvahiThreadedPoll *avahi_thread = NULL; +static AvahiServiceBrowser *avahi_browser = NULL; +#endif /* WITH_AVAHI */ + #include "../include/sane/sane.h" #include "../include/sane/sanei.h" #include "../include/sane/sanei_net.h" @@ -149,6 +164,17 @@ add_device (const char *name, Net_Device ** ndp) DBG (1, "add_device: adding backend %s\n", name); + for (nd = first_device; nd; nd = nd->next) + if (strcmp (nd->name, name) == 0) + { + DBG (1, "add_device: already in list\n"); + + if (ndp) + *ndp = nd; + + return SANE_STATUS_GOOD; + } + memset (&hints, 0, sizeof(hints)); # ifdef ENABLE_IPV6 @@ -231,6 +257,17 @@ add_device (const char *name, Net_Device ** ndp) DBG (1, "add_device: adding backend %s\n", name); + for (nd = first_device; nd; nd = nd->next) + if (strcmp (nd->name, name) == 0) + { + DBG (1, "add_device: already in list\n"); + + if (ndp) + *ndp = nd; + + return SANE_STATUS_GOOD; + } + he = gethostbyname (name); if (!he) { @@ -656,6 +693,234 @@ do_authorization (Net_Device * dev, SANE_String resource) DBG (1, "do_authorization: auth_active is false... strange\n"); } + +#ifdef WITH_AVAHI +static void +net_avahi_resolve_callback (AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, + AvahiResolverEvent event, const char *name, const char *type, + const char *domain, const char *host_name, const AvahiAddress *address, + uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, + void *userdata) +{ + char a[AVAHI_ADDRESS_STR_MAX]; + char *t; + + /* unused */ + interface = interface; + protocol = protocol; + userdata = userdata; + + if (!r) + return; + + switch (event) + { + case AVAHI_RESOLVER_FAILURE: + DBG (1, "net_avahi_resolve_callback: failed to resolve service '%s' of type '%s' in domain '%s': %s\n", + name, type, domain, avahi_strerror (avahi_client_errno (avahi_service_resolver_get_client (r)))); + break; + + case AVAHI_RESOLVER_FOUND: + DBG (3, "net_avahi_resolve_callback: service '%s' of type '%s' in domain '%s':\n", name, type, domain); + + avahi_address_snprint(a, sizeof (a), address); + t = avahi_string_list_to_string (txt); + + DBG (3, "\t%s:%u (%s)\n\tTXT=%s\n\tcookie is %u\n\tis_local: %i\n\tour_own: %i\n" + "\twide_area: %i\n\tmulticast: %i\n\tcached: %i\n", + host_name, port, a, t, avahi_string_list_get_service_cookie (txt), + !!(flags & AVAHI_LOOKUP_RESULT_LOCAL), !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN), + !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA), !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST), + !!(flags & AVAHI_LOOKUP_RESULT_CACHED)); + + /* TODO: evaluate TXT record */ + + /* Try first with the name */ + if (add_device (host_name, NULL) != SANE_STATUS_GOOD) + { + DBG (1, "net_avahi_resolve_callback: couldn't add backend with name %s\n", host_name); + + /* Then try the raw IP address */ + if (add_device (t, NULL) != SANE_STATUS_GOOD) + DBG (1, "net_avahi_resolve_callback: couldn't add backend with IP address %s either\n", t); + } + + avahi_free (t); + break; + } + + avahi_service_resolver_free(r); +} + +static void +net_avahi_browse_callback (AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, + AvahiBrowserEvent event, const char *name, const char *type, + const char *domain, AvahiLookupResultFlags flags, void *userdata) +{ + /* unused */ + flags = flags; + userdata = userdata; + + if (!b) + return; + + switch (event) + { + case AVAHI_BROWSER_FAILURE: + DBG (1, "net_avahi_browse_callback: %s\n", avahi_strerror (avahi_client_errno (avahi_service_browser_get_client (b)))); + avahi_threaded_poll_quit (avahi_thread); + return; + + case AVAHI_BROWSER_NEW: + DBG (3, "net_avahi_browse_callback: NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain); + + /* The server will actually be added to our list in the resolver callback */ + + /* The resolver object will be freed in the resolver callback, or by + * the server if it terminates before the callback is called. + */ + if (!(avahi_service_resolver_new (avahi_client, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, net_avahi_resolve_callback, NULL))) + DBG (2, "net_avahi_browse_callback: failed to resolve service '%s': %s\n", name, avahi_strerror (avahi_client_errno (avahi_client))); + break; + + case AVAHI_BROWSER_REMOVE: + DBG (3, "net_avahi_browse_callback: REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain); + /* With the current architecture, we cannot safely remove a server from the list */ + break; + + case AVAHI_BROWSER_ALL_FOR_NOW: + case AVAHI_BROWSER_CACHE_EXHAUSTED: + DBG (3, "net_avahi_browse_callback: %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW"); + break; + } +} + +static void +net_avahi_callback (AvahiClient *c, AvahiClientState state, void * userdata) +{ + int error; + + /* unused */ + userdata = userdata; + + if (!c) + return; + + switch (state) + { + case AVAHI_CLIENT_CONNECTING: + break; + + case AVAHI_CLIENT_S_COLLISION: + case AVAHI_CLIENT_S_REGISTERING: + case AVAHI_CLIENT_S_RUNNING: + if (avahi_browser) + return; + + avahi_browser = avahi_service_browser_new (c, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, SANED_SERVICE_DNS, NULL, 0, net_avahi_browse_callback, NULL); + if (avahi_browser == NULL) + { + DBG (1, "net_avahi_callback: could not create service browser: %s\n", avahi_strerror (avahi_client_errno (c))); + avahi_threaded_poll_quit (avahi_thread); + } + break; + + case AVAHI_CLIENT_FAILURE: + error = avahi_client_errno (c); + + if (error == AVAHI_ERR_DISCONNECTED) + { + /* Server disappeared - try to reconnect */ + avahi_client_free (avahi_client); + avahi_client = NULL; + + if (avahi_browser) + { + avahi_service_browser_free (avahi_browser); + avahi_browser = NULL; + } + + avahi_client = avahi_client_new (avahi_threaded_poll_get (avahi_thread), AVAHI_CLIENT_NO_FAIL, net_avahi_callback, NULL, &error); + if (avahi_client == NULL) + { + DBG (1, "net_avahi_init: could not create Avahi client: %s\n", avahi_strerror (error)); + avahi_threaded_poll_quit (avahi_thread); + } + } + else + { + /* Another error happened - game over */ + DBG (1, "net_avahi_callback: server connection failure: %s\n", avahi_strerror (error)); + avahi_threaded_poll_quit (avahi_thread); + } + break; + } +} + + +static void +net_avahi_init (void) +{ + int error; + + avahi_thread = avahi_threaded_poll_new (); + if (avahi_thread == NULL) + { + DBG (1, "net_avahi_init: could not create threaded poll object\n"); + goto fail; + } + + avahi_client = avahi_client_new (avahi_threaded_poll_get (avahi_thread), AVAHI_CLIENT_NO_FAIL, net_avahi_callback, NULL, &error); + if (avahi_client == NULL) + { + DBG (1, "net_avahi_init: could not create Avahi client: %s\n", avahi_strerror (error)); + goto fail; + } + + if (avahi_threaded_poll_start (avahi_thread) < 0) + { + DBG (1, "net_avahi_init: Avahi thread failed to start\n"); + goto fail; + } + + /* All done */ + return; + + fail: + DBG (1, "net_avahi_init: Avahi init failed, support disabled\n"); + + if (avahi_client) + { + avahi_client_free (avahi_client); + avahi_client = NULL; + } + + if (avahi_thread) + { + avahi_threaded_poll_free (avahi_thread); + avahi_thread = NULL; + } +} + +static void +net_avahi_cleanup (void) +{ + if (!avahi_thread) + return; + + avahi_threaded_poll_stop (avahi_thread); + + if (avahi_browser) + avahi_service_browser_free (avahi_browser); + + if (avahi_client) + avahi_client_free (avahi_client); + + avahi_threaded_poll_free (avahi_thread); +} +#endif /* WITH_AVAHI */ + + SANE_Status sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) { @@ -676,9 +941,13 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) DBG (2, "sane_init: authorize = %p, version_code = %p\n", (void *) authorize, (void *) version_code); - devlist = 0; - first_device = 0; - first_handle = 0; + devlist = NULL; + first_device = NULL; + first_handle = NULL; + +#ifdef WITH_AVAHI + net_avahi_init (); +#endif /* WITH_AVAHI */ auth_callback = authorize; @@ -833,6 +1102,10 @@ sane_exit (void) DBG (1, "sane_exit: exiting\n"); +#ifdef WITH_AVAHI + net_avahi_cleanup (); +#endif /* WITH_AVAHI */ + /* first, close all handles: */ for (handle = first_handle; handle; handle = next_handle) { diff --git a/configure b/configure index f64f2de31..23280e949 100755 --- a/configure +++ b/configure @@ -853,6 +853,9 @@ INSTALL_LOCKPATH LOCKPATH_GROUP HAVE_GPHOTO2 GPHOTO2_LDFLAGS +PKG_CONFIG +AVAHI_CFLAGS +AVAHI_LIBS ALLOCA LIBOBJS LN_S @@ -894,6 +897,9 @@ LDFLAGS LIBS CPPFLAGS CPP +PKG_CONFIG +AVAHI_CFLAGS +AVAHI_LIBS CXX CXXFLAGS CCC @@ -1484,6 +1490,7 @@ Optional Features: yes for everything else) --enable-locking activate device locking (default=yes, but only used by some backends) + --enable-avahi enable Avahi support for saned and the net backend --disable-libusb disable support for libusb --disable-ipv6 disable IPv6 support --enable-static[=PKGS] build static libraries [default=no] @@ -1526,6 +1533,10 @@ Some influential environment variables: CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor + PKG_CONFIG path to pkg-config utility + AVAHI_CFLAGS + C compiler flags for AVAHI, overriding pkg-config + AVAHI_LIBS linker flags for AVAHI, overriding pkg-config CXX C++ compiler command CXXFLAGS C++ compiler flags CXXCPP C++ preprocessor @@ -8167,6 +8178,216 @@ done fi + + +# Check whether --enable-avahi was given. +if test "${enable_avahi+set}" = set; then + enableval=$enable_avahi; enable_avahi=$enableval +else + enable_avahi=no +fi + + +if test "$enable_avahi" = "yes"; then + + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_PKG_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5 +echo "${ECHO_T}$PKG_CONFIG" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { echo "$as_me:$LINENO: result: $ac_pt_PKG_CONFIG" >&5 +echo "${ECHO_T}$ac_pt_PKG_CONFIG" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=0.9.0 + { echo "$as_me:$LINENO: checking pkg-config is at least version $_pkg_min_version" >&5 +echo $ECHO_N "checking pkg-config is at least version $_pkg_min_version... $ECHO_C" >&6; } + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + PKG_CONFIG="" + fi + +fi + +pkg_failed=no +{ echo "$as_me:$LINENO: checking for AVAHI" >&5 +echo $ECHO_N "checking for AVAHI... $ECHO_C" >&6; } + +if test -n "$PKG_CONFIG"; then + if test -n "$AVAHI_CFLAGS"; then + pkg_cv_AVAHI_CFLAGS="$AVAHI_CFLAGS" + else + if test -n "$PKG_CONFIG" && \ + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \" avahi-client >= 0.6.4 \"") >&5 + ($PKG_CONFIG --exists --print-errors " avahi-client >= 0.6.4 ") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + pkg_cv_AVAHI_CFLAGS=`$PKG_CONFIG --cflags " avahi-client >= 0.6.4 " 2>/dev/null` +else + pkg_failed=yes +fi + fi +else + pkg_failed=untried +fi +if test -n "$PKG_CONFIG"; then + if test -n "$AVAHI_LIBS"; then + pkg_cv_AVAHI_LIBS="$AVAHI_LIBS" + else + if test -n "$PKG_CONFIG" && \ + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \" avahi-client >= 0.6.4 \"") >&5 + ($PKG_CONFIG --exists --print-errors " avahi-client >= 0.6.4 ") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + pkg_cv_AVAHI_LIBS=`$PKG_CONFIG --libs " avahi-client >= 0.6.4 " 2>/dev/null` +else + pkg_failed=yes +fi + fi +else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + AVAHI_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors " avahi-client >= 0.6.4 "` + else + AVAHI_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors " avahi-client >= 0.6.4 "` + fi + # Put the nasty error message in config.log where it belongs + echo "$AVAHI_PKG_ERRORS" >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + enable_avahi=no +elif test $pkg_failed = untried; then + enable_avahi=no +else + AVAHI_CFLAGS=$pkg_cv_AVAHI_CFLAGS + AVAHI_LIBS=$pkg_cv_AVAHI_LIBS + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<\_ACEOF +#define WITH_AVAHI 1 +_ACEOF + + LIBS="${LIBS} ${AVAHI_LIBS}" + CFLAGS="${CFLAGS} ${AVAHI_CFLAGS}" +fi +fi + { echo "$as_me:$LINENO: checking for sane_init in -lsane" >&5 echo $ECHO_N "checking for sane_init in -lsane... $ECHO_C" >&6; } if test "${ac_cv_lib_sane_sane_init+set}" = set; then @@ -12423,7 +12644,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 12426 "configure"' > conftest.$ac_ext + echo '#line 12647 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -14866,11 +15087,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14869: $lt_compile\"" >&5) + (eval echo "\"\$as_me:15090: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14873: \$? = $ac_status" >&5 + echo "$as_me:15094: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -15134,11 +15355,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:15137: $lt_compile\"" >&5) + (eval echo "\"\$as_me:15358: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:15141: \$? = $ac_status" >&5 + echo "$as_me:15362: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -15238,11 +15459,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:15241: $lt_compile\"" >&5) + (eval echo "\"\$as_me:15462: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:15245: \$? = $ac_status" >&5 + echo "$as_me:15466: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -17546,7 +17767,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5) + (eval echo "\"\$as_me:20210: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:19993: \$? = $ac_status" >&5 + echo "$as_me:20214: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -20090,11 +20311,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:20093: $lt_compile\"" >&5) + (eval echo "\"\$as_me:20314: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:20097: \$? = $ac_status" >&5 + echo "$as_me:20318: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -21660,11 +21881,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:21663: $lt_compile\"" >&5) + (eval echo "\"\$as_me:21884: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:21667: \$? = $ac_status" >&5 + echo "$as_me:21888: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -21764,11 +21985,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:21767: $lt_compile\"" >&5) + (eval echo "\"\$as_me:21988: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:21771: \$? = $ac_status" >&5 + echo "$as_me:21992: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -23966,11 +24187,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:23969: $lt_compile\"" >&5) + (eval echo "\"\$as_me:24190: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:23973: \$? = $ac_status" >&5 + echo "$as_me:24194: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -24234,11 +24455,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:24237: $lt_compile\"" >&5) + (eval echo "\"\$as_me:24458: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:24241: \$? = $ac_status" >&5 + echo "$as_me:24462: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -24338,11 +24559,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:24341: $lt_compile\"" >&5) + (eval echo "\"\$as_me:24562: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:24345: \$? = $ac_status" >&5 + echo "$as_me:24566: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -27961,6 +28182,9 @@ INSTALL_LOCKPATH!$INSTALL_LOCKPATH$ac_delim LOCKPATH_GROUP!$LOCKPATH_GROUP$ac_delim HAVE_GPHOTO2!$HAVE_GPHOTO2$ac_delim GPHOTO2_LDFLAGS!$GPHOTO2_LDFLAGS$ac_delim +PKG_CONFIG!$PKG_CONFIG$ac_delim +AVAHI_CFLAGS!$AVAHI_CFLAGS$ac_delim +AVAHI_LIBS!$AVAHI_LIBS$ac_delim ALLOCA!$ALLOCA$ac_delim LIBOBJS!$LIBOBJS$ac_delim LN_S!$LN_S$ac_delim @@ -27970,9 +28194,6 @@ RANLIB!$RANLIB$ac_delim STRIP!$STRIP$ac_delim DLLTOOL!$DLLTOOL$ac_delim AS!$AS$ac_delim -OBJDUMP!$OBJDUMP$ac_delim -CXX!$CXX$ac_delim -CXXFLAGS!$CXXFLAGS$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then @@ -28014,6 +28235,9 @@ _ACEOF ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF +OBJDUMP!$OBJDUMP$ac_delim +CXX!$CXX$ac_delim +CXXFLAGS!$CXXFLAGS$ac_delim ac_ct_CXX!$ac_ct_CXX$ac_delim CXXCPP!$CXXCPP$ac_delim F77!$F77$ac_delim @@ -28035,7 +28259,7 @@ DISTCLEAN_FILES!$DISTCLEAN_FILES$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 19; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 22; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 @@ -28494,6 +28718,7 @@ else echo "Build saned: no" fi echo "IPv6 support: `eval eval echo ${ipv6}`" +echo "Avahi support: `eval eval echo ${enable_avahi}`" echo "-> The following backends will be built:" for backend in ${BACKENDS} ; do echo $ECHO_N "${backend} " diff --git a/configure.in b/configure.in index 0d40343ce..a34ddf63e 100644 --- a/configure.in +++ b/configure.in @@ -115,6 +115,20 @@ SANE_CHECK_IEEE1284 SANE_CHECK_PTHREAD SANE_CHECK_LOCKING SANE_CHECK_GPHOTO2 + + +AC_ARG_ENABLE(avahi, + AC_HELP_STRING([--enable-avahi], [enable Avahi support for saned and the net backend]), + [enable_avahi=$enableval], [enable_avahi=no]) + +if test "$enable_avahi" = "yes"; then + PKG_CHECK_MODULES(AVAHI, [ avahi-client >= 0.6.4 ], + [ AC_DEFINE(WITH_AVAHI, 1, [define if Avahi support is enabled for saned and the net backend]) + LIBS="${LIBS} ${AVAHI_LIBS}" + CFLAGS="${CFLAGS} ${AVAHI_CFLAGS}" ], + [ enable_avahi=no ]) +fi + dnl check sane to make sure we don't have two installations AC_CHECK_LIB(sane, sane_init, LIBSANE_EXISTS="yes") @@ -590,6 +604,7 @@ else echo "Build saned: no" fi echo "IPv6 support: `eval eval echo ${ipv6}`" +echo "Avahi support: `eval eval echo ${enable_avahi}`" echo "-> The following backends will be built:" for backend in ${BACKENDS} ; do echo $ECHO_N "${backend} " diff --git a/frontend/saned.c b/frontend/saned.c index bcb17c439..6ea475821 100644 --- a/frontend/saned.c +++ b/frontend/saned.c @@ -80,6 +80,7 @@ #include + #if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL) # include #else @@ -151,6 +152,28 @@ poll (struct pollfd *ufds, unsigned int nfds, int timeout) } #endif /* HAVE_SYS_POLL_H && HAVE_POLL */ +#ifdef WITH_AVAHI +# include +# include + +# include +# include +# include +# include + +# define SANED_SERVICE_DNS "_sane-port._tcp" +# define SANED_NAME "saned" + +pid_t avahi_pid = -1; + +char *avahi_svc_name; + +static AvahiClient *avahi_client = NULL; +static AvahiSimplePoll *avahi_poll = NULL; +static AvahiEntryGroup *avahi_group = NULL; +#endif /* WITH_AVAHI */ + + #include "../include/sane/sane.h" #include "../include/sane/sanei.h" #include "../include/sane/sanei_net.h" @@ -2082,6 +2105,15 @@ wait_child (pid_t pid, int *status, int options) if (ret <= 0) return ret; +#ifdef WITH_AVAHI + if ((avahi_pid > 0) && (ret == avahi_pid)) + { + avahi_pid = -1; + numchildren--; + return ret; + } +#endif /* WITH_AVAHI */ + for (c = children; (c != NULL) && (c->next != NULL); p = c, c = c->next) { if (c->pid == ret) @@ -2212,6 +2244,11 @@ bail_out (int error) { DBG (DBG_ERR, "%sbailing out, waiting for children...\n", (error) ? "FATAL ERROR; " : ""); +#ifdef WITH_AVAHI + if (avahi_pid > 0) + kill (avahi_pid, SIGTERM); +#endif /* WITH_AVAHI */ + while (numchildren > 0) wait_child (-1, NULL, 0); @@ -2220,7 +2257,6 @@ bail_out (int error) exit (1); } - void sig_int_term_handler (int signum); @@ -2237,6 +2273,232 @@ sig_int_term_handler (int signum) } +#ifdef WITH_AVAHI +static void +saned_avahi (void); + +static void +saned_create_avahi_services (AvahiClient *c); + +static void +saned_avahi_callback (AvahiClient *c, AvahiClientState state, void *userdata); + +static void +saned_avahi_group_callback (AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata); + + +static void +saned_avahi (void) +{ + int error; + + avahi_pid = fork (); + + if (avahi_pid > 0) + { + numchildren++; + return; + } + else if (avahi_pid < 0) + { + DBG (DBG_ERR, "saned_avahi: could not spawn Avahi process: %s\n", strerror (errno)); + return; + } + + signal (SIGINT, NULL); + signal (SIGTERM, NULL); + + avahi_svc_name = avahi_strdup(SANED_NAME); + + avahi_poll = avahi_simple_poll_new (); + if (avahi_poll == NULL) + { + DBG (DBG_ERR, "saned_avahi: failed to create simple poll object\n"); + goto fail; + } + + avahi_client = avahi_client_new (avahi_simple_poll_get (avahi_poll), AVAHI_CLIENT_NO_FAIL, saned_avahi_callback, NULL, &error); + if (avahi_client == NULL) + { + DBG (DBG_ERR, "saned_avahi: failed to create client: %s\n", avahi_strerror (error)); + goto fail; + } + + avahi_simple_poll_loop (avahi_poll); + + return; + + fail: + if (avahi_client) + avahi_client_free (avahi_client); + + if (avahi_poll) + avahi_simple_poll_free (avahi_poll); + + avahi_free (avahi_svc_name); +} + +static void +saned_avahi_group_callback (AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) +{ + char *n; + + /* unused */ + userdata = userdata; + + if ((!g) || (g != avahi_group)) + return; + + switch (state) + { + case AVAHI_ENTRY_GROUP_ESTABLISHED: + /* The entry group has been established successfully */ + DBG (DBG_INFO, "saned_avahi_group_callback: service '%s' successfully established\n", avahi_svc_name); + break; + + case AVAHI_ENTRY_GROUP_COLLISION: + /* A service name collision with a remote service + * happened. Let's pick a new name */ + n = avahi_alternative_service_name (avahi_svc_name); + avahi_free (avahi_svc_name); + avahi_svc_name = n; + + DBG (DBG_WARN, "saned_avahi_group_callback: service name collision, renaming service to '%s'\n", avahi_svc_name); + + /* And recreate the services */ + saned_create_avahi_services (avahi_entry_group_get_client (g)); + break; + + case AVAHI_ENTRY_GROUP_FAILURE : + DBG (DBG_ERR, "saned_avahi_group_callback: entry group failure: %s\n", avahi_strerror (avahi_client_errno (avahi_entry_group_get_client (g)))); + + /* Some kind of failure happened while we were registering our services */ + avahi_simple_poll_quit (avahi_poll); + break; + + case AVAHI_ENTRY_GROUP_UNCOMMITED: + case AVAHI_ENTRY_GROUP_REGISTERING: + break; + } +} + +static void +saned_create_avahi_services (AvahiClient *c) +{ + char *n; + char txt[32]; + int ret; + + if (!c) + return; + + if (!avahi_group) + { + avahi_group = avahi_entry_group_new (c, saned_avahi_group_callback, NULL); + if (avahi_group == NULL) + { + DBG (DBG_ERR, "saned_create_avahi_services: avahi_entry_group_new() failed: %s\n", avahi_strerror (avahi_client_errno (c))); + goto fail; + } + } + + if (avahi_entry_group_is_empty (avahi_group)) + { + DBG (DBG_INFO, "saned_create_avahi_services: adding service '%s'\n", avahi_svc_name); + + snprintf(txt, sizeof (txt), "protovers=%x", SANE_VERSION_CODE (V_MAJOR, V_MINOR, SANEI_NET_PROTOCOL_VERSION)); + + ret = avahi_entry_group_add_service (avahi_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, avahi_svc_name, SANED_SERVICE_DNS, NULL, NULL, SANED_SERVICE_PORT, txt, NULL); + if (ret < 0) + { + if (ret == AVAHI_ERR_COLLISION) + { + n = avahi_alternative_service_name (avahi_svc_name); + avahi_free (avahi_svc_name); + avahi_svc_name = n; + + DBG (DBG_WARN, "saned_create_avahi_services: service name collision, renaming service to '%s'\n", avahi_svc_name); + + avahi_entry_group_reset (avahi_group); + + saned_create_avahi_services (c); + + return; + } + + DBG (DBG_ERR, "saned_create_avahi_services: failed to add %s service: %s\n", SANED_SERVICE_DNS, avahi_strerror (ret)); + goto fail; + } + + /* Tell the server to register the service */ + ret = avahi_entry_group_commit (avahi_group); + if (ret < 0) + { + DBG (DBG_ERR, "saned_create_avahi_services: failed to commit entry group: %s\n", avahi_strerror (ret)); + goto fail; + } + } + + return; + + fail: + avahi_simple_poll_quit (avahi_poll); +} + +static void +saned_avahi_callback (AvahiClient *c, AvahiClientState state, void *userdata) +{ + int error; + + /* unused */ + userdata = userdata; + + if (!c) + return; + + switch (state) + { + case AVAHI_CLIENT_CONNECTING: + break; + + case AVAHI_CLIENT_S_RUNNING: + saned_create_avahi_services (c); + break; + + case AVAHI_CLIENT_S_COLLISION: + case AVAHI_CLIENT_S_REGISTERING: + if (avahi_group) + avahi_entry_group_reset (avahi_group); + break; + + case AVAHI_CLIENT_FAILURE: + error = avahi_client_errno (c); + + if (error == AVAHI_ERR_DISCONNECTED) + { + /* Server disappeared - try to reconnect */ + avahi_client_free (avahi_client); + avahi_client = NULL; + + avahi_client = avahi_client_new (avahi_simple_poll_get (avahi_poll), AVAHI_CLIENT_NO_FAIL, saned_avahi_callback, NULL, &error); + if (avahi_client == NULL) + { + DBG (DBG_ERR, "saned_avahi_callback: failed to create client: %s\n", avahi_strerror (error)); + avahi_simple_poll_quit (avahi_poll); + } + } + else + { + /* Another error happened - game over */ + DBG (DBG_ERR, "saned_avahi_callback: client failure: %s\n", avahi_strerror (error)); + avahi_simple_poll_quit (avahi_poll); + } + break; + } +} +#endif /* WITH_AVAHI */ + + #ifdef SANED_USES_AF_INDEP static void do_bindings (int *nfds, struct pollfd **fds) @@ -2526,6 +2788,11 @@ run_standalone (int argc, char **argv) signal(SIGTERM, sig_int_term_handler); } +#ifdef WITH_AVAHI + DBG (DBG_INFO, "run_standalone: spawning Avahi process\n"); + saned_avahi (); +#endif /* WITH_AVAHI */ + DBG (DBG_MSG, "run_standalone: waiting for control connection\n"); while (1) diff --git a/include/sane/config.h.in b/include/sane/config.h.in index 040aedc15..4648ecd42 100644 --- a/include/sane/config.h.in +++ b/include/sane/config.h.in @@ -449,6 +449,9 @@ /* Define to the version of the distribution. */ #undef VERSION +/* define if Avahi support is enabled for saned and the net backend */ +#undef WITH_AVAHI + /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ #undef WORDS_BIGENDIAN