Add avahi support #3066

Closed
michaelrsweet opened this Issue Jan 19, 2009 · 48 comments

Projects

None yet

1 participant

@michaelrsweet
Collaborator

Version: 1.6-feature
CUPS.org User: twaugh.redhat

I'm in the process of adding support for Avahi, an implementation of mDNS/DNS-SD.

It is not yet complete, but seems to be working for at least the dnssd backend.

I'm attaching a patch for review, to see if I'm heading in the right direction before continuing on with the scheduler.

@michaelrsweet
Collaborator

CUPS.org User: mike

The changes still need to conform to the CUPS coding standards (mainly comments are missing), and I'd rather make the code HAVE_AVAHI or HAVE_DNSSD (but only one gets defined). We can worry about adding configure options to choose which implementation to use at the end - some Linux distros come with mDNSResponder instead of Avahi.

I think you are going to have serious problems implementing Avahi in the scheduler since it is so tightly coupled to glib (or that's how it looked when I investigated adding "native" Avahi support last year), and the lack of documentation on the low-level interfaces that don't depend on glib (which is probably what you'll need to use) won't help either.

Finally, the source changes will be large enough we'll probably need a copyright assignment or at least a licensing to Apple to keep the CUPS sources (legally) clean.

Moving to -feature for now; if we end up with a complete implementation before 1.4.0 is released and have any legal issues resolved, it can go in 1.4.x, otherwise probably 1.5.x.

@michaelrsweet
Collaborator

CUPS.org User: martin.pitt.canonical

Please note that this

  • perror ("ERROR: Unable to create avahi client");
  • return (1);

causes the test suite to fail when being run without a running system D-BUS instance:

FAIL: 20 error messages, expected 18.
[...]
E [25/Aug/2009:16:17:48.540155 +0000] [CGI] Unable to create avahi client: No such file or directory
E [25/Aug/2009:16:17:48.540492 +0000] [cups-deviced] PID 22335 (dnssd) stopped with status 1!

This is usually the case when calling "make check" during package build on build servers. It's usually a great idea to enable the tests during package build to catch regressions on particular architectures or from underlying libraries, so I wouldn't like to lose this feature. Perhaps this can be toned down to a mere printf() to stdout (for debugging), and exit cleanly?

@michaelrsweet
Collaborator

CUPS.org User: martin.pitt.canonical

Just for the records, this is what
avahi_client_new() tries:

connect(5, {sa_family=AF_FILE, path="/var/run/dbus/system_bus_socket"}, 33) = -1 ENOENT (No such file or directory)

Slightly altering the code snippet to

  • perror ("DEBUG: Unable to create avahi client");
  • return (0);

keeps the test suite happy. Would this be acceptable?

@michaelrsweet
Collaborator

CUPS.org User: twaugh.redhat

It's the avahi equivalent of this:

if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError)
{
perror("ERROR: Unable to create service connection");
return (1);
}

So if one has to change, the other also has to change.

@michaelrsweet
Collaborator

CUPS.org User: Spudd86

might I suggest using pkg-config to detect avahi rather than
AC_CHECK_HEADER

so you do like this instead:

PKG_CHECK_MODULES([AVAHI], [avahi-client])
AC_SUBST(AVAHI_CFLAGS)
AC_SUBST(AVAHI_LIBS)

(with changes to make stuff work... but that's the idea)

@michaelrsweet
Collaborator

CUPS.org User: twaugh.redhat

Note that the current version of the patch is here:

http://cvs.fedoraproject.org/viewvc/devel/cups/cups-avahi.patch?view=markup

and that further work is required for Avahi support in the scheduler.

@michaelrsweet
Collaborator

CUPS.org User: twaugh.redhat

Having implemented native Avahi support for branch-1.4, I've now split it up into separate functional pieces and have begun re-basing them to trunk.

There are 5 in total but I have not yet re-based the last of them. I'll attach the first 4 here.

@michaelrsweet
Collaborator

CUPS.org User: twaugh.redhat

I've updated patch number 4 in the sequence (Avahi poll API implementation) to fix a resource leak during an error condition. Problem spotted using static code analysis.

@michaelrsweet
Collaborator

CUPS.org User: mike

Pushing out pending licensing...

@michaelrsweet
Collaborator

CUPS.org User: anybody

Has this been included in CUPS 1.5 ?

A presentation from April 2010 mentioned "Bonjour support: Full support for Avahi" as one of the changes for CUPS v1.5 (Source: https://www.linuxfoundation.org/sites/main/files/cups-openprinting-april-10.pdf), however upon release of the new version I couldn't really identify something in the changelog that made it clear to me whether this has been included or not.

Basically what I want to do is use AirPrint in Gentoo, and since Gentoo doesn't ship an Avahi-patched-CUPS-1.4 (like Ubuntu does) i'm stuck on the very old 1.3.x release... I was hoping that a "reintegration" of AVAHI would be part of CUPS 1.5 and would allow me to upgrade. Was I wrong about this?

@michaelrsweet
Collaborator

CUPS.org User: mike

No, current CUPS 1.5 does NOT have Avahi support. We are waiting on legal issues to incorporate the code changes.

@michaelrsweet
Collaborator

CUPS.org User: twaugh.redhat

Current patch set, with license updated, attached.

@michaelrsweet
Collaborator

CUPS.org User: twaugh.redhat

Current patch set attached.

@michaelrsweet
Collaborator

CUPS.org User: stoatwblr

FWIW these patches don't get used when compiling cups 1.5 on rhel6

I assumed it's the avahi-client reference in dnssd.m4 that's causing it but converting that to avahi-libs doesn't work either.

@michaelrsweet
Collaborator

CUPS.org User: twaugh.redhat

Note that you need to run these commands after applying the patches:

aclocal -I config-scripts
autoconf -I config-scripts

@michaelrsweet
Collaborator

CUPS.org User: stoatwblr

Slightly further now - it's checking for avahi and then decides "no"

@michaelrsweet
Collaborator

CUPS.org User: twaugh.redhat

Did you supply '--enable-avahi' to configure? For a working Avahi-patched CUPS build, take a look at how it is done in e.g. Fedora.

@michaelrsweet
Collaborator

CUPS.org User: andyrtr

Can you please rebase the patch set for 1.5.1 release? thanks.

@michaelrsweet
Collaborator

CUPS.org User: stoatwblr

Yes I did use the --enable-avahi flags. Will look more closely at the Fedora builds. Thanks.

@michaelrsweet
Collaborator

CUPS.org User: stoatwblr

Tim: More RHELisms, I'm afraid:

aclocal -I config-scripts

/usr/share/aclocal/aalib.m4:12: warning: underquoted definition of AM_PATH_AALIB
/usr/share/aclocal/aalib.m4:12: run info '(automake)Extending aclocal'
/usr/share/aclocal/aalib.m4:12: or see http://sources.redhat.com/automake/automake.html#Extending-aclocal

Also, would you mind looking at what's needed to rebase to 1.5.2?

@michaelrsweet
Collaborator

CUPS.org User: twaugh.redhat

stoatwblr: I'm not sure what you mean. The warnings you are seeing are from a mistake in the aalib m4 macros -- they have no bearing on CUPS or Avahi, and are not responsible for any issues you may be seeing.

I've merged upstream cups changes into my patch set, for which a git repository can be obtained as follows:
git clone http://twaugh.fedorapeople.org/cups-avahi.git

The separate parts of the Avahi support are available as patches here:
http://twaugh.fedorapeople.org/cups-avahi/

Michael, is there any possibility that these patches will be merged into the CUPS source soon? I also have patches for trunk (although they are missing the needed libcups changes).. but I think Avahi support was targeted for 1.5 in any case.

@michaelrsweet
Collaborator

CUPS.org User: mike

OK, so I've started integrating this but the changes do not conform to the CUPS coding standards and break the existing mDNSResponder code...

@michaelrsweet
Collaborator

CUPS.org User: mike

OK, I'm just getting back to this to finish up the work. I think there is a serious issue with the dnssd implementation as it is doing a RESOLVE to get the TXT record. That is really not a good idea as it forces most devices to their full power state.

What we want to use here is a QUERY to get the TXT record, which means using avahi_record_browser_new to get the TXT record type.

Geez the Avahi documentation is awful...

@michaelrsweet
Collaborator

CUPS.org User: mike

Oh, and another side-effect of how this is currently implemented is that we will flood the network with resolves, which is also not good (will fail in many cases and is not nice since it can cause a DoS of the network...)

@michaelrsweet
Collaborator

CUPS.org User: mike

The _httpResolveURI changes also needed to be re-worked. There was no timeout after 90 seconds, no initial lookup for the service in the .local domain, and no reporting of offline/online status. I am also concerned about the use of the IP address in the resolved URI since that is often a VPN address for wide-area Bonjour. Will do some more testing to see if the glibc NSS stuff is working in recent Linux distros, since that is what we really want (so the hostname information is preserved in HTTP requests...)

@michaelrsweet
Collaborator

CUPS.org User: mike

OK, the resolve issue was caused by Fedora's default firewall settings (disables mDNS completely... sigh...)

@michaelrsweet
Collaborator

CUPS.org User: mike

OK, resolution and discovery are now working properly. Working on the registration code now...

FWIW, Avahi has a bad bug in avahi_simple_poll_iterate where the timeout value is not used: http://avahi.org/ticket/364

I've worked around the bug in question by implementing a custom poll function that uses the desired timeout...

@michaelrsweet
Collaborator

CUPS.org User: mike

OK, I've re-worked all of the DNS-SD functionality in cupsd; I have a few more things to change to properly support Avahi, but we are really close now...

@michaelrsweet
Collaborator

CUPS.org User: mike

OK, trunk now has mostly complete Avahi support in r10417. The one remaining task is to add browsing to the new cupsEnumDests() API.

The implementation in the scheduler is significantly different than provided, using the avahi_threaded_poll() path to avoid introducing the whole timeout interface and more complications.

@michaelrsweet
Collaborator

CUPS.org User: twaugh.redhat

Thanks!

@michaelrsweet
Collaborator

CUPS.org User: andyrtr

New 1.5.3 release requires the cups-avahi-2-backend.patch rebased and maybe more changes. Can you please have a look?

Hunk #6 FAILED at 131.
Hunk #7 FAILED at 145.

Thanks.
-Andy
ArchLinux

@michaelrsweet
Collaborator

CUPS.org User: mike

This is complete as of r10470.

@michaelrsweet
Collaborator

"cups-avahi-backend.patch":

diff --git a/backend/dnssd.c b/backend/dnssd.c
index ec32bba..a5d7a1b 100644
--- a/backend/dnssd.c
+++ b/backend/dnssd.c
@@ -20,7 +20,8 @@

  • browse_local_callback() - Browse local devices.
  • compare_devices() - Compare two devices.
  • get_device() - Create or update a device.
  • * query_callback() - Process query data.
  • * query_callback() - Process query data from DNS-SD
  • * find_device() - Process query data.
  • unquote() - Unquote a name string.
    */

@@ -30,7 +31,18 @@

#include "backend-private.h"
#include <cups/array.h>
-#include <dns_sd.h>
+#ifdef HAVE_AVAHI
+# include <avahi-client/client.h>
+# include <avahi-client/lookup.h>
+# include <avahi-common/address.h>
+# include <avahi-common/simple-watch.h>
+# include <avahi-common/domain.h>
+# include <avahi-common/error.h>
+typedef AvahiServiceBrowser DNSServiceRef;
+#define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX
+#else
+# include <dns_sd.h>
+#endif /
Avahi */

/*
@@ -49,7 +61,11 @@ typedef enum

typedef struct
{
+#ifdef HAVE_AVAHI

  • char address;
    +#else
    DNSServiceRef ref; /
    Service reference for resolve /
    +#endif /
    !HAVE_AVAHI /
    char *name, /
    Service name /
    *domain, /
    Domain name /
    *fullName, /
    Full name */
    @@ -65,6 +81,26 @@ typedef struct
  • Local functions...
    */

+#ifdef HAVE_AVAHI
+/*

  • * Avahi callback functions

  • */
    +static void avahi_client_callback(AvahiClient *client,

  •                 AvahiClientState state,
    
  •                 void *context);
    

    +static void avahi_browse_callback(AvahiServiceBrowser *browser,

  •                 AvahiIfIndex interface,
    
  •                 AvahiProtocol protocol,
    
  •                 AvahiBrowserEvent event,
    
  •                 const char *serviceName,
    
  •                 const char *regtype,
    
  •                 const char *replyDomain,
    
  •                 AvahiLookupResultFlags flags,
    
  •                 void _context);
    

    +#else
    +/_

  • * libdns_sd callback functions

  • _/
    static void browse_callback(DNSServiceRef sdRef,
    DNSServiceFlags flags,
    uint32_t interfaceIndex,
    @@ -80,12 +116,6 @@ static void browse_local_callback(DNSServiceRef sdRef,
    const char *regtype,
    const char *replyDomain,
    void *context);
    -static int compare_devices(cups_device_t *a, cups_device_t *b);
    -static void exec_backend(char *_argv);
    -static cups_device_t *get_device(cups_array_t *devices,

  •                   const char *serviceName,
    
  •                   const char *regtype,
    
  •               const char *replyDomain);
    

    static void query_callback(DNSServiceRef sdRef,
    DNSServiceFlags flags,
    uint32_t interfaceIndex,
    @@ -94,7 +124,31 @@ static void query_callback(DNSServiceRef sdRef,
    uint16_t rrclass, uint16_t rdlen,
    const void *rdata, uint32_t ttl,
    void *context);
    +#endif
    +
    +static cups_device_t *find_device (cups_array_t *devices,

  •              cups_device_t *key,
    
  •              const char *priority, size_t priority_len,
    
  •              const char *mfg, size_t mfg_len,
    
  •              const char *mdl, size_t mdl_len,
    
  •              const char *product, size_t product_len,
    
  •              const char *ty, size_t ty_len,
    
  •              const char *printer_type,
    
  •              size_t printer_type_len);
    

    +static int compare_devices(cups_device_t _a, cups_device_t *b);
    +static void exec_backend(char *_argv);
    +static cups_device_t *get_device(cups_array_t *devices,

  •                   const char *serviceName,
    
  •                   const char *regtype,
    
  •               const char *replyDomain);
    

    static void unquote(char dst, const char *src, size_t dstsize);
    +static int device_type(const char *regtype);
    +
    +
    +#ifdef HAVE_AVAHI
    +static AvahiSimplePoll *simple_poll = NULL;
    +static int avahi_got_callback;
    +#endif /
    HAVE_AVAHI */

    /*
    @@ -122,6 +176,10 @@ main(int argc, /* I - Number of command-line args /
    struct timeval timeout; /
    Timeout for select() /
    cups_array_t *devices; /
    Device array /
    cups_device_t *device; /
    Current device */
    +#ifdef HAVE_AVAHI

  • AvahiClient *client;

  • int error;
    +#endif /* HAVE_AVAHI */

/*
@@ -161,6 +219,48 @@ main(int argc, /* I - Number of command-line args */

  • Browse for different kinds of printers...
    */

+#ifdef HAVE_AVAHI

  • if ((simple_poll = avahi_simple_poll_new ()) == NULL)
  • {
  • perror ("ERROR: Unable to create avahi simple poll object");
  • return (1);
  • }
  • client = avahi_client_new (avahi_simple_poll_get (simple_poll),
  •            0, avahi_client_callback, NULL, &error);
    
  • if (!client)
  • {
  • perror ("ERROR: Unable to create avahi client");
  • return (1);
  • }
  • fax_ipp_ref = avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •                  AVAHI_PROTO_UNSPEC,
    
  •                  "_fax-ipp._tcp", NULL, 0,
    
  •                  avahi_browse_callback, devices);
    
  • ipp_ref = avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •                  AVAHI_PROTO_UNSPEC,
    
  •                  "_ipp._tcp", NULL, 0,
    
  •                  avahi_browse_callback, devices);
    
  • ipp_tls_ref = avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •                  AVAHI_PROTO_UNSPEC,
    
  •                  "_ipp-tls._tcp", NULL, 0,
    
  •                  avahi_browse_callback, devices);
    
  • pdl_datastream_ref = avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •                     AVAHI_PROTO_UNSPEC,
    
  •                     "_pdl-datastream._tcp",
    
  •                     NULL, 0,
    
  •                     avahi_browse_callback,
    
  •                     devices);
    
  • printer_ref = avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •                  AVAHI_PROTO_UNSPEC,
    
  •                  "_printer._tcp", NULL, 0,
    
  •                  avahi_browse_callback, devices);
    
  • riousbprint_ref = avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •                      AVAHI_PROTO_UNSPEC,
    
  •                      "_riousbprint._tcp", NULL, 0,
    
  •                      avahi_browse_callback, devices);
    

    +#else
    if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError)
    {
    perror("ERROR: Unable to create service connection");
    @@ -212,6 +312,7 @@ main(int argc, /* I - Number of command-line args _/
    riousbprint_ref = main_ref;
    DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0,
    "_riousbprint.tcp", NULL, browse_callback, devices);
    +#endif /
    !HAVE_AVAHI */

    /*

    • Loop until we are killed...
      @@ -219,6 +320,18 @@ main(int argc, /* I - Number of command-line args */

    for (;;)
    {

  • int announce = 0;

+#ifdef HAVE_AVAHI

  • int r;
  • avahi_got_callback = 0;
  • r = avahi_simple_poll_iterate (simple_poll, 1);
  • if (r != 0 && r != EINTR)
  •  break;
    
  • if (avahi_got_callback)
  •  announce = 1;
    
    +#else
    FD_ZERO(&input);
    FD_SET(fd, &input);

@@ -238,11 +351,19 @@ main(int argc, /* I - Number of command-line args */
}
else
{

  •  announce = 1;
    
  • }
    +#endif /* !HAVE_AVAHI */
  • if (announce)
  • {
    /*
  • Announce any devices we've found...
    */

+#ifndef HAVE_AVAHI
DNSServiceErrorType status; /* DNS query status /
+#endif /
!HAVE_AVAHI /
cups_device_t *best; /
Best matching device /
char device_uri[1024]; /
Device URI /
int count; /
Number of queries /
@@ -255,6 +376,7 @@ main(int argc, /
I - Number of command-line args /
best = NULL, count = 0;
device;
device = (cups_device_t *)cupsArrayNext(devices))
+#ifndef HAVE_AVAHI
if (!device->ref && !device->sent)
{
/

@@ -283,23 +405,36 @@ main(int argc, /* I - Number of command-line args */
count ++;
}
}

  • else if (!device->sent)
  • else
    +#endif /* !HAVE_AVAHI */
  • if (!device->sent)
    {
    +#ifndef HAVE_AVAHI
    /*

  • Got the TXT records, now report the device...
    */

    DNSServiceRefDeallocate(device->ref);
    device->ref = 0;
    +#endif /* !HAVE_AVAHI */

    if (!best)
    best = device;
    else if (strcasecmp(best->name, device->name) ||
    strcasecmp(best->domain, device->domain))
    {
    +#ifdef HAVE_AVAHI

  •   httpAssembleURIf(HTTP_URI_CODING_ALL, 
    
  •            device_uri, sizeof(device_uri),
    
  •            schemes[best->type], NULL, best->address, 0,
    
  •            "/%s%s", best->cups_shared ? "/printers/" : "",
    
  •            best->name);
    

    +#else
    httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri),
    schemes[best->type], NULL, best->fullName, 0,
    best->cups_shared ? "/cups" : "/");
    +#endif /* HAVE_AVAHI */

    cupsBackendReport("network", device_uri, best->make_and_model,
                      best->name, NULL, NULL);
    

    @@ -319,9 +454,17 @@ main(int argc, /* I - Number of command-line args */

    if (best)
    {

  • httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri),

  •       schemes[best->type], NULL, best->fullName, 0,
    
  •       best->cups_shared ? "/cups" : "/");
    

    +#ifdef HAVE_AVAHI

  •   httpAssembleURIf(HTTP_URI_CODING_ALL,
    
  •            device_uri, sizeof(device_uri),
    
  •            schemes[best->type], NULL, best->address, 0,
    
  •            "/%s%s", best->cups_shared ? "/printers/" : "",
    
  •            best->name);
    

    +#else

  •   httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri),
    
  •           schemes[best->type], NULL, best->fullName, 0,
    
  •           best->cups_shared ? "/cups" : "/");
    

    +#endif /* HAVE_AVAHI */

    cupsBackendReport("network", device_uri, best->make_and_model,
    best->name, NULL, NULL);
    @@ -332,6 +475,164 @@ main(int argc, /* I - Number of command-line args */
    }

+#ifdef HAVE_AVAHI
+static void
+avahi_client_callback(

  • AvahiClient *client,
  • AvahiClientState state,
  • void *context)
    +{
  • fprintf (stderr, "DEBUG: client callback, %d\n", state);
    +}

+static void
+avahi_query_callback(

  • AvahiServiceResolver *resolver,
  • 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 *context)
    +{
  • AvahiClient *client = avahi_service_resolver_get_client (resolver);
  • AvahiStringList *pair;
  • cups_device_t key,
  •   *device;
    
  • char uqname[1024],
  •   *ptr;
    
  • char *priority = NULL,
  •   *mfg = NULL,
    
  •   *mdl = NULL,
    
  •   *product = NULL,
    
  •   *ty = NULL,
    
  •   *printer_type = NULL;
    
  • size_t priority_len = 0,
  •   mfg_len = 0,
    
  •   mdl_len = 0,
    
  •   product_len = 0,
    
  •   ty_len = 0,
    
  •   printer_type_len = 0;
    
  • if (event == AVAHI_RESOLVER_FAILURE)
  • {
  • fprintf (stderr, "ERROR: %s\n",
  •    avahi_strerror (avahi_client_errno (client)));
    
  • avahi_service_resolver_free (resolver);
  • return;
  • }
  • if (event != AVAHI_RESOLVER_FOUND)
  • {
  • avahi_service_resolver_free (resolver);
  • }
  • key.name = uqname;
  • unquote (uqname, name, sizeof (uqname));
  • if ((ptr = strstr(name, "._")) != NULL)
  • *ptr = '\0';
  • key.domain = domain;
  • key.type = device_type (type);
  • if ((pair = avahi_string_list_find (txt, "priority")) != NULL)
  • avahi_string_list_get_pair (pair, NULL, &priority, &priority_len);
  • if ((pair = avahi_string_list_find (txt, "usb_MFG")) == NULL)
  • pair = avahi_string_list_find (txt, "usb_MANUFACTURER");
  • if (pair != NULL)
  • avahi_string_list_get_pair (pair, NULL, &mfg, &mfg_len);
  • if ((pair = avahi_string_list_find (txt, "usb_MDL")) == NULL)
  • pair = avahi_string_list_find (txt, "usb_MODEL");
  • if (pair != NULL)
  • avahi_string_list_get_pair (pair, NULL, &mdl, &mdl_len);
  • if ((pair = avahi_string_list_find (txt, "product")) != NULL)
  • avahi_string_list_get_pair (pair, NULL, &product, &product_len);
  • if ((pair = avahi_string_list_find (txt, "ty")) != NULL)
  • avahi_string_list_get_pair (pair, NULL, &ty, &ty_len);
  • if ((pair = avahi_string_list_find (txt, "printer-type")) != NULL)
  • avahi_string_list_get_pair (pair, NULL, &printer_type, &printer_type_len);
  • device = find_device ((cups_array_t *) context,
  •       &key,
    
  •       priority, priority_len,
    
  •       mfg, mfg_len,
    
  •       mdl, mdl_len,
    
  •       product, product_len,
    
  •       ty, ty_len,
    
  •       printer_type, printer_type_len);
    
  • if (device)
  • {
  • device->address = malloc (AVAHI_ADDRESS_STR_MAX);
  • avahi_address_snprint (device->address, AVAHI_ADDRESS_STR_MAX, address);
  • avahi_got_callback = 1;
  • }
  • else
  • fprintf (stderr, "DEBUG: Ignoring TXT record for "%s"...\n", name);
  • avahi_service_resolver_free (resolver);
    +}

+static void
+avahi_browse_callback(

  • AvahiServiceBrowser *browser,
  • AvahiIfIndex interface,
  • AvahiProtocol protocol,
  • AvahiBrowserEvent event,
  • const char *name,
  • const char *type,
  • const char *domain,
  • AvahiLookupResultFlags flags,
  • void *context)
    +{
  • AvahiClient *client = avahi_service_browser_get_client (browser);
  • switch (event)
  • {
  • case AVAHI_BROWSER_FAILURE:
  • fprintf (stderr, "ERROR: %s\n",
  •    avahi_strerror (avahi_client_errno (client)));
    
  • avahi_simple_poll_quit (simple_poll);
  • return;
  • case AVAHI_BROWSER_NEW:
  • if (flags & AVAHI_LOOKUP_RESULT_LOCAL)
  • {
  •  fprintf (stderr, "DEBUG: ignoring local service %s\n", name);
    
  • }
  • else
  • {
  •  get_device ((cups_array_t *)context, name, type, domain);
    
  •  if (avahi_service_resolver_new (client, interface, protocol,
    
  •                 name, type, domain,
    
  •                 AVAHI_PROTO_UNSPEC, 0,
    
  •                 avahi_query_callback, context) == NULL)
    
  •  {
    
  • fprintf (stderr, "ERROR: failed to resolve service %s: %s\n",
  •    name, avahi_strerror (avahi_client_errno (client)));
    
  •  }
    
  • }
  • break;
  • case AVAHI_BROWSER_REMOVE:
  • case AVAHI_BROWSER_ALL_FOR_NOW:
  • case AVAHI_BROWSER_CACHE_EXHAUSTED:
  • break;
  • }
    +}

+#else /* !HAVE_AVAHI /
/

  • 'browse_callback()' - Browse devices.
    /
    @@ -420,6 +721,7 @@ browse_local_callback(
    device->fullName);
    device->sent = 1;
    }
    +#endif /
    !HAVE_AVAHI */

/*
@@ -518,18 +820,7 @@ get_device(cups_array_t devices, / I - Device array */

key.name = (char *)serviceName;

key.domain = (char *)replyDomain;

  • if (!strcmp(regtype, "_ipp._tcp.") ||
  •  !strcmp(regtype, "_ipp-tls._tcp."))
    
  • key.type = CUPS_DEVICE_IPP;
  • else if (!strcmp(regtype, "_fax-ipp._tcp."))
  • key.type = CUPS_DEVICE_FAX_IPP;
  • else if (!strcmp(regtype, "_printer._tcp."))
  • key.type = CUPS_DEVICE_PRINTER;
  • else if (!strcmp(regtype, "_pdl-datastream._tcp."))
  • key.type = CUPS_DEVICE_PDL_DATASTREAM;
  • else
  • key.type = CUPS_DEVICE_RIOUSBPRINT;
  • key.type = device_type (regtype);

for (device = cupsArrayFind(devices, &key);
device;
@@ -559,13 +850,20 @@ get_device(cups_array_t devices, / I - Device array */

  • Set the "full name" of this service, which is used for queries...
    */

+#ifdef HAVE_AVAHI

  • avahi_service_name_join (fullName, kDNSServiceMaxDomainName,
  •          serviceName, regtype, replyDomain);
    
  • device->fullName = strdup(fullName);
    +#else
    DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain);
    device->fullName = strdup(fullName);
    +#endif /* !HAVE_AVAHI */

return (device);
}

+#ifndef HAVE_AVAHI
/*

  • 'query_callback()' - Process query data.
    /
    @@ -584,12 +882,21 @@ query_callback(
    uint32_t ttl, /
    I - Time-to-live /
    void *context) /
    I - Devices array */
    {

    • cups_array_t devices; / Device array /
      char name[1024], /
      Service name /
      *ptr; /
      Pointer into name */
    • cups_device_t key, /* Search key */

    - device; / Device */

    • cups_device_t key; /* Search key */
    • const char *priority,
    •   *mfg,
      
    •   *mdl,
      
    •   *product,
      
    •   *ty,
      
    •   *printer_type;
      
    • uint8_t priority_len,
    •   mfg_len,
      
    •   mdl_len,
      
    •   product_len,
      
    •   ty_len,
      
    •   printer_type_len;
      

    fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, "
    "interfaceIndex=%d, errorCode=%d, fullName="%s", "
    @@ -610,7 +917,6 @@ query_callback(

    • Lookup the service in the devices array.
      */
  • devices = (cups_array_t *)context;
    key.name = name;

unquote(name, fullName, sizeof(name));
@@ -635,88 +941,111 @@ query_callback(
else
key.type = CUPS_DEVICE_RIOUSBPRINT;

  • for (device = cupsArrayFind(devices, &key);
  • priority = TXTRecordGetValuePtr(rdlen, rdata, "priority", &priority_len);
  • if ((mfg = TXTRecordGetValuePtr(rdlen, rdata, "usb_MFG", &mfg_len)) == NULL)
  • mfg = TXTRecordGetValuePtr(rdlen, rdata, "usb_MANUFACTURER", &mfg_len);
  • if ((mdl = TXTRecordGetValuePtr(rdlen, rdata, "usb_MDL", &mdl_len)) == NULL)
  • mdl = TXTRecordGetValuePtr(rdlen, rdata, "usb_MODEL", &mdl_len);
  • product = TXTRecordGetValuePtr(rdlen, rdata, "product", &product_len);
  • ty = TXTRecordGetValuePtr(rdlen, rdata, "ty", &ty_len);
  • printer_type = TXTRecordGetValuePtr(rdlen, rdata, "printer-type",
  •                 &printer_type_len);
    
  • if (!find_device ((cups_array_t *) context,
  •       &key,
    
  •       priority, priority_len,
    
  •       mfg, mfg_len,
    
  •       mdl, mdl_len,
    
  •       product, product_len,
    
  •       ty, ty_len,
    
  •       printer_type, printer_type_len))
    
  • fprintf(stderr, "DEBUG: Ignoring TXT record for "%s"...\n", fullName);
    +}
    +#endif /* !HAVE_AVAHI */

+static cups_device_t *
+find_device (cups_array_t *devices,

  •    cups_device_t *key,
    
  •    const char *priority, size_t priority_len,
    
  •    const char *mfg, size_t mfg_len,
    
  •    const char *mdl, size_t mdl_len,
    
  •    const char *product, size_t product_len,
    
  •    const char *ty, size_t ty_len,
    
  •    const char *printer_type, size_t printer_type_len)
    
    +{
  • cups_device_t *device;
  • for (device = cupsArrayFind(devices, key);
    device;
    device = cupsArrayNext(devices))
    {
  • if (strcasecmp(device->name, key.name) ||
  •    strcasecmp(device->domain, key.domain))
    
  • if (strcasecmp(device->name, key->name) ||
  •    strcasecmp(device->domain, key->domain))
    
    {
    device = NULL;
    break;
    }
  • else if (device->type == key.type)
  • else if (device->type == key->type)
    {
    /*
  • Found it, pull out the priority and make and model from the TXT
  • record and save it...
    */
  •  const void *value;       /* Pointer to value */
    
  •  uint8_t  valueLen;       /\* Length of value (max 255) _/
    
    char make_and_model[512], /_ Manufacturer and model /
    model[256], /
    Model */

- priority[256]; /* Priority */

  •   priority_buf[256],  /\* Priority */
    
  •   *ptr;
    
  •  value = TXTRecordGetValuePtr(rdlen, rdata, "priority", &valueLen);
    
  •  if (value && valueLen)
    
  •  if (priority && priority_len)
    
    {
  • memcpy(priority, value, valueLen);
  • priority[valueLen] = '\0';
  • device->priority = atoi(priority);
  • memcpy(priority_buf, priority, priority_len);
  • priority_buf[priority_len] = '\0';
  • device->priority = atoi(priority_buf);
    }
  •  if ((value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MFG",
    
  •               &valueLen)) == NULL)
    
  • value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MANUFACTURER",

- &valueLen);

  •  if (value && valueLen)
    
  •  if (mfg && mfg_len)
    
    {
  • memcpy(make_and_model, value, valueLen);
  • make_and_model[valueLen] = '\0';
  • memcpy(make_and_model, mfg, mfg_len);
  • make_and_model[mfg_len] = '\0';
    }
    else
    make_and_model[0] = '\0';
  •  if ((value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MDL",
    
  •               &valueLen)) == NULL)
    

- value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MODEL", &valueLen);

  •  if (value && valueLen)
    
  •  if (mdl && mdl_len)
    

    {

  • memcpy(model, value, valueLen);

  • model[valueLen] = '\0';

  • memcpy(model, mdl, mdl_len);

  • model[mdl_len] = '\0';
    }

  •  else if ((value = TXTRecordGetValuePtr(rdlen, rdata, "product",
    
  •                    &valueLen)) != NULL && valueLen > 2)
    
  •  else if (product && product_len > 2)
    

    {

  • if (((char *)value)[0] == '(')

  • if (product[0] == '(')
    {
    /*

  • Strip parenthesis...
    */

  • memcpy(model, value + 1, valueLen - 2);
    
  • model[valueLen - 2] = '\0';
    
  • memcpy(model, product + 1, product_len - 2);
    
  • model[product_len - 2] = '\0';
    

    }
    else
    {

  • memcpy(model, value, valueLen);
    
  • model[valueLen] = '\0';
    
  • memcpy(model, product, product_len);
    
  • model[product_len] = '\0';
    

    }

    if (!strcasecmp(model, "GPL Ghostscript") ||
    !strcasecmp(model, "GNU Ghostscript") ||
    !strcasecmp(model, "ESP Ghostscript"))
    {

  • if ((value = TXTRecordGetValuePtr(rdlen, rdata, "ty",
    
  •                   &valueLen)) != NULL)
    
  • if (ty && ty_len)
    

    {

  •   memcpy(model, value, valueLen);
    
  •   model[valueLen] = '\0';
    
  •   memcpy(model, ty, ty_len);
    
  •   model[ty_len] = '\0';
    
    if ((ptr = strchr(model, ',')) != NULL)
      *ptr = '\0';
    

    @@ -742,7 +1071,7 @@ query_callback(

    if ((device->type == CUPS_DEVICE_IPP ||
    device->type == CUPS_DEVICE_PRINTER) &&

  • TXTRecordGetValuePtr(rdlen, rdata, "printer-type", &valueLen))
    
  • printer_type)
    

    {
    /*

    • This is a CUPS printer!
      @@ -758,8 +1087,7 @@ query_callback(
      }
      }
  • if (!device)

  • fprintf(stderr, "DEBUG: Ignoring TXT record for "%s"...\n", fullName);

  • return device;
    }

@@ -797,6 +1125,35 @@ unquote(char dst, / I - Destination buffer */
}

+static int
+device_type (const char *regtype)
+{
+#ifdef HAVE_AVAHI

  • if (!strcmp(regtype, "_ipp._tcp") ||
  •  !strcmp(regtype, "_ipp-tls._tcp"))
    
  • return (CUPS_DEVICE_IPP);
  • else if (!strcmp(regtype, "_fax-ipp._tcp"))
  • return (CUPS_DEVICE_FAX_IPP);
  • else if (!strcmp(regtype, "_printer._tcp"))
  • return (CUPS_DEVICE_PRINTER);
  • else if (!strcmp(regtype, "_pdl-datastream._tcp"))
  • return (CUPS_DEVICE_PDL_DATASTREAM);
    +#else
  • if (!strcmp(regtype, "_ipp._tcp.") ||
  •  !strcmp(regtype, "_ipp-tls._tcp."))
    
  • return (CUPS_DEVICE_IPP);
  • else if (!strcmp(regtype, "_fax-ipp._tcp."))
  • return (CUPS_DEVICE_FAX_IPP);
  • else if (!strcmp(regtype, "_printer._tcp."))
  • return (CUPS_DEVICE_PRINTER);
  • else if (!strcmp(regtype, "_pdl-datastream._tcp."))
  • return (CUPS_DEVICE_PDL_DATASTREAM);
    +#endif /* !HAVE_AVAHI */
  • return (CUPS_DEVICE_RIOUSBPRINT);
    +}

/*

  • End of "$Id$".
    */
    diff --git a/config-scripts/cups-dnssd.m4 b/config-scripts/cups-dnssd.m4
    index 55829cf..7dc3e0b 100644
    --- a/config-scripts/cups-dnssd.m4
    +++ b/config-scripts/cups-dnssd.m4
    @@ -46,6 +46,18 @@ if test x$enable_dnssd != xno; then
    ;;
    esac
    ])
    +
  • AC_CHECK_HEADER(avahi-client/client.h, [
  •   case "$uname" in
    
  •        Linux*)
    
  •           # Linux, using Avahi.
    
  •           DNSSDLIBS="-lavahi-common -lavahi-client -ldns_sd"
    
  •           AC_DEFINE(HAVE_DNSSD)
    
  •           AC_DEFINE(HAVE_AVAHI)
    
  •           DNSSD_BACKEND="dnssd"
    
  •           ;;
    
  •   esac
    
  • ])
    fi

AC_SUBST(DNSSDLIBS)
diff --git a/config.h.in b/config.h.in
index e657b09..84df2a3 100644
--- a/config.h.in
+++ b/config.h.in
@@ -344,6 +344,13 @@

/*

  • * Does DNS Service Discovery use Avahi?
  • /
    +
    +#undef HAVE_AVAHI
    +
    +
    +/
    • Do we have <sys/ioctl.h>?
      */
@michaelrsweet
Collaborator

"0001-New-enable-avahi-configure-option.patch":

From d948ecde8d30db6fbf5688d9caf2592c7c09577d Mon Sep 17 00:00:00 2001
From: Tim Waugh twaugh@redhat.com
Date: Tue, 4 Jan 2011 15:26:26 +0000
Subject: [PATCH 1/4] New --enable-avahi configure option.

Currently has no effect.

config-scripts/cups-dnssd.m4 | 15 +++++++++++++++
config.h.in | 7 +++++++
2 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/config-scripts/cups-dnssd.m4 b/config-scripts/cups-dnssd.m4
index 0f582fc..48fb7ab 100644
--- a/config-scripts/cups-dnssd.m4
+++ b/config-scripts/cups-dnssd.m4
@@ -27,6 +27,21 @@ AC_ARG_WITH(dnssd-includes, [ --with-dnssd-includes set directory for DNS Ser
DNSSDLIBS=""
DNSSD_BACKEND=""

+AC_ARG_ENABLE(avahi, [ --enable-avahi turn on DNS Service Discovery support, default=no],

  •     [if test x$enable_avahi = xyes; then
    
  •          AC_MSG_CHECKING(for Avahi)
    
  •          if $PKGCONFIG --exists avahi-client; then
    
  •              AC_MSG_RESULT(yes)
    
  •              CFLAGS="$CFLAGS `$PKGCONFIG --cflags avahi-client`"
    
  •              DNSSDLIBS="`$PKGCONFIG --libs avahi-client`"
    
  •              DNSSD_BACKEND="dnssd"
    
  •              AC_DEFINE(HAVE_AVAHI)
    
  •              enable_dnssd=no
    
  •          else
    
  •              AC_MSG_RESULT(no)
    
  •          fi
    
  •      fi])
    

    if test x$enable_dnssd != xno; then
    AC_CHECK_HEADER(dns_sd.h, [
    case "$uname" in
    diff --git a/config.h.in b/config.h.in
    index ed3df38..4e2301c 100644
    --- a/config.h.in
    +++ b/config.h.in
    @@ -365,6 +365,13 @@

    /*

  • * Do we have Avahi for DNS Service Discovery?

  • /
    +
    +#undef HAVE_AVAHI
    +
    +
    +/

    • Do we have <sys/ioctl.h>?
      */

1.7.3.4

@michaelrsweet
Collaborator

"0002-Avahi-support-in-the-dnssd-backend.patch":

From 5e72ac0b42633facc875ab46d1601b59aed60d13 Mon Sep 17 00:00:00 2001
From: Tim Waugh twaugh@redhat.com
Date: Wed, 29 Jul 2009 13:45:35 +0100
Subject: [PATCH 2/4] Avahi support in the dnssd backend.


backend/dnssd.c | 580 +++++++++++++++++++++++++++++++++++++++++++-------
cups/http-support.c | 191 +++++++++++++++++-
2 files changed, 687 insertions(+), 84 deletions(-)

diff --git a/backend/dnssd.c b/backend/dnssd.c
index 57ecc6c..8e08271 100644
--- a/backend/dnssd.c
+++ b/backend/dnssd.c
@@ -15,14 +15,21 @@
*

  • Contents:
    *
    • * next_txt_record() - Get next TXT record from a cups_txt_records_t.
    • * parse_txt_record_pair() - Read key/value pair in cups_txt_records_t.
  • main() - Browse for printers.
  • browse_callback() - Browse devices.
  • browse_local_callback() - Browse local devices.
  • compare_devices() - Compare two devices.
  • exec_backend() - Execute the backend that corresponds to the
  •                         resolved service name.
    
    • * device_type() - Get DNS-SD type enumeration from string.
  • get_device() - Create or update a device.
  • query_callback() - Process query data.
  • * avahi_client_callback() - Avahi client callback function.
  • * avahi_query_callback() - Avahi query callback function.
  • * avahi_browse_callback() - Avahi browse callback function.
  • * find_device() - Find a device from its name and domain.
  • sigterm_handler() - Handle termination signals...
  • unquote() - Unquote a name string.
    */
    @@ -33,7 +40,18 @@

#include "backend-private.h"
#include <cups/array.h>
-#include <dns_sd.h>
+#ifdef HAVE_DNSSD
+# include <dns_sd.h>
+#endif /* HAVE_DNSSD /
+#ifdef HAVE_AVAHI
+# include <avahi-client/client.h>
+# include <avahi-client/lookup.h>
+# include <avahi-common/simple-watch.h>
+# include <avahi-common/domain.h>
+# include <avahi-common/error.h>
+# include <avahi-common/malloc.h>
+#define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX
+#endif /
HAVE_AVAHI */

/*
@@ -52,7 +70,12 @@ typedef enum

typedef struct
{
+#ifdef HAVE_DNSSD
DNSServiceRef ref; /* Service reference for resolve /
+#endif /
HAVE_DNSSD */
+#ifdef HAVE_AVAHI

  • int resolved; /* Did we resolve the device? /
    +#endif /
    HAVE_AVAHI /
    char *name, /
    Service name /
    *domain, /
    Domain name /
    *fullName, /
    Full name /
    @@ -64,6 +87,20 @@ typedef struct
    sent; /
    Did we list the device? */
    } cups_device_t;

+typedef struct
+{

  • char key[256];
  • char value[256];

+#ifdef HAVE_DNSSD

  • const uint8_t *data;
  • const uint8_t *datanext;
  • const uint8_t dataend;
    +#else /
    HAVE_AVAHI */
  • AvahiStringList txt;
    +#endif /
    HAVE_DNSSD */
    +} cups_txt_records_t;

/*

  • Local globals...
    @@ -77,6 +114,7 @@ static int job_canceled = 0;
  • Local functions...
    */

+#ifdef HAVE_DNSSD
static void browse_callback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
@@ -92,12 +130,6 @@ static void browse_local_callback(DNSServiceRef sdRef,
const char _regtype,
const char *replyDomain,
void *context);
-static int compare_devices(cups_device_t *a, cups_device_t *b);
-static void exec_backend(char *_argv);
-static cups_device_t *get_device(cups_array_t *devices,

  •                   const char *serviceName,
    
  •                   const char *regtype,
    
  •               const char _replyDomain);
    
    static void query_callback(DNSServiceRef sdRef,
    DNSServiceFlags flags,
    uint32_t interfaceIndex,
    @@ -106,9 +138,118 @@ static void query_callback(DNSServiceRef sdRef,
    uint16_t rrclass, uint16_t rdlen,
    const void *rdata, uint32_t ttl,
    void *context);
    +#endif /_ HAVE_DNSSD */
    +#ifdef HAVE_AVAHI
    +static void avahi_client_callback (AvahiClient *client,
  •                      AvahiClientState state,
    
  •                      void *context);
    
    +static void avahi_browse_callback (AvahiServiceBrowser *browser,
  •                      AvahiIfIndex interface,
    
  •                      AvahiProtocol protocol,
    
  •                      AvahiBrowserEvent event,
    
  •                      const char *serviceName,
    
  •                      const char *regtype,
    
  •                      const char *replyDomain,
    
  •                      AvahiLookupResultFlags flags,
    
  •                      void _context);
    
    +#endif /_ HAVE_AVAHI */
    +
    +static cups_device_t * find_device (cups_array_t *devices,
  •                cups_txt_records_t *txt,
    
  •                cups_device_t _dkey);
    
    +static int compare_devices(cups_device_t *a, cups_device_t *b);
    +static void exec_backend(char *_argv);
    +static cups_device_t *get_device(cups_array_t *devices,
  •                   const char *serviceName,
    
  •                   const char *regtype,
    
  •               const char *replyDomain);
    
    static void sigterm_handler(int sig);
    static void unquote(char *dst, const char *src, size_t dstsize);

+#ifdef HAVE_AVAHI
+static AvahiSimplePoll simple_poll = NULL;
+static int avahi_got_callback;
+#endif /
HAVE_AVAHI /
+
+
+/

  • * 'next_txt_record()' - Get next TXT record from a cups_txt_records_t.
  • */
    +
    +static cups_txt_records_t *
    +next_txt_record (cups_txt_records_t *txt)
    +{
    +#ifdef HAVE_DNSSD
  • txt->data = txt->datanext;
    +#else /* HAVE_AVAHI */
  • txt->txt = avahi_string_list_get_next (txt->txt);
  • if (txt->txt == NULL)
  • return NULL;
    +#endif /* HAVE_DNSSD */
  • return txt;
    +}

+/*

  • * 'parse_txt_record_pair()' - Read key/value pair in cups_txt_records_t.
  • */
    +
    +static int
    +parse_txt_record_pair (cups_txt_records_t *txt)
    +{
    +#ifdef HAVE_DNSSD
  • uint8_t datalen;
  • uint8_t *data = txt->data;
  • char *ptr;
  • /*
  • * Read a key/value pair starting with an 8-bit length. Since the
  • * length is 8 bits and the size of the key/value buffers is 256, we
  • * don't need to check for overflow...
  • */
  • datalen = *data++;
  • if (!datalen || (data + datalen) >= txt->dataend)
  • return NULL;
  • txt->datanext = data + datalen;
  • for (ptr = txt->key; data < txt->datanext && *data != '='; data ++)
  • *ptr++ = *data;
  • *ptr = '\0';
  • if (data < txt->datanext && *data == '=')
  • {
  • data++;
  • if (data < datanext)
  •  memcpy (txt->value, data, txt->datanext - data);
    
  • value[txt->datanext - data] = '\0';
  • }
  • else
  • return 1;
    +#else /* HAVE_AVAHI */
  • char *key, *value;
  • size_t len;
  • avahi_string_list_get_pair (txt->txt, &key, &value, &len);
  • if (len > sizeof (txt->value) - 1)
  • len = sizeof (txt->value) - 1;
  • memcpy (txt->value, value, len);
  • txt->value[len] = '\0';
  • len = strlen (key);
  • if (len > sizeof (txt->key) - 1)
  • len = sizeof (txt->key) - 1;
  • memcpy (txt->key, key, len);
  • txt->key[len] = '\0';
  • avahi_free (key);
  • avahi_free (value);
    +#endif /* HAVE_AVAHI */
  • return 0;
    +}

/*

  • 'main()' - Browse for printers.
    @@ -119,6 +260,13 @@ main(int argc, /* I - Number of command-line args /
    char *argv[]) /
    I - Command-line arguments /
    {
    const char *name; /
    Backend name */
  • cups_array_t devices; / Device array */
  • cups_device_t device; / Current device */
  • char uriName[1024]; /* Unquoted fullName for URI */
    +#ifdef HAVE_DNSSD
  • int fd; /* Main file descriptor */
  • fd_set input; /* Input set for select() */
  • struct timeval timeout; /* Timeout for select() /
    DNSServiceRef main_ref, /
    Main service reference /
    fax_ipp_ref, /
    IPP fax service reference /
    ipp_ref, /
    IPP service reference /
    @@ -130,12 +278,11 @@ main(int argc, /
    I - Number of command-line args /
    pdl_datastream_ref, /
    AppSocket service reference /
    printer_ref, /
    LPD service reference /
    riousbprint_ref; /
    Remote IO service reference */
  • int fd; /* Main file descriptor */
  • fd_set input; /* Input set for select() */
  • struct timeval timeout; /* Timeout for select() */
  • cups_array_t devices; / Device array */
  • cups_device_t device; / Current device */
  • char uriName[1024]; /* Unquoted fullName for URI /
    +#endif /
    HAVE_DNSSD */
    +#ifdef HAVE_AVAHI
  • AvahiClient *client;
  • int error;
    +#endif /* HAVE_AVAHI /
    #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
    struct sigaction action; /
    Actions for POSIX signals /
    #endif /
    HAVE_SIGACTION && !HAVE_SIGSET /
    @@ -195,6 +342,49 @@ main(int argc, /
    I - Number of command-line args */
  • Browse for different kinds of printers...
    */

+#ifdef HAVE_AVAHI

  • if ((simple_poll = avahi_simple_poll_new ()) == NULL)
  • {
  • perror ("ERROR: Unable to create avahi simple poll object");
  • return (1);
  • }
  • client = avahi_client_new (avahi_simple_poll_get (simple_poll),
  •            0, avahi_client_callback, NULL, &error);
    
  • if (!client)
  • {
  • perror ("DEBUG: Unable to create avahi client");
  • return (0);
  • }
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_fax-ipp._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_ipp._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_ipp-tls._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_pdl-datastream._tcp",
    
  •            NULL, 0,
    
  •            avahi_browse_callback,
    
  •            devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_printer._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_riousbprint._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    

    +#endif /* HAVE_AVAHI /
    +#ifdef HAVE_DNSSD
    if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError)
    {
    perror("ERROR: Unable to create service connection");
    @@ -246,6 +436,7 @@ main(int argc, /
    I - Number of command-line args _/
    riousbprint_ref = main_ref;
    DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0,
    "_riousbprint.tcp", NULL, browse_callback, devices);
    +#endif /
    HAVE_DNSSD */

    /*

    • Loop until we are killed...
      @@ -253,6 +444,9 @@ main(int argc, /* I - Number of command-line args */

    while (!job_canceled)
    {

  • int announce = 0;

+#ifdef HAVE_DNSSD
FD_ZERO(&input);
FD_SET(fd, &input);

@@ -272,11 +466,35 @@ main(int argc, /* I - Number of command-line args */
}
else
{

  •  announce = 1;
    
  • }
    +#else /* HAVE_AVAHI */
  • int r;
  • avahi_got_callback = 0;
  • r = avahi_simple_poll_iterate (simple_poll, 1);
  • if (r != 0 && r != EINTR)
  • {
  • /*
    
  •  \* We've been told to exit the loop.  Perhaps the connection to
    
  •  \* avahi failed.
    
  •  */
    
  •  break;
    
  • }
  • if (avahi_got_callback)
  •  announce = 1;
    
    +#endif /* HAVE_DNSSD */
    +
  • if (announce)
  • {
    /*
  • Announce any devices we've found...
    */

+#ifdef HAVE_DNSSD
DNSServiceErrorType status; /* DNS query status /
+#endif /
HAVE_DNSSD /
cups_device_t *best; /
Best matching device /
char device_uri[1024]; /
Device URI /
int count; /
Number of queries /
@@ -286,6 +504,7 @@ main(int argc, /
I - Number of command-line args /
best = NULL, count = 0;
device;
device = (cups_device_t *)cupsArrayNext(devices))
+#ifdef HAVE_DNSSD
if (!device->ref && !device->sent)
{
/

@@ -314,14 +533,23 @@ main(int argc, /* I - Number of command-line args */
count ++;
}
}

  • else if (!device->sent)

  • else
    +#endif /* HAVE_DNSSD */
    +#ifdef HAVE_AVAHI

  • if (!device->resolved)

  • continue;
    
  •    else
    

    +#endif /* HAVE_AVAHI */

  • if (!device->sent)
    {
    +#ifdef HAVE_DNSSD
    /*

  • Got the TXT records, now report the device...
    */

    DNSServiceRefDeallocate(device->ref);
    device->ref = 0;
    +#endif /* HAVE_DNSSD */

    if (!best)
    best = device;
    @@ -369,6 +597,7 @@ main(int argc, /* I - Number of command-line args */
    }

+#ifdef HAVE_DNSSD
/*

  • 'browse_callback()' - Browse devices.
    /
    @@ -457,6 +686,7 @@ browse_local_callback(
    device->fullName);
    device->sent = 1;
    }
    +#endif /
    HAVE_DNSSD */

    /*
    @@ -531,6 +761,37 @@ exec_backend(char *argv) / I - Command-line arguments */

    /*

    • * 'device_type()' - Get DNS-SD type enumeration from string.
    • */
      +
      +static int
      +device_type (const char *regtype)
      +{
      +#ifdef HAVE_AVAHI
    • if (!strcmp(regtype, "_ipp._tcp") ||
    •  !strcmp(regtype, "_ipp-tls._tcp"))
      
    • return (CUPS_DEVICE_IPP);
    • else if (!strcmp(regtype, "_fax-ipp._tcp"))
    • return (CUPS_DEVICE_FAX_IPP);
    • else if (!strcmp(regtype, "_printer._tcp"))
    • return (CUPS_DEVICE_PDL_DATASTREAM);
      +#else
    • if (!strcmp(regtype, "_ipp._tcp.") ||
    •  !strcmp(regtype, "_ipp-tls._tcp."))
      
    • return (CUPS_DEVICE_IPP);
    • else if (!strcmp(regtype, "_fax-ipp._tcp."))
    • return (CUPS_DEVICE_FAX_IPP);
    • else if (!strcmp(regtype, "_printer._tcp."))
    • return (CUPS_DEVICE_PRINTER);
    • else if (!strcmp(regtype, "_pdl-datastream._tcp."))
    • return (CUPS_DEVICE_PDL_DATASTREAM);
      +#endif /* HAVE_AVAHI */
    • return (CUPS_DEVICE_RIOUSBPRINT);
      +}

    +/*

  • 'get_device()' - Create or update a device.
    */

@@ -551,18 +812,7 @@ get_device(cups_array_t devices, / I - Device array */
*/

key.name = (char *)serviceName;

  • if (!strcmp(regtype, "_ipp._tcp.") ||
  •  !strcmp(regtype, "_ipp-tls._tcp."))
    
  • key.type = CUPS_DEVICE_IPP;
  • else if (!strcmp(regtype, "_fax-ipp._tcp."))
  • key.type = CUPS_DEVICE_FAX_IPP;
  • else if (!strcmp(regtype, "_printer._tcp."))
  • key.type = CUPS_DEVICE_PRINTER;
  • else if (!strcmp(regtype, "_pdl-datastream._tcp."))
  • key.type = CUPS_DEVICE_PDL_DATASTREAM;
  • else
  • key.type = CUPS_DEVICE_RIOUSBPRINT;
  • key.type = device_type (regtype);

for (device = cupsArrayFind(devices, &key);
device;
@@ -582,8 +832,14 @@ get_device(cups_array_t devices, / I - Device array */
free(device->domain);
device->domain = strdup(replyDomain);

+#ifdef HAVE_DNSSD
DNSServiceConstructFullName(fullName, device->name, regtype,
replyDomain);
+#else /* HAVE_AVAHI */

  • avahi_service_name_join (fullName, kDNSServiceMaxDomainName,
  •            serviceName, regtype, replyDomain);
    
    +#endif /* HAVE_DNSSD /
    +
    free(device->fullName);
    device->fullName = strdup(fullName);
    }
    @@ -603,6 +859,9 @@ get_device(cups_array_t *devices, /
    I - Device array */
    device->domain = strdup(replyDomain);
    device->type = key.type;
    device->priority = 50;
    +#ifdef HAVE_AVAHI
  • device->resolved = 0;
    +#endif /* HAVE_AVAHI */

cupsArrayAdd(devices, device);

@@ -610,13 +869,20 @@ get_device(cups_array_t devices, / I - Device array */

  • Set the "full name" of this service, which is used for queries...
    */

+#ifdef HAVE_DNSSD
DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain);
+#else /* HAVE_AVAHI */

  • avahi_service_name_join (fullName, kDNSServiceMaxDomainName,

  •          serviceName, regtype, replyDomain);
    

    +#endif /* HAVE_DNSSD */
    +
    device->fullName = strdup(fullName);

    return (device);
    }

+#ifdef HAVE_DNSSD
/*

  • 'query_callback()' - Process query data.
    /
    @@ -640,7 +906,7 @@ query_callback(
    *ptr; /
    Pointer into string /
    cups_device_t dkey, /
    Search key */

    device; / Device */

    • cups_txt_records_t txt;

    fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, "
    "interfaceIndex=%d, errorCode=%d, fullName="%s", "
    @@ -674,84 +940,232 @@ query_callback(
    if ((ptr = strstr(name, "._")) != NULL)
    *ptr = '\0';

  • if (strstr(fullName, "_ipp._tcp.") ||

  •  strstr(fullName, "_ipp-tls._tcp."))
    
  • dkey.type = CUPS_DEVICE_IPP;

  • else if (strstr(fullName, "_fax-ipp._tcp."))

  • dkey.type = CUPS_DEVICE_FAX_IPP;

  • else if (strstr(fullName, "_printer._tcp."))

  • dkey.type = CUPS_DEVICE_PRINTER;

  • else if (strstr(fullName, "_pdl-datastream._tcp."))

  • dkey.type = CUPS_DEVICE_PDL_DATASTREAM;

  • dkey.type = device_type (fullName);

  • txt.data = rdata;
  • txt.dataend = rdata + rdlen;
  • device = find_device ((cups_array_t *) context, &txt, &dkey);
  • if (!device)
  • fprintf(stderr, "DEBUG: Ignoring TXT record for "%s"...\n", fullName);
    +}
    +#endif /* HAVE_DNSSD _/

+#ifdef HAVE_AVAHI
+/_

  • * 'avahi_client_callback()' - Avahi client callback function.
  • */
    +
    +static void
    +avahi_client_callback(AvahiClient *client,
  •         AvahiClientState state,
    
  •         void *context)
    
    +{
  • /*
  • * If the connection drops, quit.
  • */
  • if (state == AVAHI_CLIENT_FAILURE)
  • {
  • fprintf (stderr, "ERROR: Avahi connection failed\n");
  • avahi_simple_poll_quit (simple_poll);
  • }
    +}

+/*

  • * 'avahi_query_callback()' - Avahi query callback function.
  • */
    +
    +static void
    +avahi_query_callback(AvahiServiceResolver *resolver,
  •        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 *context)
    
    +{
  • AvahiClient *client;
  • cups_device_t key,
  •       *device;
    
  • char uqname[1024],
  •       *ptr;
    
  • cups_txt_records_t txtr;
  • client = avahi_service_resolver_get_client (resolver);
  • if (event != AVAHI_RESOLVER_FOUND)
  • {
  • if (event == AVAHI_RESOLVER_FAILURE)
  • {
  •  fprintf (stderr, "ERROR: %s\n",
    
  •      avahi_strerror (avahi_client_errno (client)));
    
  • }
  • avahi_service_resolver_free (resolver);
  • return;
  • }
  • /*
  • * Set search key for device.
  • */
  • key.name = uqname;
  • unquote (uqname, name, sizeof (uqname));
  • if ((ptr = strstr(name, "._")) != NULL)
  • *ptr = '\0';
  • key.domain = (char *) domain;
  • key.type = device_type (type);
  • /*
  • * Find the device and the the TXT information.
  • */
  • txtr.txt = txt;
  • device = find_device ((cups_array_t *) context, &txtr, &key);
  • if (device)
  • {
  • /*
  • * Let the main loop know to announce the device.
  • */
  • device->resolved = 1;
  • avahi_got_callback = 1;
  • }
    else
  • dkey.type = CUPS_DEVICE_RIOUSBPRINT;
  • fprintf (stderr, "DEBUG: Ignoring TXT record for "%s"...\n", name);
  • avahi_service_resolver_free (resolver);
    +}

+/*

  • * 'avahi_browse_callback()' - Avahi browse callback function.
  • */
    +
    +static void
    +avahi_browse_callback(AvahiServiceBrowser *browser,
  •         AvahiIfIndex interface,
    
  •         AvahiProtocol protocol,
    
  •         AvahiBrowserEvent event,
    
  •         const char *name,
    
  •         const char *type,
    
  •         const char *domain,
    
  •         AvahiLookupResultFlags flags,
    
  •         void *context)
    
    +{
  • AvahiClient *client = avahi_service_browser_get_client (browser);
  • for (device = cupsArrayFind(devices, &dkey);
  • switch (event)
  • {
  • case AVAHI_BROWSER_FAILURE:
  • fprintf (stderr, "ERROR: %s\n",
  •    avahi_strerror (avahi_client_errno (client)));
    
  • avahi_simple_poll_quit (simple_poll);
  • return;
  • case AVAHI_BROWSER_NEW:
  • /*
  • * This object is new on the network.
  • */
  • if (flags & AVAHI_LOOKUP_RESULT_LOCAL)
  • {
  • /*
    
  •  \* This comes from the local machine so ignore it.
    
  •  */
    
  •  fprintf (stderr, "DEBUG: ignoring local service %s\n", name);
    
  • }
  • else
  • {
  • /*
    
  •  \* Create a device entry for it if it doesn't yet exist.
    
  •  */
    
  •  get_device ((cups_array_t *)context, name, type, domain);
    
  • /*
    
  •  \* Now look for a TXT entry.
    
  •  */
    
  •  if (avahi_service_resolver_new (client, interface, protocol,
    
  •                 name, type, domain,
    
  •                 AVAHI_PROTO_UNSPEC, 0,
    
  •                 avahi_query_callback, context) == NULL)
    
  •  {
    
  • fprintf (stderr, "ERROR: failed to resolve service %s: %s\n",
  •    name, avahi_strerror (avahi_client_errno (client)));
    
  •  }
    
  • }
  • break;
  • case AVAHI_BROWSER_REMOVE:
  • case AVAHI_BROWSER_ALL_FOR_NOW:
  • case AVAHI_BROWSER_CACHE_EXHAUSTED:
  • break;
  • }
    +}
    +#endif /* HAVE_AVAHI _/

+/_

  • * 'find_device()' - Find a device from its name and domain.
  • */
    +
    +static cups_device_t *
    +find_device (cups_array_t *devices,
  •    cups_txt_records_t *txt,
    
  •    cups_device_t *dkey)
    
    +{
  • cups_device_t *device;
  • char *ptr;
  • for (device = cupsArrayFind(devices, dkey);
    device;
    device = cupsArrayNext(devices))
    {
  • if (strcasecmp(device->name, dkey.name) ||
  •    strcasecmp(device->domain, dkey.domain))
    
  • if (strcasecmp(device->name, dkey->name) ||
  •    strcasecmp(device->domain, dkey->domain))
    
    {
    device = NULL;
    break;
    }
  • else if (device->type == dkey.type)
  • else if (device->type == dkey->type)
    {
    /*
  • Found it, pull out the priority and make and model from the TXT
  • record and save it...
    */
  •  const uint8_t    *data,      /* Pointer into data */
    
  •       _datanext,  /_ Next key/value pair */
    
  •       _dataend;   /_ End of entire TXT record */
    
  •  uint8_t      datalen;    /\* Length of current key/value pair */
    
  •  char     key[256],   /\* Key string */
    
  •       value[256], /\* Value string */
    
  •       make_and_model[512],
    
  •  char     make_and_model[512],
                    /\* Manufacturer and model _/
        model[256], /_ Model */
    

- device_id[2048];/* 1284 device ID */

  •       device_id[2048]; /* 1284 device ID */
    

    device_id[0] = '\0';
    make_and_model[0] = '\0';

    strcpy(model, "Unknown");

  •  for (data = rdata, dataend = data + rdlen;
    
  •       data < dataend;
    
  •       data = datanext)
    
  •  for (;;)
    

    {

  •   /*
    
  •    \* Read a key/value pair starting with an 8-bit length.  Since the
    
  • * length is 8 bits and the size of the key/value buffers is 256, we

  • * don't need to check for overflow...

- */

- datalen = *data++;

  •    if (!datalen || (data + datalen) >= dataend)
    
  • break;
    
  • char *key;
  • char *value;

- datanext = data + datalen;

  •    for (ptr = key; data < datanext && *data != '='; data ++)
    
  • *ptr++ = *data;
    

- *ptr = '\0';

  • if (data < datanext && *data == '=')
  • {

- data ++;

  • if (data < datanext)
    
  •   memcpy(value, data, datanext - data);
    
  • value[datanext - data] = '\0';
    
  • }
  • else
  • continue;
    
  • if (parse_txt_record_pair (txt))
  • goto next;
    
  • key = txt->key;
  • value = txt->value;
    if (!strncasecmp(key, "usb_", 4))
    {
    /*
    @@ -806,6 +1220,10 @@ query_callback(
    if (device->type == CUPS_DEVICE_PRINTER)
    device->sent = 1;
    }
  •  next:
    
  • if (next_txt_record (txt) == NULL)

  • break;
    

    }

    if (device->device_id)
    @@ -855,11 +1273,9 @@ query_callback(
    }
    }

  • if (!device)

  • fprintf(stderr, "DEBUG: Ignoring TXT record for "%s"...\n", fullName);

  • return device;
    }

/*

  • 'sigterm_handler()' - Handle termination signals...
    */
    diff --git a/cups/http-support.c b/cups/http-support.c
    index 6e99715..2a5d88a 100644
    --- a/cups/http-support.c
    +++ b/cups/http-support.c
    @@ -42,6 +42,10 @@
  • http_copy_decode() - Copy and decode a URI.
  • http_copy_encode() - Copy and encode a URI.
  • resolve_callback() - Build a device URI for the given service name.
  • * avahi_resolve_uri_client_cb()
  • * - Avahi client callback for resolving URI.
  • * avahi_resolve_uri_resolver_cb()
  • * - Avahi resolver callback for resolving URI.
    */

/*
@@ -59,6 +63,11 @@

include <sys/select.h>

endif /* WIN32 */

#endif /* HAVE_DNSSD /
+#ifdef HAVE_AVAHI
+# include <avahi-client/client.h>
+# include <avahi-client/lookup.h>
+# include <avahi-common/simple-watch.h>
+#endif /
HAVE_AVAHI */

/*
@@ -125,6 +134,24 @@ static void DNSSD_API resolve_callback(DNSServiceRef sdRef,
void context);
#endif /
HAVE_DNSSD */

+#ifdef HAVE_AVAHI
+static void avahi_resolve_uri_client_cb(AvahiClient *client,

  •                   AvahiClientState state,
    
  •                   void *simple_poll);
    

    +static void avahi_resolve_uri_resolver_cb(AvahiServiceResolver *resolver,

  •                     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 *context);
    

    +#endif /* HAVE_AVAHI */

    /*

    • 'httpAssembleURI()' - Assemble a uniform resource identifier from its
      @@ -1377,6 +1404,9 @@ _httpResolveURI(

    if (strstr(hostname, "._tcp"))
    {
    +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)

  • char regtype, / Pointer to type in hostname */

  •       _domain;    /_ Pointer to domain in hostname _/
    

    #ifdef HAVE_DNSSD

    ifdef WIN32

    pragma comment(lib, "dnssd.lib")

    @@ -1395,6 +1425,17 @@ httpResolveURI(
    fd_set input_set; /
    Input set for select() /
    struct timeval stimeout; /
    Timeout value for select() /
    #endif /
    HAVE_POLL /
    +#else /
    HAVE_AVAHI */

  • AvahiSimplePoll *simple_poll;

  • AvahiClient *client;

  • int error;

  • struct

  • {

  •  AvahiSimplePoll  *poll;
    
  •  _http_uribuf_t   uribuf;
    
  • } user_data;
    +#endif /* HAVE_DNSSD */

if (logit)
fprintf(stderr, "DEBUG: Resolving "%s"...\n", hostname);
@@ -1431,8 +1472,13 @@ _httpResolveURI(
if (domain)
*domain++ = '\0';

+#ifdef HAVE_DNSSD
uribuf.buffer = resolved_uri;
uribuf.bufsize = resolved_size;
+#else

  • user_data.uribuf.buffer = resolved_uri;
  • user_data.uribuf.bufsize = resolved_size;
    +#endif

resolved_uri[0] = '\0';

@@ -1447,6 +1493,7 @@ _httpResolveURI(

 uri = NULL;

+#ifdef HAVE_DNSSD
if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError)
{
localref = ref;
@@ -1545,6 +1592,36 @@ _httpResolveURI(

   DNSServiceRefDeallocate(ref);
 }

+#else /* HAVE_AVAHI */

  • if ((simple_poll = avahi_simple_poll_new ()) != NULL)
  • {
  •  if ((client = avahi_client_new (avahi_simple_poll_get (simple_poll),
    
  •                 0, avahi_resolve_uri_client_cb,
    
  •                 &simple_poll, &error)) != NULL)
    
  •  {
    
  • user_data.poll = simple_poll;
  • if (avahi_service_resolver_new (client, AVAHI_IF_UNSPEC,
  •               AVAHI_PROTO_UNSPEC, hostname,
    
  •               regtype, domain, AVAHI_PROTO_UNSPEC, 0,
    
  •               avahi_resolve_uri_resolver_cb,
    
  •               &user_data) != NULL)
    
  • {
  • avahi_simple_poll_loop (simple_poll);
    
  • /*
  • \* Collect the result.
    
  • */
    
  • if (resolved_uri[0])
    
  •   uri = resolved_uri;
    
  • }
  • avahi_client_free (client);
  •  }
    
  •  avahi_simple_poll_free (simple_poll);
    
  • }
    +#endif /* HAVE_DNSSD */

if (logit)
{
@@ -1556,13 +1633,13 @@ _httpResolveURI(
fputs("STATE: -connecting-to-device,offline-report\n", stderr);
}

-#else
+#else /* HAVE_DNSSD || HAVE_AVAHI /
/

* No DNS-SD support...
*/

 uri = NULL;

-#endif /* HAVE_DNSSD /
+#endif /
HAVE_DNSSD || HAVE_AVAHI */

 if (logit && !uri)
   _cupsLangPrintFilter(stderr, "ERROR", _("Unable to find printer."));

@@ -1768,6 +1845,116 @@ resolve_callback(
#endif /* HAVE_DNSSD */

+#ifdef HAVE_AVAHI
+/*

  • * 'avahi_resolve_uri_client_cb()' - Avahi client callback for resolving URI.
  • */
    +
    +static void
    +avahi_resolve_uri_client_cb (AvahiClient *client,
  •            AvahiClientState state,
    
  •            void *simple_poll)
    
    +{
  • DEBUG_printf(("avahi_resolve_uri_client_callback(client=%p, state=%d, "
  •   "simple_poll=%p)\n", client, state, simple_poll));
    
  • /*
  • * If the connection drops, quit.
  • */
  • if (state == AVAHI_CLIENT_FAILURE)
  • avahi_simple_poll_quit (simple_poll);
    +}

+/*

  • * 'avahi_resolve_uri_resolver_cb()' - Avahi resolver callback for resolving
  • * URI.
  • */
    +
    +static void
    +avahi_resolve_uri_resolver_cb (AvahiServiceResolver *resolver,
  •              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 *context)
    
    +{
  • const char scheme; / URI scheme */
  • char rp[256]; /* Remote printer */
  • AvahiStringList *pair;
  • char *value;
  • size_t valueLen = 0;
  • char addr[AVAHI_ADDRESS_STR_MAX];
  • struct
  • {
  • AvahiSimplePoll *poll;
  • _http_uribuf_t uribuf;
  • } *poll_uribuf = context;
  • DEBUG_printf(("avahi_resolve_uri_resolver_callback(resolver=%p, "
  •   "interface=%d, protocol=%d, event=%d, name=\"%s\", "
    
  •   "type=\"%s\", domain=\"%s\", host_name=\"%s\", address=%p, "
    
  •   "port=%d, txt=%p, flags=%d, context=%p)\n",
    
  •   resolver, interface, protocol, event, name, type, domain,
    
  •   host_name, address, port, txt, flags, context));
    
  • if (event != AVAHI_RESOLVER_FOUND)
  • {
  • avahi_service_resolver_free (resolver);
  • avahi_simple_poll_quit (poll_uribuf->poll);
  • return;
  • }
  • /*
  • * Figure out the scheme from the full name...
  • */
  • if (strstr(type, "_ipp."))
  • scheme = "ipp";
  • else if (strstr(type, "_printer."))
  • scheme = "lpd";
  • else if (strstr(type, "_pdl-datastream."))
  • scheme = "socket";
  • else
  • scheme = "riousbprint";
  • /*
  • * Extract the "remote printer key from the TXT record...
  • */
  • if ((pair = avahi_string_list_find (txt, "rp")) != NULL)
  • {
  • avahi_string_list_get_pair (pair, NULL, &value, &valueLen);
  • rp[0] = '/';
  • memcpy (rp + 1, value, valueLen);
  • rp[valueLen + 1] = '\0';
  • }
  • else
  • rp[0] = '\0';
  • /*
  • * Assemble the final device URI...
  • */
  • avahi_address_snprint (addr, AVAHI_ADDRESS_STR_MAX, address);
  • httpAssembleURI(HTTP_URI_CODING_ALL, poll_uribuf->uribuf.buffer,
  •     poll_uribuf->uribuf.bufsize, scheme, NULL,
    
  •     addr, port, rp);
    
  • DEBUG_printf(("avahi_resolve_uri_resolver_callback: Resolved URI is "%s"\n",
  •   poll_uribuf->uribuf.buffer));
    
  • avahi_simple_poll_quit (poll_uribuf->poll);
    +}
    +#endif /* HAVE_AVAHI _/

/_

  • End of "$Id$".
    */

    1.7.3.4
@michaelrsweet
Collaborator

"0003-Timed-callback-support-needed-for-Avahi.patch":

From cf80621258dfff7dad567ddb34ac042e9c59ade6 Mon Sep 17 00:00:00 2001
From: Tim Waugh twaugh@redhat.com
Date: Tue, 21 Dec 2010 17:25:24 +0000
Subject: [PATCH 3/4] Timed callback support, needed for Avahi.


scheduler/Makefile | 3 +-
scheduler/cupsd.h | 26 +++++++
scheduler/main.c | 39 ++++++++++
scheduler/timeout.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 262 insertions(+), 1 deletions(-)
create mode 100644 scheduler/timeout.c

diff --git a/scheduler/Makefile b/scheduler/Makefile
index 0decf8f..688d564 100644
--- a/scheduler/Makefile
+++ b/scheduler/Makefile
@@ -39,7 +39,8 @@ CUPSDOBJS =
server.o
statbuf.o
subscriptions.o \

  •   sysman.o
    
  •   sysman.o \
    
  •   timeout.o
    

    LIBOBJS =
    filter.o
    mime.o
    diff --git a/scheduler/cupsd.h b/scheduler/cupsd.h
    index d151015..5af3821 100644
    --- a/scheduler/cupsd.h
    +++ b/scheduler/cupsd.h
    @@ -139,6 +139,15 @@ extern const char *cups_hstrerror(int);

    typedef void (*cupsd_selfunc_t)(void *data);

+#ifdef HAVE_AVAHI
+/*

  • * Timeout callback function type...

  • _/
    +
    +typedef struct _cupsd_timeout_s cupsd_timeout_t;
    +typedef void (_cupsd_timeoutfunc_t)(cupsd_timeout_t timeout, void *data);
    +#endif /
    HAVE_AVAHI */
    +

    /*

    • Globals...
      @@ -172,6 +181,11 @@ VAR int Launchd VALUE(0);
      /* Running from launchd /
      #endif /
      HAVE_LAUNCH_H */

+#ifdef HAVE_AVAHI
+VAR cups_array_t Timeouts; / Timed callbacks for main loop /
+#endif /
HAVE_AVAHI */
+
+

/*

  • Prototypes...
    @@ -224,6 +238,18 @@ extern void cupsdRemoveSelect(int fd);
    extern void cupsdStartSelect(void);
    extern void cupsdStopSelect(void);

+#ifdef HAVE_AVAHI
+extern void cupsdInitTimeouts(void);
+extern cupsd_timeout_t *cupsdAddTimeout (const struct timeval *tv,

  •                cupsd_timeoutfunc_t cb,
    
  •                void *data);
    
    +extern cupsd_timeout_t *cupsdNextTimeout (long *delay);
    +extern void cupsdRunTimeout (cupsd_timeout_t *timeout);
    +extern void cupsdUpdateTimeout (cupsd_timeout_t *timeout,
  •               const struct timeval _tv);
    
    +extern void cupsdRemoveTimeout (cupsd_timeout_t *timeout);
    +#endif /_ HAVE_AVAHI */
    +
    extern int cupsdRemoveFile(const char *filename);

diff --git a/scheduler/main.c b/scheduler/main.c
index a19409e..798561d 100644
--- a/scheduler/main.c
+++ b/scheduler/main.c
@@ -153,6 +153,10 @@ main(int argc, /* I - Number of command-line args /
int launchd_idle_exit;
/
Idle exit on select timeout? /
#endif /
HAVE_LAUNCHD */
+#ifdef HAVE_AVAHI

  • cupsd_timeout_t tmo; / Next scheduled timed callback */
  • long tmo_delay; /* Time before it must be called /
    +#endif /
    HAVE_AVAHI */

#ifdef HAVE_GETEUID
@@ -532,6 +536,14 @@ main(int argc, /* I - Number of command-line args */

httpInitialize();

+#ifdef HAVE_AVAHI

  • /*
  • * Initialize timed callback structures.
  • */
  • cupsdInitTimeouts();
    +#endif /* HAVE_AVAHI */

cupsdStartServer();

/*
@@ -871,6 +883,16 @@ main(int argc, /* I - Number of command-line args /
}
#endif /
APPLE */

+#ifdef HAVE_AVAHI

  • /*
  • * If a timed callback is due, run it.
  • */
  • tmo = cupsdNextTimeout (&tmo_delay);
  • if (tmo && tmo_delay == 0)
  •  cupsdRunTimeout (tmo);
    
    +#endif /* HAVE_AVAHI /
    +
    #ifndef APPLE
    /
    • Update the network interfaces once a minute...
      @@ -1916,6 +1938,10 @@ select_timeout(int fds) /* I - Number of descriptors returned /
      cupsd_job_t *job; /
      Job information /
      cupsd_subscription_t *sub; /
      Subscription information /
      const char *why; /
      Debugging aid */
      +#ifdef HAVE_AVAHI
  • cupsd_timeout_t tmo; / Timed callback */
  • long tmo_delay; /* Seconds before calling it /
    +#endif /
    HAVE_AVAHI */

/*
@@ -1958,6 +1984,19 @@ select_timeout(int fds) /* I - Number of descriptors returned /
}
#endif /
APPLE */

+#ifdef HAVE_AVAHI

  • /*
  • * See if there are any scheduled timed callbacks to run.
  • */
  • tmo = cupsdNextTimeout (&tmo_delay);
  • if (tmo)
  • {
  • timeout = tmo_delay;
  • why = "run a timed callback";
  • }
    +#endif /* HAVE_AVAHI _/

/_

  • Check whether we are accepting new connections...
    /
    diff --git a/scheduler/timeout.c b/scheduler/timeout.c
    new file mode 100644
    index 0000000..415fc1a
    --- /dev/null
    +++ b/scheduler/timeout.c
    @@ -0,0 +1,195 @@
    +/
  • * "$Id$"
  • * Timeout functions for the Common UNIX Printing System (CUPS).
  • * Copyright (C) 2010 Red Hat, Inc.
  • * Authors:
  • * Tim Waugh twaugh@redhat.com
  • * Distribution and use rights are outlined in the file "LICENSE.txt"
  • * which should have been included with this file. If this file is
  • * file is missing or damaged, see the license at "http://www.cups.org/".
  • * Contents:
  • * cupsdInitTimeouts() - Initialise timeout structure.
  • * cupsdAddTimeout() - Add a timed callback.
  • * cupsdNextTimeout() - Find the next enabled timed callback.
  • * cupsdUpdateTimeout() - Adjust the time of a timed callback or disable it.
  • * cupsdRemoveTimeout() - Discard a timed callback.
  • * compare_timeouts() - Compare timed callbacks for array sorting.
  • /
    +
    +#include <config.h>
    +
    +#ifdef HAVE_AVAHI /
    Applies to entire file... /
    +
    +/
  • * Include necessary headers...
  • /
    +
    +#include "cupsd.h"
    +
    +#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
    +# include <malloc.h>
    +#endif /
    HAVE_MALLOC_H && HAVE_MALLINFO /
    +
    +#ifdef HAVE_AVAHI
    +# include <avahi-common/timeval.h>
    +#endif /
    HAVE_AVAHI */
    +
    +
    +struct _cupsd_timeout_s
    +{
  • struct timeval when;
  • int enabled;
  • cupsd_timeoutfunc_t callback;
  • void _data;
    +};

+/_

  • * Local functions...
  • /
    +
    +/
  • * 'compare_timeouts()' - Compare timed callbacks for array sorting.
  • */
    +
    +static int
    +compare_timeouts (cupsd_timeout_t *p0, cupsd_timeout_t *p1)
    +{
  • if (!p0->enabled || !p1->enabled)
  • {
  • if (!p0->enabled && !p1->enabled)
  •  return (0);
    
  • return (p0->enabled ? -1 : 1);
  • }
  • return (avahi_timeval_compare (&p0->when, &p1->when));
    +}

+/*

  • * 'cupsdInitTimeouts()' - Initialise timeout structures.
  • */
    +
    +void
    +cupsdInitTimeouts(void)
    +{
  • Timeouts = cupsArrayNew ((cups_array_func_t)compare_timeouts, NULL);
    +}

+/*

  • * 'cupsdAddTimeout()' - Add a timed callback.
  • /
    +
    +cupsd_timeout_t * /
    O - Timeout handle /
    +cupsdAddTimeout(const struct timeval *tv, /
    I - Absolute time */
  •   cupsd_timeoutfunc_t cb,     /\* I - Callback function */
    
  •   void _data)         /_ I - User data */
    
    +{
  • cupsd_timeout_t *timeout;
  • timeout = malloc (sizeof(cupsd_timeout_t));
  • if (timeout != NULL)
  • {
  • timeout->enabled = (tv != NULL);
  • if (tv)
  • {
  •  timeout->when.tv_sec = tv->tv_sec;
    
  •  timeout->when.tv_usec = tv->tv_usec;
    
  • }
  • timeout->callback = cb;
  • timeout->data = data;
  • cupsArrayAdd (Timeouts, timeout);
  • }
  • return timeout;
    +}

+/*

  • * 'cupsdNextTimeout()' - Find the next enabled timed callback.
  • /
    +
    +cupsd_timeout_t * /
    O - Next enabled timeout or NULL /
    +cupsdNextTimeout(long *delay) /
    O - Seconds before scheduled */
    +{
  • cupsd_timeout_t *first = cupsArrayFirst (Timeouts);
  • struct timeval curtime;
  • if (first && !first->enabled)
  • first = NULL;
  • if (first && delay)
  • {
  • gettimeofday (&curtime, NULL);
  • if (avahi_timeval_compare (&curtime, &first->when) > 0)
  • {
  •  *delay = 0;
    
  • } else {
  •  *delay = 1 + first->when.tv_sec - curtime.tv_sec;
    
  •  if (first->when.tv_usec < curtime.tv_usec)
    
  • (*delay)--;
  • }
  • }
  • return (first);
    +}

+/*

  • * 'cupsdRunTimeout()' - Run a timed callback.
  • /
    +
    +void
    +cupsdRunTimeout(cupsd_timeout_t *timeout) /
    I - Timeout */
    +{
  • if (!timeout)
  • return;
  • timeout->enabled = 0;
  • if (!timeout->callback)
  • return;
  • timeout->callback (timeout, timeout->data);
    +}

+/*

  • * 'cupsdUpdateTimeout()' - Adjust the time of a timed callback or disable it.
  • /
    +
    +void
    +cupsdUpdateTimeout(cupsd_timeout_t *timeout, /
    I - Timeout */
  •      const struct timeval _tv)    /_ I - Absolute time or NULL */
    
    +{
  • cupsArrayRemove (Timeouts, timeout);
  • timeout->enabled = (tv != NULL);
  • if (tv)
  • {
  • timeout->when.tv_sec = tv->tv_sec;
  • timeout->when.tv_usec = tv->tv_usec;
  • }
  • cupsArrayAdd (Timeouts, timeout);
    +}

+/*

  • * 'cupsdRemoveTimeout()' - Discard a timed callback.
  • /
    +
    +void
    +cupsdRemoveTimeout(cupsd_timeout_t *timeout) /
    I - Timeout */
    +{
  • cupsArrayRemove (Timeouts, timeout);
  • free (timeout);
    +}

+#endif /* HAVE_AVAHI ... from top of file /
+
+/

  • * End of "$Id$".

+ */

1.7.3.4

@michaelrsweet
Collaborator

"0004-Avahi-poll-API-implementation.patch":

From 6e0fe12e81d7f88b2d07924d6d1aed42d62bb89d Mon Sep 17 00:00:00 2001
From: Tim Waugh twaugh@redhat.com
Date: Tue, 4 Jan 2011 16:12:00 +0000
Subject: [PATCH 4/4] Avahi poll API implementation.


scheduler/Makefile | 1 +
scheduler/avahi.c | 443 ++++++++++++++++++++++++++++++++++++++++++++++++++++
scheduler/avahi.h | 49 ++++++
3 files changed, 493 insertions(+), 0 deletions(-)
create mode 100644 scheduler/avahi.c
create mode 100644 scheduler/avahi.h

diff --git a/scheduler/Makefile b/scheduler/Makefile
index 688d564..56e7df3 100644
--- a/scheduler/Makefile
+++ b/scheduler/Makefile
@@ -17,6 +17,7 @@ include ../Makedefs

CUPSDOBJS =
auth.o \

  •   avahi.o \
    banners.o \
    cert.o \
    classes.o \
    
    diff --git a/scheduler/avahi.c b/scheduler/avahi.c
    new file mode 100644
    index 0000000..a881bc4
    --- /dev/null
    +++ b/scheduler/avahi.c
    @@ -0,0 +1,443 @@
    +/*
  • * "$Id$"
  • * Avahi poll implementation for the CUPS scheduler.
  • * Copyright (C) 2010 Red Hat, Inc.
  • * Authors:
  • * Tim Waugh twaugh@redhat.com
  • * Distribution and use rights are outlined in the file "LICENSE.txt"
  • * "LICENSE" which should have been included with this file. If this
  • * file is missing or damaged, see the license at "http://www.cups.org/".
  • * Contents:
  • * watch_read_cb - Read callback for file descriptor
  • * watch_write_cb - Write callback for file descriptor
  • * watched_fd_add_select() - Call cupsdAddSelect() as needed
  • * watch_new() - Create a new file descriptor watch
  • * watch_free() - Free a file descriptor watch
  • * watch_update() - Update watched events for a file descriptor
  • * watch_get_events() - Get events that happened for a file descriptor
  • * timeout_cb() - Run a timed Avahi callback
  • * timeout_new() - Set a wakeup time
  • * timeout_update() - Update the expiration time for a timeout
  • * timeout_free() - Free a timeout
  • * compare_watched_fds() - Compare watched file descriptors for array sorting
  • * compare_timeouts() - Compare timeouts for array sorting
  • * avahi_cups_poll_new() - Create a new Avahi main loop object for CUPS
  • * avahi_cups_poll_free() - Free an Avahi main loop object for CUPS
  • * avahi_cups_poll_get() - Get the abstract poll API structure
  • /
    +
    +#include <config.h>
    +
    +#ifdef HAVE_AVAHI /
    Applies to entire file... /
    +
    +/
  • * Include necessary headers...
  • /
    +
    +#include "cupsd.h"
    +
    +#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
    +# include <malloc.h>
    +#endif /
    HAVE_MALLOC_H && HAVE_MALLINFO /
    +
    +#ifdef HAVE_AVAHI
    +# include <avahi-common/timeval.h>
    +#endif /
    HAVE_AVAHI */
    +
    +
    +typedef struct
    +{
  • AvahiCupsPoll *cups_poll;
  • int fd;
  • AvahiWatchEvent occurred;
  • cups_array_t *watches;
    +} cupsd_watched_fd_t;

+struct AvahiWatch
+{

  • cupsd_watched_fd_t *watched_fd;
  • AvahiWatchEvent events;
  • AvahiWatchCallback callback;
  • void *userdata;
    +};

+struct AvahiTimeout
+{

  • AvahiCupsPoll *cups_poll;
  • AvahiTimeoutCallback callback;
  • void *userdata;
  • cupsd_timeout_t _cupsd_timeout;
    +};

+/_

  • * Local functions...
  • */
    +
    +static AvahiWatch * watch_new(const AvahiPoll *api,
  •             int fd,
    
  •             AvahiWatchEvent events,
    
  •             AvahiWatchCallback callback,
    
  •             void *userdata);
    
    +static void watch_free(AvahiWatch *watch);
    +static void watch_update(AvahiWatch *watch,
  •                AvahiWatchEvent events);
    
    +static AvahiWatchEvent watch_get_events(AvahiWatch *watch);
    +static int compare_watches(AvahiWatch *p0,
  •               AvahiWatch _p1);
    
    +/_
  • * 'watch_read_cb' - Read callback for file descriptor
  • */
    +
    +static void
    +watch_read_cb (void *userdata)
    +{
  • AvahiWatch *watch;
  • cupsd_watched_fd_t *watched_fd = userdata;
  • watched_fd->occurred |= AVAHI_WATCH_IN;
  • for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
  •   watch;
    
  •   watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
    
  • if (watch->events & watched_fd->occurred) {
  •  (watch->callback) (watch, watched_fd->fd,
    
  •        AVAHI_WATCH_IN, watch->userdata);
    
  •  watched_fd->occurred &= ~AVAHI_WATCH_IN;
    
  •  break;
    
  • }
  • }
    +}

+/*

  • * 'watch_write_cb' - Write callback for file descriptor
  • */
    +
    +static void
    +watch_write_cb (void *userdata)
    +{
  • AvahiWatch *watch;
  • cupsd_watched_fd_t *watched_fd = userdata;
  • watched_fd->occurred |= AVAHI_WATCH_OUT;
  • for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
  •   watch;
    
  •   watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
    
  • if (watch->events & watched_fd->occurred) {
  •  (watch->callback) (watch, watched_fd->fd,
    
  •        AVAHI_WATCH_OUT, watch->userdata);
    
  •  watched_fd->occurred &= ~AVAHI_WATCH_OUT;
    
  •  break;
    
  • }
  • }
    +}

+/*

  • * 'watched_fd_add_select' - Call cupsdAddSelect() as needed
  • /
    +
    +static int /
    O - Watches? */
    +watched_fd_add_select (cupsd_watched_fd_t *watched_fd)
    +{
  • AvahiWatch *watch;
  • cupsd_selfunc_t read_cb = NULL, write_cb = NULL;
  • for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
  •   watch;
    
  •   watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
    
  • if (watch->events & (AVAHI_WATCH_IN |
  •            AVAHI_WATCH_ERR |
    
  •            AVAHI_WATCH_HUP)) {
    
  •  read_cb = (cupsd_selfunc_t)watch_read_cb;
    
  •  if (write_cb != NULL)
    
  • break;
  • }
  • if (watch->events & AVAHI_WATCH_OUT) {
  •  write_cb = (cupsd_selfunc_t)watch_write_cb;
    
  •  if (read_cb != NULL)
    
  • break;
  • }
  • }
  • if (read_cb || write_cb)
  • cupsdAddSelect (watched_fd->fd, read_cb, write_cb, watched_fd);
  • else
  • cupsdRemoveSelect (watched_fd->fd);
  • return (read_cb || write_cb);
    +}

+/*

  • * 'watch_new' - Create a new file descriptor watch
  • */
    +
    +static AvahiWatch *
    +watch_new (const AvahiPoll *api,
  •  int fd,
    
  •  AvahiWatchEvent events,
    
  •  AvahiWatchCallback callback,
    
  •  void *userdata)
    
    +{
  • cupsd_watched_fd_t key, *watched_fd;
  • AvahiCupsPoll *cups_poll = api->userdata;
  • AvahiWatch *watch = malloc(sizeof(AvahiWatch));
  • if (watch == NULL)
  • return (NULL);
  • watch->events = events;
  • watch->callback = callback;
  • watch->userdata = userdata;
  • key.fd = fd;
  • watched_fd = cupsArrayFind (cups_poll->watched_fds, &key);
  • if (watched_fd == NULL) {
  • watched_fd = malloc(sizeof(cupsd_watched_fd_t));
  • if (watched_fd == NULL)
  •  return (NULL);
    
  • watched_fd->fd = fd;
  • watched_fd->occurred = 0;
  • watched_fd->cups_poll = cups_poll;
  • watched_fd->watches = cupsArrayNew ((cups_array_func_t)compare_watches,
  •               NULL);
    
  • }
  • watch->watched_fd = watched_fd;
  • cupsArrayAdd(watched_fd->watches, watch);
  • watched_fd_add_select (watched_fd);
  • return (watch);
    +}

+/*

  • * 'watch_free' - Free a file descriptor watch
  • */
    +
    +static void
    +watch_free (AvahiWatch *watch)
    +{
  • cupsd_watched_fd_t *watched_fd = watch->watched_fd;
  • AvahiCupsPoll *cups_poll = watched_fd->cups_poll;
  • cupsArrayRemove (watched_fd->watches, watch);
  • free (watch);
  • if (!watched_fd_add_select (watched_fd)) {
  • /* No more watches */
  • cupsArrayRemove (cups_poll->watched_fds, watched_fd);
  • free (watched_fd);
  • }
    +}

+/*

  • * 'watch_update' - Update watched events for a file descriptor
  • */
    +
    +static void
    +watch_update (AvahiWatch *watch,
  •     AvahiWatchEvent events)
    
    +{
  • watch->events = events;
  • watched_fd_add_select (watch->watched_fd);
    +}

+/*

  • * 'watch_get_events' - Get events that happened for a file descriptor
  • */
    +
    +static AvahiWatchEvent
    +watch_get_events (AvahiWatch *watch)
    +{
  • return (watch->watched_fd->occurred);
    +}

+/*

  • * 'compare_watches' - Compare watches for array sorting
  • */
    +
    +static int
    +compare_watches (AvahiWatch *p0,
  •    AvahiWatch *p1)
    
    +{
  • if (p0->watched_fd->fd < p1->watched_fd->fd)
  • return (-1);
  • return ((p0->watched_fd->fd == p1->watched_fd->fd) ? 0 : 1);
    +}

+/*

  • * 'timeout_cb()' - Run a timed Avahi callback
  • */
    +
    +static void
    +timeout_cb (cupsd_timeout_t *cupsd_timeout, void *userdata)
    +{
  • AvahiTimeout *timeout = userdata;
  • (timeout->callback) (timeout, timeout->userdata);
    +}

+/*

  • * 'timeout_new' - Set a wakeup time
  • */
    +
    +static AvahiTimeout *
    +timeout_new (const AvahiPoll *api,
  •    const struct timeval *tv,
    
  •    AvahiTimeoutCallback callback,
    
  •    void *userdata)
    
    +{
  • AvahiTimeout *timeout;
  • AvahiCupsPoll *cups_poll = api->userdata;
  • timeout = malloc(sizeof(AvahiTimeout));
  • if (timeout == NULL)
  • return (NULL);
  • timeout->cups_poll = cups_poll;
  • timeout->callback = callback;
  • timeout->userdata = userdata;
  • timeout->cupsd_timeout = cupsdAddTimeout (tv,
  •                   (cupsd_timeoutfunc_t)timeout_cb,
    
  •                   timeout);
    
  • cupsArrayAdd (cups_poll->timeouts, timeout);
  • return (timeout);
    +}

+/*

  • * 'timeout_update' - Update the expiration time for a timeout
  • */
    +
    +static void
    +timeout_update (AvahiTimeout *timeout,
  •   const struct timeval *tv)
    
    +{
  • cupsdUpdateTimeout (timeout->cupsd_timeout, tv);
    +}

+/*

  • * ' timeout_free' - Free a timeout
  • */
    +
    +static void
    +timeout_free (AvahiTimeout *timeout)
    +{
  • cupsArrayRemove (timeout->cups_poll->timeouts, timeout);
  • cupsdRemoveTimeout (timeout->cupsd_timeout);
  • free (timeout);
    +}

+/*

  • * 'compare_watched_fds' - Compare watched file descriptors for array sorting
  • */
    +static int
    +compare_watched_fds(cupsd_watched_fd_t *p0,
  •       cupsd_watched_fd_t *p1)
    
    +{
  • if (p0->fd != p1->fd)
  • return (p0->fd < p1->fd ? -1 : 1);
  • if (p0 == p1)
  • return (0);
  • return (p0 < p1 ? -1 : 1);
    +}

+/*

  • * 'compare_timeouts' - Compare timeouts for array sorting
  • */
    +static int
    +compare_timeouts(AvahiTimeout *p0,
  •    AvahiTimeout *p1)
    
    +{
  • /*
  • * Just compare pointers to make it a stable sort.
  • */
  • if (p0->cupsd_timeout < p1->cupsd_timeout)
  • return (-1);
  • return ((p0->cupsd_timeout == p1->cupsd_timeout) ? 0 : 1);
    +}

+/*

  • * 'avahi_cups_poll_new' - Create a new Avahi main loop object for CUPS
  • */
    +
    +AvahiCupsPoll *
    +avahi_cups_poll_new (void)
    +{
  • AvahiCupsPoll *cups_poll = malloc(sizeof(AvahiCupsPoll));
  • if (cups_poll == NULL)
  • return (NULL);
  • cups_poll->watched_fds = cupsArrayNew ((cups_array_func_t)compare_watched_fds,
  •                NULL);
    
  • cups_poll->timeouts = cupsArrayNew ((cups_array_func_t)compare_timeouts,
  •                 NULL);
    
  • cups_poll->api.userdata = cups_poll;
  • cups_poll->api.watch_new = watch_new;
  • cups_poll->api.watch_free = watch_free;
  • cups_poll->api.watch_update = watch_update;
  • cups_poll->api.watch_get_events = watch_get_events;
  • cups_poll->api.timeout_new = timeout_new;
  • cups_poll->api.timeout_update = timeout_update;
  • cups_poll->api.timeout_free = timeout_free;
  • return (cups_poll);
    +}

+/*

  • * 'avahi_cups_poll_free' - Free an Avahi main loop object for CUPS
  • */
    +void
    +avahi_cups_poll_free (AvahiCupsPoll *cups_poll)
    +{
  • cupsd_watched_fd_t *watched_fd;
  • for (watched_fd = (cupsd_watched_fd_t*)cupsArrayFirst(cups_poll->watched_fds);
  •   watched_fd;
    
  •   watched_fd = (cupsd_watched_fd_t*)cupsArrayNext(cups_poll->watched_fds)){
    
  • cupsArrayClear (watched_fd->watches);
  • }
  • cupsArrayClear (cups_poll->watched_fds);
  • cupsArrayClear (cups_poll->timeouts);
    +}

+/*

  • * 'avahi_cups_poll_get' - Get the abstract poll API structure
  • */
    +
    +const AvahiPoll *
    +avahi_cups_poll_get (AvahiCupsPoll *cups_poll)
    +{
  • return (&cups_poll->api);
    +}

+#endif /* HAVE_AVAHI ... from top of file /
+
+/

  • * End of "$Id$".
  • /
    diff --git a/scheduler/avahi.h b/scheduler/avahi.h
    new file mode 100644
    index 0000000..05f441d
    --- /dev/null
    +++ b/scheduler/avahi.h
    @@ -0,0 +1,49 @@
    +/
  • * "$Id$"
  • * Avahi poll implementation for the CUPS scheduler.
  • * Copyright (C) 2010 Red Hat, Inc.
  • * Authors:
  • * Tim Waugh twaugh@redhat.com
  • * Distribution and use rights are outlined in the file "LICENSE.txt"
  • * which should have been included with this file. If this file is
  • * file is missing or damaged, see the license at "http://www.cups.org/".
  • /
    +
    +#include <config.h>
    +
    +#ifdef HAVE_AVAHI
    +# include <avahi-client/client.h>
    +# include <avahi-client/publish.h>
    +#endif /
    HAVE_AVAHI /
    +
    +#ifdef HAVE_AUTHORIZATION_H
    +# include <Security/Authorization.h>
    +#endif /
    HAVE_AUTHORIZATION_H */
    +
    +
    +#ifdef HAVE_AVAHI
    +typedef struct
    +{
  • AvahiPoll api;
  • cups_array_t *watched_fds;
  • cups_array_t timeouts;
    +} AvahiCupsPoll;
    +#endif /
    HAVE_AVAHI _/

+/_

  • * Prototypes...
  • /
    +
    +#ifdef HAVE_AVAHI
    +extern AvahiCupsPoll * avahi_cups_poll_new(void);
    +extern void avahi_cups_poll_free(AvahiCupsPoll *cups_poll);
    +extern const AvahiPoll *avahi_cups_poll_get(AvahiCupsPoll *cups_poll);
    +#endif /
    HAVE_AVAHI /
    +
    +
    +/
  • * End of "$Id$".

+ */

1.7.3.4

@michaelrsweet
Collaborator

"0004-Avahi-poll-API-implementation_v2.patch":

From 3aeafd44e8e0d5208e2ebdc65a2051942d766674 Mon Sep 17 00:00:00 2001
From: Tim Waugh twaugh@redhat.com
Date: Tue, 4 Jan 2011 16:12:00 +0000
Subject: [PATCH 4/4] Avahi poll API implementation.


scheduler/Makefile | 1 +
scheduler/avahi.c | 445 ++++++++++++++++++++++++++++++++++++++++++++++++++++
scheduler/avahi.h | 49 ++++++
3 files changed, 495 insertions(+), 0 deletions(-)
create mode 100644 scheduler/avahi.c
create mode 100644 scheduler/avahi.h

diff --git a/scheduler/Makefile b/scheduler/Makefile
index 81f8bab..b9a0149 100644
--- a/scheduler/Makefile
+++ b/scheduler/Makefile
@@ -17,6 +17,7 @@ include ../Makedefs

CUPSDOBJS =
auth.o \

  •   avahi.o \
    banners.o \
    cert.o \
    classes.o \
    
    diff --git a/scheduler/avahi.c b/scheduler/avahi.c
    new file mode 100644
    index 0000000..92e491b
    --- /dev/null
    +++ b/scheduler/avahi.c
    @@ -0,0 +1,445 @@
    +/*
  • * "$Id$"
  • * Avahi poll implementation for the CUPS scheduler.
  • * Copyright (C) 2010 Red Hat, Inc.
  • * Authors:
  • * Tim Waugh twaugh@redhat.com
  • * Distribution and use rights are outlined in the file "LICENSE.txt"
  • * "LICENSE" which should have been included with this file. If this
  • * file is missing or damaged, see the license at "http://www.cups.org/".
  • * Contents:
  • * watch_read_cb - Read callback for file descriptor
  • * watch_write_cb - Write callback for file descriptor
  • * watched_fd_add_select() - Call cupsdAddSelect() as needed
  • * watch_new() - Create a new file descriptor watch
  • * watch_free() - Free a file descriptor watch
  • * watch_update() - Update watched events for a file descriptor
  • * watch_get_events() - Get events that happened for a file descriptor
  • * timeout_cb() - Run a timed Avahi callback
  • * timeout_new() - Set a wakeup time
  • * timeout_update() - Update the expiration time for a timeout
  • * timeout_free() - Free a timeout
  • * compare_watched_fds() - Compare watched file descriptors for array sorting
  • * compare_timeouts() - Compare timeouts for array sorting
  • * avahi_cups_poll_new() - Create a new Avahi main loop object for CUPS
  • * avahi_cups_poll_free() - Free an Avahi main loop object for CUPS
  • * avahi_cups_poll_get() - Get the abstract poll API structure
  • /
    +
    +#include <config.h>
    +
    +#ifdef HAVE_AVAHI /
    Applies to entire file... /
    +
    +/
  • * Include necessary headers...
  • /
    +
    +#include "cupsd.h"
    +
    +#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
    +# include <malloc.h>
    +#endif /
    HAVE_MALLOC_H && HAVE_MALLINFO /
    +
    +#ifdef HAVE_AVAHI
    +# include <avahi-common/timeval.h>
    +#endif /
    HAVE_AVAHI */
    +
    +
    +typedef struct
    +{
  • AvahiCupsPoll *cups_poll;
  • int fd;
  • AvahiWatchEvent occurred;
  • cups_array_t *watches;
    +} cupsd_watched_fd_t;

+struct AvahiWatch
+{

  • cupsd_watched_fd_t *watched_fd;
  • AvahiWatchEvent events;
  • AvahiWatchCallback callback;
  • void *userdata;
    +};

+struct AvahiTimeout
+{

  • AvahiCupsPoll *cups_poll;
  • AvahiTimeoutCallback callback;
  • void *userdata;
  • cupsd_timeout_t _cupsd_timeout;
    +};

+/_

  • * Local functions...
  • */
    +
    +static AvahiWatch * watch_new(const AvahiPoll *api,
  •             int fd,
    
  •             AvahiWatchEvent events,
    
  •             AvahiWatchCallback callback,
    
  •             void *userdata);
    
    +static void watch_free(AvahiWatch *watch);
    +static void watch_update(AvahiWatch *watch,
  •                AvahiWatchEvent events);
    
    +static AvahiWatchEvent watch_get_events(AvahiWatch *watch);
    +static int compare_watches(AvahiWatch *p0,
  •               AvahiWatch _p1);
    
    +/_
  • * 'watch_read_cb' - Read callback for file descriptor
  • */
    +
    +static void
    +watch_read_cb (void *userdata)
    +{
  • AvahiWatch *watch;
  • cupsd_watched_fd_t *watched_fd = userdata;
  • watched_fd->occurred |= AVAHI_WATCH_IN;
  • for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
  •   watch;
    
  •   watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
    
  • if (watch->events & watched_fd->occurred) {
  •  (watch->callback) (watch, watched_fd->fd,
    
  •        AVAHI_WATCH_IN, watch->userdata);
    
  •  watched_fd->occurred &= ~AVAHI_WATCH_IN;
    
  •  break;
    
  • }
  • }
    +}

+/*

  • * 'watch_write_cb' - Write callback for file descriptor
  • */
    +
    +static void
    +watch_write_cb (void *userdata)
    +{
  • AvahiWatch *watch;
  • cupsd_watched_fd_t *watched_fd = userdata;
  • watched_fd->occurred |= AVAHI_WATCH_OUT;
  • for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
  •   watch;
    
  •   watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
    
  • if (watch->events & watched_fd->occurred) {
  •  (watch->callback) (watch, watched_fd->fd,
    
  •        AVAHI_WATCH_OUT, watch->userdata);
    
  •  watched_fd->occurred &= ~AVAHI_WATCH_OUT;
    
  •  break;
    
  • }
  • }
    +}

+/*

  • * 'watched_fd_add_select' - Call cupsdAddSelect() as needed
  • /
    +
    +static int /
    O - Watches? */
    +watched_fd_add_select (cupsd_watched_fd_t *watched_fd)
    +{
  • AvahiWatch *watch;
  • cupsd_selfunc_t read_cb = NULL, write_cb = NULL;
  • for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
  •   watch;
    
  •   watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
    
  • if (watch->events & (AVAHI_WATCH_IN |
  •            AVAHI_WATCH_ERR |
    
  •            AVAHI_WATCH_HUP)) {
    
  •  read_cb = (cupsd_selfunc_t)watch_read_cb;
    
  •  if (write_cb != NULL)
    
  • break;
  • }
  • if (watch->events & AVAHI_WATCH_OUT) {
  •  write_cb = (cupsd_selfunc_t)watch_write_cb;
    
  •  if (read_cb != NULL)
    
  • break;
  • }
  • }
  • if (read_cb || write_cb)
  • cupsdAddSelect (watched_fd->fd, read_cb, write_cb, watched_fd);
  • else
  • cupsdRemoveSelect (watched_fd->fd);
  • return (read_cb || write_cb);
    +}

+/*

  • * 'watch_new' - Create a new file descriptor watch
  • */
    +
    +static AvahiWatch *
    +watch_new (const AvahiPoll *api,
  •  int fd,
    
  •  AvahiWatchEvent events,
    
  •  AvahiWatchCallback callback,
    
  •  void *userdata)
    
    +{
  • cupsd_watched_fd_t key, *watched_fd;
  • AvahiCupsPoll *cups_poll = api->userdata;
  • AvahiWatch *watch = malloc(sizeof(AvahiWatch));
  • if (watch == NULL)
  • return (NULL);
  • watch->events = events;
  • watch->callback = callback;
  • watch->userdata = userdata;
  • key.fd = fd;
  • watched_fd = cupsArrayFind (cups_poll->watched_fds, &key);
  • if (watched_fd == NULL) {
  • watched_fd = malloc(sizeof(cupsd_watched_fd_t));
  • if (watched_fd == NULL) {
  •  free (watch);
    
  •  return (NULL);
    
  • }
  • watched_fd->fd = fd;
  • watched_fd->occurred = 0;
  • watched_fd->cups_poll = cups_poll;
  • watched_fd->watches = cupsArrayNew ((cups_array_func_t)compare_watches,
  •               NULL);
    
  • }
  • watch->watched_fd = watched_fd;
  • cupsArrayAdd(watched_fd->watches, watch);
  • watched_fd_add_select (watched_fd);
  • return (watch);
    +}

+/*

  • * 'watch_free' - Free a file descriptor watch
  • */
    +
    +static void
    +watch_free (AvahiWatch *watch)
    +{
  • cupsd_watched_fd_t *watched_fd = watch->watched_fd;
  • AvahiCupsPoll *cups_poll = watched_fd->cups_poll;
  • cupsArrayRemove (watched_fd->watches, watch);
  • free (watch);
  • if (!watched_fd_add_select (watched_fd)) {
  • /* No more watches */
  • cupsArrayRemove (cups_poll->watched_fds, watched_fd);
  • free (watched_fd);
  • }
    +}

+/*

  • * 'watch_update' - Update watched events for a file descriptor
  • */
    +
    +static void
    +watch_update (AvahiWatch *watch,
  •     AvahiWatchEvent events)
    
    +{
  • watch->events = events;
  • watched_fd_add_select (watch->watched_fd);
    +}

+/*

  • * 'watch_get_events' - Get events that happened for a file descriptor
  • */
    +
    +static AvahiWatchEvent
    +watch_get_events (AvahiWatch *watch)
    +{
  • return (watch->watched_fd->occurred);
    +}

+/*

  • * 'compare_watches' - Compare watches for array sorting
  • */
    +
    +static int
    +compare_watches (AvahiWatch *p0,
  •    AvahiWatch *p1)
    
    +{
  • if (p0->watched_fd->fd < p1->watched_fd->fd)
  • return (-1);
  • return ((p0->watched_fd->fd == p1->watched_fd->fd) ? 0 : 1);
    +}

+/*

  • * 'timeout_cb()' - Run a timed Avahi callback
  • */
    +
    +static void
    +timeout_cb (cupsd_timeout_t *cupsd_timeout, void *userdata)
    +{
  • AvahiTimeout *timeout = userdata;
  • (timeout->callback) (timeout, timeout->userdata);
    +}

+/*

  • * 'timeout_new' - Set a wakeup time
  • */
    +
    +static AvahiTimeout *
    +timeout_new (const AvahiPoll *api,
  •    const struct timeval *tv,
    
  •    AvahiTimeoutCallback callback,
    
  •    void *userdata)
    
    +{
  • AvahiTimeout *timeout;
  • AvahiCupsPoll *cups_poll = api->userdata;
  • timeout = malloc(sizeof(AvahiTimeout));
  • if (timeout == NULL)
  • return (NULL);
  • timeout->cups_poll = cups_poll;
  • timeout->callback = callback;
  • timeout->userdata = userdata;
  • timeout->cupsd_timeout = cupsdAddTimeout (tv,
  •                   (cupsd_timeoutfunc_t)timeout_cb,
    
  •                   timeout);
    
  • cupsArrayAdd (cups_poll->timeouts, timeout);
  • return (timeout);
    +}

+/*

  • * 'timeout_update' - Update the expiration time for a timeout
  • */
    +
    +static void
    +timeout_update (AvahiTimeout *timeout,
  •   const struct timeval *tv)
    
    +{
  • cupsdUpdateTimeout (timeout->cupsd_timeout, tv);
    +}

+/*

  • * ' timeout_free' - Free a timeout
  • */
    +
    +static void
    +timeout_free (AvahiTimeout *timeout)
    +{
  • cupsArrayRemove (timeout->cups_poll->timeouts, timeout);
  • cupsdRemoveTimeout (timeout->cupsd_timeout);
  • free (timeout);
    +}

+/*

  • * 'compare_watched_fds' - Compare watched file descriptors for array sorting
  • */
    +static int
    +compare_watched_fds(cupsd_watched_fd_t *p0,
  •       cupsd_watched_fd_t *p1)
    
    +{
  • if (p0->fd != p1->fd)
  • return (p0->fd < p1->fd ? -1 : 1);
  • if (p0 == p1)
  • return (0);
  • return (p0 < p1 ? -1 : 1);
    +}

+/*

  • * 'compare_timeouts' - Compare timeouts for array sorting
  • */
    +static int
    +compare_timeouts(AvahiTimeout *p0,
  •    AvahiTimeout *p1)
    
    +{
  • /*
  • * Just compare pointers to make it a stable sort.
  • */
  • if (p0->cupsd_timeout < p1->cupsd_timeout)
  • return (-1);
  • return ((p0->cupsd_timeout == p1->cupsd_timeout) ? 0 : 1);
    +}

+/*

  • * 'avahi_cups_poll_new' - Create a new Avahi main loop object for CUPS
  • */
    +
    +AvahiCupsPoll *
    +avahi_cups_poll_new (void)
    +{
  • AvahiCupsPoll *cups_poll = malloc(sizeof(AvahiCupsPoll));
  • if (cups_poll == NULL)
  • return (NULL);
  • cups_poll->watched_fds = cupsArrayNew ((cups_array_func_t)compare_watched_fds,
  •                NULL);
    
  • cups_poll->timeouts = cupsArrayNew ((cups_array_func_t)compare_timeouts,
  •                 NULL);
    
  • cups_poll->api.userdata = cups_poll;
  • cups_poll->api.watch_new = watch_new;
  • cups_poll->api.watch_free = watch_free;
  • cups_poll->api.watch_update = watch_update;
  • cups_poll->api.watch_get_events = watch_get_events;
  • cups_poll->api.timeout_new = timeout_new;
  • cups_poll->api.timeout_update = timeout_update;
  • cups_poll->api.timeout_free = timeout_free;
  • return (cups_poll);
    +}

+/*

  • * 'avahi_cups_poll_free' - Free an Avahi main loop object for CUPS
  • */
    +void
    +avahi_cups_poll_free (AvahiCupsPoll *cups_poll)
    +{
  • cupsd_watched_fd_t *watched_fd;
  • for (watched_fd = (cupsd_watched_fd_t*)cupsArrayFirst(cups_poll->watched_fds);
  •   watched_fd;
    
  •   watched_fd = (cupsd_watched_fd_t*)cupsArrayNext(cups_poll->watched_fds)){
    
  • cupsArrayClear (watched_fd->watches);
  • }
  • cupsArrayClear (cups_poll->watched_fds);
  • cupsArrayClear (cups_poll->timeouts);
    +}

+/*

  • * 'avahi_cups_poll_get' - Get the abstract poll API structure
  • */
    +
    +const AvahiPoll *
    +avahi_cups_poll_get (AvahiCupsPoll *cups_poll)
    +{
  • return (&cups_poll->api);
    +}

+#endif /* HAVE_AVAHI ... from top of file /
+
+/

  • * End of "$Id$".
  • /
    diff --git a/scheduler/avahi.h b/scheduler/avahi.h
    new file mode 100644
    index 0000000..05f441d
    --- /dev/null
    +++ b/scheduler/avahi.h
    @@ -0,0 +1,49 @@
    +/
  • * "$Id$"
  • * Avahi poll implementation for the CUPS scheduler.
  • * Copyright (C) 2010 Red Hat, Inc.
  • * Authors:
  • * Tim Waugh twaugh@redhat.com
  • * Distribution and use rights are outlined in the file "LICENSE.txt"
  • * which should have been included with this file. If this file is
  • * file is missing or damaged, see the license at "http://www.cups.org/".
  • /
    +
    +#include <config.h>
    +
    +#ifdef HAVE_AVAHI
    +# include <avahi-client/client.h>
    +# include <avahi-client/publish.h>
    +#endif /
    HAVE_AVAHI /
    +
    +#ifdef HAVE_AUTHORIZATION_H
    +# include <Security/Authorization.h>
    +#endif /
    HAVE_AUTHORIZATION_H */
    +
    +
    +#ifdef HAVE_AVAHI
    +typedef struct
    +{
  • AvahiPoll api;
  • cups_array_t *watched_fds;
  • cups_array_t timeouts;
    +} AvahiCupsPoll;
    +#endif /
    HAVE_AVAHI _/

+/_

  • * Prototypes...
  • /
    +
    +#ifdef HAVE_AVAHI
    +extern AvahiCupsPoll * avahi_cups_poll_new(void);
    +extern void avahi_cups_poll_free(AvahiCupsPoll *cups_poll);
    +extern const AvahiPoll *avahi_cups_poll_get(AvahiCupsPoll *cups_poll);
    +#endif /
    HAVE_AVAHI /
    +
    +
    +/
  • * End of "$Id$".

+ */

1.7.4

@michaelrsweet
Collaborator

"cups-1-avahi-config.patch":

diff --git a/config-scripts/cups-dnssd.m4 b/config-scripts/cups-dnssd.m4
index 66a400b..5b17603 100644
--- a/config-scripts/cups-dnssd.m4
+++ b/config-scripts/cups-dnssd.m4
@@ -23,6 +23,21 @@ AC_ARG_WITH(dnssd-includes, [ --with-dnssd-includes set directory for DNS Ser
DNSSDLIBS=""
DNSSD_BACKEND=""

+AC_ARG_ENABLE(avahi, [ --enable-avahi turn on DNS Service Discovery support, default=no],

  •     [if test x$enable_avahi = xyes; then
    
  •          AC_MSG_CHECKING(for Avahi)
    
  •          if $PKGCONFIG --exists avahi-client; then
    
  •              AC_MSG_RESULT(yes)
    
  •              CFLAGS="$CFLAGS `$PKGCONFIG --cflags avahi-client`"
    
  •              DNSSDLIBS="`$PKGCONFIG --libs avahi-client`"
    
  •              DNSSD_BACKEND="dnssd"
    
  •              AC_DEFINE(HAVE_AVAHI)
    
  •              enable_dnssd=no
    
  •          else
    
  •              AC_MSG_RESULT(no)
    
  •          fi
    
  •      fi])
    

    if test x$enable_dnssd != xno; then
    AC_CHECK_HEADER(dns_sd.h, [
    case "$uname" in
    diff --git a/config.h.in b/config.h.in
    index 8d4cd42..6182be8 100644
    --- a/config.h.in
    +++ b/config.h.in
    @@ -390,6 +390,13 @@

    /*

  • * Do we have Avahi for DNS Service Discovery?

  • /
    +
    +#undef HAVE_AVAHI
    +
    +
    +/

    • Do we have <sys/ioctl.h>?
      */
@michaelrsweet
Collaborator

"cups-2-avahi-backend.patch":

diff --git a/backend/dnssd.c b/backend/dnssd.c
index d1392ed..a35a9cc 100644
--- a/backend/dnssd.c
+++ b/backend/dnssd.c
@@ -15,14 +15,21 @@
*

  • Contents:
    *
    • * next_txt_record() - Get next TXT record from a cups_txt_records_t.
    • * parse_txt_record_pair() - Read key/value pair in cups_txt_records_t.
  • main() - Browse for printers.
  • browse_callback() - Browse devices.
  • browse_local_callback() - Browse local devices.
  • compare_devices() - Compare two devices.
  • exec_backend() - Execute the backend that corresponds to the
  •                         resolved service name.
    
    • * device_type() - Get DNS-SD type enumeration from string.
  • get_device() - Create or update a device.
  • query_callback() - Process query data.
  • * avahi_client_callback() - Avahi client callback function.
  • * avahi_query_callback() - Avahi query callback function.
  • * avahi_browse_callback() - Avahi browse callback function.
  • * find_device() - Find a device from its name and domain.
  • sigterm_handler() - Handle termination signals...
  • unquote() - Unquote a name string.
    */
    @@ -33,7 +40,18 @@

#include "backend-private.h"
#include <cups/array.h>
-#include <dns_sd.h>
+#ifdef HAVE_DNSSD
+# include <dns_sd.h>
+#endif /* HAVE_DNSSD /
+#ifdef HAVE_AVAHI
+# include <avahi-client/client.h>
+# include <avahi-client/lookup.h>
+# include <avahi-common/simple-watch.h>
+# include <avahi-common/domain.h>
+# include <avahi-common/error.h>
+# include <avahi-common/malloc.h>
+#define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX
+#endif /
HAVE_AVAHI */

/*
@@ -53,7 +71,12 @@ typedef enum

typedef struct
{
+#ifdef HAVE_DNSSD
DNSServiceRef ref; /* Service reference for resolve /
+#endif /
HAVE_DNSSD */
+#ifdef HAVE_AVAHI

  • int resolved; /* Did we resolve the device? /
    +#endif /
    HAVE_AVAHI /
    char *name, /
    Service name /
    *domain, /
    Domain name /
    *fullName, /
    Full name /
    @@ -65,6 +88,20 @@ typedef struct
    sent; /
    Did we list the device? */
    } cups_device_t;

+typedef struct
+{

  • char key[256];
  • char value[256];

+#ifdef HAVE_DNSSD

  • const uint8_t *data;
  • const uint8_t *datanext;
  • const uint8_t dataend;
    +#else /
    HAVE_AVAHI */
  • AvahiStringList txt;
    +#endif /
    HAVE_DNSSD */
    +} cups_txt_records_t;

/*

  • Local globals...
    @@ -78,6 +115,7 @@ static int job_canceled = 0;
  • Local functions...
    */

+#ifdef HAVE_DNSSD
static void browse_callback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
@@ -93,12 +131,6 @@ static void browse_local_callback(DNSServiceRef sdRef,
const char _regtype,
const char *replyDomain,
void *context);
-static int compare_devices(cups_device_t *a, cups_device_t *b);
-static void exec_backend(char *_argv);
-static cups_device_t *get_device(cups_array_t *devices,

  •                   const char *serviceName,
    
  •                   const char *regtype,
    
  •               const char _replyDomain);
    
    static void query_callback(DNSServiceRef sdRef,
    DNSServiceFlags flags,
    uint32_t interfaceIndex,
    @@ -107,9 +139,118 @@ static void query_callback(DNSServiceRef sdRef,
    uint16_t rrclass, uint16_t rdlen,
    const void *rdata, uint32_t ttl,
    void *context);
    +#endif /_ HAVE_DNSSD */
    +#ifdef HAVE_AVAHI
    +static void avahi_client_callback (AvahiClient *client,
  •                      AvahiClientState state,
    
  •                      void *context);
    
    +static void avahi_browse_callback (AvahiServiceBrowser *browser,
  •                      AvahiIfIndex interface,
    
  •                      AvahiProtocol protocol,
    
  •                      AvahiBrowserEvent event,
    
  •                      const char *serviceName,
    
  •                      const char *regtype,
    
  •                      const char *replyDomain,
    
  •                      AvahiLookupResultFlags flags,
    
  •                      void _context);
    
    +#endif /_ HAVE_AVAHI */
    +
    +static cups_device_t * find_device (cups_array_t *devices,
  •                cups_txt_records_t *txt,
    
  •                cups_device_t _dkey);
    
    +static int compare_devices(cups_device_t *a, cups_device_t *b);
    +static void exec_backend(char *_argv);
    +static cups_device_t *get_device(cups_array_t *devices,
  •                   const char *serviceName,
    
  •                   const char *regtype,
    
  •               const char *replyDomain);
    
    static void sigterm_handler(int sig);
    static void unquote(char *dst, const char *src, size_t dstsize);

+#ifdef HAVE_AVAHI
+static AvahiSimplePoll simple_poll = NULL;
+static int avahi_got_callback;
+#endif /
HAVE_AVAHI /
+
+
+/

  • * 'next_txt_record()' - Get next TXT record from a cups_txt_records_t.
  • */
    +
    +static cups_txt_records_t *
    +next_txt_record (cups_txt_records_t *txt)
    +{
    +#ifdef HAVE_DNSSD
  • txt->data = txt->datanext;
    +#else /* HAVE_AVAHI */
  • txt->txt = avahi_string_list_get_next (txt->txt);
  • if (txt->txt == NULL)
  • return NULL;
    +#endif /* HAVE_DNSSD */
  • return txt;
    +}

+/*

  • * 'parse_txt_record_pair()' - Read key/value pair in cups_txt_records_t.
  • */
    +
    +static int
    +parse_txt_record_pair (cups_txt_records_t *txt)
    +{
    +#ifdef HAVE_DNSSD
  • uint8_t datalen;
  • uint8_t *data = txt->data;
  • char *ptr;
  • /*
  • * Read a key/value pair starting with an 8-bit length. Since the
  • * length is 8 bits and the size of the key/value buffers is 256, we
  • * don't need to check for overflow...
  • */
  • datalen = *data++;
  • if (!datalen || (data + datalen) >= txt->dataend)
  • return NULL;
  • txt->datanext = data + datalen;
  • for (ptr = txt->key; data < txt->datanext && *data != '='; data ++)
  • *ptr++ = *data;
  • *ptr = '\0';
  • if (data < txt->datanext && *data == '=')
  • {
  • data++;
  • if (data < datanext)
  •  memcpy (txt->value, data, txt->datanext - data);
    
  • value[txt->datanext - data] = '\0';
  • }
  • else
  • return 1;
    +#else /* HAVE_AVAHI */
  • char *key, *value;
  • size_t len;
  • avahi_string_list_get_pair (txt->txt, &key, &value, &len);
  • if (len > sizeof (txt->value) - 1)
  • len = sizeof (txt->value) - 1;
  • memcpy (txt->value, value, len);
  • txt->value[len] = '\0';
  • len = strlen (key);
  • if (len > sizeof (txt->key) - 1)
  • len = sizeof (txt->key) - 1;
  • memcpy (txt->key, key, len);
  • txt->key[len] = '\0';
  • avahi_free (key);
  • avahi_free (value);
    +#endif /* HAVE_AVAHI */
  • return 0;
    +}

/*

  • 'main()' - Browse for printers.
    @@ -120,6 +261,13 @@ main(int argc, /* I - Number of command-line args /
    char *argv[]) /
    I - Command-line arguments /
    {
    const char *name; /
    Backend name */
  • cups_array_t devices; / Device array */
  • cups_device_t device; / Current device */
  • char uriName[1024]; /* Unquoted fullName for URI */
    +#ifdef HAVE_DNSSD
  • int fd; /* Main file descriptor */
  • fd_set input; /* Input set for select() */
  • struct timeval timeout; /* Timeout for select() /
    DNSServiceRef main_ref, /
    Main service reference /
    fax_ipp_ref, /
    IPP fax service reference /
    ipp_ref, /
    IPP service reference /
    @@ -133,12 +281,11 @@ main(int argc, /
    I - Number of command-line args /
    pdl_datastream_ref, /
    AppSocket service reference /
    printer_ref, /
    LPD service reference /
    riousbprint_ref; /
    Remote IO service reference */
  • int fd; /* Main file descriptor */
  • fd_set input; /* Input set for select() */
  • struct timeval timeout; /* Timeout for select() */
  • cups_array_t devices; / Device array */
  • cups_device_t device; / Current device */
  • char uriName[1024]; /* Unquoted fullName for URI /
    +#endif /
    HAVE_DNSSD */
    +#ifdef HAVE_AVAHI
  • AvahiClient *client;
  • int error;
    +#endif /* HAVE_AVAHI /
    #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
    struct sigaction action; /
    Actions for POSIX signals /
    #endif /
    HAVE_SIGACTION && !HAVE_SIGSET /
    @@ -198,6 +345,49 @@ main(int argc, /
    I - Number of command-line args */
  • Browse for different kinds of printers...
    */

+#ifdef HAVE_AVAHI

  • if ((simple_poll = avahi_simple_poll_new ()) == NULL)
  • {
  • perror ("ERROR: Unable to create avahi simple poll object");
  • return (1);
  • }
  • client = avahi_client_new (avahi_simple_poll_get (simple_poll),
  •            0, avahi_client_callback, NULL, &error);
    
  • if (!client)
  • {
  • perror ("DEBUG: Unable to create avahi client");
  • return (0);
  • }
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_fax-ipp._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_ipp._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_ipp-tls._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_pdl-datastream._tcp",
    
  •            NULL, 0,
    
  •            avahi_browse_callback,
    
  •            devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_printer._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_riousbprint._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    

    +#endif /* HAVE_AVAHI /
    +#ifdef HAVE_DNSSD
    if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError)
    {
    perror("ERROR: Unable to create service connection");
    @@ -258,6 +448,7 @@ main(int argc, /
    I - Number of command-line args _/
    riousbprint_ref = main_ref;
    DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0,
    "_riousbprint.tcp", NULL, browse_callback, devices);
    +#endif /
    HAVE_DNSSD */

    /*

    • Loop until we are killed...
      @@ -265,6 +456,9 @@ main(int argc, /* I - Number of command-line args */

    while (!job_canceled)
    {

  • int announce = 0;

+#ifdef HAVE_DNSSD
FD_ZERO(&input);
FD_SET(fd, &input);

@@ -284,11 +478,35 @@ main(int argc, /* I - Number of command-line args */
}
else
{

  •  announce = 1;
    
  • }
    +#else /* HAVE_AVAHI */
  • int r;
  • avahi_got_callback = 0;
  • r = avahi_simple_poll_iterate (simple_poll, 1);
  • if (r != 0 && r != EINTR)
  • {
  • /*
    
  •  \* We've been told to exit the loop.  Perhaps the connection to
    
  •  \* avahi failed.
    
  •  */
    
  •  break;
    
  • }
  • if (avahi_got_callback)
  •  announce = 1;
    
    +#endif /* HAVE_DNSSD */
    +
  • if (announce)
  • {
    /*
  • Announce any devices we've found...
    */

+#ifdef HAVE_DNSSD
DNSServiceErrorType status; /* DNS query status /
+#endif /
HAVE_DNSSD /
cups_device_t *best; /
Best matching device /
char device_uri[1024]; /
Device URI /
int count; /
Number of queries /
@@ -302,6 +520,7 @@ main(int argc, /
I - Number of command-line args */
if (device->sent)
sent ++;

+#ifdef HAVE_DNSSD
if (device->ref)
count ++;

@@ -333,14 +552,23 @@ main(int argc, /* I - Number of command-line args */
count ++;
}
}

  • else if (!device->sent)

  • else
    +#endif /* HAVE_DNSSD */
    +#ifdef HAVE_AVAHI

  • if (!device->resolved)

  • continue;
    
  •    else
    

    +#endif /* HAVE_AVAHI */

  • if (!device->sent)
    {
    +#ifdef HAVE_DNSSD
    /*

  • Got the TXT records, now report the device...
    */

    DNSServiceRefDeallocate(device->ref);
    device->ref = 0;
    +#endif /* HAVE_DNSSD */

    if (!best)
    best = device;
    @@ -401,6 +629,7 @@ main(int argc, /* I - Number of command-line args */
    }

+#ifdef HAVE_DNSSD
/*

  • 'browse_callback()' - Browse devices.
    /
    @@ -489,6 +718,7 @@ browse_local_callback(
    device->fullName);
    device->sent = 1;
    }
    +#endif /
    HAVE_DNSSD */

    /*
    @@ -569,6 +799,41 @@ exec_backend(char *argv) / I - Command-line arguments */

    /*

    • * 'device_type()' - Get DNS-SD type enumeration from string.
    • */
      +
      +static int
      +device_type (const char *regtype)
      +{
      +#ifdef HAVE_AVAHI
    • if (!strcmp(regtype, "_ipp._tcp"))
    • return (CUPS_DEVICE_IPP);
    • else if (!strcmp(regtype, "_ipps._tcp") ||
    •  !strcmp(regtype, "_ipp-tls._tcp"))
      
    • return (CUPS_DEVICE_IPPS);
    • else if (!strcmp(regtype, "_fax-ipp._tcp"))
    • return (CUPS_DEVICE_FAX_IPP);
    • else if (!strcmp(regtype, "_printer._tcp"))
    • return (CUPS_DEVICE_PDL_DATASTREAM);
      +#else
    • if (!strcmp(regtype, "_ipp._tcp."))
    • return (CUPS_DEVICE_IPP);
    • else if (!strcmp(regtype, "_ipps._tcp.") ||
    •  !strcmp(regtype, "_ipp-tls._tcp."))
      
    • return (CUPS_DEVICE_IPPS);
    • else if (!strcmp(regtype, "_fax-ipp._tcp."))
    • return (CUPS_DEVICE_FAX_IPP);
    • else if (!strcmp(regtype, "_printer._tcp."))
    • return (CUPS_DEVICE_PRINTER);
    • else if (!strcmp(regtype, "_pdl-datastream._tcp."))
    • return (CUPS_DEVICE_PDL_DATASTREAM);
      +#endif /* HAVE_AVAHI */
    • return (CUPS_DEVICE_RIOUSBPRINT);
      +}

    +/*

  • 'get_device()' - Create or update a device.
    */

@@ -589,20 +854,7 @@ get_device(cups_array_t devices, / I - Device array */
*/

key.name = (char *)serviceName;

  • if (!strcmp(regtype, "_ipp._tcp."))
  • key.type = CUPS_DEVICE_IPP;
  • else if (!strcmp(regtype, "_ipps._tcp.") ||
  •  !strcmp(regtype, "_ipp-tls._tcp."))
    
  • key.type = CUPS_DEVICE_IPPS;
  • else if (!strcmp(regtype, "_fax-ipp._tcp."))
  • key.type = CUPS_DEVICE_FAX_IPP;
  • else if (!strcmp(regtype, "_printer._tcp."))
  • key.type = CUPS_DEVICE_PRINTER;
  • else if (!strcmp(regtype, "_pdl-datastream._tcp."))
  • key.type = CUPS_DEVICE_PDL_DATASTREAM;
  • else
  • key.type = CUPS_DEVICE_RIOUSBPRINT;
  • key.type = device_type (regtype);

for (device = cupsArrayFind(devices, &key);
device;
@@ -622,8 +874,14 @@ get_device(cups_array_t devices, / I - Device array */
free(device->domain);
device->domain = strdup(replyDomain);

+#ifdef HAVE_DNSSD
DNSServiceConstructFullName(fullName, device->name, regtype,
replyDomain);
+#else /* HAVE_AVAHI */

  • avahi_service_name_join (fullName, kDNSServiceMaxDomainName,
  •            serviceName, regtype, replyDomain);
    
    +#endif /* HAVE_DNSSD /
    +
    free(device->fullName);
    device->fullName = strdup(fullName);
    }
    @@ -643,6 +901,9 @@ get_device(cups_array_t *devices, /
    I - Device array */
    device->domain = strdup(replyDomain);
    device->type = key.type;
    device->priority = 50;
    +#ifdef HAVE_AVAHI
  • device->resolved = 0;
    +#endif /* HAVE_AVAHI */

cupsArrayAdd(devices, device);

@@ -650,13 +911,20 @@ get_device(cups_array_t devices, / I - Device array */

  • Set the "full name" of this service, which is used for queries...
    */

+#ifdef HAVE_DNSSD
DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain);
+#else /* HAVE_AVAHI */

  • avahi_service_name_join (fullName, kDNSServiceMaxDomainName,

  •          serviceName, regtype, replyDomain);
    

    +#endif /* HAVE_DNSSD */
    +
    device->fullName = strdup(fullName);

    return (device);
    }

+#ifdef HAVE_DNSSD
/*

  • 'query_callback()' - Process query data.
    /
    @@ -680,7 +948,7 @@ query_callback(
    *ptr; /
    Pointer into string /
    cups_device_t dkey, /
    Search key */

    device; / Device */

    • cups_txt_records_t txt;

    fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, "
    "interfaceIndex=%d, errorCode=%d, fullName="%s", "
    @@ -714,94 +982,233 @@ query_callback(
    if ((ptr = strstr(name, "._")) != NULL)
    *ptr = '\0';

  • if (strstr(fullName, "_ipp._tcp."))

  • dkey.type = CUPS_DEVICE_IPP;

  • else if (strstr(fullName, "_ipps._tcp.") ||

  •       strstr(fullName, "_ipp-tls._tcp."))
    
  • dkey.type = CUPS_DEVICE_IPPS;

  • else if (strstr(fullName, "_fax-ipp._tcp."))

  • dkey.type = CUPS_DEVICE_FAX_IPP;

  • else if (strstr(fullName, "_printer._tcp."))

  • dkey.type = CUPS_DEVICE_PRINTER;

  • else if (strstr(fullName, "_pdl-datastream._tcp."))

  • dkey.type = CUPS_DEVICE_PDL_DATASTREAM;

  • dkey.type = device_type (fullName);

  • txt.data = rdata;
  • txt.dataend = rdata + rdlen;
  • device = find_device ((cups_array_t *) context, &txt, &dkey);
  • if (!device)
  • fprintf(stderr, "DEBUG: Ignoring TXT record for "%s"...\n", fullName);
    +}
    +#endif /* HAVE_DNSSD _/

+#ifdef HAVE_AVAHI
+/_

  • * 'avahi_client_callback()' - Avahi client callback function.
  • */
    +
    +static void
    +avahi_client_callback(AvahiClient *client,
  •         AvahiClientState state,
    
  •         void *context)
    
    +{
  • /*
  • * If the connection drops, quit.
  • */
  • if (state == AVAHI_CLIENT_FAILURE)
  • {
  • fprintf (stderr, "ERROR: Avahi connection failed\n");
  • avahi_simple_poll_quit (simple_poll);
  • }
    +}

+/*

  • * 'avahi_query_callback()' - Avahi query callback function.
  • */
    +
    +static void
    +avahi_query_callback(AvahiServiceResolver *resolver,
  •        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 *context)
    
    +{
  • AvahiClient *client;
  • cups_device_t key,
  •       *device;
    
  • char uqname[1024],
  •       *ptr;
    
  • cups_txt_records_t txtr;
  • client = avahi_service_resolver_get_client (resolver);
  • if (event != AVAHI_RESOLVER_FOUND)
  • {
  • if (event == AVAHI_RESOLVER_FAILURE)
  • {
  •  fprintf (stderr, "ERROR: %s\n",
    
  •      avahi_strerror (avahi_client_errno (client)));
    
  • }
  • avahi_service_resolver_free (resolver);
  • return;
  • }
  • /*
  • * Set search key for device.
  • */
  • key.name = uqname;
  • unquote (uqname, name, sizeof (uqname));
  • if ((ptr = strstr(name, "._")) != NULL)
  • *ptr = '\0';
  • key.domain = (char *) domain;
  • key.type = device_type (type);
  • /*
  • * Find the device and the the TXT information.
  • */
  • txtr.txt = txt;
  • device = find_device ((cups_array_t *) context, &txtr, &key);
  • if (device)
  • {
  • /*
  • * Let the main loop know to announce the device.
  • */
  • device->resolved = 1;
  • avahi_got_callback = 1;
  • }
    else
  • dkey.type = CUPS_DEVICE_RIOUSBPRINT;
  • fprintf (stderr, "DEBUG: Ignoring TXT record for "%s"...\n", name);
  • avahi_service_resolver_free (resolver);
    +}
  • for (device = cupsArrayFind(devices, &dkey);

+/*

  • * 'avahi_browse_callback()' - Avahi browse callback function.
  • */
    +
    +static void
    +avahi_browse_callback(AvahiServiceBrowser *browser,
  •         AvahiIfIndex interface,
    
  •         AvahiProtocol protocol,
    
  •         AvahiBrowserEvent event,
    
  •         const char *name,
    
  •         const char *type,
    
  •         const char *domain,
    
  •         AvahiLookupResultFlags flags,
    
  •         void *context)
    
    +{
  • AvahiClient *client = avahi_service_browser_get_client (browser);
  • switch (event)
  • {
  • case AVAHI_BROWSER_FAILURE:
  • fprintf (stderr, "ERROR: %s\n",
  •    avahi_strerror (avahi_client_errno (client)));
    
  • avahi_simple_poll_quit (simple_poll);
  • return;
  • case AVAHI_BROWSER_NEW:
  • /*
  • * This object is new on the network.
  • */
  • if (flags & AVAHI_LOOKUP_RESULT_LOCAL)
  • {
  • /*
    
  •  \* This comes from the local machine so ignore it.
    
  •  */
    
  •  fprintf (stderr, "DEBUG: ignoring local service %s\n", name);
    
  • }
  • else
  • {
  • /*
    
  •  \* Create a device entry for it if it doesn't yet exist.
    
  •  */
    
  •  get_device ((cups_array_t *)context, name, type, domain);
    
  • /*
    
  •  \* Now look for a TXT entry.
    
  •  */
    
  •  if (avahi_service_resolver_new (client, interface, protocol,
    
  •                 name, type, domain,
    
  •                 AVAHI_PROTO_UNSPEC, 0,
    
  •                 avahi_query_callback, context) == NULL)
    
  •  {
    
  • fprintf (stderr, "ERROR: failed to resolve service %s: %s\n",
  •    name, avahi_strerror (avahi_client_errno (client)));
    
  •  }
    
  • }
  • break;
  • case AVAHI_BROWSER_REMOVE:
  • case AVAHI_BROWSER_ALL_FOR_NOW:
  • case AVAHI_BROWSER_CACHE_EXHAUSTED:
  • break;
  • }
    +}
    +#endif /* HAVE_AVAHI _/

+/_

  • * 'find_device()' - Find a device from its name and domain.
  • */
    +
    +static cups_device_t *
    +find_device (cups_array_t *devices,
  •    cups_txt_records_t *txt,
    
  •    cups_device_t *dkey)
    
    +{
  • cups_device_t *device;
  • char *ptr;
  • for (device = cupsArrayFind(devices, dkey);
    device;
    device = cupsArrayNext(devices))
    {
  • if (_cups_strcasecmp(device->name, dkey.name) ||
  •    _cups_strcasecmp(device->domain, dkey.domain))
    
  • if (_cups_strcasecmp(device->name, dkey->name) ||
  •    _cups_strcasecmp(device->domain, dkey->domain))
    
    {
    device = NULL;
    break;
    }
  • else if (device->type == dkey.type)
  • else if (device->type == dkey->type)
    {
    /*
  • Found it, pull out the priority and make and model from the TXT
  • record and save it...
    */
  •  const uint8_t    *data,      /* Pointer into data */
    
  •       _datanext,  /_ Next key/value pair */
    
  •       _dataend;   /_ End of entire TXT record */
    
  •  uint8_t      datalen;    /\* Length of current key/value pair */
    
  •  char     key[256],   /\* Key string */
    
  •       value[256], /\* Value string */
    
  •       make_and_model[512],
    
  •  char     make_and_model[512],
                    /\* Manufacturer and model _/
        model[256], /_ Model */
    

- device_id[2048];/* 1284 device ID */

  •       device_id[2048]; /* 1284 device ID */
    

    device_id[0] = '\0';
    make_and_model[0] = '\0';

    strcpy(model, "Unknown");

  •  for (data = rdata, dataend = data + rdlen;
    
  •       data < dataend;
    
  •       data = datanext)
    
  •  for (;;)
    

    {

  •   /*
    
  •    \* Read a key/value pair starting with an 8-bit length.  Since the
    
  • * length is 8 bits and the size of the key/value buffers is 256, we

  • * don't need to check for overflow...

  • */

  • char *key;

  • char *value;

  •    datalen = *data++;
    
  • if (parse_txt_record_pair (txt))

  • goto next;
    
  •    if (!datalen || (data + datalen) >= dataend)
    

- break;

- datanext = data + datalen;

  •    for (ptr = key; data < datanext && *data != '='; data ++)
    
  • *ptr++ = *data;
    

- *ptr = '\0';

  • if (data < datanext && *data == '=')
  • {

- data ++;

  • if (data < datanext)
    
  •   memcpy(value, data, datanext - data);
    

- value[datanext - data] = '\0';

  • fprintf(stderr, "DEBUG2: query_callback: \"%s=%s\".\n",
    
  •         key, value);
    
  • }
  • else
  • {
  • fprintf(stderr, "DEBUG2: query_callback: \"%s\" with no value.\n",
    
  •         key);
    
  • continue;
    

- }

  •    if (!_cups_strncasecmp(key, "usb_", 4))
    
  • key = txt->key;

  • value = txt->value;

  •    if (!strncasecmp(key, "usb_", 4))
    

    {
    /*

    • Add USB device ID information...
      @@ -856,6 +1263,10 @@ query_callback(
      if (device->type == CUPS_DEVICE_PRINTER)
      device->sent = 1;
      }
      +
  •  next:
    
  • if (next_txt_record (txt) == NULL)

  • break;
    

    }

    if (device->device_id)
    @@ -905,11 +1316,9 @@ query_callback(
    }
    }

  • if (!device)

  • fprintf(stderr, "DEBUG: Ignoring TXT record for "%s"...\n", fullName);

  • return device;
    }

/*

  • 'sigterm_handler()' - Handle termination signals...
    */
    diff --git a/cups/http-support.c b/cups/http-support.c
    index 11c4604..1e65fe3 100644
    --- a/cups/http-support.c
    +++ b/cups/http-support.c
    @@ -43,6 +43,10 @@
  • http_copy_decode() - Copy and decode a URI.
  • http_copy_encode() - Copy and encode a URI.
  • http_resolve_cb() - Build a device URI for the given service name.
  • * avahi_resolve_uri_client_cb()
  • * - Avahi client callback for resolving URI.
  • * avahi_resolve_uri_resolver_cb()
  • * - Avahi resolver callback for resolving URI.
    */

/*
@@ -60,6 +64,11 @@

include <sys/select.h>

endif /* WIN32 */

#endif /* HAVE_DNSSD /
+#ifdef HAVE_AVAHI
+# include <avahi-client/client.h>
+# include <avahi-client/lookup.h>
+# include <avahi-common/simple-watch.h>
+#endif /
HAVE_AVAHI */

/*
@@ -127,6 +136,24 @@ static void DNSSD_API http_resolve_cb(DNSServiceRef sdRef,
void context);
#endif /
HAVE_DNSSD */

+#ifdef HAVE_AVAHI
+static void avahi_resolve_uri_client_cb(AvahiClient *client,

  •                   AvahiClientState state,
    
  •                   void *simple_poll);
    

    +static void avahi_resolve_uri_resolver_cb(AvahiServiceResolver *resolver,

  •                     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 *context);
    

    +#endif /* HAVE_AVAHI */

    /*

    • 'httpAssembleURI()' - Assemble a uniform resource identifier from its
      @@ -1431,6 +1458,9 @@ _httpResolveURI(

    if (strstr(hostname, "._tcp"))
    {
    +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)

  • char regtype, / Pointer to type in hostname */

  •       _domain;    /_ Pointer to domain in hostname _/
    

    #ifdef HAVE_DNSSD

    ifdef WIN32

    pragma comment(lib, "dnssd.lib")

    @@ -1449,6 +1479,17 @@ httpResolveURI(
    fd_set input_set; /
    Input set for select() /
    struct timeval stimeout; /
    Timeout value for select() /
    #endif /
    HAVE_POLL /
    +#else /
    HAVE_AVAHI */

  • AvahiSimplePoll *simple_poll;

  • AvahiClient *client;

  • int error;

  • struct

  • {

  •  AvahiSimplePoll  *poll;
    
  •  _http_uribuf_t   uribuf;
    
  • } user_data;
    +#endif /* HAVE_DNSSD */

if (options & _HTTP_RESOLVE_STDERR)
fprintf(stderr, "DEBUG: Resolving "%s"...\n", hostname);
@@ -1485,9 +1526,16 @@ _httpResolveURI(
if (domain)
*domain++ = '\0';

+#ifdef HAVE_DNSSD
uribuf.buffer = resolved_uri;
uribuf.bufsize = resolved_size;
uribuf.options = options;
+#else

  • user_data.uribuf.buffer = resolved_uri;
  • user_data.uribuf.bufsize = resolved_size;
  • user_data.uribuf.options = options;
    +#endif

resolved_uri[0] = '\0';

DEBUG_printf(("6_httpResolveURI: Resolving hostname="%s", regtype="%s", "
@@ -1501,6 +1549,7 @@ _httpResolveURI(

uri = NULL;

+#ifdef HAVE_DNSSD
if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError)
{
localref = ref;
@@ -1608,6 +1657,36 @@ _httpResolveURI(

   DNSServiceRefDeallocate(ref);
 }

+#else /* HAVE_AVAHI */

  • if ((simple_poll = avahi_simple_poll_new ()) != NULL)
  • {
  •  if ((client = avahi_client_new (avahi_simple_poll_get (simple_poll),
    
  •                 0, avahi_resolve_uri_client_cb,
    
  •                 &simple_poll, &error)) != NULL)
    
  •  {
    
  • user_data.poll = simple_poll;
  • if (avahi_service_resolver_new (client, AVAHI_IF_UNSPEC,
  •               AVAHI_PROTO_UNSPEC, hostname,
    
  •               regtype, domain, AVAHI_PROTO_UNSPEC, 0,
    
  •               avahi_resolve_uri_resolver_cb,
    
  •               &user_data) != NULL)
    
  • {
  • avahi_simple_poll_loop (simple_poll);
    
  • /*
  • \* Collect the result.
    
  • */
    
  • if (resolved_uri[0])
    
  •   uri = resolved_uri;
    
  • }
  • avahi_client_free (client);
  •  }
    
  •  avahi_simple_poll_free (simple_poll);
    
  • }
    +#endif /* HAVE_DNSSD */

if (options & _HTTP_RESOLVE_STDERR)
{
@@ -1619,13 +1698,13 @@ _httpResolveURI(
fputs("STATE: -connecting-to-device,offline-report\n", stderr);
}

-#else
+#else /* HAVE_DNSSD || HAVE_AVAHI /
/

* No DNS-SD support...
*/

 uri = NULL;

-#endif /* HAVE_DNSSD /
+#endif /
HAVE_DNSSD || HAVE_AVAHI */

 if ((options & _HTTP_RESOLVE_STDERR) && !uri)
   _cupsLangPrintFilter(stderr, "ERROR", _("Unable to find printer."));

@@ -1895,6 +1974,116 @@ http_resolve_cb(
#endif /* HAVE_DNSSD */

+#ifdef HAVE_AVAHI
+/*

  • * 'avahi_resolve_uri_client_cb()' - Avahi client callback for resolving URI.
  • */
    +
    +static void
    +avahi_resolve_uri_client_cb (AvahiClient *client,
  •            AvahiClientState state,
    
  •            void *simple_poll)
    
    +{
  • DEBUG_printf(("avahi_resolve_uri_client_callback(client=%p, state=%d, "
  •   "simple_poll=%p)\n", client, state, simple_poll));
    
  • /*
  • * If the connection drops, quit.
  • */
  • if (state == AVAHI_CLIENT_FAILURE)
  • avahi_simple_poll_quit (simple_poll);
    +}

+/*

  • * 'avahi_resolve_uri_resolver_cb()' - Avahi resolver callback for resolving
  • * URI.
  • */
    +
    +static void
    +avahi_resolve_uri_resolver_cb (AvahiServiceResolver *resolver,
  •              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 *context)
    
    +{
  • const char scheme; / URI scheme */
  • char rp[256]; /* Remote printer */
  • AvahiStringList *pair;
  • char *value;
  • size_t valueLen = 0;
  • char addr[AVAHI_ADDRESS_STR_MAX];
  • struct
  • {
  • AvahiSimplePoll *poll;
  • _http_uribuf_t uribuf;
  • } *poll_uribuf = context;
  • DEBUG_printf(("avahi_resolve_uri_resolver_callback(resolver=%p, "
  •   "interface=%d, protocol=%d, event=%d, name=\"%s\", "
    
  •   "type=\"%s\", domain=\"%s\", host_name=\"%s\", address=%p, "
    
  •   "port=%d, txt=%p, flags=%d, context=%p)\n",
    
  •   resolver, interface, protocol, event, name, type, domain,
    
  •   host_name, address, port, txt, flags, context));
    
  • if (event != AVAHI_RESOLVER_FOUND)
  • {
  • avahi_service_resolver_free (resolver);
  • avahi_simple_poll_quit (poll_uribuf->poll);
  • return;
  • }
  • /*
  • * Figure out the scheme from the full name...
  • */
  • if (strstr(type, "_ipp."))
  • scheme = "ipp";
  • else if (strstr(type, "_printer."))
  • scheme = "lpd";
  • else if (strstr(type, "_pdl-datastream."))
  • scheme = "socket";
  • else
  • scheme = "riousbprint";
  • /*
  • * Extract the "remote printer key from the TXT record...
  • */
  • if ((pair = avahi_string_list_find (txt, "rp")) != NULL)
  • {
  • avahi_string_list_get_pair (pair, NULL, &value, &valueLen);
  • rp[0] = '/';
  • memcpy (rp + 1, value, valueLen);
  • rp[valueLen + 1] = '\0';
  • }
  • else
  • rp[0] = '\0';
  • /*
  • * Assemble the final device URI...
  • */
  • avahi_address_snprint (addr, AVAHI_ADDRESS_STR_MAX, address);
  • httpAssembleURI(HTTP_URI_CODING_ALL, poll_uribuf->uribuf.buffer,
  •     poll_uribuf->uribuf.bufsize, scheme, NULL,
    
  •     addr, port, rp);
    
  • DEBUG_printf(("avahi_resolve_uri_resolver_callback: Resolved URI is "%s"\n",
  •   poll_uribuf->uribuf.buffer));
    
  • avahi_simple_poll_quit (poll_uribuf->poll);
    +}
    +#endif /* HAVE_AVAHI _/

/_

  • End of "$Id$".
    */
@michaelrsweet
Collaborator

"cups-3-timeouts.patch":

diff --git a/scheduler/Makefile b/scheduler/Makefile
index 3c7da8e..7b4d05b 100644
--- a/scheduler/Makefile
+++ b/scheduler/Makefile
@@ -39,7 +39,8 @@ CUPSDOBJS =
server.o
statbuf.o
subscriptions.o \

  •   sysman.o
    
  •   sysman.o \
    
  •   timeout.o
    

    LIBOBJS =
    filter.o
    mime.o
    diff --git a/scheduler/cupsd.h b/scheduler/cupsd.h
    index 5d7229d..3ddb173 100644
    --- a/scheduler/cupsd.h
    +++ b/scheduler/cupsd.h
    @@ -140,6 +140,15 @@ extern const char *cups_hstrerror(int);

    typedef void (*cupsd_selfunc_t)(void *data);

+#ifdef HAVE_AVAHI
+/*

  • * Timeout callback function type...

  • _/
    +
    +typedef struct _cupsd_timeout_s cupsd_timeout_t;
    +typedef void (_cupsd_timeoutfunc_t)(cupsd_timeout_t timeout, void *data);
    +#endif /
    HAVE_AVAHI */
    +

    /*

    • Globals...
      @@ -173,6 +182,11 @@ VAR int Launchd VALUE(0);
      /* Running from launchd /
      #endif /
      HAVE_LAUNCH_H */

+#ifdef HAVE_AVAHI
+VAR cups_array_t Timeouts; / Timed callbacks for main loop /
+#endif /
HAVE_AVAHI */
+
+

/*

  • Prototypes...
    @@ -242,6 +256,20 @@ extern void cupsdStopSelect(void);
    extern void cupsdStartServer(void);
    extern void cupsdStopServer(void);

+#ifdef HAVE_AVAHI
+extern void cupsdInitTimeouts(void);
+extern cupsd_timeout_t *cupsdAddTimeout (const struct timeval *tv,

  •                cupsd_timeoutfunc_t cb,
    
  •                void *data);
    

    +extern cupsd_timeout_t *cupsdNextTimeout (long *delay);
    +extern void cupsdRunTimeout (cupsd_timeout_t *timeout);
    +extern void cupsdUpdateTimeout (cupsd_timeout_t *timeout,

  •               const struct timeval *tv);
    

    +extern void cupsdRemoveTimeout (cupsd_timeout_t timeout);
    +#endif /
    HAVE_AVAHI */
    +
    +extern int cupsdRemoveFile(const char *filename);
    +

    /*

    • End of "$Id$".
      diff --git a/scheduler/main.c b/scheduler/main.c
      index baaa3a1..1e60572 100644
      --- a/scheduler/main.c
      +++ b/scheduler/main.c
      @@ -146,6 +146,10 @@ main(int argc, /* I - Number of command-line args /
      int launchd_idle_exit;
      /
      Idle exit on select timeout? /
      #endif /
      HAVE_LAUNCHD */
      +#ifdef HAVE_AVAHI
  • cupsd_timeout_t tmo; / Next scheduled timed callback */

  • long tmo_delay; /* Time before it must be called /
    +#endif /
    HAVE_AVAHI */

#ifdef HAVE_GETEUID
@@ -525,6 +529,14 @@ main(int argc, /* I - Number of command-line args */

httpInitialize();

+#ifdef HAVE_AVAHI

  • /*
  • * Initialize timed callback structures.
  • */
  • cupsdInitTimeouts();
    +#endif /* HAVE_AVAHI */

cupsdStartServer();

/*
@@ -864,6 +876,16 @@ main(int argc, /* I - Number of command-line args /
}
#endif /
APPLE */

+#ifdef HAVE_AVAHI

  • /*
  • * If a timed callback is due, run it.
  • */
  • tmo = cupsdNextTimeout (&tmo_delay);
  • if (tmo && tmo_delay == 0)
  •  cupsdRunTimeout (tmo);
    
    +#endif /* HAVE_AVAHI /
    +
    #ifndef APPLE
    /
    • Update the network interfaces once a minute...
      @@ -1777,6 +1799,10 @@ select_timeout(int fds) /* I - Number of descriptors returned /
      cupsd_job_t *job; /
      Job information /
      cupsd_subscription_t *sub; /
      Subscription information /
      const char *why; /
      Debugging aid */
      +#ifdef HAVE_AVAHI
  • cupsd_timeout_t tmo; / Timed callback */
  • long tmo_delay; /* Seconds before calling it /
    +#endif /
    HAVE_AVAHI */

/*
@@ -1819,6 +1845,19 @@ select_timeout(int fds) /* I - Number of descriptors returned /
}
#endif /
APPLE */

+#ifdef HAVE_AVAHI

  • /*
  • * See if there are any scheduled timed callbacks to run.
  • */
  • tmo = cupsdNextTimeout (&tmo_delay);
  • if (tmo)
  • {
  • timeout = tmo_delay;
  • why = "run a timed callback";
  • }
    +#endif /* HAVE_AVAHI _/

/_

  • Check whether we are accepting new connections...
    /
    diff --git a/scheduler/timeout.c b/scheduler/timeout.c
    new file mode 100644
    index 0000000..7f10d08
    --- /dev/null
    +++ b/scheduler/timeout.c
    @@ -0,0 +1,215 @@
    +/
  • * "$Id$"
  • * Timeout functions for the Common UNIX Printing System (CUPS).
  • * Copyright (C) 2010, 2011 Red Hat, Inc.
  • * Authors:
  • * Tim Waugh twaugh@redhat.com
  • * Redistribution and use in source and binary forms, with or without
  • * modification, are permitted provided that the following conditions
  • * are met:
  • * Redistributions of source code must retain the above copyright
  • * notice, this list of conditions and the following disclaimer.
  • * Redistributions in binary form must reproduce the above copyright
  • * notice, this list of conditions and the following disclaimer in the
  • * documentation and/or other materials provided with the distribution.
  • * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  • * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  • * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  • * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  • * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  • * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  • * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  • * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  • * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  • * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  • * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  • * OF THE POSSIBILITY OF SUCH DAMAGE.
  • * Contents:
  • * cupsdInitTimeouts() - Initialise timeout structure.
  • * cupsdAddTimeout() - Add a timed callback.
  • * cupsdNextTimeout() - Find the next enabled timed callback.
  • * cupsdUpdateTimeout() - Adjust the time of a timed callback or disable it.
  • * cupsdRemoveTimeout() - Discard a timed callback.
  • * compare_timeouts() - Compare timed callbacks for array sorting.
  • /
    +
    +#include <config.h>
    +
    +#ifdef HAVE_AVAHI /
    Applies to entire file... /
    +
    +/
  • * Include necessary headers...
  • /
    +
    +#include "cupsd.h"
    +
    +#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
    +# include <malloc.h>
    +#endif /
    HAVE_MALLOC_H && HAVE_MALLINFO /
    +
    +#ifdef HAVE_AVAHI
    +# include <avahi-common/timeval.h>
    +#endif /
    HAVE_AVAHI */
    +
    +
    +struct _cupsd_timeout_s
    +{
  • struct timeval when;
  • int enabled;
  • cupsd_timeoutfunc_t callback;
  • void _data;
    +};

+/_

  • * Local functions...
  • /
    +
    +/
  • * 'compare_timeouts()' - Compare timed callbacks for array sorting.
  • */
    +
    +static int
    +compare_timeouts (cupsd_timeout_t *p0, cupsd_timeout_t *p1)
    +{
  • if (!p0->enabled || !p1->enabled)
  • {
  • if (!p0->enabled && !p1->enabled)
  •  return (0);
    
  • return (p0->enabled ? -1 : 1);
  • }
  • return (avahi_timeval_compare (&p0->when, &p1->when));
    +}

+/*

  • * 'cupsdInitTimeouts()' - Initialise timeout structures.
  • */
    +
    +void
    +cupsdInitTimeouts(void)
    +{
  • Timeouts = cupsArrayNew ((cups_array_func_t)compare_timeouts, NULL);
    +}

+/*

  • * 'cupsdAddTimeout()' - Add a timed callback.
  • /
    +
    +cupsd_timeout_t * /
    O - Timeout handle /
    +cupsdAddTimeout(const struct timeval *tv, /
    I - Absolute time */
  •   cupsd_timeoutfunc_t cb,     /\* I - Callback function */
    
  •   void _data)         /_ I - User data */
    
    +{
  • cupsd_timeout_t *timeout;
  • timeout = malloc (sizeof(cupsd_timeout_t));
  • if (timeout != NULL)
  • {
  • timeout->enabled = (tv != NULL);
  • if (tv)
  • {
  •  timeout->when.tv_sec = tv->tv_sec;
    
  •  timeout->when.tv_usec = tv->tv_usec;
    
  • }
  • timeout->callback = cb;
  • timeout->data = data;
  • cupsArrayAdd (Timeouts, timeout);
  • }
  • return timeout;
    +}

+/*

  • * 'cupsdNextTimeout()' - Find the next enabled timed callback.
  • /
    +
    +cupsd_timeout_t * /
    O - Next enabled timeout or NULL /
    +cupsdNextTimeout(long *delay) /
    O - Seconds before scheduled */
    +{
  • cupsd_timeout_t *first = cupsArrayFirst (Timeouts);
  • struct timeval curtime;
  • if (first && !first->enabled)
  • first = NULL;
  • if (first && delay)
  • {
  • gettimeofday (&curtime, NULL);
  • if (avahi_timeval_compare (&curtime, &first->when) > 0)
  • {
  •  *delay = 0;
    
  • } else {
  •  *delay = 1 + first->when.tv_sec - curtime.tv_sec;
    
  •  if (first->when.tv_usec < curtime.tv_usec)
    
  • (*delay)--;
  • }
  • }
  • return (first);
    +}

+/*

  • * 'cupsdRunTimeout()' - Run a timed callback.
  • /
    +
    +void
    +cupsdRunTimeout(cupsd_timeout_t *timeout) /
    I - Timeout */
    +{
  • if (!timeout)
  • return;
  • timeout->enabled = 0;
  • if (!timeout->callback)
  • return;
  • timeout->callback (timeout, timeout->data);
    +}

+/*

  • * 'cupsdUpdateTimeout()' - Adjust the time of a timed callback or disable it.
  • /
    +
    +void
    +cupsdUpdateTimeout(cupsd_timeout_t *timeout, /
    I - Timeout */
  •      const struct timeval _tv)    /_ I - Absolute time or NULL */
    
    +{
  • cupsArrayRemove (Timeouts, timeout);
  • timeout->enabled = (tv != NULL);
  • if (tv)
  • {
  • timeout->when.tv_sec = tv->tv_sec;
  • timeout->when.tv_usec = tv->tv_usec;
  • }
  • cupsArrayAdd (Timeouts, timeout);
    +}

+/*

  • * 'cupsdRemoveTimeout()' - Discard a timed callback.
  • /
    +
    +void
    +cupsdRemoveTimeout(cupsd_timeout_t *timeout) /
    I - Timeout */
    +{
  • cupsArrayRemove (Timeouts, timeout);
  • free (timeout);
    +}

+#endif /* HAVE_AVAHI ... from top of file /
+
+/

  • * End of "$Id$".
  • */
@michaelrsweet
Collaborator

"cups-4-avahi-poll.patch":

diff --git a/scheduler/Makefile b/scheduler/Makefile
index 7b4d05b..63b5123 100644
--- a/scheduler/Makefile
+++ b/scheduler/Makefile
@@ -17,6 +17,7 @@ include ../Makedefs

CUPSDOBJS =
auth.o \

  •   avahi.o \
    banners.o \
    cert.o \
    classes.o \
    
    diff --git a/scheduler/avahi.c b/scheduler/avahi.c
    new file mode 100644
    index 0000000..920f109
    --- /dev/null
    +++ b/scheduler/avahi.c
    @@ -0,0 +1,465 @@
    +/*
  • * "$Id$"
  • * Avahi poll implementation for the CUPS scheduler.
  • * Copyright (C) 2010, 2011 Red Hat, Inc.
  • * Authors:
  • * Tim Waugh twaugh@redhat.com
  • * Redistribution and use in source and binary forms, with or without
  • * modification, are permitted provided that the following conditions
  • * are met:
  • * Redistributions of source code must retain the above copyright
  • * notice, this list of conditions and the following disclaimer.
  • * Redistributions in binary form must reproduce the above copyright
  • * notice, this list of conditions and the following disclaimer in the
  • * documentation and/or other materials provided with the distribution.
  • * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  • * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  • * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  • * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  • * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  • * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  • * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  • * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  • * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  • * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  • * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  • * OF THE POSSIBILITY OF SUCH DAMAGE.
  • * Contents:
  • * watch_read_cb - Read callback for file descriptor
  • * watch_write_cb - Write callback for file descriptor
  • * watched_fd_add_select() - Call cupsdAddSelect() as needed
  • * watch_new() - Create a new file descriptor watch
  • * watch_free() - Free a file descriptor watch
  • * watch_update() - Update watched events for a file descriptor
  • * watch_get_events() - Get events that happened for a file descriptor
  • * timeout_cb() - Run a timed Avahi callback
  • * timeout_new() - Set a wakeup time
  • * timeout_update() - Update the expiration time for a timeout
  • * timeout_free() - Free a timeout
  • * compare_watched_fds() - Compare watched file descriptors for array sorting
  • * compare_timeouts() - Compare timeouts for array sorting
  • * avahi_cups_poll_new() - Create a new Avahi main loop object for CUPS
  • * avahi_cups_poll_free() - Free an Avahi main loop object for CUPS
  • * avahi_cups_poll_get() - Get the abstract poll API structure
  • /
    +
    +#include <config.h>
    +
    +#ifdef HAVE_AVAHI /
    Applies to entire file... /
    +
    +/
  • * Include necessary headers...
  • /
    +
    +#include "cupsd.h"
    +
    +#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
    +# include <malloc.h>
    +#endif /
    HAVE_MALLOC_H && HAVE_MALLINFO /
    +
    +#ifdef HAVE_AVAHI
    +# include <avahi-common/timeval.h>
    +#endif /
    HAVE_AVAHI */
    +
    +
    +typedef struct
    +{
  • AvahiCupsPoll *cups_poll;
  • int fd;
  • AvahiWatchEvent occurred;
  • cups_array_t *watches;
    +} cupsd_watched_fd_t;

+struct AvahiWatch
+{

  • cupsd_watched_fd_t *watched_fd;
  • AvahiWatchEvent events;
  • AvahiWatchCallback callback;
  • void *userdata;
    +};

+struct AvahiTimeout
+{

  • AvahiCupsPoll *cups_poll;
  • AvahiTimeoutCallback callback;
  • void *userdata;
  • cupsd_timeout_t _cupsd_timeout;
    +};

+/_

  • * Local functions...
  • */
    +
    +static AvahiWatch * watch_new(const AvahiPoll *api,
  •             int fd,
    
  •             AvahiWatchEvent events,
    
  •             AvahiWatchCallback callback,
    
  •             void *userdata);
    
    +static void watch_free(AvahiWatch *watch);
    +static void watch_update(AvahiWatch *watch,
  •                AvahiWatchEvent events);
    
    +static AvahiWatchEvent watch_get_events(AvahiWatch *watch);
    +static int compare_watches(AvahiWatch *p0,
  •               AvahiWatch _p1);
    
    +/_
  • * 'watch_read_cb' - Read callback for file descriptor
  • */
    +
    +static void
    +watch_read_cb (void *userdata)
    +{
  • AvahiWatch *watch;
  • cupsd_watched_fd_t *watched_fd = userdata;
  • watched_fd->occurred |= AVAHI_WATCH_IN;
  • for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
  •   watch;
    
  •   watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
    
  • if (watch->events & watched_fd->occurred) {
  •  (watch->callback) (watch, watched_fd->fd,
    
  •        AVAHI_WATCH_IN, watch->userdata);
    
  •  watched_fd->occurred &= ~AVAHI_WATCH_IN;
    
  •  break;
    
  • }
  • }
    +}

+/*

  • * 'watch_write_cb' - Write callback for file descriptor
  • */
    +
    +static void
    +watch_write_cb (void *userdata)
    +{
  • AvahiWatch *watch;
  • cupsd_watched_fd_t *watched_fd = userdata;
  • watched_fd->occurred |= AVAHI_WATCH_OUT;
  • for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
  •   watch;
    
  •   watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
    
  • if (watch->events & watched_fd->occurred) {
  •  (watch->callback) (watch, watched_fd->fd,
    
  •        AVAHI_WATCH_OUT, watch->userdata);
    
  •  watched_fd->occurred &= ~AVAHI_WATCH_OUT;
    
  •  break;
    
  • }
  • }
    +}

+/*

  • * 'watched_fd_add_select' - Call cupsdAddSelect() as needed
  • /
    +
    +static int /
    O - Watches? */
    +watched_fd_add_select (cupsd_watched_fd_t *watched_fd)
    +{
  • AvahiWatch *watch;
  • cupsd_selfunc_t read_cb = NULL, write_cb = NULL;
  • for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
  •   watch;
    
  •   watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
    
  • if (watch->events & (AVAHI_WATCH_IN |
  •            AVAHI_WATCH_ERR |
    
  •            AVAHI_WATCH_HUP)) {
    
  •  read_cb = (cupsd_selfunc_t)watch_read_cb;
    
  •  if (write_cb != NULL)
    
  • break;
  • }
  • if (watch->events & AVAHI_WATCH_OUT) {
  •  write_cb = (cupsd_selfunc_t)watch_write_cb;
    
  •  if (read_cb != NULL)
    
  • break;
  • }
  • }
  • if (read_cb || write_cb)
  • cupsdAddSelect (watched_fd->fd, read_cb, write_cb, watched_fd);
  • else
  • cupsdRemoveSelect (watched_fd->fd);
  • return (read_cb || write_cb);
    +}

+/*

  • * 'watch_new' - Create a new file descriptor watch
  • */
    +
    +static AvahiWatch *
    +watch_new (const AvahiPoll *api,
  •  int fd,
    
  •  AvahiWatchEvent events,
    
  •  AvahiWatchCallback callback,
    
  •  void *userdata)
    
    +{
  • cupsd_watched_fd_t key, *watched_fd;
  • AvahiCupsPoll *cups_poll = api->userdata;
  • AvahiWatch *watch = malloc(sizeof(AvahiWatch));
  • if (watch == NULL)
  • return (NULL);
  • watch->events = events;
  • watch->callback = callback;
  • watch->userdata = userdata;
  • key.fd = fd;
  • watched_fd = cupsArrayFind (cups_poll->watched_fds, &key);
  • if (watched_fd == NULL) {
  • watched_fd = malloc(sizeof(cupsd_watched_fd_t));
  • if (watched_fd == NULL) {
  •  free (watch);
    
  •  return (NULL);
    
  • }
  • watched_fd->fd = fd;
  • watched_fd->occurred = 0;
  • watched_fd->cups_poll = cups_poll;
  • watched_fd->watches = cupsArrayNew ((cups_array_func_t)compare_watches,
  •               NULL);
    
  • }
  • watch->watched_fd = watched_fd;
  • cupsArrayAdd(watched_fd->watches, watch);
  • watched_fd_add_select (watched_fd);
  • return (watch);
    +}

+/*

  • * 'watch_free' - Free a file descriptor watch
  • */
    +
    +static void
    +watch_free (AvahiWatch *watch)
    +{
  • cupsd_watched_fd_t *watched_fd = watch->watched_fd;
  • AvahiCupsPoll *cups_poll = watched_fd->cups_poll;
  • cupsArrayRemove (watched_fd->watches, watch);
  • free (watch);
  • if (!watched_fd_add_select (watched_fd)) {
  • /* No more watches */
  • cupsArrayRemove (cups_poll->watched_fds, watched_fd);
  • free (watched_fd);
  • }
    +}

+/*

  • * 'watch_update' - Update watched events for a file descriptor
  • */
    +
    +static void
    +watch_update (AvahiWatch *watch,
  •     AvahiWatchEvent events)
    
    +{
  • watch->events = events;
  • watched_fd_add_select (watch->watched_fd);
    +}

+/*

  • * 'watch_get_events' - Get events that happened for a file descriptor
  • */
    +
    +static AvahiWatchEvent
    +watch_get_events (AvahiWatch *watch)
    +{
  • return (watch->watched_fd->occurred);
    +}

+/*

  • * 'compare_watches' - Compare watches for array sorting
  • */
    +
    +static int
    +compare_watches (AvahiWatch *p0,
  •    AvahiWatch *p1)
    
    +{
  • if (p0->watched_fd->fd < p1->watched_fd->fd)
  • return (-1);
  • return ((p0->watched_fd->fd == p1->watched_fd->fd) ? 0 : 1);
    +}

+/*

  • * 'timeout_cb()' - Run a timed Avahi callback
  • */
    +
    +static void
    +timeout_cb (cupsd_timeout_t *cupsd_timeout, void *userdata)
    +{
  • AvahiTimeout *timeout = userdata;
  • (timeout->callback) (timeout, timeout->userdata);
    +}

+/*

  • * 'timeout_new' - Set a wakeup time
  • */
    +
    +static AvahiTimeout *
    +timeout_new (const AvahiPoll *api,
  •    const struct timeval *tv,
    
  •    AvahiTimeoutCallback callback,
    
  •    void *userdata)
    
    +{
  • AvahiTimeout *timeout;
  • AvahiCupsPoll *cups_poll = api->userdata;
  • timeout = malloc(sizeof(AvahiTimeout));
  • if (timeout == NULL)
  • return (NULL);
  • timeout->cups_poll = cups_poll;
  • timeout->callback = callback;
  • timeout->userdata = userdata;
  • timeout->cupsd_timeout = cupsdAddTimeout (tv,
  •                   (cupsd_timeoutfunc_t)timeout_cb,
    
  •                   timeout);
    
  • cupsArrayAdd (cups_poll->timeouts, timeout);
  • return (timeout);
    +}

+/*

  • * 'timeout_update' - Update the expiration time for a timeout
  • */
    +
    +static void
    +timeout_update (AvahiTimeout *timeout,
  •   const struct timeval *tv)
    
    +{
  • cupsdUpdateTimeout (timeout->cupsd_timeout, tv);
    +}

+/*

  • * ' timeout_free' - Free a timeout
  • */
    +
    +static void
    +timeout_free (AvahiTimeout *timeout)
    +{
  • cupsArrayRemove (timeout->cups_poll->timeouts, timeout);
  • cupsdRemoveTimeout (timeout->cupsd_timeout);
  • free (timeout);
    +}

+/*

  • * 'compare_watched_fds' - Compare watched file descriptors for array sorting
  • */
    +static int
    +compare_watched_fds(cupsd_watched_fd_t *p0,
  •       cupsd_watched_fd_t *p1)
    
    +{
  • if (p0->fd != p1->fd)
  • return (p0->fd < p1->fd ? -1 : 1);
  • if (p0 == p1)
  • return (0);
  • return (p0 < p1 ? -1 : 1);
    +}

+/*

  • * 'compare_timeouts' - Compare timeouts for array sorting
  • */
    +static int
    +compare_timeouts(AvahiTimeout *p0,
  •    AvahiTimeout *p1)
    
    +{
  • /*
  • * Just compare pointers to make it a stable sort.
  • */
  • if (p0->cupsd_timeout < p1->cupsd_timeout)
  • return (-1);
  • return ((p0->cupsd_timeout == p1->cupsd_timeout) ? 0 : 1);
    +}

+/*

  • * 'avahi_cups_poll_new' - Create a new Avahi main loop object for CUPS
  • */
    +
    +AvahiCupsPoll *
    +avahi_cups_poll_new (void)
    +{
  • AvahiCupsPoll *cups_poll = malloc(sizeof(AvahiCupsPoll));
  • if (cups_poll == NULL)
  • return (NULL);
  • cups_poll->watched_fds = cupsArrayNew ((cups_array_func_t)compare_watched_fds,
  •                NULL);
    
  • cups_poll->timeouts = cupsArrayNew ((cups_array_func_t)compare_timeouts,
  •                 NULL);
    
  • cups_poll->api.userdata = cups_poll;
  • cups_poll->api.watch_new = watch_new;
  • cups_poll->api.watch_free = watch_free;
  • cups_poll->api.watch_update = watch_update;
  • cups_poll->api.watch_get_events = watch_get_events;
  • cups_poll->api.timeout_new = timeout_new;
  • cups_poll->api.timeout_update = timeout_update;
  • cups_poll->api.timeout_free = timeout_free;
  • return (cups_poll);
    +}

+/*

  • * 'avahi_cups_poll_free' - Free an Avahi main loop object for CUPS
  • */
    +void
    +avahi_cups_poll_free (AvahiCupsPoll *cups_poll)
    +{
  • cupsd_watched_fd_t *watched_fd;
  • for (watched_fd = (cupsd_watched_fd_t*)cupsArrayFirst(cups_poll->watched_fds);
  •   watched_fd;
    
  •   watched_fd = (cupsd_watched_fd_t*)cupsArrayNext(cups_poll->watched_fds)){
    
  • cupsArrayClear (watched_fd->watches);
  • }
  • cupsArrayClear (cups_poll->watched_fds);
  • cupsArrayClear (cups_poll->timeouts);
    +}

+/*

  • * 'avahi_cups_poll_get' - Get the abstract poll API structure
  • */
    +
    +const AvahiPoll *
    +avahi_cups_poll_get (AvahiCupsPoll *cups_poll)
    +{
  • return (&cups_poll->api);
    +}

+#endif /* HAVE_AVAHI ... from top of file /
+
+/

  • * End of "$Id$".
  • /
    diff --git a/scheduler/avahi.h b/scheduler/avahi.h
    new file mode 100644
    index 0000000..d92049d
    --- /dev/null
    +++ b/scheduler/avahi.h
    @@ -0,0 +1,69 @@
    +/
  • * "$Id$"
  • * Avahi poll implementation for the CUPS scheduler.
  • * Copyright (C) 2010, 2011 Red Hat, Inc.
  • * Authors:
  • * Tim Waugh twaugh@redhat.com
  • * Redistribution and use in source and binary forms, with or without
  • * modification, are permitted provided that the following conditions
  • * are met:
  • * Redistributions of source code must retain the above copyright
  • * notice, this list of conditions and the following disclaimer.
  • * Redistributions in binary form must reproduce the above copyright
  • * notice, this list of conditions and the following disclaimer in the
  • * documentation and/or other materials provided with the distribution.
  • * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  • * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  • * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  • * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  • * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  • * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  • * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  • * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  • * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  • * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  • * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  • * OF THE POSSIBILITY OF SUCH DAMAGE.
  • /
    +
    +#include <config.h>
    +
    +#ifdef HAVE_AVAHI
    +# include <avahi-client/client.h>
    +# include <avahi-client/publish.h>
    +#endif /
    HAVE_AVAHI /
    +
    +#ifdef HAVE_AUTHORIZATION_H
    +# include <Security/Authorization.h>
    +#endif /
    HAVE_AUTHORIZATION_H */
    +
    +
    +#ifdef HAVE_AVAHI
    +typedef struct
    +{
  • AvahiPoll api;
  • cups_array_t *watched_fds;
  • cups_array_t timeouts;
    +} AvahiCupsPoll;
    +#endif /
    HAVE_AVAHI _/

+/_

  • * Prototypes...
  • /
    +
    +#ifdef HAVE_AVAHI
    +extern AvahiCupsPoll * avahi_cups_poll_new(void);
    +extern void avahi_cups_poll_free(AvahiCupsPoll *cups_poll);
    +extern const AvahiPoll *avahi_cups_poll_get(AvahiCupsPoll *cups_poll);
    +#endif /
    HAVE_AVAHI /
    +
    +
    +/
  • * End of "$Id$".
  • */
@michaelrsweet
Collaborator

"cups-5-avahi-services.patch":

diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c
index 99b8e7b..2688eff 100644
--- a/cgi-bin/admin.c
+++ b/cgi-bin/admin.c
@@ -1643,7 +1643,7 @@ do_config_server(http_t http) / I - HTTP connection */
else
local_protocols[0] = '\0';

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
if (cgiGetVariable("BROWSE_LOCAL_DNSSD"))
{
if (local_protocols[0])
@@ -1651,7 +1651,7 @@ do_config_server(http_t http) / I - HTTP connection /
else
strcat(local_protocols, "dnssd");
}
-#endif /
HAVE_DNSSD /
+#endif /
defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

#ifdef HAVE_LDAP
if (cgiGetVariable("BROWSE_LOCAL_LDAP"))
@@ -2718,9 +2718,9 @@ do_menu(http_t http) / I - HTTP connection /
#endif /
HAVE_GSSAPI */
cgiSetVariable("KERBEROS", "");

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
cgiSetVariable("HAVE_DNSSD", "1");
-#endif /* HAVE_DNSSD /
+#endif /
defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

#ifdef HAVE_LDAP
cgiSetVariable("HAVE_LDAP", "1");
diff --git a/scheduler/client.c b/scheduler/client.c
index d5a5111..12ed881 100644
--- a/scheduler/client.c
+++ b/scheduler/client.c
@@ -4985,7 +4985,7 @@ valid_host(cupsd_client_t con) / I - Client connection */
!strncmp(host, "[::1]:", 6));
}

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
/*

  • Check if the hostname is something.local (Bonjour); if so, allow it.
    /
    @@ -4994,7 +4994,7 @@ valid_host(cupsd_client_t *con) /
    I - Client connection _/
    (!_cups_strcasecmp(end, ".local") || !_cups_strncasecmp(end, ".local:", 7) ||
    !_cups_strcasecmp(end, ".local.") || !cups_strncasecmp(end, ".local.:", 8)))
    return (1);
    -#endif /
    HAVE_DNSSD /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

    /*

  • Check if the hostname is an IP address...
    diff --git a/scheduler/conf.c b/scheduler/conf.c
    index d75fce5..bec6258 100644
    --- a/scheduler/conf.c
    +++ b/scheduler/conf.c
    @@ -649,7 +649,7 @@ cupsdReadConfiguration(void)
    Browsing = CUPS_DEFAULT_BROWSING;
    DefaultShared = CUPS_DEFAULT_DEFAULT_SHARED;

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
cupsdSetString(&DNSSDRegType, "_ipp._tcp,_cups");
#endif /* HAVE_DNSSD */

diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c
index eb3c862..48dcef9 100644
--- a/scheduler/dirsvc.c
+++ b/scheduler/dirsvc.c
@@ -27,6 +27,7 @@

  • ldap_connect() - Start new LDAP connection

  • ldap_reconnect() - Reconnect to LDAP Server

  • ldap_disconnect() - Disconnect from LDAP Server

  • * cupsdStartAvahiClient() - Start an Avahi client if needed

  • cupsdStartBrowsing() - Start sending and receiving broadcast

  •                            information.
    
  • cupsdStartPolling() - Start polling servers as needed.
    @@ -45,6 +46,8 @@

  •                            printer.
    
  • dnssdPackTxtRecord() - Pack an array of key/value pairs into the TXT

  •                            record format.
    
    • * avahiPackTxtRecord() - Pack an array of key/value pairs into an
    • * AvahiStringList.
  • dnssdRegisterCallback() - DNSServiceRegister callback.

  • dnssdRegisterPrinter() - Start sending broadcast information for a

  •                            printer or update the broadcast contents.
    

    @@ -83,6 +86,7 @@
    */

    #include "cupsd.h"
    +#include <assert.h>
    #include <grp.h>

    #ifdef HAVE_DNSSD
    @@ -97,6 +101,17 @@

    endif /* HAVE_SYSTEMCONFIGURATION */

    endif /* APPLE */

    #endif /* HAVE_DNSSD /
    +#ifdef HAVE_AVAHI
    +# include <avahi-common/domain.h>
    +#endif /
    HAVE_AVAHI /
    +
    +
    +#ifdef HAVE_DNSSD
    +typedef char *cupsd_txt_record_t;
    +#endif /
    HAVE_DNSSD /
    +#ifdef HAVE_AVAHI
    +typedef AvahiStringList *cupsd_txt_record_t;
    +#endif /
    HAVE_AVAHI */

    /*
    @@ -159,27 +174,39 @@ static void update_polling(void);
    static void update_smb(int onoff);

+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+static cupsd_txt_record_t dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p,

  •                     int for_lpd);
    
    +static int dnssdComparePrinters(cupsd_printer_t a, cupsd_printer_t *b);
    +static void dnssdDeregisterPrinter(cupsd_printer_t *p);
    +static void dnssdRegisterPrinter(cupsd_printer_t *p);
    +static void dnssdStop(void);
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) _/
    +
    #ifdef HAVE_DNSSD

    ifdef HAVE_COREFOUNDATION

    static void dnssdAddAlias(const void *key, const void *value,
    void *context);

    endif /_ HAVE_COREFOUNDATION */

    -static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p,
  •                        int for_lpd);
    
    -static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b);
    -static void dnssdDeregisterPrinter(cupsd_printer_t *p);
    -static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2],
  •                       int count);
    
    static void dnssdRegisterCallback(DNSServiceRef sdRef,
    DNSServiceFlags flags,
    DNSServiceErrorType errorCode,
    const char name, const char *regtype,
    const char *domain, void *context);
    -static void dnssdRegisterPrinter(cupsd_printer_t *p);
    -static void dnssdStop(void);
    static void dnssdUpdate(void);
    #endif /
    HAVE_DNSSD */

+#ifdef HAVE_AVAHI
+static AvahiStringList *avahiPackTxtRecord(char *keyvalue[][2],

  •                  int count);
    
    +static void avahi_entry_group_cb (AvahiEntryGroup *group,
  •                 AvahiEntryGroupState state,
    
  •                 void *userdata);
    
    +static void avahi_client_cb (AvahiClient *client,
  •            AvahiClientState state,
    
  •            void _userdata);
    
    +#endif /_ HAVE_AVAHI /
    +
    #ifdef HAVE_LDAP
    static const char * const ldap_attrs[] =/
    CUPS LDAP attributes /
    {
    @@ -283,10 +310,10 @@ cupsdDeregisterPrinter(
    ldap_dereg_printer(p);
    #endif /
    HAVE_LDAP */

-#ifdef HAVE_DNSSD

  • if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
    +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
  • if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD))
    dnssdDeregisterPrinter(p);
    -#endif /* HAVE_DNSSD /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
    }

@@ -702,10 +729,10 @@ cupsdRegisterPrinter(cupsd_printer_t p)/ I - Printer /
slpRegisterPrinter(p); */
#endif /
HAVE_LIBSLP */

-#ifdef HAVE_DNSSD

  • if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
    +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
  • if ((BrowseLocalProtocols & BROWSE_DNSSD))
    dnssdRegisterPrinter(p);
    -#endif /* HAVE_DNSSD /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
    }

@@ -1419,6 +1446,27 @@ ldap_disconnect(LDAP ld) / I - LDAP handle /
#endif /
HAVE_LDAP */

+#ifdef HAVE_AVAHI
+/*

  • * 'cupsdStartAvahiClient()' - Start an Avahi client if needed
  • */
    +
    +void
    +cupsdStartAvahiClient(void)
    +{
  • if (!AvahiCupsClient && !AvahiCupsClientConnecting)
  • {
  • if (!AvahiCupsPollHandle)
  •  AvahiCupsPollHandle = avahi_cups_poll_new ();
    
  • if (AvahiCupsPollHandle)
  •  avahi_client_new (avahi_cups_poll_get (AvahiCupsPollHandle),
    
  •       AVAHI_CLIENT_NO_FAIL, avahi_client_cb, NULL, NULL);
    
  • }
    +}
    +#endif /* HAVE_AVAHI */
  • /*
    • 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
      */
      @@ -1542,13 +1590,16 @@ cupsdStartBrowsing(void)
      else
      BrowseSocket = -1;

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
{
+#ifdef HAVE_DNSSD
DNSServiceErrorType error; /* Error from service creation /
+#endif /
HAVE_DNSSD /
cupsd_listener_t *lis; /
Current listening socket */

+#ifdef HAVE_DNSSD
/*
* First create a "master" connection for all registrations...
*/
@@ -1573,6 +1624,7 @@ cupsdStartBrowsing(void)
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);

   cupsdAddSelect(fd, (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);

+#endif /* HAVE_DNSSD */

  /*
   * Then get the port we use for registrations.  If we are not listening

@@ -1606,9 +1658,16 @@ cupsdStartBrowsing(void)
*/

   cupsdUpdateDNSSDName();

+#ifdef HAVE_AVAHI

  •  cupsdStartAvahiClient ();
    
    +#endif /* HAVE_AVAHI */
    +
    +#ifdef HAVE_DNSSD
    }
  • }
    #endif /* HAVE_DNSSD */
  • }
    +#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

#ifdef HAVE_LIBSLP
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
@@ -1834,10 +1893,10 @@ cupsdStopBrowsing(void)
BrowseSocket = -1;
}

-#ifdef HAVE_DNSSD

  • if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
    +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
  • if ((BrowseLocalProtocols & BROWSE_DNSSD))
    dnssdStop();
    -#endif /* HAVE_DNSSD /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

#ifdef HAVE_LIBSLP
if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
@@ -1902,7 +1961,7 @@ cupsdStopPolling(void)
}

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
/*

  • 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
    /
    @@ -1910,8 +1969,14 @@ cupsdStopPolling(void)
    void
    cupsdUpdateDNSSDName(void)
    {
    +#ifdef HAVE_DNSSD
    DNSServiceErrorType error; /
    Error from service creation /
    char webif[1024]; /
    Web interface share name /
    +#endif /
    HAVE_DNSSD */
    +#ifdef HAVE_AVAHI
    • int ret; /* Error from service creation */
    • char webif[AVAHI_LABEL_MAX]; /* Web interface share name /
      +#endif /
      HAVE_AVAHI _/

    ifdef HAVE_SYSTEMCONFIGURATION

    SCDynamicStoreRef sc; /_ Context for dynamic store /
    CFDictionaryRef btmm; /
    Back-to-My-Mac domains */
    @@ -2042,6 +2107,7 @@ cupsdUpdateDNSSDName(void)
    else
    strlcpy(webif, "CUPS Web Interface", sizeof(webif));

+#ifdef HAVE_DNSSD
if (WebIFRef)
DNSServiceRefDeallocate(WebIFRef);

@@ -2054,9 +2120,45 @@ cupsdUpdateDNSSDName(void)
NULL)) != kDNSServiceErr_NoError)
cupsdLogMessage(CUPSD_LOG_ERROR,
"DNS-SD web interface registration failed: %d", error);
+#endif /* HAVE_DNSSD */
+
+#ifdef HAVE_AVAHI

  • if (!AvahiCupsClient)
  • /*
    
  •  \* Client not yet running.
    
  •  */
    
  •  return;
    
  • if (AvahiWebIFGroup)
  •  avahi_entry_group_reset (AvahiWebIFGroup);
    
  • else
  •  AvahiWebIFGroup = avahi_entry_group_new (AvahiCupsClient,
    
  •                      avahi_entry_group_cb,
    
  •                      NULL);
    
  • if (AvahiWebIFGroup)
  • {
  •  ret = avahi_entry_group_add_service (AvahiWebIFGroup,
    
  •                  AVAHI_IF_UNSPEC,
    
  •                  AVAHI_PROTO_UNSPEC,
    
  •                  0, /\* flags */
    
  •                  webif, /\* name */
    
  •                  "_http._tcp", /\* type */
    
  •                  NULL, /\* domain */
    
  •                  NULL, /\* host */
    
  •                  DNSSDPort, /\* port */
    
  •                  "path=/", NULL);
    
  •  if (ret == 0)
    
  • ret = avahi_entry_group_commit (AvahiWebIFGroup);
  •  if (ret != 0)
    
  • cupsdLogMessage (CUPSD_LOG_ERROR,
  •        "Avahi web interface registration failed: %d", ret);
    
  • }
    +#endif /* HAVE_AVAHI /
    }
    }
    -#endif /
    HAVE_DNSSD /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

#ifdef HAVE_LDAP
@@ -2334,13 +2436,15 @@ dnssdAddAlias(const void key, / I - Key */
"Bad Back to My Mac domain in dynamic store!");
}

endif /* HAVE_COREFOUNDATION */

+#endif /* HAVE_DNSSD */

+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
/*

  • 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
    */

-static char * /* O - TXT record /
+static cupsd_txt_record_t /
O - TXT record /
dnssdBuildTxtRecord(
int *txt_len, /
O - TXT record length /
cupsd_printer_t *p, /
I - Printer information */
@@ -2379,7 +2483,12 @@ dnssdBuildTxtRecord(
keyvalue[i ][0] = "ty";
keyvalue[i++][1] = p->make_model ? p->make_model : "Unknown";

  • snprintf(admin_hostname, sizeof(admin_hostname), "%s.local.", DNSSDHostName);
  • snprintf(admin_hostname, sizeof(admin_hostname),
  •  "%s.local"
    
    +#ifdef HAVE_DNSSD
  •  "." /\* terminating dot no good for Avahi _/
    
    +#endif /_ HAVE_DNSSD */
  •  , DNSSDHostName);
    
    httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str),
    "http", NULL, admin_hostname, DNSSDPort, "/%s/%s",
    (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
    @@ -2462,7 +2571,12 @@ dnssdBuildTxtRecord(
    • Then pack them into a proper txt record...
      */

+#ifdef HAVE_DNSSD
return (dnssdPackTxtRecord(txt_len, keyvalue, i));
+#endif /* HAVE_DNSSD */
+#ifdef HAVE_AVAHI

  • return (avahiPackTxtRecord(keyvalue, i));
    +#endif /* HAVE_AVAHI */
    }

@@ -2474,7 +2588,16 @@ static int /* O - Result of comparison /
dnssdComparePrinters(cupsd_printer_t *a,/
I - First printer /
cupsd_printer_t *b)/
I - Second printer */
{

  • return (_cups_strcasecmp(a->reg_name, b->reg_name));
  • if (!a->reg_name)
  • if (!b->reg_name)
  •  return 0;
    
  • else
  •  return -1;
    
  • else
  • if (!b->reg_name)
  •  return 1;
    
  • else
  •  return (_cups_strcasecmp(a->reg_name, b->reg_name));
    
    }

@@ -2489,6 +2612,10 @@ dnssdDeregisterPrinter(
{
cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);

+#ifdef HAVE_DNSSD

  • if (!DNSSDRef)
  • return;

/*

  • Closing the socket deregisters the service
    /
    @@ -2524,6 +2651,24 @@ dnssdDeregisterPrinter(
    free(p->printer_txt);
    p->printer_txt = NULL;
    }
    +#endif /
    HAVE_DNSSD */
    +
    +#ifdef HAVE_AVAHI
  • if (p->avahi_group)
  • {
  •  avahi_entry_group_reset (p->avahi_group);
    
  •  avahi_entry_group_free (p->avahi_group);
    
  •  p->avahi_group = NULL;
    
  •  if (p->ipp_txt)
    
  • avahi_string_list_free (p->ipp_txt);
  •  if (p->printer_txt)
    
  • avahi_string_list_free (p->printer_txt);
  •  p->ipp_txt = p->printer_txt = NULL;
    
  • }
    +#endif /* HAVE_AVAHI */

/*

  • Remove the printer from the array of DNS-SD printers, then clear the
    @@ -2533,8 +2678,10 @@ dnssdDeregisterPrinter(
    cupsArrayRemove(DNSSDPrinters, p);
    cupsdClearString(&p->reg_name);
    }
    +#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

+#ifdef HAVE_DNSSD
/*

  • 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
  •                      TXT record format.
    
    @@ -2644,8 +2791,10 @@ dnssdRegisterCallback(
    LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
    }
    }
    +#endif /* HAVE_DNSSD */

+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
/*

  • 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
  •               or update the broadcast contents.
    
    @@ -2654,20 +2803,40 @@ dnssdRegisterCallback(
    static void
    dnssdRegisterPrinter(cupsd_printer_t p)/ I - Printer /
    {
    +#ifdef HAVE_DNSSD
    DNSServiceErrorType se; /
    dnssd errors /
    char *ipp_txt, /
    IPP TXT record buffer /
    *printer_txt, /
    LPD TXT record buffer */
    •       name[1024], /\* Service name */
      
    •       _nameptr;   /_ Pointer into name */
      
    •       name[1024]; /\* Service name _/
      
      int ipp_len, /_ IPP TXT record length /
      printer_len, /
      LPD TXT record length /
      printer_port; /
      LPD port number /
      +#endif /
      HAVE_DNSSD */
      +#ifdef HAVE_AVAHI
    • int ret; /* Error code */
    • AvahiStringList ipp_txt, / IPP TXT record */
    •       _printer_txt;   /_ LPD TXT record */
      
    • char name[AVAHI_LABEL_MAX], /* Service name */
    •       fullsubtype[AVAHI_LABEL_MAX]; /\* Full subtype */
      
    • char regtype_copy, / Writeable copy of reg type */
    •       _subtype,   /_ Current service sub type */
      
    •       _nextsubtype;   /_ Next service sub type _/
      
      +#endif /_ HAVE_AVAHI */
    • char nameptr; / Pointer into name /
      const char *regtype; /
      Registration type */

+#ifdef HAVE_DNSSD

  • if (!DNSSDRef)
  • return;

cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
!p->ipp_ref ? "new" : "update");

+#endif /* HAVE_DNSSD */
+#ifdef HAVE_AVAHI

  • cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
  •     !p->avahi_group ? "new" : "update");
    
    +#endif /* HAVE_AVAHI /
    /
    • If per-printer sharing was just disabled make sure we're not
    • registered before returning.
      @@ -2686,12 +2855,36 @@ dnssdRegisterPrinter(cupsd_printer_t p)/ I - Printer */
      if (p->info && strlen(p->info) > 0)
      {
      if (DNSSDComputerName)
  •  snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDComputerName);
    
  • {
  • /*
    
  •  \* Make sure there is room for at least 15 characters of
    
  •  \* DNSSDComputerName.
    
  •  */
    
  •  assert(sizeof(name) >= 15 + 4);
    
  •  nameptr = name + strlcpy(name, p->info,
    
  •              sizeof(name) - 4 -
    
  •              strnlen(DNSSDComputerName, 15));
    
  •  nameptr += strlcpy(nameptr, " @ ", sizeof(name) - (nameptr - name));
    
  •  strlcpy(nameptr, DNSSDComputerName, sizeof(name) - (nameptr - name));
    
  • }
    else
    strlcpy(name, p->info, sizeof(name));
    }
    else if (DNSSDComputerName)
  • snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDComputerName);
  • {
  • /*
  • * Make sure there is room for at least 15 characters of
  • * DNSSDComputerName.
  • */
  • assert(sizeof(name) >= 15 + 4);
  • nameptr = name + strlcpy(name, p->info,
  •            sizeof(name) - 4 -
    
  •            strnlen(DNSSDComputerName, 15));
    
  • nameptr += strlcpy(nameptr, " @ ", sizeof(name) - (nameptr - name));
  • strlcpy(nameptr, DNSSDComputerName, sizeof(name) - (nameptr - name));
  • }
    else
    strlcpy(name, p->name, sizeof(name));

@@ -2712,6 +2905,7 @@ dnssdRegisterPrinter(cupsd_printer_t p)/ I - Printer */

  • Register IPP and (optionally) LPD...
    */

+#ifdef HAVE_DNSSD
ipp_len = 0; /* anti-compiler-warning-code */
ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);

@@ -2884,6 +3078,209 @@ dnssdRegisterPrinter(cupsd_printer_t p)/ I - Printer */

if (printer_txt)
free(printer_txt);
+#endif /* HAVE_DNSSD */
+#ifdef HAVE_AVAHI

  • if (!AvahiCupsClient)
  • /*
  • * Client not running yet. The client callback will call us again later.
  • */
  • return;
  • ipp_txt = dnssdBuildTxtRecord(NULL, p, 0);
  • printer_txt = dnssdBuildTxtRecord(NULL, p, 1);
  • regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" : DNSSDRegType;
  • if (p->avahi_group && p->ipp_txt && ipp_txt &&
  •  !avahi_string_list_equal (p->ipp_txt, ipp_txt))
    
  • {
  • /*
  • * Update the existing registration...
  • */
  • avahi_string_list_free (p->ipp_txt);
  • if (p->printer_txt)
  •  avahi_string_list_free (p->printer_txt);
    
  • /*
  • * Update the service group entry.
  • */
  • regtype_copy = strdup (regtype);
  • subtype = strchr (regtype_copy, ',');
  • if (subtype)
  •  *subtype = '\0';
    
  • cupsdLogMessage (CUPSD_LOG_DEBUG,
  •        "Updating TXT record for %s (%s)", name, regtype_copy);
    
  • ret = avahi_entry_group_update_service_txt_strlst (p->avahi_group,
  •                          AVAHI_IF_UNSPEC,
    
  •                          AVAHI_PROTO_UNSPEC,
    
  •                          0, name,
    
  •                          regtype_copy,
    
  •                          NULL, ipp_txt);
    
  • free (regtype_copy);
  • if (ret < 0)
  •  goto update_failed;
    
  • p->ipp_txt = ipp_txt;
  • ipp_txt = NULL;
  • if (BrowseLocalProtocols & BROWSE_LPD)
  • {
  •  ret = avahi_entry_group_update_service_txt_strlst (p->avahi_group,
    
  •                        AVAHI_IF_UNSPEC,
    
  •                        AVAHI_PROTO_UNSPEC,
    
  •                        0, name,
    
  •                        "_printer._tcp", NULL,
    
  •                        printer_txt);
    
  •  if (ret < 0)
    
  • goto update_failed;
  •  p->printer_txt = printer_txt;
    
  •  printer_txt = NULL;
    
  • }
  • ret = avahi_entry_group_commit (p->avahi_group);
  • if (ret < 0)
  • {
  • update_failed:
  •  cupsdLogMessage (CUPSD_LOG_ERROR,
    
  •          "Failed to update TXT record for %s: %d",
    
  •          name, ret);
    
  •  avahi_entry_group_reset (p->avahi_group);
    
  •  avahi_entry_group_free (p->avahi_group);
    
  •  p->avahi_group = NULL;
    
  •  ipp_txt = p->ipp_txt;
    
  •  p->ipp_txt = NULL;
    
  • }
  • }
  • if (!p->avahi_group)
  • {
  • /*
  • * Initial registration. Use the _fax subtype for fax queues...
  • */
  • p->avahi_group = avahi_entry_group_new (AvahiCupsClient,
  •                   avahi_entry_group_cb,
    
  •                   p);
    
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •       "Registering Avahi printer %s with name \"%s\" and "
    
  •       "type \"%s\"", p->name, name, regtype);
    
  • if (!p->avahi_group)
  • {
  •  ret = 0;
    
  •  goto add_failed;
    
  • }
  • /*
  • * Add each service type (DNSSDRegType may contain several,
  • * separated by commas).
  • */
  • subtype = regtype_copy = strdup (regtype);
  • while (subtype && *subtype)
  • {
  •  nextsubtype = strchr (subtype, ',');
    
  •  if (nextsubtype)
    
  • *nextsubtype++ = '\0';
  •  if (subtype == regtype_copy)
    
  •  {
    
  •   /*
    
  • * Main type entry.
  • */
  • cupsdLogMessage (CUPSD_LOG_DEBUG,
  •        "Adding TXT record for %s (%s)", name, regtype_copy);
    
  • ret = avahi_entry_group_add_service_strlst (p->avahi_group,
  •                       AVAHI_IF_UNSPEC,
    
  •                       AVAHI_PROTO_UNSPEC,
    
  •                       0, name, regtype_copy,
    
  •                       NULL, NULL,
    
  •                       DNSSDPort,
    
  •                       ipp_txt);
    
  •  }
    
  •  else
    
  •  {
    
  •   /*
    
  • * Sub-type entry.
  • */
  • snprintf (fullsubtype, sizeof(fullsubtype),
  •     "%s._sub.%s", subtype, regtype_copy);
    
  • cupsdLogMessage (CUPSD_LOG_DEBUG,
  •        "Adding TXT record for %s (%s)", name, fullsubtype);
    
  • ret = avahi_entry_group_add_service_subtype (p->avahi_group,
  •                        AVAHI_IF_UNSPEC,
    
  •                        AVAHI_PROTO_UNSPEC,
    
  •                        0, name,
    
  •                        regtype_copy,
    
  •                        NULL, fullsubtype);
    
  •  }
    
  •  if (ret < 0)
    
  •  {
    
  • free (regtype_copy);
  • goto add_failed;
  •  }
    
  •  subtype = nextsubtype;
    
  • }
  • free (regtype_copy);
  • p->ipp_txt = ipp_txt;
  • ipp_txt = NULL;
  • if (BrowseLocalProtocols & BROWSE_LPD)
  • {
  •  cupsdLogMessage(CUPSD_LOG_DEBUG,
    
  •         "Registering Avahi printer %s with name \"%s\" and "
    
  •         "type \"_printer._tcp\"", p->name, name);
    
  •  ret = avahi_entry_group_add_service_strlst (p->avahi_group,
    
  •                     AVAHI_IF_UNSPEC,
    
  •                     AVAHI_PROTO_UNSPEC,
    
  •                     0, name,
    
  •                     "_printer._tcp", NULL, NULL,
    
  •                     515,
    
  •                     printer_txt);
    
  •  if (ret < 0)
    
  • goto add_failed;
  •  p->printer_txt = printer_txt;
    
  •  printer_txt = NULL;
    
  • }
  • ret = avahi_entry_group_commit (p->avahi_group);
  • if (ret < 0)
  • {
  • add_failed:
  •  cupsdLogMessage (CUPSD_LOG_ERROR,
    
  •          "Failed to add Avahi entry for %s: %d",
    
  •          name, ret);
    
  •  if (p->avahi_group)
    
  •  {
    
  • avahi_entry_group_reset (p->avahi_group);
  • avahi_entry_group_free (p->avahi_group);
  • p->avahi_group = NULL;
  •  }
    
  •  ipp_txt = p->ipp_txt;
    
  •  p->ipp_txt = NULL;
    
  • }
  • }
  • if (ipp_txt)
  • avahi_string_list_free (ipp_txt);
  • if (printer_txt)
  • avahi_string_list_free (printer_txt);
    +#endif /* HAVE_AVAHI */
    }

@@ -2896,6 +3293,10 @@ dnssdStop(void)
{
cupsd_printer_t p; / Current printer */

+#ifdef HAVE_DNSSD

  • if (!DNSSDRef)
  • return;
    +#endif /* HAVE_DNSSD */

/*

  • De-register the individual printers
    @@ -2906,6 +3307,7 @@ dnssdStop(void)
    p = (cupsd_printer_t *)cupsArrayNext(Printers))
    dnssdDeregisterPrinter(p);

+#ifdef HAVE_DNSSD
/*

  • Shutdown the rest of the service refs...
    */
    @@ -2926,14 +3328,17 @@ dnssdStop(void)

    DNSServiceRefDeallocate(DNSSDRef);
    DNSSDRef = NULL;
    +#endif /* HAVE_DNSSD */

    cupsArrayDelete(DNSSDPrinters);
    DNSSDPrinters = NULL;

    DNSSDPort = 0;
    }
    +#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

+#ifdef HAVE_DNSSD
/*

  • 'dnssdUpdate()' - Handle DNS-SD queries.
    /
    @@ -2955,6 +3360,147 @@ dnssdUpdate(void)
    #endif /
    HAVE_DNSSD */

+#ifdef HAVE_AVAHI
+/*

  • * 'avahiPackTxtRecord()' - Pack an array of key/value pairs into an
  • * AvahiStringList.
  • /
    +
    +static AvahiStringList * /
    O - new string list /
    +avahiPackTxtRecord(char *keyvalue[][2], /
    I - Table of key value pairs */
  •      int count)       /\* I - Number of items in table */
    
    +{
  • AvahiStringList *strlst = NULL;
  • char **elements;
  • size_t len;
  • int i = 0;
  • elements = malloc ((1 + count) * sizeof (char *));
  • if (!elements)
  • goto cleanup;
  • for (i = 0; i < count; i++)
  • {
  •  len = (1 + strlen (keyvalue[i][0]) +
    
  •    (keyvalue[i][1] ? 1 + strlen (keyvalue[i][1]) : 1));
    
  •  elements[i] = malloc (len \* sizeof (char));
    
  •  if (!elements[i])
    
  • goto cleanup;
  •  snprintf (elements[i], len, "%s=%s", keyvalue[i][0], keyvalue[i][1]);
    
  • }
  • strlst = avahi_string_list_new_from_array ((const char **) elements, count);

+cleanup:

  • while (--i >= 0)
  • free (elements[i]);
  • free (elements);
  • return (strlst);
    +}

+/*

  • * 'avahi_entry_group_cb()' - Avahi entry group callback function.
  • */
    +static void
    +avahi_entry_group_cb (AvahiEntryGroup *group,
  •         AvahiEntryGroupState state,
    
  •         void *userdata)
    
    +{
  • char *name;
  • if (userdata)
  • name = ((cupsd_printer_t *) userdata)->reg_name;
  • else
  • name = "CUPS web interface";
  • switch (state)
  • {
  • case AVAHI_ENTRY_GROUP_UNCOMMITED:
  • case AVAHI_ENTRY_GROUP_REGISTERING:
  • break;
  • case AVAHI_ENTRY_GROUP_ESTABLISHED:
  • cupsdLogMessage (CUPSD_LOG_DEBUG,
  •        "Avahi entry group established for %s", name);
    
  • break;
  • default:
  • cupsdLogMessage (CUPSD_LOG_DEBUG,
  •        "Avahi entry group %s has state %d",
    
  •        name, state);
    
  • break;
  • }
    +}

+/*

  • * 'avahi_client_cb()' - Avahi client callback function.
  • */
    +static void
    +avahi_client_cb (AvahiClient *client,
  •    AvahiClientState state,
    
  •    void *userdata)
    
    +{
  • cupsd_printer_t *printer;
  • switch (state)
  • {
  • case AVAHI_CLIENT_S_RUNNING:
  • /*
  • * Avahi client started successfully.
  • */
  • AvahiCupsClient = client;
  • AvahiCupsClientConnecting = 0;
  • cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client started");
  • cupsdUpdateDNSSDName ();
  • for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
  • printer;
  • printer = (cupsd_printer_t *)cupsArrayNext(Printers))
  •  if (Browsing && (BrowseLocalProtocols & BROWSE_DNSSD) &&
    
  • (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
    
  •             CUPS_PRINTER_SCANNER))) && printer->shared)
    
  • dnssdRegisterPrinter (printer);
  • break;
  • case AVAHI_CLIENT_CONNECTING:
  • /*
  • * No Avahi daemon, client is waiting.
  • */
  • AvahiCupsClientConnecting = 1;
  • cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client connecting");
  • break;
  • case AVAHI_CLIENT_FAILURE:
  • /*
  • * Avahi client failed, close it to allow a clean restart.
  • */
  • cupsdLogMessage (CUPSD_LOG_ERROR,
  •        "Avahi client failed, "
    
  •        "closing client to allow a clean restart");
    
  • for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
  • printer;
  • printer = (cupsd_printer_t *)cupsArrayNext(Printers))
  •  dnssdDeregisterPrinter (printer);
    
  • avahi_client_free(client);
  • AvahiCupsClientConnecting = 0;
  • AvahiCupsClient = NULL;
  • break;
  • default:
  • cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client state: %d", state);
  • }
    +}
    +#endif /* HAVE_AVAHI _/

/_

  • 'get_auth_info_required()' - Get the auth-info-required value to advertise.
    _/
    diff --git a/scheduler/dirsvc.h b/scheduler/dirsvc.h
    index 99079bd..d53a179 100644
    --- a/scheduler/dirsvc.h
    +++ b/scheduler/dirsvc.h
    @@ -31,6 +31,10 @@

    endif /_ HAVE_LDAP_SSL_H _/

    #endif /_ HAVE_LDAP */

+#ifdef HAVE_AVAHI
+# include <avahi-client/publish.h>
+#endif /* HAVE_AVAHI /
+
/

  • Browse protocols...
    /
    @@ -131,19 +135,22 @@ VAR int PollPipe VALUE(0);
    VAR cupsd_statbuf_t *PollStatusBuffer VALUE(NULL);
    /
    Status buffer for pollers */

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
VAR char DNSSDComputerName VALUE(NULL),
/
Computer/server name /
*DNSSDHostName VALUE(NULL),
/
Hostname /
*DNSSDRegType VALUE(NULL);
/
Bonjour registration type */
-VAR cups_array_t *DNSSDAlias VALUE(NULL);

  •               /\* List of dynamic ServerAlias's _/
    
    VAR int DNSSDPort VALUE(0);
    /_ Port number to register /
    VAR cups_array_t *DNSSDPrinters VALUE(NULL);
    /
    Printers we have registered /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
    +
    +#ifdef HAVE_DNSSD
    +VAR cups_array_t *DNSSDAlias VALUE(NULL);
  •               /\* List of dynamic ServerAlias's _/
    
    VAR DNSServiceRef DNSSDRef VALUE(NULL),
    /_ Master DNS-SD service reference /
    WebIFRef VALUE(NULL),
    @@ -152,6 +159,17 @@ VAR DNSServiceRef DNSSDRef VALUE(NULL),
    /
    Remote printer browse reference /
    #endif /
    HAVE_DNSSD */

+#ifdef HAVE_AVAHI
+VAR AvahiCupsPoll *AvahiCupsPollHandle VALUE(NULL);

  •               /\* AvahiCupsPoll object */
    
    +VAR AvahiClient *AvahiCupsClient VALUE(NULL);
  •               /\* AvahiClient object */
    
    +VAR int AvahiCupsClientConnecting VALUE(0);
  •               /\* Is AvahiClient object connecting? */
    
    +VAR AvahiEntryGroup *AvahiWebIFGroup VALUE(NULL);
  •               /\* Web interface entry group _/
    
    +#endif /_ HAVE_AVAHI /
    +
    #ifdef HAVE_LIBSLP
    VAR SLPHandle BrowseSLPHandle VALUE(NULL);
    /
    SLP API handle /
    @@ -195,13 +213,14 @@ extern void cupsdRegisterPrinter(cupsd_printer_t *p);
    extern void cupsdRestartPolling(void);
    extern void cupsdSaveRemoteCache(void);
    extern void cupsdSendBrowseList(void);
    +extern void cupsdStartAvahiClient(void);
    extern void cupsdStartBrowsing(void);
    extern void cupsdStartPolling(void);
    extern void cupsdStopBrowsing(void);
    extern void cupsdStopPolling(void);
    -#ifdef HAVE_DNSSD
    +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
    extern void cupsdUpdateDNSSDName(void);
    -#endif /
    HAVE_DNSSD /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) /
    #ifdef HAVE_LDAP
    extern void cupsdUpdateLDAPBrowse(void);
    #endif /
    HAVE_LDAP */
    diff --git a/scheduler/ipp.c b/scheduler/ipp.c
    index a048baa..9a3ab11 100644
    --- a/scheduler/ipp.c
    +++ b/scheduler/ipp.c
    @@ -6087,7 +6087,7 @@ copy_printer_attrs(
    ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time",
    ippTimeToDate(curtime));

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
if (!ra || cupsArrayFind(ra, "printer-dns-sd-name"))
{
if (printer->reg_name)
@@ -6097,7 +6097,7 @@ copy_printer_attrs(
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE,
"printer-dns-sd-name", 0);
}
-#endif /* HAVE_DNSSD /
+#endif /
defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

if (!ra || cupsArrayFind(ra, "printer-error-policy"))
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME,
diff --git a/scheduler/main.c b/scheduler/main.c
index 1e60572..6c210e6 100644
--- a/scheduler/main.c
+++ b/scheduler/main.c
@@ -120,6 +120,10 @@ main(int argc, /* I - Number of command-line args /
cupsd_listener_t *lis; /
Current listener /
time_t current_time, /
Current time /
activity, /
Client activity timer */
+#ifdef HAVE_AVAHI

  •       avahi_client_time, /\* Time for next Avahi client
    
  •                     check */
    

    +#endif /* HAVE_AVAHI /
    browse_time, /
    Next browse send time /
    senddoc_time, /
    Send-Document time /
    expire_time, /
    Subscription expire time /
    @@ -662,6 +666,9 @@ main(int argc, /
    I - Number of command-line args */
    */

    current_time = time(NULL);
    +#ifdef HAVE_AVAHI

  • avahi_client_time = current_time;
    +#endif /* HAVE_AVAHI /
    browse_time = current_time;
    event_time = current_time;
    expire_time = current_time;
    @@ -884,6 +891,16 @@ main(int argc, /
    I - Number of command-line args */
    tmo = cupsdNextTimeout (&tmo_delay);
    if (tmo && tmo_delay == 0)
    cupsdRunTimeout (tmo);

  • /*
  • * Try to restart the Avahi client every 10 seconds if needed...
  • */
  • if ((current_time - avahi_client_time) >= 10)
  • {
  •  avahi_client_time = current_time;
    
  •  cupsdStartAvahiClient();
    
  • }
    #endif /* HAVE_AVAHI */

#ifndef APPLE
diff --git a/scheduler/printers.c b/scheduler/printers.c
index 4686c4c..fac7bbc 100644
--- a/scheduler/printers.c
+++ b/scheduler/printers.c
@@ -883,9 +883,9 @@ cupsdDeletePrinter(
cupsdClearString(&p->alert);
cupsdClearString(&p->alert_description);

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
cupsdClearString(&p->pdl);
-#endif /* HAVE_DNSSD /
+#endif /
defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

cupsArrayDelete(p->filetypes);

@@ -3765,7 +3765,7 @@ add_printer_formats(cupsd_printer_t p) / I - Printer */
attr->values[i].string.text = _cupsStrAlloc(mimetype);
}

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
{
char pdl[1024]; /* Buffer to build pdl list /
mime_filter_t *filter; /
MIME filter looping var /
@@ -3821,7 +3821,7 @@ add_printer_formats(cupsd_printer_t *p) /
I - Printer */

 cupsdSetString(&p->pdl, pdl);

}
-#endif /* HAVE_DNSSD /
+#endif /
defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
}

diff --git a/scheduler/printers.h b/scheduler/printers.h
index 1751578..fb04651 100644
--- a/scheduler/printers.h
+++ b/scheduler/printers.h
@@ -16,6 +16,9 @@
#ifdef HAVE_DNSSD

include <dns_sd.h>

#endif /* HAVE_DNSSD /
+#ifdef HAVE_AVAHI
+# include "avahi.h"
+#endif /
HAVE_AVAHI */
#include <cups/pwg-private.h>

@@ -95,16 +98,23 @@ struct cupsd_printer_s
time_t marker_time; /* Last time marker attributes were updated _/
ppd_cache_t *pc; / PPD cache and mapping data */

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
char reg_name, / Name used for service registration */

  •   _pdl,           /_ pdl value for TXT record */
    
  •   _ipp_txt,       /_ IPP TXT record contents */
    
  •   _pdl;           /_ pdl value for TXT record _/
    
    +#endif /_ defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
    +#ifdef HAVE_DNSSD
  • char ipp_txt, / IPP TXT record contents /
    *printer_txt; /
    LPD TXT record contents /
    int ipp_len, /
    IPP TXT record length /
    printer_len; /
    LPD TXT record length /
    DNSServiceRef ipp_ref, /
    Reference for _ipp._tcp,_cups /
    printer_ref; /
    Reference for _printer._tcp /
    #endif /
    HAVE_DNSSD */
    +#ifdef HAVE_AVAHI
  • AvahiStringList ipp_txt, / IPP TXT record */
  •   _printer_txt;       /_ LPD TXT record */
    
  • AvahiEntryGroup avahi_group; / Avahi entry group /
    +#endif /
    HAVE_AVAHI */
    };
@michaelrsweet
Collaborator

"cups-avahi-1-config.patch":

diff -up cups-1.5.0/config.h.in.avahi-1-config cups-1.5.0/config.h.in
--- cups-1.5.0/config.h.in.avahi-1-config 2011-06-16 21:12:16.000000000 +0100
+++ cups-1.5.0/config.h.in 2011-08-05 15:04:09.535759988 +0100
@@ -390,6 +390,13 @@

/*

  • * Do we have Avahi for DNS Service Discovery?
  • /
    +
    +#undef HAVE_AVAHI
    +
    +
    +/
    • Do we have <sys/ioctl.h>?
      */

diff -up cups-1.5.0/config-scripts/cups-dnssd.m4.avahi-1-config cups-1.5.0/config-scripts/cups-dnssd.m4
--- cups-1.5.0/config-scripts/cups-dnssd.m4.avahi-1-config 2011-05-12 06:21:56.000000000 +0100
+++ cups-1.5.0/config-scripts/cups-dnssd.m4 2011-08-05 15:04:09.525760307 +0100
@@ -23,6 +23,21 @@ AC_ARG_WITH(dnssd-includes, [ --with-dn
DNSSDLIBS=""
DNSSD_BACKEND=""

+AC_ARG_ENABLE(avahi, [ --enable-avahi turn on DNS Service Discovery support, default=no],

  •     [if test x$enable_avahi = xyes; then
    
  •          AC_MSG_CHECKING(for Avahi)
    
  •          if $PKGCONFIG --exists avahi-client; then
    
  •              AC_MSG_RESULT(yes)
    
  •              CFLAGS="$CFLAGS `$PKGCONFIG --cflags avahi-client`"
    
  •              DNSSDLIBS="`$PKGCONFIG --libs avahi-client`"
    
  •              DNSSD_BACKEND="dnssd"
    
  •              AC_DEFINE(HAVE_AVAHI)
    
  •              enable_dnssd=no
    
  •          else
    
  •              AC_MSG_RESULT(no)
    
  •          fi
    
  •      fi])
    
    if test x$enable_dnssd != xno; then
    AC_CHECK_HEADER(dns_sd.h, [
    case "$uname" in
@michaelrsweet
Collaborator

"cups-avahi-2-backend.patch":

diff -up cups-1.5.0/backend/dnssd.c.avahi-2-backend cups-1.5.0/backend/dnssd.c
--- cups-1.5.0/backend/dnssd.c.avahi-2-backend 2011-08-05 15:04:46.182591844 +0100
+++ cups-1.5.0/backend/dnssd.c 2011-08-05 15:05:13.868710181 +0100
@@ -15,14 +15,21 @@
*

  • Contents:
    *
    • * next_txt_record() - Get next TXT record from a cups_txt_records_t.
    • * parse_txt_record_pair() - Read key/value pair in cups_txt_records_t.
  • main() - Browse for printers.
  • browse_callback() - Browse devices.
  • browse_local_callback() - Browse local devices.
  • compare_devices() - Compare two devices.
  • exec_backend() - Execute the backend that corresponds to the
  •                         resolved service name.
    
    • * device_type() - Get DNS-SD type enumeration from string.
  • get_device() - Create or update a device.
  • query_callback() - Process query data.
  • * avahi_client_callback() - Avahi client callback function.
  • * avahi_query_callback() - Avahi query callback function.
  • * avahi_browse_callback() - Avahi browse callback function.
  • * find_device() - Find a device from its name and domain.
  • sigterm_handler() - Handle termination signals...
  • unquote() - Unquote a name string.
    */
    @@ -33,7 +40,18 @@

#include "backend-private.h"
#include <cups/array.h>
-#include <dns_sd.h>
+#ifdef HAVE_DNSSD
+# include <dns_sd.h>
+#endif /* HAVE_DNSSD /
+#ifdef HAVE_AVAHI
+# include <avahi-client/client.h>
+# include <avahi-client/lookup.h>
+# include <avahi-common/simple-watch.h>
+# include <avahi-common/domain.h>
+# include <avahi-common/error.h>
+# include <avahi-common/malloc.h>
+#define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX
+#endif /
HAVE_AVAHI */

/*
@@ -53,7 +71,12 @@ typedef enum

typedef struct
{
+#ifdef HAVE_DNSSD
DNSServiceRef ref; /* Service reference for resolve /
+#endif /
HAVE_DNSSD */
+#ifdef HAVE_AVAHI

  • int resolved; /* Did we resolve the device? /
    +#endif /
    HAVE_AVAHI /
    char *name, /
    Service name /
    *domain, /
    Domain name /
    *fullName, /
    Full name /
    @@ -65,6 +88,20 @@ typedef struct
    sent; /
    Did we list the device? */
    } cups_device_t;

+typedef struct
+{

  • char key[256];
  • char value[256];

+#ifdef HAVE_DNSSD

  • const uint8_t *data;
  • const uint8_t *datanext;
  • const uint8_t dataend;
    +#else /
    HAVE_AVAHI */
  • AvahiStringList txt;
    +#endif /
    HAVE_DNSSD */
    +} cups_txt_records_t;

/*

  • Local globals...
    @@ -78,6 +115,7 @@ static int job_canceled = 0;
  • Local functions...
    */

+#ifdef HAVE_DNSSD
static void browse_callback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
@@ -93,12 +131,6 @@ static void browse_local_callback(DNSSe
const char _regtype,
const char *replyDomain,
void *context);
-static int compare_devices(cups_device_t *a, cups_device_t *b);
-static void exec_backend(char *_argv);
-static cups_device_t *get_device(cups_array_t *devices,

  •                   const char *serviceName,
    
  •                   const char *regtype,
    
  •               const char _replyDomain);
    
    static void query_callback(DNSServiceRef sdRef,
    DNSServiceFlags flags,
    uint32_t interfaceIndex,
    @@ -107,9 +139,118 @@ static void query_callback(DNSServiceRe
    uint16_t rrclass, uint16_t rdlen,
    const void *rdata, uint32_t ttl,
    void *context);
    +#endif /_ HAVE_DNSSD */
    +#ifdef HAVE_AVAHI
    +static void avahi_client_callback (AvahiClient *client,
  •                      AvahiClientState state,
    
  •                      void *context);
    
    +static void avahi_browse_callback (AvahiServiceBrowser *browser,
  •                      AvahiIfIndex interface,
    
  •                      AvahiProtocol protocol,
    
  •                      AvahiBrowserEvent event,
    
  •                      const char *serviceName,
    
  •                      const char *regtype,
    
  •                      const char *replyDomain,
    
  •                      AvahiLookupResultFlags flags,
    
  •                      void _context);
    
    +#endif /_ HAVE_AVAHI */
    +
    +static cups_device_t * find_device (cups_array_t *devices,
  •                cups_txt_records_t *txt,
    
  •                cups_device_t _dkey);
    
    +static int compare_devices(cups_device_t *a, cups_device_t *b);
    +static void exec_backend(char *_argv);
    +static cups_device_t *get_device(cups_array_t *devices,
  •                   const char *serviceName,
    
  •                   const char *regtype,
    
  •               const char *replyDomain);
    
    static void sigterm_handler(int sig);
    static void unquote(char *dst, const char *src, size_t dstsize);

+#ifdef HAVE_AVAHI
+static AvahiSimplePoll simple_poll = NULL;
+static int avahi_got_callback;
+#endif /
HAVE_AVAHI /
+
+
+/

  • * 'next_txt_record()' - Get next TXT record from a cups_txt_records_t.
  • */
    +
    +static cups_txt_records_t *
    +next_txt_record (cups_txt_records_t *txt)
    +{
    +#ifdef HAVE_DNSSD
  • txt->data = txt->datanext;
    +#else /* HAVE_AVAHI */
  • txt->txt = avahi_string_list_get_next (txt->txt);
  • if (txt->txt == NULL)
  • return NULL;
    +#endif /* HAVE_DNSSD */
  • return txt;
    +}

+/*

  • * 'parse_txt_record_pair()' - Read key/value pair in cups_txt_records_t.
  • */
    +
    +static int
    +parse_txt_record_pair (cups_txt_records_t *txt)
    +{
    +#ifdef HAVE_DNSSD
  • uint8_t datalen;
  • uint8_t *data = txt->data;
  • char *ptr;
  • /*
  • * Read a key/value pair starting with an 8-bit length. Since the
  • * length is 8 bits and the size of the key/value buffers is 256, we
  • * don't need to check for overflow...
  • */
  • datalen = *data++;
  • if (!datalen || (data + datalen) >= txt->dataend)
  • return NULL;
  • txt->datanext = data + datalen;
  • for (ptr = txt->key; data < txt->datanext && *data != '='; data ++)
  • *ptr++ = *data;
  • *ptr = '\0';
  • if (data < txt->datanext && *data == '=')
  • {
  • data++;
  • if (data < datanext)
  •  memcpy (txt->value, data, txt->datanext - data);
    
  • value[txt->datanext - data] = '\0';
  • }
  • else
  • return 1;
    +#else /* HAVE_AVAHI */
  • char *key, *value;
  • size_t len;
  • avahi_string_list_get_pair (txt->txt, &key, &value, &len);
  • if (len > sizeof (txt->value) - 1)
  • len = sizeof (txt->value) - 1;
  • memcpy (txt->value, value, len);
  • txt->value[len] = '\0';
  • len = strlen (key);
  • if (len > sizeof (txt->key) - 1)
  • len = sizeof (txt->key) - 1;
  • memcpy (txt->key, key, len);
  • txt->key[len] = '\0';
  • avahi_free (key);
  • avahi_free (value);
    +#endif /* HAVE_AVAHI */
  • return 0;
    +}

/*

  • 'main()' - Browse for printers.
    @@ -120,6 +261,13 @@ main(int argc, /* I - Number of comm
    char argv[]) / I - Command-line arguments /
    {
    const char *name; /
    Backend name */
  • cups_array_t devices; / Device array */
  • cups_device_t device; / Current device */
  • char uriName[1024]; /* Unquoted fullName for URI */
    +#ifdef HAVE_DNSSD
  • int fd; /* Main file descriptor */
  • fd_set input; /* Input set for select() */
  • struct timeval timeout; /* Timeout for select() /
    DNSServiceRef main_ref, /
    Main service reference /
    fax_ipp_ref, /
    IPP fax service reference /
    ipp_ref, /
    IPP service reference /
    @@ -133,12 +281,11 @@ main(int argc, /
    I - Number of comm
    pdl_datastream_ref, /* AppSocket service reference /
    printer_ref, /
    LPD service reference /
    riousbprint_ref; /
    Remote IO service reference */
  • int fd; /* Main file descriptor */
  • fd_set input; /* Input set for select() */
  • struct timeval timeout; /* Timeout for select() */
  • cups_array_t devices; / Device array */
  • cups_device_t device; / Current device */
  • char uriName[1024]; /* Unquoted fullName for URI /
    +#endif /
    HAVE_DNSSD */
    +#ifdef HAVE_AVAHI
  • AvahiClient *client;
  • int error;
    +#endif /* HAVE_AVAHI /
    #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
    struct sigaction action; /
    Actions for POSIX signals /
    #endif /
    HAVE_SIGACTION && !HAVE_SIGSET /
    @@ -198,6 +345,49 @@ main(int argc, /
    I - Number of comm
  • Browse for different kinds of printers...
    */

+#ifdef HAVE_AVAHI

  • if ((simple_poll = avahi_simple_poll_new ()) == NULL)
  • {
  • perror ("ERROR: Unable to create avahi simple poll object");
  • return (1);
  • }
  • client = avahi_client_new (avahi_simple_poll_get (simple_poll),
  •            0, avahi_client_callback, NULL, &error);
    
  • if (!client)
  • {
  • perror ("DEBUG: Unable to create avahi client");
  • return (0);
  • }
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_fax-ipp._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_ipp._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_ipp-tls._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_pdl-datastream._tcp",
    
  •            NULL, 0,
    
  •            avahi_browse_callback,
    
  •            devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_printer._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    
  • avahi_service_browser_new (client, AVAHI_IF_UNSPEC,

  •            AVAHI_PROTO_UNSPEC,
    
  •            "_riousbprint._tcp", NULL, 0,
    
  •            avahi_browse_callback, devices);
    

    +#endif /* HAVE_AVAHI /
    +#ifdef HAVE_DNSSD
    if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError)
    {
    perror("ERROR: Unable to create service connection");
    @@ -258,6 +448,7 @@ main(int argc, /
    I - Number of comm
    riousbprint_ref = main_ref;
    DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0,
    "_riousbprint._tcp", NULL, browse_callback, devices);
    +#endif /* HAVE_DNSSD */

    /*

    • Loop until we are killed...
      @@ -265,6 +456,9 @@ main(int argc, /* I - Number of comm

    while (!job_canceled)
    {

  • int announce = 0;

+#ifdef HAVE_DNSSD
FD_ZERO(&input);
FD_SET(fd, &input);

@@ -284,11 +478,35 @@ main(int argc, /* I - Number of comm
}
else
{

  •  announce = 1;
    
  • }
    +#else /* HAVE_AVAHI */
  • int r;
  • avahi_got_callback = 0;
  • r = avahi_simple_poll_iterate (simple_poll, 1);
  • if (r != 0 && r != EINTR)
  • {
  • /*
    
  •  \* We've been told to exit the loop.  Perhaps the connection to
    
  •  \* avahi failed.
    
  •  */
    
  •  break;
    
  • }
  • if (avahi_got_callback)
  •  announce = 1;
    
    +#endif /* HAVE_DNSSD */
    +
  • if (announce)
  • {
    /*
  • Announce any devices we've found...
    */

+#ifdef HAVE_DNSSD
DNSServiceErrorType status; /* DNS query status /
+#endif /
HAVE_DNSSD /
cups_device_t *best; /
Best matching device /
char device_uri[1024]; /
Device URI /
int count; /
Number of queries /
@@ -302,6 +520,7 @@ main(int argc, /
I - Number of comm
if (device->sent)
sent ++;

+#ifdef HAVE_DNSSD
if (device->ref)
count ++;

@@ -333,14 +552,23 @@ main(int argc, /* I - Number of comm
count ++;
}
}

  • else if (!device->sent)

  • else
    +#endif /* HAVE_DNSSD */
    +#ifdef HAVE_AVAHI

  • if (!device->resolved)

  • continue;
    
  •    else
    

    +#endif /* HAVE_AVAHI */

  • if (!device->sent)
    {
    +#ifdef HAVE_DNSSD
    /*

  • Got the TXT records, now report the device...
    */

    DNSServiceRefDeallocate(device->ref);
    device->ref = 0;
    +#endif /* HAVE_DNSSD */

    if (!best)
    best = device;
    @@ -401,6 +629,7 @@ main(int argc, /* I - Number of comm
    }

+#ifdef HAVE_DNSSD
/*

  • 'browse_callback()' - Browse devices.
    /
    @@ -489,6 +718,7 @@ browse_local_callback(
    device->fullName);
    device->sent = 1;
    }
    +#endif /
    HAVE_DNSSD */

    /*
    @@ -569,6 +799,41 @@ exec_backend(char *argv) / I - Comman

    /*

    • * 'device_type()' - Get DNS-SD type enumeration from string.
    • */
      +
      +static int
      +device_type (const char *regtype)
      +{
      +#ifdef HAVE_AVAHI
    • if (!strcmp(regtype, "_ipp._tcp"))
    • return (CUPS_DEVICE_IPP);
    • else if (!strcmp(regtype, "_ipps._tcp") ||
    •  !strcmp(regtype, "_ipp-tls._tcp"))
      
    • return (CUPS_DEVICE_IPPS);
    • else if (!strcmp(regtype, "_fax-ipp._tcp"))
    • return (CUPS_DEVICE_FAX_IPP);
    • else if (!strcmp(regtype, "_printer._tcp"))
    • return (CUPS_DEVICE_PDL_DATASTREAM);
      +#else
    • if (!strcmp(regtype, "_ipp._tcp."))
    • return (CUPS_DEVICE_IPP);
    • else if (!strcmp(regtype, "_ipps._tcp.") ||
    •  !strcmp(regtype, "_ipp-tls._tcp."))
      
    • return (CUPS_DEVICE_IPPS);
    • else if (!strcmp(regtype, "_fax-ipp._tcp."))
    • return (CUPS_DEVICE_FAX_IPP);
    • else if (!strcmp(regtype, "_printer._tcp."))
    • return (CUPS_DEVICE_PRINTER);
    • else if (!strcmp(regtype, "_pdl-datastream._tcp."))
    • return (CUPS_DEVICE_PDL_DATASTREAM);
      +#endif /* HAVE_AVAHI */
    • return (CUPS_DEVICE_RIOUSBPRINT);
      +}

    +/*

  • 'get_device()' - Create or update a device.
    */

@@ -589,20 +854,7 @@ get_device(cups_array_t devices, / I -
*/

key.name = (char *)serviceName;

  • if (!strcmp(regtype, "_ipp._tcp."))
  • key.type = CUPS_DEVICE_IPP;
  • else if (!strcmp(regtype, "_ipps._tcp.") ||
  •  !strcmp(regtype, "_ipp-tls._tcp."))
    
  • key.type = CUPS_DEVICE_IPPS;
  • else if (!strcmp(regtype, "_fax-ipp._tcp."))
  • key.type = CUPS_DEVICE_FAX_IPP;
  • else if (!strcmp(regtype, "_printer._tcp."))
  • key.type = CUPS_DEVICE_PRINTER;
  • else if (!strcmp(regtype, "_pdl-datastream._tcp."))
  • key.type = CUPS_DEVICE_PDL_DATASTREAM;
  • else
  • key.type = CUPS_DEVICE_RIOUSBPRINT;
  • key.type = device_type (regtype);

for (device = cupsArrayFind(devices, &key);
device;
@@ -622,8 +874,14 @@ get_device(cups_array_t devices, / I -
free(device->domain);
device->domain = strdup(replyDomain);

+#ifdef HAVE_DNSSD
DNSServiceConstructFullName(fullName, device->name, regtype,
replyDomain);
+#else /* HAVE_AVAHI */

  • avahi_service_name_join (fullName, kDNSServiceMaxDomainName,
  •            serviceName, regtype, replyDomain);
    
    +#endif /* HAVE_DNSSD /
    +
    free(device->fullName);
    device->fullName = strdup(fullName);
    }
    @@ -643,6 +901,9 @@ get_device(cups_array_t *devices, /
    I -
    device->domain = strdup(replyDomain);
    device->type = key.type;
    device->priority = 50;
    +#ifdef HAVE_AVAHI
  • device->resolved = 0;
    +#endif /* HAVE_AVAHI */

cupsArrayAdd(devices, device);

@@ -650,13 +911,20 @@ get_device(cups_array_t devices, / I -

  • Set the "full name" of this service, which is used for queries...
    */

+#ifdef HAVE_DNSSD
DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain);
+#else /* HAVE_AVAHI */

  • avahi_service_name_join (fullName, kDNSServiceMaxDomainName,

  •          serviceName, regtype, replyDomain);
    

    +#endif /* HAVE_DNSSD */
    +
    device->fullName = strdup(fullName);

    return (device);
    }

+#ifdef HAVE_DNSSD
/*

  • 'query_callback()' - Process query data.
    /
    @@ -680,7 +948,7 @@ query_callback(
    *ptr; /
    Pointer into string /
    cups_device_t dkey, /
    Search key */

    device; / Device */

    • cups_txt_records_t txt;

    fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, "
    "interfaceIndex=%d, errorCode=%d, fullName="%s", "
    @@ -714,94 +982,233 @@ query_callback(
    if ((ptr = strstr(name, "._")) != NULL)
    *ptr = '\0';

  • if (strstr(fullName, "_ipp._tcp."))

  • dkey.type = CUPS_DEVICE_IPP;

  • else if (strstr(fullName, "_ipps._tcp.") ||

  •       strstr(fullName, "_ipp-tls._tcp."))
    
  • dkey.type = CUPS_DEVICE_IPPS;

  • else if (strstr(fullName, "_fax-ipp._tcp."))

  • dkey.type = CUPS_DEVICE_FAX_IPP;

  • else if (strstr(fullName, "_printer._tcp."))

  • dkey.type = CUPS_DEVICE_PRINTER;

  • else if (strstr(fullName, "_pdl-datastream._tcp."))

  • dkey.type = CUPS_DEVICE_PDL_DATASTREAM;

  • dkey.type = device_type (fullName);

  • txt.data = rdata;
  • txt.dataend = rdata + rdlen;
  • device = find_device ((cups_array_t *) context, &txt, &dkey);
  • if (!device)
  • fprintf(stderr, "DEBUG: Ignoring TXT record for "%s"...\n", fullName);
    +}
    +#endif /* HAVE_DNSSD _/

+#ifdef HAVE_AVAHI
+/_

  • * 'avahi_client_callback()' - Avahi client callback function.
  • */
    +
    +static void
    +avahi_client_callback(AvahiClient *client,
  •         AvahiClientState state,
    
  •         void *context)
    
    +{
  • /*
  • * If the connection drops, quit.
  • */
  • if (state == AVAHI_CLIENT_FAILURE)
  • {
  • fprintf (stderr, "ERROR: Avahi connection failed\n");
  • avahi_simple_poll_quit (simple_poll);
  • }
    +}

+/*

  • * 'avahi_query_callback()' - Avahi query callback function.
  • */
    +
    +static void
    +avahi_query_callback(AvahiServiceResolver *resolver,
  •        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 *context)
    
    +{
  • AvahiClient *client;
  • cups_device_t key,
  •       *device;
    
  • char uqname[1024],
  •       *ptr;
    
  • cups_txt_records_t txtr;
  • client = avahi_service_resolver_get_client (resolver);
  • if (event != AVAHI_RESOLVER_FOUND)
  • {
  • if (event == AVAHI_RESOLVER_FAILURE)
  • {
  •  fprintf (stderr, "ERROR: %s\n",
    
  •      avahi_strerror (avahi_client_errno (client)));
    
  • }
  • avahi_service_resolver_free (resolver);
  • return;
  • }
  • /*
  • * Set search key for device.
  • */
  • key.name = uqname;
  • unquote (uqname, name, sizeof (uqname));
  • if ((ptr = strstr(name, "._")) != NULL)
  • *ptr = '\0';
  • key.domain = (char *) domain;
  • key.type = device_type (type);
  • /*
  • * Find the device and the the TXT information.
  • */
  • txtr.txt = txt;
  • device = find_device ((cups_array_t *) context, &txtr, &key);
  • if (device)
  • {
  • /*
  • * Let the main loop know to announce the device.
  • */
  • device->resolved = 1;
  • avahi_got_callback = 1;
  • }
    else
  • dkey.type = CUPS_DEVICE_RIOUSBPRINT;
  • fprintf (stderr, "DEBUG: Ignoring TXT record for "%s"...\n", name);
  • avahi_service_resolver_free (resolver);
    +}

+/*

  • * 'avahi_browse_callback()' - Avahi browse callback function.
  • */
    +
    +static void
    +avahi_browse_callback(AvahiServiceBrowser *browser,
  •         AvahiIfIndex interface,
    
  •         AvahiProtocol protocol,
    
  •         AvahiBrowserEvent event,
    
  •         const char *name,
    
  •         const char *type,
    
  •         const char *domain,
    
  •         AvahiLookupResultFlags flags,
    
  •         void *context)
    
    +{
  • AvahiClient *client = avahi_service_browser_get_client (browser);
  • switch (event)
  • {
  • case AVAHI_BROWSER_FAILURE:
  • fprintf (stderr, "ERROR: %s\n",
  •    avahi_strerror (avahi_client_errno (client)));
    
  • avahi_simple_poll_quit (simple_poll);
  • return;
  • case AVAHI_BROWSER_NEW:
  • /*
  • * This object is new on the network.
  • */
  • if (flags & AVAHI_LOOKUP_RESULT_LOCAL)
  • {
  • /*
    
  •  \* This comes from the local machine so ignore it.
    
  •  */
    
  •  fprintf (stderr, "DEBUG: ignoring local service %s\n", name);
    
  • }
  • else
  • {
  • /*
    
  •  \* Create a device entry for it if it doesn't yet exist.
    
  •  */
    
  •  get_device ((cups_array_t *)context, name, type, domain);
    
  • /*
    
  •  \* Now look for a TXT entry.
    
  •  */
    
  •  if (avahi_service_resolver_new (client, interface, protocol,
    
  •                 name, type, domain,
    
  •                 AVAHI_PROTO_UNSPEC, 0,
    
  •                 avahi_query_callback, context) == NULL)
    
  •  {
    
  • fprintf (stderr, "ERROR: failed to resolve service %s: %s\n",
  •    name, avahi_strerror (avahi_client_errno (client)));
    
  •  }
    
  • }
  • break;
  • case AVAHI_BROWSER_REMOVE:
  • case AVAHI_BROWSER_ALL_FOR_NOW:
  • case AVAHI_BROWSER_CACHE_EXHAUSTED:
  • break;
  • }
    +}
    +#endif /* HAVE_AVAHI */
  • for (device = cupsArrayFind(devices, &dkey);
    +/*
  • * 'find_device()' - Find a device from its name and domain.
  • */
    +
    +static cups_device_t *
    +find_device (cups_array_t *devices,
  •    cups_txt_records_t *txt,
    
  •    cups_device_t *dkey)
    
    +{
  • cups_device_t *device;
  • char *ptr;
  • for (device = cupsArrayFind(devices, dkey);
    device;
    device = cupsArrayNext(devices))
    {
  • if (_cups_strcasecmp(device->name, dkey.name) ||
  •    _cups_strcasecmp(device->domain, dkey.domain))
    
  • if (_cups_strcasecmp(device->name, dkey->name) ||
  •    _cups_strcasecmp(device->domain, dkey->domain))
    
    {
    device = NULL;
    break;
    }
  • else if (device->type == dkey.type)
  • else if (device->type == dkey->type)
    {
    /*
  • Found it, pull out the priority and make and model from the TXT
  • record and save it...
    */
  •  const uint8_t    *data,      /* Pointer into data */
    
  •       _datanext,  /_ Next key/value pair */
    
  •       _dataend;   /_ End of entire TXT record */
    
  •  uint8_t      datalen;    /\* Length of current key/value pair */
    
  •  char     key[256],   /\* Key string */
    
  •       value[256], /\* Value string */
    
  •       make_and_model[512],
    
  •  char     make_and_model[512],
                    /\* Manufacturer and model _/
        model[256], /_ Model */
    

- device_id[2048];/* 1284 device ID */

  •       device_id[2048]; /* 1284 device ID */
    

    device_id[0] = '\0';
    make_and_model[0] = '\0';

    strcpy(model, "Unknown");

  •  for (data = rdata, dataend = data + rdlen;
    
  •       data < dataend;
    
  •       data = datanext)
    
  •  for (;;)
    

    {

  •   /*
    
  •    \* Read a key/value pair starting with an 8-bit length.  Since the
    
  • * length is 8 bits and the size of the key/value buffers is 256, we

  • * don't need to check for overflow...

- */

- datalen = *data++;

  •    if (!datalen || (data + datalen) >= dataend)
    

- break;

- datanext = data + datalen;

  •    for (ptr = key; data < datanext && *data != '='; data ++)
    
  • *ptr++ = *data;
    
  • *ptr = '\0';
  • char *key;
  • char *value;
  • if (data < datanext && *data == '=')
  • {

- data ++;

  • if (data < datanext)
    
  •   memcpy(value, data, datanext - data);
    
  • value[datanext - data] = '\0';
    
  • if (parse_txt_record_pair (txt))
  • goto next;
    
  • fprintf(stderr, "DEBUG2: query_callback: \"%s=%s\".\n",
    
  •         key, value);
    
  • }
  • else
  • {
  • fprintf(stderr, "DEBUG2: query_callback: \"%s\" with no value.\n",
    
  •         key);
    
  • continue;
    

- }

  •    if (!_cups_strncasecmp(key, "usb_", 4))
    
  • key = txt->key;

  • value = txt->value;

  •    if (!strncasecmp(key, "usb_", 4))
    

    {
    /*

    • Add USB device ID information...
      @@ -856,6 +1263,10 @@ query_callback(
      if (device->type == CUPS_DEVICE_PRINTER)
      device->sent = 1;
      }
      +
  •  next:
    
  • if (next_txt_record (txt) == NULL)

  • break;
    

    }

    if (device->device_id)
    @@ -912,11 +1323,9 @@ query_callback(
    }
    }

  • if (!device)

  • fprintf(stderr, "DEBUG: Ignoring TXT record for "%s"...\n", fullName);

  • return device;
    }

/*

  • 'sigterm_handler()' - Handle termination signals...
    */
    diff -up cups-1.5.0/cups/http-support.c.avahi-2-backend cups-1.5.0/cups/http-support.c
    --- cups-1.5.0/cups/http-support.c.avahi-2-backend 2011-06-10 23:06:26.000000000 +0100
    +++ cups-1.5.0/cups/http-support.c 2011-08-05 15:05:13.870710117 +0100
    @@ -43,6 +43,10 @@
  • http_copy_decode() - Copy and decode a URI.
  • http_copy_encode() - Copy and encode a URI.
  • http_resolve_cb() - Build a device URI for the given service name.
  • * avahi_resolve_uri_client_cb()
  • * - Avahi client callback for resolving URI.
  • * avahi_resolve_uri_resolver_cb()
  • * - Avahi resolver callback for resolving URI.
    */

/*
@@ -60,6 +64,11 @@

include <sys/select.h>

endif /* WIN32 */

#endif /* HAVE_DNSSD /
+#ifdef HAVE_AVAHI
+# include <avahi-client/client.h>
+# include <avahi-client/lookup.h>
+# include <avahi-common/simple-watch.h>
+#endif /
HAVE_AVAHI */

/*
@@ -127,6 +136,24 @@ static void DNSSD_API http_resolve_cb(DN
void context);
#endif /
HAVE_DNSSD */

+#ifdef HAVE_AVAHI
+static void avahi_resolve_uri_client_cb(AvahiClient *client,

  •                   AvahiClientState state,
    
  •                   void *simple_poll);
    

    +static void avahi_resolve_uri_resolver_cb(AvahiServiceResolver *resolver,

  •                     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 *context);
    

    +#endif /* HAVE_AVAHI */

    /*

    • 'httpAssembleURI()' - Assemble a uniform resource identifier from its
      @@ -1431,6 +1458,9 @@ _httpResolveURI(

    if (strstr(hostname, "._tcp"))
    {
    +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)

  • char regtype, / Pointer to type in hostname */

  •       _domain;    /_ Pointer to domain in hostname _/
    

    #ifdef HAVE_DNSSD

    ifdef WIN32

    pragma comment(lib, "dnssd.lib")

    @@ -1449,6 +1479,17 @@ httpResolveURI(
    fd_set input_set; /
    Input set for select() /
    struct timeval stimeout; /
    Timeout value for select() /
    #endif /
    HAVE_POLL /
    +#else /
    HAVE_AVAHI */

  • AvahiSimplePoll *simple_poll;

  • AvahiClient *client;

  • int error;

  • struct

  • {

  •  AvahiSimplePoll  *poll;
    
  •  _http_uribuf_t   uribuf;
    
  • } user_data;
    +#endif /* HAVE_DNSSD */

if (options & _HTTP_RESOLVE_STDERR)
fprintf(stderr, "DEBUG: Resolving "%s"...\n", hostname);
@@ -1485,9 +1526,16 @@ _httpResolveURI(
if (domain)
*domain++ = '\0';

+#ifdef HAVE_DNSSD
uribuf.buffer = resolved_uri;
uribuf.bufsize = resolved_size;
uribuf.options = options;
+#else

  • user_data.uribuf.buffer = resolved_uri;
  • user_data.uribuf.bufsize = resolved_size;
  • user_data.uribuf.options = options;
    +#endif

resolved_uri[0] = '\0';

DEBUG_printf(("6_httpResolveURI: Resolving hostname="%s", regtype="%s", "
@@ -1501,6 +1549,7 @@ _httpResolveURI(

uri = NULL;

+#ifdef HAVE_DNSSD
if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError)
{
localref = ref;
@@ -1608,6 +1657,36 @@ _httpResolveURI(

   DNSServiceRefDeallocate(ref);
 }

+#else /* HAVE_AVAHI */

  • if ((simple_poll = avahi_simple_poll_new ()) != NULL)
  • {
  •  if ((client = avahi_client_new (avahi_simple_poll_get (simple_poll),
    
  •                 0, avahi_resolve_uri_client_cb,
    
  •                 &simple_poll, &error)) != NULL)
    
  •  {
    
  • user_data.poll = simple_poll;
  • if (avahi_service_resolver_new (client, AVAHI_IF_UNSPEC,
  •               AVAHI_PROTO_UNSPEC, hostname,
    
  •               regtype, domain, AVAHI_PROTO_UNSPEC, 0,
    
  •               avahi_resolve_uri_resolver_cb,
    
  •               &user_data) != NULL)
    
  • {
  • avahi_simple_poll_loop (simple_poll);
    
  • /*
  • \* Collect the result.
    
  • */
    
  • if (resolved_uri[0])
    
  •   uri = resolved_uri;
    
  • }
  • avahi_client_free (client);
  •  }
    
  •  avahi_simple_poll_free (simple_poll);
    
  • }
    +#endif /* HAVE_DNSSD */

if (options & _HTTP_RESOLVE_STDERR)
{
@@ -1619,13 +1698,13 @@ _httpResolveURI(
fputs("STATE: -connecting-to-device,offline-report\n", stderr);
}

-#else
+#else /* HAVE_DNSSD || HAVE_AVAHI /
/

* No DNS-SD support...
*/

 uri = NULL;

-#endif /* HAVE_DNSSD /
+#endif /
HAVE_DNSSD || HAVE_AVAHI */

 if ((options & _HTTP_RESOLVE_STDERR) && !uri)
   _cupsLangPrintFilter(stderr, "ERROR", _("Unable to find printer."));

@@ -1895,6 +1974,116 @@ http_resolve_cb(
#endif /* HAVE_DNSSD */

+#ifdef HAVE_AVAHI
+/*

  • * 'avahi_resolve_uri_client_cb()' - Avahi client callback for resolving URI.
  • */
    +
    +static void
    +avahi_resolve_uri_client_cb (AvahiClient *client,
  •            AvahiClientState state,
    
  •            void *simple_poll)
    
    +{
  • DEBUG_printf(("avahi_resolve_uri_client_callback(client=%p, state=%d, "
  •   "simple_poll=%p)\n", client, state, simple_poll));
    
  • /*
  • * If the connection drops, quit.
  • */
  • if (state == AVAHI_CLIENT_FAILURE)
  • avahi_simple_poll_quit (simple_poll);
    +}

+/*

  • * 'avahi_resolve_uri_resolver_cb()' - Avahi resolver callback for resolving
  • * URI.
  • */
    +
    +static void
    +avahi_resolve_uri_resolver_cb (AvahiServiceResolver *resolver,
  •              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 *context)
    
    +{
  • const char scheme; / URI scheme */
  • char rp[256]; /* Remote printer */
  • AvahiStringList *pair;
  • char *value;
  • size_t valueLen = 0;
  • char addr[AVAHI_ADDRESS_STR_MAX];
  • struct
  • {
  • AvahiSimplePoll *poll;
  • _http_uribuf_t uribuf;
  • } *poll_uribuf = context;
  • DEBUG_printf(("avahi_resolve_uri_resolver_callback(resolver=%p, "
  •   "interface=%d, protocol=%d, event=%d, name=\"%s\", "
    
  •   "type=\"%s\", domain=\"%s\", host_name=\"%s\", address=%p, "
    
  •   "port=%d, txt=%p, flags=%d, context=%p)\n",
    
  •   resolver, interface, protocol, event, name, type, domain,
    
  •   host_name, address, port, txt, flags, context));
    
  • if (event != AVAHI_RESOLVER_FOUND)
  • {
  • avahi_service_resolver_free (resolver);
  • avahi_simple_poll_quit (poll_uribuf->poll);
  • return;
  • }
  • /*
  • * Figure out the scheme from the full name...
  • */
  • if (strstr(type, "_ipp."))
  • scheme = "ipp";
  • else if (strstr(type, "_printer."))
  • scheme = "lpd";
  • else if (strstr(type, "_pdl-datastream."))
  • scheme = "socket";
  • else
  • scheme = "riousbprint";
  • /*
  • * Extract the "remote printer key from the TXT record...
  • */
  • if ((pair = avahi_string_list_find (txt, "rp")) != NULL)
  • {
  • avahi_string_list_get_pair (pair, NULL, &value, &valueLen);
  • rp[0] = '/';
  • memcpy (rp + 1, value, valueLen);
  • rp[valueLen + 1] = '\0';
  • }
  • else
  • rp[0] = '\0';
  • /*
  • * Assemble the final device URI...
  • */
  • avahi_address_snprint (addr, AVAHI_ADDRESS_STR_MAX, address);
  • httpAssembleURI(HTTP_URI_CODING_ALL, poll_uribuf->uribuf.buffer,
  •     poll_uribuf->uribuf.bufsize, scheme, NULL,
    
  •     addr, port, rp);
    
  • DEBUG_printf(("avahi_resolve_uri_resolver_callback: Resolved URI is "%s"\n",
  •   poll_uribuf->uribuf.buffer));
    
  • avahi_simple_poll_quit (poll_uribuf->poll);
    +}
    +#endif /* HAVE_AVAHI _/

/_

  • End of "$Id: http-support.c 9820 2011-06-10 22:06:26Z mike $".
    */
@michaelrsweet
Collaborator

"cups-avahi-3-timeouts.patch":

diff -up cups-1.5.0/scheduler/cupsd.h.avahi-3-timeouts cups-1.5.0/scheduler/cupsd.h
--- cups-1.5.0/scheduler/cupsd.h.avahi-3-timeouts 2011-05-11 23:17:34.000000000 +0100
+++ cups-1.5.0/scheduler/cupsd.h 2011-10-07 13:20:41.522867324 +0100
@@ -140,6 +140,15 @@ extern const char *cups_hstrerror(int);

typedef void (*cupsd_selfunc_t)(void *data);

+#ifdef HAVE_AVAHI
+/*

  • * Timeout callback function type...

  • _/
    +
    +typedef struct _cupsd_timeout_s cupsd_timeout_t;
    +typedef void (_cupsd_timeoutfunc_t)(cupsd_timeout_t timeout, void *data);
    +#endif /
    HAVE_AVAHI */
    +

    /*

    • Globals...
      @@ -173,6 +182,11 @@ VAR int Launchd VALUE(0);
      /* Running from launchd /
      #endif /
      HAVE_LAUNCH_H */

+#ifdef HAVE_AVAHI
+VAR cups_array_t Timeouts; / Timed callbacks for main loop /
+#endif /
HAVE_AVAHI */
+
+

/*

  • Prototypes...
    @@ -242,6 +256,20 @@ extern void cupsdStopSelect(void);
    extern void cupsdStartServer(void);
    extern void cupsdStopServer(void);

+#ifdef HAVE_AVAHI
+extern void cupsdInitTimeouts(void);
+extern cupsd_timeout_t *cupsdAddTimeout (const struct timeval *tv,

  •                cupsd_timeoutfunc_t cb,
    
  •                void *data);
    

    +extern cupsd_timeout_t *cupsdNextTimeout (long *delay);
    +extern void cupsdRunTimeout (cupsd_timeout_t *timeout);
    +extern void cupsdUpdateTimeout (cupsd_timeout_t *timeout,

  •               const struct timeval *tv);
    

    +extern void cupsdRemoveTimeout (cupsd_timeout_t timeout);
    +#endif /
    HAVE_AVAHI */
    +
    +extern int cupsdRemoveFile(const char *filename);
    +

    /*

    • End of "$Id: cupsd.h 9766 2011-05-11 22:17:34Z mike $".
      diff -up cups-1.5.0/scheduler/main.c.avahi-3-timeouts cups-1.5.0/scheduler/main.c
      --- cups-1.5.0/scheduler/main.c.avahi-3-timeouts 2011-10-07 13:20:36.875954675 +0100
      +++ cups-1.5.0/scheduler/main.c 2011-10-07 13:20:41.524867282 +0100
      @@ -146,6 +146,10 @@ main(int argc, /* I - Number of comm
      int launchd_idle_exit;
      /* Idle exit on select timeout? /
      #endif /
      HAVE_LAUNCHD */
      +#ifdef HAVE_AVAHI
  • cupsd_timeout_t tmo; / Next scheduled timed callback */

  • long tmo_delay; /* Time before it must be called /
    +#endif /
    HAVE_AVAHI */

#ifdef HAVE_GETEUID
@@ -535,6 +539,14 @@ main(int argc, /* I - Number of comm

httpInitialize();

+#ifdef HAVE_AVAHI

  • /*
  • * Initialize timed callback structures.
  • */
  • cupsdInitTimeouts();
    +#endif /* HAVE_AVAHI */

cupsdStartServer();

/*
@@ -874,6 +886,16 @@ main(int argc, /* I - Number of comm
}
#endif /* APPLE */

+#ifdef HAVE_AVAHI

  • /*
  • * If a timed callback is due, run it.
  • */
  • tmo = cupsdNextTimeout (&tmo_delay);
  • if (tmo && tmo_delay == 0)
  •  cupsdRunTimeout (tmo);
    
    +#endif /* HAVE_AVAHI /
    +
    #ifndef APPLE
    /
    • Update the network interfaces once a minute...
      @@ -1787,6 +1809,10 @@ select_timeout(int fds) /* I - Number
      cupsd_job_t job; / Job information /
      cupsd_subscription_t *sub; /
      Subscription information /
      const char *why; /
      Debugging aid */
      +#ifdef HAVE_AVAHI
  • cupsd_timeout_t tmo; / Timed callback */
  • long tmo_delay; /* Seconds before calling it /
    +#endif /
    HAVE_AVAHI */

/*
@@ -1829,6 +1855,19 @@ select_timeout(int fds) /* I - Number
}
#endif /* APPLE */

+#ifdef HAVE_AVAHI

  • /*
  • * See if there are any scheduled timed callbacks to run.
  • */
  • tmo = cupsdNextTimeout (&tmo_delay);
  • if (tmo)
  • {
  • timeout = tmo_delay;
  • why = "run a timed callback";
  • }
    +#endif /* HAVE_AVAHI _/

/_

  • Check whether we are accepting new connections...
    */
    diff -up cups-1.5.0/scheduler/Makefile.avahi-3-timeouts cups-1.5.0/scheduler/Makefile
    --- cups-1.5.0/scheduler/Makefile.avahi-3-timeouts 2011-10-07 13:20:36.955953170 +0100
    +++ cups-1.5.0/scheduler/Makefile 2011-10-07 13:20:41.521867343 +0100
    @@ -39,7 +39,8 @@ CUPSDOBJS =
    server.o
    statbuf.o
    subscriptions.o \
  •   sysman.o
    
  •   sysman.o \
    
  •   timeout.o
    
    LIBOBJS =
    filter.o
    mime.o
    diff -up cups-1.5.0/scheduler/timeout.c.avahi-3-timeouts cups-1.5.0/scheduler/timeout.c
    --- cups-1.5.0/scheduler/timeout.c.avahi-3-timeouts 2011-10-07 13:20:41.525867259 +0100
    +++ cups-1.5.0/scheduler/timeout.c 2011-10-07 13:20:41.525867259 +0100
    @@ -0,0 +1,235 @@
    +/*
  • * "$Id$"
  • * Timeout functions for the Common UNIX Printing System (CUPS).
  • * Copyright (C) 2010, 2011 Red Hat, Inc.
  • * Authors:
  • * Tim Waugh twaugh@redhat.com
  • * Redistribution and use in source and binary forms, with or without
  • * modification, are permitted provided that the following conditions
  • * are met:
  • * Redistributions of source code must retain the above copyright
  • * notice, this list of conditions and the following disclaimer.
  • * Redistributions in binary form must reproduce the above copyright
  • * notice, this list of conditions and the following disclaimer in the
  • * documentation and/or other materials provided with the distribution.
  • * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  • * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  • * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  • * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  • * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  • * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  • * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  • * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  • * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  • * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  • * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  • * OF THE POSSIBILITY OF SUCH DAMAGE.
  • * Contents:
  • * cupsdInitTimeouts() - Initialise timeout structure.
  • * cupsdAddTimeout() - Add a timed callback.
  • * cupsdNextTimeout() - Find the next enabled timed callback.
  • * cupsdUpdateTimeout() - Adjust the time of a timed callback or disable it.
  • * cupsdRemoveTimeout() - Discard a timed callback.
  • * compare_timeouts() - Compare timed callbacks for array sorting.
  • /
    +
    +#include <config.h>
    +
    +#ifdef HAVE_AVAHI /
    Applies to entire file... /
    +
    +/
  • * Include necessary headers...
  • /
    +
    +#include "cupsd.h"
    +
    +#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
    +# include <malloc.h>
    +#endif /
    HAVE_MALLOC_H && HAVE_MALLINFO /
    +
    +#ifdef HAVE_AVAHI
    +# include <avahi-common/timeval.h>
    +#endif /
    HAVE_AVAHI */
    +
    +
    +struct _cupsd_timeout_s
    +{
  • struct timeval when;
  • int enabled;
  • cupsd_timeoutfunc_t callback;
  • void _data;
    +};

+/_

  • * Local functions...
  • /
    +
    +/
  • * 'compare_timeouts()' - Compare timed callbacks for array sorting.
  • */
    +
    +static int
    +compare_addrs (void *p0, void *p1)
    +{
  • if (p0 == p1)
  • return (0);
  • if (p0 < p1)
  • return (-1);
  • return (1);
    +}

+static int
+compare_timeouts (cupsd_timeout_t *p0, cupsd_timeout_t *p1)
+{

  • int addrsdiff = compare_addrs (p0, p1);
  • int tvdiff;
  • if (addrsdiff == 0)
  • return (0);
  • if (!p0->enabled || !p1->enabled)
  • {
  • if (!p0->enabled && !p1->enabled)
  •  return (addrsdiff);
    
  • return (p0->enabled ? -1 : 1);
  • }
  • tvdiff = avahi_timeval_compare (&p0->when, &p1->when);
  • if (tvdiff != 0)
  • return (tvdiff);
  • return (addrsdiff);
    +}

+/*

  • * 'cupsdInitTimeouts()' - Initialise timeout structures.
  • */
    +
    +void
    +cupsdInitTimeouts(void)
    +{
  • Timeouts = cupsArrayNew ((cups_array_func_t)compare_timeouts, NULL);
    +}

+/*

  • * 'cupsdAddTimeout()' - Add a timed callback.
  • /
    +
    +cupsd_timeout_t * /
    O - Timeout handle /
    +cupsdAddTimeout(const struct timeval *tv, /
    I - Absolute time */
  •   cupsd_timeoutfunc_t cb,     /\* I - Callback function */
    
  •   void _data)         /_ I - User data */
    
    +{
  • cupsd_timeout_t *timeout;
  • timeout = malloc (sizeof(cupsd_timeout_t));
  • if (timeout != NULL)
  • {
  • timeout->enabled = (tv != NULL);
  • if (tv)
  • {
  •  timeout->when.tv_sec = tv->tv_sec;
    
  •  timeout->when.tv_usec = tv->tv_usec;
    
  • }
  • timeout->callback = cb;
  • timeout->data = data;
  • cupsArrayAdd (Timeouts, timeout);
  • }
  • return timeout;
    +}

+/*

  • * 'cupsdNextTimeout()' - Find the next enabled timed callback.
  • /
    +
    +cupsd_timeout_t * /
    O - Next enabled timeout or NULL /
    +cupsdNextTimeout(long *delay) /
    O - Seconds before scheduled */
    +{
  • cupsd_timeout_t *first = cupsArrayFirst (Timeouts);
  • struct timeval curtime;
  • if (first && !first->enabled)
  • first = NULL;
  • if (first && delay)
  • {
  • gettimeofday (&curtime, NULL);
  • if (avahi_timeval_compare (&curtime, &first->when) > 0)
  • {
  •  *delay = 0;
    
  • } else {
  •  *delay = 1 + first->when.tv_sec - curtime.tv_sec;
    
  •  if (first->when.tv_usec < curtime.tv_usec)
    
  • (*delay)--;
  • }
  • }
  • return (first);
    +}

+/*

  • * 'cupsdRunTimeout()' - Run a timed callback.
  • /
    +
    +void
    +cupsdRunTimeout(cupsd_timeout_t *timeout) /
    I - Timeout */
    +{
  • if (!timeout)
  • return;
  • timeout->enabled = 0;
  • if (!timeout->callback)
  • return;
  • timeout->callback (timeout, timeout->data);
    +}

+/*

  • * 'cupsdUpdateTimeout()' - Adjust the time of a timed callback or disable it.
  • /
    +
    +void
    +cupsdUpdateTimeout(cupsd_timeout_t *timeout, /
    I - Timeout */
  •      const struct timeval _tv)    /_ I - Absolute time or NULL */
    
    +{
  • cupsArrayRemove (Timeouts, timeout);
  • timeout->enabled = (tv != NULL);
  • if (tv)
  • {
  • timeout->when.tv_sec = tv->tv_sec;
  • timeout->when.tv_usec = tv->tv_usec;
  • }
  • cupsArrayAdd (Timeouts, timeout);
    +}

+/*

  • * 'cupsdRemoveTimeout()' - Discard a timed callback.
  • /
    +
    +void
    +cupsdRemoveTimeout(cupsd_timeout_t *timeout) /
    I - Timeout */
    +{
  • cupsArrayRemove (Timeouts, timeout);
  • free (timeout);
    +}

+#endif /* HAVE_AVAHI ... from top of file /
+
+/

  • * End of "$Id$".
  • */
@michaelrsweet
Collaborator

"cups-avahi-4-poll.patch":

diff -up cups-1.5.0/scheduler/avahi.c.avahi-4-poll cups-1.5.0/scheduler/avahi.c
--- cups-1.5.0/scheduler/avahi.c.avahi-4-poll 2011-10-11 10:56:50.102288037 +0100
+++ cups-1.5.0/scheduler/avahi.c 2011-10-11 10:56:50.102288037 +0100
@@ -0,0 +1,441 @@
+/*

  • * "$Id$"
  • * Avahi poll implementation for the CUPS scheduler.
  • * Copyright (C) 2010, 2011 Red Hat, Inc.
  • * Authors:
  • * Tim Waugh twaugh@redhat.com
  • * Redistribution and use in source and binary forms, with or without
  • * modification, are permitted provided that the following conditions
  • * are met:
  • * Redistributions of source code must retain the above copyright
  • * notice, this list of conditions and the following disclaimer.
  • * Redistributions in binary form must reproduce the above copyright
  • * notice, this list of conditions and the following disclaimer in the
  • * documentation and/or other materials provided with the distribution.
  • * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  • * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  • * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  • * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  • * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  • * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  • * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  • * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  • * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  • * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  • * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  • * OF THE POSSIBILITY OF SUCH DAMAGE.
  • * Contents:
  • * watch_read_cb - Read callback for file descriptor
  • * watch_write_cb - Write callback for file descriptor
  • * watched_fd_add_select() - Call cupsdAddSelect() as needed
  • * watch_new() - Create a new file descriptor watch
  • * watch_free() - Free a file descriptor watch
  • * watch_update() - Update watched events for a file descriptor
  • * watch_get_events() - Get events that happened for a file descriptor
  • * timeout_cb() - Run a timed Avahi callback
  • * timeout_new() - Set a wakeup time
  • * timeout_update() - Update the expiration time for a timeout
  • * timeout_free() - Free a timeout
  • * compare_watched_fds() - Compare watched file descriptors for array sorting
  • * avahi_cups_poll_new() - Create a new Avahi main loop object for CUPS
  • * avahi_cups_poll_free() - Free an Avahi main loop object for CUPS
  • * avahi_cups_poll_get() - Get the abstract poll API structure
  • /
    +
    +#include <config.h>
    +
    +#ifdef HAVE_AVAHI /
    Applies to entire file... /
    +
    +/
  • * Include necessary headers...
  • /
    +
    +#include "cupsd.h"
    +
    +#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
    +# include <malloc.h>
    +#endif /
    HAVE_MALLOC_H && HAVE_MALLINFO /
    +
    +#ifdef HAVE_AVAHI
    +# include <avahi-common/timeval.h>
    +#endif /
    HAVE_AVAHI */
    +
    +
    +typedef struct
    +{
  • AvahiCupsPoll *cups_poll;
  • int fd;
  • AvahiWatchEvent occurred;
  • cups_array_t *watches;
    +} cupsd_watched_fd_t;

+struct AvahiWatch
+{

  • cupsd_watched_fd_t *watched_fd;
  • AvahiWatchEvent events;
  • AvahiWatchCallback callback;
  • void *userdata;
    +};

+struct AvahiTimeout
+{

  • AvahiCupsPoll *cups_poll;
  • AvahiTimeoutCallback callback;
  • void *userdata;
  • cupsd_timeout_t _cupsd_timeout;
    +};

+/_

  • * Local functions...
  • */
    +
    +static AvahiWatch * watch_new(const AvahiPoll *api,
  •             int fd,
    
  •             AvahiWatchEvent events,
    
  •             AvahiWatchCallback callback,
    
  •             void *userdata);
    
    +static void watch_free(AvahiWatch *watch);
    +static void watch_update(AvahiWatch *watch,
  •                AvahiWatchEvent events);
    
    +static AvahiWatchEvent watch_get_events(AvahiWatch watch);
    +
    +
    +/
  • * 'watch_read_cb' - Read callback for file descriptor
  • */
    +
    +static void
    +watch_read_cb (void *userdata)
    +{
  • AvahiWatch *watch;
  • cupsd_watched_fd_t *watched_fd = userdata;
  • watched_fd->occurred |= AVAHI_WATCH_IN;
  • for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
  •   watch;
    
  •   watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches))
    
  • {
  • if (watch->events & watched_fd->occurred)
  • {
  •  (watch->callback) (watch, watched_fd->fd,
    
  •        AVAHI_WATCH_IN, watch->userdata);
    
  •  watched_fd->occurred &= ~AVAHI_WATCH_IN;
    
  •  break;
    
  • }
  • }
    +}

+/*

  • * 'watch_write_cb' - Write callback for file descriptor
  • */
    +
    +static void
    +watch_write_cb (void *userdata)
    +{
  • AvahiWatch *watch;
  • cupsd_watched_fd_t *watched_fd = userdata;
  • watched_fd->occurred |= AVAHI_WATCH_OUT;
  • for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
  •   watch;
    
  •   watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches))
    
  • {
  • if (watch->events & watched_fd->occurred)
  • {
  •  (watch->callback) (watch, watched_fd->fd,
    
  •        AVAHI_WATCH_OUT, watch->userdata);
    
  •  watched_fd->occurred &= ~AVAHI_WATCH_OUT;
    
  •  break;
    
  • }
  • }
    +}

+/*

  • * 'watched_fd_add_select' - Call cupsdAddSelect() as needed
  • /
    +
    +static int /
    O - Watches? */
    +watched_fd_add_select (cupsd_watched_fd_t *watched_fd)
    +{
  • AvahiWatch *watch;
  • cupsd_selfunc_t read_cb = NULL, write_cb = NULL;
  • int any_watches = 0;
  • for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
  •   watch;
    
  •   watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches))
    
  • {
  • any_watches = 1;
  • if (watch->events & (AVAHI_WATCH_IN |
  •            AVAHI_WATCH_ERR |
    
  •            AVAHI_WATCH_HUP))
    
  • {
  •  read_cb = (cupsd_selfunc_t)watch_read_cb;
    
  •  if (write_cb != NULL)
    
  • break;
  • }
  • if (watch->events & AVAHI_WATCH_OUT)
  • {
  •  write_cb = (cupsd_selfunc_t)watch_write_cb;
    
  •  if (read_cb != NULL)
    
  • break;
  • }
  • }
  • if (read_cb || write_cb)
  • cupsdAddSelect (watched_fd->fd, read_cb, write_cb, watched_fd);
  • else
  • cupsdRemoveSelect (watched_fd->fd);
  • return (any_watches);
    +}

+/*

  • * 'watch_new' - Create a new file descriptor watch
  • */
    +
    +static AvahiWatch *
    +watch_new (const AvahiPoll *api,
  •  int fd,
    
  •  AvahiWatchEvent events,
    
  •  AvahiWatchCallback callback,
    
  •  void *userdata)
    
    +{
  • cupsd_watched_fd_t key, *watched_fd;
  • AvahiCupsPoll *cups_poll = api->userdata;
  • AvahiWatch *watch = malloc(sizeof(AvahiWatch));
  • if (watch == NULL)
  • return (NULL);
  • watch->events = events;
  • watch->callback = callback;
  • watch->userdata = userdata;
  • key.fd = fd;
  • watched_fd = cupsArrayFind (cups_poll->watched_fds, &key);
  • if (watched_fd == NULL)
  • {
  • watched_fd = malloc(sizeof(cupsd_watched_fd_t));
  • if (watched_fd == NULL)
  • {
  •  free (watch);
    
  •  return (NULL);
    
  • }
  • watched_fd->fd = fd;
  • watched_fd->occurred = 0;
  • watched_fd->cups_poll = cups_poll;
  • watched_fd->watches = cupsArrayNew (NULL, NULL);
  • cupsArrayAdd (cups_poll->watched_fds, watched_fd);
  • }
  • watch->watched_fd = watched_fd;
  • cupsArrayAdd(watched_fd->watches, watch);
  • watched_fd_add_select (watched_fd);
  • return (watch);
    +}

+/*

  • * 'watch_free' - Free a file descriptor watch
  • */
    +
    +static void
    +watch_free (AvahiWatch *watch)
    +{
  • cupsd_watched_fd_t *watched_fd = watch->watched_fd;
  • AvahiCupsPoll *cups_poll = watched_fd->cups_poll;
  • cupsArrayRemove (watched_fd->watches, watch);
  • free (watch);
  • if (!watched_fd_add_select (watched_fd))
  • {
  • /* No more watches */
  • cupsArrayRemove (cups_poll->watched_fds, watched_fd);
  • free (watched_fd);
  • }
    +}

+/*

  • * 'watch_update' - Update watched events for a file descriptor
  • */
    +
    +static void
    +watch_update (AvahiWatch *watch,
  •     AvahiWatchEvent events)
    
    +{
  • watch->events = events;
  • watched_fd_add_select (watch->watched_fd);
    +}

+/*

  • * 'watch_get_events' - Get events that happened for a file descriptor
  • */
    +
    +static AvahiWatchEvent
    +watch_get_events (AvahiWatch *watch)
    +{
  • return (watch->watched_fd->occurred);
    +}

+/*

  • * 'timeout_cb()' - Run a timed Avahi callback
  • */
    +
    +static void
    +timeout_cb (cupsd_timeout_t *cupsd_timeout, void *userdata)
    +{
  • AvahiTimeout *timeout = userdata;
  • (timeout->callback) (timeout, timeout->userdata);
    +}

+/*

  • * 'timeout_new' - Set a wakeup time
  • */
    +
    +static AvahiTimeout *
    +timeout_new (const AvahiPoll *api,
  •    const struct timeval *tv,
    
  •    AvahiTimeoutCallback callback,
    
  •    void *userdata)
    
    +{
  • AvahiTimeout *timeout;
  • AvahiCupsPoll *cups_poll = api->userdata;
  • timeout = malloc(sizeof(AvahiTimeout));
  • if (timeout == NULL)
  • return (NULL);
  • timeout->cups_poll = cups_poll;
  • timeout->callback = callback;
  • timeout->userdata = userdata;
  • timeout->cupsd_timeout = cupsdAddTimeout (tv,
  •                   (cupsd_timeoutfunc_t)timeout_cb,
    
  •                   timeout);
    
  • cupsArrayAdd (cups_poll->timeouts, timeout);
  • return (timeout);
    +}

+/*

  • * 'timeout_update' - Update the expiration time for a timeout
  • */
    +
    +static void
    +timeout_update (AvahiTimeout *timeout,
  •   const struct timeval *tv)
    
    +{
  • cupsdUpdateTimeout (timeout->cupsd_timeout, tv);
    +}

+/*

  • * ' timeout_free' - Free a timeout
  • */
    +
    +static void
    +timeout_free (AvahiTimeout *timeout)
    +{
  • cupsArrayRemove (timeout->cups_poll->timeouts, timeout);
  • cupsdRemoveTimeout (timeout->cupsd_timeout);
  • free (timeout);
    +}

+/*

  • * 'compare_watched_fds' - Compare watched file descriptors for array sorting
  • */
    +static int
    +compare_watched_fds(cupsd_watched_fd_t *p0,
  •       cupsd_watched_fd_t *p1)
    
    +{
  • /*
  • * Compare by fd (no two elements have the same fd)
  • */
  • if (p0->fd == p1->fd)
  • return 0;
  • return (p0->fd < p1->fd ? -1 : 1);
    +}

+/*

  • * 'avahi_cups_poll_new' - Create a new Avahi main loop object for CUPS
  • */
    +
    +AvahiCupsPoll *
    +avahi_cups_poll_new (void)
    +{
  • AvahiCupsPoll *cups_poll = malloc(sizeof(AvahiCupsPoll));
  • if (cups_poll == NULL)
  • return (NULL);
  • cups_poll->watched_fds = cupsArrayNew ((cups_array_func_t)compare_watched_fds,
  •                NULL);
    
  • cups_poll->timeouts = cupsArrayNew (NULL, NULL);
  • cups_poll->api.userdata = cups_poll;
  • cups_poll->api.watch_new = watch_new;
  • cups_poll->api.watch_free = watch_free;
  • cups_poll->api.watch_update = watch_update;
  • cups_poll->api.watch_get_events = watch_get_events;
  • cups_poll->api.timeout_new = timeout_new;
  • cups_poll->api.timeout_update = timeout_update;
  • cups_poll->api.timeout_free = timeout_free;
  • return (cups_poll);
    +}

+/*

  • * 'avahi_cups_poll_free' - Free an Avahi main loop object for CUPS
  • */
    +void
    +avahi_cups_poll_free (AvahiCupsPoll *cups_poll)
    +{
  • cupsd_watched_fd_t *watched_fd;
  • for (watched_fd = (cupsd_watched_fd_t*)cupsArrayFirst(cups_poll->watched_fds);
  •   watched_fd;
    
  •   watched_fd = (cupsd_watched_fd_t*)cupsArrayNext(cups_poll->watched_fds))
    
  • cupsArrayClear (watched_fd->watches);
  • cupsArrayClear (cups_poll->watched_fds);
  • cupsArrayClear (cups_poll->timeouts);
    +}

+/*

  • * 'avahi_cups_poll_get' - Get the abstract poll API structure
  • */
    +
    +const AvahiPoll *
    +avahi_cups_poll_get (AvahiCupsPoll *cups_poll)
    +{
  • return (&cups_poll->api);
    +}

+#endif /* HAVE_AVAHI ... from top of file /
+
+/

  • * End of "$Id$".
  • /
    diff -up cups-1.5.0/scheduler/avahi.h.avahi-4-poll cups-1.5.0/scheduler/avahi.h
    --- cups-1.5.0/scheduler/avahi.h.avahi-4-poll 2011-10-11 10:56:50.102288037 +0100
    +++ cups-1.5.0/scheduler/avahi.h 2011-10-11 10:56:50.119287724 +0100
    @@ -0,0 +1,69 @@
    +/
  • * "$Id$"
  • * Avahi poll implementation for the CUPS scheduler.
  • * Copyright (C) 2010, 2011 Red Hat, Inc.
  • * Authors:
  • * Tim Waugh twaugh@redhat.com
  • * Redistribution and use in source and binary forms, with or without
  • * modification, are permitted provided that the following conditions
  • * are met:
  • * Redistributions of source code must retain the above copyright
  • * notice, this list of conditions and the following disclaimer.
  • * Redistributions in binary form must reproduce the above copyright
  • * notice, this list of conditions and the following disclaimer in the
  • * documentation and/or other materials provided with the distribution.
  • * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  • * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  • * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  • * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  • * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  • * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  • * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  • * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  • * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  • * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  • * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  • * OF THE POSSIBILITY OF SUCH DAMAGE.
  • /
    +
    +#include <config.h>
    +
    +#ifdef HAVE_AVAHI
    +# include <avahi-client/client.h>
    +# include <avahi-client/publish.h>
    +#endif /
    HAVE_AVAHI /
    +
    +#ifdef HAVE_AUTHORIZATION_H
    +# include <Security/Authorization.h>
    +#endif /
    HAVE_AUTHORIZATION_H */
    +
    +
    +#ifdef HAVE_AVAHI
    +typedef struct
    +{
  • AvahiPoll api;
  • cups_array_t *watched_fds;
  • cups_array_t timeouts;
    +} AvahiCupsPoll;
    +#endif /
    HAVE_AVAHI _/

+/_

  • * Prototypes...

  • /
    +
    +#ifdef HAVE_AVAHI
    +extern AvahiCupsPoll * avahi_cups_poll_new(void);
    +extern void avahi_cups_poll_free(AvahiCupsPoll *cups_poll);
    +extern const AvahiPoll *avahi_cups_poll_get(AvahiCupsPoll *cups_poll);
    +#endif /
    HAVE_AVAHI /
    +
    +
    +/

  • * End of "$Id$".

  • */
    diff -up cups-1.5.0/scheduler/Makefile.avahi-4-poll cups-1.5.0/scheduler/Makefile
    --- cups-1.5.0/scheduler/Makefile.avahi-4-poll 2011-10-11 10:56:45.868365861 +0100
    +++ cups-1.5.0/scheduler/Makefile 2011-10-11 10:56:50.101288055 +0100
    @@ -17,6 +17,7 @@ include ../Makedefs

    CUPSDOBJS =
    auth.o \

  •   avahi.o \
    banners.o \
    cert.o \
    classes.o \
    
@michaelrsweet
Collaborator

"cups-avahi-5-services.patch":

diff -up cups-1.5.0/cgi-bin/admin.c.avahi-5-services cups-1.5.0/cgi-bin/admin.c
--- cups-1.5.0/cgi-bin/admin.c.avahi-5-services 2011-05-20 04:49:49.000000000 +0100
+++ cups-1.5.0/cgi-bin/admin.c 2011-10-19 11:53:32.123177998 +0100
@@ -1643,7 +1643,7 @@ do_config_server(http_t http) / I - H
else
local_protocols[0] = '\0';

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
if (cgiGetVariable("BROWSE_LOCAL_DNSSD"))
{
if (local_protocols[0])
@@ -1651,7 +1651,7 @@ do_config_server(http_t http) / I - H
else
strcat(local_protocols, "dnssd");
}
-#endif /* HAVE_DNSSD /
+#endif /
defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

#ifdef HAVE_LDAP
if (cgiGetVariable("BROWSE_LOCAL_LDAP"))
@@ -2718,9 +2718,9 @@ do_menu(http_t http) / I - HTTP conn
#endif /* HAVE_GSSAPI */
cgiSetVariable("KERBEROS", "");

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
cgiSetVariable("HAVE_DNSSD", "1");
-#endif /* HAVE_DNSSD /
+#endif /
defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

#ifdef HAVE_LDAP
cgiSetVariable("HAVE_LDAP", "1");
diff -up cups-1.5.0/scheduler/client.c.avahi-5-services cups-1.5.0/scheduler/client.c
--- cups-1.5.0/scheduler/client.c.avahi-5-services 2011-06-10 22:16:18.000000000 +0100
+++ cups-1.5.0/scheduler/client.c 2011-10-19 11:53:32.127177926 +0100
@@ -4987,7 +4987,7 @@ valid_host(cupsd_client_t con) / I -
!strncmp(host, "[::1]:", 6));
}

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
/*

  • Check if the hostname is something.local (Bonjour); if so, allow it.
    /
    @@ -4996,7 +4996,7 @@ valid_host(cupsd_client_t *con) /
    I -
    (!_cups_strcasecmp(end, ".local") || !_cups_strncasecmp(end, ".local:", 7) ||
    !_cups_strcasecmp(end, ".local.") || !_cups_strncasecmp(end, ".local.:", 8)))
    return (1);
    -#endif /* HAVE_DNSSD /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

    /*

  • Check if the hostname is an IP address...
    diff -up cups-1.5.0/scheduler/conf.c.avahi-5-services cups-1.5.0/scheduler/conf.c
    --- cups-1.5.0/scheduler/conf.c.avahi-5-services 2011-10-19 11:53:31.895182225 +0100
    +++ cups-1.5.0/scheduler/conf.c 2011-10-19 11:53:32.131177850 +0100
    @@ -651,7 +651,7 @@ cupsdReadConfiguration(void)
    Browsing = CUPS_DEFAULT_BROWSING;
    DefaultShared = CUPS_DEFAULT_DEFAULT_SHARED;

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
cupsdSetString(&DNSSDRegType, "_ipp._tcp,_cups");
#endif /* HAVE_DNSSD */

diff -up cups-1.5.0/scheduler/dirsvc.c.avahi-5-services cups-1.5.0/scheduler/dirsvc.c
--- cups-1.5.0/scheduler/dirsvc.c.avahi-5-services 2011-10-19 11:53:32.011180075 +0100
+++ cups-1.5.0/scheduler/dirsvc.c 2011-10-19 11:53:58.916681461 +0100
@@ -27,6 +27,7 @@

  • ldap_connect() - Start new LDAP connection

  • ldap_reconnect() - Reconnect to LDAP Server

  • ldap_disconnect() - Disconnect from LDAP Server

  • * cupsdStartAvahiClient() - Start an Avahi client if needed

  • cupsdStartBrowsing() - Start sending and receiving broadcast

  •                            information.
    
  • cupsdStartPolling() - Start polling servers as needed.
    @@ -40,11 +41,12 @@

  • dequote() - Remote quotes from a string.

  • dnssdAddAlias() - Add a DNS-SD alias name.

  • dnssdBuildTxtRecord() - Build a TXT record from printer info.

  • * dnssdComparePrinters() - Compare the registered names of two printers.

  • dnssdDeregisterPrinter() - Stop sending broadcast information for a

  •                            printer.
    
  • dnssdPackTxtRecord() - Pack an array of key/value pairs into the TXT

  •                            record format.
    
    • * avahiPackTxtRecord() - Pack an array of key/value pairs into an
    • * AvahiStringList.
  • dnssdRegisterCallback() - DNSServiceRegister callback.

  • dnssdRegisterPrinter() - Start sending broadcast information for a

  •                            printer or update the broadcast contents.
    

    @@ -83,6 +85,7 @@
    */

    #include "cupsd.h"
    +#include <assert.h>
    #include <grp.h>

    #ifdef HAVE_DNSSD
    @@ -97,6 +100,17 @@

    endif /* HAVE_SYSTEMCONFIGURATION */

    endif /* APPLE */

    #endif /* HAVE_DNSSD /
    +#ifdef HAVE_AVAHI
    +# include <avahi-common/domain.h>
    +#endif /
    HAVE_AVAHI /
    +
    +
    +#ifdef HAVE_DNSSD
    +typedef char *cupsd_txt_record_t;
    +#endif /
    HAVE_DNSSD /
    +#ifdef HAVE_AVAHI
    +typedef AvahiStringList *cupsd_txt_record_t;
    +#endif /
    HAVE_AVAHI */

    /*
    @@ -159,27 +173,38 @@ static void update_polling(void);
    static void update_smb(int onoff);

+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+static cupsd_txt_record_t dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p,

  •                     int for_lpd);
    
    +static void dnssdDeregisterPrinter(cupsd_printer_t p);
    +static void dnssdRegisterPrinter(cupsd_printer_t *p);
    +static void dnssdStop(void);
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) _/
    +
    #ifdef HAVE_DNSSD

    ifdef HAVE_COREFOUNDATION

    static void dnssdAddAlias(const void *key, const void *value,
    void *context);

    endif /_ HAVE_COREFOUNDATION */

    -static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p,
  •                        int for_lpd);
    
    -static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b);
    -static void dnssdDeregisterPrinter(cupsd_printer_t *p);
    -static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2],
  •                       int count);
    
    static void dnssdRegisterCallback(DNSServiceRef sdRef,
    DNSServiceFlags flags,
    DNSServiceErrorType errorCode,
    const char name, const char *regtype,
    const char *domain, void *context);
    -static void dnssdRegisterPrinter(cupsd_printer_t *p);
    -static void dnssdStop(void);
    static void dnssdUpdate(void);
    #endif /
    HAVE_DNSSD */

+#ifdef HAVE_AVAHI
+static AvahiStringList *avahiPackTxtRecord(char *keyvalue[][2],

  •                  int count);
    
    +static void avahi_entry_group_cb (AvahiEntryGroup *group,
  •                 AvahiEntryGroupState state,
    
  •                 void *userdata);
    
    +static void avahi_client_cb (AvahiClient *client,
  •            AvahiClientState state,
    
  •            void _userdata);
    
    +#endif /_ HAVE_AVAHI /
    +
    #ifdef HAVE_LDAP
    static const char * const ldap_attrs[] =/
    CUPS LDAP attributes /
    {
    @@ -283,10 +308,10 @@ cupsdDeregisterPrinter(
    ldap_dereg_printer(p);
    #endif /
    HAVE_LDAP */

-#ifdef HAVE_DNSSD

  • if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
    +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
  • if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD))
    dnssdDeregisterPrinter(p);
    -#endif /* HAVE_DNSSD /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
    }

@@ -702,10 +727,10 @@ cupsdRegisterPrinter(cupsd_printer_t p)
slpRegisterPrinter(p); */
#endif /
HAVE_LIBSLP */

-#ifdef HAVE_DNSSD

  • if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
    +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
  • if ((BrowseLocalProtocols & BROWSE_DNSSD))
    dnssdRegisterPrinter(p);
    -#endif /* HAVE_DNSSD /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
    }

@@ -1419,6 +1444,36 @@ ldap_disconnect(LDAP ld) / I - LDAP h
#endif /* HAVE_LDAP */

+#ifdef HAVE_AVAHI
+/*

  • * 'cupsdStartAvahiClient()' - Start an Avahi client if needed
  • */
    +
    +void
    +cupsdStartAvahiClient(void)
    +{
  • int error = 0;
  • if (!AvahiCupsClient && !AvahiCupsClientConnecting)
  • {
  • if (!AvahiCupsPollHandle)
  •  AvahiCupsPollHandle = avahi_cups_poll_new ();
    
  • if (AvahiCupsPollHandle)
  • {
  •  if (avahi_client_new (avahi_cups_poll_get (AvahiCupsPollHandle),
    
  •           AVAHI_CLIENT_NO_FAIL,
    
  •           avahi_client_cb, NULL,
    
  •           &error) != NULL)
    
  • AvahiCupsClientConnecting = 1;
  •  else
    
  • cupsdLogMessage (CUPSD_LOG_WARN, "Avahi client failed: %d", error);
  • }
  • }
    +}
    +#endif /* HAVE_AVAHI */
  • /*
    • 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
      */
      @@ -1542,13 +1597,16 @@ cupsdStartBrowsing(void)
      else
      BrowseSocket = -1;

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
{
+#ifdef HAVE_DNSSD
DNSServiceErrorType error; /* Error from service creation /
+#endif /
HAVE_DNSSD /
cupsd_listener_t *lis; /
Current listening socket */

+#ifdef HAVE_DNSSD
/*
* First create a "master" connection for all registrations...
*/
@@ -1573,6 +1631,7 @@ cupsdStartBrowsing(void)
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);

   cupsdAddSelect(fd, (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);

+#endif /* HAVE_DNSSD */

  /*
   * Then get the port we use for registrations.  If we are not listening

@@ -1598,17 +1657,23 @@ cupsdStartBrowsing(void)
*/

   if (BrowseRemoteProtocols & BROWSE_DNSSD)
  •    DNSSDPrinters = cupsArrayNew((cups_array_func_t)dnssdComparePrinters,
    
  •                            NULL);
    
  • DNSSDPrinters = cupsArrayNew(NULL, NULL);
    

    /*

    • Set the computer name and register the web interface...
      */

      cupsdUpdateDNSSDName();
      +
      +#ifdef HAVE_AVAHI

  •  cupsdStartAvahiClient ();
    

    +#endif /* HAVE_AVAHI */
    +
    +#ifdef HAVE_DNSSD
    }

  • }
    #endif /* HAVE_DNSSD */

  • }
    +#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

#ifdef HAVE_LIBSLP
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
@@ -1834,10 +1899,10 @@ cupsdStopBrowsing(void)
BrowseSocket = -1;
}

-#ifdef HAVE_DNSSD

  • if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
    +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
  • if ((BrowseLocalProtocols & BROWSE_DNSSD))
    dnssdStop();
    -#endif /* HAVE_DNSSD /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

#ifdef HAVE_LIBSLP
if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
@@ -1902,7 +1967,7 @@ cupsdStopPolling(void)
}

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
/*

  • 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
    /
    @@ -1910,8 +1975,14 @@ cupsdStopPolling(void)
    void
    cupsdUpdateDNSSDName(void)
    {
    +#ifdef HAVE_DNSSD
    DNSServiceErrorType error; /
    Error from service creation /
    char webif[1024]; /
    Web interface share name /
    +#endif /
    HAVE_DNSSD */
    +#ifdef HAVE_AVAHI
    • int ret; /* Error from service creation */
    • char webif[AVAHI_LABEL_MAX]; /* Web interface share name /
      +#endif /
      HAVE_AVAHI _/

    ifdef HAVE_SYSTEMCONFIGURATION

    SCDynamicStoreRef sc; /_ Context for dynamic store /
    CFDictionaryRef btmm; /
    Back-to-My-Mac domains */
    @@ -2042,6 +2113,7 @@ cupsdUpdateDNSSDName(void)
    else
    strlcpy(webif, "CUPS Web Interface", sizeof(webif));

+#ifdef HAVE_DNSSD
if (WebIFRef)
DNSServiceRefDeallocate(WebIFRef);

@@ -2054,9 +2126,45 @@ cupsdUpdateDNSSDName(void)
NULL)) != kDNSServiceErr_NoError)
cupsdLogMessage(CUPSD_LOG_ERROR,
"DNS-SD web interface registration failed: %d", error);
+#endif /* HAVE_DNSSD */
+
+#ifdef HAVE_AVAHI

  • if (!AvahiCupsClient)
  • /*
    
  •  \* Client not yet running.
    
  •  */
    
  •  return;
    
  • if (AvahiWebIFGroup)
  •  avahi_entry_group_reset (AvahiWebIFGroup);
    
  • else
  •  AvahiWebIFGroup = avahi_entry_group_new (AvahiCupsClient,
    
  •                      avahi_entry_group_cb,
    
  •                      NULL);
    
  • if (AvahiWebIFGroup)
  • {
  •  ret = avahi_entry_group_add_service (AvahiWebIFGroup,
    
  •                  AVAHI_IF_UNSPEC,
    
  •                  AVAHI_PROTO_UNSPEC,
    
  •                  0, /\* flags */
    
  •                  webif, /\* name */
    
  •                  "_http._tcp", /\* type */
    
  •                  NULL, /\* domain */
    
  •                  NULL, /\* host */
    
  •                  DNSSDPort, /\* port */
    
  •                  "path=/", NULL);
    
  •  if (ret == 0)
    
  • ret = avahi_entry_group_commit (AvahiWebIFGroup);
  •  if (ret != 0)
    
  • cupsdLogMessage (CUPSD_LOG_ERROR,
  •        "Avahi web interface registration failed: %d", ret);
    
  • }
    +#endif /* HAVE_AVAHI /
    }
    }
    -#endif /
    HAVE_DNSSD /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

#ifdef HAVE_LDAP
@@ -2334,13 +2442,15 @@ dnssdAddAlias(const void key, / I - K
"Bad Back to My Mac domain in dynamic store!");
}

endif /* HAVE_COREFOUNDATION */

+#endif /* HAVE_DNSSD */

+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
/*

  • 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
    */

-static char * /* O - TXT record /
+static cupsd_txt_record_t /
O - TXT record /
dnssdBuildTxtRecord(
int *txt_len, /
O - TXT record length /
cupsd_printer_t *p, /
I - Printer information */
@@ -2379,7 +2489,12 @@ dnssdBuildTxtRecord(
keyvalue[i ][0] = "ty";
keyvalue[i++][1] = p->make_model ? p->make_model : "Unknown";

  • snprintf(admin_hostname, sizeof(admin_hostname), "%s.local.", DNSSDHostName);
  • snprintf(admin_hostname, sizeof(admin_hostname),
  •  "%s.local"
    
    +#ifdef HAVE_DNSSD
  •  "." /\* terminating dot no good for Avahi _/
    
    +#endif /_ HAVE_DNSSD */
  •  , DNSSDHostName);
    
    httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str),
    "http", NULL, admin_hostname, DNSSDPort, "/%s/%s",
    (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
    @@ -2462,19 +2577,12 @@ dnssdBuildTxtRecord(
    • Then pack them into a proper txt record...
      */

+#ifdef HAVE_DNSSD
return (dnssdPackTxtRecord(txt_len, keyvalue, i));

-}

-/*

  • * 'dnssdComparePrinters()' - Compare the registered names of two printers.

- */

-static int /* O - Result of comparison /
-dnssdComparePrinters(cupsd_printer_t *a,/
I - First printer */

  •                 cupsd_printer_t _b)/_ I - Second printer */
    
    -{
  • return (_cups_strcasecmp(a->reg_name, b->reg_name));
    +#endif /* HAVE_DNSSD */
    +#ifdef HAVE_AVAHI
  • return (avahiPackTxtRecord(keyvalue, i));
    +#endif /* HAVE_AVAHI */
    }

@@ -2489,6 +2597,10 @@ dnssdDeregisterPrinter(
{
cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);

+#ifdef HAVE_DNSSD

  • if (!DNSSDRef)
  • return;

/*

  • Closing the socket deregisters the service
    /
    @@ -2524,6 +2636,24 @@ dnssdDeregisterPrinter(
    free(p->printer_txt);
    p->printer_txt = NULL;
    }
    +#endif /
    HAVE_DNSSD */
    +
    +#ifdef HAVE_AVAHI
  • if (p->avahi_group)
  • {
  •  avahi_entry_group_reset (p->avahi_group);
    
  •  avahi_entry_group_free (p->avahi_group);
    
  •  p->avahi_group = NULL;
    
  •  if (p->ipp_txt)
    
  • avahi_string_list_free (p->ipp_txt);
  •  if (p->printer_txt)
    
  • avahi_string_list_free (p->printer_txt);
  •  p->ipp_txt = p->printer_txt = NULL;
    
  • }
    +#endif /* HAVE_AVAHI */

/*

  • Remove the printer from the array of DNS-SD printers, then clear the
    @@ -2533,8 +2663,10 @@ dnssdDeregisterPrinter(
    cupsArrayRemove(DNSSDPrinters, p);
    cupsdClearString(&p->reg_name);
    }
    +#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

+#ifdef HAVE_DNSSD
/*

  • 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
  •                      TXT record format.
    
    @@ -2644,8 +2776,10 @@ dnssdRegisterCallback(
    LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
    }
    }
    +#endif /* HAVE_DNSSD */

+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
/*

  • 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
  •               or update the broadcast contents.
    
    @@ -2654,20 +2788,40 @@ dnssdRegisterCallback(
    static void
    dnssdRegisterPrinter(cupsd_printer_t p)/ I - Printer /
    {
    +#ifdef HAVE_DNSSD
    DNSServiceErrorType se; /
    dnssd errors /
    char *ipp_txt, /
    IPP TXT record buffer /
    *printer_txt, /
    LPD TXT record buffer */
    •       name[1024], /\* Service name */
      
    •       _nameptr;   /_ Pointer into name */
      
    •       name[1024]; /\* Service name _/
      
      int ipp_len, /_ IPP TXT record length /
      printer_len, /
      LPD TXT record length /
      printer_port; /
      LPD port number /
      +#endif /
      HAVE_DNSSD */
      +#ifdef HAVE_AVAHI
    • int ret; /* Error code */
    • AvahiStringList ipp_txt, / IPP TXT record */
    •       _printer_txt;   /_ LPD TXT record */
      
    • char name[AVAHI_LABEL_MAX], /* Service name */
    •       fullsubtype[AVAHI_LABEL_MAX]; /\* Full subtype */
      
    • char regtype_copy, / Writeable copy of reg type */
    •       _subtype,   /_ Current service sub type */
      
    •       _nextsubtype;   /_ Next service sub type _/
      
      +#endif /_ HAVE_AVAHI */
    • char nameptr; / Pointer into name /
      const char *regtype; /
      Registration type */

+#ifdef HAVE_DNSSD

  • if (!DNSSDRef)
  • return;

cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
!p->ipp_ref ? "new" : "update");

+#endif /* HAVE_DNSSD */
+#ifdef HAVE_AVAHI

  • cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
  •     !p->avahi_group ? "new" : "update");
    
    +#endif /* HAVE_AVAHI /
    /
    • If per-printer sharing was just disabled make sure we're not
    • registered before returning.
      @@ -2686,12 +2840,36 @@ dnssdRegisterPrinter(cupsd_printer_t *p)
      if (p->info && strlen(p->info) > 0)
      {
      if (DNSSDComputerName)
  •  snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDComputerName);
    
  • {
  • /*
    
  •  \* Make sure there is room for at least 15 characters of
    
  •  \* DNSSDComputerName.
    
  •  */
    
  •  assert(sizeof(name) >= 15 + 4);
    
  •  nameptr = name + strlcpy(name, p->info,
    
  •              sizeof(name) - 4 -
    
  •              strnlen(DNSSDComputerName, 15));
    
  •  nameptr += strlcpy(nameptr, " @ ", sizeof(name) - (nameptr - name));
    
  •  strlcpy(nameptr, DNSSDComputerName, sizeof(name) - (nameptr - name));
    
  • }
    else
    strlcpy(name, p->info, sizeof(name));
    }
    else if (DNSSDComputerName)
  • snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDComputerName);
  • {
  • /*
  • * Make sure there is room for at least 15 characters of
  • * DNSSDComputerName.
  • */
  • assert(sizeof(name) >= 15 + 4);
  • nameptr = name + strlcpy(name, p->info,
  •            sizeof(name) - 4 -
    
  •            strnlen(DNSSDComputerName, 15));
    
  • nameptr += strlcpy(nameptr, " @ ", sizeof(name) - (nameptr - name));
  • strlcpy(nameptr, DNSSDComputerName, sizeof(name) - (nameptr - name));
  • }
    else
    strlcpy(name, p->name, sizeof(name));

@@ -2712,6 +2890,7 @@ dnssdRegisterPrinter(cupsd_printer_t *p)

  • Register IPP and (optionally) LPD...
    */

+#ifdef HAVE_DNSSD
ipp_len = 0; /* anti-compiler-warning-code */
ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);

@@ -2884,6 +3063,209 @@ dnssdRegisterPrinter(cupsd_printer_t *p)

if (printer_txt)
free(printer_txt);
+#endif /* HAVE_DNSSD */
+#ifdef HAVE_AVAHI

  • if (!AvahiCupsClient)
  • /*
  • * Client not running yet. The client callback will call us again later.
  • */
  • return;
  • ipp_txt = dnssdBuildTxtRecord(NULL, p, 0);
  • printer_txt = dnssdBuildTxtRecord(NULL, p, 1);
  • regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" : DNSSDRegType;
  • if (p->avahi_group && p->ipp_txt && ipp_txt &&
  •  !avahi_string_list_equal (p->ipp_txt, ipp_txt))
    
  • {
  • /*
  • * Update the existing registration...
  • */
  • avahi_string_list_free (p->ipp_txt);
  • if (p->printer_txt)
  •  avahi_string_list_free (p->printer_txt);
    
  • /*
  • * Update the service group entry.
  • */
  • regtype_copy = strdup (regtype);
  • subtype = strchr (regtype_copy, ',');
  • if (subtype)
  •  *subtype = '\0';
    
  • cupsdLogMessage (CUPSD_LOG_DEBUG,
  •        "Updating TXT record for %s (%s)", name, regtype_copy);
    
  • ret = avahi_entry_group_update_service_txt_strlst (p->avahi_group,
  •                          AVAHI_IF_UNSPEC,
    
  •                          AVAHI_PROTO_UNSPEC,
    
  •                          0, name,
    
  •                          regtype_copy,
    
  •                          NULL, ipp_txt);
    
  • free (regtype_copy);
  • if (ret < 0)
  •  goto update_failed;
    
  • p->ipp_txt = ipp_txt;
  • ipp_txt = NULL;
  • if (BrowseLocalProtocols & BROWSE_LPD)
  • {
  •  ret = avahi_entry_group_update_service_txt_strlst (p->avahi_group,
    
  •                        AVAHI_IF_UNSPEC,
    
  •                        AVAHI_PROTO_UNSPEC,
    
  •                        0, name,
    
  •                        "_printer._tcp", NULL,
    
  •                        printer_txt);
    
  •  if (ret < 0)
    
  • goto update_failed;
  •  p->printer_txt = printer_txt;
    
  •  printer_txt = NULL;
    
  • }
  • ret = avahi_entry_group_commit (p->avahi_group);
  • if (ret < 0)
  • {
  • update_failed:
  •  cupsdLogMessage (CUPSD_LOG_ERROR,
    
  •          "Failed to update TXT record for %s: %d",
    
  •          name, ret);
    
  •  avahi_entry_group_reset (p->avahi_group);
    
  •  avahi_entry_group_free (p->avahi_group);
    
  •  p->avahi_group = NULL;
    
  •  ipp_txt = p->ipp_txt;
    
  •  p->ipp_txt = NULL;
    
  • }
  • }
  • if (!p->avahi_group)
  • {
  • /*
  • * Initial registration. Use the _fax subtype for fax queues...
  • */
  • p->avahi_group = avahi_entry_group_new (AvahiCupsClient,
  •                   avahi_entry_group_cb,
    
  •                   p);
    
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •       "Registering Avahi printer %s with name \"%s\" and "
    
  •       "type \"%s\"", p->name, name, regtype);
    
  • if (!p->avahi_group)
  • {
  •  ret = 0;
    
  •  goto add_failed;
    
  • }
  • /*
  • * Add each service type (DNSSDRegType may contain several,
  • * separated by commas).
  • */
  • subtype = regtype_copy = strdup (regtype);
  • while (subtype && *subtype)
  • {
  •  nextsubtype = strchr (subtype, ',');
    
  •  if (nextsubtype)
    
  • *nextsubtype++ = '\0';
  •  if (subtype == regtype_copy)
    
  •  {
    
  •   /*
    
  • * Main type entry.
  • */
  • cupsdLogMessage (CUPSD_LOG_DEBUG,
  •        "Adding TXT record for %s (%s)", name, regtype_copy);
    
  • ret = avahi_entry_group_add_service_strlst (p->avahi_group,
  •                       AVAHI_IF_UNSPEC,
    
  •                       AVAHI_PROTO_UNSPEC,
    
  •                       0, name, regtype_copy,
    
  •                       NULL, NULL,
    
  •                       DNSSDPort,
    
  •                       ipp_txt);
    
  •  }
    
  •  else
    
  •  {
    
  •   /*
    
  • * Sub-type entry.
  • */
  • snprintf (fullsubtype, sizeof(fullsubtype),
  •     "%s._sub.%s", subtype, regtype_copy);
    
  • cupsdLogMessage (CUPSD_LOG_DEBUG,
  •        "Adding TXT record for %s (%s)", name, fullsubtype);
    
  • ret = avahi_entry_group_add_service_subtype (p->avahi_group,
  •                        AVAHI_IF_UNSPEC,
    
  •                        AVAHI_PROTO_UNSPEC,
    
  •                        0, name,
    
  •                        regtype_copy,
    
  •                        NULL, fullsubtype);
    
  •  }
    
  •  if (ret < 0)
    
  •  {
    
  • free (regtype_copy);
  • goto add_failed;
  •  }
    
  •  subtype = nextsubtype;
    
  • }
  • free (regtype_copy);
  • p->ipp_txt = ipp_txt;
  • ipp_txt = NULL;
  • if (BrowseLocalProtocols & BROWSE_LPD)
  • {
  •  cupsdLogMessage(CUPSD_LOG_DEBUG,
    
  •         "Registering Avahi printer %s with name \"%s\" and "
    
  •         "type \"_printer._tcp\"", p->name, name);
    
  •  ret = avahi_entry_group_add_service_strlst (p->avahi_group,
    
  •                     AVAHI_IF_UNSPEC,
    
  •                     AVAHI_PROTO_UNSPEC,
    
  •                     0, name,
    
  •                     "_printer._tcp", NULL, NULL,
    
  •                     515,
    
  •                     printer_txt);
    
  •  if (ret < 0)
    
  • goto add_failed;
  •  p->printer_txt = printer_txt;
    
  •  printer_txt = NULL;
    
  • }
  • ret = avahi_entry_group_commit (p->avahi_group);
  • if (ret < 0)
  • {
  • add_failed:
  •  cupsdLogMessage (CUPSD_LOG_ERROR,
    
  •          "Failed to add Avahi entry for %s: %d",
    
  •          name, ret);
    
  •  if (p->avahi_group)
    
  •  {
    
  • avahi_entry_group_reset (p->avahi_group);
  • avahi_entry_group_free (p->avahi_group);
  • p->avahi_group = NULL;
  •  }
    
  •  ipp_txt = p->ipp_txt;
    
  •  p->ipp_txt = NULL;
    
  • }
  • }
  • if (ipp_txt)
  • avahi_string_list_free (ipp_txt);
  • if (printer_txt)
  • avahi_string_list_free (printer_txt);
    +#endif /* HAVE_AVAHI */
    }

@@ -2896,6 +3278,10 @@ dnssdStop(void)
{
cupsd_printer_t p; / Current printer */

+#ifdef HAVE_DNSSD

  • if (!DNSSDRef)
  • return;
    +#endif /* HAVE_DNSSD */

/*

  • De-register the individual printers
    @@ -2906,6 +3292,7 @@ dnssdStop(void)
    p = (cupsd_printer_t *)cupsArrayNext(Printers))
    dnssdDeregisterPrinter(p);

+#ifdef HAVE_DNSSD
/*

  • Shutdown the rest of the service refs...
    */
    @@ -2926,14 +3313,17 @@ dnssdStop(void)

    DNSServiceRefDeallocate(DNSSDRef);
    DNSSDRef = NULL;
    +#endif /* HAVE_DNSSD */

    cupsArrayDelete(DNSSDPrinters);
    DNSSDPrinters = NULL;

    DNSSDPort = 0;
    }
    +#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

+#ifdef HAVE_DNSSD
/*

  • 'dnssdUpdate()' - Handle DNS-SD queries.
    /
    @@ -2955,6 +3345,153 @@ dnssdUpdate(void)
    #endif /
    HAVE_DNSSD */

+#ifdef HAVE_AVAHI
+/*

  • * 'avahiPackTxtRecord()' - Pack an array of key/value pairs into an
  • * AvahiStringList.
  • /
    +
    +static AvahiStringList * /
    O - new string list /
    +avahiPackTxtRecord(char *keyvalue[][2], /
    I - Table of key value pairs */
  •      int count)       /\* I - Number of items in table */
    
    +{
  • AvahiStringList *strlst = NULL;
  • char **elements;
  • size_t len;
  • int i = 0;
  • elements = malloc ((1 + count) * sizeof (char *));
  • if (!elements)
  • goto cleanup;
  • for (i = 0; i < count; i++)
  • {
  •  len = (1 + strlen (keyvalue[i][0]) +
    
  •    (keyvalue[i][1] ? 1 + strlen (keyvalue[i][1]) : 1));
    
  •  elements[i] = malloc (len \* sizeof (char));
    
  •  if (!elements[i])
    
  • goto cleanup;
  •  snprintf (elements[i], len, "%s=%s", keyvalue[i][0], keyvalue[i][1]);
    
  • }
  • strlst = avahi_string_list_new_from_array ((const char **) elements, count);

+cleanup:

  • while (--i >= 0)
  • free (elements[i]);
  • free (elements);
  • return (strlst);
    +}

+/*

  • * 'avahi_entry_group_cb()' - Avahi entry group callback function.
  • */
    +static void
    +avahi_entry_group_cb (AvahiEntryGroup *group,
  •         AvahiEntryGroupState state,
    
  •         void *userdata)
    
    +{
  • char *name;
  • if (userdata)
  • name = ((cupsd_printer_t *) userdata)->reg_name;
  • else
  • name = "CUPS web interface";
  • switch (state)
  • {
  • case AVAHI_ENTRY_GROUP_UNCOMMITED:
  • case AVAHI_ENTRY_GROUP_REGISTERING:
  • break;
  • case AVAHI_ENTRY_GROUP_ESTABLISHED:
  • cupsdLogMessage (CUPSD_LOG_DEBUG,
  •        "Avahi entry group established for %s", name);
    
  • break;
  • default:
  • cupsdLogMessage (CUPSD_LOG_DEBUG,
  •        "Avahi entry group %s has state %d",
    
  •        name, state);
    
  • break;
  • }
    +}

+/*

  • * 'avahi_client_cb()' - Avahi client callback function.
  • */
    +static void
    +avahi_client_cb (AvahiClient *client,
  •    AvahiClientState state,
    
  •    void *userdata)
    
    +{
  • cupsd_printer_t *printer;
  • switch (state)
  • {
  • case AVAHI_CLIENT_S_RUNNING:
  • /*
  • * Avahi client started successfully.
  • */
  • AvahiCupsClient = client;
  • AvahiCupsClientConnecting = 0;
  • cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client started");
  • cupsdUpdateDNSSDName ();
  • for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
  • printer;
  • printer = (cupsd_printer_t *)cupsArrayNext(Printers))
  •  if (Browsing && (BrowseLocalProtocols & BROWSE_DNSSD) &&
    
  • (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
    
  •             CUPS_PRINTER_SCANNER))) && printer->shared)
    
  • dnssdRegisterPrinter (printer);
  • break;
  • case AVAHI_CLIENT_CONNECTING:
  • /*
  • * No Avahi daemon, client is waiting.
  • */
  • cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client connecting");
  • break;
  • case AVAHI_CLIENT_S_REGISTERING:
  • /*
  • \* Not yet registered.
    
  • */
    
  • cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client registering");
  • break;
  • case AVAHI_CLIENT_FAILURE:
  • /*
  • * Avahi client failed, close it to allow a clean restart.
  • */
  • cupsdLogMessage (CUPSD_LOG_ERROR,
  •        "Avahi client failed, "
    
  •        "closing client to allow a clean restart");
    
  • for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
  • printer;
  • printer = (cupsd_printer_t *)cupsArrayNext(Printers))
  •  dnssdDeregisterPrinter (printer);
    
  • avahi_client_free(client);
  • AvahiCupsClientConnecting = 0;
  • AvahiCupsClient = NULL;
  • break;
  • default:
  • cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client state: %d", state);
  • }
    +}
    +#endif /* HAVE_AVAHI _/

/_

  • 'get_auth_info_required()' - Get the auth-info-required value to advertise.
    _/
    diff -up cups-1.5.0/scheduler/dirsvc.h.avahi-5-services cups-1.5.0/scheduler/dirsvc.h
    --- cups-1.5.0/scheduler/dirsvc.h.avahi-5-services 2011-03-21 02:12:14.000000000 +0000
    +++ cups-1.5.0/scheduler/dirsvc.h 2011-10-19 11:53:32.138177721 +0100
    @@ -31,6 +31,10 @@

    endif /_ HAVE_LDAP_SSL_H _/

    #endif /_ HAVE_LDAP */

+#ifdef HAVE_AVAHI
+# include <avahi-client/publish.h>
+#endif /* HAVE_AVAHI /
+
/

  • Browse protocols...
    /
    @@ -131,19 +135,22 @@ VAR int PollPipe VALUE(0);
    VAR cupsd_statbuf_t *PollStatusBuffer VALUE(NULL);
    /
    Status buffer for pollers */

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
VAR char DNSSDComputerName VALUE(NULL),
/
Computer/server name /
*DNSSDHostName VALUE(NULL),
/
Hostname /
*DNSSDRegType VALUE(NULL);
/
Bonjour registration type */
-VAR cups_array_t *DNSSDAlias VALUE(NULL);

  •               /\* List of dynamic ServerAlias's _/
    
    VAR int DNSSDPort VALUE(0);
    /_ Port number to register /
    VAR cups_array_t *DNSSDPrinters VALUE(NULL);
    /
    Printers we have registered /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
    +
    +#ifdef HAVE_DNSSD
    +VAR cups_array_t *DNSSDAlias VALUE(NULL);
  •               /\* List of dynamic ServerAlias's _/
    
    VAR DNSServiceRef DNSSDRef VALUE(NULL),
    /_ Master DNS-SD service reference /
    WebIFRef VALUE(NULL),
    @@ -152,6 +159,17 @@ VAR DNSServiceRef DNSSDRef VALUE(NULL),
    /
    Remote printer browse reference /
    #endif /
    HAVE_DNSSD */

+#ifdef HAVE_AVAHI
+VAR AvahiCupsPoll *AvahiCupsPollHandle VALUE(NULL);

  •               /\* AvahiCupsPoll object */
    
    +VAR AvahiClient *AvahiCupsClient VALUE(NULL);
  •               /\* AvahiClient object */
    
    +VAR int AvahiCupsClientConnecting VALUE(0);
  •               /\* Is AvahiClient object connecting? */
    
    +VAR AvahiEntryGroup *AvahiWebIFGroup VALUE(NULL);
  •               /\* Web interface entry group _/
    
    +#endif /_ HAVE_AVAHI /
    +
    #ifdef HAVE_LIBSLP
    VAR SLPHandle BrowseSLPHandle VALUE(NULL);
    /
    SLP API handle /
    @@ -195,13 +213,14 @@ extern void cupsdRegisterPrinter(cupsd_p
    extern void cupsdRestartPolling(void);
    extern void cupsdSaveRemoteCache(void);
    extern void cupsdSendBrowseList(void);
    +extern void cupsdStartAvahiClient(void);
    extern void cupsdStartBrowsing(void);
    extern void cupsdStartPolling(void);
    extern void cupsdStopBrowsing(void);
    extern void cupsdStopPolling(void);
    -#ifdef HAVE_DNSSD
    +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
    extern void cupsdUpdateDNSSDName(void);
    -#endif /
    HAVE_DNSSD /
    +#endif /
    defined(HAVE_DNSSD) || defined(HAVE_AVAHI) /
    #ifdef HAVE_LDAP
    extern void cupsdUpdateLDAPBrowse(void);
    #endif /
    HAVE_LDAP */
    diff -up cups-1.5.0/scheduler/ipp.c.avahi-5-services cups-1.5.0/scheduler/ipp.c
    --- cups-1.5.0/scheduler/ipp.c.avahi-5-services 2011-10-19 11:53:31.978180686 +0100
    +++ cups-1.5.0/scheduler/ipp.c 2011-10-19 11:53:32.147177555 +0100
    @@ -6096,7 +6096,7 @@ copy_printer_attrs(
    ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time",
    ippTimeToDate(curtime));

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
if (!ra || cupsArrayFind(ra, "printer-dns-sd-name"))
{
if (printer->reg_name)
@@ -6106,7 +6106,7 @@ copy_printer_attrs(
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE,
"printer-dns-sd-name", 0);
}
-#endif /* HAVE_DNSSD /
+#endif /
defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

if (!ra || cupsArrayFind(ra, "printer-error-policy"))
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME,
diff -up cups-1.5.0/scheduler/main.c.avahi-5-services cups-1.5.0/scheduler/main.c
--- cups-1.5.0/scheduler/main.c.avahi-5-services 2011-10-19 11:53:32.101178406 +0100
+++ cups-1.5.0/scheduler/main.c 2011-10-19 11:53:32.151177479 +0100
@@ -120,6 +120,10 @@ main(int argc, /* I - Number of comm
cupsd_listener_t lis; / Current listener /
time_t current_time, /
Current time /
activity, /
Client activity timer */
+#ifdef HAVE_AVAHI

  •       avahi_client_time, /\* Time for next Avahi client
    
  •                     check */
    

    +#endif /* HAVE_AVAHI /
    browse_time, /
    Next browse send time /
    senddoc_time, /
    Send-Document time /
    expire_time, /
    Subscription expire time /
    @@ -672,6 +676,9 @@ main(int argc, /
    I - Number of comm
    */

    current_time = time(NULL);
    +#ifdef HAVE_AVAHI

  • avahi_client_time = current_time;
    +#endif /* HAVE_AVAHI /
    browse_time = current_time;
    event_time = current_time;
    expire_time = current_time;
    @@ -894,6 +901,16 @@ main(int argc, /
    I - Number of comm
    tmo = cupsdNextTimeout (&tmo_delay);
    if (tmo && tmo_delay == 0)
    cupsdRunTimeout (tmo);

  • /*
  • * Try to restart the Avahi client every 10 seconds if needed...
  • */
  • if ((current_time - avahi_client_time) >= 10)
  • {
  •  avahi_client_time = current_time;
    
  •  cupsdStartAvahiClient();
    
  • }
    #endif /* HAVE_AVAHI */

#ifndef APPLE
diff -up cups-1.5.0/scheduler/printers.c.avahi-5-services cups-1.5.0/scheduler/printers.c
--- cups-1.5.0/scheduler/printers.c.avahi-5-services 2011-10-19 11:53:31.916181835 +0100
+++ cups-1.5.0/scheduler/printers.c 2011-10-19 11:53:32.156177388 +0100
@@ -883,9 +883,9 @@ cupsdDeletePrinter(
cupsdClearString(&p->alert);
cupsdClearString(&p->alert_description);

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
cupsdClearString(&p->pdl);
-#endif /* HAVE_DNSSD /
+#endif /
defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */

cupsArrayDelete(p->filetypes);

@@ -3787,7 +3787,7 @@ add_printer_formats(cupsd_printer_t *p)
attr->values[i].string.text = _cupsStrAlloc(mimetype);
}

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
{
char pdl[1024]; /* Buffer to build pdl list /
mime_filter_t *filter; /
MIME filter looping var */
@@ -3843,7 +3843,7 @@ add_printer_formats(cupsd_printer_t *p)

 cupsdSetString(&p->pdl, pdl);

}
-#endif /* HAVE_DNSSD /
+#endif /
defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
}

diff -up cups-1.5.0/scheduler/printers.h.avahi-5-services cups-1.5.0/scheduler/printers.h
--- cups-1.5.0/scheduler/printers.h.avahi-5-services 2011-03-18 18:42:46.000000000 +0000
+++ cups-1.5.0/scheduler/printers.h 2011-10-19 11:53:32.157177369 +0100
@@ -16,6 +16,9 @@
#ifdef HAVE_DNSSD

include <dns_sd.h>

#endif /* HAVE_DNSSD /
+#ifdef HAVE_AVAHI
+# include "avahi.h"
+#endif /
HAVE_AVAHI */
#include <cups/pwg-private.h>

@@ -95,16 +98,23 @@ struct cupsd_printer_s
time_t marker_time; /* Last time marker attributes were updated _/
ppd_cache_t *pc; / PPD cache and mapping data */

-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
char reg_name, / Name used for service registration */

  •   _pdl,           /_ pdl value for TXT record */
    
  •   _ipp_txt,       /_ IPP TXT record contents */
    
  •   _pdl;           /_ pdl value for TXT record _/
    
    +#endif /_ defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
    +#ifdef HAVE_DNSSD
  • char ipp_txt, / IPP TXT record contents /
    *printer_txt; /
    LPD TXT record contents /
    int ipp_len, /
    IPP TXT record length /
    printer_len; /
    LPD TXT record length /
    DNSServiceRef ipp_ref, /
    Reference for _ipp._tcp,_cups /
    printer_ref; /
    Reference for _printer._tcp /
    #endif /
    HAVE_DNSSD */
    +#ifdef HAVE_AVAHI
  • AvahiStringList ipp_txt, / IPP TXT record */
  •   _printer_txt;       /_ LPD TXT record */
    
  • AvahiEntryGroup avahi_group; / Avahi entry group /
    +#endif /
    HAVE_AVAHI */
    };
@michaelrsweet michaelrsweet added this to the Stable milestone Mar 17, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment