Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cupsd crashes because it wrongly uses D-Bus from multiple threads #4347

Closed
michaelrsweet opened this issue Jan 16, 2014 · 6 comments
Closed
Milestone

Comments

@michaelrsweet
Copy link
Collaborator

Version: 1.7.1
CUPS.org User: odyx

Hi Michael,

After the report of https://bugzilla.redhat.com/show_bug.cgi?id=979748, Tim Waugh reported the following analysis:

I think the root cause of this is that cupsd is using avahi_threaded_poll
(which makes use of D-Bus) while also using D-Bus in its main thread. I don't
think that's allowed.

The fix will be to alter the avahi polling so that it's done in the main
thread (i.e. as it was before it was re-implemented upstream).

His patch is attached, it would be nice to have this integrated upstream.

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

I REALLY HATE THIS PATCH. It is far too complicated just to support Avahi and we cannot maintain something like that. In its present form we WILL NOT add it to CUPS.

On Linux we need to use DBUS in cupsd for Avahi and colord. Both seem to be getting their own DBUS connections, so this should not be a problem (according to the documentation) unless you are shipping an old version of DBUS (1.4.x or earlier). And if it is a problem then we have a fundamental bug in DBUS that needs fixing there, not worked around with an unmaintainable patch in cupsd.

What version of DBUS is being used?

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

and it looks like we should be calling dbus_threads_init in cupsd to enable threading support (!) in DBUS...

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Back to pending while I apply a simpler 1-line patch to require a recent D-BUS with the dbus_threads_init function.

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Fixed in Subversion repository.

@michaelrsweet
Copy link
Collaborator Author

"dont-use-dbus-from-two-threads.patch":

Description: Don't use D-Bus from two threads
Author: Tim Waugh twaugh@redhat.com
Bug-Redhat: https://bugzilla.redhat.com/show_bug.cgi?id=979748
Last-Updated: 2013-11-28
--- /dev/null
+++ b/scheduler/avahi.c
@@ -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$".
  • /
    --- /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$".

  • */
    --- a/scheduler/cupsd.h
    +++ b/scheduler/cupsd.h
    @@ -119,6 +119,7 @@
    #include "colorman.h"
    #include "conf.h"
    #include "banners.h"
    +#include "avahi.h"
    #include "dirsvc.h"
    #include "network.h"
    #include "subscriptions.h"
    @@ -139,6 +140,15 @@

    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...
      @@ -165,6 +175,11 @@
      /* Running from launchd /
      #endif /
      HAVE_LAUNCH_H */

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

/*

  • Prototypes...
    @@ -229,6 +244,17 @@
    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 */

    /*

    • End of "$Id: cupsd.h 10996 2013-05-29 11:51:34Z msweet $".
      --- a/scheduler/dirsvc.c
      +++ b/scheduler/dirsvc.c
      @@ -212,7 +212,7 @@
      }

    else /* HAVE_AVAHI */

  • if ((DNSSDMaster = avahi_threaded_poll_new()) == NULL)

  • if ((DNSSDMaster = avahi_cups_poll_new()) == NULL)
    {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create DNS-SD thread.");

@@ -223,7 +223,7 @@
{
int error; /* Error code, if any */

  •  DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), 0,
    
  •  DNSSDClient = avahi_client_new(avahi_cups_poll_get(DNSSDMaster), 0,
                                  NULL, NULL, &error);
    

    if (DNSSDClient == NULL)
    @@ -235,11 +235,9 @@
    if (FatalErrors & CUPSD_FATAL_BROWSE)
    cupsdEndProcess(getpid(), 0);

  •    avahi_threaded_poll_free(DNSSDMaster);
    
  •    avahi_cups_poll_free(DNSSDMaster);
     DNSSDMaster = NULL;
    

    }

  •  else
    
  • avahi_threaded_poll_start(DNSSDMaster);
    }

endif /* HAVE_DNSSD */

@@ -754,9 +752,7 @@
DNSServiceRefDeallocate(*srv);

else /* HAVE_AVAHI */

  • avahi_threaded_poll_lock(DNSSDMaster);
    avahi_entry_group_free(*srv);
  • avahi_threaded_poll_unlock(DNSSDMaster);

endif /* HAVE_DNSSD */

*srv = NULL;
@@ -1051,14 +1047,10 @@
(void)commit;

else /* HAVE_AVAHI */

- avahi_threaded_poll_lock(DNSSDMaster);

if (!_srv)
*srv = avahi_entry_group_new(DNSSDClient, dnssdRegisterCallback, NULL);
if (!_srv)
{

- avahi_threaded_poll_unlock(DNSSDMaster);

 cupsdLogMessage(CUPSD_LOG_WARN, "DNS-SD registration of \"%s\" failed: %s",
                 name, dnssdErrorString(avahi_client_errno(DNSSDClient)));
 return (0);

@@ -1173,8 +1165,6 @@
cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD commit of "%s" failed.",
name);

}

  • avahi_threaded_poll_unlock(DNSSDMaster);

