Blame scheduler/avahi.c

Packit e8a0b7
/*
Packit e8a0b7
 * "$Id$"
Packit e8a0b7
 *
Packit e8a0b7
 *   Avahi poll implementation for the CUPS scheduler.
Packit e8a0b7
 *
Packit e8a0b7
 *   Copyright (C) 2010, 2011 Red Hat, Inc.
Packit e8a0b7
 *   Authors:
Packit e8a0b7
 *    Tim Waugh <twaugh@redhat.com>
Packit e8a0b7
 *
Packit e8a0b7
 *   Redistribution and use in source and binary forms, with or without
Packit e8a0b7
 *   modification, are permitted provided that the following conditions
Packit e8a0b7
 *   are met:
Packit e8a0b7
 *
Packit e8a0b7
 *   Redistributions of source code must retain the above copyright
Packit e8a0b7
 *   notice, this list of conditions and the following disclaimer.
Packit e8a0b7
 *
Packit e8a0b7
 *   Redistributions in binary form must reproduce the above copyright
Packit e8a0b7
 *   notice, this list of conditions and the following disclaimer in the
Packit e8a0b7
 *   documentation and/or other materials provided with the distribution.
Packit e8a0b7
 *
Packit e8a0b7
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit e8a0b7
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit e8a0b7
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
Packit e8a0b7
 *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
Packit e8a0b7
 *   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
Packit e8a0b7
 *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
Packit e8a0b7
 *   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
Packit e8a0b7
 *   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit e8a0b7
 *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
Packit e8a0b7
 *   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit e8a0b7
 *   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
Packit e8a0b7
 *   OF THE POSSIBILITY OF SUCH DAMAGE.
Packit e8a0b7
 *
Packit e8a0b7
 * Contents:
Packit e8a0b7
 *
Packit e8a0b7
 *   watch_read_cb         - Read callback for file descriptor
Packit e8a0b7
 *   watch_write_cb        - Write callback for file descriptor
Packit e8a0b7
 *   watched_fd_add_select() - Call cupsdAddSelect() as needed
Packit e8a0b7
 *   watch_new()           - Create a new file descriptor watch
Packit e8a0b7
 *   watch_free()          - Free a file descriptor watch
Packit e8a0b7
 *   watch_update()        - Update watched events for a file descriptor
Packit e8a0b7
 *   watch_get_events()    - Get events that happened for a file descriptor
Packit e8a0b7
 *   timeout_cb()          - Run a timed Avahi callback
Packit e8a0b7
 *   timeout_new()         - Set a wakeup time
Packit e8a0b7
 *   timeout_update()      - Update the expiration time for a timeout
Packit e8a0b7
 *   timeout_free()        - Free a timeout
Packit e8a0b7
 *   compare_watched_fds() - Compare watched file descriptors for array sorting
Packit e8a0b7
 *   avahi_cups_poll_new() - Create a new Avahi main loop object for CUPS
Packit e8a0b7
 *   avahi_cups_poll_free() - Free an Avahi main loop object for CUPS
Packit e8a0b7
 *   avahi_cups_poll_get() - Get the abstract poll API structure
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
#include <config.h>
Packit e8a0b7
Packit e8a0b7
#ifdef HAVE_AVAHI /* Applies to entire file... */
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * Include necessary headers...
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
#include "cupsd.h"
Packit e8a0b7
Packit e8a0b7
#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
Packit e8a0b7
#  include <malloc.h>
Packit e8a0b7
#endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
Packit e8a0b7
Packit e8a0b7
#ifdef HAVE_AVAHI
Packit e8a0b7
#  include <avahi-common/timeval.h>
Packit e8a0b7
#endif /* HAVE_AVAHI */
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
typedef struct
Packit e8a0b7
{
Packit e8a0b7
  AvahiCupsPoll *cups_poll;
Packit e8a0b7
Packit e8a0b7
  int fd;
Packit e8a0b7
  AvahiWatchEvent occurred;
Packit e8a0b7
  cups_array_t *watches;
Packit e8a0b7
} cupsd_watched_fd_t;
Packit e8a0b7
Packit e8a0b7
struct AvahiWatch
Packit e8a0b7
{
Packit e8a0b7
  cupsd_watched_fd_t *watched_fd;
Packit e8a0b7
Packit e8a0b7
  AvahiWatchEvent events;
Packit e8a0b7
  AvahiWatchCallback callback;
Packit e8a0b7
  void *userdata;
Packit e8a0b7
};
Packit e8a0b7
Packit e8a0b7
struct AvahiTimeout
Packit e8a0b7
{
Packit e8a0b7
  AvahiCupsPoll *cups_poll;
Packit e8a0b7
  AvahiTimeoutCallback callback;
Packit e8a0b7
  void *userdata;
Packit e8a0b7
  cupsd_timeout_t *cupsd_timeout;
Packit e8a0b7
};
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * Local functions...
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
static AvahiWatch *	watch_new(const AvahiPoll *api,
Packit e8a0b7
				  int fd,
Packit e8a0b7
				  AvahiWatchEvent events,
Packit e8a0b7
				  AvahiWatchCallback callback,
Packit e8a0b7
				  void *userdata);
Packit e8a0b7
static void		watch_free(AvahiWatch *watch);
Packit e8a0b7
static void		watch_update(AvahiWatch *watch,
Packit e8a0b7
				     AvahiWatchEvent events);
Packit e8a0b7
static AvahiWatchEvent	watch_get_events(AvahiWatch *watch);
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'watch_read_cb' - Read callback for file descriptor
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
static void
Packit e8a0b7
watch_read_cb (void *userdata)
Packit e8a0b7
{
Packit e8a0b7
  AvahiWatch *watch;
Packit e8a0b7
  cupsd_watched_fd_t *watched_fd = userdata;
Packit e8a0b7
  watched_fd->occurred |= AVAHI_WATCH_IN;
Packit e8a0b7
  for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
Packit e8a0b7
       watch;
Packit e8a0b7
       watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches))
Packit e8a0b7
  {
Packit e8a0b7
    if (watch->events & watched_fd->occurred)
Packit e8a0b7
    {
Packit e8a0b7
      (watch->callback) (watch, watched_fd->fd,
Packit e8a0b7
			 AVAHI_WATCH_IN, watch->userdata);
Packit e8a0b7
      watched_fd->occurred &= ~AVAHI_WATCH_IN;
Packit e8a0b7
      break;
Packit e8a0b7
    }
Packit e8a0b7
  }
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'watch_write_cb' - Write callback for file descriptor
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
static void
Packit e8a0b7
watch_write_cb (void *userdata)
Packit e8a0b7
{
Packit e8a0b7
  AvahiWatch *watch;
Packit e8a0b7
  cupsd_watched_fd_t *watched_fd = userdata;
Packit e8a0b7
  watched_fd->occurred |= AVAHI_WATCH_OUT;
Packit e8a0b7
  for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
Packit e8a0b7
       watch;
Packit e8a0b7
       watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches))
Packit e8a0b7
  {
Packit e8a0b7
    if (watch->events & watched_fd->occurred)
Packit e8a0b7
    {
Packit e8a0b7
      (watch->callback) (watch, watched_fd->fd,
Packit e8a0b7
			 AVAHI_WATCH_OUT, watch->userdata);
Packit e8a0b7
      watched_fd->occurred &= ~AVAHI_WATCH_OUT;
Packit e8a0b7
      break;
Packit e8a0b7
    }
Packit e8a0b7
  }
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'watched_fd_add_select' - Call cupsdAddSelect() as needed
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
static int						/* O - Watches? */
Packit e8a0b7
watched_fd_add_select (cupsd_watched_fd_t *watched_fd)
Packit e8a0b7
{
Packit e8a0b7
  AvahiWatch *watch;
Packit e8a0b7
  cupsd_selfunc_t read_cb = NULL, write_cb = NULL;
Packit e8a0b7
  int any_watches = 0;
Packit e8a0b7
Packit e8a0b7
  for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
Packit e8a0b7
       watch;
Packit e8a0b7
       watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches))
Packit e8a0b7
  {
Packit e8a0b7
    any_watches = 1;
Packit e8a0b7
    if (watch->events & (AVAHI_WATCH_IN |
Packit e8a0b7
			     AVAHI_WATCH_ERR |
Packit e8a0b7
			     AVAHI_WATCH_HUP))
Packit e8a0b7
    {
Packit e8a0b7
      read_cb = (cupsd_selfunc_t)watch_read_cb;
Packit e8a0b7
      if (write_cb != NULL)
Packit e8a0b7
	break;
Packit e8a0b7
    }
Packit e8a0b7
Packit e8a0b7
    if (watch->events & AVAHI_WATCH_OUT)
Packit e8a0b7
    {
Packit e8a0b7
      write_cb = (cupsd_selfunc_t)watch_write_cb;
Packit e8a0b7
      if (read_cb != NULL)
Packit e8a0b7
	break;
Packit e8a0b7
    }
Packit e8a0b7
  }
Packit e8a0b7
Packit e8a0b7
  if (read_cb || write_cb)
Packit e8a0b7
    cupsdAddSelect (watched_fd->fd, read_cb, write_cb, watched_fd);
Packit e8a0b7
  else
Packit e8a0b7
    cupsdRemoveSelect (watched_fd->fd);
Packit e8a0b7
Packit e8a0b7
  return (any_watches);
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'watch_new' - Create a new file descriptor watch
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
static AvahiWatch *
Packit e8a0b7
watch_new (const AvahiPoll *api,
Packit e8a0b7
	   int fd,
Packit e8a0b7
	   AvahiWatchEvent events,
Packit e8a0b7
	   AvahiWatchCallback callback,
Packit e8a0b7
	   void *userdata)
Packit e8a0b7
{
Packit e8a0b7
  cupsd_watched_fd_t key, *watched_fd;
Packit e8a0b7
  AvahiCupsPoll *cups_poll = api->userdata;
Packit e8a0b7
  AvahiWatch *watch = malloc(sizeof(AvahiWatch));
Packit e8a0b7
  if (watch == NULL)
Packit e8a0b7
    return (NULL);
Packit e8a0b7
Packit e8a0b7
  watch->events = events;
Packit e8a0b7
  watch->callback = callback;
Packit e8a0b7
  watch->userdata = userdata;
Packit e8a0b7
Packit e8a0b7
  key.fd = fd;
Packit e8a0b7
  watched_fd = cupsArrayFind (cups_poll->watched_fds, &key);
Packit e8a0b7
  if (watched_fd == NULL)
Packit e8a0b7
  {
Packit e8a0b7
    watched_fd = malloc(sizeof(cupsd_watched_fd_t));
Packit e8a0b7
    if (watched_fd == NULL)
Packit e8a0b7
    {
Packit e8a0b7
      free (watch);
Packit e8a0b7
      return (NULL);
Packit e8a0b7
    }
Packit e8a0b7
Packit e8a0b7
    watched_fd->fd = fd;
Packit e8a0b7
    watched_fd->occurred = 0;
Packit e8a0b7
    watched_fd->cups_poll = cups_poll;
Packit e8a0b7
    watched_fd->watches = cupsArrayNew (NULL, NULL);
Packit e8a0b7
    cupsArrayAdd (cups_poll->watched_fds, watched_fd);
Packit e8a0b7
  }
Packit e8a0b7
Packit e8a0b7
  watch->watched_fd = watched_fd;
Packit e8a0b7
  cupsArrayAdd(watched_fd->watches, watch);
Packit e8a0b7
  watched_fd_add_select (watched_fd);
Packit e8a0b7
  return (watch);
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'watch_free' - Free a file descriptor watch
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
static void
Packit e8a0b7
watch_free (AvahiWatch *watch)
Packit e8a0b7
{
Packit e8a0b7
  cupsd_watched_fd_t *watched_fd = watch->watched_fd;
Packit e8a0b7
  AvahiCupsPoll *cups_poll = watched_fd->cups_poll;
Packit e8a0b7
Packit e8a0b7
  cupsArrayRemove (watched_fd->watches, watch);
Packit e8a0b7
  free (watch);
Packit e8a0b7
Packit e8a0b7
  if (!watched_fd_add_select (watched_fd))
Packit e8a0b7
  {
Packit e8a0b7
    /* No more watches */
Packit e8a0b7
    cupsArrayRemove (cups_poll->watched_fds, watched_fd);
Packit e8a0b7
    free (watched_fd);
Packit e8a0b7
  }
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'watch_update' - Update watched events for a file descriptor
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
static void
Packit e8a0b7
watch_update (AvahiWatch *watch,
Packit e8a0b7
	      AvahiWatchEvent events)
Packit e8a0b7
{
Packit e8a0b7
  watch->events = events;
Packit e8a0b7
  watched_fd_add_select (watch->watched_fd);
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'watch_get_events' - Get events that happened for a file descriptor
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
static AvahiWatchEvent
Packit e8a0b7
watch_get_events (AvahiWatch *watch)
Packit e8a0b7
{
Packit e8a0b7
  return (watch->watched_fd->occurred);
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'timeout_cb()' - Run a timed Avahi callback
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
static void
Packit e8a0b7
timeout_cb (cupsd_timeout_t *cupsd_timeout, void *userdata)
Packit e8a0b7
{
Packit e8a0b7
  AvahiTimeout *timeout = userdata;
Packit e8a0b7
  (timeout->callback) (timeout, timeout->userdata);
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'timeout_new' - Set a wakeup time
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
static AvahiTimeout *
Packit e8a0b7
timeout_new (const AvahiPoll *api,
Packit e8a0b7
	     const struct timeval *tv,
Packit e8a0b7
	     AvahiTimeoutCallback callback,
Packit e8a0b7
	     void *userdata)
Packit e8a0b7
{
Packit e8a0b7
  AvahiTimeout *timeout;
Packit e8a0b7
  AvahiCupsPoll *cups_poll = api->userdata;
Packit e8a0b7
Packit e8a0b7
  timeout = malloc(sizeof(AvahiTimeout));
Packit e8a0b7
  if (timeout == NULL)
Packit e8a0b7
    return (NULL);
Packit e8a0b7
Packit e8a0b7
  timeout->cups_poll = cups_poll;
Packit e8a0b7
  timeout->callback = callback;
Packit e8a0b7
  timeout->userdata = userdata;
Packit e8a0b7
  timeout->cupsd_timeout = cupsdAddTimeout (tv,
Packit e8a0b7
					    (cupsd_timeoutfunc_t)timeout_cb,
Packit e8a0b7
					    timeout);
Packit e8a0b7
  cupsArrayAdd (cups_poll->timeouts, timeout);
Packit e8a0b7
  return (timeout);
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'timeout_update' - Update the expiration time for a timeout
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
static void
Packit e8a0b7
timeout_update (AvahiTimeout *timeout,
Packit e8a0b7
		const struct timeval *tv)
Packit e8a0b7
{
Packit e8a0b7
  cupsdUpdateTimeout (timeout->cupsd_timeout, tv);
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * ' timeout_free' - Free a timeout
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
static void
Packit e8a0b7
timeout_free (AvahiTimeout *timeout)
Packit e8a0b7
{
Packit e8a0b7
  cupsArrayRemove (timeout->cups_poll->timeouts, timeout);
Packit e8a0b7
  cupsdRemoveTimeout (timeout->cupsd_timeout);
Packit e8a0b7
  free (timeout);
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'compare_watched_fds' - Compare watched file descriptors for array sorting
Packit e8a0b7
 */
Packit e8a0b7
static int
Packit e8a0b7
compare_watched_fds(cupsd_watched_fd_t *p0,
Packit e8a0b7
		    cupsd_watched_fd_t *p1)
Packit e8a0b7
{
Packit e8a0b7
  /*
Packit e8a0b7
   * Compare by fd (no two elements have the same fd)
Packit e8a0b7
   */
Packit e8a0b7
Packit e8a0b7
  if (p0->fd == p1->fd)
Packit e8a0b7
    return 0;
Packit e8a0b7
Packit e8a0b7
  return (p0->fd < p1->fd ? -1 : 1);
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'avahi_cups_poll_new' - Create a new Avahi main loop object for CUPS
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
AvahiCupsPoll *
Packit e8a0b7
avahi_cups_poll_new (void)
Packit e8a0b7
{
Packit e8a0b7
  AvahiCupsPoll *cups_poll = malloc(sizeof(AvahiCupsPoll));
Packit e8a0b7
  if (cups_poll == NULL)
Packit e8a0b7
    return (NULL);
Packit e8a0b7
Packit e8a0b7
  cups_poll->watched_fds = cupsArrayNew ((cups_array_func_t)compare_watched_fds,
Packit e8a0b7
					 NULL);
Packit e8a0b7
  cups_poll->timeouts = cupsArrayNew (NULL, NULL);
Packit e8a0b7
Packit e8a0b7
  cups_poll->api.userdata = cups_poll;
Packit e8a0b7
  cups_poll->api.watch_new = watch_new;
Packit e8a0b7
  cups_poll->api.watch_free = watch_free;
Packit e8a0b7
  cups_poll->api.watch_update = watch_update;
Packit e8a0b7
  cups_poll->api.watch_get_events = watch_get_events;
Packit e8a0b7
Packit e8a0b7
  cups_poll->api.timeout_new = timeout_new;
Packit e8a0b7
  cups_poll->api.timeout_update = timeout_update;
Packit e8a0b7
  cups_poll->api.timeout_free = timeout_free;
Packit e8a0b7
Packit e8a0b7
  return (cups_poll);
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'avahi_cups_poll_free' - Free an Avahi main loop object for CUPS
Packit e8a0b7
 */
Packit e8a0b7
void
Packit e8a0b7
avahi_cups_poll_free (AvahiCupsPoll *cups_poll)
Packit e8a0b7
{
Packit e8a0b7
  cupsd_watched_fd_t *watched_fd;
Packit e8a0b7
Packit e8a0b7
  for (watched_fd = (cupsd_watched_fd_t*)cupsArrayFirst(cups_poll->watched_fds);
Packit e8a0b7
       watched_fd;
Packit e8a0b7
       watched_fd = (cupsd_watched_fd_t*)cupsArrayNext(cups_poll->watched_fds))
Packit e8a0b7
    cupsArrayClear (watched_fd->watches);
Packit e8a0b7
Packit e8a0b7
  cupsArrayClear (cups_poll->watched_fds);
Packit e8a0b7
  cupsArrayClear (cups_poll->timeouts);
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * 'avahi_cups_poll_get' - Get the abstract poll API structure
Packit e8a0b7
 */
Packit e8a0b7
Packit e8a0b7
const AvahiPoll *
Packit e8a0b7
avahi_cups_poll_get (AvahiCupsPoll *cups_poll)
Packit e8a0b7
{
Packit e8a0b7
  return (&cups_poll->api);
Packit e8a0b7
}
Packit e8a0b7
Packit e8a0b7
Packit e8a0b7
#endif /* HAVE_AVAHI ... from top of file */
Packit e8a0b7
Packit e8a0b7
/*
Packit e8a0b7
 * End of "$Id$".
Packit e8a0b7
 */