endif /* HAVE_DNSSD */

if (error)
@@ -1341,12 +1331,10 @@
DNSSDMaster = NULL;

else /* HAVE_AVAHI */

- avahi_threaded_poll_stop(DNSSDMaster);

avahi_client_free(DNSSDClient);
DNSSDClient = NULL;

  • avahi_threaded_poll_free(DNSSDMaster);
  • avahi_cups_poll_free(DNSSDMaster);
    DNSSDMaster = NULL;

endif /* HAVE_DNSSD */

--- a/scheduler/dirsvc.h
+++ b/scheduler/dirsvc.h
@@ -51,7 +51,7 @@
VAR DNSServiceRef DNSSDMaster VALUE(NULL);
/* Master DNS-SD service reference _/

else /_ HAVE_AVAHI _/

-VAR AvahiThreadedPoll *DNSSDMaster VALUE(NULL);
+VAR AvahiCupsPoll *DNSSDMaster VALUE(NULL);
/_ Master polling interface for Avahi /
VAR AvahiClient *DNSSDClient VALUE(NULL);
/
Client information /
--- a/scheduler/main.c
+++ b/scheduler/main.c
@@ -146,6 +146,10 @@
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
@@ -570,6 +574,14 @@

httpInitialize();

+#ifdef HAVE_AVAHI

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

cupsdStartServer();

/*
@@ -882,6 +894,16 @@
}
#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...
      @@ -1766,6 +1788,10 @@
      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 */

cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout: JobHistoryUpdate=%ld",
@@ -1811,6 +1837,19 @@
}
#endif /* APPLE */

+#ifdef HAVE_AVAHI

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

/_

  • Check whether we are accepting new connections...
    */
    --- a/scheduler/Makefile
    +++ b/scheduler/Makefile
    @@ -17,6 +17,7 @@

CUPSDOBJS =
auth.o \

  •   avahi.o \
    banners.o \
    cert.o \
    classes.o \
    
    @@ -41,6 +42,7 @@
    statbuf.o
    subscriptions.o
    sysman.o \
  •   timeout.o \
    tls.o
    
    LIBOBJS =
    filter.o
    --- /dev/null
    +++ b/scheduler/timeout.c
    @@ -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
Copy link
Collaborator Author

"str4347.patch":

Index: config-scripts/cups-common.m4

--- config-scripts/cups-common.m4 (revision 11597)
+++ config-scripts/cups-common.m4 (working copy)
@@ -3,7 +3,7 @@
dnl
dnl Common configuration stuff for CUPS.
dnl
-dnl Copyright 2007-2013 by Apple Inc.
+dnl Copyright 2007-2014 by Apple Inc.
dnl Copyright 1997-2007 by Easy Software Products, all rights reserved.
dnl
dnl These coded instructions, statements, and computer programs are the
@@ -304,16 +304,11 @@
LIBS="$SAVELIBS"

dnl Check for DBUS support
-if test -d /etc/dbus-1; then

  • DBUSDIR="/etc/dbus-1"
    -else
  • DBUSDIR=""
    -fi

AC_ARG_ENABLE(dbus, [ --disable-dbus build without DBUS support])
AC_ARG_WITH(dbusdir, [ --with-dbusdir set DBUS configuration directory ],
DBUSDIR="$withval")

+DBUSDIR=""
DBUS_NOTIFIER=""
DBUS_NOTIFIERLIBS=""

@@ -330,7 +325,12 @@
LIBS="$LIBS $DBUS_NOTIFIERLIBS"
AC_CHECK_FUNC(dbus_message_iter_init_append,
AC_DEFINE(HAVE_DBUS_MESSAGE_ITER_INIT_APPEND))

  •   AC_CHECK_FUNC(dbus_threads_init,
    
  •             AC_DEFINE(HAVE_DBUS_THREADS_INIT))
    LIBS="$SAVELIBS"
    
  •   if test -d /etc/dbus-1; then
    
  •       DBUSDIR="/etc/dbus-1"
    
  •   fi
    

    else
    AC_MSG_RESULT(no)
    fi

    Index: config.h.in

    --- config.h.in (revision 11597)
    +++ config.h.in (working copy)
    @@ -535,6 +535,7 @@

    #undef HAVE_DBUS
    #undef HAVE_DBUS_MESSAGE_ITER_INIT_APPEND
    +#undef HAVE_DBUS_THREADS_INIT

    /*

    Index: scheduler/main.c

    --- scheduler/main.c (revision 11597)
    +++ scheduler/main.c (working copy)
    @@ -477,7 +477,15 @@
    setlocale(LC_TIME, "");
    #endif /* LC_TIME */

+#ifdef HAVE_DBUS_THREADS_INIT
/*

  • * Enable threading support for D-BUS...
  • */
  • dbus_threads_init();
    +#endif /* HAVE_DBUS_THREADS_INIT */
  • /*
    • Set the maximum number of files...
      */

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant